@ttt-productions/ui-core 0.11.7 → 0.11.9

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.
@@ -7,11 +7,23 @@ export interface DatePickerProps {
7
7
  disableFuture?: boolean;
8
8
  className?: string;
9
9
  }
10
- /** Calendar with fast month/year navigation: the header's month and year are
11
- * each buttons — month opens a 12-month grid, year opens a paged 12-year
12
- * grid (no single-step year arrows; distant years are a couple of clicks).
13
- * Picking a year drills to the month grid, then the day grid — the natural
14
- * date-of-birth path — while picking just a month returns straight to days. */
10
+ /**
11
+ * Generic date-of-birth-friendly calendar.
12
+ *
13
+ * Stable footprint: the six-row day grid is always rendered, so the outer width
14
+ * and content height never change; the month and year choosers render as an
15
+ * overlay ON TOP of that grid rather than replacing it, so a Radix popover never
16
+ * flips sides just because the internal view changed.
17
+ *
18
+ * Month and year are INDEPENDENT pickers: choosing a month keeps the current
19
+ * year and returns to the day grid; choosing a year keeps the current month and
20
+ * returns DIRECTLY to the day grid (it never opens the month grid). Only
21
+ * choosing a day calls `onSelect` (which commits and, in a popover, closes).
22
+ *
23
+ * Keyboard: roving day focus with Arrow (±1 day / ±7 days), Home/End (within the
24
+ * week), PageUp/PageDown (±1 month), and Enter/Space to select — no extra
25
+ * dependency. Exactly one day sits in the tab order at a time.
26
+ */
15
27
  declare function DatePicker({ selected, onSelect, disabled, disablePast, disableFuture, className, }: DatePickerProps): React.JSX.Element;
