@motir/design-system 0.20.0 → 0.21.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.
Files changed (36) hide show
  1. package/README.md +150 -5
  2. package/dist/components/theme/AppearancePickers.js +30 -2
  3. package/dist/components/theme/AppearancePickers.js.map +1 -1
  4. package/dist/components/ui/DatePicker.d.ts +31 -0
  5. package/dist/components/ui/DatePicker.js +442 -0
  6. package/dist/components/ui/DatePicker.js.map +1 -0
  7. package/dist/components/ui/DatePickerFormatContext.d.ts +26 -0
  8. package/dist/components/ui/DatePickerFormatContext.js +58 -0
  9. package/dist/components/ui/DatePickerFormatContext.js.map +1 -0
  10. package/dist/components/ui/datePickerFormat.d.ts +40 -0
  11. package/dist/components/ui/datePickerFormat.js +30 -0
  12. package/dist/components/ui/datePickerFormat.js.map +1 -0
  13. package/dist/contexts/theme-context.js +30 -2
  14. package/dist/contexts/theme-context.js.map +1 -1
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.js +5 -0
  17. package/dist/mock/index.js +30 -2
  18. package/dist/mock/index.js.map +1 -1
  19. package/dist/mock/renderMock.js +30 -2
  20. package/dist/mock/renderMock.js.map +1 -1
  21. package/dist/specimen/TokensSpecimen.js +2 -2
  22. package/dist/specimen/TokensSpecimen.js.map +1 -1
  23. package/dist/theme/appearance-resolution.js +30 -2
  24. package/dist/theme/appearance-resolution.js.map +1 -1
  25. package/dist/theme/init-script.js +30 -2
  26. package/dist/theme/init-script.js.map +1 -1
  27. package/dist/theme/styles.d.ts +1 -1
  28. package/dist/theme/styles.js +2 -2
  29. package/dist/theme/styles.js.map +1 -1
  30. package/dist/theme/types.js +2 -2
  31. package/dist/theme/types.js.map +1 -1
  32. package/dist/theme/typography.d.ts +46 -3
  33. package/dist/theme/typography.js +28 -0
  34. package/dist/theme/typography.js.map +1 -1
  35. package/package.json +1 -1
  36. package/theme.css +105 -1
