gridsmith-ui 0.24.0 → 0.26.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 (87) hide show
  1. package/README.md +8 -6
  2. package/dist/MentionList-CoNBRFGR.d.ts +8 -0
  3. package/dist/charts.d.ts +42 -1
  4. package/dist/charts.js +320 -89
  5. package/dist/charts.js.map +1 -1
  6. package/dist/chat.js +5 -4
  7. package/dist/chat.js.map +1 -1
  8. package/dist/{chunk-6XAU44U4.js → chunk-CYN5O567.js} +10 -23
  9. package/dist/chunk-CYN5O567.js.map +1 -0
  10. package/dist/{chunk-SBTBMAIU.js → chunk-EX64MN2U.js} +6 -6
  11. package/dist/{chunk-SBTBMAIU.js.map → chunk-EX64MN2U.js.map} +1 -1
  12. package/dist/chunk-HP7WUZPK.js +80 -0
  13. package/dist/chunk-HP7WUZPK.js.map +1 -0
  14. package/dist/{chunk-4LDYR7QP.js → chunk-HXVXJUGV.js} +53 -13
  15. package/dist/chunk-HXVXJUGV.js.map +1 -0
  16. package/dist/{chunk-MV7JXWXK.js → chunk-KWLNEH53.js} +8 -7
  17. package/dist/chunk-KWLNEH53.js.map +1 -0
  18. package/dist/{chunk-CXMV7SXJ.js → chunk-MD2EFMES.js} +5 -77
  19. package/dist/chunk-MD2EFMES.js.map +1 -0
  20. package/dist/{chunk-SVP2IG4S.js → chunk-MYIJNVTK.js} +7 -7
  21. package/dist/chunk-MYIJNVTK.js.map +1 -0
  22. package/dist/{chunk-IVCVNAXG.js → chunk-OTCEJN64.js} +3 -3
  23. package/dist/{chunk-IVCVNAXG.js.map → chunk-OTCEJN64.js.map} +1 -1
  24. package/dist/{chunk-2PWGJ4PK.js → chunk-QM4SJKWV.js} +11 -6
  25. package/dist/chunk-QM4SJKWV.js.map +1 -0
  26. package/dist/chunk-RWKCAKN3.js +209 -0
  27. package/dist/chunk-RWKCAKN3.js.map +1 -0
  28. package/dist/{chunk-2YSEME33.js → chunk-SFY2KMHG.js} +63 -6
  29. package/dist/chunk-SFY2KMHG.js.map +1 -0
  30. package/dist/{chunk-NCIZQYXQ.js → chunk-X2HEV7FB.js} +33 -3
  31. package/dist/chunk-X2HEV7FB.js.map +1 -0
  32. package/dist/{chunk-JXANCXK6.js → chunk-ZI3OQDET.js} +18 -4
  33. package/dist/chunk-ZI3OQDET.js.map +1 -0
  34. package/dist/{chunk-7TOJ4G7S.js → chunk-ZYVXV4WC.js} +14 -9
  35. package/dist/chunk-ZYVXV4WC.js.map +1 -0
  36. package/dist/data-grid.d.ts +1 -1
  37. package/dist/data-grid.js +13 -12
  38. package/dist/data-grid.js.map +1 -1
  39. package/dist/editor-mentions.d.ts +30 -0
  40. package/dist/editor-mentions.js +160 -0
  41. package/dist/editor-mentions.js.map +1 -0
  42. package/dist/editor.d.ts +23 -3
  43. package/dist/editor.js +58 -9
  44. package/dist/editor.js.map +1 -1
  45. package/dist/{feather-2JFSFLXN.js → feather-VFWLAILO.js} +12 -3
  46. package/dist/feather-VFWLAILO.js.map +1 -0
  47. package/dist/{heroicons-4AQ4YBVG.js → heroicons-H3Z7DFCF.js} +22 -7
  48. package/dist/heroicons-H3Z7DFCF.js.map +1 -0
  49. package/dist/icons.d.ts +11 -4
  50. package/dist/icons.js +1 -1
  51. package/dist/index.d.ts +202 -31
  52. package/dist/index.js +1473 -1181
  53. package/dist/index.js.map +1 -1
  54. package/dist/kanban.js +8 -8
  55. package/dist/kanban.js.map +1 -1
  56. package/dist/{lucide-RZC2FEMS.js → lucide-MR32KM4G.js} +12 -3
  57. package/dist/lucide-MR32KM4G.js.map +1 -0
  58. package/dist/{phosphor-CEN25FLM.js → phosphor-ABQQL5N5.js} +12 -3
  59. package/dist/phosphor-ABQQL5N5.js.map +1 -0
  60. package/dist/resizable.js +8 -8
  61. package/dist/roots.css +28 -0
  62. package/dist/{tabler-YXXC7Y6B.js → tabler-ANUSY4D2.js} +12 -3
  63. package/dist/tabler-ANUSY4D2.js.map +1 -0
  64. package/dist/tokens.css +6 -0
  65. package/dist/{use-pagination-DiJo0aW5.d.ts → use-pagination-BnKOnBdz.d.ts} +3 -0
  66. package/dist/virtualized.d.ts +1 -1
  67. package/dist/virtualized.js +7 -6
  68. package/dist/virtualized.js.map +1 -1
  69. package/dist-static/tokens.css +6 -0
  70. package/package.json +29 -21
  71. package/dist/chunk-2PWGJ4PK.js.map +0 -1
  72. package/dist/chunk-2YSEME33.js.map +0 -1
  73. package/dist/chunk-4LDYR7QP.js.map +0 -1
  74. package/dist/chunk-6XAU44U4.js.map +0 -1
  75. package/dist/chunk-7TOJ4G7S.js.map +0 -1
  76. package/dist/chunk-CXMV7SXJ.js.map +0 -1
  77. package/dist/chunk-JXANCXK6.js.map +0 -1
  78. package/dist/chunk-MV7JXWXK.js.map +0 -1
  79. package/dist/chunk-NCIZQYXQ.js.map +0 -1
  80. package/dist/chunk-SVP2IG4S.js.map +0 -1
  81. package/dist/chunk-WOVYHFUD.js +0 -50
  82. package/dist/chunk-WOVYHFUD.js.map +0 -1
  83. package/dist/feather-2JFSFLXN.js.map +0 -1
  84. package/dist/heroicons-4AQ4YBVG.js.map +0 -1
  85. package/dist/lucide-RZC2FEMS.js.map +0 -1
  86. package/dist/phosphor-CEN25FLM.js.map +0 -1
  87. package/dist/tabler-YXXC7Y6B.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,30 +1,33 @@
1
- import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-MV7JXWXK.js';
2
- export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-MV7JXWXK.js';
3
- import { Skeleton, TITLE_TEXT } from './chunk-NCIZQYXQ.js';
4
- export { Skeleton } from './chunk-NCIZQYXQ.js';
1
+ import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-OTCEJN64.js';
2
+ import { useWholeListCheck, pagerPart, Pagination, Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, Label, InlineFieldError, AddAnotherRowCtx, Field } from './chunk-CYN5O567.js';
3
+ export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-CYN5O567.js';
4
+ import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-KWLNEH53.js';
5
+ export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-KWLNEH53.js';
6
+ import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, preferenceActionKey } from './chunk-ZYVXV4WC.js';
7
+ export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, preferenceActionKey, usePreferences } from './chunk-ZYVXV4WC.js';
8
+ import { Skeleton, TITLE_TEXT, formatLocale } from './chunk-X2HEV7FB.js';
9
+ export { Skeleton } from './chunk-X2HEV7FB.js';
5
10
  import { useScrollEdges, EDGE_FADE } from './chunk-3BRQRKDO.js';
6
- import { Link } from './chunk-SVP2IG4S.js';
7
- export { CodeBlock, Divider, Link } from './chunk-SVP2IG4S.js';
8
- import { useFillHeight, FillContext } from './chunk-2YSEME33.js';
9
- import { Badge } from './chunk-SBTBMAIU.js';
10
- export { Badge } from './chunk-SBTBMAIU.js';
11
- import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-IVCVNAXG.js';
12
- import { useWholeListCheck, pagerPart, Pagination, Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, warnOnce, Label, InlineFieldError, AddAnotherRowCtx, Field } from './chunk-6XAU44U4.js';
13
- export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-6XAU44U4.js';
14
- import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, preferenceActionKey } from './chunk-7TOJ4G7S.js';
15
- export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, preferenceActionKey, usePreferences } from './chunk-7TOJ4G7S.js';
16
11
  import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
17
12
  export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
18
13
  import { FormChangeCtx, useReportedChange, useOptionalFormContext, FormCtx } from './chunk-XVB55M3N.js';
19
14
  export { useFormContext } from './chunk-XVB55M3N.js';
20
- import { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, PageActionsCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-2PWGJ4PK.js';
21
- import { FOCUSABLE, usePopupFocus, FIELD, ZOOM_KEYS, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, rovingTabStop, useGridKeyboard, focusAfterRemoval, useNonModalDialog, useReturnFocus, useCloseOnFocusOut } from './chunk-JXANCXK6.js';
22
- export { useGridKeyboard } from './chunk-JXANCXK6.js';
23
- import { useTextOverflow, Tooltip, usePosition } from './chunk-CXMV7SXJ.js';
24
- export { Tooltip, useTextOverflow } from './chunk-CXMV7SXJ.js';
15
+ import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-RWKCAKN3.js';
16
+ export { Avatar } from './chunk-RWKCAKN3.js';
17
+ import { Link } from './chunk-MYIJNVTK.js';
18
+ export { CodeBlock, Divider, Link } from './chunk-MYIJNVTK.js';
19
+ import { useFillHeight, FillContext, useKeyboardScroll, FOCUS_INSET } from './chunk-SFY2KMHG.js';
20
+ import { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, RowsCtx, PageActionsCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-QM4SJKWV.js';
21
+ import { FOCUSABLE, usePopupFocus, FIELD, ZOOM_KEYS, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, rovingTabStop, useGridKeyboard, focusAfterRemoval, useNonModalDialog, useReturnFocus } from './chunk-ZI3OQDET.js';
22
+ export { useGridKeyboard } from './chunk-ZI3OQDET.js';
23
+ import { Badge } from './chunk-EX64MN2U.js';
24
+ export { Badge } from './chunk-EX64MN2U.js';
25
+ import { useTextOverflow, Tooltip } from './chunk-MD2EFMES.js';
26
+ export { Tooltip, useTextOverflow } from './chunk-MD2EFMES.js';
25
27
  import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
28
+ import { Icon, slotIcon, warnOnce } from './chunk-HXVXJUGV.js';
29
+ import { usePosition } from './chunk-HP7WUZPK.js';
26
30
  import { useLatest } from './chunk-WH2FUFAC.js';
27
- import { Icon } from './chunk-4LDYR7QP.js';
28
31
  import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ACTIVE_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, FOCUS_WITHIN_RING } from './chunk-M2QRNBDQ.js';
29
32
  import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useEffect, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
30
33
  import { createPortal, flushSync } from 'react-dom';
@@ -227,7 +230,7 @@ var TEXT_SIZE = {
227
230
  md: "text-sm",
228
231
  lg: "text-base"
229
232
  };
230
- function Combobox({ value, onChange: onChangeProp, options, placeholder = "Search\u2026", disabled, loading = false, className, ref, container, error = false, size: sizeProp, ...wiring }) {
233
+ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Search\u2026", disabled, loading = false, className, ref, container, error = false, size: sizeProp, "aria-label": ariaLabel, ...wiring }) {
231
234
  const onChange = useReportedChange(onChangeProp, value);
232
235
  const contextSize = useContext(ControlSizeContext);
233
236
  const control = useFieldControl({ ...wiring, error: error || void 0 });
@@ -244,8 +247,9 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
244
247
  const listboxId = useId();
245
248
  const pos = usePosition(triggerRef, listRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
246
249
  const filtered = options.filter(
247
- (o) => !o.disabled && o.label.toLowerCase().includes(query.toLowerCase())
250
+ (o) => !o.disabled && foldForSearch(o.keywords ? `${o.label} ${o.keywords}` : o.label).includes(foldForSearch(query))
248
251
  );
252
+ useActiveOptionInView(listRef, open && filtered[highlightIdx] ? `${listboxId}-opt-${highlightIdx}` : void 0);
249
253
  const selectedLabel = options.find((o) => o.value === value)?.label ?? "";
250
254
  const { ref: overflowRef, isTruncated: labelTruncated } = useTextOverflow({ lines: 1, content: selectedLabel, disabled: open });
251
255
  const [prevQuery, setPrevQuery] = useState(query);
@@ -359,6 +363,7 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
359
363
  id: control.id,
360
364
  role: "combobox",
361
365
  "aria-labelledby": wiring["aria-labelledby"],
366
+ "aria-label": control.labelId ? void 0 : ariaLabel,
362
367
  "aria-describedby": control.describedBy,
363
368
  "aria-invalid": control.invalid || void 0,
364
369
  "aria-required": control.required || void 0,
@@ -454,6 +459,183 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
454
459
  ] });
455
460
  return /* @__PURE__ */ jsx(Tooltip, { content: selectedLabel, disabled: !labelTruncated || open, children: triggerContent });
456
461
  }
