KQ-1680 · DESTINATION/PICKER
Destination Picker
A move dialog whose file rides along: the item sits as a chip in the header and hops on a short arc to each destination you hover or arrow onto — one progress spring on springs.snap carries it in a line plus a parabola of arcHeight, landing with a small settle in the row's end slot. Hops interrupted by the next key leave from wherever the chip is, refused folders grey the chip and open their reason on glide, and moving dives the chip into the folder's glyph on glide before the dialog leaves on the exit ease. The tree is a real treeview with type-ahead and lazy branches behind a spinner row, search turns it into a listbox, and Enter moves.
- Pump curve – Rev C.pdf1.4 MB
- Valve schedule.xlsx88 KB
- Site walk – 9 Oct.jpg3.1 MB
- Crane lift plan.pdf640 KB
Move
MovingPump curve – Rev C.pdf
Arrow keys move between folders, Right opens and Left closes, letters jump, Enter moves the file.
moving pump curve – rev c.pdf · arrow onto a folder
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/destination-picker
Props
- item
- { name, kind?, size? }
- default defaultDestinationItem
- The file being moved; kind (pdf, image, sheet, doc) picks the chip's glyph.
- folders
- DestinationFolder[]
- default defaultDestinationFolders
- The project tree: { id, name, count?, project?, children?, hasChildren?, forbidden? }.
- recent
- string[]
- default defaultDestinationRecent
- Folder ids offered as one-press destinations above the tree.
- value / defaultValue
- string | null
- default — / null
- The chosen destination, controlled or initial; the chip rests on it.
- onValueChange
- (id) => void
- default —
- Fires from the arrow key, press or type-ahead that changed the destination.
- onMove
- (folder, path) => void | Promise<void>
- default —
- Move or Enter was pressed on an allowed folder. A promise holds the dialog (Moving…) until it lands; a rejection's message stays in the footer.
- onCreateFolder
- (parent, name) => DestinationFolder | Promise<DestinationFolder>
- default —
- A new folder was named in the inline row; the returned folder joins the tree and is chosen.
- onLoadChildren
- (folder) => Promise<DestinationFolder[]>
- default —
- Loads a folder that has hasChildren and no children; a spinner row stands in until it answers, a failure offers Retry.
- open / defaultOpen
- boolean
- default — / true
- Whether the dialog is open over the listing, controlled or initial.
- onOpenChange
- (open) => void
- default —
- Move…, the close button, the scrim, Escape or a finished move opened or closed it.
- currentFolder
- string
- default "inbox"
- Where the file is now; moving there is refused with a reason.
- status
- "ready" | "loading" | "error"
- default "ready"
- Loading shows placeholder rows; error explains and offers Try again.
- onRetry
- () => void
- default —
- Try again was pressed after the tree failed to load.
- chipStyle
- "pill" | "tag" | "icon"
- default "pill"
- The riding file as a pill with its name, a folded tag with its extension, or just its glyph in a disc.
- arcHeight
- number
- default 20
- The apex of the hop in px, scaled down for short hops; 0 slides straight.
- accent
- string
- default "var(--accent-bright)"
- The chip, the chosen row and Move; text on it flips light or dark with its lightness.
- title
- string
- default "Move"
- The dialog's heading.
- height
- number
- default 540
- Height of the frame in px; the tree scrolls inside the dialog.
- disabled
- boolean
- default false
- Nothing can be moved or created.
- className
- string
- default —
- Classes for the frame.
| Prop | Type | Default | Description |
|---|---|---|---|
| item | { name, kind?, size? } | defaultDestinationItem | The file being moved; kind (pdf, image, sheet, doc) picks the chip's glyph. |
| folders | DestinationFolder[] | defaultDestinationFolders | The project tree: { id, name, count?, project?, children?, hasChildren?, forbidden? }. |
| recent | string[] | defaultDestinationRecent | Folder ids offered as one-press destinations above the tree. |
| value / defaultValue | string | null | — / null | The chosen destination, controlled or initial; the chip rests on it. |
| onValueChange | (id) => void | — | Fires from the arrow key, press or type-ahead that changed the destination. |
| onMove | (folder, path) => void | Promise<void> | — | Move or Enter was pressed on an allowed folder. A promise holds the dialog (Moving…) until it lands; a rejection's message stays in the footer. |
| onCreateFolder | (parent, name) => DestinationFolder | Promise<DestinationFolder> | — | A new folder was named in the inline row; the returned folder joins the tree and is chosen. |
| onLoadChildren | (folder) => Promise<DestinationFolder[]> | — | Loads a folder that has hasChildren and no children; a spinner row stands in until it answers, a failure offers Retry. |
| open / defaultOpen | boolean | — / true | Whether the dialog is open over the listing, controlled or initial. |
| onOpenChange | (open) => void | — | Move…, the close button, the scrim, Escape or a finished move opened or closed it. |
| currentFolder | string | "inbox" | Where the file is now; moving there is refused with a reason. |
| status | "ready" | "loading" | "error" | "ready" | Loading shows placeholder rows; error explains and offers Try again. |
| onRetry | () => void | — | Try again was pressed after the tree failed to load. |
| chipStyle | "pill" | "tag" | "icon" | "pill" | The riding file as a pill with its name, a folded tag with its extension, or just its glyph in a disc. |
| arcHeight | number | 20 | The apex of the hop in px, scaled down for short hops; 0 slides straight. |
| accent | string | "var(--accent-bright)" | The chip, the chosen row and Move; text on it flips light or dark with its lightness. |
| title | string | "Move" | The dialog's heading. |
| height | number | 540 | Height of the frame in px; the tree scrolls inside the dialog. |
| disabled | boolean | false | Nothing can be moved or created. |
| className | string | — | Classes for the frame. |