KQ-1721 · PINCH/BOARD
Pinch Board
A kanban board you zoom: cards have levels of detail — coloured dots, one-line titles, full cards with owner and due date, and open cards with a note and checklist — and a pinch, Ctrl or ⌘ with the wheel, the + and − keys or the toolbar morphs every card between them on the glide spring. The board notes the card under the focal point and where inside it the point sits, and its scroll rides the same glide spring to the offset that puts that spot back under the fingers, so the focal card holds still for the whole morph; at an edge the content is shifted instead and settles back on drift. Cards move by drag on flick and snap or by keys — Space lifts, arrows carry, Space drops, Escape puts back — and the level pill slides on snap.
Waylight 4.2 release
72 cards · 5 columns
Arrow keys move between cards. Plus and minus change the level of detail. Space picks a card up; arrows carry it, Space drops it, Escape puts it back. Enter opens a card.
72 cards · pinch, ctrl + scroll or press + and −
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/pinch-board
Props
- columns
- PinchColumn[]
- default defaultPinchColumns
- The columns in order ({ id, title, status? }); a loading column draws outlines in the level's shape.
- cards / defaultCards
- PinchCard[]
- default defaultPinchCards
- Controlled or initial cards ({ id, columnId, title, key?, kind?, owner?, due?, note?, checklist? }); order within a column is the array's order.
- onCardsChange
- (cards: PinchCard[]) => void
- default —
- Fires with every card after a move.
- onMove
- (move: PinchMove) => void
- default —
- Fires from the drop or key that moved a card.
- level / defaultLevel
- "dots" | "titles" | "cards" | "detail"
- default —
- Controlled or initial level of detail. Omit both and narrow boards (under 40rem) start at titles, wider ones at cards, on the first paint.
- onZoom
- (level: PinchLevel, info: { from: PinchLevel; source: "pinch" | "wheel" | "key" | "button" }) => void
- default —
- Fires from the pinch, wheel, key or button that changed the level.
- zoomLevels
- number
- default 3
- How many levels the zoom steps through: 2 (titles, cards), 3 (dots, titles, cards) or 4 (adds detail).
- pinchStep
- number
- default 1.3
- The pinch ratio that steps one level; lower is more eager.
- cardStyle
- "plain" | "edge" | "tint"
- default "plain"
- Cards drawn plain with a hairline, with a coloured edge by kind, or on a soft tint of their kind.
- accent
- string
- default "var(--accent-bright)"
- The level pill, the lifted card's ring and the placeholder; any CSS colour.
- now
- number
- default defaultPinchNow
- Today, ms, for "in 3d" and "2d late".
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the board's cards have arrived.
- onRetry
- () => void
- default —
- "Try again" was pressed after the board failed to load.
- onOpen
- (cardId: string) => void
- default —
- A card was tapped, or Enter was pressed on it.
- title
- string
- default "Waylight 4.2 release"
- The heading.
- height
- number
- default 480
- The board's height in px; columns scroll inside it.
- label
- string
- default —
- The board's accessible name; defaults to the title.
- disabled
- boolean
- default false
- Freezes the board: no zoom, drags or keys.
- className
- string
- default —
- Classes for the outer panel.
| Prop | Type | Default | Description |
|---|---|---|---|
| columns | PinchColumn[] | defaultPinchColumns | The columns in order ({ id, title, status? }); a loading column draws outlines in the level's shape. |
| cards / defaultCards | PinchCard[] | defaultPinchCards | Controlled or initial cards ({ id, columnId, title, key?, kind?, owner?, due?, note?, checklist? }); order within a column is the array's order. |
| onCardsChange | (cards: PinchCard[]) => void | — | Fires with every card after a move. |
| onMove | (move: PinchMove) => void | — | Fires from the drop or key that moved a card. |
| level / defaultLevel | "dots" | "titles" | "cards" | "detail" | — | Controlled or initial level of detail. Omit both and narrow boards (under 40rem) start at titles, wider ones at cards, on the first paint. |
| onZoom | (level: PinchLevel, info: { from: PinchLevel; source: "pinch" | "wheel" | "key" | "button" }) => void | — | Fires from the pinch, wheel, key or button that changed the level. |
| zoomLevels | number | 3 | How many levels the zoom steps through: 2 (titles, cards), 3 (dots, titles, cards) or 4 (adds detail). |
| pinchStep | number | 1.3 | The pinch ratio that steps one level; lower is more eager. |
| cardStyle | "plain" | "edge" | "tint" | "plain" | Cards drawn plain with a hairline, with a coloured edge by kind, or on a soft tint of their kind. |
| accent | string | "var(--accent-bright)" | The level pill, the lifted card's ring and the placeholder; any CSS colour. |
| now | number | defaultPinchNow | Today, ms, for "in 3d" and "2d late". |
| status | "ready" | "loading" | "error" | "ready" | Whether the board's cards have arrived. |
| onRetry | () => void | — | "Try again" was pressed after the board failed to load. |
| onOpen | (cardId: string) => void | — | A card was tapped, or Enter was pressed on it. |
| title | string | "Waylight 4.2 release" | The heading. |
| height | number | 480 | The board's height in px; columns scroll inside it. |
| label | string | — | The board's accessible name; defaults to the title. |
| disabled | boolean | false | Freezes the board: no zoom, drags or keys. |
| className | string | — | Classes for the outer panel. |