462
+ function canonicalTimeZone(zone) {
463
+ try {
464
+ return new Intl.DateTimeFormat("en-US", { timeZone: zone }).resolvedOptions().timeZone;
465
+ } catch {
466
+ return zone;
467
+ }
468
+ }
469
+ function browserTimeZone() {
470
+ try {
471
+ return canonicalTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC");
472
+ } catch {
473
+ return "UTC";
474
+ }
475
+ }
476
+ function timeZoneOffset(zone, at = /* @__PURE__ */ new Date()) {
477
+ try {
478
+ return new Intl.DateTimeFormat(formatLocale(), { timeZone: zone, timeZoneName: "shortOffset" }).formatToParts(at).find((p) => p.type === "timeZoneName")?.value ?? "";
479
+ } catch {
480
+ return "";
481
+ }
482
+ }
483
+ function timeZones() {
484
+ const listed = typeof Intl.supportedValuesOf === "function" ? Intl.supportedValuesOf("timeZone") : [];
485
+ const zones = [...new Set(listed.map(canonicalTimeZone))].filter((z) => z !== "UTC").sort((a, b) => a.localeCompare(b));
486
+ return ["UTC", ...zones];
487
+ }
488
+ var RENAMED_CITIES = [
489
+ ["Kolkata", ["Asia/Calcutta", "Asia/Kolkata"]],
490
+ ["Kyiv", ["Europe/Kiev", "Europe/Kyiv"]],
491
+ ["Ho Chi Minh City", ["Asia/Saigon", "Asia/Ho_Chi_Minh"]],
492
+ ["Yangon", ["Asia/Rangoon", "Asia/Yangon"]],
493
+ ["Kathmandu", ["Asia/Katmandu", "Asia/Kathmandu"]],
494
+ ["Nuuk", ["America/Godthab", "America/Nuuk"]],
495
+ ["Faroe", ["Atlantic/Faeroe", "Atlantic/Faroe"]],
496
+ ["Chuuk", ["Pacific/Truk", "Pacific/Chuuk"]],
497
+ ["Pohnpei", ["Pacific/Ponape", "Pacific/Pohnpei"]],
498
+ ["Kanton", ["Pacific/Enderbury", "Pacific/Kanton"]],
499
+ ["Asmara", ["Africa/Asmera", "Africa/Asmara"]],
500
+ ["Atikokan", ["America/Coral_Harbour", "America/Atikokan"]],
501
+ ["Thimphu", ["Asia/Thimbu", "Asia/Thimphu"]],
502
+ ["Dhaka", ["Asia/Dacca", "Asia/Dhaka"]],
503
+ ["Ulaanbaatar", ["Asia/Ulan_Bator", "Asia/Ulaanbaatar"]]
504
+ ];
505
+ var CITY_OF = new Map(RENAMED_CITIES.flatMap(([city, zones]) => zones.map((zone) => [zone, city])));
506
+ var labelOf = (zone, at) => {
507
+ const offset = timeZoneOffset(zone, at);
508
+ return offset ? `${zone.replace(/_/g, " ")} (${offset})` : zone.replace(/_/g, " ");
509
+ };
510
+ var HOUR = 36e5;
511
+ var zoneList = null;
512
+ function zoneOptions() {
513
+ const now = Date.now();
514
+ if (!zoneList || now - zoneList.at > HOUR) {
515
+ const at = new Date(now);
516
+ zoneList = { at: now, options: timeZones().map((zone) => ({ value: zone, label: labelOf(zone, at), keywords: CITY_OF.get(zone) })) };
517
+ }
518
+ return zoneList.options;
519
+ }
520
+ function TimezoneSelect({ value, onChange, placeholder = "Search time zones\u2026", ...rest }) {
521
+ const zones = zoneOptions();
522
+ const stored = value ? canonicalTimeZone(value) : "";
523
+ const options = useMemo(() => {
524
+ if (!stored) {
525
+ const mine = browserTimeZone();
526
+ const label = zones.find((o) => o.value === mine)?.label ?? labelOf(mine, /* @__PURE__ */ new Date());
527
+ return [{ value: mine, label: `${label} \xB7 your time zone`, keywords: CITY_OF.get(mine) }, ...zones.filter((o) => o.value !== mine)];
528
+ }
529
+ return zones.some((o) => o.value === stored) ? zones : [{ value: stored, label: labelOf(stored, /* @__PURE__ */ new Date()), keywords: CITY_OF.get(stored) }, ...zones];
530
+ }, [zones, stored]);
531
+ return /* @__PURE__ */ jsx(Combobox, { value: stored, onChange, options, placeholder, ...rest });
532
+ }
533
+ var MINUTE = 6e4;
534
+ var HOUR2 = 60 * MINUTE;
535
+ var DAY = 24 * HOUR2;
536
+ var LONGEST_WAIT = DAY;
537
+ var CONTROL_ANCESTOR = 'a[href], button, summary, label, [role="button"], [role="link"], [role="option"], [role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"], [role="tab"], [role="treeitem"], [role="row"], [role="gridcell"], [role="checkbox"], [role="radio"], [role="switch"]';
538
+ var noChange = () => () => {
539
+ };
540
+ var inBrowser = () => true;
541
+ var onServer = () => false;
542
+ function toMillis(time) {
543
+ if (time instanceof Date) return time.getTime();
544
+ if (typeof time === "number") return time;
545
+ if (typeof time !== "string") return NaN;
546
+ const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(time.trim());
547
+ if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3])).getTime();
548
+ return Date.parse(time);
549
+ }
550
+ function thresholdOf(hours, from) {
551
+ if (typeof hours === "number" && Number.isFinite(hours) && hours >= 0) return hours;
552
+ const house = PREFERENCE_HOUSE_DEFAULTS.relativeThresholdHours;
553
+ warnOnce(from, `a threshold of ${String(hours)} isn't a number of hours, so the house's ${house} is used.`);
554
+ return house;
555
+ }
556
+ function midnight(t) {
557
+ const d = new Date(t);
558
+ d.setHours(0, 0, 0, 0);
559
+ return d.getTime();
560
+ }
561
+ function formatRelativeTime(time, options) {
562
+ const at = toMillis(time);
563
+ if (!Number.isFinite(at)) return "";
564
+ const now = options.now ?? Date.now();
565
+ const diff = at - now;
566
+ const age = Math.abs(diff);
567
+ if (age > thresholdOf(options.thresholdHours, "formatRelativeTime") * HOUR2) return new Intl.DateTimeFormat(formatLocale(), { dateStyle: "medium", timeStyle: "short" }).format(at);
568
+ const rtf = new Intl.RelativeTimeFormat(formatLocale(), { numeric: "auto" });
569
+ if (age < MINUTE) return rtf.format(0, "second");
570
+ if (age < HOUR2) return rtf.format(Math.trunc(diff / MINUTE), "minute");
571
+ if (age < DAY) return rtf.format(Math.trunc(diff / HOUR2), "hour");
572
+ return rtf.format(Math.round((midnight(at) - midnight(now)) / DAY), "day");
573
+ }
574
+ function useRelativeTimeFormat() {
575
+ const thresholdHours = useShellPreferences().relativeThresholdHours ?? PREFERENCE_HOUSE_DEFAULTS.relativeThresholdHours;
576
+ return (time) => formatRelativeTime(time, { thresholdHours });
577
+ }
578
+ function formatFullTime(time) {
579
+ const at = toMillis(time);
580
+ return Number.isFinite(at) ? new Intl.DateTimeFormat(formatLocale(), { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", timeZoneName: "short" }).format(at) : "";
581
+ }
582
+ function nextChange(at, now, threshold) {
583
+ const diff = at - now;
584
+ const age = Math.abs(diff);
585
+ let wait;
586
+ if (age > threshold) {
587
+ if (diff <= 0) return null;
588
+ wait = age - threshold + 1;
589
+ } else {
590
+ const step = age < HOUR2 ? MINUTE : HOUR2;
591
+ const untilStep = diff > 0 ? age % step + 1 : step - age % step;
592
+ wait = diff > 0 ? untilStep : Math.min(untilStep, threshold - age + 1);
593
+ }
594
+ return Number.isFinite(wait) ? Math.min(Math.max(1e3, wait), LONGEST_WAIT) : null;
595
+ }
596
+ function RelativeTime({ time, thresholdHours, className }) {
597
+ const shellThreshold = useShellPreferences().relativeThresholdHours;
598
+ const hours = thresholdOf(thresholdHours ?? shellThreshold ?? PREFERENCE_HOUSE_DEFAULTS.relativeThresholdHours, "RelativeTime");
599
+ const at = toMillis(time);
600
+ if (!Number.isFinite(at)) {
601
+ warnOnce("RelativeTime", `${JSON.stringify(time) ?? String(time)} isn't a time (an ISO string, a Date or milliseconds), so nothing is drawn.`);
602
+ return null;
603
+ }
604
+ return /* @__PURE__ */ jsx(RelativeTimeAt, { at, hours, className }, `${at}:${hours}`);
605
+ }
606
+ function RelativeTimeAt({ at, hours, className }) {
607
+ const inRows = useContext(RowsCtx);
608
+ const [now, setNow] = useState(() => Date.now());
609
+ const [inControl, setInControl] = useState(false);
610
+ const placed = useCallback((el) => {
611
+ const inside = !!el?.parentElement?.closest(CONTROL_ANCESTOR);
612
+ if (inside) el.removeAttribute("tabindex");
613
+ if (el) setInControl(inside);
614
+ }, []);
615
+ const mounted = useSyncExternalStore(noChange, inBrowser, onServer);
616
+ useEffect(() => {
617
+ const wait = nextChange(at, now, hours * HOUR2);
618
+ if (wait === null) return;
619
+ const timer = setTimeout(() => setNow(Date.now()), wait);
620
+ return () => clearTimeout(timer);
621
+ }, [at, now, hours]);
622
+ const full = formatFullTime(at);
623
+ return /* @__PURE__ */ jsx(Tooltip, { content: full, ref: placed, children: /* @__PURE__ */ jsxs(
624
+ "time",
625
+ {
626
+ tabIndex: inRows || inControl ? void 0 : 0,
627
+ dateTime: new Date(at).toISOString(),
628
+ "data-relative-time": "",
629
+ suppressHydrationWarning: true,
630
+ className: cn("rounded-[var(--ds-radius-sm)] focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2", className),
631
+ children: [
632
+ formatRelativeTime(at, { thresholdHours: hours, now }),
633
+ /* @__PURE__ */ jsx("span", { className: "sr-only", suppressHydrationWarning: true, children: `, ${full}` })
634
+ ]
635
+ },
636
+ mounted ? "browser" : "first"
637
+ ) });
638
+ }
457
639
  var CHECKBOX_SIZES = {
458
640
  sm: { box: "h-[16px] w-[16px]", glyph: 10, label: "text-xs" },
459
641
  md: { box: "h-[18px] w-[18px]", glyph: 12, label: "text-sm" }
@@ -713,6 +895,279 @@ function dateSegments(dayFirst, daysInMonth = 31) {
713
895
  const year = { key: "year", label: "Year", min: 1, max: 9999, maxDigits: 4, placeholder: "yyyy" };
714
896
  return dayFirst ? [day, month, year] : [month, day, year];
715
897
  }
898
+
899
+ // ../../showcase/src/components/Calendar/calendar-utils.ts
900
+ var formatters = /* @__PURE__ */ new Map();
901
+ function dtf(options) {
902
+ const locale = formatLocale();
903
+ const key = `${locale ?? ""}|${JSON.stringify(options)}`;
904
+ let f = formatters.get(key);
905
+ if (!f) {
906
+ f = new Intl.DateTimeFormat(locale, options);
907
+ formatters.set(key, f);
908
+ }
909
+ return f;
910
+ }
911
+ function monthName(month, width = "long") {
912
+ return dtf({ month: width }).format(new Date(2026, month, 1));
913
+ }
914
+ function weekdayNames(weekStartsOn, width = "short") {
915
+ const f = dtf({ weekday: width });
916
+ return Array.from({ length: 7 }, (_, i) => f.format(new Date(2026, 0, 4 + weekStartsOn + i)));
917
+ }
918
+ function isSameDay(a, b) {
919
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
920
+ }
921
+ function isSameMonth(a, b) {
922
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
923
+ }
924
+ function isToday(d) {
925
+ return isSameDay(d, /* @__PURE__ */ new Date());
926
+ }
927
+ function isWeekend(d) {
928
+ const day = d.getDay();
929
+ return day === 0 || day === 6;
930
+ }
931
+ function startOfDay(d) {
932
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
933
+ }
934
+ function startOfWeek(d, weekStartsOn = 0) {
935
+ const date = new Date(d);
936
+ const day = date.getDay();
937
+ const diff = (day - weekStartsOn + 7) % 7;
938
+ date.setDate(date.getDate() - diff);
939
+ return startOfDay(date);
940
+ }
941
+ function endOfWeek(d, weekStartsOn = 0) {
942
+ const start = startOfWeek(d, weekStartsOn);
943
+ const end = new Date(start);
944
+ end.setDate(end.getDate() + 6);
945
+ end.setHours(23, 59, 59, 999);
946
+ return end;
947
+ }
948
+ function addDays2(d, n) {
949
+ const result = new Date(d);
950
+ result.setDate(result.getDate() + n);
951
+ return result;
952
+ }
953
+ function addMonths(d, n) {
954
+ const result = new Date(d);
955
+ const day = result.getDate();
956
+ result.setDate(1);
957
+ result.setMonth(result.getMonth() + n);
958
+ result.setDate(Math.min(day, new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate()));
959
+ return result;
960
+ }
961
+ function getMonthGrid(year, month, weekStartsOn = 0) {
962
+ const firstOfMonth = new Date(year, month, 1);
963
+ const gridStart = startOfWeek(firstOfMonth, weekStartsOn);
964
+ const weeks = [];
965
+ const current = new Date(gridStart);
966
+ for (let w = 0; w < 6; w++) {
967
+ const week = [];
968
+ for (let d = 0; d < 7; d++) {
969
+ week.push(new Date(current));
970
+ current.setDate(current.getDate() + 1);
971
+ }
972
+ weeks.push(week);
973
+ }
974
+ return weeks;
975
+ }
976
+ function getWeekDays(date, weekStartsOn = 0) {
977
+ const start = startOfWeek(date, weekStartsOn);
978
+ const days = [];
979
+ for (let i = 0; i < 7; i++) {
980
+ days.push(addDays2(start, i));
981
+ }
982
+ return days;
983
+ }
984
+ var DAY_MS = 864e5;
985
+ function daysBetween(a, b) {
986
+ return Math.round((startOfDay(b).getTime() - startOfDay(a).getTime()) / DAY_MS);
987
+ }
988
+ function eventSpan(e) {
989
+ const first = startOfDay(e.start);
990
+ if (!e.end) return { first, last: first };
991
+ const lastInstant = e.allDay ? e.end : new Date(e.end.getTime() - 1);
992
+ const last = startOfDay(lastInstant);
993
+ return { first, last: last < first ? first : last };
994
+ }
995
+ function isBarEvent(e) {
996
+ if (e.allDay) return true;
997
+ if (!e.end) return false;
998
+ const dayLater = new Date(e.start);
999
+ dayLater.setDate(dayLater.getDate() + 1);
1000
+ return e.end.getTime() >= dayLater.getTime();
1001
+ }
1002
+ function getEventsForDay(events, date) {
1003
+ const day = startOfDay(date).getTime();
1004
+ return events.filter((e) => {
1005
+ const { first, last } = eventSpan(e);
1006
+ return first.getTime() <= day && day <= last.getTime();
1007
+ });
1008
+ }
1009
+ function dayPieces(events, date) {
1010
+ const dayStart = startOfDay(date);
1011
+ const next = new Date(dayStart.getFullYear(), dayStart.getMonth(), dayStart.getDate() + 1);
1012
+ const pieces = [];
1013
+ for (const event of events) {
1014
+ if (isBarEvent(event)) continue;
1015
+ const ownDayEnd = new Date(event.start.getFullYear(), event.start.getMonth(), event.start.getDate() + 1);
1016
+ const end = event.end && event.end > event.start ? event.end : new Date(Math.min(event.start.getTime() + 36e5, ownDayEnd.getTime()));
1017
+ const start = event.start < dayStart ? dayStart : event.start;
1018
+ const stop = end > next ? next : end;
1019
+ if (stop > start) pieces.push({ event, start, end: stop });
1020
+ }
1021
+ return pieces.sort((a, b) => a.start.getTime() - b.start.getTime() || b.end.getTime() - a.end.getTime());
1022
+ }
1023
+ function twelveHour() {
1024
+ return /^h1[12]$/.test(dtf({ hour: "numeric" }).resolvedOptions().hourCycle ?? "");
1025
+ }
1026
+ var timeOptions = () => ({ hour: twelveHour() ? "numeric" : "2-digit", minute: "2-digit" });
1027
+ function formatTime(d) {
1028
+ return dtf(timeOptions()).format(d);
1029
+ }
1030
+ function formatHourLabel(hour) {
1031
+ const at = new Date(2026, 0, 5, hour);
1032
+ return twelveHour() ? dtf({ hour: "numeric" }).format(at) : dtf({ hour: "2-digit", minute: "2-digit" }).format(at);
1033
+ }
1034
+ function dayOffset(days) {
1035
+ return new Intl.NumberFormat(formatLocale(), { signDisplay: "always" }).format(days);
1036
+ }
1037
+ function formatTimeRange(start, end) {
1038
+ if (!end) return formatTime(start);
1039
+ const f = dtf(timeOptions());
1040
+ if (daysBetween(start, end) === 0) return f.formatRange(start, end);
1041
+ const sep = f.formatRangeToParts(start, end).find((p) => p.source === "shared" && p.type === "literal")?.value ?? " \u2013 ";
1042
+ const days = endDays(start, end);
1043
+ return days === 0 ? `${f.format(start)}${sep}${f.format(end)}` : `${f.format(start)}${sep}${f.format(end)} (${dayOffset(days)})`;
1044
+ }
1045
+ function endDays(start, end) {
1046
+ return end > start ? daysBetween(start, new Date(end.getTime() - 1)) : daysBetween(start, end);
1047
+ }
1048
+ function speakTimeRange(start, end) {
1049
+ if (!end) return formatTime(start);
1050
+ const days = endDays(start, end);
1051
+ const to = `${formatTime(start)} to ${formatTime(end)}`;
1052
+ return days === 0 ? to : days === 1 ? `${to} the next day` : `${to}, ${days} days later`;
1053
+ }
1054
+ function formatMonthYear(d) {
1055
+ return dtf({ month: "long", year: "numeric" }).format(d);
1056
+ }
1057
+ function formatDayLong(d) {
1058
+ return dtf({ weekday: "long", day: "numeric", month: "long", year: "numeric" }).format(d);
1059
+ }
1060
+ function formatDayShort(d) {
1061
+ return dtf({ weekday: "short", day: "numeric", month: "short" }).format(d);
1062
+ }
1063
+ function formatDayMedium(d) {
1064
+ return dtf({ day: "numeric", month: "short", year: "numeric" }).format(d);
1065
+ }
1066
+ function formatDayRange(start, end) {
1067
+ return dtf({ day: "numeric", month: "short", year: "numeric" }).formatRange(startOfDay(start), startOfDay(end));
1068
+ }
1069
+ function formatMonthRange(start, end) {
1070
+ return dtf({ month: "long", year: "numeric" }).formatRange(new Date(start.getFullYear(), start.getMonth(), 1), new Date(end.getFullYear(), end.getMonth(), 1));
1071
+ }
1072
+ function formatWeekRange(d, weekStartsOn = 0) {
1073
+ return dtf({ day: "numeric", month: "short", year: "numeric" }).formatRange(startOfWeek(d, weekStartsOn), startOfDay(endOfWeek(d, weekStartsOn)));
1074
+ }
1075
+ function formatEventWhen(e, spoken = false) {
1076
+ const { first, last } = eventSpan(e);
1077
+ const multiDay = last > first;
1078
+ if (e.allDay) {
1079
+ if (!multiDay) return spoken ? formatDayLong(first) : formatDayShort(first);
1080
+ return dtf(spoken ? { weekday: "long", day: "numeric", month: "long" } : { day: "numeric", month: "short" }).formatRange(first, last);
1081
+ }
1082
+ if (!e.end || !isBarEvent(e)) {
1083
+ const day = spoken ? formatDayLong(e.start) : formatDayShort(e.start);
1084
+ const end = e.end && e.end > e.start ? e.end : void 0;
1085
+ return `${day}, ${spoken ? speakTimeRange(e.start, end) : formatTimeRange(e.start, end)}`;
1086
+ }
1087
+ return dtf({ weekday: "short", day: "numeric", month: "short", hour: "numeric", minute: "2-digit" }).formatRange(e.start, e.end);
1088
+ }
1089
+ function layoutWeek(events, days, capacity) {
1090
+ const weekStart = startOfDay(days[0]);
1091
+ const weekEnd = startOfDay(days[days.length - 1]);
1092
+ const items = [];
1093
+ for (const event of events) {
1094
+ const { first, last } = eventSpan(event);
1095
+ if (last < weekStart || first > weekEnd) continue;
1096
+ items.push({
1097
+ event,
1098
+ startCol: Math.max(0, daysBetween(weekStart, first)),
1099
+ endCol: Math.min(days.length - 1, daysBetween(weekStart, last)),
1100
+ before: first < weekStart,
1101
+ after: last > weekEnd,
1102
+ length: daysBetween(first, last) + 1
1103
+ });
1104
+ }
1105
+ items.sort((a, b) => {
1106
+ const barA = isBarEvent(a.event) || a.length > 1, barB = isBarEvent(b.event) || b.length > 1;
1107
+ if (barA !== barB) return barA ? -1 : 1;
1108
+ if (barA && a.length !== b.length) return b.length - a.length;
1109
+ return a.event.start.getTime() - b.event.start.getTime() || a.event.title.localeCompare(b.event.title);
1110
+ });
1111
+ const taken = [];
1112
+ const laneOf = /* @__PURE__ */ new Map();
1113
+ for (const item of items) {
1114
+ let lane = 0;
1115
+ while (Array.from({ length: item.endCol - item.startCol + 1 }, (_, k) => taken[lane]?.[item.startCol + k]).some(Boolean)) lane++;
1116
+ taken[lane] ??= [];
1117
+ for (let c = item.startCol; c <= item.endCol; c++) taken[lane][c] = true;
1118
+ laneOf.set(item, lane);
1119
+ }
1120
+ const cap = Math.max(1, capacity);
1121
+ const overflow = days.map((_, c) => items.some((it) => laneOf.get(it) >= cap && it.startCol <= c && c <= it.endCol));
1122
+ const more = days.map((_, c) => overflow[c] ? items.filter((it) => laneOf.get(it) >= cap - 1 && it.startCol <= c && c <= it.endCol).map((it) => it.event) : []);
1123
+ const segments = [];
1124
+ for (const item of items) {
1125
+ const lane = laneOf.get(item);
1126
+ if (lane >= cap) continue;
1127
+ if (lane < cap - 1) {
1128
+ segments.push({ event: item.event, startCol: item.startCol, span: item.endCol - item.startCol + 1, lane, continuesBefore: item.before, continuesAfter: item.after });
1129
+ continue;
1130
+ }
1131
+ let runStart = -1;
1132
+ for (let c = item.startCol; c <= item.endCol + 1; c++) {
1133
+ const free = c <= item.endCol && !overflow[c];
1134
+ if (free && runStart < 0) runStart = c;
1135
+ if (!free && runStart >= 0) {
1136
+ segments.push({ event: item.event, startCol: runStart, span: c - runStart, lane, continuesBefore: runStart > item.startCol || item.before, continuesAfter: c - 1 < item.endCol || item.after });
1137
+ runStart = -1;
1138
+ }
1139
+ }
1140
+ }
1141
+ const lanes = Math.min(cap, taken.length);
1142
+ return { segments, more, lanes };
1143
+ }
1144
+ function layoutPieces(pieces, minMinutes = 0) {
1145
+ const out = [];
1146
+ let group = [];
1147
+ let columnEnds = [];
1148
+ let groupEnd = -Infinity;
1149
+ const close = () => {
1150
+ for (const placed of group) placed.columns = columnEnds.length;
1151
+ out.push(...group);
1152
+ group = [];
1153
+ columnEnds = [];
1154
+ };
1155
+ for (const piece of pieces) {
1156
+ const at = piece.start.getTime();
1157
+ const end = Math.max(piece.end.getTime(), at + minMinutes * 6e4);
1158
+ if (group.length && at >= groupEnd) close();
1159
+ let column = columnEnds.findIndex((e) => e <= at);
1160
+ if (column < 0) column = columnEnds.push(0) - 1;
1161
+ columnEnds[column] = end;
1162
+ groupEnd = Math.max(group.length ? groupEnd : -Infinity, end);
1163
+ group.push({ piece, column, columns: 0 });
1164
+ }
1165
+ if (group.length) close();
1166
+ return out;
1167
+ }
1168
+ function timeToFraction(d) {
1169
+ return (d.getHours() * 60 + d.getMinutes()) / (24 * 60);
1170
+ }
716
1171
  var CONTROL_HEIGHT2 = {
717
1172
  sm: "h-[var(--ds-control-height-sm)]",
718
1173
  md: "h-[var(--ds-control-height-md)]",
@@ -723,21 +1178,19 @@ var TEXT_SIZE2 = {
723
1178
  md: "text-sm",
724
1179
  lg: "text-base"
725
1180
  };
726
- var DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
727
- var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
728
- var MONTHS = [
729
- "January",
730
- "February",
731
- "March",
732
- "April",
733
- "May",
734
- "June",
735
- "July",
736
- "August",
737
- "September",
738
- "October",
739
- "November",
740
- "December"
1181
+ var ENGLISH_MONTHS = [
1182
+ "january",
1183
+ "february",
1184
+ "march",
1185
+ "april",
1186
+ "may",
1187
+ "june",
1188
+ "july",
1189
+ "august",
1190
+ "september",
1191
+ "october",
1192
+ "november",
1193
+ "december"
741
1194
  ];
742
1195
  function getDaysInMonth(year, month) {
743
1196
  return new Date(year, month + 1, 0).getDate();
@@ -745,37 +1198,43 @@ function getDaysInMonth(year, month) {
745
1198
  function getFirstDayOfWeek(year, month) {
746
1199
  return new Date(year, month, 1).getDay();
747
1200
  }
748
- function isSameDay(a, b) {
1201
+ function isSameDay2(a, b) {
749
1202
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
750
1203
  }
751
- function formatDate(d) {
752
- return `${MONTHS[d.getMonth()].slice(0, 3)} ${d.getDate()}, ${d.getFullYear()}`;
753
- }
754
1204
  function localeDayFirst() {
755
1205
  try {
756
- const parts = new Intl.DateTimeFormat(void 0).formatToParts(new Date(2e3, 11, 25));
1206
+ const parts = new Intl.DateTimeFormat(formatLocale()).formatToParts(new Date(2e3, 11, 25));
757
1207
  return parts.findIndex((p) => p.type === "day") < parts.findIndex((p) => p.type === "month");
758
1208
  } catch {
759
1209
  return true;
760
1210
  }
761
1211
  }
762
- function validDate(year, monthIndex, day) {
763
- if (monthIndex < 0 || monthIndex > 11 || day < 1) return null;
764
- const d = new Date(year, monthIndex, day);
765
- return d.getFullYear() === year && d.getMonth() === monthIndex && d.getDate() === day ? d : null;
1212
+ function validDate(year, monthIndex2, day) {
1213
+ if (monthIndex2 < 0 || monthIndex2 > 11 || day < 1) return null;
1214
+ const d = new Date(year, monthIndex2, day);
1215
+ return d.getFullYear() === year && d.getMonth() === monthIndex2 && d.getDate() === day ? d : null;
1216
+ }
1217
+ function monthIndex(name) {
1218
+ const typed = name.toLocaleLowerCase().replace(/\.$/, "");
1219
+ const fold = (m) => m.toLocaleLowerCase().replace(/\.$/, "");
1220
+ const lists = [ENGLISH_MONTHS, Array.from({ length: 12 }, (_, i) => fold(monthName(i, "long"))), Array.from({ length: 12 }, (_, i) => fold(monthName(i, "short")))];
1221
+ for (const list of lists) {
1222
+ const i = list.findIndex((m) => m.startsWith(typed) || typed.length >= 3 && typed.startsWith(m));
1223
+ if (i >= 0) return i;
1224
+ }
1225
+ return -1;
766
1226
  }
767
1227
  function parseTypedDate(text, dayFirst = localeDayFirst()) {
768
1228
  const t = text.trim().replace(/\s+/g, " ");
769
1229
  if (!t) return null;
770
1230
  let m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(t);
771
1231
  if (m) return validDate(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
772
- const monthIndex = (name) => MONTHS.findIndex((mm) => mm.toLowerCase().startsWith(name.toLowerCase().replace(/\.$/, "")));
773
- m = /^([A-Za-z]{3,})\.?\s+(\d{1,2}),?\s+(\d{4})$/.exec(t);
1232
+ m = /^(\p{L}{3,})\.?\s+(\d{1,2}),?\s+(\d{4})$/u.exec(t);
774
1233
  if (m) {
775
1234
  const mi = monthIndex(m[1]);
776
1235
  return mi < 0 ? null : validDate(Number(m[3]), mi, Number(m[2]));
777
1236
  }
778
- m = /^(\d{1,2})\s+([A-Za-z]{3,})\.?,?\s+(\d{4})$/.exec(t);
1237
+ m = /^(\d{1,2})\.?\s+(\p{L}{3,})\.?,?\s+(\d{4})$/u.exec(t);
779
1238
  if (m) {
780
1239
  const mi = monthIndex(m[2]);
781
1240
  return mi < 0 ? null : validDate(Number(m[3]), mi, Number(m[1]));
@@ -895,7 +1354,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
895
1354
  const d = validDate(next.year, next.month - 1, next.day);
896
1355
  const ok = !!d && (!min || d >= min) && (!max || d <= max);
897
1356
  setTypedInvalid(!ok);
898
- if (d && ok && !(value && isSameDay(value, d))) {
1357
+ if (d && ok && !(value && isSameDay2(value, d))) {
899
1358
  lastCommitted.current = d.getTime();
900
1359
  onChange(d);
901
1360
  setViewDate(d);
@@ -975,7 +1434,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
975
1434
  };
976
1435
  const rangeA = range2?.start ?? null;
977
1436
  const rangeB = range2?.end ?? null;
978
- const otherEnd = value ? rangeA && !isSameDay(rangeA, value) ? rangeA : rangeB : rangeA ?? rangeB;
1437
+ const otherEnd = value ? rangeA && !isSameDay2(rangeA, value) ? rangeA : rangeB : rangeA ?? rangeB;
979
1438
  const thisEnd = value ?? (otherEnd && hover ? hover : null);
980
1439
  const [bandStart, bandEnd] = otherEnd && thisEnd ? otherEnd <= thisEnd ? [otherEnd, thisEnd] : [thisEnd, otherEnd] : [null, null];
981
1440
  const inBand = (d) => !!(bandStart && bandEnd && d > bandStart && d < bandEnd);
@@ -1092,11 +1551,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1092
1551
  style: { padding: "var(--ds-space-2) var(--ds-space-3)" },
1093
1552
  children: [
1094
1553
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: prevMonth, "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
1095
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: [
1096
- MONTHS[month],
1097
- " ",
1098
- year
1099
- ] }),
1554
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: formatMonthYear(viewDate) }),
1100
1555
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: nextMonth, "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
1101
1556
  ]
1102
1557
  }
@@ -1106,18 +1561,18 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1106
1561
  {
1107
1562
  ref: gridRef,
1108
1563
  role: "grid",
1109
- "aria-label": `${MONTHS[month]} ${year}`,
1564
+ "aria-label": formatMonthYear(viewDate),
1110
1565
  onKeyDown: grid.onKeyDown,
1111
1566
  className: "flex flex-col gap-ds-0.5 tabular-nums",
1112
1567
  style: { padding: "var(--ds-space-2) var(--ds-space-3)" },
1113
1568
  children: [
1114
- /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: DAYS.map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": DAY_NAMES[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, d)) }),
1569
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: weekdayNames(0, "narrow").map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": weekdayNames(0, "long")[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, i)) }),
1115
1570
  weeks.map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5", onMouseLeave: () => setHover(null), children: week.map((day, i) => {
1116
1571
  if (day === null) return /* @__PURE__ */ jsx("div", { role: "gridcell" }, `empty-${i}`);
1117
1572
  const dateObj = new Date(year, month, day);
1118
- const isSelected = !!value && isSameDay(dateObj, value);
1119
- const isOtherEnd = !!otherEnd && isSameDay(dateObj, otherEnd);
1120
- const isToday2 = isSameDay(dateObj, today);
1573
+ const isSelected = !!value && isSameDay2(dateObj, value);
1574
+ const isOtherEnd = !!otherEnd && isSameDay2(dateObj, otherEnd);
1575
+ const isToday2 = isSameDay2(dateObj, today);
1121
1576
  const between = inBand(dateObj);
1122
1577
  const dis = isDisabledDay(dateObj);
1123
1578
  return /* @__PURE__ */ jsx(
@@ -1130,12 +1585,12 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1130
1585
  "aria-disabled": dis || void 0,
1131
1586
  onClick: () => selectDay(day),
1132
1587
  onFocus: () => {
1133
- if (!isSameDay(dateObj, focusDate)) setFocusDate(dateObj);
1588
+ if (!isSameDay2(dateObj, focusDate)) setFocusDate(dateObj);
1134
1589
  },
1135
1590
  onMouseEnter: () => setHover(dateObj),
1136
1591
  "aria-selected": isSelected,
1137
1592
  "aria-current": isToday2 ? "date" : void 0,
1138
- "aria-label": formatDate(dateObj),
1593
+ "aria-label": formatDayLong(dateObj),
1139
1594
  className: cn(
1140
1595
  "w-full aspect-square flex items-center justify-center text-xs",
1141
1596
  "transition-colors cursor-pointer",
@@ -1191,174 +1646,6 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1191
1646
  )
1192
1647
  ] });
1193
1648
  }
1194
-
1195
- // ../../showcase/src/components/Calendar/calendar-utils.ts
1196
- var MONTH_NAMES = [
1197
- "January",
1198
- "February",
1199
- "March",
1200
- "April",
1201
- "May",
1202
- "June",
1203
- "July",
1204
- "August",
1205
- "September",
1206
- "October",
1207
- "November",
1208
- "December"
1209
- ];
1210
- var MONTH_NAMES_SHORT = [
1211
- "Jan",
1212
- "Feb",
1213
- "Mar",
1214
- "Apr",
1215
- "May",
1216
- "Jun",
1217
- "Jul",
1218
- "Aug",
1219
- "Sep",
1220
- "Oct",
1221
- "Nov",
1222
- "Dec"
1223
- ];
1224
- var DAY_NAMES_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1225
- var DAY_NAMES_MIN = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
1226
- function getOrderedDayNames(weekStartsOn) {
1227
- if (weekStartsOn === 1) return [...DAY_NAMES_MIN.slice(1), DAY_NAMES_MIN[0]];
1228
- return DAY_NAMES_MIN;
1229
- }
1230
- function getOrderedDayNamesShort(weekStartsOn) {
1231
- if (weekStartsOn === 1) return [...DAY_NAMES_SHORT.slice(1), DAY_NAMES_SHORT[0]];
1232
- return DAY_NAMES_SHORT;
1233
- }
1234
- function isSameDay2(a, b) {
1235
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
1236
- }
1237
- function isSameMonth(a, b) {
1238
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
1239
- }
1240
- function isToday(d) {
1241
- return isSameDay2(d, /* @__PURE__ */ new Date());
1242
- }
1243
- function isWeekend(d) {
1244
- const day = d.getDay();
1245
- return day === 0 || day === 6;
1246
- }
1247
- function startOfDay(d) {
1248
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
1249
- }
1250
- function startOfWeek(d, weekStartsOn = 0) {
1251
- const date = new Date(d);
1252
- const day = date.getDay();
1253
- const diff = (day - weekStartsOn + 7) % 7;
1254
- date.setDate(date.getDate() - diff);
1255
- return startOfDay(date);
1256
- }
1257
- function endOfWeek(d, weekStartsOn = 0) {
1258
- const start = startOfWeek(d, weekStartsOn);
1259
- const end = new Date(start);
1260
- end.setDate(end.getDate() + 6);
1261
- end.setHours(23, 59, 59, 999);
1262
- return end;
1263
- }
1264
- function addDays2(d, n) {
1265
- const result = new Date(d);
1266
- result.setDate(result.getDate() + n);
1267
- return result;
1268
- }
1269
- function addMonths(d, n) {
1270
- const result = new Date(d);
1271
- result.setMonth(result.getMonth() + n);
1272
- return result;
1273
- }
1274
- function getMonthGrid(year, month, weekStartsOn = 0) {
1275
- const firstOfMonth = new Date(year, month, 1);
1276
- const gridStart = startOfWeek(firstOfMonth, weekStartsOn);
1277
- const weeks = [];
1278
- const current = new Date(gridStart);
1279
- for (let w = 0; w < 6; w++) {
1280
- const week = [];
1281
- for (let d = 0; d < 7; d++) {
1282
- week.push(new Date(current));
1283
- current.setDate(current.getDate() + 1);
1284
- }
1285
- weeks.push(week);
1286
- }
1287
- return weeks;
1288
- }
1289
- function getWeekDays(date, weekStartsOn = 0) {
1290
- const start = startOfWeek(date, weekStartsOn);
1291
- const days = [];
1292
- for (let i = 0; i < 7; i++) {
1293
- days.push(addDays2(start, i));
1294
- }
1295
- return days;
1296
- }
1297
- function getEventsForDay(events, date) {
1298
- const dayStart = startOfDay(date);
1299
- const dayEnd = new Date(dayStart);
1300
- dayEnd.setHours(23, 59, 59, 999);
1301
- return events.filter((e) => {
1302
- const eStart = new Date(e.start);
1303
- const eEnd = e.end ? new Date(e.end) : eStart;
1304
- return eStart <= dayEnd && eEnd >= dayStart;
1305
- });
1306
- }
1307
- function formatTime(d) {
1308
- const h = d.getHours();
1309
- const m = d.getMinutes();
1310
- const ampm = h >= 12 ? "PM" : "AM";
1311
- const hour = h % 12 || 12;
1312
- return m === 0 ? `${hour} ${ampm}` : `${hour}:${String(m).padStart(2, "0")} ${ampm}`;
1313
- }
1314
- function formatTimeRange(start, end) {
1315
- if (!end) return formatTime(start);
1316
- return `${formatTime(start)} \u2013 ${formatTime(end)}`;
1317
- }
1318
- function formatWeekRange(d, weekStartsOn = 0) {
1319
- const start = startOfWeek(d, weekStartsOn);
1320
- const end = endOfWeek(d, weekStartsOn);
1321
- const sameMonth = start.getMonth() === end.getMonth();
1322
- if (sameMonth) {
1323
- return `${MONTH_NAMES_SHORT[start.getMonth()]} ${start.getDate()} \u2013 ${end.getDate()}, ${start.getFullYear()}`;
1324
- }
1325
- const sameYear = start.getFullYear() === end.getFullYear();
1326
- if (sameYear) {
1327
- return `${MONTH_NAMES_SHORT[start.getMonth()]} ${start.getDate()} \u2013 ${MONTH_NAMES_SHORT[end.getMonth()]} ${end.getDate()}, ${start.getFullYear()}`;
1328
- }
1329
- return `${MONTH_NAMES_SHORT[start.getMonth()]} ${start.getDate()}, ${start.getFullYear()} \u2013 ${MONTH_NAMES_SHORT[end.getMonth()]} ${end.getDate()}, ${end.getFullYear()}`;
1330
- }
1331
- function getOverlappingGroups(events) {
1332
- const timed = events.filter((e) => !e.allDay && e.end).sort((a, b) => a.start.getTime() - b.start.getTime());
1333
- if (timed.length === 0) return [];
1334
- const result = [];
1335
- const columns = [];
1336
- for (const event of timed) {
1337
- const eStart = event.start.getTime();
1338
- const eEnd = (event.end ?? event.start).getTime();
1339
- let placed = false;
1340
- for (let col = 0; col < columns.length; col++) {
1341
- if (columns[col].end <= eStart) {
1342
- columns[col].end = eEnd;
1343
- result.push({ event, column: col, totalColumns: 0 });
1344
- placed = true;
1345
- break;
1346
- }
1347
- }
1348
- if (!placed) {
1349
- columns.push({ end: eEnd });
1350
- result.push({ event, column: columns.length - 1, totalColumns: 0 });
1351
- }
1352
- }
1353
- const totalCols = columns.length;
1354
- for (const item of result) {
1355
- item.totalColumns = totalCols;
1356
- }
1357
- return result;
1358
- }
1359
- function timeToFraction(d) {
1360
- return (d.getHours() * 60 + d.getMinutes()) / (24 * 60);
1361
- }
1362
1649
  var CONTROL_HEIGHT3 = {
1363
1650
  sm: "h-[var(--ds-control-height-sm)]",
1364
1651
  md: "h-[var(--ds-control-height-md)]",
@@ -1369,10 +1656,6 @@ var TEXT_SIZE3 = {
1369
1656
  md: "text-sm",
1370
1657
  lg: "text-base"
1371
1658
  };
1372
- var MONTHS2 = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
1373
- function fmt(d) {
1374
- return `${MONTHS2[d.getMonth()].slice(0, 3)} ${d.getDate()}, ${d.getFullYear()}`;
1375
- }
1376
1659
  var DEFAULT_DATE_RANGE_PRESETS = [
1377
1660
  { label: "Today", range: () => {
1378
1661
  const t = startOfDay(/* @__PURE__ */ new Date());
@@ -1427,7 +1710,8 @@ function DateRangePicker({
1427
1710
  const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : void 0;
1428
1711
  const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
1429
1712
  const today = useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
1430
- const dayNames = getOrderedDayNamesShort(weekStartsOn);
1713
+ const dayNames = weekdayNames(weekStartsOn, "narrow");
1714
+ const dayNamesLong = weekdayNames(weekStartsOn, "long");
1431
1715
  const gridRef = useRef(null);
1432
1716
  const [focusDate, setFocusDate] = useState(() => startOfDay(value.start ?? /* @__PURE__ */ new Date()));
1433
1717
  const [prevOpen, setPrevOpen] = useState(open);
@@ -1441,8 +1725,8 @@ function DateRangePicker({
1441
1725
  }
1442
1726
  const showDay = (d) => {
1443
1727
  setFocusDate(d);
1444
- const monthIndex = (x) => x.getFullYear() * 12 + x.getMonth();
1445
- const offset = monthIndex(d) - monthIndex(viewDate);
1728
+ const monthIndex2 = (x) => x.getFullYear() * 12 + x.getMonth();
1729
+ const offset = monthIndex2(d) - monthIndex2(viewDate);
1446
1730
  if (offset < 0) setViewDate(new Date(d.getFullYear(), d.getMonth(), 1));
1447
1731
  else if (offset > 1) setViewDate(new Date(d.getFullYear(), d.getMonth() - 1, 1));
1448
1732
  };
@@ -1504,7 +1788,7 @@ function DateRangePicker({
1504
1788
  const rangeEnd2 = value.end ?? previewEnd;
1505
1789
  const inRange = (d) => !!(rangeStart && rangeEnd2 && d > rangeStart && d < rangeEnd2);
1506
1790
  const months = [viewDate, addMonths(viewDate, 1)];
1507
- const summary = value.start && value.end ? `${fmt(value.start)} \u2013 ${fmt(value.end)}` : value.start ? `${fmt(value.start)} \u2013 \u2026` : null;
1791
+ const summary = value.start && value.end ? formatDayRange(value.start, value.end) : value.start ? `${formatDayMedium(value.start)} \u2013 \u2026` : null;
1508
1792
  return /* @__PURE__ */ jsxs("div", { ref, className: cn(className), children: [
1509
1793
  label && /* @__PURE__ */ jsx("label", { htmlFor: triggerId, className: "block text-sm font-medium text-[var(--ds-text-primary)] mb-ds-1", children: label }),
1510
1794
  control.requiredNote,
@@ -1571,23 +1855,15 @@ function DateRangePicker({
1571
1855
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
1572
1856
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between bg-[var(--ds-bg-muted)] rounded-tr-[var(--ds-radius-md)] px-ds-3 py-ds-2", children: [
1573
1857
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => pageMonths(-1), "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
1574
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: [
1575
- MONTHS2[months[0].getMonth()],
1576
- " ",
1577
- months[0].getFullYear(),
1578
- " \u2013 ",
1579
- MONTHS2[months[1].getMonth()],
1580
- " ",
1581
- months[1].getFullYear()
1582
- ] }),
1858
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: formatMonthRange(months[0], months[1]) }),
1583
1859
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => pageMonths(1), "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
1584
1860
  ] }),
1585
- /* @__PURE__ */ jsx("div", { ref: gridRef, onKeyDown: grid.onKeyDown, className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { role: "grid", "aria-label": `${MONTHS2[m.getMonth()]} ${m.getFullYear()}`, className: "w-[224px] flex flex-col gap-ds-0.5", children: [
1586
- /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: dayNames.map((d) => /* @__PURE__ */ jsx("div", { role: "columnheader", className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, d)) }),
1861
+ /* @__PURE__ */ jsx("div", { ref: gridRef, onKeyDown: grid.onKeyDown, className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { role: "grid", "aria-label": formatMonthYear(m), className: "w-[224px] flex flex-col gap-ds-0.5", children: [
1862
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: dayNames.map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": dayNamesLong[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, i)) }),
1587
1863
  getMonthGrid(m.getFullYear(), m.getMonth(), weekStartsOn).map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5", children: week.map((d) => {
1588
1864
  if (!isSameMonth(d, m)) return /* @__PURE__ */ jsx("div", { role: "gridcell" }, d.toISOString());
1589
- const isStart = !!rangeStart && isSameDay2(d, rangeStart);
1590
- const isEnd = !!rangeEnd2 && isSameDay2(d, rangeEnd2);
1865
+ const isStart = !!rangeStart && isSameDay(d, rangeStart);
1866
+ const isEnd = !!rangeEnd2 && isSameDay(d, rangeEnd2);
1591
1867
  const between = inRange(d);
1592
1868
  const dis = isDisabledDay(d);
1593
1869
  return /* @__PURE__ */ jsx(
@@ -1600,17 +1876,17 @@ function DateRangePicker({
1600
1876
  "aria-disabled": dis || void 0,
1601
1877
  onClick: () => selectDay(d),
1602
1878
  onFocus: () => {
1603
- if (!isSameDay2(d, focusDate)) setFocusDate(d);
1879
+ if (!isSameDay(d, focusDate)) setFocusDate(d);
1604
1880
  },
1605
1881
  onMouseEnter: () => setHover(d),
1606
1882
  "aria-selected": isStart || isEnd || between,
1607
- "aria-current": isSameDay2(d, today) ? "date" : void 0,
1608
- "aria-label": fmt(d),
1883
+ "aria-current": isSameDay(d, today) ? "date" : void 0,
1884
+ "aria-label": formatDayLong(d),
1609
1885
  className: cn(
1610
1886
  "w-full aspect-square flex items-center justify-center text-xs",
1611
1887
  "transition-colors cursor-pointer",
1612
1888
  "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
1613
- isStart || isEnd ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : isSameDay2(d, today) ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)] text-[var(--ds-accent-primary)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
1889
+ isStart || isEnd ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : isSameDay(d, today) ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)] text-[var(--ds-accent-primary)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
1614
1890
  dis && "opacity-disabled cursor-not-allowed hover:bg-transparent"
1615
1891
  ),
1616
1892
  children: d.getDate()
@@ -3515,7 +3791,7 @@ var Alert = forwardRef(function Alert2({
3515
3791
  isAccent ? cn("border-[length:var(--ds-border-width)] border-current", actionColorsByVariant[variant]) : cn("border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]", "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]")
3516
3792
  ),
3517
3793
  children: [
3518
- a.iconLeft && /* @__PURE__ */ jsx("span", { className: "inline-flex mr-ds-1", children: a.iconLeft }),
3794
+ a.iconLeft && /* @__PURE__ */ jsx("span", { className: "inline-flex mr-ds-1", children: slotIcon(a.iconLeft, 14, "an Alert action's iconLeft") }),
3519
3795
  a.label
3520
3796
  ]
3521
3797
  },
@@ -4065,102 +4341,6 @@ function PanelCheckbox({ checked, indeterminate, onClick, label }) {
4065
4341
  }
4066
4342
  );
4067
4343
  }
4068
-
4069
- // ../../showcase/src/lib/initials.ts
4070
- function initialsOf(name) {
4071
- return name.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((word) => Array.from(word)[0] ?? "").join("").toUpperCase();
4072
- }
4073
- function toInitials(value) {
4074
- const s = value.trim();
4075
- if (!s) return "";
4076
- if (!/\s/.test(s) && Array.from(s).length <= 3) return s;
4077
- return initialsOf(s);
4078
- }
4079
- var sizeStyles2 = {
4080
- sm: "h-8 w-8 text-xs",
4081
- md: "h-10 w-10 text-sm",
4082
- lg: "h-12 w-12 text-base"
4083
- };
4084
- var paletteStyles = {
4085
- 1: "bg-[var(--ds-palette-1-bg,var(--ds-bg-muted))] text-[var(--ds-palette-1-text,var(--ds-text-secondary))]",
4086
- 2: "bg-[var(--ds-palette-2-bg,var(--ds-bg-muted))] text-[var(--ds-palette-2-text,var(--ds-text-secondary))]",
4087
- 3: "bg-[var(--ds-palette-3-bg,var(--ds-bg-muted))] text-[var(--ds-palette-3-text,var(--ds-text-secondary))]",
4088
- 4: "bg-[var(--ds-palette-4-bg,var(--ds-bg-muted))] text-[var(--ds-palette-4-text,var(--ds-text-secondary))]",
4089
- 5: "bg-[var(--ds-palette-5-bg,var(--ds-bg-muted))] text-[var(--ds-palette-5-text,var(--ds-text-secondary))]"
4090
- };
4091
- function paletteFor(seed) {
4092
- let h = 0;
4093
- for (const ch of seed) h = h * 31 + ch.charCodeAt(0) >>> 0;
4094
- return h % 5 + 1;
4095
- }
4096
- function colorStyles(color, seed) {
4097
- if (color === "accent") return "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]";
4098
- if (color === "neutral") return "bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]";
4099
- return paletteStyles[color === "auto" ? paletteFor(seed) : color];
4100
- }
4101
- function PresenceMark({ status }) {
4102
- return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 10 10", width: "10", height: "10", "aria-hidden": "true", focusable: "false", "data-presence": status, className: "block", children: [
4103
- status === "online" && /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "5", className: "fill-[var(--ds-status-success)]" }),
4104
- status === "away" && /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "4", fill: "none", strokeWidth: "2", className: "stroke-[var(--ds-status-warning)]" }),
4105
- status === "busy" && /* @__PURE__ */ jsxs(Fragment, { children: [
4106
- /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "5", className: "fill-[var(--ds-status-error)]" }),
4107
- /* @__PURE__ */ jsx("rect", { x: "2.5", y: "4.1", width: "5", height: "1.8", rx: "0.9", className: "fill-[var(--ds-bg-canvas)]" })
4108
- ] }),
4109
- status === "offline" && /* @__PURE__ */ jsxs(Fragment, { children: [
4110
- /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "4", fill: "none", strokeWidth: "2", className: "stroke-[var(--ds-text-muted)]" }),
4111
- /* @__PURE__ */ jsx("line", { x1: "3.1", y1: "6.9", x2: "6.9", y2: "3.1", strokeWidth: "1.5", strokeLinecap: "round", className: "stroke-[var(--ds-text-muted)]" })
4112
- ] })
4113
- ] });
4114
- }
4115
- function Avatar({ initials, src, alt, size = "md", status, color = "auto", className }) {
4116
- const who = alt ?? initials ?? "";
4117
- const named = status ? [who, status].filter(Boolean).join(", ") : void 0;
4118
- const base = cn(
4119
- "inline-flex items-center justify-center font-medium shrink-0",
4120
- "rounded-[var(--ds-radius-full)]",
4121
- sizeStyles2[size],
4122
- className
4123
- );
4124
- const avatarElement = src ? /* @__PURE__ */ jsx(
4125
- "img",
4126
- {
4127
- "data-avatar": "",
4128
- src,
4129
- alt: named ?? alt ?? initials ?? "",
4130
- className: cn(base, "object-cover")
4131
- }
4132
- ) : /* @__PURE__ */ jsx(
4133
- "div",
4134
- {
4135
- "data-avatar": "",
4136
- role: named ? "img" : void 0,
4137
- "aria-label": named,
4138
- className: cn(
4139
- base,
4140
- colorStyles(color, alt ?? initials ?? ""),
4141
- "border-[length:var(--ds-border-width)] border-transparent"
4142
- ),
4143
- children: initials != null ? toInitials(initials) : null
4144
- }
4145
- );
4146
- if (!status) return avatarElement;
4147
- return /* @__PURE__ */ jsxs("div", { className: "relative inline-flex", children: [
4148
- avatarElement,
4149
- /* @__PURE__ */ jsx(
4150
- "span",
4151
- {
4152
- className: cn(
4153
- "absolute",
4154
- size === "sm" && "bottom-[-4px] right-[-4px]",
4155
- size === "md" && "bottom-[-2px] right-[-2px]",
4156
- size === "lg" && "bottom-[0px] right-[0px]"
4157
- ),
4158
- "aria-hidden": "true",
4159
- children: /* @__PURE__ */ jsx("span", { className: "block rounded-[var(--ds-radius-full)] bg-[var(--ds-bg-canvas)] shadow-[0_0_0_2px_var(--ds-bg-canvas)]", children: /* @__PURE__ */ jsx(PresenceMark, { status }) })
4160
- }
4161
- )
4162
- ] });
4163
- }
4164
4344
  function MentionInput({
4165
4345
  value: controlledValue,
4166
4346
  onChange: onChangeProp,
@@ -4168,8 +4348,12 @@ function MentionInput({
4168
4348
  trigger = "@",
4169
4349
  placeholder,
4170
4350
  disabled,
4171
- className
4351
+ className,
4352
+ error = false,
4353
+ "aria-label": ariaLabel,
4354
+ ...wiring
4172
4355
  }) {
4356
+ const control = useFieldControl({ ...wiring, error: error || void 0 });
4173
4357
  const [internalValue, setInternalValue] = useState("");
4174
4358
  const value = controlledValue ?? internalValue;
4175
4359
  const onChange = useReportedChange(onChangeProp, value);
@@ -4177,14 +4361,14 @@ function MentionInput({
4177
4361
  const [showPopup, setShowPopup] = useState(false);
4178
4362
  const [activeIndex, setActiveIndex] = useState(0);
4179
4363
  const [triggerStart, setTriggerStart] = useState(-1);
4180
- const [popupPos, setPopupPos] = useState({ top: 0, left: 0 });
4364
+ const [anchor, setAnchor] = useState(null);
4181
4365
  const inputRef = useRef(null);
4182
4366
  const popupRef = useRef(null);
4183
4367
  const mirrorRef = useRef(null);
4184
- const filtered = suggestions.filter(
4185
- (s) => s.label.toLowerCase().includes(query.toLowerCase()) || s.description?.toLowerCase().includes(query.toLowerCase())
4186
- );
4187
- useOverlayLayer(showPopup && filtered.length > 0);
4368
+ const listId = useId();
4369
+ const { items: filtered, more } = shownMentions(matchMentions(suggestions, query));
4370
+ const listShown = showPopup && filtered.length > 0;
4371
+ useOverlayLayer(listShown);
4188
4372
  const updateValue = useCallback(
4189
4373
  (v) => {
4190
4374
  if (controlledValue === void 0) setInternalValue(v);
@@ -4227,13 +4411,15 @@ function MentionInput({
4227
4411
  const span = document.createElement("span");
4228
4412
  span.textContent = trigger;
4229
4413
  mirror.appendChild(span);
4230
- const rect = el.getBoundingClientRect();
4231
4414
  const spanRect = span.getBoundingClientRect();
4232
4415
  const mirrorRect = mirror.getBoundingClientRect();
4233
- setPopupPos({
4234
- top: rect.top + (spanRect.top - mirrorRect.top) + span.offsetHeight + 4,
4235
- left: rect.left + (spanRect.left - mirrorRect.left)
4236
- });
4416
+ setAnchor({ x: spanRect.left - mirrorRect.left, y: spanRect.top - mirrorRect.top, width: spanRect.width, height: span.offsetHeight });
4417
+ };
4418
+ const anchorRect = () => {
4419
+ const el = inputRef.current;
4420
+ if (!el || !anchor) return null;
4421
+ const field = el.getBoundingClientRect();
4422
+ return new DOMRect(field.left + anchor.x, field.top + anchor.y - el.scrollTop, anchor.width, anchor.height);
4237
4423
  };
4238
4424
  const insertMention = (suggestion) => {
4239
4425
  const el = inputRef.current;
@@ -4252,13 +4438,15 @@ function MentionInput({
4252
4438
  });
4253
4439
  };
4254
4440
  const handleKeyDown = (e) => {
4255
- if (!showPopup || filtered.length === 0) return;
4441
+ if (!listShown) return;
4256
4442
  if (e.key === "ArrowDown") {
4257
4443
  e.preventDefault();
4258
4444
  setActiveIndex((i) => (i + 1) % filtered.length);
4259
4445
  } else if (e.key === "ArrowUp") {
4260
4446
  e.preventDefault();
4261
4447
  setActiveIndex((i) => (i - 1 + filtered.length) % filtered.length);
4448
+ } else if (e.key === "Tab" && e.shiftKey) {
4449
+ flushSync(() => setShowPopup(false));
4262
4450
  } else if (e.key === "Enter" || e.key === "Tab") {
4263
4451
  e.preventDefault();
4264
4452
  insertMention(filtered[activeIndex]);
@@ -4282,21 +4470,30 @@ function MentionInput({
4282
4470
  "textarea",
4283
4471
  {
4284
4472
  ref: inputRef,
4473
+ id: control.id,
4474
+ "aria-labelledby": wiring["aria-labelledby"],
4475
+ "aria-label": control.labelId ? void 0 : ariaLabel,
4476
+ "aria-describedby": control.describedBy,
4477
+ "aria-invalid": control.invalid || void 0,
4478
+ "aria-required": control.required || void 0,
4285
4479
  value,
4286
4480
  onChange: handleInput,
4287
4481
  onKeyDown: handleKeyDown,
4482
+ "aria-autocomplete": "list",
4483
+ "aria-controls": listShown ? listId : void 0,
4484
+ "aria-activedescendant": listShown ? mentionOptionId(listId, activeIndex) : void 0,
4288
4485
  placeholder,
4289
4486
  disabled,
4290
4487
  rows: 3,
4291
4488
  className: cn(
4292
4489
  "flex w-full px-ds-3 py-ds-2 text-sm resize-none",
4293
4490
  "bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
4294
- "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
4491
+ "border-[length:var(--ds-border-width)]",
4492
+ control.invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-input-border-hover)]",
4295
4493
  "rounded-[var(--ds-radius-md)]",
4296
4494
  "shadow-[var(--ds-input-shadow)]",
4297
4495
  "placeholder:text-[var(--ds-text-muted)]",
4298
- "hover:border-[var(--ds-input-border-hover)]",
4299
- FOCUS_RING,
4496
+ control.invalid ? ERROR_FOCUS_RING : FOCUS_RING,
4300
4497
  "disabled:cursor-not-allowed disabled:opacity-disabled disabled:hover:border-[var(--ds-input-border)]",
4301
4498
  "transition-colors duration-[var(--ds-transition-speed)]"
4302
4499
  )
@@ -4310,59 +4507,19 @@ function MentionInput({
4310
4507
  className: "fixed top-0 left-0 -z-50 opacity-0 pointer-events-none"
4311
4508
  }
4312
4509
  ),
4313
- showPopup && filtered.length > 0 && createPortal(
4314
- /* @__PURE__ */ jsx(
4315
- "div",
4316
- {
4317
- ref: popupRef,
4318
- role: "listbox",
4319
- className: cn(
4320
- "fixed z-[var(--ds-z-popover)] min-w-[200px] max-h-[200px] overflow-y-auto",
4321
- "bg-[var(--ds-bg-surface-elevated)]",
4322
- "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
4323
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
4324
- "rounded-[var(--ds-radius-md)] shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
4325
- "py-ds-1"
4326
- ),
4327
- style: { top: popupPos.top, left: popupPos.left },
4328
- children: filtered.map((s, i) => /* @__PURE__ */ jsxs(
4329
- "button",
4330
- {
4331
- type: "button",
4332
- role: "option",
4333
- "aria-selected": i === activeIndex,
4334
- className: cn(
4335
- "flex items-center gap-ds-2.5 w-full px-ds-3 py-ds-1.5 text-left text-sm cursor-pointer",
4336
- "transition-colors duration-[var(--ds-transition-speed)]",
4337
- i === activeIndex ? "bg-[var(--ds-bg-muted)] text-[var(--ds-text-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
4338
- ),
4339
- onMouseDown: (e) => {
4340
- e.preventDefault();
4341
- insertMention(s);
4342
- },
4343
- onMouseEnter: () => setActiveIndex(i),
4344
- children: [
4345
- /* @__PURE__ */ jsx(
4346
- Avatar,
4347
- {
4348
- src: s.avatar,
4349
- initials: s.label.charAt(0).toUpperCase(),
4350
- alt: s.label,
4351
- size: "sm",
4352
- className: "!h-6 !w-6 !text-2xs"
4353
- }
4354
- ),
4355
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
4356
- /* @__PURE__ */ jsx("div", { className: "font-medium text-[var(--ds-text-primary)] truncate", children: s.label }),
4357
- s.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] truncate", children: s.description })
4358
- ] })
4359
- ]
4360
- },
4361
- s.id
4362
- ))
4363
- }
4364
- ),
4365
- document.body
4510
+ listShown && /* @__PURE__ */ jsx(
4511
+ MentionList,
4512
+ {
4513
+ id: listId,
4514
+ label: "Suggestions",
4515
+ items: filtered,
4516
+ more,
4517
+ activeIndex,
4518
+ onActiveIndexChange: setActiveIndex,
4519
+ onPick: insertMention,
4520
+ anchorRect,
4521
+ listRef: popupRef
4522
+ }
4366
4523
  )
4367
4524
  ] });
4368
4525
  }
@@ -5025,7 +5182,7 @@ function CardGrid({ minWidth, maxColumns = 4, compare = false, gap = "var(--ds-s
5025
5182
  }
5026
5183
  );
5027
5184
  }
5028
- var sizeStyles3 = {
5185
+ var sizeStyles2 = {
5029
5186
  sm: { gap: "gap-ds-0.5", label: "text-[length:var(--ds-font-size-xs)]", value: "text-[length:var(--ds-font-size-xs)]", iconSize: 12, py: "py-ds-1.5" },
5030
5187
  md: { gap: "gap-ds-1", label: "text-[length:var(--ds-font-size-sm)]", value: "text-[length:var(--ds-font-size-sm)]", iconSize: 14, py: "py-ds-2.5" },
5031
5188
  lg: { gap: "gap-ds-1.5", label: "text-[length:var(--ds-font-size-base)]", value: "text-[length:var(--ds-font-size-base)]", iconSize: 16, py: "py-ds-3" }
@@ -5071,7 +5228,7 @@ var DescriptionList = forwardRef(function DescriptionList2({
5071
5228
  stackBelow: stackBelowProp,
5072
5229
  className
5073
5230
  }, ref) {
5074
- const s = sizeStyles3[size];
5231
+ const s = sizeStyles2[size];
5075
5232
  const stackBelow = stackBelowProp ?? (columns > 1 ? "sm" : void 0);
5076
5233
  const templateClass = (layout) => columns > 1 && stackBelow !== "none" ? autoColumnClasses[layout][columns] : columnClasses[columns];
5077
5234
  if (orientation === "vertical") {
@@ -5367,17 +5524,31 @@ function clickIsRows(e) {
5367
5524
  const control = target.closest(ROW_CONTROL);
5368
5525
  return !control || control === e.currentTarget || !e.currentTarget.contains(control);
5369
5526
  }
5527
+ var ISO_MOMENT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?$/;
5370
5528
  function sortableValue(v) {
5371
5529
  if (v === null || v === void 0 || v === "") return void 0;
5372
5530
  if (v instanceof Date) return v.getTime();
5531
+ if (typeof v === "string" && ISO_MOMENT.test(v)) {
5532
+ const at = Date.parse(v);
5533
+ if (Number.isFinite(at)) return at;
5534
+ }
5373
5535
  if (typeof v === "string" || typeof v === "number") return v;
5374
5536
  if (typeof v === "boolean") return v ? 1 : 0;
5375
5537
  return isValidElement(v) || typeof v === "object" ? null : String(v);
5376
5538
  }
5377
- var COLLATOR = new Intl.Collator(void 0, { numeric: true });
5539
+ var COLLATORS = /* @__PURE__ */ new Map();
5540
+ function collator() {
5541
+ const locale = formatLocale() ?? "";
5542
+ let c = COLLATORS.get(locale);
5543
+ if (!c) {
5544
+ c = new Intl.Collator(locale || void 0, { numeric: true });
5545
+ COLLATORS.set(locale, c);
5546
+ }
5547
+ return c;
5548
+ }
5378
5549
  function compareValues(a, b) {
5379
5550
  if (typeof a === "number" && typeof b === "number") return a - b;
5380
- return COLLATOR.compare(String(a), String(b));
5551
+ return collator().compare(String(a), String(b));
5381
5552
  }
5382
5553
  var UNIT_SCALE = {
5383
5554
  "": 1,
@@ -5782,7 +5953,7 @@ function Table({
5782
5953
  if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
5783
5954
  return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className: cn("py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", className), children: emptyState });
5784
5955
  }
5785
- const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: title ? void 0 : listRoot, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("flex flex-col gap-ds-3 overflow-y-auto", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
5956
+ const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: title ? void 0 : listRoot, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("flex flex-col gap-ds-3 overflow-y-auto", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
5786
5957
  selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
5787
5958
  drawn.map(({ row, originalIdx }) => {
5788
5959
  const isSelected = selectedSet.has(originalIdx);
@@ -5865,7 +6036,7 @@ function Table({
5865
6036
  String(id)
5866
6037
  );
5867
6038
  })
5868
- ] }) });
6039
+ ] }) }) });
5869
6040
  return withControl(title ? titledCards(cards) : cards);
5870
6041
  }
5871
6042
  const cellCount = columns.length + lead;
@@ -5934,7 +6105,7 @@ function Table({
5934
6105
  );
5935
6106
  })
5936
6107
  ] }) }),
5937
- /* @__PURE__ */ jsx("tbody", { children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
6108
+ /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
5938
6109
  "td",
5939
6110
  {
5940
6111
  colSpan: cellCount,
@@ -6063,7 +6234,7 @@ function Table({
6063
6234
  }
6064
6235
  ) })
6065
6236
  ] }, String(id));