@@ -0,0 +1,31 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { DatePickerLocale, DatePickerFormatter } from './datePickerFormat.js';
3
+
4
+ interface DatePickerProps {
5
+ /** Selected date as an ISO `YYYY-MM-DD` string, or null when unset. */
6
+ value: string | null;
7
+ /** Called with the next `YYYY-MM-DD` string, or null when cleared. */
8
+ onChange: (next: string | null) => void;
9
+ disabled?: boolean;
10
+ /** Trigger text when nothing is selected. */
11
+ placeholder?: string;
12
+ /** Accessible name for the trigger + calendar dialog. */
13
+ 'aria-label'?: string;
14
+ /** id for the trigger button (e.g. to pair with an external label). */
15
+ id?: string;
16
+ /** Open the calendar as soon as the field mounts (the rail's inline-edit entry). */
17
+ autoOpen?: boolean;
18
+ /** Fired when the calendar closes via Radix (outside-click / Escape / trigger
19
+ * toggle) — the inline-edit cell uses it to leave edit mode (Subtask 2.5.5).
20
+ * A day-pick commits through `onChange` and closes directly, so this fires
21
+ * only for a dismiss-without-pick. */
22
+ onClose?: () => void;
23
+ className?: string;
24
+ /** Locale the trigger formats the date in. Beats a `DatePickerFormatProvider`'s. */
25
+ locale?: DatePickerLocale;
26
+ /** Formatter for the trigger date, `(isoDate, locale) => string`. Beats the provider's. */
27
+ formatDate?: DatePickerFormatter;
28
+ }
29
+ declare function DatePicker({ value, onChange, disabled, placeholder, 'aria-label': ariaLabel, id, autoOpen, onClose, className, locale, formatDate, }: DatePickerProps): react_jsx_runtime.JSX.Element;
30
+
31
+ export { DatePicker, type DatePickerProps };
@@ -0,0 +1,442 @@
1
+ 'use client';
2
+ import { forwardRef, useRef, useCallback, useState, useSyncExternalStore, useId, useEffect } from 'react';
3
+ import { Calendar, X, ChevronLeft, ChevronRight } from 'lucide-react';
4
+ import * as RadixPopover from '@radix-ui/react-popover';
5
+ import { clsx } from 'clsx';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+ import { useDatePickerFormat } from './DatePickerFormatContext.js';
9
+
10
+ function cn(...inputs) {
11
+ return twMerge(clsx(inputs));
12
+ }
13
+ function getServerSnapshot() {
14
+ return null;
15
+ }
16
+ function usePortalContainer(own) {
17
+ const [store] = useState(() => createPortalContainerStore(own));
18
+ return useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);
19
+ }
20
+ function createPortalContainerStore(own) {
21
+ let container = typeof document === "undefined" ? null : document.fullscreenElement ?? null;
22
+ return {
23
+ subscribe(onChange) {
24
+ const sync = () => {
25
+ const next = document.fullscreenElement ?? null;
26
+ const root = own.current;
27
+ if (next !== null && root !== null && root.contains(next)) return;
28
+ if (next === container) return;
29
+ container = next;
30
+ onChange();
31
+ };
32
+ sync();
33
+ document.addEventListener("fullscreenchange", sync);
34
+ return () => document.removeEventListener("fullscreenchange", sync);
35
+ },
36
+ getSnapshot: () => container
37
+ };
38
+ }
39
+ function PopoverRoot({ open, onOpenChange, modal, children }) {
40
+ return /* @__PURE__ */ jsx(RadixPopover.Root, { open, onOpenChange, modal, children });
41
+ }
42
+ var PopoverContent = forwardRef(function PopoverContent2({
43
+ className,
44
+ align = "start",
45
+ sideOffset = 8,
46
+ width = 320,
47
+ style,
48
+ children,
49
+ overflowVisible = false,
50
+ ...rest
51
+ }, ref) {
52
+ const contentRef = useRef(null);
53
+ const setContentRef = useCallback(
54
+ (node) => {
55
+ contentRef.current = node;
56
+ if (typeof ref === "function") ref(node);
57
+ else if (ref) ref.current = node;
58
+ },
59
+ [ref]
60
+ );
61
+ const fullscreenContainer = usePortalContainer(contentRef);
62
+ return /* @__PURE__ */ jsx(RadixPopover.Portal, { container: fullscreenContainer ?? void 0, children: /* @__PURE__ */ jsx(
63
+ RadixPopover.Content,
64
+ {
65
+ ref: setContentRef,
66
+ align,
67
+ sideOffset,
68
+ "data-surface": "popover",
69
+ className: cn(
70
+ "z-50 rounded-(--radius-card) bg-(--el-page-bg)",
71
+ overflowVisible ? "overflow-visible" : "overflow-hidden",
72
+ "shadow-(--shadow-elevated) border border-(--el-border)",
73
+ "focus:outline-none",
74
+ // NO entry/exit animation utilities here. Overlay motion is the
75
+ // THEME's, declared per style in `theme.css` against the
76
+ // `data-surface="popover"` hook above and gated behind
77
+ // `prefers-reduced-motion` — see the `immersive-menu-open` block.
78
+ // `animate-in` / `fade-in-0` are a Tailwind PLUGIN's vocabulary this
79
+ // repository has never installed, so they generated nothing
80
+ // (MOTIR-4889); `tests/theme/no-inert-animation-utilities.test.ts`
81
+ // keeps them out.
82
+ className
83
+ ),
84
+ style: { width: typeof width === "number" ? `${width}px` : width, ...style },
85
+ ...rest,
86
+ children
87
+ }
88
+ ) });
89
+ });
90
+ var PopoverTrigger = RadixPopover.Trigger;
91
+ var PopoverClose = RadixPopover.Close;
92
+ var PopoverAnchor = RadixPopover.Anchor;
93
+ var Popover = Object.assign(PopoverRoot, {
94
+ Trigger: PopoverTrigger,
95
+ Content: PopoverContent,
96
+ Close: PopoverClose,
97
+ Anchor: PopoverAnchor
98
+ });
99
+ var WEEKDAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
100
+ var WEEKDAY_LABELS = [
101
+ "Sunday",
102
+ "Monday",
103
+ "Tuesday",
104
+ "Wednesday",
105
+ "Thursday",
106
+ "Friday",
107
+ "Saturday"
108
+ ];
109
+ var MONTHS = [
110
+ "January",
111
+ "February",
112
+ "March",
113
+ "April",
114
+ "May",
115
+ "June",
116
+ "July",
117
+ "August",
118
+ "September",
119
+ "October",
120
+ "November",
121
+ "December"
122
+ ];
123
+ var pad = (n) => String(n).padStart(2, "0");
124
+ var toKey = ({ y, m, d }) => `${y}-${pad(m + 1)}-${pad(d)}`;
125
+ var sameDay = (a, b) => a.y === b.y && a.m === b.m && a.d === b.d;
126
+ function parseKey(value) {
127
+ if (!value) return null;
128
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
129
+ if (!match) return null;
130
+ return { y: Number(match[1]), m: Number(match[2]) - 1, d: Number(match[3]) };
131
+ }
132
+ function todayUTC() {
133
+ const now = /* @__PURE__ */ new Date();
134
+ return { y: now.getUTCFullYear(), m: now.getUTCMonth(), d: now.getUTCDate() };
135
+ }
136
+ function addDays({ y, m, d }, days) {
137
+ const dt = new Date(Date.UTC(y, m, d + days));
138
+ return { y: dt.getUTCFullYear(), m: dt.getUTCMonth(), d: dt.getUTCDate() };
139
+ }
140
+ function addMonths({ y, m, d }, delta) {
141
+ const base = new Date(Date.UTC(y, m + delta, 1));
142
+ const ny = base.getUTCFullYear();
143
+ const nm = base.getUTCMonth();
144
+ const lastDay = new Date(Date.UTC(ny, nm + 1, 0)).getUTCDate();
145
+ return { y: ny, m: nm, d: Math.min(d, lastDay) };
146
+ }
147
+ function monthGrid(y, m) {
148
+ const firstDow = new Date(Date.UTC(y, m, 1)).getUTCDay();
149
+ const start = new Date(Date.UTC(y, m, 1 - firstDow));
150
+ return Array.from({ length: 42 }, (_, i) => {
151
+ const dt = new Date(
152
+ Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate() + i)
153
+ );
154
+ return { y: dt.getUTCFullYear(), m: dt.getUTCMonth(), d: dt.getUTCDate() };
155
+ });
156
+ }
157
+ function DatePicker({
158
+ value,
159
+ onChange,
160
+ disabled = false,
161
+ placeholder = "Select a date",
162
+ "aria-label": ariaLabel = "Date",
163
+ id,
164
+ autoOpen = false,
165
+ onClose,
166
+ className,
167
+ locale,
168
+ formatDate
169
+ }) {
170
+ const selected = parseKey(value);
171
+ const [open, setOpen] = useState(autoOpen && !disabled);
172
+ const [view, setView] = useState(() => {
173
+ const seed = selected ?? todayUTC();
174
+ return { y: seed.y, m: seed.m };
175
+ });
176
+ const [focusKey, setFocusKey] = useState(() => toKey(selected ?? todayUTC()));
177
+ const gridRef = useRef(null);
178
+ const format = useDatePickerFormat({ locale, formatDate });
179
+ const baseId = useId();
180
+ const captionId = `${baseId}-caption`;
181
+ const today = todayUTC();
182
+ useEffect(() => {
183
+ if (!open) return;
184
+ const el = gridRef.current?.querySelector(`button[data-key="${focusKey}"]`);
185
+ el?.focus();
186
+ }, [open, focusKey, view.y, view.m]);
187
+ function handleOpenChange(next) {
188
+ if (disabled) return;
189
+ if (next) {
190
+ const anchor = parseKey(value) ?? todayUTC();
191
+ setView({ y: anchor.y, m: anchor.m });
192
+ setFocusKey(toKey(anchor));
193
+ } else {
194
+ onClose?.();
195
+ }
196
+ setOpen(next);
197
+ }
198
+ function moveFocus(next) {
199
+ setView({ y: next.y, m: next.m });
200
+ setFocusKey(toKey(next));
201
+ }
202
+ function select(day) {
203
+ if (disabled) return;
204
+ onChange(toKey(day));
205
+ setOpen(false);
206
+ }
207
+ function onGridKeyDown(e) {
208
+ const cur = parseKey(focusKey);
209
+ if (!cur) return;
210
+ switch (e.key) {
211
+ case "ArrowLeft":
212
+ e.preventDefault();
213
+ moveFocus(addDays(cur, -1));
214
+ break;
215
+ case "ArrowRight":
216
+ e.preventDefault();
217
+ moveFocus(addDays(cur, 1));
218
+ break;
219
+ case "ArrowUp":
220
+ e.preventDefault();
221
+ moveFocus(addDays(cur, -7));
222
+ break;
223
+ case "ArrowDown":
224
+ e.preventDefault();
225
+ moveFocus(addDays(cur, 7));
226
+ break;
227
+ case "PageUp":
228
+ e.preventDefault();
229
+ moveFocus(addMonths(cur, -1));
230
+ break;
231
+ case "PageDown":
232
+ e.preventDefault();
233
+ moveFocus(addMonths(cur, 1));
234
+ break;
235
+ case "Home": {
236
+ e.preventDefault();
237
+ const dow = new Date(Date.UTC(cur.y, cur.m, cur.d)).getUTCDay();
238
+ moveFocus(addDays(cur, -dow));
239
+ break;
240
+ }
241
+ case "End": {
242
+ e.preventDefault();
243
+ const dow = new Date(Date.UTC(cur.y, cur.m, cur.d)).getUTCDay();
244
+ moveFocus(addDays(cur, 6 - dow));
245
+ break;
246
+ }
247
+ case "Enter":
248
+ case " ":
249
+ e.preventDefault();
250
+ select(cur);
251
+ break;
252
+ }
253
+ }
254
+ const cells = monthGrid(view.y, view.m);
255
+ const triggerLabel = selected && value ? format.formatDate(value) : placeholder;
256
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
257
+ /* @__PURE__ */ jsx(Popover.Anchor, { asChild: true, children: /* @__PURE__ */ jsxs(
258
+ "div",
259
+ {
260
+ className: cn(
261
+ "flex h-(--height-input) w-full items-center gap-2 rounded-(--radius-input) border bg-(--el-page-bg)",
262
+ "border-(--el-border-strong) px-(--spacing-input-x)",
263
+ "focus-within:ring-2 focus-within:ring-(--focus-ring-color) focus-within:ring-offset-2 focus-within:ring-offset-background",
264
+ disabled && "cursor-not-allowed opacity-50",
265
+ className
266
+ ),
267
+ children: [
268
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
269
+ "button",
270
+ {
271
+ type: "button",
272
+ id,
273
+ disabled,
274
+ "aria-label": ariaLabel,
275
+ className: "flex flex-1 items-center gap-2 truncate bg-transparent text-left text-sm outline-none disabled:cursor-not-allowed",
276
+ children: [
277
+ /* @__PURE__ */ jsx(Calendar, { className: "h-4 w-4 shrink-0 text-(--el-icon-field)", "aria-hidden": true }),
278
+ /* @__PURE__ */ jsx(
279
+ "span",
280
+ {
281
+ className: cn(
282
+ "flex-1 truncate",
283
+ selected ? "text-(--el-text)" : "text-(--el-text-muted)"
284
+ ),
285
+ children: triggerLabel
286
+ }
287
+ )
288
+ ]
289
+ }
290
+ ) }),
291
+ selected && !disabled ? /* @__PURE__ */ jsx(
292
+ "button",
293
+ {
294
+ type: "button",
295
+ "aria-label": "Clear date",
296
+ onClick: () => onChange(null),
297
+ className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-(--radius-control) text-(--el-text-muted) hover:bg-(--el-tint-rose) hover:text-(--el-danger)",
298
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5", "aria-hidden": true })
299
+ }
300
+ ) : null
301
+ ]
302
+ }
303
+ ) }),
304
+ /* @__PURE__ */ jsxs(
305
+ Popover.Content,
306
+ {
307
+ width: 296,
308
+ align: "start",
309
+ role: "dialog",
310
+ "aria-label": ariaLabel,
311
+ className: "p-3",
312
+ onOpenAutoFocus: (e) => {
313
+ e.preventDefault();
314
+ gridRef.current?.querySelector(`button[data-key="${focusKey}"]`)?.focus();
315
+ },
316
+ children: [
317
+ /* @__PURE__ */ jsxs("div", { className: "mb-2.5 flex items-center justify-between px-1", children: [
318
+ /* @__PURE__ */ jsxs(
319
+ "span",
320
+ {
321
+ id: captionId,
322
+ className: "text-sm font-semibold text-(--el-text)",
323
+ "aria-live": "polite",
324
+ children: [
325
+ MONTHS[view.m],
326
+ " ",
327
+ view.y
328
+ ]
329
+ }
330
+ ),
331
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-0.5", children: [
332
+ /* @__PURE__ */ jsx(
333
+ "button",
334
+ {
335
+ type: "button",
336
+ "aria-label": "Previous month",
337
+ onClick: () => setView((v) => v.m === 0 ? { y: v.y - 1, m: 11 } : { y: v.y, m: v.m - 1 }),
338
+ className: "inline-flex h-(--height-control-28) w-7 items-center justify-center rounded-(--radius-control) text-(--el-text-muted) hover:bg-(--el-surface) hover:text-(--el-text)",
339
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-[18px] w-[18px]", "aria-hidden": true })
340
+ }
341
+ ),
342
+ /* @__PURE__ */ jsx(
343
+ "button",
344
+ {
345
+ type: "button",
346
+ "aria-label": "Next month",
347
+ onClick: () => setView((v) => v.m === 11 ? { y: v.y + 1, m: 0 } : { y: v.y, m: v.m + 1 }),
348
+ className: "inline-flex h-(--height-control-28) w-7 items-center justify-center rounded-(--radius-control) text-(--el-text-muted) hover:bg-(--el-surface) hover:text-(--el-text)",
349
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-[18px] w-[18px]", "aria-hidden": true })
350
+ }
351
+ )
352
+ ] })
353
+ ] }),
354
+ /* @__PURE__ */ jsxs("div", { ref: gridRef, role: "grid", "aria-labelledby": captionId, onKeyDown: onGridKeyDown, children: [
355
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7", children: WEEKDAYS.map((wd, i) => /* @__PURE__ */ jsx(
356
+ "span",
357
+ {
358
+ role: "columnheader",
359
+ "aria-label": WEEKDAY_LABELS[i],
360
+ className: "flex h-7 items-center justify-center text-[11px] font-semibold uppercase text-(--el-text-secondary)",
361
+ children: wd
362
+ },
363
+ wd
364
+ )) }),
365
+ Array.from({ length: 6 }, (_, week) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7", children: cells.slice(week * 7, week * 7 + 7).map((day) => {
366
+ const key = toKey(day);
367
+ const isOutside = day.m !== view.m;
368
+ const isSelected = selected ? sameDay(day, selected) : false;
369
+ const isToday = sameDay(day, today);
370
+ return /* @__PURE__ */ jsx(
371
+ "div",
372
+ {
373
+ role: "gridcell",
374
+ "aria-selected": isSelected,
375
+ className: "flex justify-center",
376
+ children: /* @__PURE__ */ jsxs(
377
+ "button",
378
+ {
379
+ type: "button",
380
+ "data-key": key,
381
+ tabIndex: key === focusKey ? 0 : -1,
382
+ "aria-label": `${MONTHS[day.m]} ${day.d}, ${day.y}`,
383
+ "aria-current": isToday ? "date" : void 0,
384
+ onClick: () => select(day),
385
+ className: cn(
386
+ "relative flex h-(--height-control) w-9 items-center justify-center rounded-(--radius-control) border border-transparent text-sm",
387
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--focus-ring-color)",
388
+ isOutside && "text-(--el-text-secondary)",
389
+ !isOutside && "text-(--el-text)",
390
+ !isSelected && "hover:bg-(--el-surface)",
391
+ isToday && !isSelected && "border-(--el-border-strong) font-bold",
392
+ isSelected && "border-transparent bg-(--el-accent) font-bold text-(--el-accent-text) hover:bg-(--el-accent-pressed)"
393
+ ),
394
+ children: [
395
+ day.d,
396
+ isToday && !isSelected ? /* @__PURE__ */ jsx(
397
+ "span",
398
+ {
399
+ "aria-hidden": true,
400
+ className: "absolute bottom-1 left-1/2 h-1 w-1 -translate-x-1/2 rounded-full bg-(--el-accent)"
401
+ }
402
+ ) : null
403
+ ]
404
+ }
405
+ )
406
+ },
407
+ key
408
+ );
409
+ }) }, week))
410
+ ] }),
411
+ /* @__PURE__ */ jsxs("div", { className: "mt-2.5 flex items-center justify-between border-t border-(--el-border-soft) pt-2.5", children: [
412
+ /* @__PURE__ */ jsx(
413
+ "button",
414
+ {
415
+ type: "button",
416
+ onClick: () => moveFocus(todayUTC()),
417
+ className: "rounded-(--radius-control) px-(--spacing-control-x-6) py-(--spacing-control-y-4) text-sm font-medium text-(--el-link) hover:bg-(--el-surface)",
418
+ children: "Today"
419
+ }
420
+ ),
421
+ /* @__PURE__ */ jsx(
422
+ "button",
423
+ {
424
+ type: "button",
425
+ onClick: () => {
426
+ onChange(null);
427
+ setOpen(false);
428
+ },
429
+ className: "rounded-(--radius-control) px-(--spacing-control-x-6) py-(--spacing-control-y-4) text-sm font-medium text-(--el-text-secondary) hover:bg-(--el-surface)",
430
+ children: "Clear"
431
+ }
432
+ )
433
+ ] })
434
+ ]
435
+ }
436
+ )
437
+ ] });
438
+ }
439
+
440
+ export { DatePicker };
441
+ //# sourceMappingURL=DatePicker.js.map
442
+ //# sourceMappingURL=DatePicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/cn.ts","../../../src/utils/fullscreen.ts","../../../src/components/ui/Popover.tsx","../../../src/components/ui/DatePicker.tsx"],"names":["PopoverContent","useState","useRef","jsx"],"mappings":"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","file":"DatePicker.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge Tailwind class names without conflicts.\n *\n * `clsx` handles conditional inclusion (booleans, undefineds, arrays);\n * `twMerge` resolves conflicting Tailwind classes (later wins, e.g.\n * `px-2 px-4` → `px-4`). Together they are the de facto standard for\n * composing Tailwind classes in React components.\n *\n * @example\n * cn('px-2 py-1', isActive && 'bg-primary', className)\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport { useState, useSyncExternalStore, type RefObject } from 'react';\n\n/**\n * The element currently in NATIVE full screen (`document.fullscreenElement`), or\n * `null` — re-read on every `fullscreenchange`.\n *\n * While an element is in native full screen the browser paints ONLY that\n * element's subtree, in the top layer. Anything portalled to `document.body` —\n * a dialog, a popover, a picker's menu — is not shown at all, whatever its\n * z-index (MOTIR-7658: the roadmap canvas's quick view opened invisibly and\n * held focus and scroll lock until Esc).\n *\n * A portalling primitive does not use this directly: it uses\n * `usePortalContainer`, which also refuses to follow full screen into the\n * primitive's own subtree.\n *\n * `null` on the server and in a document with no Fullscreen API.\n */\nexport function useFullscreenElement(): Element | null {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\nfunction subscribe(onChange: () => void): () => void {\n document.addEventListener('fullscreenchange', onChange);\n return () => document.removeEventListener('fullscreenchange', onChange);\n}\n\nfunction getSnapshot(): Element | null {\n return document.fullscreenElement ?? null;\n}\n\nfunction getServerSnapshot(): null {\n return null;\n}\n\n/**\n * The element a portalling surface mounts into: the element in native full\n * screen while there is one (MOTIR-7658), else `null` — which the caller turns\n * into `document.body`.\n *\n * `own` is the surface's portalled root (a dialog's content, a menu). When the\n * element that goes full screen is INSIDE it — the native full-screen button of\n * a `<video>` in a dialog — the container stays where it was (MOTIR-8560).\n * Following it would re-portal the surface into its own descendant: React\n * unmounts the subtree to move it, the full-screen element leaves the document,\n * the browser exits full screen, and the surface snaps back to a fresh copy.\n *\n * `null` on the server and in a document with no Fullscreen API.\n */\nexport function usePortalContainer(own: RefObject<Element | null>): Element | null {\n const [store] = useState(() => createPortalContainerStore(own));\n return useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n}\n\nfunction createPortalContainerStore(own: RefObject<Element | null>) {\n let container: Element | null =\n typeof document === 'undefined' ? null : (document.fullscreenElement ?? null);\n return {\n subscribe(onChange: () => void): () => void {\n const sync = () => {\n const next = document.fullscreenElement ?? null;\n const root = own.current;\n // The surface's own descendant went full screen: stay put.\n if (next !== null && root !== null && root.contains(next)) return;\n if (next === container) return;\n container = next;\n onChange();\n };\n // A change between creating the store and subscribing to it.\n sync();\n document.addEventListener('fullscreenchange', sync);\n return () => document.removeEventListener('fullscreenchange', sync);\n },\n getSnapshot: (): Element | null => container,\n };\n}\n","'use client';\n\nimport {\n forwardRef,\n useCallback,\n useRef,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from 'react';\nimport * as RadixPopover from '@radix-ui/react-popover';\nimport { cn } from '../../utils/cn';\nimport { usePortalContainer } from '../../utils/fullscreen';\n\n/**\n * Popover — anchored, click-outside-dismissable, focus-managed floating\n * panel wrapping @radix-ui/react-popover.\n *\n * Same shape as Modal.tsx (Radix-wrapped, controlled open state). Unlike\n * Modal, the content is anchored to a trigger rather than centered, and\n * there is no overlay — clicking outside dismisses. Use it for menus and\n * dropdowns where the panel holds free-form content (the workspace\n * switcher's section header + membership rows, the user menu).\n *\n * Portal + border + shadow match Modal so the two primitives feel\n * consistent. No new tokens — reuses --radius-card, --shadow-elevated,\n * --color-hairline.\n *\n * @example\n * <Popover open={open} onOpenChange={setOpen}>\n * <Popover.Trigger asChild>\n * <Button variant=\"ghost\" rightIcon={<ChevronDown />}>Menu</Button>\n * </Popover.Trigger>\n * <Popover.Content align=\"start\">{items}</Popover.Content>\n * </Popover>\n */\nexport interface PopoverProps {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n modal?: boolean;\n children: ReactNode;\n}\n\nfunction PopoverRoot({ open, onOpenChange, modal, children }: PopoverProps) {\n return (\n <RadixPopover.Root open={open} onOpenChange={onOpenChange} modal={modal}>\n {children}\n </RadixPopover.Root>\n );\n}\n\nexport interface PopoverContentProps extends ComponentPropsWithoutRef<typeof RadixPopover.Content> {\n /** Panel width; defaults to the 320px the switcher mockup pins. */\n width?: number | string;\n /**\n * Drop the panel's `overflow-hidden` so a child anchored dropdown — e.g. a\n * `Combobox` listbox — can render past the panel's edge instead of being\n * clipped by it. Set this whenever the popover hosts a `Combobox` (or any\n * other absolutely-positioned floating child) whose menu can grow taller\n * than the popover's content-sized height — a real-product Jira-style\n * dropdown-inside-popover (mark-duplicate target, promote sprint picker)\n * always escapes its anchor (`bug-combobox-menu-clipped-inside-popover`).\n *\n * Safe because the popover's own padding (`p-2`, `p-3`) keeps children off\n * the rounded corners, so the corners stay clean without overflow clipping;\n * and the Combobox menu stays in the popover's DOM subtree so non-modal\n * Radix Popover does not treat its clicks as outside-dismissals.\n *\n * Leave unset for popovers that hold only static rows (the workspace\n * switcher, the user menu) — the default `overflow-hidden` is fine and\n * cheaper to reason about.\n */\n overflowVisible?: boolean;\n}\n\nconst PopoverContent = forwardRef<\n React.ElementRef<typeof RadixPopover.Content>,\n PopoverContentProps\n>(function PopoverContent(\n {\n className,\n align = 'start',\n sideOffset = 8,\n width = 320,\n style,\n children,\n overflowVisible = false,\n ...rest\n },\n ref,\n) {\n // Into the element in native full screen while there is one, else <body>\n // (MOTIR-7658 — the browser paints nothing outside a full-screen element),\n // unless that element is inside this panel (MOTIR-8560).\n const contentRef = useRef<HTMLDivElement | null>(null);\n const setContentRef = useCallback(\n (node: HTMLDivElement | null) => {\n contentRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n const fullscreenContainer = usePortalContainer(contentRef);\n return (\n <RadixPopover.Portal container={fullscreenContainer ?? undefined}>\n <RadixPopover.Content\n ref={setContentRef}\n align={align}\n sideOffset={sideOffset}\n // `data-surface` lets a surface-material style (glassmorphism) frost\n // the floating panel — see globals.css's material layer.\n data-surface=\"popover\"\n className={cn(\n 'z-50 rounded-(--radius-card) bg-(--el-page-bg)',\n overflowVisible ? 'overflow-visible' : 'overflow-hidden',\n 'shadow-(--shadow-elevated) border border-(--el-border)',\n 'focus:outline-none',\n // NO entry/exit animation utilities here. Overlay motion is the\n // THEME's, declared per style in `theme.css` against the\n // `data-surface=\"popover\"` hook above and gated behind\n // `prefers-reduced-motion` — see the `immersive-menu-open` block.\n // `animate-in` / `fade-in-0` are a Tailwind PLUGIN's vocabulary this\n // repository has never installed, so they generated nothing\n // (MOTIR-4889); `tests/theme/no-inert-animation-utilities.test.ts`\n // keeps them out.\n className,\n )}\n style={{ width: typeof width === 'number' ? `${width}px` : width, ...style }}\n {...rest}\n >\n {children}\n </RadixPopover.Content>\n </RadixPopover.Portal>\n );\n});\n\nconst PopoverTrigger = RadixPopover.Trigger;\nconst PopoverClose = RadixPopover.Close;\nconst PopoverAnchor = RadixPopover.Anchor;\n\nexport const Popover = Object.assign(PopoverRoot, {\n Trigger: PopoverTrigger,\n Content: PopoverContent,\n Close: PopoverClose,\n Anchor: PopoverAnchor,\n});\n","'use client';\n\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { Calendar, ChevronLeft, ChevronRight, X } from 'lucide-react';\nimport { Popover } from './Popover';\nimport { cn } from '../../utils/cn';\nimport type { DatePickerFormatter, DatePickerLocale } from './datePickerFormat';\nimport { useDatePickerFormat } from './DatePickerFormatContext';\n\n/**\n * DatePicker — the design-system replacement for the native `<input type=\"date\">`\n * calendar popup (Subtask 2.4.12, design `design/work-items/datepicker.mock.html`).\n * An `Input`-styled trigger field (selected date or placeholder + a Clear control)\n * opens an anchored `Popover` holding a month grid.\n *\n * Moved into `@motir/design-system` from motir-core's `components/ui/` (Story\n * MOTIR-10551) so any app on the package can use it. It needs no i18n library:\n * the trigger formats the selected date with an INJECTED locale + formatter —\n * the `locale` / `formatDate` props, else the nearest `DatePickerFormatProvider`,\n * else the default (locale `en`, a UTC formatter: `2026-06-03` → `Jun 3, 2026`),\n * resolved per input. The calendar's own strings (month and weekday names,\n * `Select a date`, `Clear date`, `Today`, `Clear`) stay English.\n *\n * Pure presentation: no queries, no Server Actions. The value crosses as an ISO\n * `YYYY-MM-DD` string (or null) — exactly what the issue forms already hold — so\n * the swap is drop-in: `value` + `onChange(next)` + `disabled`. All date math is\n * UTC-based (via `Date.UTC` / `getUTC*`), so there is no off-by-one from\n * local-timezone parsing — the same guard the ISO-string shape already gives the\n * forms.\n *\n * A11y: the WAI-ARIA dialog + grid date-picker pattern, hand-rolled like\n * `Combobox` / `TreeTable`. The trigger is a labelled button (Radix Popover gives\n * it `aria-haspopup=\"dialog\"`); the panel is a labelled `dialog` holding a\n * `role=\"grid\"` of day buttons with roving tabindex + the 2.4.11 keyboard model\n * (arrows / PageUp-Down / Home-End / Enter / Esc). Today carries\n * `aria-current=\"date\"`, the selected day `aria-selected` — per the WAI-ARIA APG\n * (the durable a11y standard; the 2.4.12 card's \"aria-current on selected\" is the\n * looser reading, deferred to the APG split). Themed through `--el-*` only.\n *\n * @example\n * <DatePicker value={dueDate} onChange={setDueDate} aria-label=\"Due date\" />\n */\nconst WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] as const;\nconst WEEKDAY_LABELS = [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n] as const;\nconst MONTHS = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n] as const;\n\ninterface YMD {\n y: number;\n m: number; // 0-indexed month\n d: number;\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\nconst toKey = ({ y, m, d }: YMD) => `${y}-${pad(m + 1)}-${pad(d)}`;\nconst sameDay = (a: YMD, b: YMD) => a.y === b.y && a.m === b.m && a.d === b.d;\n\nfunction parseKey(value: string | null): YMD | null {\n if (!value) return null;\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value);\n if (!match) return null;\n return { y: Number(match[1]), m: Number(match[2]) - 1, d: Number(match[3]) };\n}\n\n/** Today as a UTC calendar date — matches the UTC formatting the trigger uses. */\nfunction todayUTC(): YMD {\n const now = new Date();\n return { y: now.getUTCFullYear(), m: now.getUTCMonth(), d: now.getUTCDate() };\n}\n\n/** Shift a date by ±days, normalising month/year rollover via Date.UTC. */\nfunction addDays({ y, m, d }: YMD, days: number): YMD {\n const dt = new Date(Date.UTC(y, m, d + days));\n return { y: dt.getUTCFullYear(), m: dt.getUTCMonth(), d: dt.getUTCDate() };\n}\n\n/** Same day-of-month in the month `delta` away, clamped to that month's length. */\nfunction addMonths({ y, m, d }: YMD, delta: number): YMD {\n const base = new Date(Date.UTC(y, m + delta, 1));\n const ny = base.getUTCFullYear();\n const nm = base.getUTCMonth();\n const lastDay = new Date(Date.UTC(ny, nm + 1, 0)).getUTCDate();\n return { y: ny, m: nm, d: Math.min(d, lastDay) };\n}\n\n/** The 42 cells (6 weeks) of the month grid, starting on the Sunday on/before the 1st. */\nfunction monthGrid(y: number, m: number): YMD[] {\n const firstDow = new Date(Date.UTC(y, m, 1)).getUTCDay();\n const start = new Date(Date.UTC(y, m, 1 - firstDow));\n return Array.from({ length: 42 }, (_, i) => {\n const dt = new Date(\n Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate() + i),\n );\n return { y: dt.getUTCFullYear(), m: dt.getUTCMonth(), d: dt.getUTCDate() };\n });\n}\n\nexport interface DatePickerProps {\n /** Selected date as an ISO `YYYY-MM-DD` string, or null when unset. */\n value: string | null;\n /** Called with the next `YYYY-MM-DD` string, or null when cleared. */\n onChange: (next: string | null) => void;\n disabled?: boolean;\n /** Trigger text when nothing is selected. */\n placeholder?: string;\n /** Accessible name for the trigger + calendar dialog. */\n 'aria-label'?: string;\n /** id for the trigger button (e.g. to pair with an external label). */\n id?: string;\n /** Open the calendar as soon as the field mounts (the rail's inline-edit entry). */\n autoOpen?: boolean;\n /** Fired when the calendar closes via Radix (outside-click / Escape / trigger\n * toggle) — the inline-edit cell uses it to leave edit mode (Subtask 2.5.5).\n * A day-pick commits through `onChange` and closes directly, so this fires\n * only for a dismiss-without-pick. */\n onClose?: () => void;\n className?: string;\n /** Locale the trigger formats the date in. Beats a `DatePickerFormatProvider`'s. */\n locale?: DatePickerLocale;\n /** Formatter for the trigger date, `(isoDate, locale) => string`. Beats the provider's. */\n formatDate?: DatePickerFormatter;\n}\n\nexport function DatePicker({\n value,\n onChange,\n disabled = false,\n placeholder = 'Select a date',\n 'aria-label': ariaLabel = 'Date',\n id,\n autoOpen = false,\n onClose,\n className,\n locale,\n formatDate,\n}: DatePickerProps) {\n const selected = parseKey(value);\n // Disabled never opens, `autoOpen` included (MOTIR-6173 — the MOTIR-4822 path).\n const [open, setOpen] = useState(autoOpen && !disabled);\n // The month on screen + the day holding roving focus. Seeded on each open.\n const [view, setView] = useState<{ y: number; m: number }>(() => {\n const seed = selected ?? todayUTC();\n return { y: seed.y, m: seed.m };\n });\n const [focusKey, setFocusKey] = useState<string>(() => toKey(selected ?? todayUTC()));\n\n const gridRef = useRef<HTMLDivElement>(null);\n // Prop → provider → default, per input (the precedence lives in the resolver).\n const format = useDatePickerFormat({ locale, formatDate });\n const baseId = useId();\n const captionId = `${baseId}-caption`;\n const today = todayUTC();\n\n // Move DOM focus to the roving day whenever it (or the open month) changes —\n // a pure DOM side-effect, never setState (the seeding lives in handleOpenChange\n // so this effect can't cascade). The initial autoOpen anchor comes from the\n // useState initializers above.\n useEffect(() => {\n if (!open) return;\n const el = gridRef.current?.querySelector<HTMLButtonElement>(`button[data-key=\"${focusKey}\"]`);\n el?.focus();\n }, [open, focusKey, view.y, view.m]);\n\n // Re-seed the view + roving focus to the selected day (or today) every time the\n // calendar opens — in the open handler, not an effect, so re-opening after an\n // external value change re-anchors without a setState-in-effect cascade.\n function handleOpenChange(next: boolean) {\n if (disabled) return;\n if (next) {\n const anchor = parseKey(value) ?? todayUTC();\n setView({ y: anchor.y, m: anchor.m });\n setFocusKey(toKey(anchor));\n } else {\n onClose?.();\n }\n setOpen(next);\n }\n\n function moveFocus(next: YMD) {\n setView({ y: next.y, m: next.m });\n setFocusKey(toKey(next));\n }\n\n function select(day: YMD) {\n if (disabled) return;\n onChange(toKey(day));\n setOpen(false);\n }\n\n function onGridKeyDown(e: React.KeyboardEvent) {\n const cur = parseKey(focusKey);\n if (!cur) return;\n switch (e.key) {\n case 'ArrowLeft':\n e.preventDefault();\n moveFocus(addDays(cur, -1));\n break;\n case 'ArrowRight':\n e.preventDefault();\n moveFocus(addDays(cur, 1));\n break;\n case 'ArrowUp':\n e.preventDefault();\n moveFocus(addDays(cur, -7));\n break;\n case 'ArrowDown':\n e.preventDefault();\n moveFocus(addDays(cur, 7));\n break;\n case 'PageUp':\n e.preventDefault();\n moveFocus(addMonths(cur, -1));\n break;\n case 'PageDown':\n e.preventDefault();\n moveFocus(addMonths(cur, 1));\n break;\n case 'Home': {\n e.preventDefault();\n const dow = new Date(Date.UTC(cur.y, cur.m, cur.d)).getUTCDay();\n moveFocus(addDays(cur, -dow));\n break;\n }\n case 'End': {\n e.preventDefault();\n const dow = new Date(Date.UTC(cur.y, cur.m, cur.d)).getUTCDay();\n moveFocus(addDays(cur, 6 - dow));\n break;\n }\n case 'Enter':\n case ' ':\n e.preventDefault();\n select(cur);\n break;\n // Escape is handled by Radix Popover (closes + returns focus to the trigger).\n }\n }\n\n const cells = monthGrid(view.y, view.m);\n const triggerLabel = selected && value ? format.formatDate(value) : placeholder;\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <Popover.Anchor asChild>\n <div\n className={cn(\n 'flex h-(--height-input) w-full items-center gap-2 rounded-(--radius-input) border bg-(--el-page-bg)',\n 'border-(--el-border-strong) px-(--spacing-input-x)',\n 'focus-within:ring-2 focus-within:ring-(--focus-ring-color) focus-within:ring-offset-2 focus-within:ring-offset-background',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n >\n <Popover.Trigger asChild>\n <button\n type=\"button\"\n id={id}\n disabled={disabled}\n aria-label={ariaLabel}\n className=\"flex flex-1 items-center gap-2 truncate bg-transparent text-left text-sm outline-none disabled:cursor-not-allowed\"\n >\n <Calendar className=\"h-4 w-4 shrink-0 text-(--el-icon-field)\" aria-hidden />\n <span\n className={cn(\n 'flex-1 truncate',\n selected ? 'text-(--el-text)' : 'text-(--el-text-muted)',\n )}\n >\n {triggerLabel}\n </span>\n </button>\n </Popover.Trigger>\n {selected && !disabled ? (\n <button\n type=\"button\"\n aria-label=\"Clear date\"\n onClick={() => onChange(null)}\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-(--radius-control) text-(--el-text-muted) hover:bg-(--el-tint-rose) hover:text-(--el-danger)\"\n >\n <X className=\"h-3.5 w-3.5\" aria-hidden />\n </button>\n ) : null}\n </div>\n </Popover.Anchor>\n\n <Popover.Content\n width={296}\n align=\"start\"\n role=\"dialog\"\n aria-label={ariaLabel}\n className=\"p-3\"\n onOpenAutoFocus={(e) => {\n // Focus the roving day, not Radix's default (the first tabbable node).\n e.preventDefault();\n gridRef.current\n ?.querySelector<HTMLButtonElement>(`button[data-key=\"${focusKey}\"]`)\n ?.focus();\n }}\n >\n <div className=\"mb-2.5 flex items-center justify-between px-1\">\n <span\n id={captionId}\n className=\"text-sm font-semibold text-(--el-text)\"\n aria-live=\"polite\"\n >\n {MONTHS[view.m]} {view.y}\n </span>\n <div className=\"flex gap-0.5\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n onClick={() =>\n setView((v) => (v.m === 0 ? { y: v.y - 1, m: 11 } : { y: v.y, m: v.m - 1 }))\n }\n className=\"inline-flex h-(--height-control-28) w-7 items-center justify-center rounded-(--radius-control) text-(--el-text-muted) hover:bg-(--el-surface) hover:text-(--el-text)\"\n >\n <ChevronLeft className=\"h-[18px] w-[18px]\" aria-hidden />\n </button>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n onClick={() =>\n setView((v) => (v.m === 11 ? { y: v.y + 1, m: 0 } : { y: v.y, m: v.m + 1 }))\n }\n className=\"inline-flex h-(--height-control-28) w-7 items-center justify-center rounded-(--radius-control) text-(--el-text-muted) hover:bg-(--el-surface) hover:text-(--el-text)\"\n >\n <ChevronRight className=\"h-[18px] w-[18px]\" aria-hidden />\n </button>\n </div>\n </div>\n\n <div ref={gridRef} role=\"grid\" aria-labelledby={captionId} onKeyDown={onGridKeyDown}>\n <div role=\"row\" className=\"grid grid-cols-7\">\n {WEEKDAYS.map((wd, i) => (\n <span\n key={wd}\n role=\"columnheader\"\n aria-label={WEEKDAY_LABELS[i]}\n className=\"flex h-7 items-center justify-center text-[11px] font-semibold uppercase text-(--el-text-secondary)\"\n >\n {wd}\n </span>\n ))}\n </div>\n {Array.from({ length: 6 }, (_, week) => (\n <div role=\"row\" key={week} className=\"grid grid-cols-7\">\n {cells.slice(week * 7, week * 7 + 7).map((day) => {\n const key = toKey(day);\n const isOutside = day.m !== view.m;\n const isSelected = selected ? sameDay(day, selected) : false;\n const isToday = sameDay(day, today);\n return (\n <div\n role=\"gridcell\"\n aria-selected={isSelected}\n key={key}\n className=\"flex justify-center\"\n >\n <button\n type=\"button\"\n data-key={key}\n tabIndex={key === focusKey ? 0 : -1}\n aria-label={`${MONTHS[day.m]} ${day.d}, ${day.y}`}\n aria-current={isToday ? 'date' : undefined}\n onClick={() => select(day)}\n className={cn(\n 'relative flex h-(--height-control) w-9 items-center justify-center rounded-(--radius-control) border border-transparent text-sm',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--focus-ring-color)',\n isOutside && 'text-(--el-text-secondary)',\n !isOutside && 'text-(--el-text)',\n !isSelected && 'hover:bg-(--el-surface)',\n isToday && !isSelected && 'border-(--el-border-strong) font-bold',\n isSelected &&\n 'border-transparent bg-(--el-accent) font-bold text-(--el-accent-text) hover:bg-(--el-accent-pressed)',\n )}\n >\n {day.d}\n {isToday && !isSelected ? (\n <span\n aria-hidden\n className=\"absolute bottom-1 left-1/2 h-1 w-1 -translate-x-1/2 rounded-full bg-(--el-accent)\"\n />\n ) : null}\n </button>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n\n <div className=\"mt-2.5 flex items-center justify-between border-t border-(--el-border-soft) pt-2.5\">\n <button\n type=\"button\"\n onClick={() => moveFocus(todayUTC())}\n className=\"rounded-(--radius-control) px-(--spacing-control-x-6) py-(--spacing-control-y-4) text-sm font-medium text-(--el-link) hover:bg-(--el-surface)\"\n >\n Today\n </button>\n <button\n type=\"button\"\n onClick={() => {\n onChange(null);\n setOpen(false);\n }}\n className=\"rounded-(--radius-control) px-(--spacing-control-x-6) py-(--spacing-control-y-4) text-sm font-medium text-(--el-text-secondary) hover:bg-(--el-surface)\"\n >\n Clear\n </button>\n </div>\n </Popover.Content>\n </Popover>\n );\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { DatePickerFormatInputs, ResolvedDatePickerFormat } from './datePickerFormat.js';
4
+
5
+ interface DatePickerFormatProviderProps extends DatePickerFormatInputs {
6
+ children: ReactNode;
7
+ }
8
+ /**
9
+ * Sets the `DatePicker`'s locale and/or formatter for everything below it.
10
+ * Each input is optional and merges over an enclosing provider PER FIELD: an
11
+ * inner provider that sets only `locale` keeps the outer `formatDate`.
12
+ *
13
+ * @example
14
+ * <DatePickerFormatProvider locale={appLocale} formatDate={appFormatDate}>
15
+ * <App />
16
+ * </DatePickerFormatProvider>
17
+ */
18
+ declare function DatePickerFormatProvider({ locale, formatDate, children, }: DatePickerFormatProviderProps): react_jsx_runtime.JSX.Element;
19
+ /**
20
+ * The resolved format for a picker: `props` (a component's own `locale` /
21
+ * `formatDate`) beat the nearest provider, which beats the default — per field.
22
+ * Called with no argument it resolves the provider over the default.
23
+ */
24
+ declare function useDatePickerFormat(props?: DatePickerFormatInputs): ResolvedDatePickerFormat;
25
+
26
+ export { DatePickerFormatProvider, type DatePickerFormatProviderProps, useDatePickerFormat };
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+ import { createContext, useContext, useMemo } from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/components/ui/datePickerFormat.ts
6
+ var DEFAULT_DATE_PICKER_LOCALE = "en";
7
+ var DATE_ONLY_UTC = {
8
+ timeZone: "UTC",
9
+ year: "numeric",
10
+ month: "short",
11
+ day: "numeric"
12
+ };
13
+ var FALLBACK_INTL_TAG = "en-US";
14
+ function toIntlTag(locale) {
15
+ return locale === DEFAULT_DATE_PICKER_LOCALE ? FALLBACK_INTL_TAG : locale;
16
+ }
17
+ var defaultDatePickerFormatter = (isoDate, locale) => {
18
+ const date = new Date(isoDate);
19
+ try {
20
+ return date.toLocaleString(toIntlTag(locale), DATE_ONLY_UTC);
21
+ } catch (error) {
22
+ if (error instanceof RangeError) return date.toLocaleString(FALLBACK_INTL_TAG, DATE_ONLY_UTC);
23
+ throw error;
24
+ }
25
+ };
26
+ function resolveDatePickerFormat(props = {}, provider = {}) {
27
+ const locale = props.locale ?? provider.locale ?? DEFAULT_DATE_PICKER_LOCALE;
28
+ const formatter = props.formatDate ?? provider.formatDate ?? defaultDatePickerFormatter;
29
+ return { locale, formatDate: (isoDate) => formatter(isoDate, locale) };
30
+ }
31
+ var DatePickerFormatContext = createContext({});
32
+ function DatePickerFormatProvider({
33
+ locale,
34
+ formatDate,
35
+ children
36
+ }) {
37
+ const parent = useContext(DatePickerFormatContext);
38
+ const value = useMemo(
39
+ () => ({
40
+ locale: locale ?? parent.locale,
41
+ formatDate: formatDate ?? parent.formatDate
42
+ }),
43
+ [locale, formatDate, parent.locale, parent.formatDate]
44
+ );
45
+ return /* @__PURE__ */ jsx(DatePickerFormatContext.Provider, { value, children });
46
+ }
47
+ function useDatePickerFormat(props = {}) {
48
+ const provider = useContext(DatePickerFormatContext);
49
+ const { locale, formatDate } = props;
50
+ return useMemo(
51
+ () => resolveDatePickerFormat({ locale, formatDate }, provider),
52
+ [locale, formatDate, provider]
53
+ );
54
+ }
55
+
56
+ export { DatePickerFormatProvider, useDatePickerFormat };
57
+ //# sourceMappingURL=DatePickerFormatContext.js.map
58
+ //# sourceMappingURL=DatePickerFormatContext.js.map