cupertino-datetime-picker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/calendar.ts","../src/time.ts","../src/utils.ts","../src/hooks.ts","../src/wheel-math.ts","../src/wheel.tsx","../src/calendar-panel.tsx","../src/segmented-control.tsx","../src/segments.ts","../src/time-panel.tsx","../src/date-time-picker.tsx"],"sourcesContent":["/**\n * Calendar arithmetic on local `Date`s, with no library. A picker only ever\n * needs the month grid, day-level comparisons, and \"same clock, other day\".\n */\nexport type YearMonth = { year: number; month: number };\n\nexport function startOfDay(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\nexport function isSameDay(a: Date | null | undefined, b: Date | null | undefined): boolean {\n return (\n !!a &&\n !!b &&\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nexport function daysInMonth(year: number, month: number): number {\n return new Date(year, month + 1, 0).getDate();\n}\n\nexport function yearMonthOf(date: Date): YearMonth {\n return { year: date.getFullYear(), month: date.getMonth() };\n}\n\n/** Months between `a` and `b`; negative when `b` is earlier. */\nexport function monthDiff(a: YearMonth, b: YearMonth): number {\n return (b.year - a.year) * 12 + (b.month - a.month);\n}\n\nexport function shiftMonth(ym: YearMonth, by: number): YearMonth {\n const total = ym.month + by;\n return { year: ym.year + Math.floor(total / 12), month: ((total % 12) + 12) % 12 };\n}\n\n/** The same clock on another calendar day; the day is clamped into the month. */\nexport function withDay(base: Date, year: number, month: number, day: number): Date {\n const next = new Date(base);\n next.setFullYear(year, month, Math.min(day, daysInMonth(year, month)));\n return next;\n}\n\nexport function withTime(base: Date, hours: number, minutes: number): Date {\n const next = new Date(base);\n next.setHours(hours, minutes, 0, 0);\n return next;\n}\n\nexport function addDays(date: Date, days: number): Date {\n const next = new Date(date);\n next.setDate(next.getDate() + days);\n return next;\n}\n\nexport function addMonths(date: Date, months: number): Date {\n const ym = shiftMonth(yearMonthOf(date), months);\n return withDay(date, ym.year, ym.month, date.getDate());\n}\n\n/** Whether the whole day lies outside [min, max]. */\nexport function isDayDisabled(date: Date, min?: Date, max?: Date): boolean {\n const day = startOfDay(date).getTime();\n if (min && day < startOfDay(min).getTime()) return true;\n if (max && day > startOfDay(max).getTime()) return true;\n return false;\n}\n\nexport type DayCell = { date: Date; inMonth: boolean };\n\n/**\n * Rows of seven for one month, starting on `weekStart` (0 = Sunday). Only as\n * many rows as the month needs, like the iOS inline calendar.\n */\nexport function monthGrid(year: number, month: number, weekStart: number): DayCell[][] {\n const lead = (new Date(year, month, 1).getDay() - weekStart + 7) % 7;\n const rows = Math.ceil((lead + daysInMonth(year, month)) / 7);\n return Array.from({ length: rows }, (_row, r) =>\n Array.from({ length: 7 }, (_cell, c) => {\n const date = new Date(year, month, r * 7 + c - lead + 1);\n return { date, inMonth: date.getMonth() === month };\n }),\n );\n}\n\n/** First day of the week for a locale, 0 = Sunday … 6 = Saturday. */\nexport function weekStartFor(locale: string): number {\n const firstDay = readFirstDay(locale);\n if (firstDay !== undefined) return firstDay % 7;\n return /^(en-(US|CA|AU)|ja|ko|zh-(TW|HK)|he|pt-BR|es-(MX|US))\\b/i.test(locale) ? 0 : 1;\n}\n\n/**\n * `Intl.Locale#getWeekInfo` (or the older `weekInfo` getter) where the engine\n * has it, read without assuming either exists in the type library.\n */\nfunction readFirstDay(locale: string): number | undefined {\n let l: object;\n try {\n l = new Intl.Locale(locale);\n } catch {\n return undefined;\n }\n const info: unknown =\n \"getWeekInfo\" in l && typeof l.getWeekInfo === \"function\"\n ? l.getWeekInfo()\n : \"weekInfo\" in l\n ? l.weekInfo\n : undefined;\n return typeof info === \"object\" &&\n info !== null &&\n \"firstDay\" in info &&\n typeof info.firstDay === \"number\"\n ? info.firstDay\n : undefined;\n}\n","/**\n * Clock helpers on top of `Intl`, so 12/24-hour, day-period labels, and month\n * and weekday names all follow the locale instead of a hard-coded table.\n */\nexport type HourCycle = \"h12\" | \"h23\";\n\nexport function hourCycleFor(locale: string): HourCycle {\n const cycle = new Intl.DateTimeFormat(locale, { hour: \"numeric\" }).resolvedOptions().hourCycle;\n return cycle === \"h11\" || cycle === \"h12\" ? \"h12\" : \"h23\";\n}\n\nexport function to12(hour24: number): { hour: number; pm: boolean } {\n return { hour: hour24 % 12 === 0 ? 12 : hour24 % 12, pm: hour24 >= 12 };\n}\n\nexport function to24(hour12: number, pm: boolean): number {\n return (hour12 % 12) + (pm ? 12 : 0);\n}\n\nexport function dayPeriodLabels(locale: string): { am: string; pm: string } {\n const f = new Intl.DateTimeFormat(locale, { hour: \"numeric\", hourCycle: \"h12\" });\n const label = (hour: number) =>\n f.formatToParts(new Date(2000, 0, 1, hour)).find((p) => p.type === \"dayPeriod\")?.value ??\n (hour < 12 ? \"AM\" : \"PM\");\n return { am: label(1), pm: label(13) };\n}\n\nexport function monthNames(locale: string, style: \"long\" | \"short\" = \"long\"): string[] {\n const f = new Intl.DateTimeFormat(locale, { month: style });\n return Array.from({ length: 12 }, (_, m) => f.format(new Date(2000, m, 1)));\n}\n\n/** Seven names starting on `weekStart` (0 = Sunday). */\nexport function weekdayNames(\n locale: string,\n weekStart: number,\n style: \"narrow\" | \"short\" = \"narrow\",\n): string[] {\n const f = new Intl.DateTimeFormat(locale, { weekday: style });\n // 2023-01-01 is a Sunday.\n return Array.from({ length: 7 }, (_, i) =>\n f.format(new Date(2023, 0, 1 + ((weekStart + i) % 7))),\n );\n}\n\n/** The locale's medium date, as the iOS pill shows it: \"Sep 5, 2026\", \"05.09.2026\", \"2026年9月5日\". */\nexport function formatDay(date: Date, locale: string): string {\n return new Intl.DateTimeFormat(locale, { dateStyle: \"medium\" }).format(date);\n}\n\n/** \"6:30 PM\" on a 12-hour clock, \"06:30\" on a 24-hour one. */\nexport function formatClock(date: Date, locale: string, hourCycle: HourCycle): string {\n return new Intl.DateTimeFormat(locale, {\n hour: hourCycle === \"h12\" ? \"numeric\" : \"2-digit\",\n minute: \"2-digit\",\n hourCycle,\n }).format(date);\n}\n\nexport function formatMonthYear(date: Date, locale: string): string {\n return new Intl.DateTimeFormat(locale, { month: \"long\", year: \"numeric\" }).format(date);\n}\n\nexport function formatFullDate(date: Date, locale: string): string {\n return new Intl.DateTimeFormat(locale, {\n weekday: \"long\",\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n }).format(date);\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport function clamp(n: number, min: number, max: number) {\n return Math.min(max, Math.max(min, n));\n}\n\n/** Wrap `n` into [0, len). */\nexport function mod(n: number, len: number) {\n return ((n % len) + len) % len;\n}\n\nexport function pad2(n: number) {\n return n < 10 ? `0${n}` : String(n);\n}\n","import * as React from \"react\";\n\n/** Controlled when `value` is given, otherwise owned here. */\nexport function useControlled<T>(\n value: T | undefined,\n defaultValue: T,\n onChange: ((next: T) => void) | undefined,\n): [T, (next: T) => void] {\n const [inner, setInner] = React.useState(defaultValue);\n const current = value === undefined ? inner : value;\n const set = (next: T) => {\n if (value === undefined) setInner(next);\n onChange?.(next);\n };\n return [current, set];\n}\n\nexport function usePrefersReducedMotion(): boolean {\n return React.useSyncExternalStore(\n (notify) => {\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n query.addEventListener(\"change\", notify);\n return () => query.removeEventListener(\"change\", notify);\n },\n () => window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches,\n () => false,\n );\n}\n","import { clamp } from \"./utils\";\n\n/** The row a scroll offset rests on. */\nexport function snapIndex(scrollTop: number, itemHeight: number): number {\n return Math.round(scrollTop / itemHeight);\n}\n\n/**\n * Where a released drag comes to rest. `velocity` is d(scrollTop)/dt in\n * px/ms; the projection mirrors UIScrollView's normal deceleration, then\n * lands on a row.\n */\nexport function flingTarget(\n scrollTop: number,\n velocity: number,\n itemHeight: number,\n maxIndex: number,\n): number {\n const projected = scrollTop + velocity * 380;\n return clamp(snapIndex(projected, itemHeight), 0, maxIndex);\n}\n\n/** Of the copies of `logical` in a looped wheel, the one nearest `from`. */\nexport function nearestCopy(logical: number, from: number, len: number, copies: number): number {\n let best = logical;\n for (let c = 0; c < copies; c++) {\n const candidate = c * len + logical;\n if (Math.abs(candidate - from) < Math.abs(best - from)) best = candidate;\n }\n return best;\n}\n\nexport function easeOutCubic(t: number): number {\n return 1 - (1 - t) ** 3;\n}\n","import * as React from \"react\";\n\nimport { usePrefersReducedMotion } from \"./hooks\";\nimport { clamp, cn, mod } from \"./utils\";\nimport { easeOutCubic, flingTarget, nearestCopy, snapIndex } from \"./wheel-math\";\n\nexport type WheelOption = { value: number; label: string };\n\nexport type WheelProps = {\n options: WheelOption[];\n value: number;\n onChange: (value: number) => void;\n /** Hours and minutes wrap around like the iOS clock wheels. */\n loop?: boolean;\n itemHeight?: number;\n visibleRows?: number;\n \"aria-label\": string;\n className?: string;\n};\n\n// Looped wheels render the options this many times and rest in the middle\n// copy, so a fling always has road in both directions.\nconst COPIES = 7;\nconst TYPEAHEAD_MS = 700;\n\ntype Drag = {\n startY: number;\n startTop: number;\n lastTop: number;\n lastT: number;\n v: number;\n moved: boolean;\n};\n\n/**\n * One column of an iOS picker: native scrolling with snap points (so touch\n * and trackpad flings come from the platform), mouse drag with its own\n * deceleration, a click on any row, and the keyboard — arrows step, digits\n * jump. The centre row is the value; the parent draws the highlight bar.\n */\nexport function Wheel({\n options,\n value,\n onChange,\n loop = false,\n itemHeight = 32,\n visibleRows = 5,\n \"aria-label\": ariaLabel,\n className,\n}: WheelProps) {\n const scroller = React.useRef<HTMLDivElement>(null);\n const reduceMotion = usePrefersReducedMotion();\n const len = options.length;\n const copies = loop ? COPIES : 1;\n const base = loop ? Math.floor(COPIES / 2) * len : 0;\n const maxIndex = len * copies - 1;\n const selected = Math.max(\n 0,\n options.findIndex((o) => o.value === value),\n );\n const pad = ((visibleRows - 1) / 2) * itemHeight;\n\n // Physical row the wheel rests on; the value is `options[resting % len]`.\n const resting = React.useRef(base + selected);\n const drag = React.useRef<Drag | null>(null);\n const fling = React.useRef(0);\n const settleTimer = React.useRef(0);\n const typeahead = React.useRef({ buffer: \"\", timer: 0 });\n // A mouse click is resolved on pointer-up (pointer capture would retarget\n // the click event); the click that follows is then ignored. WebKit labels a\n // touch-synthesised click \"mouse\" too, so the click itself cannot be trusted.\n const clickHandled = React.useRef(false);\n // Timers and animation frames call back after this render; give them the\n // latest handler rather than the one they closed over.\n const onChangeRef = React.useRef(onChange);\n const valueRef = React.useRef(value);\n React.useLayoutEffect(() => {\n onChangeRef.current = onChange;\n valueRef.current = value;\n });\n\n // Only a different row is a change: settling where the wheel already was\n // (including the first layout) must not write anything.\n const report = (physical: number) => {\n const option = optionAt(physical);\n if (option && option.value !== valueRef.current) onChangeRef.current(option.value);\n };\n\n const optionAt = (physical: number) => options.at(mod(physical, len));\n\n // Depth: rows tilt away from the centre, like the drum of a real picker.\n const paint = () => {\n const el = scroller.current;\n if (!el) return;\n const centre = el.scrollTop / itemHeight;\n const rows = el.firstElementChild?.children;\n if (!rows) return;\n const from = Math.max(0, Math.floor(centre) - visibleRows);\n const to = Math.min(rows.length - 1, Math.ceil(centre) + visibleRows);\n const nearest = snapIndex(el.scrollTop, itemHeight);\n for (let i = from; i <= to; i++) {\n const row = rows[i] as HTMLElement;\n const offset = i - centre;\n const angle = clamp(offset * 22, -85, 85);\n row.style.transform = `perspective(600px) rotateX(${-angle}deg)`;\n row.style.opacity = String(clamp(1 - Math.abs(offset) * 0.28, 0.12, 1));\n if (i === nearest) row.dataset.active = \"\";\n else delete row.dataset.active;\n }\n };\n\n const scrollToIndex = (physical: number, smooth: boolean) => {\n const el = scroller.current;\n if (!el) return;\n el.scrollTo({\n top: clamp(physical, 0, maxIndex) * itemHeight,\n behavior: smooth && !reduceMotion ? \"smooth\" : \"auto\",\n });\n };\n\n // Where the wheel stopped becomes the value; looped wheels quietly re-centre.\n const settle = () => {\n const el = scroller.current;\n if (!el || drag.current || fling.current) return;\n let idx = snapIndex(el.scrollTop, itemHeight);\n if (loop) {\n const centred = base + mod(idx, len);\n if (idx !== centred) {\n idx = centred;\n el.scrollTop = idx * itemHeight;\n }\n }\n resting.current = idx;\n report(idx);\n };\n\n const go = (physical: number, smooth = true) => {\n const target = clamp(physical, 0, maxIndex);\n resting.current = target;\n report(target);\n scrollToIndex(target, smooth);\n };\n\n // Initial rest, without animation.\n const mounted = React.useRef(false);\n React.useLayoutEffect(() => {\n if (mounted.current) return;\n mounted.current = true;\n scroller.current?.scrollTo({ top: resting.current * itemHeight });\n paint();\n });\n\n // The value changed from outside (typed into the field, or set by the app).\n React.useEffect(() => {\n if (drag.current || fling.current) return;\n if (options.at(mod(resting.current, len))?.value === value) return;\n const physical = loop ? nearestCopy(selected, resting.current, len, copies) : selected;\n resting.current = physical;\n scroller.current?.scrollTo({\n top: physical * itemHeight,\n behavior: reduceMotion ? \"auto\" : \"smooth\",\n });\n }, [value, options, len, loop, selected, copies, itemHeight, reduceMotion, resting, scroller]);\n\n const onScroll = () => {\n paint();\n // `scrollend` is the real signal; the timer covers engines without it.\n window.clearTimeout(settleTimer.current);\n settleTimer.current = window.setTimeout(settle, 120);\n };\n\n const onScrollEnd = () => {\n window.clearTimeout(settleTimer.current);\n settle();\n };\n\n // Mouse drag: the browser gives touch a fling for free, the mouse needs one.\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (e.pointerType !== \"mouse\" || e.button !== 0) return;\n const el = e.currentTarget;\n cancelAnimationFrame(fling.current);\n fling.current = 0;\n el.setPointerCapture(e.pointerId);\n el.style.scrollSnapType = \"none\";\n drag.current = {\n startY: e.clientY,\n startTop: el.scrollTop,\n lastTop: el.scrollTop,\n lastT: e.timeStamp,\n v: 0,\n moved: false,\n };\n };\n\n const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const d = drag.current;\n if (!d) return;\n const el = e.currentTarget;\n const top = clamp(d.startTop - (e.clientY - d.startY), 0, maxIndex * itemHeight);\n const dt = Math.max(1, e.timeStamp - d.lastT);\n d.v = d.v * 0.5 + ((top - d.lastTop) / dt) * 0.5;\n d.lastTop = top;\n d.lastT = e.timeStamp;\n if (Math.abs(e.clientY - d.startY) > 3) d.moved = true;\n el.scrollTop = top;\n };\n\n const onPointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n const d = drag.current;\n if (!d) return;\n drag.current = null;\n const el = e.currentTarget;\n el.releasePointerCapture(e.pointerId);\n if (!d.moved) {\n // A click: the row under the pointer becomes the value.\n el.style.scrollSnapType = \"\";\n const y = e.clientY - el.getBoundingClientRect().top;\n go(Math.floor((el.scrollTop + y - pad) / itemHeight));\n clickHandled.current = true;\n return;\n }\n clickHandled.current = true;\n const target = flingTarget(\n el.scrollTop,\n e.timeStamp - d.lastT > 80 ? 0 : d.v,\n itemHeight,\n maxIndex,\n );\n const from = el.scrollTop;\n const to = target * itemHeight;\n const duration = reduceMotion ? 0 : clamp(Math.abs(to - from) * 1.2, 180, 720);\n const start = e.timeStamp;\n const step = (now: number) => {\n const t = duration === 0 ? 1 : Math.min(1, (now - start) / duration);\n el.scrollTop = from + (to - from) * easeOutCubic(t);\n if (t < 1) {\n fling.current = requestAnimationFrame(step);\n } else {\n fling.current = 0;\n el.style.scrollSnapType = \"\";\n settle();\n }\n };\n fling.current = requestAnimationFrame(step);\n };\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const r = resting.current;\n const first = loop ? base : 0;\n const last = loop ? base + len - 1 : len - 1;\n switch (e.key) {\n case \"ArrowUp\":\n go(r - 1);\n break;\n case \"ArrowDown\":\n go(r + 1);\n break;\n case \"PageUp\":\n go(r - 5);\n break;\n case \"PageDown\":\n go(r + 5);\n break;\n case \"Home\":\n go(first);\n break;\n case \"End\":\n go(last);\n break;\n default: {\n if (e.key.length !== 1 || e.metaKey || e.ctrlKey || e.altKey) return;\n const ta = typeahead.current;\n window.clearTimeout(ta.timer);\n ta.buffer += e.key.toLowerCase();\n ta.timer = window.setTimeout(() => (ta.buffer = \"\"), TYPEAHEAD_MS);\n const hit = options.findIndex(\n (o) => String(o.value) === ta.buffer || o.label.toLowerCase().startsWith(ta.buffer),\n );\n if (hit === -1) {\n ta.buffer = e.key.toLowerCase();\n const retry = options.findIndex(\n (o) => String(o.value) === ta.buffer || o.label.toLowerCase().startsWith(ta.buffer),\n );\n if (retry === -1) return;\n go(loop ? nearestCopy(retry, r, len, copies) : retry);\n } else {\n go(loop ? nearestCopy(hit, r, len, copies) : hit);\n }\n break;\n }\n }\n e.preventDefault();\n };\n\n const current = options.at(selected);\n\n return (\n <div\n ref={scroller}\n role=\"spinbutton\"\n tabIndex={0}\n aria-label={ariaLabel}\n aria-valuenow={current?.value}\n aria-valuetext={current?.label}\n aria-valuemin={options.at(0)?.value}\n aria-valuemax={options.at(-1)?.value}\n data-slot=\"wheel\"\n onScroll={onScroll}\n onScrollEnd={onScrollEnd}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n onKeyDown={onKeyDown}\n className={cn(\n \"cdp-wheel relative snap-y snap-mandatory overflow-y-scroll overscroll-contain rounded-lg outline-none select-none focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)]\",\n className,\n )}\n style={{ height: visibleRows * itemHeight, scrollbarWidth: \"none\", touchAction: \"pan-y\" }}\n >\n <div aria-hidden style={{ paddingBlock: pad }}>\n {Array.from({ length: len * copies }, (_, i) => {\n const option = options.at(i % len);\n return (\n <div\n key={i}\n role=\"presentation\"\n className=\"flex snap-center items-center justify-center text-[22px] leading-none text-[var(--cdp-secondary)] tabular-nums transition-colors data-active:text-[var(--cdp-label)]\"\n style={{ height: itemHeight }}\n onClick={() => {\n if (clickHandled.current) {\n clickHandled.current = false;\n return;\n }\n go(i);\n }}\n >\n {option?.label}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\n/** The translucent bar behind the centre row, shared by a group of wheels. */\nexport function WheelHighlight({\n itemHeight = 32,\n className,\n}: {\n itemHeight?: number;\n className?: string;\n}) {\n return (\n <div\n aria-hidden\n className={cn(\n \"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2 rounded-lg bg-[var(--cdp-fill)]\",\n className,\n )}\n style={{ height: itemHeight }}\n />\n );\n}\n","import * as React from \"react\";\n\nimport {\n addDays,\n addMonths,\n isDayDisabled,\n isSameDay,\n monthDiff,\n monthGrid,\n shiftMonth,\n startOfDay,\n weekStartFor,\n withDay,\n yearMonthOf,\n type YearMonth,\n} from \"./calendar\";\nimport { formatFullDate, formatMonthYear, monthNames, weekdayNames } from \"./time\";\nimport { cn } from \"./utils\";\nimport { Wheel, WheelHighlight } from \"./wheel\";\n\nexport type CalendarPanelLabels = {\n previousMonth: string;\n nextMonth: string;\n month: string;\n year: string;\n};\n\nexport const CALENDAR_LABELS: CalendarPanelLabels = {\n previousMonth: \"Previous month\",\n nextMonth: \"Next month\",\n month: \"Month\",\n year: \"Year\",\n};\n\nexport type CalendarPanelProps = {\n value: Date | null;\n onChange: (date: Date) => void;\n locale?: string;\n min?: Date;\n max?: Date;\n /** Accessible names; visible text comes from `Intl`. */\n labels?: Partial<CalendarPanelLabels>;\n /** Injected for tests and stories. */\n today?: Date;\n className?: string;\n};\n\nconst YEAR_SPAN = 100;\nconst SWIPE_PX = 40;\n\nfunction Chevron({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 20 20\" className={cn(\"size-5\", className)} aria-hidden fill=\"none\">\n <path\n d=\"M7.5 4.5 13 10l-5.5 5.5\"\n stroke=\"currentColor\"\n strokeWidth=\"2.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\n/**\n * The iOS inline calendar: month title that opens month/year wheels, next\n * and previous month, a grid of circles. Months slide, the wheels cross-fade\n * in over the grid, a horizontal swipe changes month, and the keyboard walks\n * the grid (arrows, Home/End, PageUp/PageDown, Enter).\n */\nexport function CalendarPanel({\n value,\n onChange,\n locale = navigator.language,\n min,\n max,\n labels: labelsProp,\n today: todayProp,\n className,\n}: CalendarPanelProps) {\n const labels = { ...CALENDAR_LABELS, ...labelsProp };\n const today = todayProp ?? startOfDay(new Date());\n const weekStart = weekStartFor(locale);\n const [view, setView] = React.useState<YearMonth>(() => yearMonthOf(value ?? today));\n const [dir, setDir] = React.useState<-1 | 0 | 1>(0);\n const [picking, setPicking] = React.useState(false);\n const [focusDate, setFocusDate] = React.useState<Date>(value ?? today);\n const wantFocus = React.useRef(false);\n const grid = React.useRef<HTMLDivElement>(null);\n const swipe = React.useRef<{ x: number; y: number } | null>(null);\n\n // A value set from outside moves the view to its month.\n const [seen, setSeen] = React.useState(value);\n if (value !== seen) {\n setSeen(value);\n if (value && monthDiff(view, yearMonthOf(value)) !== 0) {\n setDir(0);\n setView(yearMonthOf(value));\n setFocusDate(value);\n }\n }\n\n const show = (next: YearMonth, direction: -1 | 0 | 1) => {\n setDir(direction);\n setView(next);\n };\n const shift = (by: number) => show(shiftMonth(view, by), by > 0 ? 1 : -1);\n\n const canShift = (by: number) => {\n const target = shiftMonth(view, by);\n if (by < 0 && min && monthDiff(yearMonthOf(min), target) < 0) return false;\n if (by > 0 && max && monthDiff(target, yearMonthOf(max)) < 0) return false;\n return true;\n };\n\n const pick = (date: Date) => {\n setFocusDate(date);\n onChange(withDay(value ?? today, date.getFullYear(), date.getMonth(), date.getDate()));\n };\n\n const moveFocus = (next: Date) => {\n if (isDayDisabled(next, min, max)) return;\n wantFocus.current = true;\n setFocusDate(next);\n const diff = monthDiff(view, yearMonthOf(next));\n if (diff !== 0) show(yearMonthOf(next), diff > 0 ? 1 : -1);\n };\n\n React.useEffect(() => {\n if (!wantFocus.current) return;\n wantFocus.current = false;\n grid.current\n ?.querySelector<HTMLButtonElement>(`[data-date=\"${startOfDay(focusDate).getTime()}\"]`)\n ?.focus();\n }, [focusDate]);\n\n const onGridKeyDown = (e: React.KeyboardEvent) => {\n const f = focusDate;\n const jump = new Map<string, () => Date>([\n [\"ArrowLeft\", () => addDays(f, -1)],\n [\"ArrowRight\", () => addDays(f, 1)],\n [\"ArrowUp\", () => addDays(f, -7)],\n [\"ArrowDown\", () => addDays(f, 7)],\n [\"Home\", () => addDays(f, -((f.getDay() - weekStart + 7) % 7))],\n [\"End\", () => addDays(f, 6 - ((f.getDay() - weekStart + 7) % 7))],\n [\"PageUp\", () => addMonths(f, e.shiftKey ? -12 : -1)],\n [\"PageDown\", () => addMonths(f, e.shiftKey ? 12 : 1)],\n ]);\n const to = jump.get(e.key);\n if (!to) return;\n e.preventDefault();\n moveFocus(to());\n };\n\n const onPointerDown = (e: React.PointerEvent) => {\n if (e.pointerType === \"mouse\") return;\n swipe.current = { x: e.clientX, y: e.clientY };\n };\n const onPointerUp = (e: React.PointerEvent) => {\n const s = swipe.current;\n swipe.current = null;\n if (!s) return;\n const dx = e.clientX - s.x;\n if (Math.abs(dx) < SWIPE_PX || Math.abs(dx) < Math.abs(e.clientY - s.y)) return;\n const by = dx < 0 ? 1 : -1;\n if (canShift(by)) shift(by);\n };\n\n const rows = monthGrid(view.year, view.month, weekStart);\n const viewDate = new Date(view.year, view.month, 1);\n const months = monthNames(locale).map((label, month) => ({ value: month, label }));\n const years = Array.from({ length: YEAR_SPAN * 2 + 1 }, (_, i) => {\n const year = today.getFullYear() - YEAR_SPAN + i;\n return { value: year, label: String(year) };\n });\n\n return (\n <div className={cn(\"cdp flex w-[312px] flex-col select-none\", className)} data-slot=\"calendar\">\n <div className=\"flex h-11 items-center justify-between pr-1 pl-2.5\">\n <button\n type=\"button\"\n aria-expanded={picking}\n onClick={() => setPicking((p) => !p)}\n className=\"flex h-9 items-center gap-1 rounded-lg px-1.5 text-[17px] font-semibold tracking-[-0.01em] text-[var(--cdp-label)] transition-opacity outline-none active:opacity-50 focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)]\"\n >\n <span>{formatMonthYear(viewDate, locale)}</span>\n <Chevron\n className={cn(\n \"size-4 text-[var(--cdp-tint)] transition-transform duration-200\",\n picking && \"rotate-90\",\n )}\n />\n </button>\n <div\n className={cn(\n \"flex items-center transition-opacity duration-150\",\n picking && \"pointer-events-none opacity-0\",\n )}\n >\n <button\n type=\"button\"\n aria-label={labels.previousMonth}\n disabled={!canShift(-1)}\n onClick={() => shift(-1)}\n className=\"flex size-11 items-center justify-center rounded-full text-[var(--cdp-tint)] transition-opacity outline-none active:opacity-40 disabled:opacity-30 focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)]\"\n >\n <Chevron className=\"rotate-180\" />\n </button>\n <button\n type=\"button\"\n aria-label={labels.nextMonth}\n disabled={!canShift(1)}\n onClick={() => shift(1)}\n className=\"flex size-11 items-center justify-center rounded-full text-[var(--cdp-tint)] transition-opacity outline-none active:opacity-40 disabled:opacity-30 focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)]\"\n >\n <Chevron />\n </button>\n </div>\n </div>\n\n <div className=\"relative grid px-1.5 pb-1.5\">\n {/* Day grid and the month/year wheels share the cell; one fades out as the other fades in. */}\n <div\n className={cn(\n \"col-start-1 row-start-1 transition-[opacity,transform] duration-200\",\n picking && \"pointer-events-none scale-95 opacity-0\",\n )}\n aria-hidden={picking}\n >\n <div className=\"grid grid-cols-7\" aria-hidden>\n {weekdayNames(locale, weekStart).map((name, i) => (\n <div\n key={i}\n className=\"flex h-8 items-center justify-center text-[13px] font-semibold text-[var(--cdp-tertiary)]\"\n >\n {name}\n </div>\n ))}\n </div>\n <div\n ref={grid}\n role=\"grid\"\n tabIndex={-1}\n aria-label={formatMonthYear(viewDate, locale)}\n key={`${view.year}-${view.month}`}\n data-dir={dir}\n onKeyDown={onGridKeyDown}\n onPointerDown={onPointerDown}\n onPointerUp={onPointerUp}\n className=\"grid grid-cols-7 gap-y-0.5 data-[dir=-1]:animate-[cdp-slide-from-left_240ms_cubic-bezier(0.2,0.9,0.3,1)] data-[dir=1]:animate-[cdp-slide-from-right_240ms_cubic-bezier(0.2,0.9,0.3,1)]\"\n style={{ touchAction: \"pan-y\" }}\n >\n {rows.flat().map(({ date, inMonth }, i) => {\n if (!inMonth) return <div key={i} role=\"gridcell\" aria-hidden />;\n const selected = isSameDay(date, value);\n const isToday = isSameDay(date, today);\n const disabled = isDayDisabled(date, min, max);\n return (\n <button\n key={i}\n type=\"button\"\n role=\"gridcell\"\n aria-selected={selected}\n aria-label={formatFullDate(date, locale)}\n aria-current={isToday ? \"date\" : undefined}\n data-date={startOfDay(date).getTime()}\n data-today={isToday || undefined}\n data-selected={selected || undefined}\n tabIndex={isSameDay(date, focusDate) ? 0 : -1}\n disabled={disabled}\n onClick={() => pick(date)}\n onFocus={() => setFocusDate(date)}\n className={cn(\n \"mx-auto flex size-10 items-center justify-center rounded-full text-[20px] leading-none tabular-nums transition-transform duration-150 outline-none active:scale-90 focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--cdp-bg)] disabled:opacity-30\",\n selected\n ? isToday\n ? \"bg-[var(--cdp-tint)] font-semibold text-[var(--cdp-on-tint)]\"\n : \"bg-[var(--cdp-tint-fill)] font-semibold text-[var(--cdp-tint)]\"\n : isToday\n ? \"text-[var(--cdp-tint)] hover:bg-[var(--cdp-fill)]\"\n : \"text-[var(--cdp-label)] hover:bg-[var(--cdp-fill)]\",\n )}\n >\n {date.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n\n <div\n className={cn(\n \"cdp-wheel-mask relative col-start-1 row-start-1 flex items-center justify-center gap-2 px-2 transition-[opacity,transform] duration-200\",\n !picking && \"pointer-events-none scale-95 opacity-0\",\n )}\n aria-hidden={!picking}\n data-slot=\"month-year\"\n >\n <WheelHighlight className=\"inset-x-2\" />\n <Wheel\n aria-label={labels.month}\n options={months}\n value={view.month}\n loop\n visibleRows={7}\n onChange={(month) => show({ year: view.year, month }, 0)}\n className=\"w-40\"\n />\n <Wheel\n aria-label={labels.year}\n options={years}\n value={view.year}\n visibleRows={7}\n onChange={(year) => show({ year, month: view.month }, 0)}\n className=\"w-24\"\n />\n </div>\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\nexport type SegmentedOption<T> = { value: T; label: string };\n\n/**\n * The iOS segmented control: a translucent track with a white thumb that\n * slides to the chosen segment. Underneath it is a native radio group, so\n * arrow keys, focus and form semantics come from the browser.\n */\nexport function SegmentedControl<T extends string | number | boolean>({\n options,\n value,\n onChange,\n \"aria-label\": ariaLabel,\n className,\n}: {\n options: SegmentedOption<T>[];\n value: T;\n onChange: (value: T) => void;\n \"aria-label\": string;\n className?: string;\n}) {\n const name = React.useId();\n const index = Math.max(\n 0,\n options.findIndex((o) => o.value === value),\n );\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n data-slot=\"segmented-control\"\n className={cn(\n \"relative inline-grid h-8 auto-cols-fr grid-flow-col rounded-[9px] bg-[var(--cdp-fill)] p-0.5\",\n className,\n )}\n >\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-y-0.5 left-0.5 rounded-[7px] bg-[var(--cdp-thumb)] shadow-[0_3px_8px_rgba(0,0,0,0.12),0_3px_1px_rgba(0,0,0,0.04)] transition-transform duration-200 ease-[cubic-bezier(0.2,0,0,1)]\"\n style={{\n width: `calc((100% - 4px) / ${options.length})`,\n transform: `translateX(${index * 100}%)`,\n }}\n />\n {options.map((option) => {\n const checked = option.value === value;\n return (\n <label\n key={String(option.value)}\n className={cn(\n \"relative z-10 flex min-w-12 cursor-pointer items-center justify-center rounded-[7px] px-3 text-[13px] font-semibold transition-colors select-none has-focus-visible:ring-2 has-focus-visible:ring-[var(--cdp-tint)]\",\n checked ? \"text-[var(--cdp-label)]\" : \"text-[var(--cdp-label)]/80 active:opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={name}\n checked={checked}\n onChange={() => onChange(option.value)}\n // Covers the label so the radio itself is the hit target.\n className=\"absolute inset-0 cursor-pointer appearance-none opacity-0\"\n />\n {option.label}\n </label>\n );\n })}\n </div>\n );\n}\n","/**\n * Typing into a two-digit clock segment. The person types digits; the segment\n * shows what has been typed, commits as soon as the digits name a value, and\n * says when it is done so focus can move on (the second digit arrived, or no\n * further digit could still fit under `max`).\n */\nexport type DigitStep = { buffer: string; value: number | null; done: boolean };\n\nexport function typeDigit(buffer: string, digit: string, min: number, max: number): DigitStep {\n const next = buffer.length >= 2 ? digit : buffer + digit;\n const n = Number(next);\n if (n > max) {\n // The pair cannot be a value: start over with just this digit.\n const d = Number(digit);\n return d > max || d < min\n ? { buffer: \"\", value: null, done: false }\n : { buffer: digit, value: d, done: d * 10 > max };\n }\n return { buffer: next, value: n >= min ? n : null, done: next.length === 2 || n * 10 > max };\n}\n\n/** Step within [min, max], wrapping at both ends. */\nexport function stepValue(value: number, by: number, min: number, max: number): number {\n const span = max - min + 1;\n return min + ((((value - min + by) % span) + span) % span);\n}\n","import * as React from \"react\";\n\nimport { withTime } from \"./calendar\";\nimport { SegmentedControl } from \"./segmented-control\";\nimport { stepValue, typeDigit } from \"./segments\";\nimport { dayPeriodLabels, hourCycleFor, to12, to24, type HourCycle } from \"./time\";\nimport { cn, pad2 } from \"./utils\";\nimport { Wheel, WheelHighlight } from \"./wheel\";\n\nexport type TimePanelLabels = {\n time: string;\n hour: string;\n minute: string;\n dayPeriod: string;\n};\n\nexport const TIME_LABELS: TimePanelLabels = {\n time: \"Time\",\n hour: \"Hour\",\n minute: \"Minute\",\n dayPeriod: \"Day period\",\n};\n\nexport type TimePanelProps = {\n value: Date;\n onChange: (date: Date) => void;\n locale?: string;\n hourCycle?: HourCycle;\n /** Accessible names; visible text comes from `Intl`. */\n labels?: Partial<TimePanelLabels>;\n /** Minute wheel granularity, like `UIDatePicker.minuteInterval`. */\n minuteInterval?: number;\n /** Hide the wheels and keep only the typed field. */\n wheels?: boolean;\n className?: string;\n};\n\ntype Segment = \"hour\" | \"minute\";\n\n/**\n * Time entry the way iOS 14+ does it, both halves at once: a field of\n * segments that takes digits from a keyboard or keypad and steps with the\n * arrows, and the hour / minute / period wheels underneath. Either side\n * moves the other — type \"930\" and the wheels spin there; fling a wheel and\n * the digits follow.\n */\nexport function TimePanel({\n value,\n onChange,\n locale = navigator.language,\n hourCycle: hourCycleProp,\n minuteInterval = 1,\n wheels = true,\n labels: labelsProp,\n className,\n}: TimePanelProps) {\n const labels = { ...TIME_LABELS, ...labelsProp };\n const hourCycle = hourCycleProp ?? hourCycleFor(locale);\n const twelve = hourCycle === \"h12\";\n const hours24 = value.getHours();\n const minutes = value.getMinutes();\n const { hour: hour12, pm } = to12(hours24);\n const hourShown = twelve ? hour12 : hours24;\n const hourMin = twelve ? 1 : 0;\n const hourMax = twelve ? 12 : 23;\n const periods = dayPeriodLabels(locale);\n\n const [typing, setTyping] = React.useState<{ segment: Segment; buffer: string } | null>(null);\n const hourRef = React.useRef<HTMLInputElement>(null);\n const minuteRef = React.useRef<HTMLInputElement>(null);\n\n const setHour = (shown: number) =>\n onChange(withTime(value, twelve ? to24(shown, pm) : shown, minutes));\n const setMinute = (m: number) => onChange(withTime(value, hours24, m));\n const setPm = (next: boolean) => onChange(withTime(value, to24(hour12, next), minutes));\n\n const focusSegment = (segment: Segment) => {\n const el = segment === \"hour\" ? hourRef.current : minuteRef.current;\n el?.focus();\n el?.select();\n };\n\n const typeInto = (segment: Segment, digit: string) => {\n const buffer = typing?.segment === segment ? typing.buffer : \"\";\n const step =\n segment === \"hour\"\n ? typeDigit(buffer, digit, hourMin, hourMax)\n : typeDigit(buffer, digit, 0, 59);\n if (step.value !== null) (segment === \"hour\" ? setHour : setMinute)(step.value);\n if (step.done) {\n setTyping(null);\n if (segment === \"hour\") focusSegment(\"minute\");\n } else {\n setTyping({ segment, buffer: step.buffer });\n }\n };\n\n const onSegmentKeyDown = (segment: Segment) => (e: React.KeyboardEvent<HTMLInputElement>) => {\n const key = e.key;\n if (/^\\d$/.test(key)) {\n e.preventDefault();\n typeInto(segment, key);\n return;\n }\n const by = key === \"ArrowUp\" ? 1 : key === \"ArrowDown\" ? -1 : 0;\n if (by) {\n e.preventDefault();\n setTyping(null);\n if (segment === \"hour\") setHour(stepValue(hourShown, by, hourMin, hourMax));\n else setMinute(stepValue(minutes, by * minuteInterval, 0, 59));\n return;\n }\n if (key === \"ArrowLeft\" && segment === \"minute\") {\n e.preventDefault();\n focusSegment(\"hour\");\n } else if (key === \"ArrowRight\" && segment === \"hour\") {\n e.preventDefault();\n focusSegment(\"minute\");\n } else if (key === \"Backspace\" || key === \"Delete\") {\n e.preventDefault();\n setTyping({ segment, buffer: \"\" });\n } else if (twelve && (key === \"a\" || key === \"A\" || key === \"p\" || key === \"P\")) {\n e.preventDefault();\n setPm(key === \"p\" || key === \"P\");\n } else if (key === \"Enter\") {\n e.currentTarget.blur();\n } else if (key.length === 1 && !e.metaKey && !e.ctrlKey) {\n e.preventDefault();\n }\n };\n\n // Mobile keypads and IMEs insert text without a key name; `beforeinput`\n // carries the digit either way.\n const onBeforeInput = (segment: Segment) => (e: React.FormEvent<HTMLInputElement>) => {\n e.preventDefault();\n const data = (e.nativeEvent as InputEvent).data ?? \"\";\n for (const ch of data) if (/\\d/.test(ch)) typeInto(segment, ch);\n };\n\n // An engine that skipped `beforeinput` still changes the input: whatever\n // was added to the shown text is what was typed.\n const onInput = (segment: Segment) => (e: React.ChangeEvent<HTMLInputElement>) => {\n const added = e.target.value.replace(shownText(segment), \"\");\n for (const ch of added) if (/\\d/.test(ch)) typeInto(segment, ch);\n };\n\n const shownText = (segment: Segment) => {\n if (typing?.segment === segment) return typing.buffer;\n if (segment === \"hour\") return twelve ? String(hourShown) : pad2(hourShown);\n return pad2(minutes);\n };\n\n const segmentClass =\n \"box-content h-10 rounded-md bg-transparent px-1 text-center text-[32px] leading-none font-light tabular-nums text-[var(--cdp-label)] caret-transparent outline-none selection:bg-transparent focus:bg-[var(--cdp-tint-fill)] focus:text-[var(--cdp-tint)]\";\n\n const hourOptions = Array.from({ length: hourMax - hourMin + 1 }, (_, i) => {\n const h = hourMin + i;\n return { value: h, label: twelve ? String(h) : pad2(h) };\n });\n const minuteOptions = Array.from({ length: Math.ceil(60 / minuteInterval) }, (_, i) => ({\n value: i * minuteInterval,\n label: pad2(i * minuteInterval),\n }));\n\n return (\n <div\n className={cn(\"cdp flex w-[280px] flex-col gap-2 p-3 select-none\", className)}\n data-slot=\"time\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <div\n role=\"group\"\n aria-label={labels.time}\n className=\"flex h-11 items-center rounded-lg bg-[var(--cdp-fill)] px-1.5\"\n data-slot=\"time-field\"\n >\n <input\n ref={hourRef}\n aria-label={labels.hour}\n inputMode=\"numeric\"\n autoComplete=\"off\"\n value={shownText(\"hour\")}\n onChange={onInput(\"hour\")}\n onBeforeInput={onBeforeInput(\"hour\")}\n onKeyDown={onSegmentKeyDown(\"hour\")}\n onFocus={(e) => e.currentTarget.select()}\n onBlur={() => setTyping(null)}\n className={segmentClass}\n style={{ width: `${Math.max(1, shownText(\"hour\").length || 1)}ch` }}\n data-segment=\"hour\"\n />\n <span\n className=\"-mx-0.5 text-[32px] leading-none font-light text-[var(--cdp-label)]\"\n aria-hidden\n >\n :\n </span>\n <input\n ref={minuteRef}\n aria-label={labels.minute}\n inputMode=\"numeric\"\n autoComplete=\"off\"\n value={shownText(\"minute\")}\n onChange={onInput(\"minute\")}\n onBeforeInput={onBeforeInput(\"minute\")}\n onKeyDown={onSegmentKeyDown(\"minute\")}\n onFocus={(e) => e.currentTarget.select()}\n onBlur={() => setTyping(null)}\n className={segmentClass}\n style={{ width: \"2ch\" }}\n data-segment=\"minute\"\n />\n </div>\n {twelve && (\n <SegmentedControl\n aria-label={labels.dayPeriod}\n options={[\n { value: false, label: periods.am },\n { value: true, label: periods.pm },\n ]}\n value={pm}\n onChange={setPm}\n />\n )}\n </div>\n\n {wheels && (\n <div className=\"cdp-wheel-mask relative flex justify-center\" data-slot=\"time-wheels\">\n <WheelHighlight />\n <Wheel\n aria-label={labels.hour}\n options={hourOptions}\n value={hourShown}\n loop\n onChange={setHour}\n className=\"w-16\"\n />\n <Wheel\n aria-label={labels.minute}\n options={minuteOptions}\n value={minutes - (minutes % minuteInterval)}\n loop\n onChange={setMinute}\n className=\"w-16\"\n />\n {twelve && (\n <Wheel\n aria-label={labels.dayPeriod}\n options={[\n { value: 0, label: periods.am },\n { value: 1, label: periods.pm },\n ]}\n value={pm ? 1 : 0}\n onChange={(v) => setPm(v === 1)}\n className=\"w-16\"\n />\n )}\n </div>\n )}\n </div>\n );\n}\n","import { Popover } from \"@base-ui/react/popover\";\n\nimport { CalendarPanel } from \"./calendar-panel\";\nimport { useControlled } from \"./hooks\";\nimport { formatClock, formatDay, hourCycleFor, type HourCycle } from \"./time\";\nimport { TimePanel } from \"./time-panel\";\nimport { cn } from \"./utils\";\n\nexport type DateTimePickerProps = {\n value?: Date | null;\n defaultValue?: Date | null;\n onChange?: (date: Date | null) => void;\n /** Which parts are editable — `UIDatePicker.Mode`. */\n mode?: \"date\" | \"time\" | \"dateTime\";\n /** Pills that open popovers (`.compact`), or the panels laid out in place (`.inline`). */\n display?: \"compact\" | \"inline\";\n locale?: string;\n hourCycle?: HourCycle;\n minuteInterval?: number;\n min?: Date;\n max?: Date;\n disabled?: boolean;\n className?: string;\n /** Placeholder labels when there is no value. */\n labels?: { date?: string; time?: string };\n};\n\n/** The compact pill and its popover, for composing your own rows. */\nexport const pillClass =\n \"inline-flex h-[34px] items-center rounded-lg bg-[var(--cdp-fill)] px-3 text-[17px] leading-none text-[var(--cdp-label)] transition-[background-color,color] outline-none hover:bg-[var(--cdp-fill-hover)] focus-visible:ring-2 focus-visible:ring-[var(--cdp-tint)] active:opacity-60 disabled:opacity-40 data-popup-open:text-[var(--cdp-tint)]\";\n\nexport const popupClass =\n \"cdp origin-(--transform-origin) rounded-[13px] bg-[var(--cdp-bg)] shadow-[var(--cdp-shadow)] outline-none data-open:animate-[cdp-pop-in_260ms_cubic-bezier(0.18,0.9,0.32,1.15)] data-closed:animate-[cdp-pop-out_140ms_ease-in]\";\n\n/**\n * The iOS 14+ date picker for the web. Compact display shows the date and\n * time as pills; each opens a popover — the calendar or the time panel —\n * anchored to it. Inline display lays the panels out in place.\n */\nexport function DateTimePicker({\n value: valueProp,\n defaultValue = null,\n onChange,\n mode = \"dateTime\",\n display = \"compact\",\n locale = navigator.language,\n hourCycle: hourCycleProp,\n minuteInterval = 1,\n min,\n max,\n disabled = false,\n className,\n labels,\n}: DateTimePickerProps) {\n const [value, setValue] = useControlled(valueProp, defaultValue, onChange);\n const hourCycle = hourCycleProp ?? hourCycleFor(locale);\n const showDate = mode !== \"time\";\n const showTime = mode !== \"date\";\n // Panels always have something to edit; a picked day or time starts from now.\n const draft = value ?? new Date();\n\n const calendar = (\n <CalendarPanel value={value} onChange={setValue} locale={locale} min={min} max={max} />\n );\n const time = (\n <TimePanel\n value={draft}\n onChange={setValue}\n locale={locale}\n hourCycle={hourCycle}\n minuteInterval={minuteInterval}\n />\n );\n\n const timePopover = (\n <Popover.Root>\n <Popover.Trigger className={pillClass} disabled={disabled} data-slot=\"time-trigger\">\n {value ? formatClock(value, locale, hourCycle) : (labels?.time ?? \"Time\")}\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Positioner sideOffset={8} align=\"center\" className=\"isolate z-50\">\n <Popover.Popup className={popupClass} data-slot=\"time-popup\">\n {time}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n\n if (display === \"inline\") {\n return (\n <div\n className={cn(\n \"cdp inline-flex flex-col items-stretch rounded-[13px] bg-[var(--cdp-bg)]\",\n className,\n )}\n data-slot=\"date-time-picker\"\n data-display=\"inline\"\n >\n {showDate && calendar}\n {/* As on iOS: the time sits on a \"Time\" row under the calendar and opens the wheels. */}\n {showTime &&\n (showDate ? (\n <div className=\"mx-3 flex h-[52px] items-center justify-between border-t border-[var(--cdp-fill)]\">\n <span className=\"text-[17px] text-[var(--cdp-label)]\">{labels?.time ?? \"Time\"}</span>\n {timePopover}\n </div>\n ) : (\n time\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={cn(\"cdp inline-flex items-center gap-2\", className)}\n data-slot=\"date-time-picker\"\n data-display=\"compact\"\n >\n {showDate && (\n <Popover.Root>\n <Popover.Trigger className={pillClass} disabled={disabled} data-slot=\"date-trigger\">\n {value ? formatDay(value, locale) : (labels?.date ?? \"Date\")}\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Positioner sideOffset={8} align=\"center\" className=\"isolate z-50\">\n <Popover.Popup className={popupClass} data-slot=\"date-popup\">\n {calendar}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n )}\n {showTime && timePopover}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ export type SegmentedOption<T> = {
3
+ value: T;
4
+ label: string;
5
+ };
6
+ /**
7
+ * The iOS segmented control: a translucent track with a white thumb that
8
+ * slides to the chosen segment. Underneath it is a native radio group, so
9
+ * arrow keys, focus and form semantics come from the browser.
10
+ */
11
+ export declare function SegmentedControl<T extends string | number | boolean>({ options, value, onChange, "aria-label": ariaLabel, className, }: {
12
+ options: SegmentedOption<T>[];
13
+ value: T;
14
+ onChange: (value: T) => void;
15
+ "aria-label": string;
16
+ className?: string;
17
+ }): React.JSX.Element;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Typing into a two-digit clock segment. The person types digits; the segment
3
+ * shows what has been typed, commits as soon as the digits name a value, and
4
+ * says when it is done so focus can move on (the second digit arrived, or no
5
+ * further digit could still fit under `max`).
6
+ */
7
+ export type DigitStep = {
8
+ buffer: string;
9
+ value: number | null;
10
+ done: boolean;
11
+ };
12
+ export declare function typeDigit(buffer: string, digit: string, min: number, max: number): DigitStep;
13
+ /** Step within [min, max], wrapping at both ends. */
14
+ export declare function stepValue(value: number, by: number, min: number, max: number): number;
@@ -0,0 +1,30 @@
1
+ import { HourCycle } from './time';
2
+ import * as React from "react";
3
+ export type TimePanelLabels = {
4
+ time: string;
5
+ hour: string;
6
+ minute: string;
7
+ dayPeriod: string;
8
+ };
9
+ export declare const TIME_LABELS: TimePanelLabels;
10
+ export type TimePanelProps = {
11
+ value: Date;
12
+ onChange: (date: Date) => void;
13
+ locale?: string;
14
+ hourCycle?: HourCycle;
15
+ /** Accessible names; visible text comes from `Intl`. */
16
+ labels?: Partial<TimePanelLabels>;
17
+ /** Minute wheel granularity, like `UIDatePicker.minuteInterval`. */
18
+ minuteInterval?: number;
19
+ /** Hide the wheels and keep only the typed field. */
20
+ wheels?: boolean;
21
+ className?: string;
22
+ };
23
+ /**
24
+ * Time entry the way iOS 14+ does it, both halves at once: a field of
25
+ * segments that takes digits from a keyboard or keypad and steps with the
26
+ * arrows, and the hour / minute / period wheels underneath. Either side
27
+ * moves the other — type "930" and the wheels spin there; fling a wheel and
28
+ * the digits follow.
29
+ */
30
+ export declare function TimePanel({ value, onChange, locale, hourCycle: hourCycleProp, minuteInterval, wheels, labels: labelsProp, className, }: TimePanelProps): React.JSX.Element;
package/dist/time.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Clock helpers on top of `Intl`, so 12/24-hour, day-period labels, and month
3
+ * and weekday names all follow the locale instead of a hard-coded table.
4
+ */
5
+ export type HourCycle = "h12" | "h23";
6
+ export declare function hourCycleFor(locale: string): HourCycle;
7
+ export declare function to12(hour24: number): {
8
+ hour: number;
9
+ pm: boolean;
10
+ };
11
+ export declare function to24(hour12: number, pm: boolean): number;
12
+ export declare function dayPeriodLabels(locale: string): {
13
+ am: string;
14
+ pm: string;
15
+ };
16
+ export declare function monthNames(locale: string, style?: "long" | "short"): string[];
17
+ /** Seven names starting on `weekStart` (0 = Sunday). */
18
+ export declare function weekdayNames(locale: string, weekStart: number, style?: "narrow" | "short"): string[];
19
+ /** The locale's medium date, as the iOS pill shows it: "Sep 5, 2026", "05.09.2026", "2026年9月5日". */
20
+ export declare function formatDay(date: Date, locale: string): string;
21
+ /** "6:30 PM" on a 12-hour clock, "06:30" on a 24-hour one. */
22
+ export declare function formatClock(date: Date, locale: string, hourCycle: HourCycle): string;
23
+ export declare function formatMonthYear(date: Date, locale: string): string;
24
+ export declare function formatFullDate(date: Date, locale: string): string;
@@ -0,0 +1,6 @@
1
+ import { ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
3
+ export declare function clamp(n: number, min: number, max: number): number;
4
+ /** Wrap `n` into [0, len). */
5
+ export declare function mod(n: number, len: number): number;
6
+ export declare function pad2(n: number): string;
@@ -0,0 +1,11 @@
1
+ /** The row a scroll offset rests on. */
2
+ export declare function snapIndex(scrollTop: number, itemHeight: number): number;
3
+ /**
4
+ * Where a released drag comes to rest. `velocity` is d(scrollTop)/dt in
5
+ * px/ms; the projection mirrors UIScrollView's normal deceleration, then
6
+ * lands on a row.
7
+ */
8
+ export declare function flingTarget(scrollTop: number, velocity: number, itemHeight: number, maxIndex: number): number;
9
+ /** Of the copies of `logical` in a looped wheel, the one nearest `from`. */
10
+ export declare function nearestCopy(logical: number, from: number, len: number, copies: number): number;
11
+ export declare function easeOutCubic(t: number): number;
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ export type WheelOption = {
3
+ value: number;
4
+ label: string;
5
+ };
6
+ export type WheelProps = {
7
+ options: WheelOption[];
8
+ value: number;
9
+ onChange: (value: number) => void;
10
+ /** Hours and minutes wrap around like the iOS clock wheels. */
11
+ loop?: boolean;
12
+ itemHeight?: number;
13
+ visibleRows?: number;
14
+ "aria-label": string;
15
+ className?: string;
16
+ };
17
+ /**
18
+ * One column of an iOS picker: native scrolling with snap points (so touch
19
+ * and trackpad flings come from the platform), mouse drag with its own
20
+ * deceleration, a click on any row, and the keyboard — arrows step, digits
21
+ * jump. The centre row is the value; the parent draws the highlight bar.
22
+ */
23
+ export declare function Wheel({ options, value, onChange, loop, itemHeight, visibleRows, "aria-label": ariaLabel, className, }: WheelProps): React.JSX.Element;
24
+ /** The translucent bar behind the centre row, shared by a group of wheels. */
25
+ export declare function WheelHighlight({ itemHeight, className, }: {
26
+ itemHeight?: number;
27
+ className?: string;
28
+ }): React.JSX.Element;
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "cupertino-datetime-picker",
3
+ "version": "0.1.0",
4
+ "description": "iOS-style compact date & time picker for React: an inline calendar with month/year wheels, and time wheels that also take typing. Built for shadcn/ui on Base UI.",
5
+ "keywords": [
6
+ "base-ui",
7
+ "cupertino",
8
+ "date-picker",
9
+ "datetime-picker",
10
+ "ios",
11
+ "react",
12
+ "shadcn",
13
+ "tailwind",
14
+ "time-picker",
15
+ "wheel-picker"
16
+ ],
17
+ "homepage": "https://cupertino-datetime-picker-docs.vercel.app",
18
+ "bugs": {
19
+ "url": "https://github.com/fanzzzd/cupertino-datetime-picker/issues"
20
+ },
21
+ "license": "MIT",
22
+ "author": "fanzzzd",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/fanzzzd/cupertino-datetime-picker.git"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "src",
30
+ "registry.json"
31
+ ],
32
+ "type": "module",
33
+ "sideEffects": [
34
+ "*.css"
35
+ ],
36
+ "module": "./dist/index.js",
37
+ "types": "./dist/index.d.ts",
38
+ "exports": {
39
+ ".": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/index.js"
42
+ },
43
+ "./styles.css": "./src/styles.css"
44
+ },
45
+ "scripts": {
46
+ "dev": "vite",
47
+ "build": "vite build --mode lib",
48
+ "build:demo": "vite build",
49
+ "registry:build": "shadcn build -o docs/public/r",
50
+ "test": "vitest run",
51
+ "e2e": "playwright test",
52
+ "typecheck": "tsc --noEmit",
53
+ "lint": "oxlint && oxfmt --check .",
54
+ "fmt": "oxfmt .",
55
+ "check": "pnpm typecheck && pnpm lint && pnpm test && pnpm build",
56
+ "docs": "pnpm -C docs dev",
57
+ "docs:build": "pnpm -C docs build",
58
+ "docs:typecheck": "pnpm -C docs typecheck",
59
+ "prepublishOnly": "pnpm check"
60
+ },
61
+ "dependencies": {
62
+ "clsx": "^2.1.1",
63
+ "tailwind-merge": "^3.6.0"
64
+ },
65
+ "devDependencies": {
66
+ "@base-ui/react": "1.8.0",
67
+ "@playwright/test": "1.61.1",
68
+ "@tailwindcss/vite": "4.3.3",
69
+ "@types/node": "^24.13.3",
70
+ "@types/react": "19.2.18",
71
+ "@types/react-dom": "19.2.7",
72
+ "@vitejs/plugin-react": "6.1.1",
73
+ "oxfmt": "0.66.0",
74
+ "oxlint": "1.81.0",
75
+ "react": "19.2.8",
76
+ "react-dom": "19.2.8",
77
+ "shadcn": "4.21.0",
78
+ "tailwindcss": "4.3.3",
79
+ "typescript": "^5.9.0",
80
+ "vite": "8.2.2",
81
+ "vite-plugin-dts": "5.1.0",
82
+ "vitest": "5.0.0"
83
+ },
84
+ "peerDependencies": {
85
+ "@base-ui/react": ">=1.4.0",
86
+ "react": "^19.0.0",
87
+ "react-dom": "^19.0.0"
88
+ },
89
+ "packageManager": "pnpm@11.17.0"
90
+ }
package/registry.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry.json",
3
+ "name": "cupertino-datetime-picker",
4
+ "homepage": "https://cupertino-datetime-picker-docs.vercel.app",
5
+ "items": [
6
+ {
7
+ "name": "cupertino-datetime-picker",
8
+ "type": "registry:ui",
9
+ "title": "Cupertino Date & Time Picker",
10
+ "description": "The iOS 14+ compact date & time picker: inline calendar with month/year wheels, time wheels that also take typing. Base UI popovers, Tailwind, no date library.",
11
+ "dependencies": ["@base-ui/react", "clsx", "tailwind-merge"],
12
+ "files": [
13
+ {
14
+ "path": "src/date-time-picker.tsx",
15
+ "type": "registry:ui",
16
+ "target": "components/ui/cupertino/date-time-picker.tsx"
17
+ },
18
+ {
19
+ "path": "src/calendar-panel.tsx",
20
+ "type": "registry:ui",
21
+ "target": "components/ui/cupertino/calendar-panel.tsx"
22
+ },
23
+ {
24
+ "path": "src/time-panel.tsx",
25
+ "type": "registry:ui",
26
+ "target": "components/ui/cupertino/time-panel.tsx"
27
+ },
28
+ {
29
+ "path": "src/wheel.tsx",
30
+ "type": "registry:ui",
31
+ "target": "components/ui/cupertino/wheel.tsx"
32
+ },
33
+ {
34
+ "path": "src/segmented-control.tsx",
35
+ "type": "registry:ui",
36
+ "target": "components/ui/cupertino/segmented-control.tsx"
37
+ },
38
+ {
39
+ "path": "src/hooks.ts",
40
+ "type": "registry:ui",
41
+ "target": "components/ui/cupertino/hooks.ts"
42
+ },
43
+ {
44
+ "path": "src/calendar.ts",
45
+ "type": "registry:ui",
46
+ "target": "components/ui/cupertino/calendar.ts"
47
+ },
48
+ {
49
+ "path": "src/time.ts",
50
+ "type": "registry:ui",
51
+ "target": "components/ui/cupertino/time.ts"
52
+ },
53
+ {
54
+ "path": "src/segments.ts",
55
+ "type": "registry:ui",
56
+ "target": "components/ui/cupertino/segments.ts"
57
+ },
58
+ {
59
+ "path": "src/wheel-math.ts",
60
+ "type": "registry:ui",
61
+ "target": "components/ui/cupertino/wheel-math.ts"
62
+ },
63
+ {
64
+ "path": "src/utils.ts",
65
+ "type": "registry:ui",
66
+ "target": "components/ui/cupertino/utils.ts"
67
+ },
68
+ {
69
+ "path": "src/styles.css",
70
+ "type": "registry:file",
71
+ "target": "components/ui/cupertino/styles.css"
72
+ }
73
+ ]
74
+ }
75
+ ]
76
+ }