6066
- }) })
6237
+ }) }) })
6067
6238
  ] });
6068
6239
  const region = scrollable || regionFocused ? { tabIndex: 0, role: "region", ...title ? { "aria-labelledby": titleId } : { "aria-label": ariaLabel ?? "Table" } } : {};
6069
6240
  return withControl(
@@ -6095,7 +6266,7 @@ function Table({
6095
6266
  },
6096
6267
  ...fade,
6097
6268
  ...region,
6098
- className: cn("min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
6269
+ className: cn("relative min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
6099
6270
  children: table
6100
6271
  }
6101
6272
  )
@@ -6334,593 +6505,755 @@ function SegmentedControl({
6334
6505
  }
6335
6506
  );
6336
6507
  }
6337
- function EventPopover({ event, category, open, anchorRef }) {
6338
- const floatingRef = useRef(null);
6339
- const pos = usePosition(anchorRef, floatingRef, open, {
6340
- side: "top",
6341
- align: "center",
6342
- offset: 8,
6343
- flip: true
6344
- });
6345
- if (!open) return null;
6346
- const color = category?.color ?? "var(--ds-accent-primary)";
6347
- return createPortal(
6348
- /* @__PURE__ */ jsxs(
6349
- "div",
6508
+
6509
+ // ../../showcase/src/components/Calendar/event-colours.ts
6510
+ function eventColours(category) {
6511
+ const colour = category?.color;
6512
+ if (colour === void 0 || colour === "accent" || colour === "var(--ds-accent-primary)") return ACCENT;
6513
+ if (colour === "neutral") return NEUTRAL;
6514
+ if (typeof colour === "number") return Number.isInteger(colour) && colour >= 1 ? supporting(colour) : NEUTRAL;
6515
+ const named = SUPPORTING_TOKEN.exec(colour.trim());
6516
+ if (named) return supporting(Number(named[1]));
6517
+ const chart = CHART_TOKEN.exec(colour.trim());
6518
+ if (chart) return Number(chart[1]) === 1 ? ACCENT : supporting(Number(chart[1]) - 1);
6519
+ return { ...NEUTRAL, edge: colour };
6520
+ }
6521
+ var SUPPORTING_TOKEN = /^var\(\s*--ds-palette-(\d+)-[a-z-]+\s*\)$/;
6522
+ var CHART_TOKEN = /^var\(\s*--ds-chart-(\d+)\s*\)$/;
6523
+ var supporting = (n) => ({
6524
+ fill: `var(--ds-palette-${n}-bg, ${NEUTRAL.fill})`,
6525
+ text: `var(--ds-palette-${n}-text, ${NEUTRAL.text})`,
6526
+ edge: `var(--ds-palette-${n}-chart, ${NEUTRAL.edge})`
6527
+ });
6528
+ var ACCENT = {
6529
+ fill: "var(--ds-accent-bg, var(--ds-accent-subtle))",
6530
+ text: "var(--ds-accent-text, var(--ds-text-primary))",
6531
+ edge: "var(--ds-chart-1)"
6532
+ };
6533
+ var NEUTRAL = {
6534
+ fill: "var(--ds-bg-muted)",
6535
+ text: "var(--ds-text-primary)",
6536
+ edge: "var(--ds-input-border)"
6537
+ };
6538
+ function EventBar({ event, category, compact, onOpen, inert, showTime = true, continuesBefore, continuesAfter, className, style }) {
6539
+ const ref = useRef(null);
6540
+ const colours = eventColours(category);
6541
+ const name = eventName(event, category);
6542
+ const look = cn(
6543
+ "border-[length:var(--ds-border-width)] border-solid rounded-[var(--ds-radius-sm)]",
6544
+ continuesBefore && "rounded-s-none border-s-0",
6545
+ continuesAfter && "rounded-e-none border-e-0"
6546
+ );
6547
+ const paint = { backgroundColor: colours.fill, color: colours.text, borderColor: colours.edge, ...style };
6548
+ if (inert) {
6549
+ return /* @__PURE__ */ jsx(
6550
+ "span",
6350
6551
  {
6351
- ref: floatingRef,
6352
- className: cn(
6353
- "fixed z-[var(--ds-z-popover)] w-64 pointer-events-none",
6354
- "bg-[var(--ds-bg-surface-elevated)]",
6355
- "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
6356
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
6357
- "rounded-[var(--ds-radius-md)]",
6358
- "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
6359
- "p-ds-3 space-y-ds-2"
6360
- ),
6361
- style: { top: pos.top, left: pos.left },
6362
- role: "tooltip",
6363
- children: [
6364
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-ds-2", children: [
6365
- /* @__PURE__ */ jsx("p", { className: "font-[var(--ds-weight-heading)] text-sm text-[var(--ds-text-primary)] leading-snug", children: event.title }),
6366
- category && /* @__PURE__ */ jsxs(Badge, { variant: "outline", size: "sm", className: "shrink-0", children: [
6367
- /* @__PURE__ */ jsx(
6368
- "span",
6369
- {
6370
- className: "inline-block w-1.5 h-1.5 rounded-[var(--ds-radius-full)] mr-ds-1",
6371
- style: { backgroundColor: color }
6372
- }
6373
- ),
6374
- category.label
6375
- ] })
6376
- ] }),
6377
- /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-secondary)]", children: event.allDay ? "All day" : formatTimeRange(event.start, event.end) }),
6378
- event.location && /* @__PURE__ */ jsxs("p", { className: "text-xs text-[var(--ds-text-muted)] flex items-center gap-ds-1", children: [
6379
- /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6380
- /* @__PURE__ */ jsx("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
6381
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "10", r: "3" })
6382
- ] }),
6383
- event.location
6384
- ] }),
6385
- event.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)] line-clamp-2", children: event.description })
6386
- ]
6552
+ className: cn("block w-full text-left text-xs leading-tight px-ds-1.5 py-ds-0.5 truncate", look, className),
6553
+ style: paint,
6554
+ children: event.title
6387
6555
  }
