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.

KQ-1680 · DESTINATION/PICKER
Fernworks / InboxInbox
  • Pump curve – Rev C.pdf1.4 MB
  • Valve schedule.xlsx88 KB
  • Site walk – 9 Oct.jpg3.1 MB
  • Crane lift plan.pdf640 KB

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.