KQ-1657 · OPEN/DAY

Open Day

An empty calendar day: the working hours as a calm column, suggested blocks floating beside it, and an empty message that sits in the largest free stretch and shrinks as the day fills. A suggestion follows the finger 1:1, tucked to a compact chip while a dashed slot shows where it would land; released over the day it drops onto the slot on springs.snap with the throw's velocity and then stretches to its default length on springs.glide a beat later, and released anywhere else it flies home. Keyboard users pick a suggestion and press Enter to place it at the next free hour with the same drop and stretch, Delete dismisses it, and placed blocks move a quarter hour with Up and Down.

KQ-1657 · OPEN/DAY

Thursday 15 October

09:00–17:00

8 h open
Nothing booked yetDrag a block in, or pick one and press Enter.

nothing booked · 8 h open

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/open-day

Props

hourHeight
number
default 40
Pixels per hour of the column; the drag maps to it.
cardStyle
"soft" | "outline" | "solid"
default "soft"
How blocks and suggestions are drawn: a tinted fill, a dashed outline, or solid pigment.
tone
"calm" | "warm" | "mono"
default "calm"
The block colours: token hues at a fixed lightness, so they read in both themes.
date
number
default defaultOpenDayDate
Any time on the day shown, in ms (read in UTC).
workingHours
[number, number]
default [9, 17]
Working hours as whole hours; the column covers them.
suggestions
DaySuggestion[]
default defaultDaySuggestions
Blocks offered beside the day: { id, label, kind: "focus" | "lunch" | "review" | "inbox" | "prep", minutes }.
value / defaultValue
DayBlock[]
default — / []
The placed blocks, controlled or initial: { id, suggestion, label, kind, start, end } in ms.
onValueChange
(blocks: DayBlock[]) => void
default —
Fires from the drop, key or press that changed the day, with every block.
onPlace
(block: DayBlock) => void | Promise<unknown>
default —
A block landed or moved. Return a promise to save it; a rejection keeps it, marked unsaved.
onDismiss
(suggestion: DaySuggestion) => void
default —
A suggestion was dismissed (its × or Delete).
onRemove
(block: DayBlock) => void
default —
A placed block was removed; its suggestion goes back beside the day.
now
number
default defaultOpenDayNow
The current time in ms; "next free hour" counts from it on its own day. Never read from the clock.
status
"ready" | "loading" | "error"
default "ready"
Whether the day has loaded. Loading shows a skeleton column and cards; error marks every placed block unsaved under a Retry banner.
onRetry
() => void
default —
Retry was pressed on the sync banner; unsaved blocks are placed again through onPlace.
step
number
default 15
The minutes the column snaps to, and one Up or Down press.
height
number
default 540
Height of the day in px; its body scrolls inside it.
disabled
boolean
default false
Nothing can be placed, moved or dismissed.
className
string
default —
Classes for the outer surface.