crucıble

Almanac

Scheduling widget in three panes: a host card with duration chips, a keyboard-navigable month grid with availability dots and direction-aware month slides, and a day's time slots that cascade in, with a 12h/24h toggle and an IANA time-zone select (plain Intl, no date library). Picking a slot splits it into Confirm, then a details form slides in, an async onBook runs, and the button morphs into a confirmation card with a drawn check and an .ics Add to calendar button.

motionpro

Installation

CLI

npx shadcn@latest add @crucible/almanac

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
hostAlmanacHosta sample design-review hostHost and event details for the left pane.
durationsnumber[][15, 30, 60]Duration chips in minutes. Changing the chip recomputes the slots.
defaultDurationnumberthe middle entry of durationsInitially selected duration.
availabilityAlmanacAvailabilityOpen slots for a day. Omit for a deterministic seeded generator (weekdays, working hours in hostTimeZone, a few busy blocks, nothing in the past, 60-day booking window) relative to today.
todayDate | stringThe day treated as "today" — a Date or "YYYY-MM-DD". Omit to use the real current day, computed after mount (a skeleton renders until then, so server and client markup match).
timeZonesstring[]IANA zones offered in the time-zone select. The viewer's detected zone is added if missing.
defaultTimeZonestringthe viewer's detected zone (after mount)Initial time zone.
hostTimeZonestring"America/New_York"Zone the default availability generator schedules working hours in.
defaultHourCycle"12h" | "24h""12h"Initial clock format.
weekStartsOn0 | 10First day of the week in the month grid (0 = Sunday, 1 = Monday).
onBook(booking: AlmanacBooking) => void | Promise<unknown>Called with the booking when the details form is submitted. Return a Promise to hold the button in a pending state — resolve morphs into the confirmation card, reject shows the error's message inline.
onAddToCalendar(booking: AlmanacBooking) => voiddownloads an .ics file for the bookingOverride "Add to calendar".
onDurationChange(minutes: number) => voidFires when the duration chip changes.
onTimeZoneChange(tz: string) => voidFires when the time zone changes.
accentColorstring"#a5b4fc"Signature accent for selection, focus rings and the confirm button.
refReact.Ref<AlmanacHandle>Imperative handle (reset(), replay()). React 19 ref-as-prop.
classNamestringExtra classes for the <section> root.
Also accepts all props of Omit<React.ComponentPropsWithoutRef<"section">, "children" | "onChange" | "onDurationChange"> — they pass through to the underlying element.

Honors prefers-reduced-motion with a designed static fallback, and passes className through.