16
28
  declare namespace DatePicker {
17
29
  var displayName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../../../src/react/components/date-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAA;IAClC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgBD;;;;gFAIgF;AAChF,iBAAS,UAAU,CAAC,EAClB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,WAAmB,EACnB,aAAqB,EACrB,SAAS,GACV,EAAE,eAAe,qBAoSjB;kBA3SQ,UAAU;;;AA+SnB,OAAO,EAAE,UAAU,EAAE,CAAA"}
1
+ {"version":3,"file":"date-picker.d.ts","sourceRoot":"","sources":["../../../src/react/components/date-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAA;IAClC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAqCD;;;;;;;;;;;;;;;;GAgBG;AACH,iBAAS,UAAU,CAAC,EAClB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,WAAmB,EACnB,aAAqB,EACrB,SAAS,GACV,EAAE,eAAe,qBAuejB;kBA9eQ,UAAU;;;AAkfnB,OAAO,EAAE,UAAU,EAAE,CAAA"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { ChevronLeft, ChevronRight } from "lucide-react";
5
5
  import { Button } from "./button.js";
@@ -13,31 +13,52 @@ const MONTHS_SHORT = [
13
13
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
14
14
  ];
15
15
  const DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
16
+ const DAY_NAMES_LONG = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
16
17
  const YEARS_PER_PAGE = 12;
17
- /** Calendar with fast month/year navigation: the header's month and year are
18
- * each buttons — month opens a 12-month grid, year opens a paged 12-year
19
- * grid (no single-step year arrows; distant years are a couple of clicks).
20
- * Picking a year drills to the month grid, then the day grid — the natural
21
- * date-of-birth path — while picking just a month returns straight to days. */
18
+ /** Six rows × seven columns — a calendar month never spans more, and always
19
+ * filling six rows keeps the day grid (and therefore the whole popover
20
+ * footprint) the same height for every month. */
21
+ const CALENDAR_CELLS = 42;
22
+ const startOfDay = (d) => {
23
+ const x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
24
+ return x;
25
+ };
26
+ const monthStart = (year, month) => new Date(year, month, 1);
27
+ const addMonths = (d, n) => new Date(d.getFullYear(), d.getMonth() + n, 1);
28
+ const daysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
29
+ const isSameDay = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
30
+ const isSameMonth = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
31
+ const fullDateLabel = (date) => `${MONTHS[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
32
+ /**
33
+ * Generic date-of-birth-friendly calendar.
34
+ *
35
+ * Stable footprint: the six-row day grid is always rendered, so the outer width
36
+ * and content height never change; the month and year choosers render as an
37
+ * overlay ON TOP of that grid rather than replacing it, so a Radix popover never
38
+ * flips sides just because the internal view changed.
39
+ *
40
+ * Month and year are INDEPENDENT pickers: choosing a month keeps the current
41
+ * year and returns to the day grid; choosing a year keeps the current month and
42
+ * returns DIRECTLY to the day grid (it never opens the month grid). Only
43
+ * choosing a day calls `onSelect` (which commits and, in a popover, closes).
44
+ *
45
+ * Keyboard: roving day focus with Arrow (±1 day / ±7 days), Home/End (within the
46
+ * week), PageUp/PageDown (±1 month), and Enter/Space to select — no extra
47
+ * dependency. Exactly one day sits in the tab order at a time.
48
+ */
22
49
  function DatePicker({ selected, onSelect, disabled, disablePast = false, disableFuture = false, className, }) {
23
- const [viewDate, setViewDate] = React.useState(() => selected || new Date());
50
+ const today = React.useMemo(() => startOfDay(new Date()), []);
51
+ const [viewDate, setViewDate] = React.useState(() => monthStart((selected ?? today).getFullYear(), (selected ?? today).getMonth()));
24
52
  const [view, setView] = React.useState("days");
25
- const [yearPageStart, setYearPageStart] = React.useState(() => Math.floor((selected || new Date()).getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE);
26
- const today = new Date();
27
- today.setHours(0, 0, 0, 0);
28
- const getDaysInMonth = (date) => {
29
- const year = date.getFullYear();
30
- const month = date.getMonth();
31
- return new Date(year, month + 1, 0).getDate();
32
- };
33
- const getFirstDayOfMonth = (date) => {
34
- const year = date.getFullYear();
35
- const month = date.getMonth();
36
- return new Date(year, month, 1).getDay();
37
- };
53
+ const [yearPageStart, setYearPageStart] = React.useState(() => Math.floor((selected ?? today).getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE);
54
+ const [focusedDate, setFocusedDate] = React.useState(() => startOfDay(selected ?? today));
55
+ const monthTriggerRef = React.useRef(null);
56
+ const yearTriggerRef = React.useRef(null);
57
+ const daysGridRef = React.useRef(null);
58
+ const overlayRef = React.useRef(null);
59
+ const pendingFocusRef = React.useRef(null);
38
60
  const isDateDisabled = (date) => {
39
- const checkDate = new Date(date);
40
- checkDate.setHours(0, 0, 0, 0);
61
+ const checkDate = startOfDay(date);
41
62
  if (disablePast && checkDate < today)
42
63
  return true;
43
64
  if (disableFuture && checkDate > today)
@@ -61,67 +82,260 @@ function DatePicker({ selected, onSelect, disabled, disablePast = false, disable
61
82
  return true;
62
83
  return false;
63
84
  };
64
- const isDateSelected = (date) => {
65
- if (!selected)
66
- return false;
67
- const selectedDate = new Date(selected);
68
- selectedDate.setHours(0, 0, 0, 0);
69
- const checkDate = new Date(date);
70
- checkDate.setHours(0, 0, 0, 0);
71
- return selectedDate.getTime() === checkDate.getTime();
85
+ const rangeAllYearsDisabled = (from, to) => {
86
+ for (let y = from; y <= to; y++)
87
+ if (!isYearDisabled(y))
88
+ return false;
89
+ return true;
72
90
  };
73
- const isToday = (date) => {
74
- const checkDate = new Date(date);
75
- checkDate.setHours(0, 0, 0, 0);
76
- return checkDate.getTime() === today.getTime();
91
+ const isSelectedDay = (date) => (selected ? isSameDay(startOfDay(selected), startOfDay(date)) : false);
92
+ const isTodayDate = (date) => isSameDay(startOfDay(date), today);
93
+ /** The best in-month day to seed roving focus: the selected day, then today,
94
+ * then the first available day, then the 1st. */
95
+ const pickInMonthFocus = (vd) => {
96
+ const year = vd.getFullYear();
97
+ const month = vd.getMonth();
98
+ if (selected) {
99
+ const s = startOfDay(selected);
100
+ if (isSameMonth(s, vd) && !isDateDisabled(s))
101
+ return s;
102
+ }
103
+ if (isSameMonth(today, vd) && !isDateDisabled(today))
104
+ return new Date(today);
105
+ const dim = daysInMonth(year, month);
106
+ for (let d = 1; d <= dim; d++) {
107
+ const cand = new Date(year, month, d);
108
+ if (!isDateDisabled(cand))
109
+ return cand;
110
+ }
111
+ return new Date(year, month, 1);
77
112
  };
113
+ // Resynchronize the visible month/year (and roving focus) when the controlled
114
+ // `selected` prop changes — e.g. the consumer's typed MM/DD/YYYY fields.
115
+ const selectedTime = selected ? startOfDay(selected).getTime() : undefined;
116
+ React.useEffect(() => {
117
+ if (selectedTime === undefined)
118
+ return;
119
+ const d = new Date(selectedTime);
120
+ setViewDate(monthStart(d.getFullYear(), d.getMonth()));
121
+ setFocusedDate(startOfDay(d));
122
+ }, [selectedTime]);
123
+ // Deliberate focus after every view transition — never left on document.body.
124
+ React.useLayoutEffect(() => {
125
+ const target = pendingFocusRef.current;
126
+ if (!target)
127
+ return;
128
+ pendingFocusRef.current = null;
129
+ if (target === "monthTrigger") {
130
+ monthTriggerRef.current?.focus();
131
+ }
132
+ else if (target === "yearTrigger") {
133
+ yearTriggerRef.current?.focus();
134
+ }
135
+ else if (target === "day") {
136
+ daysGridRef.current?.querySelector('[data-roving="true"]')?.focus();
137
+ }
138
+ else if (target === "monthGrid" || target === "yearGrid") {
139
+ const active = overlayRef.current?.querySelector('[data-active="true"]:not([disabled])');
140
+ const fallback = overlayRef.current?.querySelector("button:not([disabled])");
141
+ (active ?? fallback)?.focus();
142
+ }
143
+ });
78
144
  const generateCalendarDays = () => {
79
145
  const year = viewDate.getFullYear();
80
146
  const month = viewDate.getMonth();
81
- const daysInMonth = getDaysInMonth(viewDate);
82
- const firstDay = getFirstDayOfMonth(viewDate);
147
+ const dim = daysInMonth(year, month);
148
+ const firstDay = new Date(year, month, 1).getDay();
83
149
  const days = [];
84
150
  for (let i = 0; i < firstDay; i++)
85
151
  days.push(null);
86
- for (let day = 1; day <= daysInMonth; day++)
152
+ for (let day = 1; day <= dim; day++)
87
153
  days.push(new Date(year, month, day));
154
+ while (days.length < CALENDAR_CELLS)
155
+ days.push(null);
88
156
  return days;
89
157
  };
90
- const previousMonth = () => setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1));
91
- const nextMonth = () => setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1));
92
- const handleDateClick = (date) => {
158
+ const inViewMonth = isSameMonth(focusedDate, viewDate);
159
+ const rovingDate = inViewMonth ? focusedDate : pickInMonthFocus(viewDate);
160
+ const commitDay = (date) => {
93
161
  if (isDateDisabled(date))
94
162
  return;
95
163
  onSelect?.(date);
96
164
  };
165
+ const moveFocusTo = (date) => {
166
+ const d = startOfDay(date);
167
+ setFocusedDate(d);
168
+ if (!isSameMonth(d, viewDate))
169
+ setViewDate(monthStart(d.getFullYear(), d.getMonth()));
170
+ pendingFocusRef.current = "day";
171
+ };
172
+ /** From `origin`, walk `step` days at a time until an available day is found
173
+ * (inclusive of `origin`). Returns null if none within `maxSteps`. */
174
+ const firstAvailableFrom = (origin, step, maxSteps) => {
175
+ let d = startOfDay(origin);
176
+ for (let i = 0; i < maxSteps; i++) {
177
+ if (!isDateDisabled(d))
178
+ return d;
179
+ d = new Date(d.getFullYear(), d.getMonth(), d.getDate() + step);
180
+ }
181
+ return null;
182
+ };
183
+ const handleDaysKeyDown = (e) => {
184
+ const base = rovingDate;
185
+ let candidate;
186
+ let probeStep;
187
+ switch (e.key) {
188
+ case "ArrowLeft":
189
+ candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() - 1);
190
+ probeStep = -1;
191
+ break;
192
+ case "ArrowRight":
193
+ candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() + 1);
194
+ probeStep = 1;
195
+ break;
196
+ case "ArrowUp":
197
+ candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() - 7);
198
+ probeStep = -1;
199
+ break;
200
+ case "ArrowDown":
201
+ candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() + 7);
202
+ probeStep = 1;
203
+ break;
204
+ case "Home":
205
+ candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() - base.getDay());
206
+ probeStep = 1;
207
+ break;
208
+ case "End":
209
+ candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() + (6 - base.getDay()));
210
+ probeStep = -1;
211
+ break;
212
+ case "PageUp": {
213
+ const prev = addMonths(base, -1);
214
+ candidate = new Date(prev.getFullYear(), prev.getMonth(), Math.min(base.getDate(), daysInMonth(prev.getFullYear(), prev.getMonth())));
215
+ probeStep = 1;
216
+ break;
217
+ }
218
+ case "PageDown": {
219
+ const next = addMonths(base, 1);
220
+ candidate = new Date(next.getFullYear(), next.getMonth(), Math.min(base.getDate(), daysInMonth(next.getFullYear(), next.getMonth())));
221
+ probeStep = 1;
222
+ break;
223
+ }
224
+ case "Enter":
225
+ case " ":
226
+ e.preventDefault();
227
+ commitDay(base);
228
+ return;
229
+ default:
230
+ return;
231
+ }
232
+ e.preventDefault();
233
+ let target = firstAvailableFrom(candidate, probeStep, 62);
234
+ if (!target && probeStep !== -1)
235
+ target = firstAvailableFrom(candidate, -1, 62);
236
+ if (target)
237
+ moveFocusTo(target);
238
+ };
239
+ // Header prev/next adapt to the active view; disabled when the whole target
240
+ // range is unavailable so navigation never lands on a dead page.
241
+ const prevMonthDate = addMonths(viewDate, -1);
242
+ const nextMonthDate = addMonths(viewDate, 1);
243
+ let prevDisabled;
244
+ let nextDisabled;
245
+ let prevLabel;
246
+ let nextLabel;
247
+ if (view === "days") {
248
+ prevDisabled = isMonthDisabled(prevMonthDate.getFullYear(), prevMonthDate.getMonth());
249
+ nextDisabled = isMonthDisabled(nextMonthDate.getFullYear(), nextMonthDate.getMonth());
250
+ prevLabel = "Previous month";
251
+ nextLabel = "Next month";
252
+ }
253
+ else if (view === "months") {
254
+ prevDisabled = isYearDisabled(viewDate.getFullYear() - 1);
255
+ nextDisabled = isYearDisabled(viewDate.getFullYear() + 1);
256
+ prevLabel = "Previous year";
257
+ nextLabel = "Next year";
258
+ }
259
+ else {
260
+ prevDisabled = rangeAllYearsDisabled(yearPageStart - YEARS_PER_PAGE, yearPageStart - 1);
261
+ nextDisabled = rangeAllYearsDisabled(yearPageStart + YEARS_PER_PAGE, yearPageStart + YEARS_PER_PAGE * 2 - 1);
262
+ prevLabel = `Previous ${YEARS_PER_PAGE} years`;
263
+ nextLabel = `Next ${YEARS_PER_PAGE} years`;
264
+ }
265
+ const handlePrev = () => {
266
+ if (view === "days")
267
+ setViewDate(prevMonthDate);
268
+ else if (view === "months")
269
+ setViewDate(monthStart(viewDate.getFullYear() - 1, viewDate.getMonth()));
270
+ else
271
+ setYearPageStart((s) => s - YEARS_PER_PAGE);
272
+ };
273
+ const handleNext = () => {
274
+ if (view === "days")
275
+ setViewDate(nextMonthDate);
276
+ else if (view === "months")
277
+ setViewDate(monthStart(viewDate.getFullYear() + 1, viewDate.getMonth()));
278
+ else
279
+ setYearPageStart((s) => s + YEARS_PER_PAGE);
280
+ };
281
+ const openMonths = () => {
282
+ if (view === "months") {
283
+ setView("days");
284
+ pendingFocusRef.current = "monthTrigger";
285
+ }
286
+ else {
287
+ setView("months");
288
+ pendingFocusRef.current = "monthGrid";
289
+ }
290
+ };
97
291
  const openYears = () => {
98
- setYearPageStart(Math.floor(viewDate.getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE);
99
- setView("years");
292
+ if (view === "years") {
293
+ setView("days");
294
+ pendingFocusRef.current = "yearTrigger";
295
+ }
296
+ else {
297
+ setYearPageStart(Math.floor(viewDate.getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE);
298
+ setView("years");
299
+ pendingFocusRef.current = "yearGrid";
300
+ }
301
+ };
302
+ // Month selection: keep the year, return to days, focus the Month trigger.
303
+ const handleMonthPick = (month) => {
304
+ setViewDate(monthStart(viewDate.getFullYear(), month));
305
+ setView("days");
306
+ pendingFocusRef.current = "monthTrigger";
307
+ };
308
+ // Year selection: keep the month, return to days (never months), focus Year.
309
+ const handleYearPick = (year) => {
310
+ setViewDate(monthStart(year, viewDate.getMonth()));
311
+ setView("days");
312
+ pendingFocusRef.current = "yearTrigger";
100
313
  };
101
314
  const calendarDays = generateCalendarDays();
102
315
  const yearPage = Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPageStart + i);
103
- return (_jsxs("div", { className: cn("p-4 bg-card rounded-lg", className), children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx(Button, { variant: "default", size: "sm", className: cn("h-8 w-8 p-0", view !== "days" && "invisible"), "aria-label": "Previous month", onClick: previousMonth, children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("button", { type: "button", onClick: () => setView(view === "months" ? "days" : "months"), "aria-expanded": view === "months", className: "text-base font-bold hover:opacity-80 transition-opacity text-foreground underline decoration-1 underline-offset-4 decoration-border", children: MONTHS[viewDate.getMonth()] }), _jsx("button", { type: "button", onClick: () => (view === "years" ? setView("days") : openYears()), "aria-expanded": view === "years", className: "text-base font-bold hover:opacity-80 transition-opacity text-foreground underline decoration-1 underline-offset-4 decoration-border", children: viewDate.getFullYear() })] }), _jsx(Button, { variant: "default", size: "sm", className: cn("h-8 w-8 p-0", view !== "days" && "invisible"), "aria-label": "Next month", onClick: nextMonth, children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] }), view === "years" && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx(Button, { variant: "ghost", size: "sm", className: "h-8 w-8 p-0", "aria-label": `Previous ${YEARS_PER_PAGE} years`, onClick: () => setYearPageStart((s) => s - YEARS_PER_PAGE), children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsxs("span", { className: "text-sm font-semibold text-muted-foreground", children: [yearPageStart, " \u2013 ", yearPageStart + YEARS_PER_PAGE - 1] }), _jsx(Button, { variant: "ghost", size: "sm", className: "h-8 w-8 p-0", "aria-label": `Next ${YEARS_PER_PAGE} years`, onClick: () => setYearPageStart((s) => s + YEARS_PER_PAGE), children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "grid grid-cols-3 gap-1", children: yearPage.map((year) => {
104
- const yearDisabled = isYearDisabled(year);
105
- const isViewYear = year === viewDate.getFullYear();
106
- return (_jsx("button", { type: "button", disabled: yearDisabled, onClick: () => {
107
- setViewDate((prev) => new Date(year, prev.getMonth()));
108
- setView("months");
109
- }, className: cn("h-10 rounded-lg text-sm font-semibold transition-all", "flex items-center justify-center", !yearDisabled && !isViewYear && "text-foreground hover:bg-primary/10", isViewYear && "bg-primary text-white font-bold shadow-lg", yearDisabled && "opacity-30 cursor-not-allowed"), children: year }, year));
110
- }) })] })), view === "months" && (_jsx("div", { className: "grid grid-cols-3 gap-1", children: MONTHS_SHORT.map((label, month) => {
111
- const monthDisabled = isMonthDisabled(viewDate.getFullYear(), month);
112
- const isViewMonth = month === viewDate.getMonth();
113
- return (_jsx("button", { type: "button", disabled: monthDisabled, onClick: () => {
114
- setViewDate((prev) => new Date(prev.getFullYear(), month));
115
- setView("days");
116
- }, className: cn("h-10 rounded-lg text-sm font-semibold transition-all", "flex items-center justify-center", !monthDisabled && !isViewMonth && "text-foreground hover:bg-primary/10", isViewMonth && "bg-primary text-white font-bold shadow-lg", monthDisabled && "opacity-30 cursor-not-allowed"), children: label }, label));
117
- }) })), view === "days" && (_jsxs(_Fragment, { children: [_jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS.map((day) => (_jsx("div", { className: "text-center text-sm font-bold py-2 text-foreground", children: day }, day))) }), _jsx("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
118
- if (!date)
119
- return _jsx("div", { className: "h-9" }, `empty-${index}`);
120
- const dateDisabled = isDateDisabled(date);
121
- const dateSelected = isDateSelected(date);
122
- const todayDate = isToday(date);
123
- return (_jsxs("button", { type: "button", onClick: () => handleDateClick(date), disabled: dateDisabled, className: cn("h-9 w-9 rounded-lg text-sm font-semibold transition-all", "hover:scale-105 active:scale-95", "flex items-center justify-center", !dateDisabled && !dateSelected && !todayDate && "text-foreground hover:bg-primary/10", todayDate && !dateSelected && "bg-accent text-foreground font-bold ring-2 ring-border", dateSelected && "bg-primary text-white font-bold shadow-lg", dateDisabled && "opacity-30 cursor-not-allowed hover:scale-100 hover:bg-transparent", dateDisabled && "relative"), children: [date.getDate(), dateDisabled && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "w-px h-full bg-current transform rotate-45" }) }))] }, date.toISOString()));
124
- }) }), _jsxs("div", { className: "mt-4 pt-3 border-t border-border text-xs space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-3 w-3 rounded-sm bg-primary" }), _jsx("span", { className: "text-muted-foreground", children: "Selected" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-3 w-3 rounded-sm bg-accent ring-2 ring-border" }), _jsx("span", { className: "text-muted-foreground", children: "Today" })] }), (disablePast || disableFuture || disabled) && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-3 w-3 rounded-sm bg-muted opacity-30 relative", children: _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "w-px h-full bg-foreground transform rotate-45" }) }) }), _jsx("span", { className: "text-muted-foreground", children: "Unavailable" })] }))] })] }))] }));
316
+ const overlayActive = view !== "days";
317
+ const triggerClass = "min-h-[1.5rem] px-1 text-base font-bold text-foreground underline decoration-1 underline-offset-4 decoration-border rounded-sm " +
318
+ "hover:opacity-80 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background";
319
+ const gridCellClass = "h-10 rounded-lg text-sm font-semibold transition-transform flex items-center justify-center " +
320
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background";
321
+ return (_jsxs("div", { className: cn("p-4 bg-card rounded-lg", className), children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx(Button, { variant: "ghost", size: "icon", className: "h-9 w-9 p-0", "aria-label": prevLabel, disabled: prevDisabled, onClick: handlePrev, children: _jsx(ChevronLeft, { className: "h-4 w-4", "aria-hidden": "true" }) }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("button", { ref: monthTriggerRef, type: "button", onClick: openMonths, "aria-expanded": view === "months", "aria-label": `Choose month, currently ${MONTHS[viewDate.getMonth()]}`, className: triggerClass, children: MONTHS[viewDate.getMonth()] }), _jsx("button", { ref: yearTriggerRef, type: "button", onClick: openYears, "aria-expanded": view === "years", "aria-label": `Choose year, currently ${viewDate.getFullYear()}`, className: triggerClass, children: viewDate.getFullYear() })] }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-9 w-9 p-0", "aria-label": nextLabel, disabled: nextDisabled, onClick: handleNext, children: _jsx(ChevronRight, { className: "h-4 w-4", "aria-hidden": "true" }) })] }), _jsxs("div", { "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: [MONTHS[viewDate.getMonth()], " ", viewDate.getFullYear()] }), _jsxs("div", { className: "relative", children: [_jsxs("div", { "aria-hidden": overlayActive ? true : undefined, children: [_jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS.map((day, i) => (_jsxs("div", { className: "text-center text-sm font-bold py-2 text-foreground", "aria-hidden": "true", children: [_jsx("span", { className: "sr-only", children: DAY_NAMES_LONG[i] }), _jsx("span", { "aria-hidden": "true", children: day })] }, day))) }), _jsx("div", { ref: daysGridRef, className: "grid grid-cols-7 gap-1", role: "group", "aria-label": "Calendar", onKeyDown: overlayActive ? undefined : handleDaysKeyDown, children: calendarDays.map((date, index) => {
322
+ if (!date)
323
+ return _jsx("div", { className: "h-9", "aria-hidden": "true" }, `empty-${index}`);
324
+ const dateDisabled = isDateDisabled(date);
325
+ const dateSelected = isSelectedDay(date);
326
+ const todayDate = isTodayDate(date);
327
+ const roving = isSameDay(date, rovingDate);
328
+ const tabIndex = !overlayActive && roving ? 0 : -1;
329
+ return (_jsxs("button", { type: "button", onClick: () => commitDay(date), disabled: dateDisabled, tabIndex: tabIndex, "data-roving": roving ? "true" : undefined, "aria-label": fullDateLabel(date), "aria-pressed": dateSelected, "aria-current": todayDate ? "date" : undefined, className: cn("h-9 w-9 rounded-lg text-sm font-semibold transition-transform", "motion-safe:hover:scale-105 motion-safe:active:scale-95", "flex items-center justify-center", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", !dateDisabled && !dateSelected && !todayDate && "text-foreground hover:bg-primary/10", todayDate && !dateSelected && "bg-accent text-accent-foreground font-bold ring-2 ring-border", dateSelected && "bg-primary text-primary-foreground font-bold", dateDisabled && "opacity-30 cursor-not-allowed motion-safe:hover:scale-100 hover:bg-transparent relative"), children: [date.getDate(), dateDisabled && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center", "aria-hidden": "true", children: _jsx("span", { className: "w-px h-full bg-current transform rotate-45" }) }))] }, date.toISOString()));
330
+ }) }), _jsxs("div", { className: "mt-4 pt-3 border-t border-border text-xs space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-3 w-3 rounded-sm bg-primary", "aria-hidden": "true" }), _jsx("span", { className: "text-muted-foreground", children: "Selected" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-3 w-3 rounded-sm bg-accent ring-2 ring-border", "aria-hidden": "true" }), _jsx("span", { className: "text-muted-foreground", children: "Today" })] }), (disablePast || disableFuture || disabled) && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-3 w-3 rounded-sm bg-muted opacity-30 relative", "aria-hidden": "true", children: _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "w-px h-full bg-foreground transform rotate-45" }) }) }), _jsx("span", { className: "text-muted-foreground", children: "Unavailable" })] }))] })] }), overlayActive && (_jsxs("div", { ref: overlayRef, className: "absolute inset-0 bg-card rounded-lg flex flex-col justify-center", children: [view === "years" && (_jsxs("div", { className: "mb-2 text-center text-sm font-semibold text-muted-foreground", "aria-hidden": "true", children: [yearPageStart, " \u2013 ", yearPageStart + YEARS_PER_PAGE - 1] })), view === "months" && (_jsx("div", { className: "grid grid-cols-3 gap-1", children: MONTHS_SHORT.map((label, month) => {
331
+ const monthDisabled = isMonthDisabled(viewDate.getFullYear(), month);
332
+ const isViewMonth = month === viewDate.getMonth();
333
+ return (_jsx("button", { type: "button", disabled: monthDisabled, "data-active": isViewMonth ? "true" : undefined, "aria-pressed": isViewMonth, "aria-label": `${MONTHS[month]} ${viewDate.getFullYear()}`, onClick: () => handleMonthPick(month), className: cn(gridCellClass, !monthDisabled && !isViewMonth && "text-foreground hover:bg-primary/10", isViewMonth && "bg-primary text-primary-foreground font-bold", monthDisabled && "opacity-30 cursor-not-allowed"), children: label }, label));
334
+ }) })), view === "years" && (_jsx("div", { className: "grid grid-cols-3 gap-1", children: yearPage.map((year) => {
335
+ const yearDisabled = isYearDisabled(year);
336
+ const isViewYear = year === viewDate.getFullYear();
337
+ return (_jsx("button", { type: "button", disabled: yearDisabled, "data-active": isViewYear ? "true" : undefined, "aria-pressed": isViewYear, "aria-label": `Year ${year}`, onClick: () => handleYearPick(year), className: cn(gridCellClass, !yearDisabled && !isViewYear && "text-foreground hover:bg-primary/10", isViewYear && "bg-primary text-primary-foreground font-bold", yearDisabled && "opacity-30 cursor-not-allowed"), children: year }, year));
338
+ }) }))] }))] })] }));
125
339
  }
126
340
  DatePicker.displayName = "DatePicker";
127
341
  export { DatePicker };
@@ -1 +1 @@
1
- {"version":3,"file":"date-picker.js","sourceRoot":"","sources":["../../../src/react/components/date-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronLeft, ChevronRight } from \"lucide-react\"\nimport { Button } from \"./button.js\"\nimport { cn } from \"../../lib/utils.js\"\n\nexport interface DatePickerProps {\n selected?: Date\n onSelect?: (date: Date | undefined) => void\n disabled?: (date: Date) => boolean\n disablePast?: boolean\n disableFuture?: boolean\n className?: string\n}\n\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n]\n\nconst MONTHS_SHORT = [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n]\n\nconst DAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"]\n\nconst YEARS_PER_PAGE = 12\n\n/** Calendar with fast month/year navigation: the header's month and year are\n * each buttons — month opens a 12-month grid, year opens a paged 12-year\n * grid (no single-step year arrows; distant years are a couple of clicks).\n * Picking a year drills to the month grid, then the day grid — the natural\n * date-of-birth path — while picking just a month returns straight to days. */\nfunction DatePicker({\n selected,\n onSelect,\n disabled,\n disablePast = false,\n disableFuture = false,\n className,\n}: DatePickerProps) {\n const [viewDate, setViewDate] = React.useState(() => selected || new Date())\n const [view, setView] = React.useState<\"days\" | \"months\" | \"years\">(\"days\")\n const [yearPageStart, setYearPageStart] = React.useState(\n () => Math.floor((selected || new Date()).getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE,\n )\n\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n\n const getDaysInMonth = (date: Date) => {\n const year = date.getFullYear()\n const month = date.getMonth()\n return new Date(year, month + 1, 0).getDate()\n }\n\n const getFirstDayOfMonth = (date: Date) => {\n const year = date.getFullYear()\n const month = date.getMonth()\n return new Date(year, month, 1).getDay()\n }\n\n const isDateDisabled = (date: Date) => {\n const checkDate = new Date(date)\n checkDate.setHours(0, 0, 0, 0)\n\n if (disablePast && checkDate < today) return true\n if (disableFuture && checkDate > today) return true\n if (disabled && disabled(checkDate)) return true\n\n return false\n }\n\n /** A whole month is unpickable only when every day in it is out of range. */\n const isMonthDisabled = (year: number, month: number) => {\n if (disableFuture && new Date(year, month, 1) > today) return true\n if (disablePast && new Date(year, month + 1, 0) < today) return true\n return false\n }\n\n const isYearDisabled = (year: number) => {\n if (disableFuture && year > today.getFullYear()) return true\n if (disablePast && year < today.getFullYear()) return true\n return false\n }\n\n const isDateSelected = (date: Date) => {\n if (!selected) return false\n const selectedDate = new Date(selected)\n selectedDate.setHours(0, 0, 0, 0)\n const checkDate = new Date(date)\n checkDate.setHours(0, 0, 0, 0)\n return selectedDate.getTime() === checkDate.getTime()\n }\n\n const isToday = (date: Date) => {\n const checkDate = new Date(date)\n checkDate.setHours(0, 0, 0, 0)\n return checkDate.getTime() === today.getTime()\n }\n\n const generateCalendarDays = () => {\n const year = viewDate.getFullYear()\n const month = viewDate.getMonth()\n const daysInMonth = getDaysInMonth(viewDate)\n const firstDay = getFirstDayOfMonth(viewDate)\n\n const days: (Date | null)[] = []\n\n for (let i = 0; i < firstDay; i++) days.push(null)\n for (let day = 1; day <= daysInMonth; day++) days.push(new Date(year, month, day))\n\n return days\n }\n\n const previousMonth = () => setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1))\n const nextMonth = () => setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1))\n\n const handleDateClick = (date: Date) => {\n if (isDateDisabled(date)) return\n onSelect?.(date)\n }\n\n const openYears = () => {\n setYearPageStart(Math.floor(viewDate.getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE)\n setView(\"years\")\n }\n\n const calendarDays = generateCalendarDays()\n const yearPage = Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPageStart + i)\n\n return (\n <div className={cn(\"p-4 bg-card rounded-lg\", className)}>\n <div className=\"flex items-center justify-between mb-4\">\n <Button\n variant=\"default\"\n size=\"sm\"\n className={cn(\"h-8 w-8 p-0\", view !== \"days\" && \"invisible\")}\n aria-label=\"Previous month\"\n onClick={previousMonth}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n\n {/* Month and year are EACH pickers: month → 12-month grid; year →\n paged 12-year grid. No single-step year arrows. */}\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setView(view === \"months\" ? \"days\" : \"months\")}\n aria-expanded={view === \"months\"}\n className=\"text-base font-bold hover:opacity-80 transition-opacity text-foreground underline decoration-1 underline-offset-4 decoration-border\"\n >\n {MONTHS[viewDate.getMonth()]}\n </button>\n <button\n type=\"button\"\n onClick={() => (view === \"years\" ? setView(\"days\") : openYears())}\n aria-expanded={view === \"years\"}\n className=\"text-base font-bold hover:opacity-80 transition-opacity text-foreground underline decoration-1 underline-offset-4 decoration-border\"\n >\n {viewDate.getFullYear()}\n </button>\n </div>\n\n <Button\n variant=\"default\"\n size=\"sm\"\n className={cn(\"h-8 w-8 p-0\", view !== \"days\" && \"invisible\")}\n aria-label=\"Next month\"\n onClick={nextMonth}\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n\n {view === \"years\" && (\n <>\n <div className=\"flex items-center justify-between mb-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Previous ${YEARS_PER_PAGE} years`}\n onClick={() => setYearPageStart((s) => s - YEARS_PER_PAGE)}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <span className=\"text-sm font-semibold text-muted-foreground\">\n {yearPageStart} – {yearPageStart + YEARS_PER_PAGE - 1}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Next ${YEARS_PER_PAGE} years`}\n onClick={() => setYearPageStart((s) => s + YEARS_PER_PAGE)}\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n <div className=\"grid grid-cols-3 gap-1\">\n {yearPage.map((year) => {\n const yearDisabled = isYearDisabled(year)\n const isViewYear = year === viewDate.getFullYear()\n return (\n <button\n key={year}\n type=\"button\"\n disabled={yearDisabled}\n onClick={() => {\n setViewDate((prev) => new Date(year, prev.getMonth()))\n setView(\"months\")\n }}\n className={cn(\n \"h-10 rounded-lg text-sm font-semibold transition-all\",\n \"flex items-center justify-center\",\n !yearDisabled && !isViewYear && \"text-foreground hover:bg-primary/10\",\n isViewYear && \"bg-primary text-white font-bold shadow-lg\",\n yearDisabled && \"opacity-30 cursor-not-allowed\",\n )}\n >\n {year}\n </button>\n )\n })}\n </div>\n </>\n )}\n\n {view === \"months\" && (\n <div className=\"grid grid-cols-3 gap-1\">\n {MONTHS_SHORT.map((label, month) => {\n const monthDisabled = isMonthDisabled(viewDate.getFullYear(), month)\n const isViewMonth = month === viewDate.getMonth()\n return (\n <button\n key={label}\n type=\"button\"\n disabled={monthDisabled}\n onClick={() => {\n setViewDate((prev) => new Date(prev.getFullYear(), month))\n setView(\"days\")\n }}\n className={cn(\n \"h-10 rounded-lg text-sm font-semibold transition-all\",\n \"flex items-center justify-center\",\n !monthDisabled && !isViewMonth && \"text-foreground hover:bg-primary/10\",\n isViewMonth && \"bg-primary text-white font-bold shadow-lg\",\n monthDisabled && \"opacity-30 cursor-not-allowed\",\n )}\n >\n {label}\n </button>\n )\n })}\n </div>\n )}\n\n {view === \"days\" && (\n <>\n <div className=\"grid grid-cols-7 gap-1 mb-2\">\n {DAYS.map((day) => (\n <div\n key={day}\n className=\"text-center text-sm font-bold py-2 text-foreground\"\n >\n {day}\n </div>\n ))}\n </div>\n\n <div className=\"grid grid-cols-7 gap-1\">\n {calendarDays.map((date, index) => {\n if (!date) return <div key={`empty-${index}`} className=\"h-9\" />\n\n const dateDisabled = isDateDisabled(date)\n const dateSelected = isDateSelected(date)\n const todayDate = isToday(date)\n\n return (\n <button\n key={date.toISOString()}\n type=\"button\"\n onClick={() => handleDateClick(date)}\n disabled={dateDisabled}\n className={cn(\n \"h-9 w-9 rounded-lg text-sm font-semibold transition-all\",\n \"hover:scale-105 active:scale-95\",\n \"flex items-center justify-center\",\n !dateDisabled && !dateSelected && !todayDate && \"text-foreground hover:bg-primary/10\",\n todayDate && !dateSelected && \"bg-accent text-foreground font-bold ring-2 ring-border\",\n dateSelected && \"bg-primary text-white font-bold shadow-lg\",\n dateDisabled && \"opacity-30 cursor-not-allowed hover:scale-100 hover:bg-transparent\",\n dateDisabled && \"relative\"\n )}\n >\n {date.getDate()}\n {dateDisabled && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"w-px h-full bg-current transform rotate-45\" />\n </div>\n )}\n </button>\n )\n })}\n </div>\n\n <div className=\"mt-4 pt-3 border-t border-border text-xs space-y-1\">\n <div className=\"flex items-center gap-2\">\n <div className=\"h-3 w-3 rounded-sm bg-primary\" />\n <span className=\"text-muted-foreground\">Selected</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"h-3 w-3 rounded-sm bg-accent ring-2 ring-border\" />\n <span className=\"text-muted-foreground\">Today</span>\n </div>\n {(disablePast || disableFuture || disabled) && (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-3 w-3 rounded-sm bg-muted opacity-30 relative\">\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"w-px h-full bg-foreground transform rotate-45\" />\n </div>\n </div>\n <span className=\"text-muted-foreground\">Unavailable</span>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n )\n}\n\nDatePicker.displayName = \"DatePicker\"\n\nexport { DatePicker }\n"]}
1
+ {"version":3,"file":"date-picker.js","sourceRoot":"","sources":["../../../src/react/components/date-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronLeft, ChevronRight } from \"lucide-react\"\nimport { Button } from \"./button.js\"\nimport { cn } from \"../../lib/utils.js\"\n\nexport interface DatePickerProps {\n selected?: Date\n onSelect?: (date: Date | undefined) => void\n disabled?: (date: Date) => boolean\n disablePast?: boolean\n disableFuture?: boolean\n className?: string\n}\n\nconst MONTHS = [\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n \"July\", \"August\", \"September\", \"October\", \"November\", \"December\",\n]\n\nconst MONTHS_SHORT = [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n]\n\nconst DAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"]\nconst DAY_NAMES_LONG = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]\n\nconst YEARS_PER_PAGE = 12\n/** Six rows × seven columns — a calendar month never spans more, and always\n * filling six rows keeps the day grid (and therefore the whole popover\n * footprint) the same height for every month. */\nconst CALENDAR_CELLS = 42\n\ntype View = \"days\" | \"months\" | \"years\"\ntype PendingFocus = \"day\" | \"monthTrigger\" | \"yearTrigger\" | \"monthGrid\" | \"yearGrid\"\n\nconst startOfDay = (d: Date) => {\n const x = new Date(d.getFullYear(), d.getMonth(), d.getDate())\n return x\n}\nconst monthStart = (year: number, month: number) => new Date(year, month, 1)\nconst addMonths = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth() + n, 1)\nconst daysInMonth = (year: number, month: number) => new Date(year, month + 1, 0).getDate()\nconst isSameDay = (a: Date, b: Date) =>\n a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate()\nconst isSameMonth = (a: Date, b: Date) =>\n a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth()\nconst fullDateLabel = (date: Date) => `${MONTHS[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`\n\n/**\n * Generic date-of-birth-friendly calendar.\n *\n * Stable footprint: the six-row day grid is always rendered, so the outer width\n * and content height never change; the month and year choosers render as an\n * overlay ON TOP of that grid rather than replacing it, so a Radix popover never\n * flips sides just because the internal view changed.\n *\n * Month and year are INDEPENDENT pickers: choosing a month keeps the current\n * year and returns to the day grid; choosing a year keeps the current month and\n * returns DIRECTLY to the day grid (it never opens the month grid). Only\n * choosing a day calls `onSelect` (which commits and, in a popover, closes).\n *\n * Keyboard: roving day focus with Arrow (±1 day / ±7 days), Home/End (within the\n * week), PageUp/PageDown (±1 month), and Enter/Space to select — no extra\n * dependency. Exactly one day sits in the tab order at a time.\n */\nfunction DatePicker({\n selected,\n onSelect,\n disabled,\n disablePast = false,\n disableFuture = false,\n className,\n}: DatePickerProps) {\n const today = React.useMemo(() => startOfDay(new Date()), [])\n\n const [viewDate, setViewDate] = React.useState(() =>\n monthStart((selected ?? today).getFullYear(), (selected ?? today).getMonth()),\n )\n const [view, setView] = React.useState<View>(\"days\")\n const [yearPageStart, setYearPageStart] = React.useState(\n () => Math.floor((selected ?? today).getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE,\n )\n const [focusedDate, setFocusedDate] = React.useState(() => startOfDay(selected ?? today))\n\n const monthTriggerRef = React.useRef<HTMLButtonElement | null>(null)\n const yearTriggerRef = React.useRef<HTMLButtonElement | null>(null)\n const daysGridRef = React.useRef<HTMLDivElement | null>(null)\n const overlayRef = React.useRef<HTMLDivElement | null>(null)\n const pendingFocusRef = React.useRef<PendingFocus | null>(null)\n\n const isDateDisabled = (date: Date) => {\n const checkDate = startOfDay(date)\n if (disablePast && checkDate < today) return true\n if (disableFuture && checkDate > today) return true\n if (disabled && disabled(checkDate)) return true\n return false\n }\n\n /** A whole month is unpickable only when every day in it is out of range. */\n const isMonthDisabled = (year: number, month: number) => {\n if (disableFuture && new Date(year, month, 1) > today) return true\n if (disablePast && new Date(year, month + 1, 0) < today) return true\n return false\n }\n\n const isYearDisabled = (year: number) => {\n if (disableFuture && year > today.getFullYear()) return true\n if (disablePast && year < today.getFullYear()) return true\n return false\n }\n\n const rangeAllYearsDisabled = (from: number, to: number) => {\n for (let y = from; y <= to; y++) if (!isYearDisabled(y)) return false\n return true\n }\n\n const isSelectedDay = (date: Date) => (selected ? isSameDay(startOfDay(selected), startOfDay(date)) : false)\n const isTodayDate = (date: Date) => isSameDay(startOfDay(date), today)\n\n /** The best in-month day to seed roving focus: the selected day, then today,\n * then the first available day, then the 1st. */\n const pickInMonthFocus = (vd: Date): Date => {\n const year = vd.getFullYear()\n const month = vd.getMonth()\n if (selected) {\n const s = startOfDay(selected)\n if (isSameMonth(s, vd) && !isDateDisabled(s)) return s\n }\n if (isSameMonth(today, vd) && !isDateDisabled(today)) return new Date(today)\n const dim = daysInMonth(year, month)\n for (let d = 1; d <= dim; d++) {\n const cand = new Date(year, month, d)\n if (!isDateDisabled(cand)) return cand\n }\n return new Date(year, month, 1)\n }\n\n // Resynchronize the visible month/year (and roving focus) when the controlled\n // `selected` prop changes — e.g. the consumer's typed MM/DD/YYYY fields.\n const selectedTime = selected ? startOfDay(selected).getTime() : undefined\n React.useEffect(() => {\n if (selectedTime === undefined) return\n const d = new Date(selectedTime)\n setViewDate(monthStart(d.getFullYear(), d.getMonth()))\n setFocusedDate(startOfDay(d))\n }, [selectedTime])\n\n // Deliberate focus after every view transition — never left on document.body.\n React.useLayoutEffect(() => {\n const target = pendingFocusRef.current\n if (!target) return\n pendingFocusRef.current = null\n if (target === \"monthTrigger\") {\n monthTriggerRef.current?.focus()\n } else if (target === \"yearTrigger\") {\n yearTriggerRef.current?.focus()\n } else if (target === \"day\") {\n daysGridRef.current?.querySelector<HTMLButtonElement>('[data-roving=\"true\"]')?.focus()\n } else if (target === \"monthGrid\" || target === \"yearGrid\") {\n const active = overlayRef.current?.querySelector<HTMLButtonElement>('[data-active=\"true\"]:not([disabled])')\n const fallback = overlayRef.current?.querySelector<HTMLButtonElement>(\"button:not([disabled])\")\n ;(active ?? fallback)?.focus()\n }\n })\n\n const generateCalendarDays = (): (Date | null)[] => {\n const year = viewDate.getFullYear()\n const month = viewDate.getMonth()\n const dim = daysInMonth(year, month)\n const firstDay = new Date(year, month, 1).getDay()\n const days: (Date | null)[] = []\n for (let i = 0; i < firstDay; i++) days.push(null)\n for (let day = 1; day <= dim; day++) days.push(new Date(year, month, day))\n while (days.length < CALENDAR_CELLS) days.push(null)\n return days\n }\n\n const inViewMonth = isSameMonth(focusedDate, viewDate)\n const rovingDate = inViewMonth ? focusedDate : pickInMonthFocus(viewDate)\n\n const commitDay = (date: Date) => {\n if (isDateDisabled(date)) return\n onSelect?.(date)\n }\n\n const moveFocusTo = (date: Date) => {\n const d = startOfDay(date)\n setFocusedDate(d)\n if (!isSameMonth(d, viewDate)) setViewDate(monthStart(d.getFullYear(), d.getMonth()))\n pendingFocusRef.current = \"day\"\n }\n\n /** From `origin`, walk `step` days at a time until an available day is found\n * (inclusive of `origin`). Returns null if none within `maxSteps`. */\n const firstAvailableFrom = (origin: Date, step: number, maxSteps: number): Date | null => {\n let d = startOfDay(origin)\n for (let i = 0; i < maxSteps; i++) {\n if (!isDateDisabled(d)) return d\n d = new Date(d.getFullYear(), d.getMonth(), d.getDate() + step)\n }\n return null\n }\n\n const handleDaysKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const base = rovingDate\n let candidate: Date\n let probeStep: number\n\n switch (e.key) {\n case \"ArrowLeft\":\n candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() - 1)\n probeStep = -1\n break\n case \"ArrowRight\":\n candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() + 1)\n probeStep = 1\n break\n case \"ArrowUp\":\n candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() - 7)\n probeStep = -1\n break\n case \"ArrowDown\":\n candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() + 7)\n probeStep = 1\n break\n case \"Home\":\n candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() - base.getDay())\n probeStep = 1\n break\n case \"End\":\n candidate = new Date(base.getFullYear(), base.getMonth(), base.getDate() + (6 - base.getDay()))\n probeStep = -1\n break\n case \"PageUp\": {\n const prev = addMonths(base, -1)\n candidate = new Date(\n prev.getFullYear(),\n prev.getMonth(),\n Math.min(base.getDate(), daysInMonth(prev.getFullYear(), prev.getMonth())),\n )\n probeStep = 1\n break\n }\n case \"PageDown\": {\n const next = addMonths(base, 1)\n candidate = new Date(\n next.getFullYear(),\n next.getMonth(),\n Math.min(base.getDate(), daysInMonth(next.getFullYear(), next.getMonth())),\n )\n probeStep = 1\n break\n }\n case \"Enter\":\n case \" \":\n e.preventDefault()\n commitDay(base)\n return\n default:\n return\n }\n\n e.preventDefault()\n let target = firstAvailableFrom(candidate, probeStep, 62)\n if (!target && probeStep !== -1) target = firstAvailableFrom(candidate, -1, 62)\n if (target) moveFocusTo(target)\n }\n\n // Header prev/next adapt to the active view; disabled when the whole target\n // range is unavailable so navigation never lands on a dead page.\n const prevMonthDate = addMonths(viewDate, -1)\n const nextMonthDate = addMonths(viewDate, 1)\n\n let prevDisabled: boolean\n let nextDisabled: boolean\n let prevLabel: string\n let nextLabel: string\n\n if (view === \"days\") {\n prevDisabled = isMonthDisabled(prevMonthDate.getFullYear(), prevMonthDate.getMonth())\n nextDisabled = isMonthDisabled(nextMonthDate.getFullYear(), nextMonthDate.getMonth())\n prevLabel = \"Previous month\"\n nextLabel = \"Next month\"\n } else if (view === \"months\") {\n prevDisabled = isYearDisabled(viewDate.getFullYear() - 1)\n nextDisabled = isYearDisabled(viewDate.getFullYear() + 1)\n prevLabel = \"Previous year\"\n nextLabel = \"Next year\"\n } else {\n prevDisabled = rangeAllYearsDisabled(yearPageStart - YEARS_PER_PAGE, yearPageStart - 1)\n nextDisabled = rangeAllYearsDisabled(yearPageStart + YEARS_PER_PAGE, yearPageStart + YEARS_PER_PAGE * 2 - 1)\n prevLabel = `Previous ${YEARS_PER_PAGE} years`\n nextLabel = `Next ${YEARS_PER_PAGE} years`\n }\n\n const handlePrev = () => {\n if (view === \"days\") setViewDate(prevMonthDate)\n else if (view === \"months\") setViewDate(monthStart(viewDate.getFullYear() - 1, viewDate.getMonth()))\n else setYearPageStart((s) => s - YEARS_PER_PAGE)\n }\n const handleNext = () => {\n if (view === \"days\") setViewDate(nextMonthDate)\n else if (view === \"months\") setViewDate(monthStart(viewDate.getFullYear() + 1, viewDate.getMonth()))\n else setYearPageStart((s) => s + YEARS_PER_PAGE)\n }\n\n const openMonths = () => {\n if (view === \"months\") {\n setView(\"days\")\n pendingFocusRef.current = \"monthTrigger\"\n } else {\n setView(\"months\")\n pendingFocusRef.current = \"monthGrid\"\n }\n }\n const openYears = () => {\n if (view === \"years\") {\n setView(\"days\")\n pendingFocusRef.current = \"yearTrigger\"\n } else {\n setYearPageStart(Math.floor(viewDate.getFullYear() / YEARS_PER_PAGE) * YEARS_PER_PAGE)\n setView(\"years\")\n pendingFocusRef.current = \"yearGrid\"\n }\n }\n\n // Month selection: keep the year, return to days, focus the Month trigger.\n const handleMonthPick = (month: number) => {\n setViewDate(monthStart(viewDate.getFullYear(), month))\n setView(\"days\")\n pendingFocusRef.current = \"monthTrigger\"\n }\n // Year selection: keep the month, return to days (never months), focus Year.\n const handleYearPick = (year: number) => {\n setViewDate(monthStart(year, viewDate.getMonth()))\n setView(\"days\")\n pendingFocusRef.current = \"yearTrigger\"\n }\n\n const calendarDays = generateCalendarDays()\n const yearPage = Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPageStart + i)\n const overlayActive = view !== \"days\"\n\n const triggerClass =\n \"min-h-[1.5rem] px-1 text-base font-bold text-foreground underline decoration-1 underline-offset-4 decoration-border rounded-sm \" +\n \"hover:opacity-80 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n\n const gridCellClass =\n \"h-10 rounded-lg text-sm font-semibold transition-transform flex items-center justify-center \" +\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n\n return (\n <div className={cn(\"p-4 bg-card rounded-lg\", className)}>\n {/* Header — same footprint in every view. */}\n <div className=\"flex items-center justify-between mb-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 p-0\"\n aria-label={prevLabel}\n disabled={prevDisabled}\n onClick={handlePrev}\n >\n <ChevronLeft className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n\n <div className=\"flex items-center gap-1.5\">\n <button\n ref={monthTriggerRef}\n type=\"button\"\n onClick={openMonths}\n aria-expanded={view === \"months\"}\n aria-label={`Choose month, currently ${MONTHS[viewDate.getMonth()]}`}\n className={triggerClass}\n >\n {MONTHS[viewDate.getMonth()]}\n </button>\n <button\n ref={yearTriggerRef}\n type=\"button\"\n onClick={openYears}\n aria-expanded={view === \"years\"}\n aria-label={`Choose year, currently ${viewDate.getFullYear()}`}\n className={triggerClass}\n >\n {viewDate.getFullYear()}\n </button>\n </div>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 p-0\"\n aria-label={nextLabel}\n disabled={nextDisabled}\n onClick={handleNext}\n >\n <ChevronRight className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n </div>\n\n {/* One polite live region for the displayed month/year. */}\n <div aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {MONTHS[viewDate.getMonth()]} {viewDate.getFullYear()}\n </div>\n\n <div className=\"relative\">\n {/* Day grid — ALWAYS rendered so width and height stay stable; inert\n while a chooser overlay covers it. */}\n <div aria-hidden={overlayActive ? true : undefined}>\n <div className=\"grid grid-cols-7 gap-1 mb-2\">\n {DAYS.map((day, i) => (\n <div key={day} className=\"text-center text-sm font-bold py-2 text-foreground\" aria-hidden=\"true\">\n <span className=\"sr-only\">{DAY_NAMES_LONG[i]}</span>\n <span aria-hidden=\"true\">{day}</span>\n </div>\n ))}\n </div>\n\n <div\n ref={daysGridRef}\n className=\"grid grid-cols-7 gap-1\"\n role=\"group\"\n aria-label=\"Calendar\"\n onKeyDown={overlayActive ? undefined : handleDaysKeyDown}\n >\n {calendarDays.map((date, index) => {\n if (!date) return <div key={`empty-${index}`} className=\"h-9\" aria-hidden=\"true\" />\n\n const dateDisabled = isDateDisabled(date)\n const dateSelected = isSelectedDay(date)\n const todayDate = isTodayDate(date)\n const roving = isSameDay(date, rovingDate)\n const tabIndex = !overlayActive && roving ? 0 : -1\n\n return (\n <button\n key={date.toISOString()}\n type=\"button\"\n onClick={() => commitDay(date)}\n disabled={dateDisabled}\n tabIndex={tabIndex}\n data-roving={roving ? \"true\" : undefined}\n aria-label={fullDateLabel(date)}\n aria-pressed={dateSelected}\n aria-current={todayDate ? \"date\" : undefined}\n className={cn(\n \"h-9 w-9 rounded-lg text-sm font-semibold transition-transform\",\n \"motion-safe:hover:scale-105 motion-safe:active:scale-95\",\n \"flex items-center justify-center\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n !dateDisabled && !dateSelected && !todayDate && \"text-foreground hover:bg-primary/10\",\n todayDate && !dateSelected && \"bg-accent text-accent-foreground font-bold ring-2 ring-border\",\n dateSelected && \"bg-primary text-primary-foreground font-bold\",\n dateDisabled && \"opacity-30 cursor-not-allowed motion-safe:hover:scale-100 hover:bg-transparent relative\",\n )}\n >\n {date.getDate()}\n {dateDisabled && (\n <span className=\"absolute inset-0 flex items-center justify-center\" aria-hidden=\"true\">\n <span className=\"w-px h-full bg-current transform rotate-45\" />\n </span>\n )}\n </button>\n )\n })}\n </div>\n\n <div className=\"mt-4 pt-3 border-t border-border text-xs space-y-1\">\n <div className=\"flex items-center gap-2\">\n <div className=\"h-3 w-3 rounded-sm bg-primary\" aria-hidden=\"true\" />\n <span className=\"text-muted-foreground\">Selected</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"h-3 w-3 rounded-sm bg-accent ring-2 ring-border\" aria-hidden=\"true\" />\n <span className=\"text-muted-foreground\">Today</span>\n </div>\n {(disablePast || disableFuture || disabled) && (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-3 w-3 rounded-sm bg-muted opacity-30 relative\" aria-hidden=\"true\">\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"w-px h-full bg-foreground transform rotate-45\" />\n </div>\n </div>\n <span className=\"text-muted-foreground\">Unavailable</span>\n </div>\n )}\n </div>\n </div>\n\n {/* Month / year choosers overlay the day grid — same footprint. */}\n {overlayActive && (\n <div ref={overlayRef} className=\"absolute inset-0 bg-card rounded-lg flex flex-col justify-center\">\n {view === \"years\" && (\n <div className=\"mb-2 text-center text-sm font-semibold text-muted-foreground\" aria-hidden=\"true\">\n {yearPageStart} – {yearPageStart + YEARS_PER_PAGE - 1}\n </div>\n )}\n\n {view === \"months\" && (\n <div className=\"grid grid-cols-3 gap-1\">\n {MONTHS_SHORT.map((label, month) => {\n const monthDisabled = isMonthDisabled(viewDate.getFullYear(), month)\n const isViewMonth = month === viewDate.getMonth()\n return (\n <button\n key={label}\n type=\"button\"\n disabled={monthDisabled}\n data-active={isViewMonth ? \"true\" : undefined}\n aria-pressed={isViewMonth}\n aria-label={`${MONTHS[month]} ${viewDate.getFullYear()}`}\n onClick={() => handleMonthPick(month)}\n className={cn(\n gridCellClass,\n !monthDisabled && !isViewMonth && \"text-foreground hover:bg-primary/10\",\n isViewMonth && \"bg-primary text-primary-foreground font-bold\",\n monthDisabled && \"opacity-30 cursor-not-allowed\",\n )}\n >\n {label}\n </button>\n )\n })}\n </div>\n )}\n\n {view === \"years\" && (\n <div className=\"grid grid-cols-3 gap-1\">\n {yearPage.map((year) => {\n const yearDisabled = isYearDisabled(year)\n const isViewYear = year === viewDate.getFullYear()\n return (\n <button\n key={year}\n type=\"button\"\n disabled={yearDisabled}\n data-active={isViewYear ? \"true\" : undefined}\n aria-pressed={isViewYear}\n aria-label={`Year ${year}`}\n onClick={() => handleYearPick(year)}\n className={cn(\n gridCellClass,\n !yearDisabled && !isViewYear && \"text-foreground hover:bg-primary/10\",\n isViewYear && \"bg-primary text-primary-foreground font-bold\",\n yearDisabled && \"opacity-30 cursor-not-allowed\",\n )}\n >\n {year}\n </button>\n )\n })}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nDatePicker.displayName = \"DatePicker\"\n\nexport { DatePicker }\n"]}