KQ-753 · ATTACH/TRAY
Attach Tray
Files that dock beside the prompt. The whole tray takes a drop from the OS and an Add files button opens a real file input, so the keyboard reaches the same door. Each file becomes a chip that slides in from eight pixels on snap with a progress ring whose dash offset follows progress on glide — an upload settles, it does not jump — and at 1 the ring gives way to a check drawn on flick. Removing a chip runs its exit on the exit ease while the row beneath is measured, so the tray's height glides to the new row count and to zero when the last chip goes, with nothing reserved. Rings are progress bars with a value text, remove buttons are named by file, and a status line announces each file as it attaches.
Empty · drop a file
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/attach-tray
Props
- files
- AttachFile[]
- default —
- { id, name, size, progress, kind? } — size in bytes, progress 0..1, kind image, doc, sheet, code or file (inferred from the extension when omitted).
- onAdd
- (files: { name: string; size: number }[]) => void
- default —
- Fires from a drop or the file picker with the names and sizes chosen; the parent starts the upload and owns the progress.
- onRemove
- (id: string) => void
- default —
- Fires from a chip's remove button.
- format
- (bytes: number) => string
- default formatBytes
- Formats every size; the default prints B, KB or MB with one decimal.
- label
- string
- default —
- Names the tray as a group.
| Prop | Type | Default | Description |
|---|---|---|---|
| files | AttachFile[] | — | { id, name, size, progress, kind? } — size in bytes, progress 0..1, kind image, doc, sheet, code or file (inferred from the extension when omitted). |
| onAdd | (files: { name: string; size: number }[]) => void | — | Fires from a drop or the file picker with the names and sizes chosen; the parent starts the upload and owns the progress. |
| onRemove | (id: string) => void | — | Fires from a chip's remove button. |
| format | (bytes: number) => string | formatBytes | Formats every size; the default prints B, KB or MB with one decimal. |
| label | string | — | Names the tray as a group. |