gridsmith-ui 0.23.0 → 0.25.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 (89) hide show
  1. package/README.md +8 -6
  2. package/dist/Breadcrumbs-CGS8GKl-.d.ts +33 -0
  3. package/dist/MentionList-CoNBRFGR.d.ts +8 -0
  4. package/dist/charts.d.ts +42 -1
  5. package/dist/charts.js +320 -89
  6. package/dist/charts.js.map +1 -1
  7. package/dist/chat.js +5 -4
  8. package/dist/chat.js.map +1 -1
  9. package/dist/chunk-2YSEME33.js +118 -0
  10. package/dist/chunk-2YSEME33.js.map +1 -0
  11. package/dist/{chunk-6PL7FXYH.js → chunk-3CUKJ4VP.js} +321 -11
  12. package/dist/chunk-3CUKJ4VP.js.map +1 -0
  13. package/dist/{chunk-SBTBMAIU.js → chunk-FHMCAOAH.js} +6 -6
  14. package/dist/{chunk-SBTBMAIU.js.map → chunk-FHMCAOAH.js.map} +1 -1
  15. package/dist/chunk-HP7WUZPK.js +80 -0
  16. package/dist/chunk-HP7WUZPK.js.map +1 -0
  17. package/dist/{chunk-4LDYR7QP.js → chunk-HYMXAIXN.js} +53 -13
  18. package/dist/chunk-HYMXAIXN.js.map +1 -0
  19. package/dist/{chunk-7TOJ4G7S.js → chunk-HZIP4EJI.js} +14 -9
  20. package/dist/chunk-HZIP4EJI.js.map +1 -0
  21. package/dist/{chunk-RT7RYGC3.js → chunk-JXANCXK6.js} +4 -39
  22. package/dist/chunk-JXANCXK6.js.map +1 -0
  23. package/dist/{chunk-CXMV7SXJ.js → chunk-MD2EFMES.js} +5 -77
  24. package/dist/chunk-MD2EFMES.js.map +1 -0
  25. package/dist/{chunk-IVCVNAXG.js → chunk-OTCEJN64.js} +3 -3
  26. package/dist/{chunk-IVCVNAXG.js.map → chunk-OTCEJN64.js.map} +1 -1
  27. package/dist/{chunk-EYMGLK4M.js → chunk-QGSCF7PN.js} +7 -7
  28. package/dist/chunk-QGSCF7PN.js.map +1 -0
  29. package/dist/{chunk-CKWITUSH.js → chunk-QM4SJKWV.js} +15 -5
  30. package/dist/chunk-QM4SJKWV.js.map +1 -0
  31. package/dist/chunk-RWKCAKN3.js +209 -0
  32. package/dist/chunk-RWKCAKN3.js.map +1 -0
  33. package/dist/{chunk-ICNWPNMM.js → chunk-W7GCEJEH.js} +11 -23
  34. package/dist/chunk-W7GCEJEH.js.map +1 -0
  35. package/dist/chunk-WOVYHFUD.js +50 -0
  36. package/dist/chunk-WOVYHFUD.js.map +1 -0
  37. package/dist/{chunk-NCIZQYXQ.js → chunk-X2HEV7FB.js} +33 -3
  38. package/dist/chunk-X2HEV7FB.js.map +1 -0
  39. package/dist/chunk-XVB55M3N.js +42 -0
  40. package/dist/chunk-XVB55M3N.js.map +1 -0
  41. package/dist/data-grid.d.ts +1 -1
  42. package/dist/data-grid.js +14 -12
  43. package/dist/data-grid.js.map +1 -1
  44. package/dist/editor-mentions.d.ts +30 -0
  45. package/dist/editor-mentions.js +160 -0
  46. package/dist/editor-mentions.js.map +1 -0
  47. package/dist/editor.d.ts +23 -3
  48. package/dist/editor.js +59 -9
  49. package/dist/editor.js.map +1 -1
  50. package/dist/{feather-2JFSFLXN.js → feather-W26ERBQV.js} +11 -3
  51. package/dist/feather-W26ERBQV.js.map +1 -0
  52. package/dist/{heroicons-4AQ4YBVG.js → heroicons-MY43466C.js} +21 -7
  53. package/dist/heroicons-MY43466C.js.map +1 -0
  54. package/dist/icons.d.ts +11 -4
  55. package/dist/icons.js +1 -1
  56. package/dist/index.d.ts +348 -65
  57. package/dist/index.js +886 -576
  58. package/dist/index.js.map +1 -1
  59. package/dist/kanban.js +26 -8
  60. package/dist/kanban.js.map +1 -1
  61. package/dist/{lucide-RZC2FEMS.js → lucide-CMPVM3PS.js} +11 -3
  62. package/dist/lucide-CMPVM3PS.js.map +1 -0
  63. package/dist/{phosphor-CEN25FLM.js → phosphor-RMHZOW2O.js} +11 -3
  64. package/dist/phosphor-RMHZOW2O.js.map +1 -0
  65. package/dist/resizable.d.ts +16 -1
  66. package/dist/resizable.js +91 -23
  67. package/dist/resizable.js.map +1 -1
  68. package/dist/roots.css +15 -0
  69. package/dist/{tabler-YXXC7Y6B.js → tabler-MJVEYHA5.js} +11 -3
  70. package/dist/tabler-MJVEYHA5.js.map +1 -0
  71. package/dist/{use-pagination-DiJo0aW5.d.ts → use-pagination-BnKOnBdz.d.ts} +3 -0
  72. package/dist/virtualized.d.ts +1 -1
  73. package/dist/virtualized.js +8 -6
  74. package/dist/virtualized.js.map +1 -1
  75. package/package.json +29 -21
  76. package/dist/chunk-4LDYR7QP.js.map +0 -1
  77. package/dist/chunk-6PL7FXYH.js.map +0 -1
  78. package/dist/chunk-7TOJ4G7S.js.map +0 -1
  79. package/dist/chunk-CKWITUSH.js.map +0 -1
  80. package/dist/chunk-CXMV7SXJ.js.map +0 -1
  81. package/dist/chunk-EYMGLK4M.js.map +0 -1
  82. package/dist/chunk-ICNWPNMM.js.map +0 -1
  83. package/dist/chunk-NCIZQYXQ.js.map +0 -1
  84. package/dist/chunk-RT7RYGC3.js.map +0 -1
  85. package/dist/feather-2JFSFLXN.js.map +0 -1
  86. package/dist/heroicons-4AQ4YBVG.js.map +0 -1
  87. package/dist/lucide-RZC2FEMS.js.map +0 -1
  88. package/dist/phosphor-CEN25FLM.js.map +0 -1
  89. package/dist/tabler-YXXC7Y6B.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,27 +1,33 @@
1
- import { useAppShell, REACT_VERSION_PROBLEM, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-6PL7FXYH.js';
2
- export { AppShell, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-6PL7FXYH.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-W7GCEJEH.js';
3
+ export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-W7GCEJEH.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-3CUKJ4VP.js';
5
+ export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-3CUKJ4VP.js';
6
+ import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, preferenceActionKey } from './chunk-HZIP4EJI.js';
7
+ export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, preferenceActionKey, usePreferences } from './chunk-HZIP4EJI.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-EYMGLK4M.js';
7
- export { CodeBlock, Divider, Link } from './chunk-EYMGLK4M.js';
8
- import { Badge } from './chunk-SBTBMAIU.js';
9
- export { Badge } from './chunk-SBTBMAIU.js';
10
- import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-IVCVNAXG.js';
11
- import { useWholeListCheck, pagerPart, Pagination, 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, Input, Field } from './chunk-ICNWPNMM.js';
12
- export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-ICNWPNMM.js';
13
- import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, preferenceActionKey } from './chunk-7TOJ4G7S.js';
14
- export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, preferenceActionKey, usePreferences } from './chunk-7TOJ4G7S.js';
15
11
  import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
16
12
  export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
17
- import { FOCUSABLE, usePopupFocus, FIELD, ZOOM_KEYS, FormChangeCtx, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, useReportedChange, rovingTabStop, useGridKeyboard, useOptionalFormContext, focusAfterRemoval, FormCtx, useNonModalDialog, useReturnFocus, useCloseOnFocusOut } from './chunk-RT7RYGC3.js';
18
- export { useFormContext, useGridKeyboard } from './chunk-RT7RYGC3.js';
19
- import { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-CKWITUSH.js';
20
- import { useTextOverflow, Tooltip, usePosition } from './chunk-CXMV7SXJ.js';
21
- export { Tooltip, useTextOverflow } from './chunk-CXMV7SXJ.js';
13
+ import { FormChangeCtx, useReportedChange, useOptionalFormContext, FormCtx } from './chunk-XVB55M3N.js';
14
+ export { useFormContext } from './chunk-XVB55M3N.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-QGSCF7PN.js';
18
+ export { CodeBlock, Divider, Link } from './chunk-QGSCF7PN.js';
19
+ import { useFillHeight, FillContext } from './chunk-2YSEME33.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, useCloseOnFocusOut } from './chunk-JXANCXK6.js';
22
+ export { useGridKeyboard } from './chunk-JXANCXK6.js';
23
+ import { Badge } from './chunk-FHMCAOAH.js';
24
+ export { Badge } from './chunk-FHMCAOAH.js';
25
+ import { useTextOverflow, Tooltip } from './chunk-MD2EFMES.js';
26
+ export { Tooltip, useTextOverflow } from './chunk-MD2EFMES.js';
22
27
  import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
28
+ import { Icon, slotIcon, warnOnce } from './chunk-HYMXAIXN.js';
29
+ import { usePosition } from './chunk-HP7WUZPK.js';
23
30
  import { useLatest } from './chunk-WH2FUFAC.js';
24
- import { Icon } from './chunk-4LDYR7QP.js';
25
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';
26
32
  import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useEffect, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
27
33
  import { createPortal, flushSync } from 'react-dom';
@@ -224,7 +230,7 @@ var TEXT_SIZE = {
224
230
  md: "text-sm",
225
231
  lg: "text-base"
226
232
  };
227
- 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 }) {
228
234
  const onChange = useReportedChange(onChangeProp, value);
229
235
  const contextSize = useContext(ControlSizeContext);
230
236
  const control = useFieldControl({ ...wiring, error: error || void 0 });
@@ -241,8 +247,9 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
241
247
  const listboxId = useId();
242
248
  const pos = usePosition(triggerRef, listRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
243
249
  const filtered = options.filter(
244
- (o) => !o.disabled && o.label.toLowerCase().includes(query.toLowerCase())
250
+ (o) => !o.disabled && foldForSearch(o.label).includes(foldForSearch(query))
245
251
  );
252
+ useActiveOptionInView(listRef, open && filtered[highlightIdx] ? `${listboxId}-opt-${highlightIdx}` : void 0);
246
253
  const selectedLabel = options.find((o) => o.value === value)?.label ?? "";
247
254
  const { ref: overflowRef, isTruncated: labelTruncated } = useTextOverflow({ lines: 1, content: selectedLabel, disabled: open });
248
255
  const [prevQuery, setPrevQuery] = useState(query);
@@ -356,6 +363,7 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
356
363
  id: control.id,
357
364
  role: "combobox",
358
365
  "aria-labelledby": wiring["aria-labelledby"],
366
+ "aria-label": control.labelId ? void 0 : ariaLabel,
359
367
  "aria-describedby": control.describedBy,
360
368
  "aria-invalid": control.invalid || void 0,
361
369
  "aria-required": control.required || void 0,
@@ -451,6 +459,165 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
451
459
  ] });
452
460
  return /* @__PURE__ */ jsx(Tooltip, { content: selectedLabel, disabled: !labelTruncated || open, children: triggerContent });
453
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 labelOf = (zone, at) => {
489
+ const offset = timeZoneOffset(zone, at);
490
+ return offset ? `${zone.replace(/_/g, " ")} (${offset})` : zone.replace(/_/g, " ");
491
+ };
492
+ var HOUR = 36e5;
493
+ var zoneList = null;
494
+ function zoneOptions() {
495
+ const now = Date.now();
496
+ if (!zoneList || now - zoneList.at > HOUR) {
497
+ const at = new Date(now);
498
+ zoneList = { at: now, options: timeZones().map((zone) => ({ value: zone, label: labelOf(zone, at) })) };
499
+ }
500
+ return zoneList.options;
501
+ }
502
+ function TimezoneSelect({ value, onChange, placeholder = "Search time zones\u2026", ...rest }) {
503
+ const zones = zoneOptions();
504
+ const stored = value ? canonicalTimeZone(value) : "";
505
+ const options = useMemo(() => {
506
+ if (!stored) {
507
+ const mine = browserTimeZone();
508
+ const label = zones.find((o) => o.value === mine)?.label ?? labelOf(mine, /* @__PURE__ */ new Date());
509
+ return [{ value: mine, label: `${label} \xB7 your time zone` }, ...zones.filter((o) => o.value !== mine)];
510
+ }
511
+ return zones.some((o) => o.value === stored) ? zones : [{ value: stored, label: labelOf(stored, /* @__PURE__ */ new Date()) }, ...zones];
512
+ }, [zones, stored]);
513
+ return /* @__PURE__ */ jsx(Combobox, { value: stored, onChange, options, placeholder, ...rest });
514
+ }
515
+ var MINUTE = 6e4;
516
+ var HOUR2 = 60 * MINUTE;
517
+ var DAY = 24 * HOUR2;
518
+ var LONGEST_WAIT = DAY;
519
+ 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"]';
520
+ var noChange = () => () => {
521
+ };
522
+ var inBrowser = () => true;
523
+ var onServer = () => false;
524
+ function toMillis(time) {
525
+ if (time instanceof Date) return time.getTime();
526
+ if (typeof time === "number") return time;
527
+ if (typeof time !== "string") return NaN;
528
+ const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(time.trim());
529
+ if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3])).getTime();
530
+ return Date.parse(time);
531
+ }
532
+ function thresholdOf(hours, from) {
533
+ if (typeof hours === "number" && Number.isFinite(hours) && hours >= 0) return hours;
534
+ const house = PREFERENCE_HOUSE_DEFAULTS.relativeThresholdHours;
535
+ warnOnce(from, `a threshold of ${String(hours)} isn't a number of hours, so the house's ${house} is used.`);
536
+ return house;
537
+ }
538
+ function midnight(t) {
539
+ const d = new Date(t);
540
+ d.setHours(0, 0, 0, 0);
541
+ return d.getTime();
542
+ }
543
+ function formatRelativeTime(time, options) {
544
+ const at = toMillis(time);
545
+ if (!Number.isFinite(at)) return "";
546
+ const now = options.now ?? Date.now();
547
+ const diff = at - now;
548
+ const age = Math.abs(diff);
549
+ if (age > thresholdOf(options.thresholdHours, "formatRelativeTime") * HOUR2) return new Intl.DateTimeFormat(formatLocale(), { dateStyle: "medium", timeStyle: "short" }).format(at);
550
+ const rtf = new Intl.RelativeTimeFormat(formatLocale(), { numeric: "auto" });
551
+ if (age < MINUTE) return rtf.format(0, "second");
552
+ if (age < HOUR2) return rtf.format(Math.trunc(diff / MINUTE), "minute");
553
+ if (age < DAY) return rtf.format(Math.trunc(diff / HOUR2), "hour");
554
+ return rtf.format(Math.round((midnight(at) - midnight(now)) / DAY), "day");
555
+ }
556
+ function useRelativeTimeFormat() {
557
+ const thresholdHours = useShellPreferences().relativeThresholdHours ?? PREFERENCE_HOUSE_DEFAULTS.relativeThresholdHours;
558
+ return (time) => formatRelativeTime(time, { thresholdHours });
559
+ }
560
+ function formatFullTime(time) {
561
+ const at = toMillis(time);
562
+ return Number.isFinite(at) ? new Intl.DateTimeFormat(formatLocale(), { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", timeZoneName: "short" }).format(at) : "";
563
+ }
564
+ function nextChange(at, now, threshold) {
565
+ const diff = at - now;
566
+ const age = Math.abs(diff);
567
+ let wait;
568
+ if (age > threshold) {
569
+ if (diff <= 0) return null;
570
+ wait = age - threshold + 1;
571
+ } else {
572
+ const step = age < HOUR2 ? MINUTE : HOUR2;
573
+ const untilStep = diff > 0 ? age % step + 1 : step - age % step;
574
+ wait = diff > 0 ? untilStep : Math.min(untilStep, threshold - age + 1);
575
+ }
576
+ return Number.isFinite(wait) ? Math.min(Math.max(1e3, wait), LONGEST_WAIT) : null;
577
+ }
578
+ function RelativeTime({ time, thresholdHours, className }) {
579
+ const shellThreshold = useShellPreferences().relativeThresholdHours;
580
+ const hours = thresholdOf(thresholdHours ?? shellThreshold ?? PREFERENCE_HOUSE_DEFAULTS.relativeThresholdHours, "RelativeTime");
581
+ const at = toMillis(time);
582
+ if (!Number.isFinite(at)) {
583
+ warnOnce("RelativeTime", `${JSON.stringify(time) ?? String(time)} isn't a time (an ISO string, a Date or milliseconds), so nothing is drawn.`);
584
+ return null;
585
+ }
586
+ return /* @__PURE__ */ jsx(RelativeTimeAt, { at, hours, className }, `${at}:${hours}`);
587
+ }
588
+ function RelativeTimeAt({ at, hours, className }) {
589
+ const inRows = useContext(RowsCtx);
590
+ const [now, setNow] = useState(() => Date.now());
591
+ const [inControl, setInControl] = useState(false);
592
+ const placed = useCallback((el) => {
593
+ const inside = !!el?.parentElement?.closest(CONTROL_ANCESTOR);
594
+ if (inside) el.removeAttribute("tabindex");
595
+ if (el) setInControl(inside);
596
+ }, []);
597
+ const mounted = useSyncExternalStore(noChange, inBrowser, onServer);
598
+ useEffect(() => {
599
+ const wait = nextChange(at, now, hours * HOUR2);
600
+ if (wait === null) return;
601
+ const timer = setTimeout(() => setNow(Date.now()), wait);
602
+ return () => clearTimeout(timer);
603
+ }, [at, now, hours]);
604
+ const full = formatFullTime(at);
605
+ return /* @__PURE__ */ jsx(Tooltip, { content: full, ref: placed, children: /* @__PURE__ */ jsxs(
606
+ "time",
607
+ {
608
+ tabIndex: inRows || inControl ? void 0 : 0,
609
+ dateTime: new Date(at).toISOString(),
610
+ "data-relative-time": "",
611
+ suppressHydrationWarning: true,
612
+ className: cn("rounded-[var(--ds-radius-sm)] focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2", className),
613
+ children: [
614
+ formatRelativeTime(at, { thresholdHours: hours, now }),
615
+ /* @__PURE__ */ jsx("span", { className: "sr-only", suppressHydrationWarning: true, children: `, ${full}` })
616
+ ]
617
+ },
618
+ mounted ? "browser" : "first"
619
+ ) });
620
+ }
454
621
  var CHECKBOX_SIZES = {
455
622
  sm: { box: "h-[16px] w-[16px]", glyph: 10, label: "text-xs" },
456
623
  md: { box: "h-[18px] w-[18px]", glyph: 12, label: "text-sm" }
@@ -750,7 +917,7 @@ function formatDate(d) {
750
917
  }
751
918
  function localeDayFirst() {
752
919
  try {
753
- const parts = new Intl.DateTimeFormat(void 0).formatToParts(new Date(2e3, 11, 25));
920
+ const parts = new Intl.DateTimeFormat(formatLocale()).formatToParts(new Date(2e3, 11, 25));
754
921
  return parts.findIndex((p) => p.type === "day") < parts.findIndex((p) => p.type === "month");
755
922
  } catch {
756
923
  return true;
@@ -1882,9 +2049,9 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
1882
2049
  useEffect(() => {
1883
2050
  const owner = inputRef.current?.form;
1884
2051
  if (!owner) return;
1885
- const clear = () => setRejected(null);
1886
- owner.addEventListener("submit", clear);
1887
- return () => owner.removeEventListener("submit", clear);
2052
+ const clear2 = () => setRejected(null);
2053
+ owner.addEventListener("submit", clear2);
2054
+ return () => owner.removeEventListener("submit", clear2);
1888
2055
  }, []);
1889
2056
  const invalid = error || rejected != null || !!waiting;
1890
2057
  const describedBy = [constraints ? constraintsId : null, field?.describedBy, rejected ? rejectedId : null, waiting ? waitingId : null].filter(Boolean).join(" ") || void 0;
@@ -3512,7 +3679,7 @@ var Alert = forwardRef(function Alert2({
3512
3679
  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)]")
3513
3680
  ),
3514
3681
  children: [
3515
- a.iconLeft && /* @__PURE__ */ jsx("span", { className: "inline-flex mr-ds-1", children: a.iconLeft }),
3682
+ a.iconLeft && /* @__PURE__ */ jsx("span", { className: "inline-flex mr-ds-1", children: slotIcon(a.iconLeft, 14, "an Alert action's iconLeft") }),
3516
3683
  a.label
3517
3684
  ]
3518
3685
  },
@@ -3587,7 +3754,7 @@ function focusTarget(el) {
3587
3754
  if (el.tabIndex >= 0 || /^(?:INPUT|SELECT|TEXTAREA|BUTTON)$/.test(el.tagName)) return el;
3588
3755
  return el.querySelector("[aria-checked='true'], [aria-selected='true']:not([tabindex='-1'])") ?? el.querySelector("input, select, textarea, button, [tabindex]:not([tabindex='-1'])") ?? el;
3589
3756
  }
3590
- function FormWrapper({ onSubmit, validationMode: validationModeProp, children, actions: actionsProp, actionsAlign: actionsAlignProp, onCancel, cancelLabel = "Cancel", focusFirstError = true, errorSummary = true, className, ref }) {
3757
+ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, actions: actionsProp, actionsAlign: actionsAlignProp, onCancel, cancelLabel = "Cancel", focusFirstError = true, errorSummary = true, fullWidth = false, className, ref }) {
3591
3758
  const preferences = useShellPreferences();
3592
3759
  const validationMode = validationModeProp ?? preferences.validationTiming ?? "onSubmit";
3593
3760
  const actionsAlign = actionsAlignProp ?? preferences.formActions?.align ?? "end";
@@ -3754,7 +3921,7 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
3754
3921
  f.message
3755
3922
  ] }, f.id || f.label)) }) }) : null;
