KQ-1658 · EMPTY/ROOM
Empty Room
The empty state of a space nobody has joined: a table seen from above with a dashed ghost seat for each person the directory suggests. Inviting someone turns their seat solid with a small hop — up on an enter tween, down on springs.recoil, the landing spring — while the disc grows in on springs.snap, one ring leaves the seat, the table warms toward the accent and the copy moves from waiting to welcoming; Invite all runs the hops round the table on cascade(). Seats are buttons in clockwise order, so Tab (or the arrows, Home and End) walks round the table and Enter invites; a refused invite marks its seat for a retry.
Harbour Ops
New space · created 4 min ago
Nobody's here yet.
Harbour Ops is ready for the people who belong in it, suggested from the Basinworks directory.
Tab or the arrow keys move round the table. Enter invites the person in that seat.
0 of 8 seats · link not copied
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/empty-room
Props
- suggestions
- EmptyRoomPerson[]
- default defaultEmptyRoomSuggestions
- People from the directory, { id, name, role?, reason? }, one per seat in clockwise order from the top left.
- invited / defaultInvited
- string[]
- default — / []
- Ids of the people already invited, controlled or initial.
- onInvitedChange
- (ids: string[]) => void
- default —
- Fires with every invited id once an invite has gone through.
- onInvite
- (person: EmptyRoomPerson) => void | Promise<unknown>
- default —
- A seat was pressed. Return a promise to show the invite in flight; a rejection marks the seat for a retry.
- onCopyLink
- (link: string) => void
- default —
- The share link was copied (it is also written to the clipboard when one is available).
- inviteLink
- string
- default "basinworks/join/harbour-ops-7qf2"
- The space's share link, shown in the header and copied by Copy.
- spaceName
- string
- default "Harbour Ops"
- The new space's name; also the surface's accessible name.
- directory
- string
- default "Basinworks directory"
- Where the suggestions come from, used in the copy.
- createdAt
- number
- default four minutes before now
- When the space was created, in ms.
- now
- number
- default defaultEmptyRoomNow
- The moment ages count from, in ms; never read from the clock during render.
- status
- "ready" | "loading"
- default "ready"
- Loading draws blank breathing seats with skeleton names, and nothing can be invited.
- seatCount
- number
- default 8
- How many chairs the table seats, 4 to 10; the ends take a seat each from six.
- seatShape
- "round" | "square" | "chair"
- default "round"
- Seats as circles, rounded squares, or chairs whose backs face away from the table.
- accent
- string
- default "var(--accent-bright)"
- The colour of a taken seat, its welcome ring and the table's warmth. Any CSS colour; seats take its hue at a fixed lightness.
- inviteAll
- boolean
- default true
- Offer Invite all, which seats everyone left in one run round the table.
- disabled
- boolean
- default false
- Nothing can be invited or copied; the surface dims.
- className
- string
- default —
- Classes for the outer surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| suggestions | EmptyRoomPerson[] | defaultEmptyRoomSuggestions | People from the directory, { id, name, role?, reason? }, one per seat in clockwise order from the top left. |
| invited / defaultInvited | string[] | — / [] | Ids of the people already invited, controlled or initial. |
| onInvitedChange | (ids: string[]) => void | — | Fires with every invited id once an invite has gone through. |
| onInvite | (person: EmptyRoomPerson) => void | Promise<unknown> | — | A seat was pressed. Return a promise to show the invite in flight; a rejection marks the seat for a retry. |
| onCopyLink | (link: string) => void | — | The share link was copied (it is also written to the clipboard when one is available). |
| inviteLink | string | "basinworks/join/harbour-ops-7qf2" | The space's share link, shown in the header and copied by Copy. |
| spaceName | string | "Harbour Ops" | The new space's name; also the surface's accessible name. |
| directory | string | "Basinworks directory" | Where the suggestions come from, used in the copy. |
| createdAt | number | four minutes before now | When the space was created, in ms. |
| now | number | defaultEmptyRoomNow | The moment ages count from, in ms; never read from the clock during render. |
| status | "ready" | "loading" | "ready" | Loading draws blank breathing seats with skeleton names, and nothing can be invited. |
| seatCount | number | 8 | How many chairs the table seats, 4 to 10; the ends take a seat each from six. |
| seatShape | "round" | "square" | "chair" | "round" | Seats as circles, rounded squares, or chairs whose backs face away from the table. |
| accent | string | "var(--accent-bright)" | The colour of a taken seat, its welcome ring and the table's warmth. Any CSS colour; seats take its hue at a fixed lightness. |
| inviteAll | boolean | true | Offer Invite all, which seats everyone left in one run round the table. |
| disabled | boolean | false | Nothing can be invited or copied; the surface dims. |
| className | string | — | Classes for the outer surface. |