6388
- ),
6389
- document.body
6390
- );
6391
- }
6392
- function EventBar({ event, category, compact, onClick, className }) {
6393
- const [hovered, setHovered] = useState(false);
6394
- const barRef = useRef(null);
6395
- const hoverTimeout = useRef(void 0);
6396
- const color = category?.color ?? "var(--ds-accent-primary)";
6397
- const handleMouseEnter = () => {
6398
- hoverTimeout.current = setTimeout(() => setHovered(true), 300);
6399
- };
6400
- const handleMouseLeave = () => {
6401
- clearTimeout(hoverTimeout.current);
6402
- setHovered(false);
6403
- };
6556
+ );
6557
+ }
6404
6558
  if (compact) {
6405
6559
  return /* @__PURE__ */ jsx(
6406
6560
  "button",
6407
6561
  {
6408
- ref: barRef,
6409
- className: cn(
6410
- "w-1.5 h-1.5 rounded-[var(--ds-radius-full)] shrink-0 cursor-pointer",
6411
- className
6412
- ),
6413
- style: { backgroundColor: color },
6414
- onMouseEnter: handleMouseEnter,
6415
- onMouseLeave: handleMouseLeave,
6562
+ ref,
6563
+ type: "button",
6564
+ className: cn("w-1.5 h-1.5 rounded-[var(--ds-radius-full)] shrink-0 cursor-pointer", className),
6565
+ style: { backgroundColor: colours.edge },
6416
6566
  onClick: (e) => {
6417
6567
  e.stopPropagation();
6418
- onClick?.(event);
6568
+ onOpen?.(event, e.currentTarget);
6419
6569
  },
6420
- "aria-label": event.title,
6421
- children: /* @__PURE__ */ jsx(
6422
- EventPopover,
6423
- {
6424
- event,
6425
- category,
6426
- open: hovered,
6427
- anchorRef: barRef
6428
- }
6429
- )
6570
+ "aria-label": name
6430
6571
  }
6431
6572
  );
6432
6573
  }
6433
6574
  return /* @__PURE__ */ jsxs(
6434
6575
  "button",
6435
6576
  {
6436
- ref: barRef,
6577
+ ref,
6578
+ type: "button",
6579
+ "data-calendar-event": event.id,
6437
6580
  className: cn(
6438
- "w-full text-left text-xs leading-tight px-ds-1.5 py-ds-0.5 rounded-[var(--ds-radius-sm)]",
6439
- "truncate cursor-pointer transition-opacity hover:opacity-80",
6581
+ "w-full text-left text-xs leading-tight px-ds-1.5 py-ds-0.5",
6582
+ look,
6583
+ "truncate cursor-pointer transition-[filter] hover:brightness-95",
6440
6584
  "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
6441
6585
  className
6442
6586
  ),
6443
- style: {
6444
- backgroundColor: `color-mix(in oklch, ${color} 18%, transparent)`,
6445
- color,
6446
- borderLeft: `2px solid ${color}`
6447
- },
6448
- onMouseEnter: handleMouseEnter,
6449
- onMouseLeave: handleMouseLeave,
6587
+ style: paint,
6450
6588
  onClick: (e) => {
6451
6589
  e.stopPropagation();
6452
- onClick?.(event);
6590
+ onOpen?.(event, e.currentTarget);
6453
6591
  },
6454
- title: event.title,
6592
+ "aria-label": name,
6455
6593
  children: [
6456
- !event.allDay && /* @__PURE__ */ jsx("span", { className: "font-medium mr-ds-1 opacity-70", children: formatTime(event.start) }),
6457
- event.title,
6458
- /* @__PURE__ */ jsx(
6459
- EventPopover,
6460
- {
6461
- event,
6462
- category,
6463
- open: hovered,
6464
- anchorRef: barRef
6465
- }
6466
- )
6594
+ showTime && !event.allDay && /* @__PURE__ */ jsx("span", { className: "font-medium mr-ds-1", children: formatTime(event.start) }),
6595
+ event.title
6467
6596
  ]
6468
6597
  }
6469
6598
  );
6470
6599
  }
6471
- var MAX_VISIBLE_EVENTS = 3;
6472
- function OverflowPopover({
6473
- events,
6474
- categories,
6475
- date,
6476
- onEventClick
6477
- }) {
6478
- const [open, setOpen] = useState(false);
6479
- const triggerRef = useRef(null);
6480
- const floatingRef = useRef(null);
6481
- const pos = usePosition(triggerRef, floatingRef, open, {
6482
- side: "bottom",
6483
- align: "start",
6484
- offset: 4,
6485
- flip: true
6486
- });
6487
- const { isTop, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => setOpen(false), tabExits: "edges" });
6600
+ function eventName(event, category) {
6601
+ return [event.title, formatEventWhen(event, true), category?.label].filter(Boolean).join(", ");
6602
+ }
6603
+ var CALENDAR_LAYER = "data-calendar-layer";
6604
+ function EventCard({ event, category, anchor, actions, onClose, fallbackFocus }) {
6605
+ const anchorRef = useMemo(() => ({ current: anchor }), [anchor]);
6606
+ const panelRef = useRef(null);
6607
+ const titleId = useId();
6608
+ const pos = usePosition(anchorRef, panelRef, true, { side: "bottom", align: "start", offset: 4, flip: true });
6609
+ const { isTop, returnFocus } = usePopupFocus(true, { trigger: anchorRef, panel: panelRef, close: onClose, tabExits: "edges" });
6610
+ const colours = eventColours(category);
6611
+ const [attendeeScroll, setAttendeeScroll] = useState(null);
6612
+ useKeyboardScroll(attendeeScroll, "Attendees");
6613
+ const closeRef = useLatest(onClose);
6614
+ useEffect(() => {
6615
+ const raf = requestAnimationFrame(() => {
6616
+ const panel = panelRef.current;
6617
+ if (!panel) return;
6618
+ const actions2 = Array.from(panel.querySelectorAll("[data-card-action]"));
6619
+ const safe = actions2.find((el) => el.getAttribute("data-variant") !== "destructive");
6620
+ if (safe) safe.focus();
6621
+ else if (actions2.length) panel.focus();
6622
+ else focusInitial(panel);
6623
+ });
6624
+ return () => cancelAnimationFrame(raf);
6625
+ }, [anchor]);
6488
6626
  useEffect(() => {
6489
- if (!open) return;
6490
- const raf = requestAnimationFrame(() => focusInitial(floatingRef.current));
6491
6627
  const onKey = (e) => {
6492
6628
  if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
6493
6629
  e.preventDefault();
6494
6630
  returnFocus();
6495
- setOpen(false);
6631
+ closeRef.current();
6496
6632
  };
6497
6633
  const onDown = (e) => {
6498
- if (!triggerRef.current?.contains(e.target)) setOpen(false);
6634
+ if (!isTop()) return;
6635
+ const t = e.target;
6636
+ if (!(t instanceof Node) || panelRef.current?.contains(t) || anchor.contains(t)) return;
6637
+ if (t instanceof Element && t.closest(`[${CALENDAR_LAYER}]`)) return;
6638
+ closeRef.current();
6499
6639
  };
6500
6640
  document.addEventListener("keydown", onKey);
6501
- document.addEventListener("mousedown", onDown);
6641
+ document.addEventListener("pointerdown", onDown, true);
6502
6642
  return () => {
6503
- cancelAnimationFrame(raf);
6504
6643
  document.removeEventListener("keydown", onKey);
6505
- document.removeEventListener("mousedown", onDown);
6644
+ document.removeEventListener("pointerdown", onDown, true);
6506
6645
  };
6507
- }, [open, isTop, returnFocus]);
6508
- return /* @__PURE__ */ jsxs(Fragment, { children: [
6646
+ }, [anchor, isTop, returnFocus, closeRef]);
6647
+ const run = (action) => {
6648
+ const list = anchor.closest(`[${CALENDAR_LAYER}]`);
6649
+ returnFocus();
6650
+ onClose();
6651
+ action.onClick(event);
6652
+ requestAnimationFrame(() => {
6653
+ const now = document.activeElement;
6654
+ if (now && now !== document.body && now.isConnected) return;
6655
+ if (list?.isConnected && focusInitial(list)) return;
6656
+ fallbackFocus?.()?.focus();
6657
+ });
6658
+ };
6659
+ return createPortal(
6509
6660
  /* @__PURE__ */ jsxs(
6510
- "button",
6661
+ "div",
6511
6662
  {
6512
- ref: triggerRef,
6513
- "aria-haspopup": "dialog",
6514
- "aria-expanded": open,
6515
- className: "text-2xs text-[var(--ds-accent-primary)] font-medium cursor-pointer hover:underline px-ds-1.5",
6516
- onClick: (e) => {
6517
- e.stopPropagation();
6518
- setOpen(!open);
6519
- },
6663
+ ref: panelRef,
6664
+ role: "dialog",
6665
+ "aria-labelledby": titleId,
6666
+ ...{ [CALENDAR_LAYER]: "" },
6667
+ "data-calendar-card": event.id,
6668
+ tabIndex: -1,
6669
+ className: cn(
6670
+ "fixed z-[var(--ds-z-popover)] w-72 max-w-[calc(100vw-2*var(--ds-space-3))] outline-none",
6671
+ "bg-[var(--ds-bg-surface-elevated)]",
6672
+ "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
6673
+ "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
6674
+ "rounded-[var(--ds-radius-md)]",
6675
+ "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
6676
+ "p-ds-3 space-y-ds-2"
6677
+ ),
6678
+ style: { top: pos.top, left: pos.left },
6520
6679
  children: [
6521
- "+",
6522
- events.length,
6523
- " more"
6680
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-ds-2", children: [
6681
+ /* @__PURE__ */ jsx("h3", { id: titleId, className: "font-[var(--ds-weight-heading)] text-sm text-[var(--ds-text-primary)] leading-snug min-w-0 break-words", children: event.title }),
6682
+ /* @__PURE__ */ jsx(
6683
+ Button,
6684
+ {
6685
+ variant: "ghost",
6686
+ size: "icon-sm",
6687
+ "aria-label": "Close",
6688
+ ...{ [OVERLAY_CLOSE_ATTR]: "" },
6689
+ onClick: () => {
6690
+ returnFocus();
6691
+ onClose();
6692
+ },
6693
+ className: "-mt-ds-1 -mr-ds-1 shrink-0",
6694
+ children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 })
6695
+ }
6696
+ )
6697
+ ] }),
6698
+ category && /* @__PURE__ */ jsxs("p", { className: "inline-flex items-center gap-ds-1.5 text-xs text-[var(--ds-text-secondary)]", children: [
6699
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-block w-2 h-2 rounded-[var(--ds-radius-full)]", style: { backgroundColor: colours.edge } }),
6700
+ category.label
6701
+ ] }),
6702
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-[var(--ds-text-secondary)] tabular-nums", children: [
6703
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: formatEventWhen(event) }),
6704
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: formatEventWhen(event, true) })
6705
+ ] }),
6706
+ event.location && /* @__PURE__ */ jsxs("p", { className: "text-xs text-[var(--ds-text-secondary)] flex items-start gap-ds-1", children: [
6707
+ /* @__PURE__ */ jsx(Icon, { name: "map-pin", size: 14, className: "shrink-0 mt-px" }),
6708
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 break-words", children: event.location })
6709
+ ] }),
6710
+ event.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-secondary)] whitespace-pre-line break-words", children: event.description }),
6711
+ event.attendees && event.attendees.length > 0 && /* @__PURE__ */ jsx("div", { ref: setAttendeeScroll, className: "max-h-32 overflow-y-auto", children: /* @__PURE__ */ jsx("ul", { "aria-label": "Attendees", className: "space-y-ds-1", children: event.attendees.map((person, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-ds-2 text-xs text-[var(--ds-text-primary)]", children: [
6712
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "shrink-0", children: /* @__PURE__ */ jsx(Avatar, { size: "sm", initials: person.initials ?? person.name }) }),
6713
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: person.name })
6714
+ ] }, `${person.name}-${i}`)) }) }),
6715
+ actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-ds-2 pt-ds-1", children: actions.map((action) => /* @__PURE__ */ jsx(Button, { "data-card-action": "", size: "sm", variant: action.variant ?? "secondary", iconLeft: action.iconLeft, onClick: () => run(action), children: action.label }, action.label)) })
6524
6716
  ]
6525
6717
  }
6526
6718
  ),