3756
3923
  const actionsNode = actions && !drawerFooter ? /* @__PURE__ */ jsx("div", { "data-form-actions": "", className: cn("flex flex-wrap items-center gap-ds-2 pt-ds-2", actionsAlign === "end" ? "justify-end" : "justify-start"), children: actions }) : null;
3757
- return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsx(FormChangeCtx.Provider, { value: reportChange, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5 max-w-[var(--ds-form-max,none)]", className), noValidate: true, children: [
3924
+ return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsx(FormChangeCtx.Provider, { value: reportChange, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5 max-w-[var(--ds-form-max,calc(var(--ds-bp-md)_-_2*var(--ds-space-6)))]", className), style: fullWidth ? { "--ds-form-max": "none" } : void 0, noValidate: true, children: [
3758
3925
  summaryNode && /* @__PURE__ */ jsx("div", { ref: summaryRef, "data-form-error-summary": "", tabIndex: -1, className: "rounded-[var(--ds-radius-md)] outline-none focus-visible:shadow-[var(--ds-shadow-focus)]", children: summaryNode }),
3759
3926
  children,
3760
3927
  actionsNode
@@ -4062,102 +4229,6 @@ function PanelCheckbox({ checked, indeterminate, onClick, label }) {
4062
4229
  }
4063
4230
  );
4064
4231
  }
4065
-
4066
- // ../../showcase/src/lib/initials.ts
4067
- function initialsOf(name) {
4068
- return name.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((word) => Array.from(word)[0] ?? "").join("").toUpperCase();
4069
- }
4070
- function toInitials(value) {
4071
- const s = value.trim();
4072
- if (!s) return "";
4073
- if (!/\s/.test(s) && Array.from(s).length <= 3) return s;
4074
- return initialsOf(s);
4075
- }
4076
- var sizeStyles2 = {
4077
- sm: "h-8 w-8 text-xs",
4078
- md: "h-10 w-10 text-sm",
4079
- lg: "h-12 w-12 text-base"
4080
- };
4081
- var paletteStyles = {
4082
- 1: "bg-[var(--ds-palette-1-bg,var(--ds-bg-muted))] text-[var(--ds-palette-1-text,var(--ds-text-secondary))]",
4083
- 2: "bg-[var(--ds-palette-2-bg,var(--ds-bg-muted))] text-[var(--ds-palette-2-text,var(--ds-text-secondary))]",
4084
- 3: "bg-[var(--ds-palette-3-bg,var(--ds-bg-muted))] text-[var(--ds-palette-3-text,var(--ds-text-secondary))]",
4085
- 4: "bg-[var(--ds-palette-4-bg,var(--ds-bg-muted))] text-[var(--ds-palette-4-text,var(--ds-text-secondary))]",
4086
- 5: "bg-[var(--ds-palette-5-bg,var(--ds-bg-muted))] text-[var(--ds-palette-5-text,var(--ds-text-secondary))]"
4087
- };
4088
- function paletteFor(seed) {
4089
- let h = 0;
4090
- for (const ch of seed) h = h * 31 + ch.charCodeAt(0) >>> 0;
4091
- return h % 5 + 1;
4092
- }
4093
- function colorStyles(color, seed) {
4094
- if (color === "accent") return "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]";
4095
- if (color === "neutral") return "bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]";
4096
- return paletteStyles[color === "auto" ? paletteFor(seed) : color];
4097
- }
4098
- function PresenceMark({ status }) {
4099
- return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 10 10", width: "10", height: "10", "aria-hidden": "true", focusable: "false", "data-presence": status, className: "block", children: [
4100
- status === "online" && /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "5", className: "fill-[var(--ds-status-success)]" }),
4101
- status === "away" && /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "4", fill: "none", strokeWidth: "2", className: "stroke-[var(--ds-status-warning)]" }),
4102
- status === "busy" && /* @__PURE__ */ jsxs(Fragment, { children: [
4103
- /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "5", className: "fill-[var(--ds-status-error)]" }),
4104
- /* @__PURE__ */ jsx("rect", { x: "2.5", y: "4.1", width: "5", height: "1.8", rx: "0.9", className: "fill-[var(--ds-bg-canvas)]" })
4105
- ] }),
4106
- status === "offline" && /* @__PURE__ */ jsxs(Fragment, { children: [
4107
- /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "4", fill: "none", strokeWidth: "2", className: "stroke-[var(--ds-text-muted)]" }),
4108
- /* @__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)]" })
4109
- ] })
4110
- ] });
4111
- }
4112
- function Avatar({ initials, src, alt, size = "md", status, color = "auto", className }) {
4113
- const who = alt ?? initials ?? "";
4114
- const named = status ? [who, status].filter(Boolean).join(", ") : void 0;
4115
- const base = cn(
4116
- "inline-flex items-center justify-center font-medium shrink-0",
4117
- "rounded-[var(--ds-radius-full)]",
4118
- sizeStyles2[size],
4119
- className
4120
- );
4121
- const avatarElement = src ? /* @__PURE__ */ jsx(
4122
- "img",
4123
- {
4124
- "data-avatar": "",
4125
- src,
4126
- alt: named ?? alt ?? initials ?? "",
4127
- className: cn(base, "object-cover")
4128
- }
4129
- ) : /* @__PURE__ */ jsx(
4130
- "div",
4131
- {
4132
- "data-avatar": "",
4133
- role: named ? "img" : void 0,
4134
- "aria-label": named,
4135
- className: cn(
4136
- base,
4137
- colorStyles(color, alt ?? initials ?? ""),
4138
- "border-[length:var(--ds-border-width)] border-transparent"
4139
- ),
4140
- children: initials != null ? toInitials(initials) : null
4141
- }
4142
- );
4143
- if (!status) return avatarElement;
4144
- return /* @__PURE__ */ jsxs("div", { className: "relative inline-flex", children: [
4145
- avatarElement,
4146
- /* @__PURE__ */ jsx(
4147
- "span",
4148
- {
4149
- className: cn(
4150
- "absolute",
4151
- size === "sm" && "bottom-[-4px] right-[-4px]",
4152
- size === "md" && "bottom-[-2px] right-[-2px]",
4153
- size === "lg" && "bottom-[0px] right-[0px]"
4154
- ),
4155
- "aria-hidden": "true",
4156
- 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 }) })
4157
- }
4158
- )
4159
- ] });
4160
- }
4161
4232
  function MentionInput({
4162
4233
  value: controlledValue,
4163
4234
  onChange: onChangeProp,
@@ -4165,8 +4236,12 @@ function MentionInput({
4165
4236
  trigger = "@",
4166
4237
  placeholder,
4167
4238
  disabled,
4168
- className
4239
+ className,
4240
+ error = false,
4241
+ "aria-label": ariaLabel,
4242
+ ...wiring
4169
4243
  }) {
4244
+ const control = useFieldControl({ ...wiring, error: error || void 0 });
4170
4245
  const [internalValue, setInternalValue] = useState("");
4171
4246
  const value = controlledValue ?? internalValue;
4172
4247
  const onChange = useReportedChange(onChangeProp, value);
@@ -4174,14 +4249,14 @@ function MentionInput({
4174
4249
  const [showPopup, setShowPopup] = useState(false);
4175
4250
  const [activeIndex, setActiveIndex] = useState(0);
4176
4251
  const [triggerStart, setTriggerStart] = useState(-1);
4177
- const [popupPos, setPopupPos] = useState({ top: 0, left: 0 });
4252
+ const [anchor, setAnchor] = useState(null);
4178
4253
  const inputRef = useRef(null);
4179
4254
  const popupRef = useRef(null);
4180
4255
  const mirrorRef = useRef(null);
4181
- const filtered = suggestions.filter(
4182
- (s) => s.label.toLowerCase().includes(query.toLowerCase()) || s.description?.toLowerCase().includes(query.toLowerCase())
4183
- );
4184
- useOverlayLayer(showPopup && filtered.length > 0);
4256
+ const listId = useId();
4257
+ const { items: filtered, more } = shownMentions(matchMentions(suggestions, query));
4258
+ const listShown = showPopup && filtered.length > 0;
4259
+ useOverlayLayer(listShown);
4185
4260
  const updateValue = useCallback(
4186
4261
  (v) => {
4187
4262
  if (controlledValue === void 0) setInternalValue(v);
@@ -4224,13 +4299,15 @@ function MentionInput({
4224
4299
  const span = document.createElement("span");
4225
4300
  span.textContent = trigger;
4226
4301
  mirror.appendChild(span);
4227
- const rect = el.getBoundingClientRect();
4228
4302
  const spanRect = span.getBoundingClientRect();
4229
4303
  const mirrorRect = mirror.getBoundingClientRect();
4230
- setPopupPos({
4231
- top: rect.top + (spanRect.top - mirrorRect.top) + span.offsetHeight + 4,
4232
- left: rect.left + (spanRect.left - mirrorRect.left)
4233
- });
4304
+ setAnchor({ x: spanRect.left - mirrorRect.left, y: spanRect.top - mirrorRect.top, width: spanRect.width, height: span.offsetHeight });
4305
+ };
4306
+ const anchorRect = () => {
4307
+ const el = inputRef.current;
4308
+ if (!el || !anchor) return null;
4309
+ const field = el.getBoundingClientRect();
4310
+ return new DOMRect(field.left + anchor.x, field.top + anchor.y - el.scrollTop, anchor.width, anchor.height);
4234
4311
  };
4235
4312
  const insertMention = (suggestion) => {
4236
4313
  const el = inputRef.current;
@@ -4249,13 +4326,15 @@ function MentionInput({
4249
4326
  });
4250
4327
  };
4251
4328
  const handleKeyDown = (e) => {
4252
- if (!showPopup || filtered.length === 0) return;
4329
+ if (!listShown) return;
4253
4330
  if (e.key === "ArrowDown") {
4254
4331
  e.preventDefault();
4255
4332
  setActiveIndex((i) => (i + 1) % filtered.length);
4256
4333
  } else if (e.key === "ArrowUp") {
4257
4334
  e.preventDefault();
4258
4335
  setActiveIndex((i) => (i - 1 + filtered.length) % filtered.length);
4336
+ } else if (e.key === "Tab" && e.shiftKey) {
4337
+ flushSync(() => setShowPopup(false));
4259
4338
  } else if (e.key === "Enter" || e.key === "Tab") {
4260
4339
  e.preventDefault();
4261
4340
  insertMention(filtered[activeIndex]);
@@ -4279,21 +4358,30 @@ function MentionInput({
4279
4358
  "textarea",
4280
4359
  {
4281
4360
  ref: inputRef,
4361
+ id: control.id,
4362
+ "aria-labelledby": wiring["aria-labelledby"],
4363
+ "aria-label": control.labelId ? void 0 : ariaLabel,
4364
+ "aria-describedby": control.describedBy,
4365
+ "aria-invalid": control.invalid || void 0,
4366
+ "aria-required": control.required || void 0,
4282
4367
  value,
4283
4368
  onChange: handleInput,
4284
4369
  onKeyDown: handleKeyDown,
4370
+ "aria-autocomplete": "list",
4371
+ "aria-controls": listShown ? listId : void 0,
4372
+ "aria-activedescendant": listShown ? mentionOptionId(listId, activeIndex) : void 0,
4285
4373
  placeholder,
4286
4374
  disabled,
4287
4375
  rows: 3,
4288
4376
  className: cn(
4289
4377
  "flex w-full px-ds-3 py-ds-2 text-sm resize-none",
4290
4378
  "bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
4291
- "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
4379
+ "border-[length:var(--ds-border-width)]",
4380
+ control.invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-input-border-hover)]",
4292
4381
  "rounded-[var(--ds-radius-md)]",
4293
4382
  "shadow-[var(--ds-input-shadow)]",
4294
4383
  "placeholder:text-[var(--ds-text-muted)]",
4295
- "hover:border-[var(--ds-input-border-hover)]",
4296
- FOCUS_RING,
4384
+ control.invalid ? ERROR_FOCUS_RING : FOCUS_RING,
4297
4385
  "disabled:cursor-not-allowed disabled:opacity-disabled disabled:hover:border-[var(--ds-input-border)]",
4298
4386
  "transition-colors duration-[var(--ds-transition-speed)]"
4299
4387
  )
@@ -4307,59 +4395,19 @@ function MentionInput({
4307
4395
  className: "fixed top-0 left-0 -z-50 opacity-0 pointer-events-none"
4308
4396
  }
4309
4397
  ),
4310
- showPopup && filtered.length > 0 && createPortal(
4311
- /* @__PURE__ */ jsx(
4312
- "div",
4313
- {
4314
- ref: popupRef,
4315
- role: "listbox",
4316
- className: cn(
4317
- "fixed z-[var(--ds-z-popover)] min-w-[200px] max-h-[200px] overflow-y-auto",
4318
- "bg-[var(--ds-bg-surface-elevated)]",
4319
- "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
4320
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
4321
- "rounded-[var(--ds-radius-md)] shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
4322
- "py-ds-1"
4323
- ),
4324
- style: { top: popupPos.top, left: popupPos.left },
4325
- children: filtered.map((s, i) => /* @__PURE__ */ jsxs(
4326
- "button",
4327
- {
4328
- type: "button",
4329
- role: "option",
4330
- "aria-selected": i === activeIndex,
4331
- className: cn(
4332
- "flex items-center gap-ds-2.5 w-full px-ds-3 py-ds-1.5 text-left text-sm cursor-pointer",
4333
- "transition-colors duration-[var(--ds-transition-speed)]",
4334
- 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)]"
4335
- ),
4336
- onMouseDown: (e) => {
4337
- e.preventDefault();
4338
- insertMention(s);
4339
- },
4340
- onMouseEnter: () => setActiveIndex(i),
4341
- children: [
4342
- /* @__PURE__ */ jsx(
4343
- Avatar,
4344
- {
4345
- src: s.avatar,
4346
- initials: s.label.charAt(0).toUpperCase(),
4347
- alt: s.label,
4348
- size: "sm",
4349
- className: "!h-6 !w-6 !text-2xs"
4350
- }
4351
- ),
4352
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
4353
- /* @__PURE__ */ jsx("div", { className: "font-medium text-[var(--ds-text-primary)] truncate", children: s.label }),
4354
- s.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] truncate", children: s.description })
4355
- ] })
4356
- ]
4357
- },
4358
- s.id
4359
- ))
4360
- }
4361
- ),
4362
- document.body
4398
+ listShown && /* @__PURE__ */ jsx(
4399
+ MentionList,
4400
+ {
4401
+ id: listId,
4402
+ label: "Suggestions",
4403
+ items: filtered,
4404
+ more,
4405
+ activeIndex,
4406
+ onActiveIndexChange: setActiveIndex,
4407
+ onPick: insertMention,
4408
+ anchorRect,
4409
+ listRef: popupRef
4410
+ }
4363
4411
  )
4364
4412
  ] });
4365
4413
  }
@@ -5022,7 +5070,7 @@ function CardGrid({ minWidth, maxColumns = 4, compare = false, gap = "var(--ds-s
5022
5070
  }
5023
5071
  );
5024
5072
  }
5025
- var sizeStyles3 = {
5073
+ var sizeStyles2 = {
5026
5074
  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" },
5027
5075
  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" },
5028
5076
  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" }
@@ -5068,7 +5116,7 @@ var DescriptionList = forwardRef(function DescriptionList2({
5068
5116
  stackBelow: stackBelowProp,
5069
5117
  className
5070
5118
  }, ref) {
5071
- const s = sizeStyles3[size];
5119
+ const s = sizeStyles2[size];
5072
5120
  const stackBelow = stackBelowProp ?? (columns > 1 ? "sm" : void 0);
5073
5121
  const templateClass = (layout) => columns > 1 && stackBelow !== "none" ? autoColumnClasses[layout][columns] : columnClasses[columns];
5074
5122
  if (orientation === "vertical") {
@@ -5353,6 +5401,9 @@ var PINNED_LAYERS = cn(
5353
5401
  );
5354
5402
  var PIN_SHADOW = "oklch(0 0 0 / 0.18)";
5355
5403
  var ROW_CONTROL = `${FOCUSABLE}, label, [role="button"], [role="checkbox"], [role="switch"], [role="menuitem"], [role="link"]`;
5404
+ function clickIsCard(e) {
5405
+ return clickIsRows(e) && !(e.target instanceof Element && e.target.closest("[data-card-detail]"));
5406
+ }
5356
5407
  function clickIsRows(e) {
5357
5408
  const target = e.target;
5358
5409
  if (!(target instanceof Element) || !e.currentTarget.contains(target)) return false;
@@ -5361,17 +5412,31 @@ function clickIsRows(e) {
5361
5412
  const control = target.closest(ROW_CONTROL);
5362
5413
  return !control || control === e.currentTarget || !e.currentTarget.contains(control);
5363
5414
  }
5415
+ var ISO_MOMENT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?$/;
5364
5416
  function sortableValue(v) {
5365
5417
  if (v === null || v === void 0 || v === "") return void 0;
5366
5418
  if (v instanceof Date) return v.getTime();
5419
+ if (typeof v === "string" && ISO_MOMENT.test(v)) {
5420
+ const at = Date.parse(v);
5421
+ if (Number.isFinite(at)) return at;
5422
+ }
5367
5423
  if (typeof v === "string" || typeof v === "number") return v;
5368
5424
  if (typeof v === "boolean") return v ? 1 : 0;
5369
5425
  return isValidElement(v) || typeof v === "object" ? null : String(v);
5370
5426
  }
5371
- var COLLATOR = new Intl.Collator(void 0, { numeric: true });
5427
+ var COLLATORS = /* @__PURE__ */ new Map();
5428
+ function collator() {
5429
+ const locale = formatLocale() ?? "";
5430
+ let c = COLLATORS.get(locale);
5431
+ if (!c) {
5432
+ c = new Intl.Collator(locale || void 0, { numeric: true });
5433
+ COLLATORS.set(locale, c);
5434
+ }
5435
+ return c;
5436
+ }
5372
5437
  function compareValues(a, b) {
5373
5438
  if (typeof a === "number" && typeof b === "number") return a - b;
5374
- return COLLATOR.compare(String(a), String(b));
5439
+ return collator().compare(String(a), String(b));
5375
5440
  }
5376
5441
  var UNIT_SCALE = {
5377
5442
  "": 1,
@@ -5693,9 +5758,16 @@ function Table({
5693
5758
  const expandedKey = expanded.map(String).join("");
5694
5759
  const shownBefore = useRef(/* @__PURE__ */ new Set());
5695
5760
  const pendingScroll = useRef(null);
5761
+ const scrollFrame = useRef(0);
5696
5762
  const scrollToRow = useCallback((key) => {
5697
- const row = rootRef.current?.querySelector(`[data-row-key="${CSS.escape(key)}"], [data-row-index="${CSS.escape(key)}"]`);
5698
- if (row && typeof row.scrollIntoView === "function") row.scrollIntoView({ block: "nearest" });
5763
+ cancelAnimationFrame(scrollFrame.current);
5764
+ scrollFrame.current = requestAnimationFrame(() => {
5765
+ const row = rootRef.current?.querySelector(`[data-row-key="${CSS.escape(key)}"], [data-row-index="${CSS.escape(key)}"]`);
5766
+ if (!row || typeof row.scrollIntoView !== "function") return;
5767
+ const panel = row.nextElementSibling?.querySelector("[data-row-panel]") ? row.nextElementSibling : null;
5768
+ panel?.scrollIntoView({ block: "nearest" });
5769
+ row.scrollIntoView({ block: "nearest" });
5770
+ });
5699
5771
  }, [rootRef]);
5700
5772
  useEffect(() => {
5701
5773
  const now = new Set(expanded.map(String));
@@ -5769,11 +5841,19 @@ function Table({
5769
5841
  if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
5770
5842
  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 });
5771
5843
  }
5772
- 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: [
5844
+ 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: [
5773
5845
  selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
5774
5846
  drawn.map(({ row, originalIdx }) => {
5775
5847
  const isSelected = selectedSet.has(originalIdx);
5776
5848
  const id = idOf(row, originalIdx);
5849
+ const opens = !!expandable && !!renderExpanded;
5850
+ const isExpanded = opens && expandedSet.has(String(id));
5851
+ const toggleCard = (card) => {
5852
+ const closing = isExpanded;
5853
+ const inDetail = closing && card.querySelector("[data-card-detail]")?.contains(document.activeElement);
5854
+ toggleExpand(id);
5855
+ if (inDetail) card.querySelector("[data-card-toggle]")?.focus();
5856
+ };
5777
5857
  return /* @__PURE__ */ jsxs(
5778
5858
  "div",
5779
5859
  {
@@ -5784,10 +5864,15 @@ function Table({
5784
5864
  "rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
5785
5865
  "p-ds-4 space-y-ds-3",
5786
5866
  isSelected && ACTIVE_RING,
5787
- onRowClick && "cursor-pointer hover:bg-[var(--ds-bg-muted)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
5867
+ onRowClick && "cursor-pointer hover:bg-[var(--ds-bg-muted)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
5868
+ // with no onRowClick a tap on the card opens and closes it, as a click on the row does; the toggle is the
5869
+ // keyboard's way
5870
+ !onRowClick && canOpenByClick && "cursor-pointer"
5788
5871
  ),
5789
5872
  onClick: onRowClick ? (e) => {
5790
- if (clickIsRows(e)) onRowClick(row, originalIdx);
5873
+ if (clickIsCard(e)) onRowClick(row, originalIdx);
5874
+ } : canOpenByClick ? (e) => {
5875
+ if (clickIsCard(e)) toggleCard(e.currentTarget);
5791
5876
  } : void 0,
5792
5877
  tabIndex: onRowClick ? 0 : void 0,
5793
5878
  onKeyDown: onRowClick ? (e) => {
@@ -5804,13 +5889,42 @@ function Table({
5804
5889
  /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: col.header }),
5805
5890
  /* @__PURE__ */ jsx(CardValue, { value: row[col.key], id: lead + c === nameIndex ? `${headingId}-card-name-${idPart(id)}` : void 0 })
5806
5891
  ] }, col.key)),
5807
- expandable && renderExpanded && /* @__PURE__ */ jsx("div", { className: "pt-ds-2 border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-sm text-[var(--ds-text-secondary)]", children: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) }) })
5892
+ opens && // Alert's disclosure: a button that says whether it is open, at the card's foot, the detail below it, so
5893
+ // the control the user pressed stays where it was. Its name carries the row's (T15).
5894
+ /* @__PURE__ */ jsxs("div", { className: "pt-ds-1", children: [
5895
+ /* @__PURE__ */ jsxs(
5896
+ "button",
5897
+ {
5898
+ type: "button",
5899
+ "data-card-toggle": "",
5900
+ "aria-expanded": isExpanded,
5901
+ ...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-card-toggle-${idPart(id)} ${headingId}-card-name-${idPart(id)}` } : {},
5902
+ onClick: (e) => {
5903
+ e.stopPropagation();
5904
+ toggleCard(e.currentTarget.closest("[data-row]"));
5905
+ },
5906
+ className: cn(
5907
+ // at least 24 px tall: the card around it is a target too, so its own box must meet the size (WCAG 2.5.8)
5908
+ "inline-flex min-h-[24px] items-center gap-ds-1 text-xs font-medium cursor-pointer",
5909
+ "transition-colors duration-[var(--ds-transition-speed)]",
5910
+ "text-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-muted)]",
5911
+ "rounded-[var(--ds-radius-sm)] px-ds-1.5 py-ds-0.5 -mx-ds-1.5",
5912
+ "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
5913
+ ),
5914
+ children: [
5915
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 12, className: cn("transition-transform duration-[var(--ds-transition-speed)]", isExpanded && "rotate-90") }),
5916
+ /* @__PURE__ */ jsx("span", { id: `${headingId}-card-toggle-${idPart(id)}`, children: isExpanded ? "Hide details" : "Show details" })
5917
+ ]
5918
+ }
5919
+ ),
5920
+ isExpanded && /* @__PURE__ */ jsx("div", { "data-card-detail": "", className: "mt-ds-3 pt-ds-3 border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-sm text-[var(--ds-text-secondary)]", children: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) }) })
5921
+ ] })
5808
5922
  ]
5809
5923
  },
5810
5924
  String(id)
5811
5925
  );
5812
5926
  })
5813
- ] }) });
5927
+ ] }) }) });
5814
5928
  return withControl(title ? titledCards(cards) : cards);
5815
5929
  }
5816
5930
  const cellCount = columns.length + lead;
@@ -5879,7 +5993,7 @@ function Table({
5879
5993
  );
5880
5994
  })
5881
5995
  ] }) }),
5882
- /* @__PURE__ */ jsx("tbody", { children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
5996
+ /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
5883
5997
  "td",
5884
5998
  {
5885
5999
  colSpan: cellCount,
@@ -6008,7 +6122,7 @@ function Table({
6008
6122
  }
6009
6123
  ) })
6010
6124
  ] }, String(id));
6011
- }) })
6125
+ }) }) })
6012
6126
  ] });
6013
6127
  const region = scrollable || regionFocused ? { tabIndex: 0, role: "region", ...title ? { "aria-labelledby": titleId } : { "aria-label": ariaLabel ?? "Table" } } : {};
6014
6128
  return withControl(
@@ -6040,7 +6154,7 @@ function Table({
6040
6154
  },
6041
6155
  ...fade,
6042
6156
  ...region,
6043
- className: cn("min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
6157
+ className: cn("relative min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
6044
6158
  children: table
6045
6159
  }
6046
6160
  )
@@ -6070,6 +6184,9 @@ var indicatorInset = {
6070
6184
  md: "4px",
6071
6185
  lg: "4px"
6072
6186
  };
6187
+ function segmentRadius(inset, bordered) {
6188
+ return `max(var(--ds-radius-sm), calc(var(--ds-radius-md) - ${inset}${bordered ? " - var(--ds-border-width)" : ""}))`;
6189
+ }
6073
6190
  function SegmentedControl({
6074
6191
  value,
6075
6192
  onChange: onChangeProp,
@@ -6211,19 +6328,26 @@ function SegmentedControl({
6211
6328
  containerPadding[size],
6212
6329
  containerHeight[size],
6213
6330
  "bg-[var(--ds-bg-muted)]",
6214
- "rounded-[var(--ds-radius-lg)]",
6215
- // Sprint 25.14 A20: the track's edge is a control's, at 3:1
6216
- variant === "default" && "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
6331
+ // The owner's review of 1 October 2026: the frame's corner is a field's, so the two change together with the
6332
+ // theme's radius; the segments inside sit concentric with it (SEGMENT_RADIUS)
6333
+ "rounded-[var(--ds-radius-md)]",
6334
+ // The frame's edge is a button's: each segment is a labelled button, so the frame isn't what identifies the
6335
+ // control, and WCAG 1.4.11 asks no 3:1 of it. The selected segment carries the 3:1 edge instead (below)
6336
+ variant === "default" && "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
6217
6337
  control.invalid && "border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]",
6218
6338
  className
6219
6339
  ),
6340
+ style: { "--ds-segment-radius": segmentRadius(indicatorInset[size], variant === "default" || !!control.invalid) },
6220
6341
  children: [
6221
6342
  /* @__PURE__ */ jsx(
6222
6343
  "div",
6223
6344
  {
6224
6345
  className: cn(
6225
- "absolute rounded-[var(--ds-radius-md)]",
6346
+ "absolute rounded-[var(--ds-segment-radius)]",
6226
6347
  "bg-[var(--ds-bg-surface)]",
6348
+ // The selected state is what the control shows, so its edge is the one at 3:1 (WCAG 1.4.11), against the
6349
+ // frame's fill and its own: the surface on the muted fill alone measures 1.05–1.46:1 across the presets
6350
+ "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
6227
6351
  variant === "default" && "shadow-[var(--ds-shadow-sm)]",
6228
6352
  "transition-all motion-reduce:transition-none"
6229
6353
  ),
@@ -6254,7 +6378,7 @@ function SegmentedControl({
6254
6378
  className: cn(
6255
6379
  "relative z-10 inline-flex items-center justify-center self-stretch font-medium whitespace-nowrap",
6256
6380
  fullWidth && "flex-1",
6257
- "rounded-[var(--ds-radius-md)]",
6381
+ "rounded-[var(--ds-segment-radius)]",
6258
6382
  "transition-colors cursor-pointer",
6259
6383
  "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
6260
6384
  sizes2[size],
@@ -6465,7 +6589,7 @@ function OverflowPopover({
6465
6589
  {
6466
6590
  ref: floatingRef,
6467
6591
  role: "dialog",
6468
- "aria-label": date.toLocaleDateString(void 0, { weekday: "long", month: "long", day: "numeric" }),
6592
+ "aria-label": date.toLocaleDateString(formatLocale(), { weekday: "long", month: "long", day: "numeric" }),
6469
6593
  className: cn(
6470
6594
  "fixed z-[var(--ds-z-popover)] w-56 max-h-48 overflow-y-auto",
6471
6595
  "bg-[var(--ds-bg-surface-elevated)]",
@@ -6479,7 +6603,7 @@ function OverflowPopover({
6479
6603
  onClick: (e) => e.stopPropagation(),
6480
6604
  onMouseDown: (e) => e.stopPropagation(),
6481
6605
  children: [
6482
- /* @__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" }) }),
6606
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-1", children: date.toLocaleDateString(formatLocale(), { weekday: "short", month: "short", day: "numeric" }) }),
6483
6607
  events.map((event) => /* @__PURE__ */ jsx(
6484
6608
  EventBar,
6485
6609
  {
@@ -6745,7 +6869,7 @@ function WeekView({
6745
6869
  ),
6746
6870
  onClick: () => onDayClick?.(day),
6747
6871
  children: [
6748
- /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] font-medium", children: day.toLocaleDateString(void 0, { weekday: "short" }) }),
6872
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] font-medium", children: day.toLocaleDateString(formatLocale(), { weekday: "short" }) }),
6749
6873
  /* @__PURE__ */ jsx(
6750
6874
  "div",
6751
6875
  {
@@ -6938,7 +7062,7 @@ function DayCellWithPopover({
6938
7062
  style: { top: pos.top, left: pos.left },
6939
7063
  role: "tooltip",
6940
7064
  children: [
6941
- /* @__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" }) }),
7065
+ /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-0.5", children: day.toLocaleDateString(formatLocale(), { weekday: "short", month: "short", day: "numeric" }) }),
6942
7066
  dayEvents.map((event) => /* @__PURE__ */ jsx(
6943
7067
  EventBar,
6944
7068
  {
@@ -7177,7 +7301,7 @@ function CompactDayCell({
7177
7301
  style: { top: pos.top, left: pos.left },
7178
7302
  role: "tooltip",
7179
7303
  children: [
7180
- /* @__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" }) }),
7304
+ /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium text-[var(--ds-text-muted)] px-ds-1 mb-ds-0.5", children: day.toLocaleDateString(formatLocale(), { weekday: "short", month: "short", day: "numeric" }) }),
7181
7305
  dayEvents.map((event) => /* @__PURE__ */ jsx(
7182
7306
  EventBar,
7183
7307
  {
@@ -7369,16 +7493,16 @@ function MonthDropdown({
7369
7493
  )
7370
7494
  ] }),
7371
7495
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-ds-1", children: MONTH_NAMES_SHORT.map((name, i) => {
7372
- const isActive = i === currentMonth && browseYear === currentYear;
7496
+ const isActive2 = i === currentMonth && browseYear === currentYear;
7373
7497
  return /* @__PURE__ */ jsx(
7374
7498
  "button",
7375
7499
  {
7376
7500
  className: cn(
7377
7501
  "px-ds-2 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)] cursor-pointer transition-colors",
7378
7502
  "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7379
- isActive ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
7503
+ isActive2 ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
7380
7504
  ),
7381
- "data-current": isActive || void 0,
7505
+ "data-current": isActive2 || void 0,
7382
7506
  onClick: () => {
7383
7507
  returnFocus();
7384
7508
  onSelect(new Date(browseYear, i, 1));
@@ -7865,7 +7989,7 @@ var defaultIcons = {
7865
7989
  };
7866
7990
  var FRAME_ICON_SIZE = 28;
7867
7991
  function renderIcon(icon) {
7868
- if (typeof icon === "string") return /* @__PURE__ */ jsx(Icon, { name: icon, size: FRAME_ICON_SIZE, className: "text-[var(--ds-text-muted)]" });
7992
+ if (typeof icon === "string") return /* @__PURE__ */ jsx(Icon, { name: icon, size: FRAME_ICON_SIZE, className: "text-[var(--ds-text-muted)]", from: "EmptyState's icon" });
7869
7993
  if (isValidElement(icon) && icon.type === Icon) return cloneElement(icon, { size: FRAME_ICON_SIZE });
7870
7994
  return icon;
7871
7995
  }
@@ -7966,7 +8090,7 @@ function TableToolbar({
7966
8090
  const iconSize = size === "sm" ? 14 : 16;
7967
8091
  const count = activeFilterCount ?? activeFilters?.length ?? 0;
7968
8092
  const hasChips = !!activeFilters?.length;
7969
- const inPane = useContext(SplitPaneCtx);
8093
+ const inPane = !!useContext(SplitPaneCtx);
7970
8094
  const searchFills = inPane || !primaryFilter && !filters && !actions;
7971
8095
  const hasControls = !!(search || primaryFilter || filters || actions);
7972
8096
  const noun = (n) => n === 1 ? resultNoun[0] : resultNoun[1];
@@ -8044,7 +8168,7 @@ function TableToolbar({
8044
8168
  var ICON_TEXT_OFFSET = "calc((2rem - 1.25rem) / 2)";
8045
8169
  function Marker({ item, vertical }) {
8046
8170
  if (item.icon) {
8047
- 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 });
8171
+ 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") });
8048
8172
  }
8049
8173
  return /* @__PURE__ */ jsx(
8050
8174
  "div",
@@ -8091,7 +8215,7 @@ function ExpandableDescription({ children, className }) {
8091
8215
  );
8092
8216
  }
8093
8217
  function HorizontalLayout({ items, minItemWidth, className }) {
8094
- return /* @__PURE__ */ jsx("div", { "data-timeline-row": "", className: cn("flex items-start overflow-x-auto snap-x", className), children: items.map((item, i) => {
8218
+ return /* @__PURE__ */ jsx("div", { "data-timeline-row": "", className: cn("relative flex items-start overflow-x-auto snap-x", className), children: items.map((item, i) => {
8095
8219
  const isFirst = i === 0;
8096
8220
  const isLast = i === items.length - 1;
8097
8221
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 shrink-0 flex-col items-center snap-start", style: { minWidth: minItemWidth }, children: [
@@ -8124,8 +8248,8 @@ function HorizontalLayout({ items, minItemWidth, className }) {
8124
8248
  ] }, i);
8125
8249
  }) });
8126
8250
  }
8127
- var EXACT = new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" });
8128
- var EXACT_DAY = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
8251
+ var EXACT = { format: (d) => new Intl.DateTimeFormat(formatLocale(), { dateStyle: "medium", timeStyle: "short" }).format(d) };
8252
+ var EXACT_DAY = { format: (d) => new Intl.DateTimeFormat(formatLocale(), { dateStyle: "medium" }).format(d) };
8129
8253
  var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
8130
8254
  function exactTime(value) {
8131
8255
  if (typeof value === "string") {
@@ -8140,6 +8264,9 @@ function exactTime(value) {
8140
8264
  return Number.isNaN(date.getTime()) ? null : { iso: date.toISOString(), text: EXACT.format(date) };
8141
8265
  }
8142
8266
  function ItemTime({ item }) {
8267
+ if (item.time !== void 0) {
8268
+ 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 }) });
8269
+ }
8143
8270
  const exact = item.dateTime ? exactTime(item.dateTime) : null;
8144
8271
  if (!item.timestamp && !exact) return null;
8145
8272
  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: [
@@ -8177,7 +8304,7 @@ function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 20
8177
8304
  }, [ref]);
8178
8305
  const fits = width === 0 || width >= items.length * minItemWidth;
8179
8306
  const horizontal = orientation === "horizontal" || orientation === "responsive" && fits;
8180
- 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 }) });
8307
+ 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 }) }) });
8181
8308
  if (!pager) return list;
8182
8309
  return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
8183
8310
  list,
@@ -8285,12 +8412,26 @@ function Kbd({ children, className }) {
8285
8412
  }
8286
8413
  );
8287
8414
  }
8415
+
8416
+ // ../../showcase/src/lib/nested-items.ts
8417
+ function holdsCurrent(items, isCurrent) {
8418
+ return !!items?.some((item) => isCurrent(item) || holdsCurrent(item.children, isCurrent));
8419
+ }
8288
8420
  function TruncLabel2({ children }) {
8289
8421
  const { ref, isTruncated } = useTextOverflow({ lines: 1 });
8290
8422
  const label = /* @__PURE__ */ jsx("span", { ref, className: "truncate", children });
8291
8423
  if (!isTruncated) return label;
8292
8424
  return /* @__PURE__ */ jsx(Tooltip, { content: children, children: label });
8293
8425
  }
8426
+ function foldersHolding(nodes, selected) {
8427
+ const ids = [];
8428
+ for (const node of nodes) {
8429
+ if (!holdsCurrent(node.children, (n) => selected.has(n.id))) continue;
8430
+ ids.push(node.id, ...foldersHolding(node.children, selected));
8431
+ }
8432
+ return ids;
8433
+ }
8434
+ var inTree = (nodes, id) => holdsCurrent(nodes, (n) => n.id === id);
8294
8435
  function allDescendantIds(node) {
8295
8436
  const ids = [node.id];
8296
8437
  if (node.children) {
@@ -8305,13 +8446,26 @@ function TreeView({
8305
8446
  checkable,
8306
8447
  defaultExpanded = [],
8307
8448
  defaultSelected = [],
8449
+ selected: selectedProp,
8308
8450
  defaultChecked = [],
8309
8451
  onSelect,
8310
8452
  onCheck,
8311
8453
  className
8312
8454
  }) {
8313
- const [expanded, setExpanded] = useState(new Set(defaultExpanded));
8314
- const [selected, setSelected] = useState(new Set(defaultSelected));
8455
+ const [ownSelected, setOwnSelected] = useState(() => new Set(defaultSelected));
8456
+ const selected = useMemo(() => selectedProp ? new Set(selectedProp) : ownSelected, [selectedProp, ownSelected]);
8457
+ const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set([...defaultExpanded, ...foldersHolding(nodes, selected)]));
8458
+ const revealed = useRef(null);
8459
+ if (revealed.current === null) revealed.current = new Set([...selected].filter((id) => inTree(nodes, id)));
8460
+ useEffect(() => {
8461
+ const seen = revealed.current;
8462
+ const fresh = [...selected].filter((id) => !seen.has(id) && inTree(nodes, id));
8463
+ if (!fresh.length) return;
8464
+ for (const id of fresh) seen.add(id);
8465
+ const folders = foldersHolding(nodes, new Set(fresh));
8466
+ if (folders.length) setExpanded((prev) => folders.every((id) => prev.has(id)) ? prev : /* @__PURE__ */ new Set([...prev, ...folders]));
8467
+ }, [nodes, selected]);
8468
+ const holding = useMemo(() => new Set(foldersHolding(nodes, selected)), [nodes, selected]);
8315
8469
  const [checked, setChecked] = useState(new Set(defaultChecked));
8316
8470
  const baseId = useId();
8317
8471
  const toggleExpand = useCallback((id) => {
@@ -8325,20 +8479,18 @@ function TreeView({
8325
8479
  const handleSelect = useCallback(
8326
8480
  (id) => {
8327
8481
  if (!selectable) return;
8328
- setSelected((prev) => {
8329
- let next;
8330
- if (multiSelect) {
8331
- next = new Set(prev);
8332
- if (next.has(id)) next.delete(id);
8333
- else next.add(id);
8334
- } else {
8335
- next = prev.has(id) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([id]);
8336
- }
8337
- onSelect?.(Array.from(next));
8338
- return next;
8339
- });
8482
+ let next;
8483
+ if (multiSelect) {
8484
+ next = new Set(selected);
8485
+ if (next.has(id)) next.delete(id);
8486
+ else next.add(id);
8487
+ } else {
8488
+ next = selected.has(id) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([id]);
8489
+ }
8490
+ if (!selectedProp) setOwnSelected(next);
8491
+ onSelect?.(Array.from(next));
8340
8492
  },
8341
- [selectable, multiSelect, onSelect]
8493
+ [selectable, multiSelect, selected, selectedProp, onSelect]
8342
8494
  );
8343
8495
  const handleCheck = useCallback(
8344
8496
  (node) => {
@@ -8423,6 +8575,7 @@ function TreeView({
8423
8575
  baseId,
8424
8576
  expanded,
8425
8577
  selected,
8578
+ holding,
8426
8579
  checked,
8427
8580
  checkable,
8428
8581
  selectable,
@@ -8441,6 +8594,7 @@ function TreeNodeRow({
8441
8594
  baseId,
8442
8595
  expanded,
8443
8596
  selected,
8597
+ holding,
8444
8598
  checkable,
8445
8599
  selectable,
8446
8600
  toggleExpand,
@@ -8452,6 +8606,7 @@ function TreeNodeRow({
8452
8606
  const hasChildren = !!node.children?.length;
8453
8607
  const isExpanded = expanded.has(node.id);
8454
8608
  const isSelected = selected.has(node.id);
8609
+ const holdsSelection = !isSelected && holding.has(node.id);
8455
8610
  const checkState = checkable ? getCheckState(node) : "unchecked";
8456
8611
  return /* @__PURE__ */ jsxs("div", { role: "treeitem", "aria-expanded": hasChildren ? isExpanded : void 0, "aria-selected": selectable ? isSelected : void 0, children: [
8457
8612
  /* @__PURE__ */ jsxs(
@@ -8467,6 +8622,9 @@ function TreeNodeRow({
8467
8622
  // transparent placeholder so content never shifts on selection.
8468
8623
  "border-l-[length:var(--ds-tree-active-rail)]",
8469
8624
  isSelected ? "bg-[var(--ds-tree-active-bg)] text-[var(--ds-tree-active-text)] font-medium border-[var(--ds-accent-primary)]" : "border-transparent text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)] hover:text-[var(--ds-text-primary)]",
8625
+ // A folder holding the selection, as SidebarNav draws a parent of the current page (Sprint 25.16 A18): no
8626
+ // fill, so it reads the plain tokens, never the active set (pill's on-primary text would vanish here).
8627
+ holdsSelection && "font-medium",
8470
8628
  node.disabled && "opacity-disabled pointer-events-none"
8471
8629
  ),
8472
8630
  style: { paddingLeft: `calc(var(--ds-space-3) * ${depth} + var(--ds-space-2))` },
@@ -8493,7 +8651,7 @@ function TreeNodeRow({
8493
8651
  {
8494
8652
  name: "chevron-right",
8495
8653
  size: 14,
8496
- className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
8654
+ className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : holdsSelection ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
8497
8655
  }
8498
8656
  )
8499
8657
  }
@@ -8508,7 +8666,7 @@ function TreeNodeRow({
8508
8666
  }
8509
8667
  }
8510
8668
  ),
8511
- node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : "text-[var(--ds-text-muted)]") }),
8669
+ node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : holdsSelection ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)]") }),
8512
8670
  /* @__PURE__ */ jsx(TruncLabel2, { children: node.label })
8513
8671
  ]
8514
8672
  }
@@ -8521,6 +8679,7 @@ function TreeNodeRow({
8521
8679
  baseId,
8522
8680
  expanded,
8523
8681
  selected,
8682
+ holding,
8524
8683
  checked: /* @__PURE__ */ new Set(),
8525
8684
  checkable,
8526
8685
  selectable,
@@ -8714,7 +8873,7 @@ function Carousel({
8714
8873
  );
8715
8874
  }
8716
8875
  function formatTime2(d) {
8717
- return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
8876
+ return d.toLocaleTimeString(formatLocale(), { hour: "2-digit", minute: "2-digit" });
8718
8877
  }
8719
8878
  function isSameMinute(a, b) {
8720
8879
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() && a.getHours() === b.getHours() && a.getMinutes() === b.getMinutes();
@@ -9481,7 +9640,7 @@ var StackedList = forwardRef(function StackedList2({
9481
9640
  useScrollsInside();
9482
9641
  const isPhone = useBreakpoint("sm");
9483
9642
  const inCard = useContext(CardSurfaceCtx);
9484
- const inPane = useContext(SplitPaneCtx);
9643
+ const inPane = !!useContext(SplitPaneCtx);
9485
9644
  const variant = variantProp ?? (flush || hover === "title" ? "articles" : "list");
9486
9645
  const legacy = flush !== void 0 || hover !== void 0;
9487
9646
  useEffect(() => {
@@ -9505,7 +9664,7 @@ var StackedList = forwardRef(function StackedList2({
9505
9664
  !pager && className
9506
9665
  ),
9507
9666
  role: "list",
9508
- children: shown.map((item) => {
9667
+ children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: shown.map((item) => {
9509
9668
  const isSelected = item.selected ?? (selectedId !== void 0 && item.id === selectedId);
9510
9669
  const interactive = !!item.onClick;
9511
9670
  const hasEmphasis = item.unread !== void 0;
@@ -9594,7 +9753,7 @@ var StackedList = forwardRef(function StackedList2({
9594
9753
  ]
9595
9754
  }
9596
9755
  ) }, item.id);
9597
- })
9756
+ }) })
9598
9757
  }
9599
9758
  );
9600
9759
  if (!pager) return list;
@@ -9668,7 +9827,8 @@ function periodAfter(unit, start) {
9668
9827
  return utcDay(y + 1, 0, 1);
9669
9828
  }
9670
9829
  var formats = /* @__PURE__ */ new Map();
9671
- function formatter(locale, options) {
9830
+ function formatter(given, options) {
9831
+ const locale = given ?? formatLocale();
9672
9832
  const key = `${locale ?? ""}|${JSON.stringify(options)}`;
9673
9833
  let f = formats.get(key);
9674
9834
  if (!f) {
@@ -9781,10 +9941,10 @@ function extendTimeScaleTo(scale, endDay) {
9781
9941
  }
9782
9942
  var noSubscription = () => () => {
9783
9943
  };
9784
- var inBrowser = () => true;
9785
- var onServer = () => false;
9944
+ var inBrowser2 = () => true;
9945
+ var onServer2 = () => false;
9786
9946
  function useTimeScale({ start, end, zoom, today, weekStartsOn = 1, locale, pxPerDay, pad: pad3 = 0 }) {
9787
- const readable = useSyncExternalStore(noSubscription, inBrowser, onServer);
9947
+ const readable = useSyncExternalStore(noSubscription, inBrowser2, onServer2);
9788
9948
  const [mounted] = useState(() => toMinute(dayOf(/* @__PURE__ */ new Date())));
9789
9949
  const pending = today === void 0 && !readable;
9790
9950
  const from = dayOf(start);
@@ -10148,6 +10308,8 @@ var TimeViewport = forwardRef(function TimeViewport2({
10148
10308
  className
10149
10309
  }, ref) {
10150
10310
  const scrollerRef = useRef(null);
10311
+ const rootRef = useRef(null);
10312
+ const fill2 = useFillHeight(rootRef);
10151
10313
  const headerRef = useRef(null);
10152
10314
  const rowsRef = useRef(null);
10153
10315
  const [frame, setFrame] = useState({ width: 0, header: 0 });
@@ -10370,23 +10532,26 @@ var TimeViewport = forwardRef(function TimeViewport2({
10370
10532
  };
10371
10533
  const headerNode = header === void 0 ? /* @__PURE__ */ jsx(TimeScaleHeader, {}) : header;
10372
10534
  const hasHeader = headerNode != null || labelHeader != null;
10373
- const bar = toolbar === false ? null : /* @__PURE__ */ jsxs("div", { className: cn("flex shrink-0 flex-wrap items-center gap-ds-1 px-ds-2 py-ds-1.5 border-b-[length:var(--ds-border-width)]", border), children: [
10374
- onZoomChange && levels.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
10375
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Zoom out", "aria-disabled": !canZoomOut || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(1), children: /* @__PURE__ */ jsx(Icon, { name: "minus", size: 14 }) }),
10376
- /* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "min-w-[4.5rem] text-center text-xs text-[var(--ds-text-secondary)]", children: ZOOM_NAMES[scale.zoom] }),
10377
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Zoom in", "aria-disabled": !canZoomIn || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(-1), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 14 }) })
10378
- ] }),
10379
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Previous period", onClick: () => api.page(-1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 14 }) }),
10380
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: todayAtX === null, onClick: () => {
10381
- if (todayAtX !== null) setLeft(todayAtX - visibleWidth / 2);
10382
- }, children: "Today" }),
10383
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Next period", onClick: () => api.page(1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) }),
10384
- toolbar
10385
- ] });
10535
+ const bar = toolbar === false ? null : (
10536
+ // a wrapped line (a chart's key, or controls on a phone) stands a row gap apart (Sprint 25.16 A43)
10537
+ /* @__PURE__ */ jsxs("div", { className: cn("flex shrink-0 flex-wrap items-center gap-x-ds-1 gap-y-ds-2 px-ds-2 py-ds-1.5 border-b-[length:var(--ds-border-width)]", border), children: [
10538
+ onZoomChange && levels.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
10539
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Zoom out", "aria-disabled": !canZoomOut || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(1), children: /* @__PURE__ */ jsx(Icon, { name: "minus", size: 14 }) }),
10540
+ /* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "min-w-[4.5rem] text-center text-xs text-[var(--ds-text-secondary)]", children: ZOOM_NAMES[scale.zoom] }),
10541
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Zoom in", "aria-disabled": !canZoomIn || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(-1), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 14 }) })
10542
+ ] }),
10543
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Previous period", onClick: () => api.page(-1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 14 }) }),
10544
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: todayAtX === null, onClick: () => {
10545
+ if (todayAtX !== null) setLeft(todayAtX - visibleWidth / 2);
10546
+ }, children: "Today" }),
10547
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Next period", onClick: () => api.page(1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) }),
10548
+ toolbar
10549
+ ] })
10550
+ );
10386
10551
  return (
10387
10552
  // Inline-size containment: the rows' width never widens the frame (in a grid or flex parent it would, and the
10388
10553
  // wider frame would extend the scale again). The viewport takes the width it is given and scrolls inside it.
10389
- /* @__PURE__ */ jsx("div", { "data-time-viewport": "", "data-compact": phone || void 0, className: cn("flex h-full min-h-0 w-full min-w-0 flex-col [contain:inline-size] bg-[var(--ds-bg-surface)]", className), onKeyDown, children: /* @__PURE__ */ jsx(TimeViewportCtx, { value: layout, children: /* @__PURE__ */ jsxs(TimeViewportScrollCtx, { value: store, children: [
10554
+ /* @__PURE__ */ jsx("div", { ref: rootRef, "data-time-viewport": "", "data-compact": phone || void 0, "data-fill": fill2 != null ? "" : void 0, className: cn("flex h-full min-h-0 w-full min-w-0 flex-col [contain:inline-size] bg-[var(--ds-bg-surface)]", className), style: fill2 != null ? { height: fill2 } : void 0, onKeyDown, children: /* @__PURE__ */ jsx(TimeViewportCtx, { value: layout, children: /* @__PURE__ */ jsxs(TimeViewportScrollCtx, { value: store, children: [
10390
10555
  bar,
10391
10556
  /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1", children: [
10392
10557
  /* @__PURE__ */ jsx(
@@ -10662,7 +10827,7 @@ function Cue({ name, size }) {
10662
10827
  function Legend({ statuses }) {
10663
10828
  const entries = Object.entries(statuses);
10664
10829
  if (!entries.length) return null;
10665
- return /* @__PURE__ */ jsx("ul", { "aria-label": "Status key", className: "ms-auto flex flex-wrap items-center gap-x-ds-3 gap-y-ds-1 ps-ds-2 text-xs text-[var(--ds-text-secondary)]", children: entries.map(([key, s]) => {
10830
+ return /* @__PURE__ */ jsx("ul", { "aria-label": "Status key", className: "flex flex-wrap items-center gap-x-ds-3 gap-y-ds-1 text-xs text-[var(--ds-text-secondary)]", children: entries.map(([key, s]) => {
10666
10831
  const tone = TONES[s.tone] ?? TONES.neutral;
10667
10832
  return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-ds-1.5", children: [
10668
10833
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("grid size-4 shrink-0 place-items-center rounded-[var(--ds-radius-sm)]", EDGE, tone.fill, tone.on), children: /* @__PURE__ */ jsx(Cue, { name: s.icon ?? tone.icon, size: 10 }) }),
@@ -10754,7 +10919,7 @@ function Gantt({
10754
10919
  const byKey = useMemo(() => new Map(rows.map((r) => [r.key, r])), [rows]);
10755
10920
  const names = useMemo(() => {
10756
10921
  const byId = new Map(tasks.map((i) => [i.id, i]));
10757
- const list = new Intl.ListFormat(locale, { type: "conjunction" });
10922
+ const list = new Intl.ListFormat(locale ?? formatLocale(), { type: "conjunction" });
10758
10923
  const out = /* @__PURE__ */ new Map();
10759
10924
  for (const item of tasks) {
10760
10925
  const dates = datesOf(item);
@@ -11004,6 +11169,8 @@ function Gantt({
11004
11169
  };
11005
11170
  const legend = /* @__PURE__ */ jsx(Legend, { statuses });
11006
11171
  const legendApart = toolbar === false && hasStatuses;
11172
+ const apartRef = useRef(null);
11173
+ const apartFill = useFillHeight(apartRef, legendApart);
11007
11174
  const chart = /* @__PURE__ */ jsx(
11008
11175
  TimeViewport,
11009
11176
  {
@@ -11013,6 +11180,7 @@ function Gantt({
11013
11180
  labelHeader,
11014
11181
  toolbar: toolbar === false ? false : /* @__PURE__ */ jsxs(Fragment, { children: [
11015
11182
  toolbar,
11183
+ hasStatuses && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "min-w-0 flex-1" }),
11016
11184
  legend
11017
11185
  ] }),
11018
11186
  tabStop: false,
@@ -11041,9 +11209,9 @@ function Gantt({
11041
11209
  }
11042
11210
  );
11043
11211
  if (!legendApart) return chart;
11044
- return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 w-full min-w-0 flex-col", className), children: [
11045
- /* @__PURE__ */ jsx("div", { className: "flex shrink-0 px-ds-2 py-ds-1.5", children: legend }),
11046
- chart
11212
+ return /* @__PURE__ */ jsxs("div", { ref: apartRef, "data-fill": apartFill != null ? "" : void 0, className: cn("flex h-full min-h-0 w-full min-w-0 flex-col", className), style: apartFill != null ? { height: apartFill } : void 0, children: [
11213
+ /* @__PURE__ */ jsx("div", { className: "flex shrink-0 justify-end px-ds-2 py-ds-1.5", children: legend }),
11214
+ /* @__PURE__ */ jsx(FillContext, { value: true, children: chart })
11047
11215
  ] });
11048
11216
  }
11049
11217
  var DEFAULT_OFFSET2 = "var(--ds-space-4)";
@@ -11469,14 +11637,14 @@ function TabButton({
11469
11637
  hasPanel
11470
11638
  }) {
11471
11639
  const { ref: truncRef, isTruncated } = useTextOverflow({ lines: 1, disabled: !truncate && orientation !== "horizontal" });
11472
- const isActive = activeTab === id;
11640
+ const isActive2 = activeTab === id;
11473
11641
  const tabId = `ds-tab-${id}`;
11474
11642
  const panelId = hasPanel === false ? void 0 : `ds-tabpanel-${id}`;
11475
11643
  const badgeBg = orientation === "vertical" ? "bg-[var(--ds-nav-v-badge-bg)]" : "bg-[var(--ds-nav-h-badge-bg)]";
11476
11644
  const countBadge = count !== void 0 ? /* @__PURE__ */ jsx("span", { className: cn(
11477
11645
  orientation === "vertical" ? "ml-ds-2" : "",
11478
11646
  "px-ds-1.5 py-ds-0.5 text-xs rounded-[var(--ds-radius-sm)]",
11479
- isActive ? cn(badgeBg, "text-[var(--ds-text-on-primary)]") : "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-muted)]"
11647
+ isActive2 ? cn(badgeBg, "text-[var(--ds-text-on-primary)]") : "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-muted)]"
11480
11648
  ), children: count }) : null;
11481
11649
  if (orientation === "vertical") {
11482
11650
  const btn2 = /* @__PURE__ */ jsxs(
@@ -11485,10 +11653,10 @@ function TabButton({
11485
11653
  type: "button",
11486
11654
  id: tabId,
11487
11655
  role: "tab",
11488
- "aria-selected": isActive,
11656
+ "aria-selected": isActive2,
11489
11657
  "aria-controls": panelId,
11490
11658
  "aria-disabled": disabled || void 0,
11491
- tabIndex: isActive ? 0 : -1,
11659
+ tabIndex: isActive2 ? 0 : -1,
11492
11660
  onClick: disabled ? void 0 : () => onTabChange(id),
11493
11661
  onKeyDown,
11494
11662
  className: cn(
@@ -11500,7 +11668,7 @@ function TabButton({
11500
11668
  // Every item carries the rail width as a transparent placeholder so the
11501
11669
  // label does not shift when the rail appears on the active item.
11502
11670
  "border-l-[length:var(--ds-nav-v-active-rail)]",
11503
- isActive ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-[var(--ds-accent-primary)]" : "border-transparent text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]",
11671
+ isActive2 ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-[var(--ds-accent-primary)]" : "border-transparent text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]",
11504
11672
  className
11505
11673
  ),
11506
11674
  children: [
@@ -11521,10 +11689,10 @@ function TabButton({
11521
11689
  type: "button",
11522
11690
  id: tabId,
11523
11691
  role: "tab",
11524
- "aria-selected": isActive,
11692
+ "aria-selected": isActive2,
11525
11693
  "aria-controls": panelId,
11526
11694
  "aria-disabled": disabled || void 0,
11527
- tabIndex: isActive ? 0 : -1,
11695
+ tabIndex: isActive2 ? 0 : -1,
11528
11696
  onClick: disabled ? void 0 : () => onTabChange(id),
11529
11697
  onKeyDown,
11530
11698
  className: cn(
@@ -11540,10 +11708,10 @@ function TabButton({
11540
11708
  fullWidth && "flex-1",
11541
11709
  truncate && "flex-1 min-w-0 justify-start",
11542
11710
  "rounded-[var(--ds-nav-h-item-radius)]",
11543
- isActive ? "bg-[var(--ds-nav-h-active-bg)] text-[var(--ds-nav-h-active-text)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-nav-h-inactive-text)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-nav-h-hover-bg)]",
11711
+ isActive2 ? "bg-[var(--ds-nav-h-active-bg)] text-[var(--ds-nav-h-active-text)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-nav-h-inactive-text)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-nav-h-hover-bg)]",
11544
11712
  className
11545
11713
  ),
11546
- style: isActive ? { borderBottomWidth: "var(--ds-nav-h-indicator)", marginBottom: "calc(var(--ds-nav-h-track-border) * -1)" } : void 0,
11714
+ style: isActive2 ? { borderBottomWidth: "var(--ds-nav-h-indicator)", marginBottom: "calc(var(--ds-nav-h-track-border) * -1)" } : void 0,
11547
11715
  children: truncate ? /* @__PURE__ */ jsxs(Fragment, { children: [
11548
11716
  icon && /* @__PURE__ */ jsx(Icon, { name: icon, size: 16, className: "shrink-0" }),
11549
11717
  /* @__PURE__ */ jsx("span", { ref: truncRef, className: "truncate min-w-0 flex-1", children: label }),
@@ -11772,241 +11940,6 @@ function SettingsLayout({
11772
11940
  /* @__PURE__ */ jsx("div", { "data-settings-panel": "", className: cn("flex-1", PANEL_CLASSES), style: PANEL_STYLE, children })
11773
11941
  ] });
11774
11942
  }
11775
- function SeparatorIcon({ type, size }) {
11776
- const iconSize = size === "sm" ? 10 : 12;
11777
- if (type === "chevron") return /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: iconSize });
11778
- if (type === "arrow") return /* @__PURE__ */ jsx(Icon, { name: "arrow-right", size: iconSize });
11779
- if (type === "dot") return /* @__PURE__ */ jsx("span", { children: "\xB7" });
11780
- return /* @__PURE__ */ jsx("span", { children: "/" });
11781
- }
11782
- var Breadcrumbs = forwardRef(function Breadcrumbs2({
11783
- items,
11784
- separator = "chevron",
11785
- variant = "inline",
11786
- itemVariant,
11787
- size = "md",
11788
- showIcons = false,
11789
- maxItems,
11790
- bleed = false,
11791
- contentMaxWidth,
11792
- className,
11793
- container
11794
- }, ref) {
11795
- const [dropdownOpen, setDropdownOpen] = useState(false);
11796
- const [activeIdx, setActiveIdx] = useState(0);
11797
- const ellipsisBtnRef = useRef(null);
11798
- const dropdownRef = useRef(null);
11799
- const closeDropdown = useCallback(() => setDropdownOpen(false), []);
11800
- const { isTop, returnFocus } = usePopupFocus(dropdownOpen, { trigger: ellipsisBtnRef, panel: dropdownRef, close: closeDropdown, tabExits: "any" });
11801
- const pos = usePosition(ellipsisBtnRef, dropdownRef, dropdownOpen, { side: "bottom", align: "start", offset: 4, flip: true });
11802
- const effectiveMaxItems = maxItems ? Math.max(maxItems, 2) : void 0;
11803
- const shouldCollapse = effectiveMaxItems && items.length > effectiveMaxItems;
11804
- const collapsedItems = shouldCollapse ? items.slice(1, -(effectiveMaxItems - 1)) : [];
11805
- const visibleItems = shouldCollapse ? [...items.slice(0, 1), null, ...items.slice(-(effectiveMaxItems - 1))] : items;
11806
- useEffect(() => {
11807
- if (!dropdownOpen) return;
11808
- const handler = (e) => {
11809
- const target = e.target;
11810
- if (ellipsisBtnRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
11811
- setDropdownOpen(false);
11812
- };
11813
- const onKeyDown = (e) => {
11814
- if (e.key !== "Escape" || e.defaultPrevented || !isTop()) return;
11815
- e.preventDefault();
11816
- returnFocus();
11817
- setDropdownOpen(false);
11818
- };
11819
- document.addEventListener("mousedown", handler);
11820
- document.addEventListener("keydown", onKeyDown);
11821
- return () => {
11822
- document.removeEventListener("mousedown", handler);
11823
- document.removeEventListener("keydown", onKeyDown);
11824
- };
11825
- }, [dropdownOpen, isTop, returnFocus]);
11826
- useEffect(() => {
11827
- if (!dropdownOpen) return;
11828
- const id = requestAnimationFrame(() => dropdownRef.current?.querySelector(`[data-index="${activeIdx}"]`)?.focus());
11829
- return () => cancelAnimationFrame(id);
11830
- }, [dropdownOpen, activeIdx]);
11831
- function onMenuKeyDown(e) {
11832
- const last = collapsedItems.length - 1;
11833
- const next = e.key === "ArrowDown" ? activeIdx >= last ? 0 : activeIdx + 1 : e.key === "ArrowUp" ? activeIdx <= 0 ? last : activeIdx - 1 : e.key === "Home" ? 0 : e.key === "End" ? last : null;
11834
- if (next === null) return;
11835
- e.preventDefault();
11836
- setActiveIdx(next);
11837
- }
11838
- const textClass = size === "sm" ? "text-xs" : "text-sm";
11839
- const gapClass = size === "sm" ? "gap-ds-1" : "gap-ds-1.5";
11840
- const iconSize = size === "sm" ? 12 : 14;
11841
- const isContainedBleed = variant === "contained" && bleed;
11842
- const wrapperClasses = cn(
11843
- variant === "contained" && !bleed && cn(
11844
- "bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-md)]",
11845
- size === "sm" ? "py-ds-1 px-ds-2" : "py-ds-1.5 px-ds-3"
11846
- ),
11847
- !isContainedBleed && className
11848
- );
11849
- function renderItem(item, _index, isLast) {
11850
- const isPill = itemVariant === "pill" || variant === "pill" && !itemVariant;
11851
- const insideContained = variant === "contained";
11852
- const pillClasses = isPill ? cn(
11853
- "rounded-[var(--ds-radius-full)]",
11854
- insideContained ? "bg-[var(--ds-bg-surface)]" : "bg-[var(--ds-bg-muted)]",
11855
- size === "sm" ? "px-ds-2 py-[2px]" : "px-ds-2.5 py-ds-0.5"
11856
- ) : "";
11857
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
11858
- showIcons && item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: iconSize, className: "shrink-0" }),
11859
- /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label })
11860
- ] });
11861
- if (isLast) {
11862
- return /* @__PURE__ */ jsx(
11863
- "span",
11864
- {
11865
- "aria-current": "page",
11866
- className: cn(
11867
- "font-medium text-[var(--ds-text-primary)] flex items-center",
11868
- gapClass,
11869
- pillClasses
11870
- ),
11871
- children: content
11872
- }
11873
- );
11874
- }
11875
- return /* @__PURE__ */ jsx(
11876
- "a",
11877
- {
11878
- href: item.href ?? "#",
11879
- onClick: (e) => {
11880
- e.preventDefault();
11881
- item.onClick?.();
11882
- },
11883
- className: cn(
11884
- "text-[var(--ds-text-secondary)] flex items-center",
11885
- "hover:text-[var(--ds-text-primary)]",
11886
- "transition-colors duration-[var(--ds-transition-speed)]",
11887
- gapClass,
11888
- pillClasses
11889
- ),
11890
- children: content
11891
- }
11892
- );
11893
- }
11894
- const listContent = /* @__PURE__ */ jsx("ol", { className: cn("flex items-center flex-wrap", gapClass, textClass), children: visibleItems.map((item, i) => {
11895
- if (item === null) {
11896
- return /* @__PURE__ */ jsxs("li", { className: cn("flex items-center", gapClass), children: [
11897
- i > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[var(--ds-text-secondary)] select-none flex items-center", children: /* @__PURE__ */ jsx(SeparatorIcon, { type: separator, size }) }),
11898
- /* @__PURE__ */ jsx(
11899
- "button",
11900
- {
11901
- type: "button",
11902
- ref: ellipsisBtnRef,
11903
- onClick: () => {
11904
- if (!dropdownOpen) setActiveIdx(0);
11905
- setDropdownOpen(!dropdownOpen);
11906
- },
11907
- "aria-label": "Show hidden breadcrumbs",
11908
- "aria-expanded": dropdownOpen,
11909
- "aria-haspopup": "menu",
11910
- className: cn(
11911
- "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]",
11912
- "transition-colors duration-[var(--ds-transition-speed)] cursor-pointer",
11913
- "flex items-center",
11914
- (itemVariant === "pill" || variant === "pill" && !itemVariant) && cn(
11915
- "rounded-[var(--ds-radius-full)]",
11916
- variant === "contained" ? "bg-[var(--ds-bg-surface)]" : "bg-[var(--ds-bg-muted)]",
11917
- size === "sm" ? "px-ds-2 py-[2px]" : "px-ds-2.5 py-ds-0.5"
11918
- )
11919
- ),
11920
- children: "\xB7\xB7\xB7"
11921
- }
11922
- )
11923
- ] }, "__ellipsis");
11924
- }
11925
- const isLast = i === visibleItems.length - 1;
11926
- return /* @__PURE__ */ jsxs("li", { className: cn("flex items-center", gapClass), children: [
11927
- i > 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-[var(--ds-text-secondary)] select-none flex items-center", children: /* @__PURE__ */ jsx(SeparatorIcon, { type: separator, size }) }),
11928
- renderItem(item, i, isLast)
11929
- ] }, i);
11930
- }) });
11931
- const dropdown = dropdownOpen && collapsedItems.length > 0 && createPortal(
11932
- /* @__PURE__ */ jsx(
11933
- "div",
11934
- {
11935
- ref: dropdownRef,
11936
- role: "menu",
11937
- "aria-label": "Hidden breadcrumbs",
11938
- onKeyDown: onMenuKeyDown,
11939
- className: cn(
11940
- "fixed z-[var(--ds-z-popover)] min-w-[160px] max-h-60 overflow-auto",
11941
- "bg-[var(--ds-bg-surface-elevated)]",
11942
- "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
11943
- "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
11944
- "rounded-[var(--ds-radius-md)]",
11945
- "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
11946
- "py-ds-1"
11947
- ),
11948
- style: { top: pos.top, left: pos.left },
11949
- children: collapsedItems.map((ci, idx) => /* @__PURE__ */ jsxs(
11950
- "button",
11951
- {
11952
- type: "button",
11953
- "data-index": idx,
11954
- role: "menuitem",
11955
- tabIndex: idx === activeIdx ? 0 : -1,
11956
- className: cn(
11957
- "flex items-center w-full text-left text-sm cursor-pointer",
11958
- "px-ds-3 py-ds-1.5 transition-colors",
11959
- "text-[var(--ds-text-secondary)]",
11960
- "hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
11961
- "focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)] focus-visible:shadow-[inset_var(--ds-shadow-focus)]",
11962
- gapClass
11963
- ),
11964
- onClick: () => {
11965
- setDropdownOpen(false);
11966
- ci.onClick?.();
11967
- },
11968
- children: [
11969
- showIcons && ci.icon && /* @__PURE__ */ jsx(Icon, { name: ci.icon, size: iconSize, className: "shrink-0" }),
11970
- ci.label
11971
- ]
11972
- },
11973
- idx
11974
- ))
11975
- }
11976
- ),
11977
- container ?? document.body
11978
- );
11979
- if (isContainedBleed) {
11980
- return /* @__PURE__ */ jsxs(
11981
- "nav",
11982
- {
11983
- ref,
11984
- "aria-label": "Breadcrumb",
11985
- className: cn(
11986
- "w-full bg-[var(--ds-bg-muted)]",
11987
- // Hairline under the band: it sits within ~1.2:1 of both canvas and a tinted header, so the edge needs a line.
11988
- "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
11989
- className
11990
- ),
11991
- children: [
11992
- /* @__PURE__ */ jsx(
11993
- "div",
11994
- {
11995
- className: cn("w-full mx-auto px-ds-6", size === "sm" ? "py-ds-1" : "py-ds-1.5"),
11996
- style: { maxWidth: contentMaxWidth ?? "var(--ds-bp-xl)" },
11997
- children: listContent
11998
- }
11999
- ),
12000
- dropdown
12001
- ]
12002
- }
12003
- );
12004
- }
12005
- return /* @__PURE__ */ jsxs("nav", { ref, "aria-label": "Breadcrumb", className: wrapperClasses, children: [
12006
- listContent,
12007
- dropdown
12008
- ] });
12009
- });
12010
11943
  var HeaderTabRowContext = createContext(null);
12011
11944
  function useHeaderTabRow() {
12012
11945
  return useContext(HeaderTabRowContext);
@@ -12059,13 +11992,13 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
12059
11992
  const isLast = i === steps.length - 1;
12060
11993
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-start min-w-0", isLast ? "flex-none" : "flex-1"), children: [
12061
11994
  /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full", children: [
12062
- /* @__PURE__ */ jsx(StepCircle, { status, index: i, onClick: onStepChange ? () => onStepChange(i) : void 0, clickable: !!onStepChange }),
11995
+ /* @__PURE__ */ jsx(StepCircle, { status, index: i, label: step.label, onClick: onStepChange && !step.disabled ? () => onStepChange(i) : void 0, clickable: !!onStepChange && !step.disabled }),
12063
11996
  !isLast && /* @__PURE__ */ jsx(
12064
11997
  "div",
12065
11998
  {
12066
11999
  className: cn(
12067
12000
  "flex-1 h-0.5 mx-ds-2 transition-colors",
12068
- i < currentStep ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
12001
+ i < currentStep || steps[i + 1]?.status === "complete" ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
12069
12002
  )
12070
12003
  }
12071
12004
  )
@@ -12092,13 +12025,13 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
12092
12025
  const isLast = i === steps.length - 1;
12093
12026
  return /* @__PURE__ */ jsxs("div", { className: "flex gap-ds-3", children: [
12094
12027
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
12095
- /* @__PURE__ */ jsx(StepCircle, { status, index: i, onClick: onStepChange ? () => onStepChange(i) : void 0, clickable: !!onStepChange }),
12028
+ /* @__PURE__ */ jsx(StepCircle, { status, index: i, label: step.label, onClick: onStepChange && !step.disabled ? () => onStepChange(i) : void 0, clickable: !!onStepChange && !step.disabled }),
12096
12029
  !isLast && /* @__PURE__ */ jsx(
12097
12030
  "div",
12098
12031
  {
12099
12032
  className: cn(
12100
12033
  "w-0.5 flex-1 min-h-6 transition-colors",
12101
- i < currentStep ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
12034
+ i < currentStep || steps[i + 1]?.status === "complete" ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
12102
12035
  )
12103
12036
  }
12104
12037
  )
@@ -12139,13 +12072,13 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
12139
12072
  )
12140
12073
  }
12141
12074
  ),
12142
- /* @__PURE__ */ jsx(StepCircle, { status, index: i, onClick: onStepChange ? () => onStepChange(i) : void 0, clickable: !!onStepChange }),
12075
+ /* @__PURE__ */ jsx(StepCircle, { status, index: i, label: step.label, onClick: onStepChange && !step.disabled ? () => onStepChange(i) : void 0, clickable: !!onStepChange && !step.disabled }),
12143
12076
  /* @__PURE__ */ jsx(
12144
12077
  "div",
12145
12078
  {
12146
12079
  className: cn(
12147
12080
  "flex-1 h-0.5 transition-colors",
12148
- isLast ? "bg-transparent" : i < currentStep ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
12081
+ isLast ? "bg-transparent" : i < currentStep || steps[i + 1]?.status === "complete" ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-border-subtle)]"
12149
12082
  )
12150
12083
  }
12151
12084
  )
@@ -12168,13 +12101,14 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
12168
12101
  }
12169
12102
  );
12170
12103
  }
12171
- function StepCircle({ status, index, onClick, clickable }) {
12104
+ function StepCircle({ status, index, label, onClick, clickable }) {
12172
12105
  return /* @__PURE__ */ jsx(
12173
12106
  "button",
12174
12107
  {
12175
12108
  type: "button",
12176
12109
  onClick,
12177
12110
  disabled: !clickable,
12111
+ "aria-label": `Step ${index + 1}: ${label}${status === "complete" ? ", completed" : ""}`,
12178
12112
  "aria-current": status === "current" ? "step" : void 0,
12179
12113
  className: cn(
12180
12114
  "flex items-center justify-center shrink-0 w-8 h-8 rounded-[var(--ds-radius-full)] text-xs font-bold transition-colors",
@@ -12185,7 +12119,9 @@ function StepCircle({ status, index, onClick, clickable }) {
12185
12119
  status === "current" && `border-2 ${ACTIVE_RING} text-[var(--ds-accent-primary)] bg-[var(--ds-bg-surface)]`,
12186
12120
  status === "error" && "bg-[var(--ds-status-error)] text-[var(--ds-text-on-error)]",
12187
12121
  status === "loading" && `border-2 ${ACTIVE_RING} text-[var(--ds-accent-primary)] bg-[var(--ds-bg-surface)] animate-pulse`,
12188
- status === "upcoming" && "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)] text-[var(--ds-text-muted)] bg-[var(--ds-bg-surface)]"
12122
+ status === "upcoming" && "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)] text-[var(--ds-text-muted)] bg-[var(--ds-bg-surface)]",
12123
+ // a step reached but not done (the user went back) can be gone to: it answers the pointer as the done ones do
12124
+ status === "upcoming" && clickable && "hover:border-[var(--ds-accent-primary)] hover:text-[var(--ds-accent-primary)]"
12189
12125
  ),
12190
12126
  children: status === "complete" ? /* @__PURE__ */ jsx(Icon, { name: "check", size: 14 }) : status === "error" ? /* @__PURE__ */ jsx(Icon, { name: "warning", size: 14 }) : index + 1
12191
12127
  }
@@ -12517,17 +12453,13 @@ function TruncLabel3({ children, className, side = "right", container, lines = 1
12517
12453
  if (!isTruncated) return label;
12518
12454
  return /* @__PURE__ */ jsx(Tooltip, { content: children, side, delay: 200, container, children: label });
12519
12455
  }
12520
- function hasActiveDescendant(items) {
12521
- return items.some(
12522
- (it) => it.active || it.children && hasActiveDescendant(it.children)
12523
- );
12524
- }
12456
+ var isActive = (item) => !!item.active;
12525
12457
  function collectInitialExpanded(items, prefix = "") {
12526
12458
  const keys = [];
12527
12459
  for (const item of items) {
12528
12460
  if (!item.children?.length) continue;
12529
12461
  const key = prefix ? `${prefix}/${item.label}` : item.label;
12530
- if (item.defaultExpanded || hasActiveDescendant(item.children)) {
12462
+ if (item.defaultExpanded || holdsCurrent(item.children, isActive)) {
12531
12463
  keys.push(key);
12532
12464
  }
12533
12465
  keys.push(...collectInitialExpanded(item.children, key));
@@ -12749,7 +12681,7 @@ function SidebarNav({
12749
12681
  function renderCompactItem(item, index, parentKey) {
12750
12682
  const hasChildren = !!item.children?.length;
12751
12683
  const key = makeKey(item.label, parentKey);
12752
- const childActive = hasChildren && hasActiveDescendant(item.children);
12684
+ const childActive = hasChildren && holdsCurrent(item.children, isActive);
12753
12685
  const isOpen = openFlyout === key;
12754
12686
  return /* @__PURE__ */ jsx(
12755
12687
  CompactNavItem,
@@ -12783,7 +12715,7 @@ function SidebarNav({
12783
12715
  return renderLeaf(item, depth, index);
12784
12716
  }
12785
12717
  const isExpanded = expandedItems.has(key);
12786
- const childActive = hasActiveDescendant(item.children);
12718
+ const childActive = holdsCurrent(item.children, isActive);
12787
12719
  const isRoot = depth === 0;
12788
12720
  const rootPy = isSm ? "py-ds-1.5" : "py-ds-2";
12789
12721
  const childPy = isSm ? "py-ds-1" : "py-ds-1.5";
@@ -13353,7 +13285,7 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
13353
13285
  const noteShown = useCallback((id, variant, action, fresh) => {
13354
13286
  if (runs.current.size) shownDuringRuns.current.push({ seq: ++showSeq.current, at: Date.now(), id, variant, action, fresh });
13355
13287
  }, []);
13356
- const update = useCallback((id, message, options = {}) => {
13288
+ const update2 = useCallback((id, message, options = {}) => {
13357
13289
  const list2 = entries.current;
13358
13290
  const at = list2.findIndex((t2) => t2.id === id);
13359
13291
  if (at === -1) return;
@@ -13403,21 +13335,21 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
13403
13335
  success: (m, o) => toast(m, { ...o, variant: "success" }),
13404
13336
  warning: (m, o) => toast(m, { ...o, variant: "warning" }),
13405
13337
  error: (m, o) => toast(m, { ...o, variant: "error" }),
13406
- update,
13338
+ update: update2,
13407
13339
  dismiss: remove,
13408
13340
  dismissAll,
13409
13341
  promise: async (promise, messages, options = {}) => {
13410
13342
  const id = toast(messages.loading, { ...options, variant: "default", duration: Infinity });
13411
13343
  try {
13412
13344
  const value = await promise;
13413
- update(id, typeof messages.success === "function" ? messages.success(value) : messages.success, { variant: "success", duration });
13345
+ update2(id, typeof messages.success === "function" ? messages.success(value) : messages.success, { variant: "success", duration });
13414
13346
  return value;
13415
13347
  } catch (err) {
13416
- update(id, typeof messages.error === "function" ? messages.error(err) : messages.error, { variant: "error", duration });
13348
+ update2(id, typeof messages.error === "function" ? messages.error(err) : messages.error, { variant: "error", duration });
13417
13349
  throw err;
13418
13350
  }
13419
13351
  }
13420
- }), [toast, update, remove, dismissAll, duration]);
13352
+ }), [toast, update2, remove, dismissAll, duration]);
13421
13353
  const ledger = useMemo(() => ({
13422
13354
  begin: () => {
13423
13355
  const run = ++runSeq.current;
@@ -13749,15 +13681,16 @@ var paddingClasses = {
13749
13681
  default: "px-[var(--ds-page-gutter)]",
13750
13682
  wide: "px-ds-10"
13751
13683
  };
13684
+ var FILLED_BOTTOM = "has-[[data-fill]]:pb-[var(--ds-page-gutter)]";
13752
13685
  var verticalPaddingClasses = {
13753
13686
  none: "",
13754
- default: "pt-ds-8 pb-ds-12",
13755
- spacious: "pt-ds-8 pb-ds-16"
13687
+ default: `pt-ds-8 pb-ds-12 ${FILLED_BOTTOM}`,
13688
+ spacious: `pt-ds-8 pb-ds-16 ${FILLED_BOTTOM}`
13756
13689
  };
13757
13690
  var bottomPaddingClasses = {
13758
13691
  none: "",
13759
- default: "pb-ds-12",
13760
- spacious: "pb-ds-16"
13692
+ default: `pb-ds-12 ${FILLED_BOTTOM}`,
13693
+ spacious: `pb-ds-16 ${FILLED_BOTTOM}`
13761
13694
  };
13762
13695
  var bottomPaddingValues = {
13763
13696
  none: "0px",
@@ -13780,6 +13713,38 @@ function useContentWidth(width) {
13780
13713
  return () => request(null);
13781
13714
  }, [request, width]);
13782
13715
  }
13716
+ function PageActions({ children }) {
13717
+ const slot = useContext(PageActionsCtx);
13718
+ const add = slot?.add;
13719
+ useEffect(() => add?.(), [add]);
13720
+ const target = slot?.target;
13721
+ return target ? createPortal(/* @__PURE__ */ jsx(ControlSizeContext, { value: target.size, children }), target.el) : null;
13722
+ }
13723
+ var pageOrder = (a, b) => a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
13724
+ function usePageActionsSlot() {
13725
+ const outer = useContext(PageActionsCtx);
13726
+ const [asking, setAsking] = useState(0);
13727
+ const [slots, setSlots] = useState([]);
13728
+ const register = useCallback((el, size) => {
13729
+ setSlots((list) => [...list.filter((s) => s.el !== el), { el, size }]);
13730
+ return () => setSlots((list) => list.filter((s) => s.el !== el));
13731
+ }, []);
13732
+ const outerAdd = outer?.add;
13733
+ const add = useCallback(() => {
13734
+ setAsking((n) => n + 1);
13735
+ const releaseOuter = outerAdd?.();
13736
+ let released = false;
13737
+ return () => {
13738
+ if (released) return;
13739
+ released = true;
13740
+ setAsking((n) => n - 1);
13741
+ releaseOuter?.();
13742
+ };
13743
+ }, [outerAdd]);
13744
+ const own = useMemo(() => [...slots].sort(pageOrder)[0] ?? null, [slots]);
13745
+ const target = own ?? outer?.target ?? null;
13746
+ return useMemo(() => ({ wanted: asking > 0, target, register, add }), [asking, target, register, add]);
13747
+ }
13783
13748
  function usePageContainer() {
13784
13749
  return useContext(PageContainerContext);
13785
13750
  }
@@ -13856,6 +13821,7 @@ var PageContainer = forwardRef(function PageContainer2({
13856
13821
  headerCount.current = Math.max(0, headerCount.current + (present ? 1 : -1));
13857
13822
  setWrappedHeader(headerCount.current > 0);
13858
13823
  }, []);
13824
+ const pageActions = usePageActionsSlot();
13859
13825
  const launcherCorner = shell?.launcherCorner ?? null;
13860
13826
  const vPad = verticalPadding ?? "default";
13861
13827
  const launcherPadding = launcherCorner ? { paddingBottom: `max(${bottomPaddingValues[vPad]}, var(--ds-toast-inset-${launcherCorner}, 0px))` } : {};
@@ -13901,7 +13867,7 @@ var PageContainer = forwardRef(function PageContainer2({
13901
13867
  observedRef.current = null;
13902
13868
  }, []);
13903
13869
  if (headerIdx === -1 || !headerEl || !r) {
13904
- return /* @__PURE__ */ jsx(PageContainerContext, { value: { contentMaxWidth: maxWidthValue, placement: "inside", containedBreadcrumbs: false, breadcrumbsInsideHeader: false, noBottomMargin: false, overlap: false, setPinnedHeight, reportHeader, requestContentWidth, insidePaddedColumn: true }, children: /* @__PURE__ */ jsx(
13870
+ return /* @__PURE__ */ jsx(PageActionsCtx, { value: pageActions, children: /* @__PURE__ */ jsx(PageContainerContext, { value: { contentMaxWidth: maxWidthValue, placement: "inside", containedBreadcrumbs: false, breadcrumbsInsideHeader: false, noBottomMargin: false, overlap: false, setPinnedHeight, reportHeader, requestContentWidth, insidePaddedColumn: true }, children: /* @__PURE__ */ jsx(
13905
13871
  "div",
13906
13872
  {
13907
13873
  ref: setRoot,
@@ -13917,7 +13883,7 @@ var PageContainer = forwardRef(function PageContainer2({
13917
13883
  style: { maxWidth: maxWidthValue, containerType: "inline-size", ...launcherPadding },
13918
13884
  children: capped(children)
13919
13885
  }
13920
- ) });
13886
+ ) }) });
13921
13887
  }
13922
13888
  const rest = kids.filter((_, i) => i !== headerIdx);
13923
13889
  const snapping = r.behavior === "snapping";
@@ -13938,7 +13904,7 @@ var PageContainer = forwardRef(function PageContainer2({
13938
13904
  ...overlapActive ? { marginTop: "calc(-1 * var(--ds-overlap, 0px))", position: "relative", zIndex: 1 } : {}
13939
13905
  } : void 0;
13940
13906
  const column = /* @__PURE__ */ jsx(PageContainerContext, { value: { contentMaxWidth: maxWidthValue, placement: "inside", containedBreadcrumbs: false, breadcrumbsInsideHeader: false, noBottomMargin: false, overlap: false, setPinnedHeight, reportHeader, requestContentWidth, insidePaddedColumn: true }, children: /* @__PURE__ */ jsx("div", { ref: columnRef, className: cn(columnClass(contentPadding), bottomPaddingClasses[vPad], className), style: { ...columnStyle, ...launcherPadding }, children: capped(rest) }) });
13941
- return /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-page-container": "", "data-width": dataWidth, className: "w-full", children: [
13907
+ return /* @__PURE__ */ jsx(PageActionsCtx, { value: pageActions, children: /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-page-container": "", "data-width": dataWidth, className: "w-full", children: [
13942
13908
  placement === "block" ? /* @__PURE__ */ jsx("div", { style: floatingBlockPadding(r.navbarFloating, r.sidebarFloating, overlapActive), children: /* @__PURE__ */ jsxs("div", { className: FLOATING_BLOCK, children: [
13943
13909
  strip,
13944
13910
  colourful ? header : /* @__PURE__ */ jsx("div", { className: columnClass(padding), style: columnStyle, children: header })
@@ -13950,7 +13916,7 @@ var PageContainer = forwardRef(function PageContainer2({
13950
13916
  /* @__PURE__ */ jsx("div", { className: columnClass(padding), style: columnStyle, children: header })
13951
13917
  ] }),
13952
13918
  wrapperStyle ? /* @__PURE__ */ jsx("div", { style: wrapperStyle, children: column }) : column
13953
- ] });
13919
+ ] }) });
13954
13920
  });
13955
13921
  function TruncHeading({ as: Tag3 = "h1", className, children, lines: linesProp }) {
13956
13922
  const lines = linesProp ?? (Tag3 === "h1" ? 2 : 1);
@@ -13978,7 +13944,8 @@ function outerHeight(el) {
13978
13944
  const s = getComputedStyle(el);
13979
13945
  return el.getBoundingClientRect().height + (parseFloat(s.marginTop) || 0) + (parseFloat(s.marginBottom) || 0);
13980
13946
  }
13981
- function Breadcrumbs3({ items, onLight, onTint, pill, separator = "chevron" }) {
13947
+ function Breadcrumbs2({ items, onLight, onTint, pill, separator = "chevron" }) {
13948
+ const follow = useCrumbFollow();
13982
13949
  if (!items.length) return null;
13983
13950
  const mutedCls = onLight ? "text-[var(--ds-text-on-primary)]/40" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]";
13984
13951
  const sepEl = (key) => {
@@ -13993,17 +13960,15 @@ function Breadcrumbs3({ items, onLight, onTint, pill, separator = "chevron" }) {
13993
13960
  onLight ? "bg-[var(--ds-text-on-primary)]/10" : onTint ? "bg-[var(--ds-bg-surface)]/70" : "bg-[var(--ds-bg-muted)]"
13994
13961
  ) : "";
13995
13962
  return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-ds-1.5 text-sm", children: items.map((item, i) => {
13996
- const isNavigable = !!(item.onClick || item.href);
13963
+ const isNavigable = crumbGoes(item);
13964
+ const isCurrent = !isNavigable && i === items.length - 1;
13997
13965
  return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-ds-1.5", children: [
13998
13966
  i > 0 && sepEl(i),
13999
13967
  isNavigable ? /* @__PURE__ */ jsx(
14000
13968
  "a",
14001
13969
  {
14002
13970
  href: item.href ?? "#",
14003
- onClick: (e) => {
14004
- e.preventDefault();
14005
- item.onClick?.();
14006
- },
13971
+ onClick: (e) => follow(e, item),
14007
13972
  className: cn(
14008
13973
  "transition-colors duration-[var(--ds-transition-speed)]",
14009
13974
  onLight ? "text-[var(--ds-text-on-primary)]/60 hover:text-[var(--ds-text-on-primary)]/90" : cn(mutedCls, "hover:text-[var(--ds-text-primary)]"),
@@ -14011,9 +13976,8 @@ function Breadcrumbs3({ items, onLight, onTint, pill, separator = "chevron" }) {
14011
13976
  ),
14012
13977
  children: item.label
14013
13978
  }
14014
- ) : /* @__PURE__ */ jsx("span", { className: cn(
14015
- "font-medium",
14016
- onLight ? "text-[var(--ds-text-on-primary)]/80" : "text-[var(--ds-text-primary)]",
13979
+ ) : /* @__PURE__ */ jsx("span", { "aria-current": isCurrent ? "page" : void 0, className: cn(
13980
+ isCurrent ? cn("font-medium", onLight ? "text-[var(--ds-text-on-primary)]/80" : "text-[var(--ds-text-primary)]") : onLight ? "text-[var(--ds-text-on-primary)]/60" : mutedCls,
14017
13981
  pillCls
14018
13982
  ), children: item.label })
14019
13983
  ] }, i);
@@ -14028,6 +13992,11 @@ function TintWash() {
14028
13992
  }
14029
13993
  );
14030
13994
  }
13995
+ function PageActionsSlotMark({ register }) {
13996
+ const size = useContext(ControlSizeContext);
13997
+ const ref = useCallback((el) => el ? register(el, size) : void 0, [register, size]);
13998
+ return /* @__PURE__ */ jsx("span", { ref, "data-page-actions": "", className: "contents" });
13999
+ }
14031
14000
  function BackButton({ onLight, onClick }) {
14032
14001
  return /* @__PURE__ */ jsx(
14033
14002
  "button",
@@ -14134,6 +14103,11 @@ var PageHeader = forwardRef(function PageHeader2({
14134
14103
  }, ref) {
14135
14104
  const shell = useAppShell();
14136
14105
  const container = usePageContainer();
14106
+ const pageActions = useContext(PageActionsCtx);
14107
+ const shownActions = pageActions?.wanted ? /* @__PURE__ */ jsxs(Fragment, { children: [
14108
+ actions,
14109
+ /* @__PURE__ */ jsx(PageActionsSlotMark, { register: pageActions.register })
14110
+ ] }) : actions;
14137
14111
  const reportHeader = container?.reportHeader;
14138
14112
  useLayoutEffect(() => {
14139
14113
  if (!reportHeader) return;
@@ -14179,7 +14153,7 @@ var PageHeader = forwardRef(function PageHeader2({
14179
14153
  badge,
14180
14154
  breadcrumbs: inlineBreadcrumbs,
14181
14155
  onBack,
14182
- actions,
14156
+ actions: shownActions,
14183
14157
  avatar,
14184
14158
  filters,
14185
14159
  expandedContent,
@@ -14207,7 +14181,7 @@ var PageHeader = forwardRef(function PageHeader2({
14207
14181
  }
14208
14182
  let header;
14209
14183
  if (variant === "minimal") {
14210
- header = /* @__PURE__ */ jsx(MinimalHeader, { title, description, caption, focusBack, badge, breadcrumbs: inlineBreadcrumbs, actions, tabs, breadcrumbPill: bcPill, breadcrumbSeparator: bcSep, as: Heading, className, headerRef: floating ? void 0 : ref, isFloating: floating, contentMaxWidth: gutterWidth });
14184
+ header = /* @__PURE__ */ jsx(MinimalHeader, { title, description, caption, focusBack, badge, breadcrumbs: inlineBreadcrumbs, actions: shownActions, tabs, breadcrumbPill: bcPill, breadcrumbSeparator: bcSep, as: Heading, className, headerRef: floating ? void 0 : ref, isFloating: floating, contentMaxWidth: gutterWidth });
14211
14185
  } else if (variant === "tabs-integrated") {
14212
14186
  header = /* @__PURE__ */ jsx(
14213
14187
  TabsIntegratedHeader,
@@ -14219,7 +14193,7 @@ var PageHeader = forwardRef(function PageHeader2({
14219
14193
  badge,
14220
14194
  breadcrumbs: inlineBreadcrumbs,
14221
14195
  onBack,
14222
- actions,
14196
+ actions: shownActions,
14223
14197
  avatar,
14224
14198
  tabs,
14225
14199
  breadcrumbPill: bcPill,
@@ -14244,7 +14218,7 @@ var PageHeader = forwardRef(function PageHeader2({
14244
14218
  badge,
14245
14219
  breadcrumbs: inlineBreadcrumbs,
14246
14220
  onBack,
14247
- actions,
14221
+ actions: shownActions,
14248
14222
  avatar,
14249
14223
  filters,
14250
14224
  intensity,
@@ -14272,7 +14246,7 @@ var PageHeader = forwardRef(function PageHeader2({
14272
14246
  badge,
14273
14247
  breadcrumbs: inlineBreadcrumbs,
14274
14248
  onBack,
14275
- actions,
14249
+ actions: shownActions,
14276
14250
  avatar,
14277
14251
  filters,
14278
14252
  bannerImage,
@@ -14354,7 +14328,7 @@ function DefaultHeader({
14354
14328
  hasBanner && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[var(--ds-bg-canvas)]/85" }),
14355
14329
  /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
14356
14330
  focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
14357
- hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14331
+ hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs2, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14358
14332
  /* @__PURE__ */ jsxs("div", { className: cn(
14359
14333
  "flex flex-col @sm:flex-row @sm:items-center justify-between gap-ds-4",
14360
14334
  hasBreadcrumbs && "mt-ds-1"
@@ -14401,7 +14375,7 @@ function MinimalHeader({
14401
14375
  const inner = floatingContentProps(isFloating, contentMaxWidth);
14402
14376
  return /* @__PURE__ */ jsx("header", { "data-gs": "page-header", ref: headerRef, className: cn("py-ds-2", hasBreadcrumbs && "pt-ds-1", tabs && "pb-ds-4", isFloating && FLOATING_HEADER, className), children: /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
14403
14377
  focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
14404
- hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14378
+ hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs2, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14405
14379
  caption && /* @__PURE__ */ jsx(Caption, { children: caption }),
14406
14380
  /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-ds-4", hasBreadcrumbs && "mt-ds-0.5"), children: [
14407
14381
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 min-w-0", children: [
@@ -14491,7 +14465,7 @@ function ColourfulHeader({
14491
14465
  },
14492
14466
  children: [
14493
14467
  focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack, onLight: isBold }),
14494
- hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, onLight: isBold, onTint: !isBold, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14468
+ hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs2, { items: breadcrumbs, onLight: isBold, onTint: !isBold, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14495
14469
  /* @__PURE__ */ jsxs("div", { className: cn(
14496
14470
  "flex flex-col @sm:flex-row @sm:items-center justify-between gap-ds-4",
14497
14471
  hasBreadcrumbs && "mt-ds-1"
@@ -14558,6 +14532,7 @@ function SnappingHeader({
14558
14532
  stickyTop = "top-[var(--ds-navbar-height)]"
14559
14533
  }) {
14560
14534
  const [collapsed, setCollapsed] = useState(false);
14535
+ const followCrumb = useCrumbFollow();
14561
14536
  const container = usePageContainer();
14562
14537
  const stickyRef = useRef(null);
14563
14538
  const setStickyRef = useCallback((node) => {
@@ -14692,7 +14667,7 @@ function SnappingHeader({
14692
14667
  const hasBreadcrumbs = !!(breadcrumbs && breadcrumbs.length > 0);
14693
14668
  const innerContent = isMinimal && !collapsed ? /* @__PURE__ */ jsxs("div", { className: cn("py-ds-2", hasBreadcrumbs && !hideExpandedBreadcrumbs && "pt-ds-1", tabs && "pb-ds-4"), children: [
14694
14669
  focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
14695
- hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14670
+ hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs2, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14696
14671
  caption && /* @__PURE__ */ jsx(Caption, { children: caption }),
14697
14672
  /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-ds-4", hasBreadcrumbs && !hideExpandedBreadcrumbs && "mt-ds-0.5"), children: [
14698
14673
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 min-w-0", children: [
@@ -14719,7 +14694,7 @@ function SnappingHeader({
14719
14694
  style: !collapsed && isColourful && overlapActive ? { paddingBottom: `calc(var(--ds-space-6) + var(--ds-overlap, 0px) - ${isBoldColourful && !(isFloating && !wrapperHasCard) ? "2px" : "var(--ds-border-width)"})` } : void 0,
14720
14695
  children: [
14721
14696
  !collapsed && focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack, onLight }),
14722
- !collapsed && hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, onLight, onTint, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14697
+ !collapsed && hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs2, { items: breadcrumbs, onLight, onTint, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14723
14698
  /* @__PURE__ */ jsxs("div", { className: cn(
14724
14699
  "flex justify-between gap-ds-4",
14725
14700
  collapsed ? "items-center" : "flex-col @sm:flex-row @sm:items-center",
@@ -14734,17 +14709,14 @@ function SnappingHeader({
14734
14709
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
14735
14710
  collapsed && hasBreadcrumbs && (() => {
14736
14711
  const lastCrumb = breadcrumbs[breadcrumbs.length - 1];
14737
- const isClickable = !!(lastCrumb?.onClick || lastCrumb?.href);
14712
+ const isClickable = !!lastCrumb && crumbGoes(lastCrumb);
14738
14713
  const Tag3 = isClickable ? "a" : "span";
14739
14714
  return /* @__PURE__ */ jsxs(
14740
14715
  Tag3,
14741
14716
  {
14742
14717
  ...isClickable ? {
14743
14718
  href: lastCrumb.href ?? "#",
14744
- onClick: (e) => {
14745
- e.preventDefault();
14746
- lastCrumb.onClick?.();
14747
- }
14719
+ onClick: (e) => followCrumb(e, lastCrumb)
14748
14720
  } : {},
14749
14721
  className: cn(
14750
14722
  "text-sm hidden @sm:inline-flex items-center gap-ds-1",
@@ -14841,7 +14813,7 @@ function TabsIntegratedHeader({
14841
14813
  const inner = floatingContentProps(isFloating, contentMaxWidth);
14842
14814
  return /* @__PURE__ */ jsx("header", { "data-gs": "page-header", ref: headerRef, className: cn(hasBreadcrumbs ? "pt-ds-3" : "pt-ds-6", "pb-ds-4", isFloating && cn(FLOATING_HEADER, "overflow-hidden"), className), children: /* @__PURE__ */ jsxs("div", { className: inner.className, style: inner.style, children: [
14843
14815
  focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack }),
14844
- hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14816
+ hasBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs2, { items: breadcrumbs, pill: breadcrumbPill, separator: breadcrumbSeparator }),
14845
14817
  /* @__PURE__ */ jsxs("div", { className: cn(
14846
14818
  "flex flex-col @sm:flex-row @sm:items-center justify-between gap-ds-4",
14847
14819
  hasBreadcrumbs && "mt-ds-1"
@@ -15390,7 +15362,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
15390
15362
  "data-gs": "dialog",
15391
15363
  "aria-labelledby": titleId,
15392
15364
  "aria-describedby": description ? descriptionId : void 0,
15393
- style: { containerType: "inline-size" },
15365
+ style: { containerType: "inline-size", "--ds-form-max": "none" },
15394
15366
  className: cn(
15395
15367
  // a column: the title row, a body that scrolls when it is taller than the room, and the footer (Sprint 25.14,
15396
15368
  // with A36's full-screen phone dialog: its content ran past the screen with the footer cut off)
@@ -15601,7 +15573,7 @@ var Navbar = forwardRef(function Navbar2({
15601
15573
  }
15602
15574
  focus.onExit?.();
15603
15575
  };
15604
- const exitControl = focus ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: requestExit, children: focus.exitLabel ?? (focus.kind === "before-app" ? "Save and log out" : "Exit") }) : null;
15576
+ const exitControl = focus && !appShell?.flowLeft ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: requestExit, children: focus.exitLabel ?? (focus.kind === "before-app" ? "Save and log out" : "Exit") }) : null;
15605
15577
  const shownUserMenu = focus?.kind === "before-app" ? null : userMenu;
15606
15578
  const asking = confirmExit && focus?.kind === "in-app" && !!appShell?.hasUnsavedChanges;
15607
15579
  if (confirmExit && !asking) setConfirmExit(false);
@@ -16077,7 +16049,7 @@ function HoverCard({
16077
16049
  className
16078
16050
  ),
16079
16051
  style: { top: pos.top, left: pos.left },
16080
- children: content
16052
+ children: /* @__PURE__ */ jsx(RowsCtx, { value: false, children: content })
16081
16053
  }
16082
16054
  ),
16083
16055
  container ?? document.body
@@ -16735,6 +16707,310 @@ function getPopoverPosition(rect, placement, padding) {
16735
16707
  top = Math.max(8, Math.min(top, window.innerHeight - popH - 8));
16736
16708
  return { top, left };
16737
16709
  }
16710
+ var FLOW_STORAGE_PREFIX = "gridsmith-flow:";
16711
+ var stores = /* @__PURE__ */ new Map();
16712
+ var storeFor = (key) => {
16713
+ let store = stores.get(key);
16714
+ if (!store) {
16715
+ store = { value: null, raw: void 0, stale: false, listeners: /* @__PURE__ */ new Set(), finished: false, focusStep: null, left: null };
16716
+ stores.set(key, store);
16717
+ }
16718
+ return store;
16719
+ };
16720
+ var notify = (store) => store.listeners.forEach((listener) => listener());
16721
+ function subscribeTo(key, listener) {
16722
+ const store = storeFor(key);
16723
+ store.listeners.add(listener);
16724
+ if (!store.onStorage && typeof window !== "undefined") {
16725
+ store.onStorage = (e) => {
16726
+ if (e.key !== null && e.key !== FLOW_STORAGE_PREFIX + key) return;
16727
+ store.stale = true;
16728
+ notify(store);
16729
+ };
16730
+ window.addEventListener("storage", store.onStorage);
16731
+ }
16732
+ return () => {
16733
+ store.listeners.delete(listener);
16734
+ if (store.listeners.size > 0) return;
16735
+ if (store.onStorage) window.removeEventListener("storage", store.onStorage);
16736
+ store.onStorage = void 0;
16737
+ store.finished = false;
16738
+ };
16739
+ }
16740
+ var readRaw = (key) => {
16741
+ try {
16742
+ return window.localStorage.getItem(FLOW_STORAGE_PREFIX + key);
16743
+ } catch {
16744
+ return null;
16745
+ }
16746
+ };
16747
+ function readRecord(key) {
16748
+ return parseRecord(readRaw(key));
16749
+ }
16750
+ function parseRecord(raw) {
16751
+ try {
16752
+ if (!raw) return null;
16753
+ const stored = JSON.parse(raw);
16754
+ const furthest = Math.max(1, Math.floor(Number(stored.furthest)) || 1);
16755
+ const current = Math.floor(Number(stored.current)) || void 0;
16756
+ return { furthest, current, answers: stored.answers ?? {} };
16757
+ } catch {
16758
+ return null;
16759
+ }
16760
+ }
16761
+ function writeRecord(key, value) {
16762
+ for (const text of [() => JSON.stringify(value), () => JSON.stringify({ furthest: value.furthest, current: value.current })]) {
16763
+ try {
16764
+ const raw = text();
16765
+ window.localStorage.setItem(FLOW_STORAGE_PREFIX + key, raw);
16766
+ return raw;
16767
+ } catch {
16768
+ }
16769
+ }
16770
+ return null;
16771
+ }
16772
+ function snapshot(key) {
16773
+ const store = storeFor(key);
16774
+ if (store.raw === void 0 || store.stale || store.listeners.size === 0) {
16775
+ store.stale = false;
16776
+ const raw = readRaw(key);
16777
+ if (raw !== store.raw || store.value === null) {
16778
+ store.raw = raw;
16779
+ store.value = parseRecord(raw) ?? { furthest: 1, answers: {} };
16780
+ }
16781
+ }
16782
+ return store.value;
16783
+ }
16784
+ function update(key, change) {
16785
+ const store = storeFor(key);
16786
+ const raw = readRaw(key);
16787
+ if (raw !== null && raw !== store.raw) {
16788
+ store.raw = raw;
16789
+ store.value = parseRecord(raw) ?? store.value;
16790
+ }
16791
+ store.value = change(store.value ?? { furthest: 1, answers: {} });
16792
+ store.raw = writeRecord(key, store.value) ?? store.raw;
16793
+ store.stale = false;
16794
+ notify(store);
16795
+ }
16796
+ function clear(key) {
16797
+ const store = storeFor(key);
16798
+ try {
16799
+ window.localStorage.removeItem(FLOW_STORAGE_PREFIX + key);
16800
+ } catch {
16801
+ }
16802
+ store.value = null;
16803
+ store.raw = void 0;
16804
+ notify(store);
16805
+ }
16806
+ function markFlowMove(storageKey, step) {
16807
+ storeFor(storageKey).focusStep = step;
16808
+ }
16809
+ function stepJustLeft(storageKey) {
16810
+ const left = storeFor(storageKey).left;
16811
+ return left && Date.now() - left.time < 3e3 ? left.step : null;
16812
+ }
16813
+ function readFlowProgress(storageKey, initialAnswers) {
16814
+ const record = typeof window === "undefined" ? null : readRecord(storageKey);
16815
+ return record ? { ...record, answers: { ...initialAnswers, ...record.answers } } : null;
16816
+ }
16817
+ function useFlowNavigate(navigate) {
16818
+ const shellNavigate = useAppShell()?.navigate;
16819
+ return useCallback((href, options) => {
16820
+ const go = navigate ?? shellNavigate;
16821
+ if (go) go(href, options);
16822
+ else if (options?.replace) window.location.replace(href);
16823
+ else window.location.assign(href);
16824
+ }, [navigate, shellNavigate]);
16825
+ }
16826
+ function focusHeading() {
16827
+ const heading = document.querySelector("main h1") ?? document.querySelector("main");
16828
+ if (!heading) return;
16829
+ if (!heading.hasAttribute("tabindex")) heading.setAttribute("tabindex", "-1");
16830
+ heading.focus({ preventScroll: false });
16831
+ }
16832
+ function focusAfterLeaving() {
16833
+ if (typeof window === "undefined" || typeof requestAnimationFrame === "undefined") return () => {
16834
+ };
16835
+ const from = window.location.href;
16836
+ const old = document.querySelector("main h1");
16837
+ const oldText = old?.textContent ?? null;
16838
+ return () => {
16839
+ let frames = 0;
16840
+ const tick = () => {
16841
+ const heading = document.querySelector("main h1");
16842
+ const drawn = window.location.href !== from && !!heading && (heading !== old || heading.textContent !== oldText);
16843
+ if (!drawn) {
16844
+ if (++frames < 60) requestAnimationFrame(tick);
16845
+ return;
16846
+ }
16847
+ const active = document.activeElement;
16848
+ if (!active || active === document.body || !active.isConnected) focusHeading();
16849
+ };
16850
+ requestAnimationFrame(tick);
16851
+ };
16852
+ }
16853
+ var titleBase = null;
16854
+ var titleUsers = 0;
16855
+ function usePageTitle(title) {
16856
+ useEffect(() => {
16857
+ if (!title || typeof document === "undefined") return;
16858
+ if (titleUsers++ === 0) titleBase = document.title;
16859
+ document.title = titleBase ? `${title} \u2013 ${titleBase}` : title;
16860
+ return () => {
16861
+ if (--titleUsers > 0) return;
16862
+ if (titleBase !== null) document.title = titleBase;
16863
+ titleBase = null;
16864
+ };
16865
+ }, [title]);
16866
+ }
16867
+ var shownSteps = (steps, answers) => steps.filter((s) => !s.when || s.when(answers));
16868
+ var STEP = /^[1-9]\d*$/;
16869
+ function useFlowSteps(options) {
16870
+ const { steps, at, href, initialAnswers, exitTo, finishTo } = options;
16871
+ const key = options.storageKey || null;
16872
+ const go = useFlowNavigate(options.navigate);
16873
+ const subscribe = useCallback((listener) => key ? subscribeTo(key, listener) : () => {
16874
+ }, [key]);
16875
+ const stored = useSyncExternalStore(subscribe, () => key ? snapshot(key) : null, () => null);
16876
+ const answers = useMemo(() => ({ ...initialAnswers, ...stored?.answers ?? {} }), [initialAnswers, stored]);
16877
+ const shown = useMemo(() => shownSteps(steps, answers), [steps, answers]);
16878
+ const total = Math.max(shown.length, 1);
16879
+ const furthest = Math.min(stored?.furthest ?? 1, total);
16880
+ const asked = at !== void 0 && STEP.test(at) ? Number(at) : NaN;
16881
+ const valid = asked >= 1 && asked <= furthest;
16882
+ const step = valid ? asked : furthest;
16883
+ const finished = !!key && storeFor(key).finished;
16884
+ const ready = !!key && stored != null && valid && !finished;
16885
+ const redirected = useRef(null);
16886
+ useEffect(() => {
16887
+ if (!key || storeFor(key).finished) return;
16888
+ if (!stored || valid) {
16889
+ redirected.current = null;
16890
+ return;
16891
+ }
16892
+ const target = href(furthest);
16893
+ if (redirected.current === `${at} ${target}`) return;
16894
+ redirected.current = `${at} ${target}`;
16895
+ go(target, { replace: true });
16896
+ }, [key, stored, valid, furthest, href, go, at]);
16897
+ useEffect(() => {
16898
+ if (key && ready && stored?.current !== step) update(key, (v) => ({ ...v, current: step }));
16899
+ }, [key, ready, stored?.current, step]);
16900
+ useEffect(() => {
16901
+ if (!key || !ready) return;
16902
+ const store = storeFor(key);
16903
+ if (store.focusStep !== step) return;
16904
+ store.focusStep = null;
16905
+ focusHeading();
16906
+ }, [key, ready, step]);
16907
+ useLayoutEffect(() => {
16908
+ if (!key || !ready) return;
16909
+ const store = storeFor(key);
16910
+ return () => {
16911
+ store.left = { step, time: Date.now() };
16912
+ };
16913
+ }, [key, ready, step]);
16914
+ const current = shown[step - 1] ?? steps[0];
16915
+ usePageTitle(ready ? current.title : null);
16916
+ const setAnswers = useCallback((patch) => {
16917
+ if (!key) return;
16918
+ update(key, (before) => {
16919
+ const prev = { ...initialAnswers, ...before.answers };
16920
+ const next2 = { ...prev, ...patch };
16921
+ const here = Math.max(step, before.current ?? step);
16922
+ const ahead = (list) => list.slice(here).map((s) => s.label).join("\0");
16923
+ const changes = ahead(shownSteps(steps, prev)) !== ahead(shownSteps(steps, next2));
16924
+ return { ...before, furthest: changes ? Math.min(before.furthest, here) : before.furthest, answers: next2 };
16925
+ });
16926
+ }, [key, initialAnswers, step, steps]);
16927
+ const moveTo = useCallback((target) => {
16928
+ if (key) storeFor(key).focusStep = target;
16929
+ go(href(target));
16930
+ }, [key, go, href]);
16931
+ const goTo = useCallback((target) => {
16932
+ if (!Number.isInteger(target) || target < 1 || target > furthest || target === step) return;
16933
+ moveTo(target);
16934
+ }, [furthest, step, moveTo]);
16935
+ const next = useCallback((patch) => {
16936
+ if (!key) return;
16937
+ if (patch) setAnswers(patch);
16938
+ const shownNow = patch ? shownSteps(steps, { ...answers, ...patch }) : shown;
16939
+ if (step >= shownNow.length) return;
16940
+ update(key, (v) => ({ ...v, furthest: Math.max(v.furthest, step + 1), current: step + 1 }));
16941
+ moveTo(step + 1);
16942
+ }, [key, setAnswers, steps, answers, shown, step, moveTo]);
16943
+ const back = step > 1 ? () => moveTo(step - 1) : void 0;
16944
+ const saveAndExit = useCallback(() => {
16945
+ if (key && stored) update(key, (v) => ({ ...v, current: step }));
16946
+ const left = focusAfterLeaving();
16947
+ go(exitTo);
16948
+ left();
16949
+ }, [key, stored, step, go, exitTo]);
16950
+ const finish = useCallback(() => {
16951
+ if (key) storeFor(key).finished = true;
16952
+ const left = focusAfterLeaving();
16953
+ go(finishTo);
16954
+ if (key) clear(key);
16955
+ left();
16956
+ }, [key, go, finishTo]);
16957
+ return {
16958
+ ready,
16959
+ step,
16960
+ total,
16961
+ current,
16962
+ caption: `Step ${step} of ${total}`,
16963
+ title: current.title,
16964
+ answers,
16965
+ setAnswers,
16966
+ furthest,
16967
+ isFirst: step === 1,
16968
+ isLast: step === total,
16969
+ next,
16970
+ back,
16971
+ goTo,
16972
+ stepper: {
16973
+ steps: shown.map((s, i) => ({
16974
+ label: s.label,
16975
+ status: i + 1 < furthest && i + 1 !== step ? "complete" : void 0,
16976
+ disabled: i + 1 > furthest || void 0
16977
+ })),
16978
+ currentStep: step - 1,
16979
+ onStepChange: (index) => goTo(index + 1)
16980
+ },
16981
+ saveAndExit,
16982
+ finish
16983
+ };
16984
+ }
16985
+ function FlowSaved({ storageKey, href, title = "Your progress has been saved", children, navigate }) {
16986
+ const go = useFlowNavigate(navigate);
16987
+ const titleId = useId();
16988
+ const markFlowLeft = useAppShell()?.markFlowLeft;
16989
+ useLayoutEffect(() => markFlowLeft?.(), [markFlowLeft]);
16990
+ const [saved, setSaved] = useState(void 0);
16991
+ useLayoutEffect(() => {
16992
+ const progress = readFlowProgress(storageKey, {});
16993
+ const step = progress ? progress.current ?? progress.furthest : null;
16994
+ setSaved(step === null ? null : { step, behind: stepJustLeft(storageKey) === step });
16995
+ }, [storageKey]);
16996
+ const resume = () => {
16997
+ const step = saved?.step ?? 1;
16998
+ markFlowMove(storageKey, step);
16999
+ if (saved?.behind) window.history.back();
17000
+ else go(href(step), { replace: true });
17001
+ };
17002
+ useLayoutEffect(() => {
17003
+ if (saved !== void 0) focusHeading();
17004
+ }, [saved]);
17005
+ const heading = saved === null ? "There's no saved progress" : title;
17006
+ usePageTitle(saved === void 0 ? null : heading);
17007
+ return /* @__PURE__ */ jsx(PageContainer, { width: "narrow", children: /* @__PURE__ */ jsxs("section", { "aria-labelledby": titleId, className: "flex min-h-[60vh] flex-col items-center justify-center py-ds-12 text-center", children: [
17008
+ saved !== null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grid size-14 place-items-center rounded-[var(--ds-radius-full)] bg-[var(--ds-status-success-bg)] text-[var(--ds-status-success)]", children: /* @__PURE__ */ jsx(Icon, { name: "check", size: 28 }) }),
17009
+ /* @__PURE__ */ jsx("h1", { id: titleId, className: "mt-ds-6 font-[family-name:var(--ds-font-display)] text-3xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]", children: heading }),
17010
+ /* @__PURE__ */ jsx("div", { className: "mt-ds-3 max-w-md text-[var(--ds-text-secondary)]", children: saved === null ? /* @__PURE__ */ jsx("p", { children: "Nothing has been saved in this browser yet." }) : children ?? /* @__PURE__ */ jsx("p", { children: "Your answers are kept in this browser. Come back to it to carry on where you left off." }) }),
17011
+ /* @__PURE__ */ jsx("div", { className: "mt-ds-8 flex flex-wrap justify-center gap-ds-3", children: /* @__PURE__ */ jsx(Button, { type: "button", onClick: resume, children: saved === null ? "Start" : "Continue" }) })
17012
+ ] }) });
17013
+ }
16738
17014
  function useDestructiveAction(options) {
16739
17015
  const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, doneMessage, undoMessage, restoredMessage, severity } = options;
16740
17016
  const preferences = useShellPreferences();
@@ -16900,6 +17176,9 @@ function pastTenseOf(label) {
16900
17176
  }
16901
17177
  var SectionHeading = forwardRef(function SectionHeading2({
16902
17178
  title,
17179
+ onTitleChange,
17180
+ titleLabel = "Title",
17181
+ titleId,
16903
17182
  description,
16904
17183
  actions,
16905
17184
  badge,
@@ -16911,6 +17190,8 @@ var SectionHeading = forwardRef(function SectionHeading2({
16911
17190
  }, ref) {
16912
17191
  const isPhone = useBreakpoint("sm");
16913
17192
  const pane = variant === "pane";
17193
+ const inDetail = useContext(SplitPaneCtx) === "detail";
17194
+ const editable = !!onTitleChange;
16914
17195
  return /* @__PURE__ */ jsxs(
16915
17196
  "div",
16916
17197
  {
@@ -16918,7 +17199,7 @@ var SectionHeading = forwardRef(function SectionHeading2({
16918
17199
  "data-gs": "section-heading",
16919
17200
  "data-variant": variant,
16920
17201
  className: cn(
16921
- pane ? "shrink-0 px-ds-4 pt-ds-4 pb-ds-3 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]" : "mb-[var(--ds-heading-gap)]",
17202
+ pane ? cn("shrink-0 pt-ds-4 pb-ds-3 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", inDetail ? "px-[var(--ds-page-gutter)]" : "px-ds-4") : "mb-[var(--ds-heading-gap)]",
16922
17203
  !pane && bordered && "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] pb-ds-4",
16923
17204
  className
16924
17205
  ),
@@ -16927,11 +17208,23 @@ var SectionHeading = forwardRef(function SectionHeading2({
16927
17208
  "flex gap-ds-4",
16928
17209
  // the actions wrap under the title when the two do not fit on one line (round 11: a search Input in a 284 px
16929
17210
  // pane's actions slot squeezed "Inbox" to "I."); below sm they always stack
16930
- isPhone && actions ? "flex-col" : "flex-wrap items-start justify-between"
17211
+ isPhone && actions ? "flex-col" : cn("flex-wrap justify-between", editable && !description ? "items-center" : "items-start")
16931
17212
  ), children: [
16932
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
17213
+ /* @__PURE__ */ jsxs("div", { className: cn("min-w-0", editable && !(isPhone && actions) && "flex-[1_1_20ch] text-lg"), children: [
16933
17214
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
16934
- /* @__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 }),
17215
+ editable ? (
17216
+ // the field is the title: the heading holds it, so the page's headings still name the view by its title
17217
+ /* @__PURE__ */ jsx("h2", { id: titleId, className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
17218
+ Input,
17219
+ {
17220
+ size: "md",
17221
+ "aria-label": titleLabel,
17222
+ value: title,
17223
+ onChange: (e) => onTitleChange(e.target.value),
17224
+ className: "font-[family-name:var(--ds-font-display)] text-lg font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)]"
17225
+ }
17226
+ ) })
17227
+ ) : /* @__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 }),
16935
17228
  badge,
16936
17229
  count !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "neutral", size: "sm", children: count })
16937
17230
  ] }),
@@ -16987,6 +17280,23 @@ var ActionPanelGroup = forwardRef(function ActionPanelGroup2({
16987
17280
  }
16988
17281
  );
16989
17282
  });
17283
+ function DangerZone({ title = "Danger zone", description, children, className }) {
17284
+ const titleId = useId();
17285
+ return /* @__PURE__ */ jsxs("section", { "aria-labelledby": titleId, "data-gs": "danger-zone", className, children: [
17286
+ /* @__PURE__ */ jsx(SectionHeading, { title, titleId, description }),
17287
+ /* @__PURE__ */ jsx(
17288
+ "div",
17289
+ {
17290
+ "data-danger-frame": "",
17291
+ className: cn(
17292
+ "rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)] border-[length:var(--ds-border-width)] border-[var(--ds-status-error)] px-ds-5",
17293
+ GLASS_SURFACE
17294
+ ),
17295
+ children: /* @__PURE__ */ jsx(ActionPanelGroup, { children })
17296
+ }
17297
+ )
17298
+ ] });
17299
+ }
16990
17300
  var lineClampClasses = {
16991
17301
  1: "truncate",
16992
17302
  2: "line-clamp-2",
@@ -17038,6 +17348,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
17038
17348
  return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
17039
17349
  });
17040
17350
 
17041
- export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, 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, FormWrapper, Gantt, HoverCard, Kbd, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, 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, timeExtent, useContentWidth, useDestructiveAction, useFittedLabels, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
17351
+ 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 };
17042
17352
  //# sourceMappingURL=index.js.map
17043
17353
  //# sourceMappingURL=index.js.map