KQ-1662 · PING/MATRIX
Ping Matrix
Notification preferences as a grid of switches, events down and channels across. Pressing a channel's heading turns the whole column on (or off when it is all on) and the change runs down the column like falling dominoes: each switch tips forward about its bottom edge on an ease-in, flips while it is down and stands back up on springs.snap, the next starting the moment it hits as the gaps close. A switch that differs from the workspace default carries a mark that pops in on springs.flick, and Reset to defaults runs every edited switch back as one diagonal run. It is a real grid with one roving tab stop — arrows, Home and End, Ctrl with Home or End, Space to toggle, Delete to reset — onChange and onReset fire per cell, and below 760px each event becomes a card of channel chips.
Notifications
A dot marks a switch that differs from the Basinworks defaults.
Arrow keys move between switches and channel headings. Space toggles. Delete puts a switch back to the workspace default.
your settings · 2 edited from default
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/ping-matrix
Props
- events
- PingMatrixEvent[]
- default defaultPingMatrixEvents
- The rows, { id, label, description? }: what can happen.
- channels
- PingMatrixChannel[]
- default defaultPingMatrixChannels
- The columns, { id, label }: where it can reach you.
- value / defaultValue
- Record<string, Record<string, boolean>>
- default — / defaultPingMatrixValue
- On or off for every event and channel (value[eventId][channelId]), controlled or initial; the initial value also counts as saved.
- onValueChange
- (value: PingMatrixValue) => void
- default —
- Fires with every preference after each cell changes, run cells included.
- defaults
- PingMatrixValue
- default defaultPingMatrixDefaults
- The workspace's defaults; a cell that differs carries the edited mark and says what the default is.
- onChange
- (eventId: string, channelId: string, on: boolean) => void
- default —
- One cell changed — per cell, also as a column's run reaches it.
- onReset
- (eventId: string, channelId: string) => void
- default —
- One cell went back to the workspace default — per cell, from Delete or Reset to defaults.
- onSave
- (value: PingMatrixValue) => void | Promise<unknown>
- default —
- Save was pressed. Return a promise to show it saving; a rejection keeps the edits and says so.
- status
- "ready" | "loading"
- default "ready"
- Loading draws switch skeletons, makes the headings inert and marks the grid aria-busy.
- switchStyle
- "pill" | "check" | "dot"
- default "pill"
- A track whose knob slides on snap, a box whose tick draws on flick, or a ring whose core grows on snap.
- density
- "compact" | "cozy" | "roomy"
- default "cozy"
- Row height and how much is said: 40, 52 or 64px rows; compact hides the descriptions.
- accent
- string
- default "var(--accent-bright)"
- The colour of a switch that is on, the edited marks and the column meters. Any CSS colour.
- title
- string
- default "Notifications"
- The heading and the grid's accessible name.
- workspace
- string
- default "Basinworks"
- Whose defaults these are, in the copy and the switches' names.
- maxHeight
- number
- default 548
- Tallest the surface grows before its body scrolls inside, px.
- disabled
- boolean
- default false
- Nothing can be changed or saved; the surface dims.
- className
- string
- default —
- Classes for the outer surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| events | PingMatrixEvent[] | defaultPingMatrixEvents | The rows, { id, label, description? }: what can happen. |
| channels | PingMatrixChannel[] | defaultPingMatrixChannels | The columns, { id, label }: where it can reach you. |
| value / defaultValue | Record<string, Record<string, boolean>> | — / defaultPingMatrixValue | On or off for every event and channel (value[eventId][channelId]), controlled or initial; the initial value also counts as saved. |
| onValueChange | (value: PingMatrixValue) => void | — | Fires with every preference after each cell changes, run cells included. |
| defaults | PingMatrixValue | defaultPingMatrixDefaults | The workspace's defaults; a cell that differs carries the edited mark and says what the default is. |
| onChange | (eventId: string, channelId: string, on: boolean) => void | — | One cell changed — per cell, also as a column's run reaches it. |
| onReset | (eventId: string, channelId: string) => void | — | One cell went back to the workspace default — per cell, from Delete or Reset to defaults. |
| onSave | (value: PingMatrixValue) => void | Promise<unknown> | — | Save was pressed. Return a promise to show it saving; a rejection keeps the edits and says so. |
| status | "ready" | "loading" | "ready" | Loading draws switch skeletons, makes the headings inert and marks the grid aria-busy. |
| switchStyle | "pill" | "check" | "dot" | "pill" | A track whose knob slides on snap, a box whose tick draws on flick, or a ring whose core grows on snap. |
| density | "compact" | "cozy" | "roomy" | "cozy" | Row height and how much is said: 40, 52 or 64px rows; compact hides the descriptions. |
| accent | string | "var(--accent-bright)" | The colour of a switch that is on, the edited marks and the column meters. Any CSS colour. |
| title | string | "Notifications" | The heading and the grid's accessible name. |
| workspace | string | "Basinworks" | Whose defaults these are, in the copy and the switches' names. |
| maxHeight | number | 548 | Tallest the surface grows before its body scrolls inside, px. |
| disabled | boolean | false | Nothing can be changed or saved; the surface dims. |
| className | string | — | Classes for the outer surface. |