6527
- open && createPortal(
6528
- /* @__PURE__ */ jsxs(
6529
- "div",
6530
- {
6531
- ref: floatingRef,
6532
- role: "dialog",
6533
- "aria-label": date.toLocaleDateString(void 0, { weekday: "long", month: "long", day: "numeric" }),
6534
- className: cn(
6535
- "fixed z-[var(--ds-z-popover)] w-56 max-h-48 overflow-y-auto",
6536
- "bg-[var(--ds-bg-surface-elevated)]",
6537
- "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
6538
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
6539
- "rounded-[var(--ds-radius-md)]",
6540
- "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
6541
- "p-ds-2 space-y-ds-1"
6542
- ),
6543
- style: { top: pos.top, left: pos.left },
6544
- onClick: (e) => e.stopPropagation(),
6545
- onMouseDown: (e) => e.stopPropagation(),
6546
- children: [
6547
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-1", children: date.toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" }) }),
6548
- events.map((event) => /* @__PURE__ */ jsx(
6549
- EventBar,
6550
- {
6551
- event,
6552
- category: categories[event.category ?? ""],
6553
- onClick: onEventClick
6554
- },
6555
- event.id
6556
- ))
6557
- ]
6558
- }
6559
- ),
6560
- document.body
6561
- )
6562
- ] });
6563
- }
6564
- function MonthView({
6565
- date,
6566
- events,
6567
- categories,
6568
- selectedDate,
6569
- onDayClick,
6570
- onEventClick,
6571
- weekStartsOn
6572
- }) {
6573
- const weeks = useMemo(
6574
- () => getMonthGrid(date.getFullYear(), date.getMonth(), weekStartsOn),
6575
- [date, weekStartsOn]
6719
+ document.body
6576
6720
  );
6577
- const dayNames = useMemo(() => getOrderedDayNames(weekStartsOn), [weekStartsOn]);
6578
- const currentMonth = date.getMonth();
6579
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
6580
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: dayNames.map((name) => /* @__PURE__ */ jsxs(
6721
+ }
6722
+ function DayList({ day, events, categories, anchor, onOpenEvent, onNewEvent, onClose }) {
6723
+ const anchorRef = useMemo(() => ({ current: anchor }), [anchor]);
6724
+ const panelRef = useRef(null);
6725
+ const pos = usePosition(anchorRef, panelRef, true, { side: "bottom", align: "start", offset: 4, flip: true });
6726
+ const { isTop, returnFocus } = usePopupFocus(true, { trigger: anchorRef, panel: panelRef, close: onClose, tabExits: "edges" });
6727
+ const closeRef = useLatest(onClose);
6728
+ useEffect(() => {
6729
+ const raf = requestAnimationFrame(() => focusInitial(panelRef.current));
6730
+ return () => cancelAnimationFrame(raf);
6731
+ }, [anchor]);
6732
+ useEffect(() => {
6733
+ const onKey = (e) => {
6734
+ if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
6735
+ e.preventDefault();
6736
+ returnFocus();
6737
+ closeRef.current();
6738
+ };
6739
+ const onDown = (e) => {
6740
+ if (!isTop()) return;
6741
+ const t = e.target;
6742
+ if (!(t instanceof Node) || panelRef.current?.contains(t) || anchor.contains(t)) return;
6743
+ if (t instanceof Element && t.closest(`[${CALENDAR_LAYER}]`)) return;
6744
+ closeRef.current();
6745
+ };
6746
+ document.addEventListener("keydown", onKey);
6747
+ document.addEventListener("pointerdown", onDown, true);
6748
+ return () => {
6749
+ document.removeEventListener("keydown", onKey);
6750
+ document.removeEventListener("pointerdown", onDown, true);
6751
+ };
6752
+ }, [anchor, isTop, returnFocus, closeRef]);
6753
+ return createPortal(
6754
+ /* @__PURE__ */ jsxs(
6581
6755
  "div",
6582
6756
  {
6583
- className: "text-center text-xs font-medium text-[var(--ds-text-muted)] py-ds-2 px-ds-1",
6757
+ ref: panelRef,
6758
+ role: "dialog",
6759
+ "aria-label": formatDayLong(day),
6760
+ ...{ [CALENDAR_LAYER]: "" },
6761
+ className: cn(
6762
+ "fixed z-[var(--ds-z-popover)] w-60 max-h-72 overflow-y-auto",
6763
+ "bg-[var(--ds-bg-surface-elevated)]",
6764
+ "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
6765
+ "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
6766
+ "rounded-[var(--ds-radius-md)]",
6767
+ "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
6768
+ "p-ds-2 space-y-ds-1"
6769
+ ),
6770
+ style: { top: pos.top, left: pos.left },
6771
+ onClick: (e) => e.stopPropagation(),
6584
6772
  children: [
6585
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: name }),
6586
- /* @__PURE__ */ jsx("span", { className: "sm:hidden", children: name[0] })
6773
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-1", children: formatDayShort(day) }),
6774
+ events.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-secondary)] px-ds-1", children: "No events" }),
6775
+ events.map((event) => /* @__PURE__ */ jsx(EventBar, { event, category: categories[event.category ?? ""], onOpen: onOpenEvent }, event.id)),
6776
+ onNewEvent && /* @__PURE__ */ jsx(
6777
+ Button,
6778
+ {
6779
+ variant: "ghost",
6780
+ size: "sm",
6781
+ iconLeft: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 14 }),
6782
+ className: "w-full justify-start mt-ds-1",
6783
+ onClick: () => {
6784
+ returnFocus();
6785
+ onClose();
6786
+ onNewEvent(day);
6787
+ },
6788
+ children: "New event"
6789
+ }
6790
+ )
6587
6791
  ]
6588
- },
6589
- name
6590
- )) }),
6591
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 flex-1 auto-rows-fr", children: weeks.map(
6592
- (week, wi) => week.map((day, di) => {
6593
- const dayEvents = getEventsForDay(events, day);
6594
- const isCurrentMonth = day.getMonth() === currentMonth;
6595
- const today = isToday(day);
6596
- const selected = selectedDate && isSameDay2(day, selectedDate);
6597
- const weekend = isWeekend(day);
6598
- const visibleEvents = dayEvents.slice(0, MAX_VISIBLE_EVENTS);
6599
- const overflowEvents = dayEvents.slice(MAX_VISIBLE_EVENTS);
6600
- const lastCol = di === 6;
6792
+ }
6793
+ ),
6794
+ document.body
6795
+ );
6796
+ }
6797
+
6798
+ // ../../showcase/src/components/Calendar/styles.ts
6799
+ var TODAY_CIRCLE = "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)] font-bold";
6800
+ var LANES = 3;
6801
+ var LANE_H = 20;
6802
+ var LANE_GAP = 4;
6803
+ var NUMBER_ROW = 30;
6804
+ var INSET = "var(--ds-space-1)";
6805
+ function MonthView({ date, events, categories, selectedDate, onDayClick, canStartEvent, onOpenEvent, onNavigate, weekStartsOn }) {
6806
+ const weeks = useMemo(() => getMonthGrid(date.getFullYear(), date.getMonth(), weekStartsOn), [date, weekStartsOn]);
6807
+ const phone = useBreakpoint("sm");
6808
+ const names = { short: weekdayNames(weekStartsOn, "short"), narrow: weekdayNames(weekStartsOn, "narrow"), long: weekdayNames(weekStartsOn, "long") };
6809
+ const layouts = useMemo(() => weeks.map((week) => layoutWeek(events, week, LANES)), [weeks, events]);
6810
+ const currentMonth = date.getMonth();
6811
+ const gridRef = useRef(null);
6812
+ const [list, setList] = useState(null);
6813
+ const inMonth = (d) => !!d && d.getMonth() === currentMonth && d.getFullYear() === date.getFullYear();
6814
+ const fallback = inMonth(selectedDate) ? selectedDate : inMonth(/* @__PURE__ */ new Date()) ? /* @__PURE__ */ new Date() : new Date(date.getFullYear(), currentMonth, 1);
6815
+ const [activeDay, setActiveDay] = useState(fallback);
6816
+ const active = inMonth(activeDay) ? activeDay : fallback;
6817
+ const openList = (day, anchor) => setList({ day, anchor });
6818
+ const choose = (day, anchor) => phone ? openList(day, anchor) : onDayClick(day);
6819
+ const grid = useGridKeyboard({
6820
+ container: gridRef,
6821
+ active,
6822
+ setActive: (d) => {
6823
+ setActiveDay(d);
6824
+ if (!inMonth(d)) onNavigate(d);
6825
+ },
6826
+ keyOf: dayKey,
6827
+ move: (from, e) => moveDay(from, e.key, e.shiftKey, weekStartsOn),
6828
+ onActivate: (day, e) => choose(day, e.currentTarget.querySelector(`[data-grid-key="${dayKey(day)}"]`) ?? e.target)
6829
+ });
6830
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
6831
+ /* @__PURE__ */ jsxs("div", { ref: gridRef, role: "grid", "aria-label": formatMonthYear(date), onKeyDown: grid.onKeyDown, className: "flex flex-col flex-1 min-h-0", children: [
6832
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: names.short.map((name, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": names.long[i], className: "text-center text-xs font-medium text-[var(--ds-text-muted)] py-ds-2 px-ds-1", children: phone ? names.narrow[i] : name }, i)) }),
6833
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col flex-1", children: weeks.map((week, wi) => {
6834
+ const layout = layouts[wi];
6601
6835
  const lastRow = wi === weeks.length - 1;
6602
- return /* @__PURE__ */ jsxs(
6603
- "div",
6604
- {
6605
- className: cn(
6606
- "min-h-[80px] sm:min-h-[100px] border-[var(--ds-border-subtle)]",
6607
- !lastRow && "border-b-[length:var(--ds-divider-width)]",
6608
- !lastCol && "border-r-[length:var(--ds-divider-width)]",
6609
- "p-ds-1 flex flex-col cursor-pointer transition-colors",
6610
- "hover:bg-[var(--ds-bg-muted)]",
6611
- !isCurrentMonth && "opacity-40",
6612
- selected && "bg-[var(--ds-accent-whisper)]",
6613
- weekend && isCurrentMonth && "bg-[var(--ds-bg-muted)]/30"
6614
- ),
6615
- onClick: () => onDayClick?.(day),
6616
- children: [
6617
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-ds-0.5", children: /* @__PURE__ */ jsx(
6618
- "span",
6619
- {
6620
- className: cn(
6621
- "text-xs w-6 h-6 flex items-center justify-center rounded-[var(--ds-radius-full)]",
6622
- today ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)] font-bold" : "text-[var(--ds-text-secondary)]"
6623
- ),
6624
- children: day.getDate()
6625
- }
6626
- ) }),
6627
- /* @__PURE__ */ jsxs("div", { className: "hidden sm:flex flex-col gap-ds-0.5 flex-1 overflow-hidden", children: [
6628
- visibleEvents.map((event) => /* @__PURE__ */ jsx(
6629
- EventBar,
6630
- {
6631
- event,
6632
- category: categories[event.category ?? ""],
6633
- onClick: onEventClick
6634
- },
6635
- event.id
6636
- )),
6637
- overflowEvents.length > 0 && /* @__PURE__ */ jsx(
6638
- OverflowPopover,
6639
- {
6640
- events: dayEvents,
6641
- categories,
6642
- date: day,
6643
- onEventClick
6644
- }
6645
- )
6646
- ] }),
6647
- /* @__PURE__ */ jsxs("div", { className: "flex sm:hidden gap-ds-0.5 flex-wrap mt-ds-0.5", children: [
6648
- dayEvents.slice(0, 4).map((event) => /* @__PURE__ */ jsx(
6649
- EventBar,
6650
- {
6651
- event,
6652
- category: categories[event.category ?? ""],
6653
- compact: true,
6654
- onClick: onEventClick
6655
- },
6656
- event.id
6657
- )),
6658
- dayEvents.length > 4 && /* @__PURE__ */ jsxs("span", { className: "text-2xs text-[var(--ds-text-muted)]", children: [
6659
- "+",
6660
- dayEvents.length - 4
6836
+ return /* @__PURE__ */ jsx("div", { role: "row", className: "relative grid grid-cols-7 flex-1", children: week.map((day, di) => {
6837
+ const dayEvents = getEventsForDay(events, day);
6838
+ const isCurrentMonth = day.getMonth() === currentMonth;
6839
+ const today = isToday(day);
6840
+ const selected = !!selectedDate && isSameDay(day, selectedDate);
6841
+ const weekend = isWeekend(day);
6842
+ const more = layout.more[di];
6843
+ const label = phone && dayEvents.length > 0 ? `${formatDayLong(day)}, ${dayEvents.length} ${dayEvents.length === 1 ? "event" : "events"}` : formatDayLong(day);
6844
+ return /* @__PURE__ */ jsxs(
6845
+ "div",
6846
+ {
6847
+ role: "gridcell",
6848
+ "data-grid-key": dayKey(day),
6849
+ tabIndex: grid.tabIndexOf(day),
6850
+ "aria-label": label,
6851
+ "aria-selected": selected,
6852
+ "aria-current": today ? "date" : void 0,
6853
+ onFocus: () => {
6854
+ if (!isSameDay(day, active)) setActiveDay(day);
6855
+ },
6856
+ onClick: (e) => choose(day, e.currentTarget),
6857
+ className: cn(
6858
+ "relative min-h-[80px] sm:min-h-[100px] border-[var(--ds-border-subtle)]",
6859
+ !lastRow && "border-b-[length:var(--ds-divider-width)]",
6860
+ di < 6 && "border-r-[length:var(--ds-divider-width)]",
6861
+ "p-ds-1 flex flex-col cursor-pointer transition-colors",
6862
+ FOCUS_INSET,
6863
+ "hover:bg-[var(--ds-bg-muted)]",
6864
+ !isCurrentMonth && "[&>.gs-day-number]:opacity-40",
6865
+ selected && "bg-[var(--ds-accent-whisper)]",
6866
+ weekend && isCurrentMonth && !selected && "bg-[var(--ds-bg-muted)]/30"
6867
+ ),
6868
+ children: [
6869
+ /* @__PURE__ */ jsx("span", { className: cn("gs-day-number text-xs w-6 h-6 flex items-center justify-center rounded-[var(--ds-radius-full)] shrink-0", today ? TODAY_CIRCLE : "text-[var(--ds-text-secondary)]"), children: day.getDate() }),
6870
+ phone ? (
6871
+ // dots, a day's presence of events: the day itself is what a tap opens (D46)
6872
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "flex gap-ds-0.5 flex-wrap mt-ds-0.5", children: [
6873
+ dayEvents.slice(0, 4).map((event) => /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-[var(--ds-radius-full)]", style: { backgroundColor: eventColours(categories[event.category ?? ""]).edge } }, event.id)),
6874
+ dayEvents.length > 4 && /* @__PURE__ */ jsxs("span", { className: "text-2xs text-[var(--ds-text-muted)] leading-none", children: [
6875
+ "+",
6876
+ dayEvents.length - 4
6877
+ ] })
6878
+ ] })
6879
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
6880
+ layout.segments.filter((s) => s.startCol === di).map((s) => /* @__PURE__ */ jsx(
6881
+ EventBar,
6882
+ {
6883
+ event: s.event,
6884
+ category: categories[s.event.category ?? ""],
6885
+ onOpen: onOpenEvent,
6886
+ continuesBefore: s.continuesBefore,
6887
+ continuesAfter: s.continuesAfter,
6888
+ className: "absolute z-[1] flex items-center",
6889
+ style: {
6890
+ top: NUMBER_ROW + s.lane * (LANE_H + LANE_GAP),
6891
+ height: LANE_H,
6892
+ left: s.continuesBefore ? 0 : INSET,
6893
+ width: `calc(${s.span} * (100% + var(--ds-divider-width)) - var(--ds-divider-width) - ${s.continuesBefore ? "0px" : INSET} - ${s.continuesAfter ? "0px" : INSET})`
6894
+ }
6895
+ },
6896
+ `${s.event.id}-${s.startCol}`
6897
+ )),
6898
+ more.length > 0 && /* @__PURE__ */ jsxs(
6899
+ "button",
6900
+ {
6901
+ type: "button",
6902
+ "aria-haspopup": "dialog",
6903
+ "aria-expanded": !!list && isSameDay(list.day, day),
6904
+ className: "absolute z-[1] text-2xs text-[var(--ds-accent-text,var(--ds-accent-primary))] font-medium cursor-pointer hover:underline px-ds-1.5 rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
6905
+ style: { top: NUMBER_ROW + (LANES - 1) * (LANE_H + LANE_GAP), left: INSET, height: LANE_H },
6906
+ onClick: (e) => {
6907
+ e.stopPropagation();
6908
+ openList(day, e.currentTarget);
6909
+ },
6910
+ children: [
6911
+ "+",
6912
+ more.length,
6913
+ " more"
6914
+ ]
6915
+ }
6916
+ )
6661
6917
  ] })
6662
- ] })
6663
- ]
6664
- },
6665
- `${wi}-${di}`
6666
- );
6667
- })
6668
- ) })
6918
+ ]
6919
+ },
6920
+ dayKey(day)
6921
+ );
6922
+ }) }, dayKey(week[0]));
6923
+ }) })
6924
+ ] }),
6925
+ list && /* @__PURE__ */ jsx(
6926
+ DayList,
6927
+ {
6928
+ day: list.day,
6929
+ events: getEventsForDay(events, list.day),
6930
+ categories,
6931
+ anchor: list.anchor,
6932
+ onOpenEvent,
6933
+ onNewEvent: phone && canStartEvent ? onDayClick : void 0,
6934
+ onClose: () => setList(null)
6935
+ }
6936
+ )
6669
6937
  ] });
6670
6938
  }
6671
6939
  var HOUR_HEIGHT = 40;
6672
6940
  var HOURS = Array.from({ length: 24 }, (_, i) => i);
6673
6941
  var GRID_HEIGHT = HOURS.length * HOUR_HEIGHT;
6674
- function formatHour(h) {
6675
- if (h === 0) return "12 AM";
6676
- if (h < 12) return `${h} AM`;
6677
- if (h === 12) return "12 PM";
6678
- return `${h - 12} PM`;
6679
- }
6680
- function CurrentTimeLine() {
6681
- const [now, setNow] = useState(/* @__PURE__ */ new Date());
6942
+ var MIN_EVENT_PX = 24;
6943
+ var MIN_EVENT_MINUTES = MIN_EVENT_PX / HOUR_HEIGHT * 60;
6944
+ var ALL_DAY_LANES = 3;
6945
+ var LANE_H2 = 20;
6946
+ var LANE_GAP2 = 4;
6947
+ var WORKING_DAY = 8;
6948
+ var HOUR_LABEL_ROOM = 8;
6949
+ var FADE = 24;
6950
+ var MIN_DAY_WIDTH = 100;
6951
+ var hh = (hour) => String(hour).padStart(2, "0");
6952
+ var cellKey = (day, hour) => hour === null ? dayKey(day) : `${dayKey(day)}T${hh(hour)}`;
6953
+ function parseKey(key) {
6954
+ const [d, h] = key.split("T");
6955
+ const [y, m, dd] = d.split("-").map(Number);
6956
+ return { day: new Date(y, m - 1, dd), hour: h === void 0 ? null : Number(h) };
6957
+ }
6958
+ function NowLine() {
6959
+ const [now, setNow] = useState(() => /* @__PURE__ */ new Date());
6682
6960
  useEffect(() => {
6683
6961
  const id = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
6684
6962
  return () => clearInterval(id);
6685
6963
  }, []);
6686
- const top = timeToFraction(now) * GRID_HEIGHT;
6687
- return /* @__PURE__ */ jsx(
6688
- "div",
6689
- {
6690
- className: "absolute left-0 right-0 z-10 pointer-events-none",
6691
- style: { top },
6692
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
6693
- /* @__PURE__ */ jsx("div", { className: "w-2 h-2 rounded-[var(--ds-radius-full)] bg-[var(--ds-status-error)] -ml-1" }),
6694
- /* @__PURE__ */ jsx("div", { className: "flex-1 h-[2px] bg-[var(--ds-status-error)]" })
6695
- ] })
6696
- }
6697
- );
6698
- }
6699
- function TimedEvent({
6700
- event,
6701
- category,
6702
- column,
6703
- totalColumns,
6704
- onEventClick
6705
- }) {
6706
- const start = new Date(event.start);
6707
- const end = event.end ? new Date(event.end) : new Date(start.getTime() + 60 * 6e4);
6708
- const top = timeToFraction(start) * GRID_HEIGHT;
6709
- const bottom = timeToFraction(end) * GRID_HEIGHT;
6710
- const height = Math.max(bottom - top, 20);
6711
- const color = category?.color ?? "var(--ds-accent-primary)";
6712
- const width = `calc(${100 / totalColumns}% - 2px)`;
6713
- const left = `calc(${column / totalColumns * 100}% + 1px)`;
6964
+ return /* @__PURE__ */ jsx("div", { "data-now-line": "", "aria-hidden": "true", className: "absolute left-0 right-0 z-[2] pointer-events-none", style: { top: timeToFraction(now) * GRID_HEIGHT }, children: /* @__PURE__ */ jsx("div", { className: "relative border-t-2 border-[var(--ds-accent-primary)]", children: /* @__PURE__ */ jsx("span", { className: "absolute -left-1 -top-[5px] box-border w-2 h-2 rounded-[var(--ds-radius-full)] border-4 border-[var(--ds-accent-primary)]" }) }) });
6965
+ }
6966
+ function TimedEvent({ placed, category, onOpen, onFocusEvent }) {
6967
+ const { piece, column, columns } = placed;
6968
+ const { event } = piece;
6969
+ const top = timeToFraction(piece.start) * GRID_HEIGHT;
6970
+ const bottom = piece.end.getHours() === 0 && piece.end.getMinutes() === 0 && piece.end > piece.start ? GRID_HEIGHT : timeToFraction(piece.end) * GRID_HEIGHT;
6971
+ const height = Math.max(bottom - top, MIN_EVENT_PX);
6972
+ const drawnTop = Math.min(top, GRID_HEIGHT - height);
6973
+ const colours = eventColours(category);
6974
+ const end = event.end && event.end > event.start ? event.end : void 0;
6975
+ const cutTop = piece.start > event.start;
6976
+ const cutBottom = !!end && piece.end < end;
6714
6977
  return /* @__PURE__ */ jsxs(
6715
- "div",
6978
+ "button",
6716
6979
  {
6980
+ type: "button",
6981
+ "data-calendar-event": event.id,
6982
+ "aria-label": eventName(event, category),
6717
6983
  className: cn(
6718
- "absolute rounded-[var(--ds-radius-sm)] px-ds-1.5 py-ds-1 text-xs leading-tight",
6719
- "flex flex-col items-start justify-start",
6720
- "overflow-hidden cursor-pointer transition-opacity hover:opacity-80",
6721
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
6984
+ // a short event keeps its title whole: no padding above and below it
6985
+ "absolute pointer-events-auto text-left px-ds-1.5 text-xs leading-tight",
6986
+ height > 30 ? "py-ds-1" : "py-0 justify-center",
6987
+ "flex flex-col items-start overflow-hidden cursor-pointer transition-[filter] hover:brightness-95",
6988
+ height > 30 && "justify-start",
6989
+ "border-[length:var(--ds-border-width)] border-solid rounded-[var(--ds-radius-sm)]",
6990
+ cutTop && "rounded-t-none border-t-0",
6991
+ cutBottom && "rounded-b-none border-b-0",
6992
+ "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)] focus-visible:z-[3]"
6722
6993
  ),
6723
6994
  style: {
6724
- top,
6995
+ top: drawnTop,
6725
6996
  height,
6726
- left,
6727
- width,
6728
- backgroundColor: `color-mix(in oklch, ${color} 20%, transparent)`,
6729
- color,
6730
- borderLeft: `2px solid ${color}`
6997
+ left: `calc(${column / columns * 100}% + 1px)`,
6998
+ width: `calc(${100 / columns}% - 2px)`,
6999
+ backgroundColor: colours.fill,
7000
+ color: colours.text,
7001
+ borderColor: colours.edge
6731
7002
  },
6732
7003
  onClick: (e) => {
6733
7004
  e.stopPropagation();
6734
- onEventClick?.(event);
7005
+ onOpen(event, e.currentTarget);
6735
7006
  },
6736
- title: event.title,
6737
- role: "button",
6738
- tabIndex: 0,
7007
+ onFocus: onFocusEvent,
6739
7008
  children: [
6740
- /* @__PURE__ */ jsx("div", { className: "font-medium truncate w-full", children: event.title }),
6741
- height > 30 && /* @__PURE__ */ jsxs("div", { className: "text-2xs opacity-70 truncate w-full", children: [
6742
- formatTime(start),
6743
- " \u2013 ",
6744
- formatTime(end)
6745
- ] })
7009
+ /* @__PURE__ */ jsx("span", { className: "font-medium truncate w-full", children: event.title }),
7010
+ height > 30 && /* @__PURE__ */ jsx("span", { className: "text-2xs truncate w-full tabular-nums", children: formatTimeRange(event.start, end) })
6746
7011
  ]
6747
7012
  }
6748
7013
  );
6749
7014
  }
6750
- function WeekView({
6751
- date,
6752
- events,
6753
- categories,
6754
- selectedDate,
6755
- onDayClick,
6756
- onEventClick,
6757
- weekStartsOn
6758
- }) {
7015
+ function WeekView({ date, events, categories, selectedDate, onDayClick, onOpenEvent, onNavigate, weekStartsOn }) {
6759
7016
  const days = useMemo(() => getWeekDays(date, weekStartsOn), [date, weekStartsOn]);
6760
- const allDayEvents = useMemo(() => {
6761
- return days.map(
6762
- (day) => getEventsForDay(events, day).filter((e) => e.allDay)
6763
- );
6764
- }, [days, events]);
6765
- const hasAllDay = allDayEvents.some((d) => d.length > 0);
6766
- const containerRef = useRef(null);
7017
+ const names = weekdayNames(weekStartsOn, "short");
7018
+ const barEvents = useMemo(() => events.filter(isBarEvent), [events]);
7019
+ const allDay = useMemo(() => layoutWeek(barEvents, days, ALL_DAY_LANES), [barEvents, days]);
7020
+ const pieces = useMemo(() => days.map((day) => layoutPieces(dayPieces(events, day), MIN_EVENT_MINUTES)), [days, events]);
7021
+ const allDayHeight = Math.max(28, 4 + allDay.lanes * (LANE_H2 + LANE_GAP2) + 2);
7022
+ const rootRef = useRef(null);
7023
+ const scrollerRef = useRef(null);
6767
7024
  const syncingScroll = useRef(false);
6768
7025
  const { ref: edgesRef, measure: measureEdges, fadeProps: edgeFade } = useScrollEdges();
7026
+ const [list, setList] = useState(null);
6769
7027
  const handleScroll = useCallback((e) => {
6770
7028
  if (syncingScroll.current) return;
6771
7029
  syncingScroll.current = true;
6772
7030
  const source = e.target;
6773
- const scrollLeft = source.scrollLeft;
6774
- const panels = containerRef.current?.querySelectorAll("[data-week-scroll]");
6775
- panels?.forEach((panel) => {
6776
- if (panel !== source) panel.scrollLeft = scrollLeft;
7031
+ rootRef.current?.querySelectorAll("[data-week-scroll]").forEach((panel) => {
7032
+ if (panel !== source) panel.scrollLeft = source.scrollLeft;
6777
7033
  });
6778
7034
  syncingScroll.current = false;
6779
7035
  }, []);
6780
7036
  useEffect(() => {
6781
- const container = containerRef.current;
6782
- if (!container) return;
6783
- const panels = container.querySelectorAll("[data-week-scroll]");
6784
- panels.forEach((panel) => panel.addEventListener("scroll", handleScroll));
6785
- return () => {
6786
- panels.forEach((panel) => panel.removeEventListener("scroll", handleScroll));
7037
+ const panels = rootRef.current?.querySelectorAll("[data-week-scroll]");
7038
+ panels?.forEach((panel) => panel.addEventListener("scroll", handleScroll));
7039
+ return () => panels?.forEach((panel) => panel.removeEventListener("scroll", handleScroll));
7040
+ }, [handleScroll]);
7041
+ const starts = pieces.flat().filter((p) => p.piece.start.getTime() === p.piece.event.start.getTime()).map((p) => p.piece.start.getHours() + p.piece.start.getMinutes() / 60);
7042
+ const earliest = Math.floor(Math.min(WORKING_DAY, ...starts));
7043
+ const topOf = (hour) => Math.max(0, hour * HOUR_HEIGHT - HOUR_LABEL_ROOM);
7044
+ const openingHourRef = useLatest(earliest);
7045
+ const opened = useRef(null);
7046
+ const week = dayKey(days[0]);
7047
+ const weekRef = useLatest(week);
7048
+ const [openingHour] = useState(earliest);
7049
+ useLayoutEffect(() => {
7050
+ const scroller = scrollerRef.current;
7051
+ if (!scroller) return;
7052
+ let done = false;
7053
+ const open = () => {
7054
+ if (done || scroller.scrollHeight <= scroller.clientHeight + 1) return;
7055
+ done = true;
7056
+ scroller.scrollTo({ top: topOf(openingHourRef.current) });
7057
+ opened.current = { top: scroller.scrollTop, week: weekRef.current };
6787
7058
  };
6788
- }, [handleScroll, hasAllDay]);
6789
- const MIN_DAY_WIDTH = 100;
6790
- const dayGridColumns = `repeat(${days.length}, minmax(${MIN_DAY_WIDTH}px, 1fr))`;
6791
- return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "flex flex-col h-full overflow-hidden", children: [
6792
- /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: [
6793
- /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]" }),
6794
- /* @__PURE__ */ jsx("div", { ref: edgesRef, onScroll: measureEdges, ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
6795
- "div",
6796
- {
6797
- className: "grid",
6798
- style: { gridTemplateColumns: dayGridColumns, minWidth: MIN_DAY_WIDTH * days.length },
6799
- children: days.map((day, i) => {
6800
- const today = isToday(day);
6801
- const selected = selectedDate && isSameDay2(day, selectedDate);
6802
- return /* @__PURE__ */ jsxs(
6803
- "div",
6804
- {
6805
- className: cn(
6806
- "text-center py-ds-2 cursor-pointer transition-colors",
6807
- "hover:bg-[var(--ds-bg-muted)]",
6808
- i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]",
6809
- selected && "bg-[var(--ds-accent-whisper)]"
6810
- ),
6811
- onClick: () => onDayClick?.(day),
6812
- children: [
6813
- /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] font-medium", children: day.toLocaleDateString(void 0, { weekday: "short" }) }),
6814
- /* @__PURE__ */ jsx(
6815
- "div",
6816
- {
6817
- className: cn(
6818
- "text-lg font-semibold mt-ds-0.5 mx-auto w-8 h-8 flex items-center justify-center rounded-[var(--ds-radius-full)]",
6819
- today ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-primary)]"
6820
- ),
6821
- children: day.getDate()
6822
- }
6823
- )
6824
- ]
6825
- },
6826
- i
6827
- );
6828
- })
6829
- }
6830
- ) })
7059
+ open();
7060
+ if (done || typeof ResizeObserver === "undefined") return;
7061
+ const ro = new ResizeObserver(() => {
7062
+ open();
7063
+ if (done) ro.disconnect();
7064
+ });
7065
+ ro.observe(scroller);
7066
+ return () => ro.disconnect();
7067
+ }, [openingHour, openingHourRef, weekRef]);
7068
+ useLayoutEffect(() => {
7069
+ const scroller = scrollerRef.current;
7070
+ const o = opened.current;
7071
+ if (!scroller || !o || o.week !== week) return;
7072
+ if (Math.abs(scroller.scrollTop - o.top) > 1) {
7073
+ opened.current = null;
7074
+ return;
7075
+ }
7076
+ if (topOf(earliest) >= o.top) return;
7077
+ scroller.scrollTo({ top: topOf(earliest) });
7078
+ opened.current = { top: scroller.scrollTop, week };
7079
+ }, [earliest, week]);
7080
+ const inWeek = (d) => days.some((day) => isSameDay(day, d));
7081
+ const anchorDay = selectedDate && inWeek(selectedDate) ? selectedDate : days.find(isToday) ?? days[0];
7082
+ const [activeKey, setActiveKey] = useState(() => cellKey(anchorDay, openingHour));
7083
+ const active = inWeek(parseKey(activeKey).day) ? activeKey : cellKey(anchorDay, parseKey(activeKey).hour);
7084
+ const firstVisibleHour = () => Math.min(23, Math.ceil((scrollerRef.current?.scrollTop ?? 0) / HOUR_HEIGHT));
7085
+ const placeInView = (_key, el) => {
7086
+ const scroller = scrollerRef.current;
7087
+ if (scroller && scroller.contains(el) && scroller.scrollHeight > scroller.clientHeight + 1) {
7088
+ const top = el.offsetTop;
7089
+ if (top < scroller.scrollTop) scroller.scrollTop = top;
7090
+ else if (top + el.offsetHeight > scroller.scrollTop + scroller.clientHeight) scroller.scrollTop = top + el.offsetHeight - scroller.clientHeight;
7091
+ } else {
7092
+ el.scrollIntoView?.({ block: "nearest", inline: "nearest" });
7093
+ }
7094
+ const strip = el.closest("[data-week-scroll]");
7095
+ if (strip) {
7096
+ const cell = el.getBoundingClientRect();
7097
+ const box = strip.getBoundingClientRect();
7098
+ if (cell.left - FADE < box.left) strip.scrollLeft -= box.left - (cell.left - FADE);
7099
+ else if (cell.right + FADE > box.right) strip.scrollLeft += cell.right + FADE - box.right;
7100
+ }
7101
+ };
7102
+ const grid = useGridKeyboard({
7103
+ container: rootRef,
7104
+ active,
7105
+ setActive: (key) => {
7106
+ setActiveKey(key);
7107
+ const { day } = parseKey(key);
7108
+ if (!inWeek(day)) onNavigate(day);
7109
+ },
7110
+ keyOf: (key) => key,
7111
+ move: (from, e) => {
7112
+ const { day, hour } = parseKey(from);
7113
+ const col = days.findIndex((d) => isSameDay(d, day));
7114
+ switch (e.key) {
7115
+ case "ArrowUp":
7116
+ return hour === null ? from : hour === 0 ? cellKey(day, null) : cellKey(day, hour - 1);
7117
+ case "ArrowDown":
7118
+ return hour === null ? cellKey(day, firstVisibleHour()) : cellKey(day, Math.min(23, hour + 1));
7119
+ case "ArrowLeft":
7120
+ return col > 0 ? cellKey(days[col - 1], hour) : from;
7121
+ case "ArrowRight":
7122
+ return col >= 0 && col < days.length - 1 ? cellKey(days[col + 1], hour) : from;
7123
+ case "Home":
7124
+ return cellKey(days[0], hour);
7125
+ case "End":
7126
+ return cellKey(days[days.length - 1], hour);
7127
+ case "PageUp":
7128
+ return cellKey(addDays2(day, -7), hour);
7129
+ case "PageDown":
7130
+ return cellKey(addDays2(day, 7), hour);
7131
+ default:
7132
+ return null;
7133
+ }
7134
+ },
7135
+ onActivate: (key) => {
7136
+ const { day, hour } = parseKey(key);
7137
+ onDayClick(day, hour === null ? void 0 : { time: `${hh(hour)}:00` });
7138
+ },
7139
+ scrollIntoView: placeInView
7140
+ });
7141
+ const dayGridColumns = `repeat(${days.length}, minmax(${MIN_DAY_WIDTH}px, 1fr))`;
7142
+ const stripWidth = MIN_DAY_WIDTH * days.length;
7143
+ const chooseHour = (day, hour) => (e) => {
7144
+ const minutes = e.nativeEvent.offsetY >= HOUR_HEIGHT / 2 ? 30 : 0;
7145
+ onDayClick(day, { time: `${hh(hour)}:${minutes === 30 ? "30" : "00"}` });
7146
+ };
7147
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "flex flex-col h-full overflow-hidden", onKeyDown: grid.onKeyDown, children: [
7148
+ /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: [
7149
+ /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]" }),
7150
+ /* @__PURE__ */ jsx("div", { ref: edgesRef, onScroll: measureEdges, ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx("div", { className: "grid", style: { gridTemplateColumns: dayGridColumns, minWidth: stripWidth }, children: days.map((day, i) => /* @__PURE__ */ jsxs("div", { className: cn("text-center py-ds-2", i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", selectedDate && isSameDay(day, selectedDate) && "bg-[var(--ds-accent-whisper)]"), children: [
7151
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] font-medium", children: names[i] }),
7152
+ /* @__PURE__ */ jsx("div", { className: cn("text-lg font-semibold mt-ds-0.5 mx-auto w-8 h-8 flex items-center justify-center rounded-[var(--ds-radius-full)]", isToday(day) ? TODAY_CIRCLE : "text-[var(--ds-text-primary)]"), children: day.getDate() })
7153
+ ] }, i)) }) })
6831
7154
  ] }),
6832
- hasAllDay && /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]/30", children: [
7155
+ /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]/30", children: [
6833
7156
  /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-2xs text-[var(--ds-text-muted)] px-ds-1 py-ds-1 text-right", children: "all-day" }),
6834
- /* @__PURE__ */ jsx("div", { ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
6835
- "div",
6836
- {
6837
- className: "grid",
6838
- style: { gridTemplateColumns: dayGridColumns, minWidth: MIN_DAY_WIDTH * days.length },
6839
- children: allDayEvents.map((dayEvts, i) => /* @__PURE__ */ jsx(
6840
- "div",
6841
- {
6842
- className: cn(
6843
- "p-ds-0.5 space-y-ds-0.5 min-h-[28px]",
6844
- i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]"
6845
- ),
6846
- children: dayEvts.map((event) => /* @__PURE__ */ jsx(
7157
+ /* @__PURE__ */ jsx("div", { ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx("div", { role: "grid", "aria-label": "All day", "aria-readonly": "true", style: { minWidth: stripWidth }, children: /* @__PURE__ */ jsx("div", { role: "row", className: "grid", style: { gridTemplateColumns: dayGridColumns, height: allDayHeight }, children: days.map((day, i) => {
7158
+ const key = cellKey(day, null);
7159
+ const more = allDay.more[i];
7160
+ return /* @__PURE__ */ jsxs(
7161
+ "div",
7162
+ {
7163
+ role: "gridcell",
7164
+ "data-grid-key": key,
7165
+ tabIndex: grid.tabIndexOf(key),
7166
+ "aria-label": `${formatDayLong(day)}, all day`,
7167
+ onFocus: () => {
7168
+ if (active !== key) setActiveKey(key);
7169
+ },
7170
+ onClick: () => onDayClick(day),
7171
+ className: cn("relative cursor-pointer", FOCUS_INSET, i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]"),
7172
+ children: [
7173
+ allDay.segments.filter((s) => s.startCol === i).map((s) => /* @__PURE__ */ jsx(
6847
7174
  EventBar,
6848
7175
  {
6849
- event,
6850
- category: categories[event.category ?? ""],
6851
- onClick: onEventClick
7176
+ event: s.event,
7177
+ category: categories[s.event.category ?? ""],
7178
+ onOpen: onOpenEvent,
7179
+ continuesBefore: s.continuesBefore,
7180
+ continuesAfter: s.continuesAfter,
7181
+ className: "absolute z-[1] flex items-center",
7182
+ style: {
7183
+ top: 2 + s.lane * (LANE_H2 + LANE_GAP2),
7184
+ height: LANE_H2,
7185
+ left: s.continuesBefore ? 0 : 2,
7186
+ width: `calc(${s.span} * (100% + var(--ds-divider-width)) - var(--ds-divider-width) - ${s.continuesBefore ? 0 : 2}px - ${s.continuesAfter ? 0 : 2}px)`
7187
+ }
6852
7188
  },
6853
- event.id
6854
- ))
7189
+ `${s.event.id}-${s.startCol}`
7190
+ )),
7191
+ more.length > 0 && /* @__PURE__ */ jsxs(
7192
+ "button",
7193
+ {
7194
+ type: "button",
7195
+ "aria-haspopup": "dialog",
7196
+ "aria-expanded": !!list && isSameDay(list.day, day),
7197
+ className: "absolute z-[1] text-2xs text-[var(--ds-accent-text,var(--ds-accent-primary))] font-medium cursor-pointer hover:underline px-ds-1.5 rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7198
+ style: { top: 2 + (ALL_DAY_LANES - 1) * (LANE_H2 + LANE_GAP2), left: 2, height: LANE_H2 },
7199
+ onClick: (e) => {
7200
+ e.stopPropagation();
7201
+ setList({ day, anchor: e.currentTarget });
7202
+ },
7203
+ children: [
7204
+ "+",
7205
+ more.length,
7206
+ " more"
7207
+ ]
7208
+ }
7209
+ )
7210
+ ]
7211
+ },
7212
+ i
7213
+ );
7214
+ }) }) }) })
7215
+ ] }),
7216
+ /* @__PURE__ */ jsxs("div", { ref: scrollerRef, className: "flex flex-1 min-h-0 overflow-y-auto", "data-week-hours": "", children: [
7217
+ /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 relative border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", style: { height: GRID_HEIGHT }, "aria-hidden": "true", children: HOURS.map((h) => /* @__PURE__ */ jsx("div", { className: "absolute right-0 pr-ds-2 text-2xs text-[var(--ds-text-muted)] -translate-y-1/2 tabular-nums", style: { top: h * HOUR_HEIGHT }, children: h > 0 && formatHourLabel(h) }, h)) }),
7218
+ /* @__PURE__ */ jsx("div", { ...edgeFade, className: "flex-1 self-start overflow-x-auto overflow-y-hidden gs-scrollbar-none", style: { height: GRID_HEIGHT }, "data-week-scroll": true, children: /* @__PURE__ */ jsxs("div", { className: "relative", style: { height: GRID_HEIGHT, minWidth: stripWidth }, children: [
7219
+ /* @__PURE__ */ jsx("div", { role: "grid", "aria-label": formatWeekRange(date, weekStartsOn), "aria-readonly": "true", className: "absolute inset-0", children: HOURS.map((hour) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid", style: { gridTemplateColumns: dayGridColumns, height: HOUR_HEIGHT }, children: days.map((day, i) => {
7220
+ const key = cellKey(day, hour);
7221
+ return /* @__PURE__ */ jsx(
7222
+ "div",
7223
+ {
7224
+ role: "gridcell",
7225
+ "data-grid-key": key,
7226
+ tabIndex: grid.tabIndexOf(key),
7227
+ "aria-label": `${formatDayLong(day)}, ${formatTime(new Date(day.getFullYear(), day.getMonth(), day.getDate(), hour))}`,
7228
+ onFocus: () => {
7229
+ if (active !== key) setActiveKey(key);
7230
+ },
7231
+ onClick: chooseHour(day, hour),
7232
+ className: cn(
7233
+ "cursor-pointer border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] hover:bg-[var(--ds-bg-muted)]/40",
7234
+ FOCUS_INSET,
7235
+ i > 0 && "border-l-[length:var(--ds-divider-width)]"
7236
+ )
6855
7237
  },
6856
7238
  i
7239
+ );
7240
+ }) }, hour)) }),
7241
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 grid pointer-events-none", style: { gridTemplateColumns: dayGridColumns }, children: days.map((day, i) => /* @__PURE__ */ jsxs("div", { className: "relative", children: [
7242
+ isToday(day) && /* @__PURE__ */ jsx(NowLine, {}),
7243
+ pieces[i].map((placed) => /* @__PURE__ */ jsx(
7244
+ TimedEvent,
7245
+ {
7246
+ placed,
7247
+ category: categories[placed.piece.event.category ?? ""],
7248
+ onOpen: onOpenEvent,
7249
+ onFocusEvent: () => setActiveKey(cellKey(day, placed.piece.start.getHours()))
7250
+ },
7251
+ `${placed.piece.event.id}-${i}`
6857
7252
  ))
6858
- }
6859
- ) })
7253
+ ] }, i)) })
7254
+ ] }) })
6860
7255
  ] }),
6861
- /* @__PURE__ */ jsxs("div", { className: "flex flex-1 min-h-0 overflow-y-auto", children: [
6862
- /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 relative border-r-[length:var(--ds-divider-width)] border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", style: { height: GRID_HEIGHT }, children: HOURS.map((h) => /* @__PURE__ */ jsx(
6863
- "div",
6864
- {
6865
- className: "absolute right-0 pr-ds-2 text-2xs text-[var(--ds-text-muted)] -translate-y-1/2",
6866
- style: { top: h * HOUR_HEIGHT },
6867
- children: h > 0 && formatHour(h)
6868
- },
6869
- h
6870
- )) }),
6871
- /* @__PURE__ */ jsx("div", { ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
6872
- "div",
6873
- {
6874
- className: "relative",
6875
- style: { height: GRID_HEIGHT, minWidth: MIN_DAY_WIDTH * days.length },
6876
- children: /* @__PURE__ */ jsx(
6877
- "div",
6878
- {
6879
- className: "grid h-full",
6880
- style: { gridTemplateColumns: dayGridColumns },
6881
- children: days.map((day, i) => {
6882
- const dayEvents = getEventsForDay(events, day).filter((e) => !e.allDay);
6883
- const layout = getOverlappingGroups(dayEvents);
6884
- const today = isToday(day);
6885
- return /* @__PURE__ */ jsxs(
6886
- "div",
6887
- {
6888
- className: cn(
6889
- "relative",
6890
- i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]"
6891
- ),
6892
- onClick: () => onDayClick?.(day),
6893
- children: [
6894
- HOURS.map((h) => /* @__PURE__ */ jsx(
6895
- "div",
6896
- {
6897
- className: "absolute left-0 right-0 border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]",
6898
- style: { top: h * HOUR_HEIGHT }
6899
- },
6900
- h
6901
- )),
6902
- today && /* @__PURE__ */ jsx(CurrentTimeLine, {}),
6903
- layout.map(({ event, column, totalColumns }) => /* @__PURE__ */ jsx(
6904
- TimedEvent,
6905
- {
6906
- event,
6907
- category: categories[event.category ?? ""],
6908
- column,
6909
- totalColumns,
6910
- onEventClick
6911
- },
6912
- event.id
6913
- ))
6914
- ]
6915
- },
6916
- i
6917
- );
6918
- })
6919
- }
6920
- )
6921
- }
6922
- ) })
6923
- ] })
7256
+ list && /* @__PURE__ */ jsx(DayList, { day: list.day, events: getEventsForDay(barEvents, list.day), categories, anchor: list.anchor, onOpenEvent, onClose: () => setList(null) })
6924
7257
  ] });
6925
7258
  }
6926
7259
  var WEEKS_SHOWN = 6;
@@ -6931,7 +7264,6 @@ function DayCellWithPopover({
6931
7264
  events,
6932
7265
  categories,
6933
7266
  selectedDate,
6934
- onEventClick,
6935
7267
  isEvenRow
6936
7268
  }) {
6937
7269
  const [open, setOpen] = useState(false);
@@ -6947,7 +7279,7 @@ function DayCellWithPopover({
6947
7279
  const inMonth = day.getMonth() === month;
6948
7280
  const dayEvents = inMonth ? getEventsForDay(events, day) : [];
6949
7281
  const today = inMonth && isToday(day);
6950
- const selected = inMonth && selectedDate && isSameDay2(day, selectedDate);
7282
+ const selected = inMonth && selectedDate && isSameDay(day, selectedDate);
6951
7283
  const hasEvents = dayEvents.length > 0;
6952
7284
  const handleMouseEnter = () => {
6953
7285
  if (!hasEvents) return;
@@ -6969,7 +7301,6 @@ function DayCellWithPopover({
6969
7301
  inMonth && "cursor-pointer hover:bg-[var(--ds-bg-muted)]",
6970
7302
  !inMonth && "bg-[var(--ds-bg-muted)]/40",
6971
7303
  inMonth && isEvenRow && !today && !selected && "bg-[var(--ds-bg-muted)]/20",
6972
- today && "bg-[var(--ds-accent-subtle)]",
6973
7304
  selected && !today && "bg-[var(--ds-accent-whisper)]"
6974
7305
  ),
6975
7306
  children: [
@@ -6979,7 +7310,7 @@ function DayCellWithPopover({
6979
7310
  {
6980
7311
  className: cn(
6981
7312
  "text-2xs leading-none z-[1]",
6982
- today ? "font-bold text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-secondary)]"
7313
+ today ? cn("w-5 h-5 inline-flex items-center justify-center rounded-[var(--ds-radius-full)]", TODAY_CIRCLE) : "text-[var(--ds-text-secondary)]"
6983
7314
  ),
6984
7315
  children: day.getDate()
6985
7316
  }
@@ -7003,16 +7334,8 @@ function DayCellWithPopover({
7003
7334
  style: { top: pos.top, left: pos.left },
7004
7335
  role: "tooltip",
7005
7336
  children: [
7006
- /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-0.5", children: day.toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" }) }),
7007
- dayEvents.map((event) => /* @__PURE__ */ jsx(
7008
- EventBar,
7009
- {
7010
- event,
7011
- category: categories[event.category ?? ""],
7012
- onClick: onEventClick
7013
- },
7014
- event.id
7015
- ))
7337
+ /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-0.5", children: formatDayShort(day) }),
7338
+ dayEvents.map((event) => /* @__PURE__ */ jsx(EventBar, { event, category: categories[event.category ?? ""], inert: true }, event.id))
7016
7339
  ]
7017
7340
  }
7018
7341
  ),
@@ -7029,7 +7352,6 @@ function MonthRow({
7029
7352
  categories,
7030
7353
  selectedDate,
7031
7354
  onClick,
7032
- onEventClick,
7033
7355
  weekStartsOn
7034
7356
  }) {
7035
7357
  const grid = useMemo(
@@ -7047,7 +7369,7 @@ function MonthRow({
7047
7369
  "border-r-[length:var(--ds-divider-width)] border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]"
7048
7370
  ),
7049
7371
  onClick,
7050
- children: MONTH_NAMES_SHORT[month]
7372
+ children: monthName(month, "short")
7051
7373
  }
7052
7374
  ),
7053
7375
  flat.map((day, i) => /* @__PURE__ */ jsx(
@@ -7058,7 +7380,6 @@ function MonthRow({
7058
7380
  events,
7059
7381
  categories,
7060
7382
  selectedDate,
7061
- onEventClick,
7062
7383
  isEvenRow: month % 2 === 0
7063
7384
  },
7064
7385
  i
@@ -7071,11 +7392,10 @@ function YearView({
7071
7392
  categories,
7072
7393
  selectedDate,
7073
7394
  onMonthClick,
7074
- onEventClick,
7075
7395
  weekStartsOn
7076
7396
  }) {
7077
7397
  const year = date.getFullYear();
7078
- const dayNames = useMemo(() => getOrderedDayNames(weekStartsOn), [weekStartsOn]);
7398
+ const dayNames = weekdayNames(weekStartsOn, "narrow");
7079
7399
  const repeatedHeaders = useMemo(() => {
7080
7400
  const headers = [];
7081
7401
  for (let w = 0; w < WEEKS_SHOWN; w++) {
@@ -7090,7 +7410,7 @@ function YearView({
7090
7410
  {
7091
7411
  className: "grid min-w-[700px]",
7092
7412
  style: {
7093
- gridTemplateColumns: `48px repeat(${COLS}, minmax(22px, 1fr))`,
7413
+ gridTemplateColumns: `48px repeat(${COLS}, minmax(24px, 1fr))`,
7094
7414
  gridTemplateRows: `auto repeat(12, 36px)`
7095
7415
  },
7096
7416
  children: [
@@ -7103,7 +7423,7 @@ function YearView({
7103
7423
  "bg-[var(--ds-bg-muted)] border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]",
7104
7424
  h.isWeekStart && "border-l-[length:var(--ds-divider-width)]"
7105
7425
  ),
7106
- children: h.label[0]
7426
+ children: h.label
7107
7427
  },
7108
7428
  i
7109
7429
  )),
@@ -7116,7 +7436,6 @@ function YearView({
7116
7436
  categories,
7117
7437
  selectedDate,
7118
7438
  onClick: () => onMonthClick(month),
7119
- onEventClick,
7120
7439
  weekStartsOn
7121
7440
  },
7122
7441
  month
@@ -7125,191 +7444,83 @@ function YearView({
7125
7444
  }
7126
7445
  ) });
7127
7446
  }
7128
- function CompactDayCell({
7129
- day,
7130
- isCurrentMonth,
7131
- events,
7132
- categories,
7133
- selectedDate,
7134
- onDayClick,
7135
- onEventClick
7136
- }) {
7137
- const [open, setOpen] = useState(false);
7138
- const cellRef = useRef(null);
7139
- const floatingRef = useRef(null);
7140
- const pos = usePosition(cellRef, floatingRef, open, {
7141
- side: "bottom",
7142
- align: "center",
7143
- offset: 4,
7144
- flip: true
7447
+ function CompactMonthView({ date, events, categories, selectedDate, onDayClick, onOpenEvent, onNavigate, weekStartsOn }) {
7448
+ const weeks = useMemo(() => getMonthGrid(date.getFullYear(), date.getMonth(), weekStartsOn), [date, weekStartsOn]);
7449
+ const names = { narrow: weekdayNames(weekStartsOn, "narrow"), long: weekdayNames(weekStartsOn, "long") };
7450
+ const currentMonth = date.getMonth();
7451
+ const gridRef = useRef(null);
7452
+ const [list, setList] = useState(null);
7453
+ const inMonth = (d) => !!d && d.getMonth() === currentMonth && d.getFullYear() === date.getFullYear();
7454
+ const fallback = inMonth(selectedDate) ? selectedDate : inMonth(/* @__PURE__ */ new Date()) ? /* @__PURE__ */ new Date() : new Date(date.getFullYear(), currentMonth, 1);
7455
+ const [activeDay, setActiveDay] = useState(fallback);
7456
+ const active = inMonth(activeDay) ? activeDay : fallback;
7457
+ const grid = useGridKeyboard({
7458
+ container: gridRef,
7459
+ active,
7460
+ setActive: (d) => {
7461
+ setActiveDay(d);
7462
+ if (!inMonth(d)) onNavigate(d);
7463
+ },
7464
+ keyOf: dayKey,
7465
+ move: (from, e) => moveDay(from, e.key, e.shiftKey, weekStartsOn)
7145
7466
  });
7146
- const hoverTimeout = useRef(void 0);
7147
- const dayEvents = isCurrentMonth ? getEventsForDay(events, day) : [];
7148
- const today = isCurrentMonth && isToday(day);
7149
- const selected = isCurrentMonth && selectedDate && isSameDay2(day, selectedDate);
7150
- const hasEvents = dayEvents.length > 0;
7151
- const shown = open && hasEvents;
7152
- const isTop = useOverlayLayer(shown);
7153
- useCloseOnFocusOut(shown, cellRef, floatingRef, () => setOpen(false), isTop);
7154
- const eventColors = dayEvents.slice(0, 3).map((e) => categories[e.category ?? ""]?.color ?? "var(--ds-accent-primary)");
7155
- const handleMouseEnter = () => {
7156
- if (!hasEvents) return;
7157
- hoverTimeout.current = setTimeout(() => setOpen(true), 250);
7158
- };
7159
- const handleMouseLeave = () => {
7160
- clearTimeout(hoverTimeout.current);
7161
- setOpen(false);
7162
- };
7163
- const handleClick = () => {
7164
- onDayClick?.(day);
7165
- if (hasEvents) {
7166
- setOpen((prev) => !prev);
7167
- }
7168
- };
7169
- useEffect(() => {
7170
- if (!open) return;
7171
- const onKey = (e) => {
7172
- if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
7173
- e.preventDefault();
7174
- setOpen(false);
7175
- };
7176
- const onClick = (e) => {
7177
- const t = e.target;
7178
- if (cellRef.current?.contains(t) || floatingRef.current?.contains(t)) return;
7179
- setOpen(false);
7180
- };
7181
- document.addEventListener("keydown", onKey);
7182
- document.addEventListener("mousedown", onClick);
7183
- return () => {
7184
- document.removeEventListener("keydown", onKey);
7185
- document.removeEventListener("mousedown", onClick);
7186
- };
7187
- }, [open, isTop]);
7188
- return /* @__PURE__ */ jsxs(Fragment, { children: [
7189
- /* @__PURE__ */ jsxs(
7190
- "button",
7191
- {
7192
- ref: cellRef,
7193
- type: "button",
7194
- onClick: handleClick,
7195
- onMouseEnter: handleMouseEnter,
7196
- onMouseLeave: handleMouseLeave,
7197
- className: cn(
7198
- "flex flex-col items-center justify-center py-ds-1.5 rounded-[var(--ds-radius-sm)] cursor-pointer transition-colors",
7199
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7200
- !isCurrentMonth && "opacity-30",
7201
- selected && "bg-[var(--ds-accent-subtle)]",
7202
- !selected && "hover:bg-[var(--ds-bg-muted)]"
7203
- ),
7204
- children: [
7205
- /* @__PURE__ */ jsx(
7206
- "span",
7207
- {
7208
- className: cn(
7209
- "text-sm w-7 h-7 flex items-center justify-center rounded-[var(--ds-radius-full)]",
7210
- today ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)] font-bold" : "text-[var(--ds-text-primary)]"
7211
- ),
7212
- children: day.getDate()
7213
- }
7214
- ),
7215
- /* @__PURE__ */ jsx("div", { className: "flex gap-ds-0.5 mt-ds-0.5 h-[6px] items-center", children: eventColors.map((color, i) => /* @__PURE__ */ jsx(
7216
- "span",
7217
- {
7218
- className: "w-1.5 h-1.5 rounded-[var(--ds-radius-full)]",
7219
- style: { backgroundColor: color }
7467
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "var(--ds-space-3) var(--ds-space-2.5)" }, children: [
7468
+ /* @__PURE__ */ jsxs("div", { ref: gridRef, role: "grid", "aria-label": formatMonthYear(date), onKeyDown: grid.onKeyDown, className: "flex flex-col gap-y-ds-0.5", children: [
7469
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 mb-ds-1", children: names.narrow.map((name, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": names.long[i], className: "text-center text-xs font-medium text-[var(--ds-text-muted)] py-ds-1.5", children: name }, i)) }),
7470
+ weeks.map((week) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7", children: week.map((day) => {
7471
+ const isCurrentMonth = day.getMonth() === currentMonth;
7472
+ const dayEvents = isCurrentMonth ? getEventsForDay(events, day) : [];
7473
+ const today = isCurrentMonth && isToday(day);
7474
+ const selected = isCurrentMonth && !!selectedDate && isSameDay(day, selectedDate);
7475
+ return /* @__PURE__ */ jsxs(
7476
+ "button",
7477
+ {
7478
+ type: "button",
7479
+ role: "gridcell",
7480
+ "data-grid-key": dayKey(day),
7481
+ tabIndex: grid.tabIndexOf(day),
7482
+ "aria-label": dayEvents.length ? `${formatDayLong(day)}, ${dayEvents.length} ${dayEvents.length === 1 ? "event" : "events"}` : formatDayLong(day),
7483
+ "aria-selected": selected,
7484
+ "aria-current": today ? "date" : void 0,
7485
+ onFocus: () => {
7486
+ if (!isSameDay(day, active)) setActiveDay(day);
7220
7487
  },
7221
- i
7222
- )) })
7223
- ]
7224
- }
7225
- ),
7226
- open && hasEvents && createPortal(
7227
- /* @__PURE__ */ jsxs(
7228
- "div",
7229
- {
7230
- ref: floatingRef,
7231
- onMouseEnter: () => clearTimeout(hoverTimeout.current),
7232
- onMouseLeave: () => setOpen(false),
7233
- className: cn(
7234
- "fixed z-[var(--ds-z-popover)] w-52 max-h-40 overflow-y-auto",
7235
- "bg-[var(--ds-bg-surface-elevated)]",
7236
- "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
7237
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
7238
- "rounded-[var(--ds-radius-md)]",
7239
- "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
7240
- "p-ds-2 space-y-ds-1"
7241
- ),
7242
- style: { top: pos.top, left: pos.left },
7243
- role: "tooltip",
7244
- children: [
7245
- /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-0.5", children: day.toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" }) }),
7246
- dayEvents.map((event) => /* @__PURE__ */ jsx(
7247
- EventBar,
7248
- {
7249
- event,
7250
- category: categories[event.category ?? ""],
7251
- onClick: onEventClick
7252
- },
7253
- event.id
7254
- ))
7255
- ]
7256
- }
7257
- ),
7258
- document.body
7259
- )
7260
- ] });
7261
- }
7262
- function CompactMonthView({
7263
- date,
7264
- events,
7265
- categories,
7266
- selectedDate,
7267
- onDayClick,
7268
- onEventClick,
7269
- weekStartsOn
7270
- }) {
7271
- const weeks = useMemo(
7272
- () => getMonthGrid(date.getFullYear(), date.getMonth(), weekStartsOn),
7273
- [date, weekStartsOn]
7274
- );
7275
- const dayNames = useMemo(() => getOrderedDayNames(weekStartsOn), [weekStartsOn]);
7276
- const currentMonth = date.getMonth();
7277
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", style: { padding: "var(--ds-space-3) var(--ds-space-2.5)" }, children: [
7278
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 mb-ds-1.5", children: dayNames.map((name) => /* @__PURE__ */ jsx(
7279
- "div",
7280
- {
7281
- className: "text-center text-xs font-medium text-[var(--ds-text-muted)] py-ds-1.5",
7282
- children: name[0]
7283
- },
7284
- name
7285
- )) }),
7286
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-y-ds-0.5", children: weeks.map(
7287
- (week, wi) => week.map((day, di) => /* @__PURE__ */ jsx(
7288
- CompactDayCell,
7289
- {
7290
- day,
7291
- isCurrentMonth: day.getMonth() === currentMonth,
7292
- events,
7293
- categories,
7294
- selectedDate,
7295
- onDayClick,
7296
- onEventClick
7297
- },
7298
- `${wi}-${di}`
7299
- ))
7300
- ) })
7488
+ onClick: (e) => {
7489
+ onDayClick(day);
7490
+ const anchor = e.currentTarget;
7491
+ if (dayEvents.length) setList((cur) => cur && isSameDay(cur.day, day) ? null : { day, anchor });
7492
+ },
7493
+ className: cn(
7494
+ "flex flex-col items-center justify-center py-ds-1.5 rounded-[var(--ds-radius-sm)] cursor-pointer transition-colors",
7495
+ "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7496
+ !isCurrentMonth && "opacity-30",
7497
+ selected && "bg-[var(--ds-accent-subtle)]",
7498
+ !selected && "hover:bg-[var(--ds-bg-muted)]"
7499
+ ),
7500
+ children: [
7501
+ /* @__PURE__ */ jsx("span", { className: cn("text-sm w-7 h-7 flex items-center justify-center rounded-[var(--ds-radius-full)]", today ? TODAY_CIRCLE : "text-[var(--ds-text-primary)]"), children: day.getDate() }),
7502
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "flex gap-ds-0.5 mt-ds-0.5 h-[6px] items-center", children: dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-[var(--ds-radius-full)]", style: { backgroundColor: eventColours(categories[event.category ?? ""]).edge } }, event.id)) })
7503
+ ]
7504
+ },
7505
+ dayKey(day)
7506
+ );
7507
+ }) }, dayKey(week[0])))
7508
+ ] }),
7509
+ list && /* @__PURE__ */ jsx(DayList, { day: list.day, events: getEventsForDay(events, list.day), categories, anchor: list.anchor, onOpenEvent, onClose: () => setList(null) })
7301
7510
  ] });
7302
7511
  }
7303
7512
 
7304
7513
  // ../../showcase/src/components/Calendar/types.ts
7305
7514
  var DEFAULT_CATEGORIES = {
7306
- work: { color: "var(--ds-accent-primary)", label: "Work" },
7307
- personal: { color: "var(--ds-status-success)", label: "Personal" },
7308
- meeting: { color: "var(--ds-status-warning)", label: "Meeting" },
7309
- deadline: { color: "var(--ds-status-error)", label: "Deadline" },
7310
- travel: { color: "var(--ds-status-info)", label: "Travel" },
7311
- social: { color: "var(--ds-hue-secondary)", label: "Social" }
7515
+ work: { color: "accent", label: "Work" },
7516
+ personal: { color: 1, label: "Personal" },
7517
+ meeting: { color: 2, label: "Meeting" },
7518
+ deadline: { color: 3, label: "Deadline" },
7519
+ travel: { color: 4, label: "Travel" },
7520
+ social: { color: 5, label: "Social" }
7312
7521
  };
7522
+ var notADate = (d) => d !== void 0 && Number.isNaN(new Date(d).getTime());
7523
+ var WEEK_FLOOR = 160 + 4 * HOUR_HEIGHT;
7313
7524
  function useControllableState(controlled, defaultValue, onChange) {
7314
7525
  const [internal, setInternal] = useState(defaultValue);
7315
7526
  const value = controlled !== void 0 ? controlled : internal;
@@ -7389,9 +7600,7 @@ function MonthDropdown({
7389
7600
  "pl-ds-3 pr-ds-2 py-ds-1"
7390
7601
  ),
7391
7602
  children: [
7392
- MONTH_NAMES[currentMonth],
7393
- " ",
7394
- currentYear,
7603
+ formatMonthYear(currentDate),
7395
7604
  /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 12, className: cn("transition-transform", open && "rotate-180") })
7396
7605
  ]
7397
7606
  }
@@ -7433,7 +7642,7 @@ function MonthDropdown({
7433
7642
  }
7434
7643
  )
7435
7644
  ] }),
7436
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-ds-1", children: MONTH_NAMES_SHORT.map((name, i) => {
7645
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-ds-1", children: Array.from({ length: 12 }, (_, i) => monthName(i, "short")).map((name, i) => {
7437
7646
  const isActive2 = i === currentMonth && browseYear === currentYear;
7438
7647
  return /* @__PURE__ */ jsx(
7439
7648
  "button",
@@ -7451,7 +7660,7 @@ function MonthDropdown({
7451
7660
  },
7452
7661
  children: name
7453
7662
  },
7454
- name
7663
+ i
7455
7664
  );
7456
7665
  }) })
7457
7666
  ]
@@ -7604,6 +7813,7 @@ function Calendar({
7604
7813
  onDateRangeChange,
7605
7814
  onEventClick,
7606
7815
  onDayClick,
7816
+ eventActions,
7607
7817
  categories = DEFAULT_CATEGORIES,
7608
7818
  weekStartsOn = 1,
7609
7819
  size = "default",
@@ -7614,14 +7824,21 @@ function Calendar({
7614
7824
  defaultView,
7615
7825
  onViewChange
7616
7826
  );
7827
+ const today = useMemo(() => /* @__PURE__ */ new Date(), []);
7617
7828
  const [currentDate, setCurrentDate] = useControllableState(
7618
- controlledDate,
7619
- defaultDate ?? /* @__PURE__ */ new Date(),
7829
+ notADate(controlledDate) ? today : controlledDate,
7830
+ defaultDate !== void 0 && !notADate(defaultDate) ? defaultDate : today,
7620
7831
  onDateChange
7621
7832
  );
7833
+ const dateUnreadable = notADate(controlledDate) || notADate(defaultDate);
7834
+ useEffect(() => {
7835
+ if (dateUnreadable) warnOnce("Calendar", "its date (or defaultDate) isn't a date, so it shows today: pass a Date, or a date string Date reads.");
7836
+ }, [dateUnreadable]);
7622
7837
  const [selectedDate, setSelectedDate] = useState(null);
7623
7838
  const [isNarrow, setIsNarrow] = useState(false);
7839
+ const rootRef = useRef(null);
7624
7840
  const containerRef = useCallback((node) => {
7841
+ rootRef.current = node;
7625
7842
  if (!node) return;
7626
7843
  const ro = new ResizeObserver((entries) => {
7627
7844
  const width = entries[0]?.contentRect.width ?? 0;
@@ -7630,10 +7847,44 @@ function Calendar({
7630
7847
  ro.observe(node);
7631
7848
  return () => ro.disconnect();
7632
7849
  }, []);
7633
- const stableEvents = useMemo(
7634
- () => events.map((e) => ({ ...e, start: new Date(e.start), end: e.end ? new Date(e.end) : void 0 })),
7635
- [events]
7636
- );
7850
+ const fillRaw = useFillHeight(rootRef, size !== "compact" && currentView === "week");
7851
+ const fill2 = fillRaw !== null && fillRaw >= WEEK_FLOOR ? fillRaw : null;
7852
+ const inPane = useContext(FillContext) && currentView === "week";
7853
+ const [openEvent, setOpenEvent] = useState(null);
7854
+ const openCard = useCallback((event, from) => {
7855
+ if (onEventClick) {
7856
+ onEventClick(event);
7857
+ return;
7858
+ }
7859
+ setOpenEvent((cur) => cur && cur.event.id === event.id && cur.anchor === from ? null : { event, anchor: from });
7860
+ }, [onEventClick]);
7861
+ const actionsHidden = !!onEventClick && !!eventActions;
7862
+ useEffect(() => {
7863
+ if (actionsHidden) warnOnce("Calendar", "eventActions are never shown while onEventClick is set: the page opens a surface of its own for an event, so no card shows. Pass eventActions for the Calendar's card, or onEventClick for your own (Sprint 25.18).");
7864
+ }, [actionsHidden]);
7865
+ const shownKey = `${currentView}|${currentDate.toDateString()}`;
7866
+ const [cardShownKey, setCardShownKey] = useState(shownKey);
7867
+ if (cardShownKey !== shownKey) {
7868
+ setCardShownKey(shownKey);
7869
+ if (openEvent) setOpenEvent(null);
7870
+ }
7871
+ const { stableEvents, unreadable } = useMemo(() => {
7872
+ const read = [];
7873
+ const left = [];
7874
+ for (const e of events) {
7875
+ const start = new Date(e.start);
7876
+ if (Number.isNaN(start.getTime())) {
7877
+ left.push(String(e.id));
7878
+ continue;
7879
+ }
7880
+ const end = e.end ? new Date(e.end) : void 0;
7881
+ read.push({ ...e, start, end: end && !Number.isNaN(end.getTime()) ? end : void 0 });
7882
+ }
7883
+ return { stableEvents: read, unreadable: left.join(", ") };
7884
+ }, [events]);
7885
+ useEffect(() => {
7886
+ if (unreadable) warnOnce("Calendar", `events with a start that isn't a date aren't drawn (${unreadable}): give each a Date, or a date string Date reads.`);
7887
+ }, [unreadable]);
7637
7888
  useEffect(() => {
7638
7889
  if (!onDateRangeChange) return;
7639
7890
  let start, end;
@@ -7666,9 +7917,10 @@ function Calendar({
7666
7917
  setSelectedDate(/* @__PURE__ */ new Date());
7667
7918
  }, [setCurrentDate]);
7668
7919
  const handleDayClick = useCallback(
7669
- (date) => {
7920
+ (date, detail) => {
7670
7921
  setSelectedDate(date);
7671
- onDayClick?.(date);
7922
+ if (detail) onDayClick?.(date, detail);
7923
+ else onDayClick?.(date);
7672
7924
  },
7673
7925
  [onDayClick]
7674
7926
  );
@@ -7683,10 +7935,24 @@ function Calendar({
7683
7935
  if (currentView === "week") return formatWeekRange(currentDate, weekStartsOn);
7684
7936
  return void 0;
7685
7937
  }, [currentView, currentDate, weekStartsOn]);
7938
+ const live = openEvent && stableEvents.find((e) => e.id === openEvent.event.id);
7939
+ const card = openEvent && live ? /* @__PURE__ */ jsx(
7940
+ EventCard,
7941
+ {
7942
+ event: live,
7943
+ category: categories[live.category ?? ""],
7944
+ anchor: openEvent.anchor,
7945
+ actions: typeof eventActions === "function" ? eventActions(live) : eventActions ?? [],
7946
+ onClose: () => setOpenEvent(null),
7947
+ fallbackFocus: () => rootRef.current?.querySelector('[role="gridcell"][tabindex="0"]')
7948
+ },
7949
+ openEvent.event.id
7950
+ ) : null;
7686
7951
  if (size === "compact") {
7687
7952
  return /* @__PURE__ */ jsxs(
7688
7953
  "div",
7689
7954
  {
7955
+ ref: containerRef,
7690
7956
  className: cn(
7691
7957
  "flex flex-col",
7692
7958
  "bg-[var(--ds-bg-surface)]",
@@ -7716,16 +7982,12 @@ function Calendar({
7716
7982
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 16 })
7717
7983
  }
7718
7984
  ),
7719
- /* @__PURE__ */ jsxs(
7985
+ /* @__PURE__ */ jsx(
7720
7986
  "button",
7721
7987
  {
7722
7988
  onClick: goToToday,
7723
7989
  className: "text-sm font-medium text-[var(--ds-text-primary)] hover:text-[var(--ds-accent-primary)] transition-colors cursor-pointer px-ds-2",
7724
- children: [
7725
- MONTH_NAMES[currentDate.getMonth()],
7726
- " ",
7727
- currentDate.getFullYear()
7728
- ]
7990
+ children: formatMonthYear(currentDate)
7729
7991
  }
7730
7992
  ),
7731
7993
  /* @__PURE__ */ jsx(
@@ -7748,10 +8010,12 @@ function Calendar({
7748
8010
  categories,
7749
8011
  selectedDate,
7750
8012
  onDayClick: handleDayClick,
7751
- onEventClick,
8013
+ onOpenEvent: openCard,
8014
+ onNavigate: setCurrentDate,
7752
8015
  weekStartsOn
7753
8016
  }
7754
- )
8017
+ ),
8018
+ card
7755
8019
  ]
7756
8020
  }
7757
8021
  );
@@ -7760,6 +8024,7 @@ function Calendar({
7760
8024
  "div",
7761
8025
  {
7762
8026
  ref: containerRef,
8027
+ "data-fill": fill2 != null ? "" : void 0,
7763
8028
  className: cn(
7764
8029
  "flex flex-col",
7765
8030
  "bg-[var(--ds-bg-surface)]",
@@ -7767,8 +8032,10 @@ function Calendar({
7767
8032
  "rounded-[var(--ds-radius-lg)]",
7768
8033
  "shadow-[var(--ds-shadow-sm)]",
7769
8034
  "overflow-hidden",
8035
+ inPane && "h-full min-h-0",
7770
8036
  className
7771
8037
  ),
8038
+ style: fill2 != null ? { height: fill2 } : void 0,
7772
8039
  children: [
7773
8040
  isNarrow ? /* @__PURE__ */ jsxs(
7774
8041
  "div",
@@ -7827,7 +8094,7 @@ function Calendar({
7827
8094
  ]
7828
8095
  }
7829
8096
  ),
7830
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0", style: { minHeight: currentView === "week" ? 420 : currentView === "month" ? isNarrow ? 360 : 500 : void 0 }, children: [
8097
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0", style: { minHeight: currentView === "week" ? fill2 != null || inPane ? void 0 : 420 : currentView === "month" ? isNarrow ? 360 : 500 : void 0 }, children: [
7831
8098
  currentView === "month" && /* @__PURE__ */ jsx(
7832
8099
  MonthView,
7833
8100
  {
@@ -7836,7 +8103,9 @@ function Calendar({
7836
8103
  categories,
7837
8104
  selectedDate,
7838
8105
  onDayClick: handleDayClick,
7839
- onEventClick,
8106
+ canStartEvent: !!onDayClick,
8107
+ onOpenEvent: openCard,
8108
+ onNavigate: setCurrentDate,
7840
8109
  weekStartsOn
7841
8110
  }
7842
8111
  ),
@@ -7848,7 +8117,8 @@ function Calendar({
7848
8117
  categories,
7849
8118
  selectedDate,
7850
8119
  onDayClick: handleDayClick,
7851
- onEventClick,
8120
+ onOpenEvent: openCard,
8121
+ onNavigate: setCurrentDate,
7852
8122
  weekStartsOn
7853
8123
  }
7854
8124
  ),
@@ -7860,11 +8130,11 @@ function Calendar({
7860
8130
  categories,
7861
8131
  selectedDate,
7862
8132
  onMonthClick: handleMonthClick,
7863
- weekStartsOn,
7864
- onEventClick
8133
+ weekStartsOn
7865
8134
  }
7866
8135
  )
7867
- ] })
8136
+ ] }),
8137
+ card
7868
8138
  ]
7869
8139
  }
7870
8140
  );
@@ -7930,7 +8200,7 @@ var defaultIcons = {
7930
8200
  };
7931
8201
  var FRAME_ICON_SIZE = 28;
7932
8202
  function renderIcon(icon) {
7933
- if (typeof icon === "string") return /* @__PURE__ */ jsx(Icon, { name: icon, size: FRAME_ICON_SIZE, className: "text-[var(--ds-text-muted)]" });
8203
+ if (typeof icon === "string") return /* @__PURE__ */ jsx(Icon, { name: icon, size: FRAME_ICON_SIZE, className: "text-[var(--ds-text-muted)]", from: "EmptyState's icon" });
7934
8204
  if (isValidElement(icon) && icon.type === Icon) return cloneElement(icon, { size: FRAME_ICON_SIZE });
7935
8205
  return icon;
7936
8206
  }
@@ -8109,7 +8379,7 @@ function TableToolbar({
8109
8379
  var ICON_TEXT_OFFSET = "calc((2rem - 1.25rem) / 2)";
8110
8380
  function Marker({ item, vertical }) {
8111
8381
  if (item.icon) {
8112
- return /* @__PURE__ */ jsx("div", { "data-timeline-icon": "", className: "shrink-0 w-8 h-8 flex items-center justify-center *:max-w-8 *:max-h-8", children: item.icon });
8382
+ return /* @__PURE__ */ jsx("div", { "data-timeline-icon": "", className: "shrink-0 w-8 h-8 flex items-center justify-center *:max-w-8 *:max-h-8", children: slotIcon(item.icon, 16, "a Timeline item's icon") });
8113
8383
  }
8114
8384
  return /* @__PURE__ */ jsx(
8115
8385
  "div",
@@ -8156,7 +8426,7 @@ function ExpandableDescription({ children, className }) {
8156
8426
  );
8157
8427
  }
8158
8428
  function HorizontalLayout({ items, minItemWidth, className }) {
8159
- return /* @__PURE__ */ jsx("div", { "data-timeline-row": "", className: cn("flex items-start overflow-x-auto snap-x", className), children: items.map((item, i) => {
8429
+ return /* @__PURE__ */ jsx("div", { "data-timeline-row": "", className: cn("relative flex items-start overflow-x-auto snap-x", className), children: items.map((item, i) => {
8160
8430
  const isFirst = i === 0;
8161
8431
  const isLast = i === items.length - 1;
8162
8432
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 shrink-0 flex-col items-center snap-start", style: { minWidth: minItemWidth }, children: [
@@ -8189,8 +8459,8 @@ function HorizontalLayout({ items, minItemWidth, className }) {
8189
8459
  ] }, i);
8190
8460
  }) });
8191
8461
  }
8192
- var EXACT = new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" });
8193
- var EXACT_DAY = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
8462
+ var EXACT = { format: (d) => new Intl.DateTimeFormat(formatLocale(), { dateStyle: "medium", timeStyle: "short" }).format(d) };
8463
+ var EXACT_DAY = { format: (d) => new Intl.DateTimeFormat(formatLocale(), { dateStyle: "medium" }).format(d) };
8194
8464
  var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
8195
8465
  function exactTime(value) {
8196
8466
  if (typeof value === "string") {
@@ -8205,6 +8475,9 @@ function exactTime(value) {
8205
8475
  return Number.isNaN(date.getTime()) ? null : { iso: date.toISOString(), text: EXACT.format(date) };
8206
8476
  }
8207
8477
  function ItemTime({ item }) {
8478
+ if (item.time !== void 0) {
8479
+ return /* @__PURE__ */ jsx("p", { className: "text-2xs text-[var(--ds-text-muted)] mt-ds-0.5 tabular-nums", children: /* @__PURE__ */ jsx(RelativeTime, { time: item.time }) });
8480
+ }
8208
8481
  const exact = item.dateTime ? exactTime(item.dateTime) : null;
8209
8482
  if (!item.timestamp && !exact) return null;
8210
8483
  return /* @__PURE__ */ jsx("p", { className: "text-2xs text-[var(--ds-text-muted)] mt-ds-0.5 tabular-nums", children: exact ? /* @__PURE__ */ jsxs("time", { dateTime: exact.iso, title: exact.text, children: [
@@ -8242,7 +8515,7 @@ function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 20
8242
8515
  }, [ref]);
8243
8516
  const fits = width === 0 || width >= items.length * minItemWidth;
8244
8517
  const horizontal = orientation === "horizontal" || orientation === "responsive" && fits;
8245
- const list = /* @__PURE__ */ jsx("div", { ref: setRefs, "data-ds-list": "", "data-timeline-orientation": horizontal ? "horizontal" : "vertical", className: pager ? void 0 : className, children: horizontal ? /* @__PURE__ */ jsx(HorizontalLayout, { items, minItemWidth }) : /* @__PURE__ */ jsx(VerticalLayout, { items }) });
8518
+ const list = /* @__PURE__ */ jsx("div", { ref: setRefs, "data-ds-list": "", "data-timeline-orientation": horizontal ? "horizontal" : "vertical", className: pager ? void 0 : className, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: horizontal ? /* @__PURE__ */ jsx(HorizontalLayout, { items, minItemWidth }) : /* @__PURE__ */ jsx(VerticalLayout, { items }) }) });
8246
8519
  if (!pager) return list;
8247
8520
  return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
8248
8521
  list,
@@ -8811,7 +9084,7 @@ function Carousel({
8811
9084
  );
8812
9085
  }
8813
9086
  function formatTime2(d) {
8814
- return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
9087
+ return d.toLocaleTimeString(formatLocale(), { hour: "2-digit", minute: "2-digit" });
8815
9088
  }
8816
9089
  function isSameMinute(a, b) {
8817
9090
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() && a.getHours() === b.getHours() && a.getMinutes() === b.getMinutes();
@@ -9602,7 +9875,7 @@ var StackedList = forwardRef(function StackedList2({
9602
9875
  !pager && className
9603
9876
  ),
9604
9877
  role: "list",
9605
- children: shown.map((item) => {
9878
+ children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: shown.map((item) => {
9606
9879
  const isSelected = item.selected ?? (selectedId !== void 0 && item.id === selectedId);
9607
9880
  const interactive = !!item.onClick;
9608
9881
  const hasEmphasis = item.unread !== void 0;
@@ -9691,7 +9964,7 @@ var StackedList = forwardRef(function StackedList2({
9691
9964
  ]
9692
9965
  }
9693
9966
  ) }, item.id);
9694
- })
9967
+ }) })
9695
9968
  }
9696
9969
  );
9697
9970
  if (!pager) return list;
@@ -9701,9 +9974,9 @@ var StackedList = forwardRef(function StackedList2({
9701
9974
  ] });
9702
9975
  });
9703
9976
  var TIME_ZOOMS = ["day", "week", "month", "quarter"];
9704
- var DAY_MS = 864e5;
9977
+ var DAY_MS2 = 864e5;
9705
9978
  var DATE_ONLY2 = /^(\d{4})-(\d{2})-(\d{2})$/;
9706
- var utcDay = (y, m, d) => Math.round(Date.UTC(y, m, d) / DAY_MS);
9979
+ var utcDay = (y, m, d) => Math.round(Date.UTC(y, m, d) / DAY_MS2);
9707
9980
  function dayOfDate(d) {
9708
9981
  const t = d.getTime();
9709
9982
  if (Number.isNaN(t)) return NaN;
@@ -9712,7 +9985,7 @@ function dayOfDate(d) {
9712
9985
  first.setHours(0, 0, 0, 0);
9713
9986
  if (first.getTime() === t) return day;
9714
9987
  const ms = ((d.getHours() * 60 + d.getMinutes()) * 60 + d.getSeconds()) * 1e3 + d.getMilliseconds();
9715
- return day + ms / DAY_MS;
9988
+ return day + ms / DAY_MS2;
9716
9989
  }
9717
9990
  function dayOf(value) {
9718
9991
  if (typeof value === "number") return Number.isFinite(value) ? value : NaN;
@@ -9722,13 +9995,13 @@ function dayOf(value) {
9722
9995
  if (!m) return dayOfDate(new Date(value));
9723
9996
  const [y, mo, d] = [Number(m[1]), Number(m[2]) - 1, Number(m[3])];
9724
9997
  const day = utcDay(y, mo, d);
9725
- const back = new Date(day * DAY_MS);
9998
+ const back = new Date(day * DAY_MS2);
9726
9999
  return back.getUTCFullYear() === y && back.getUTCMonth() === mo && back.getUTCDate() === d ? day : NaN;
9727
10000
  }
9728
10001
  function dateOfDay(day) {
9729
10002
  const whole = Math.floor(day);
9730
- const u = new Date(whole * DAY_MS);
9731
- return new Date(u.getUTCFullYear(), u.getUTCMonth(), u.getUTCDate(), 0, 0, 0, Math.round((day - whole) * DAY_MS));
10003
+ const u = new Date(whole * DAY_MS2);
10004
+ return new Date(u.getUTCFullYear(), u.getUTCMonth(), u.getUTCDate(), 0, 0, 0, Math.round((day - whole) * DAY_MS2));
9732
10005
  }
9733
10006
  function isWholeDay(value) {
9734
10007
  return typeof value === "string" ? DATE_ONLY2.test(value.trim()) : Number.isInteger(dayOf(value));
@@ -9747,7 +10020,7 @@ function periodStart(unit, day, weekStartsOn) {
9747
10020
  const d = Math.floor(day);
9748
10021
  if (unit === "day") return d;
9749
10022
  if (unit === "week") return d - (weekday(d) - weekStartsOn + 7) % 7;
9750
- const u = new Date(d * DAY_MS);
10023
+ const u = new Date(d * DAY_MS2);
9751
10024
  const y = u.getUTCFullYear();
9752
10025
  const m = u.getUTCMonth();
9753
10026
  if (unit === "month") return utcDay(y, m, 1);
@@ -9757,7 +10030,7 @@ function periodStart(unit, day, weekStartsOn) {
9757
10030
  function periodAfter(unit, start) {
9758
10031
  if (unit === "day") return start + 1;
9759
10032
  if (unit === "week") return start + 7;
9760
- const u = new Date(start * DAY_MS);
10033
+ const u = new Date(start * DAY_MS2);
9761
10034
  const y = u.getUTCFullYear();
9762
10035
  const m = u.getUTCMonth();
9763
10036
  if (unit === "month") return utcDay(y, m + 1, 1);
@@ -9765,7 +10038,8 @@ function periodAfter(unit, start) {
9765
10038
  return utcDay(y + 1, 0, 1);
9766
10039
  }
9767
10040
  var formats = /* @__PURE__ */ new Map();
9768
- function formatter(locale, options) {
10041
+ function formatter(given, options) {
10042
+ const locale = given ?? formatLocale();
9769
10043
  const key = `${locale ?? ""}|${JSON.stringify(options)}`;
9770
10044
  let f = formats.get(key);
9771
10045
  if (!f) {
@@ -9775,11 +10049,11 @@ function formatter(locale, options) {
9775
10049
  return f;
9776
10050
  }
9777
10051
  function format(day, locale, options) {
9778
- return formatter(locale, options).format(new Date(day * DAY_MS));
10052
+ return formatter(locale, options).format(new Date(day * DAY_MS2));
9779
10053
  }
9780
10054
  var pad22 = (n) => String(n).padStart(2, "0");
9781
10055
  function keyOf(unit, day) {
9782
- const u = new Date(day * DAY_MS);
10056
+ const u = new Date(day * DAY_MS2);
9783
10057
  const y = u.getUTCFullYear();
9784
10058
  const m = u.getUTCMonth();
9785
10059
  if (unit === "year") return String(y);
@@ -9794,7 +10068,7 @@ function labelsOf(unit, role, day, locale) {
9794
10068
  else if (unit === "week") forms = [f({ day: "numeric", month: "short" }), f({ day: "numeric" })];
9795
10069
  else if (unit === "month") {
9796
10070
  forms = role === "major" ? [f({ month: "long", year: "numeric" }), f({ month: "short", year: "numeric" }), f({ month: "short" }), f({ month: "narrow" })] : [f({ month: "long" }), f({ month: "short" }), f({ month: "narrow" })];
9797
- } else if (unit === "quarter") forms = [`Q${Math.floor(new Date(day * DAY_MS).getUTCMonth() / 3) + 1}`];
10071
+ } else if (unit === "quarter") forms = [`Q${Math.floor(new Date(day * DAY_MS2).getUTCMonth() / 3) + 1}`];
9798
10072
  else forms = [f({ year: "numeric" }), f({ year: "2-digit" })];
9799
10073
  return forms;
9800
10074
  }
@@ -9878,10 +10152,10 @@ function extendTimeScaleTo(scale, endDay) {
9878
10152
  }
9879
10153
  var noSubscription = () => () => {
9880
10154
  };
9881
- var inBrowser = () => true;
9882
- var onServer = () => false;
10155
+ var inBrowser2 = () => true;
10156
+ var onServer2 = () => false;
9883
10157
  function useTimeScale({ start, end, zoom, today, weekStartsOn = 1, locale, pxPerDay, pad: pad3 = 0 }) {
9884
- const readable = useSyncExternalStore(noSubscription, inBrowser, onServer);
10158
+ const readable = useSyncExternalStore(noSubscription, inBrowser2, onServer2);
9885
10159
  const [mounted] = useState(() => toMinute(dayOf(/* @__PURE__ */ new Date())));
9886
10160
  const pending = today === void 0 && !readable;
9887
10161
  const from = dayOf(start);
@@ -9935,8 +10209,8 @@ function formatDateRange(start, end, words) {
9935
10209
  const timed = !isWholeDay(start) || !isWholeDay(until);
9936
10210
  const first = timed ? from : Math.floor(from);
9937
10211
  const last = timed ? Math.max(from, stop) : Math.max(first, Math.ceil(stop) - 1);
9938
- const a = new Date(first * DAY_MS);
9939
- const b = new Date(last * DAY_MS);
10212
+ const a = new Date(first * DAY_MS2);
10213
+ const b = new Date(last * DAY_MS2);
9940
10214
  const years = a.getUTCFullYear() !== b.getUTCFullYear() && day.year === void 0;
9941
10215
  const f = formatter(locale, { ...day, ...years ? { year: "numeric" } : {}, ...timed ? time : {} });
9942
10216
  return first === last ? f.format(a) : range(f, a, b, to ?? (english(f) ? " to " : void 0));
@@ -10213,9 +10487,9 @@ function TimeScaleHeader({ todayLabel = "Today", className }) {
10213
10487
  }
10214
10488
  var ZOOM_NAMES = { day: "Days", week: "Weeks", month: "Months", quarter: "Quarters" };
10215
10489
  var SHADE_MIN = 4;
10216
- var INSET = 8;
10490
+ var INSET2 = 8;
10217
10491
  var MIN_INSET = 2;
10218
- var MIN_TITLE = 2 * INSET + 12;
10492
+ var MIN_TITLE = 2 * INSET2 + 12;
10219
10493
  var PHONE_BELOW = 640;
10220
10494
  var MIN_LABEL = 112;
10221
10495
  var ROW_HEIGHT = 40;
@@ -10569,7 +10843,7 @@ function TimeBar({ start, end, minWidth = 0, labels, children, className, style,
10569
10843
  let label = null;
10570
10844
  if (labels && hasLabels) {
10571
10845
  const widths = labels.map(measure);
10572
- const inset = Math.min(INSET, Math.max(MIN_INSET, (drawnWidth - borders.start - borders.end - Math.min(...widths)) / 2 - 0.5));
10846
+ const inset = Math.min(INSET2, Math.max(MIN_INSET, (drawnWidth - borders.start - borders.end - Math.min(...widths)) / 2 - 0.5));
10573
10847
  const fits = (i) => `clamp(0, calc((${inView} - ${widths[i] + 2 * inset} + 0.25) * 1000), 1)`;
10574
10848
  const shows = (i) => i === 0 ? fits(0) : `calc(${[fits(i), ...labels.slice(0, i).map((_, j) => `(1 - ${fits(j)})`)].join(" * ")})`;
10575
10849
  const named = props["aria-label"] !== void 0 || props["aria-labelledby"] !== void 0;
@@ -10584,7 +10858,7 @@ function TimeBar({ start, end, minWidth = 0, labels, children, className, style,
10584
10858
  "data-time-bar-label": "",
10585
10859
  "data-gs-clip": "",
10586
10860
  className: "sticky flex min-w-0 items-center gap-ds-1 overflow-hidden whitespace-nowrap",
10587
- style: { ...sticky, paddingInline: INSET, opacity: `clamp(0, calc((${inView} - ${MIN_TITLE}) * 1000), 1)` },
10861
+ style: { ...sticky, paddingInline: INSET2, opacity: `clamp(0, calc((${inView} - ${MIN_TITLE}) * 1000), 1)` },
10588
10862
  children: typeof children === "string" ? /* @__PURE__ */ jsx("span", { className: "truncate", children }) : children
10589
10863
  }
10590
10864
  );
@@ -10856,7 +11130,7 @@ function Gantt({
10856
11130
  const byKey = useMemo(() => new Map(rows.map((r) => [r.key, r])), [rows]);
10857
11131
  const names = useMemo(() => {
10858
11132
  const byId = new Map(tasks.map((i) => [i.id, i]));
10859
- const list = new Intl.ListFormat(locale, { type: "conjunction" });
11133
+ const list = new Intl.ListFormat(locale ?? formatLocale(), { type: "conjunction" });
10860
11134
  const out = /* @__PURE__ */ new Map();
10861
11135
  for (const item of tasks) {
10862
11136
  const dates = datesOf(item);
@@ -15986,7 +16260,7 @@ function HoverCard({
15986
16260
  className
15987
16261
  ),
15988
16262
  style: { top: pos.top, left: pos.left },
15989
- children: content
16263
+ children: /* @__PURE__ */ jsx(RowsCtx, { value: false, children: content })
15990
16264
  }
15991
16265
  ),
15992
16266
  container ?? document.body
@@ -17115,6 +17389,7 @@ var SectionHeading = forwardRef(function SectionHeading2({
17115
17389
  title,
17116
17390
  onTitleChange,
17117
17391
  titleLabel = "Title",
17392
+ titleId,
17118
17393
  description,
17119
17394
  actions,
17120
17395
  badge,
@@ -17150,7 +17425,7 @@ var SectionHeading = forwardRef(function SectionHeading2({
17150
17425
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
17151
17426
  editable ? (
17152
17427
  // the field is the title: the heading holds it, so the page's headings still name the view by its title
17153
- /* @__PURE__ */ jsx("h2", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
17428
+ /* @__PURE__ */ jsx("h2", { id: titleId, className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
17154
17429
  Input,
17155
17430
  {
17156
17431
  size: "md",
@@ -17160,7 +17435,7 @@ var SectionHeading = forwardRef(function SectionHeading2({
17160
17435
  className: "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]"
17161
17436
  }
17162
17437
  ) })
17163
- ) : /* @__PURE__ */ jsx("h2", { className: cn("font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", pane ? "truncate" : "min-w-0 break-words"), children: title }),
17438
+ ) : /* @__PURE__ */ jsx("h2", { id: titleId, className: cn("font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", pane ? "truncate" : "min-w-0 break-words"), children: title }),
17164
17439
  badge,
17165
17440
  count !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "neutral", size: "sm", children: count })
17166
17441
  ] }),
@@ -17216,6 +17491,23 @@ var ActionPanelGroup = forwardRef(function ActionPanelGroup2({
17216
17491
  }
17217
17492
  );
17218
17493
  });
17494
+ function DangerZone({ title = "Danger zone", description, children, className }) {
17495
+ const titleId = useId();
17496
+ return /* @__PURE__ */ jsxs("section", { "aria-labelledby": titleId, "data-gs": "danger-zone", className, children: [
17497
+ /* @__PURE__ */ jsx(SectionHeading, { title, titleId, description }),
17498
+ /* @__PURE__ */ jsx(
17499
+ "div",
17500
+ {
17501
+ "data-danger-frame": "",
17502
+ className: cn(
17503
+ "rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)] border-[length:var(--ds-border-width)] border-[var(--ds-status-error)] px-ds-5",
17504
+ GLASS_SURFACE
17505
+ ),
17506
+ children: /* @__PURE__ */ jsx(ActionPanelGroup, { children })
17507
+ }
17508
+ )
17509
+ ] });
17510
+ }
17219
17511
  var lineClampClasses = {
17220
17512
  1: "truncate",
17221
17513
  2: "line-clamp-2",
@@ -17267,6 +17559,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
17267
17559
  return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
17268
17560
  });
17269
17561
 
17270
- export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, DropdownMenu, EmptyState, EntityCell, FileUpload, FlowSaved, FormWrapper, Gantt, HoverCard, Kbd, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, PageActions, PageContainer, PageHeader, PinInput, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sheet, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, Toast, ToastProvider, Tour, TransferList, TreeView, dateOfDay, dayOf, endDayOf, fitLabel, fitLabels, formatDateRange, readFlowProgress, timeExtent, useContentWidth, useDestructiveAction, useFittedLabels, useFlowSteps, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
17562
+ export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, AvatarGroup, BottomNav, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DangerZone, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, DropdownMenu, EmptyState, EntityCell, FileUpload, FlowSaved, FormWrapper, Gantt, HoverCard, Kbd, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, PageActions, PageContainer, PageHeader, PinInput, Progress, RadioGroup, Rating, RelativeTime, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sheet, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, TimezoneSelect, Toast, ToastProvider, Tour, TransferList, TreeView, browserTimeZone, canonicalTimeZone, dateOfDay, dayOf, endDayOf, fitLabel, fitLabels, formatDateRange, formatFullTime, formatRelativeTime, readFlowProgress, timeExtent, timeZoneOffset, useContentWidth, useDestructiveAction, useFittedLabels, useFlowSteps, useRelativeTimeFormat, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
17271
17563
  //# sourceMappingURL=index.js.map
17272
17564
  //# sourceMappingURL=index.js.map