gridsmith-ui 0.30.0 → 0.30.2

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 (70) hide show
  1. package/CHANGELOG.md +61 -1
  2. package/dist/charts.js +21 -8
  3. package/dist/charts.js.map +1 -1
  4. package/dist/chat.js +15 -9
  5. package/dist/chat.js.map +1 -1
  6. package/dist/{chunk-OIOII5L6.js → chunk-4HJDOZ2M.js} +303 -20
  7. package/dist/chunk-4HJDOZ2M.js.map +1 -0
  8. package/dist/{chunk-INGF2CPW.js → chunk-6C2IUMY7.js} +3 -3
  9. package/dist/{chunk-INGF2CPW.js.map → chunk-6C2IUMY7.js.map} +1 -1
  10. package/dist/chunk-ACLKDE5W.js +59 -0
  11. package/dist/chunk-ACLKDE5W.js.map +1 -0
  12. package/dist/{chunk-NLXQ323J.js → chunk-BZRZENBS.js} +5 -4
  13. package/dist/chunk-BZRZENBS.js.map +1 -0
  14. package/dist/{chunk-RHWTMTU5.js → chunk-DBHVJ7Z3.js} +5 -49
  15. package/dist/chunk-DBHVJ7Z3.js.map +1 -0
  16. package/dist/{chunk-Z4MCD73B.js → chunk-HVGHGBKV.js} +6 -7
  17. package/dist/chunk-HVGHGBKV.js.map +1 -0
  18. package/dist/{chunk-UNS4TGGK.js → chunk-K6IDOCGE.js} +77 -27
  19. package/dist/chunk-K6IDOCGE.js.map +1 -0
  20. package/dist/{chunk-Q36JVJX4.js → chunk-MIUSSYVE.js} +4 -4
  21. package/dist/{chunk-Q36JVJX4.js.map → chunk-MIUSSYVE.js.map} +1 -1
  22. package/dist/{chunk-F2BNJSON.js → chunk-SIWERRP2.js} +70 -69
  23. package/dist/chunk-SIWERRP2.js.map +1 -0
  24. package/dist/{chunk-KTPGMJUK.js → chunk-SQHKC4HA.js} +8 -5
  25. package/dist/chunk-SQHKC4HA.js.map +1 -0
  26. package/dist/{chunk-NI5542ZM.js → chunk-USHW523V.js} +81 -24
  27. package/dist/chunk-USHW523V.js.map +1 -0
  28. package/dist/{chunk-GQVBZ4GW.js → chunk-WWN6CQKI.js} +31 -104
  29. package/dist/chunk-WWN6CQKI.js.map +1 -0
  30. package/dist/{chunk-JTU7OBYJ.js → chunk-YL5KD5RC.js} +4 -3
  31. package/dist/chunk-YL5KD5RC.js.map +1 -0
  32. package/dist/{chunk-6A5RHW2W.js → chunk-ZASGFL5D.js} +4 -5
  33. package/dist/chunk-ZASGFL5D.js.map +1 -0
  34. package/dist/chunk-ZCDA74RQ.js +110 -0
  35. package/dist/chunk-ZCDA74RQ.js.map +1 -0
  36. package/dist/data-grid.js +8 -10
  37. package/dist/data-grid.js.map +1 -1
  38. package/dist/editor-mentions.js +3 -5
  39. package/dist/editor-mentions.js.map +1 -1
  40. package/dist/editor.js +8 -7
  41. package/dist/editor.js.map +1 -1
  42. package/dist/index.d.ts +14 -1
  43. package/dist/index.js +198 -105
  44. package/dist/index.js.map +1 -1
  45. package/dist/kanban.js +11 -12
  46. package/dist/kanban.js.map +1 -1
  47. package/dist/resizable.js +42 -14
  48. package/dist/resizable.js.map +1 -1
  49. package/dist/utils.js.map +1 -1
  50. package/dist/virtualized.d.ts +6 -1
  51. package/dist/virtualized.js +12 -11
  52. package/dist/virtualized.js.map +1 -1
  53. package/package.json +1 -1
  54. package/dist/chunk-6A5RHW2W.js.map +0 -1
  55. package/dist/chunk-F2BNJSON.js.map +0 -1
  56. package/dist/chunk-GQVBZ4GW.js.map +0 -1
  57. package/dist/chunk-HP7WUZPK.js +0 -81
  58. package/dist/chunk-HP7WUZPK.js.map +0 -1
  59. package/dist/chunk-HTXP5BMM.js +0 -38
  60. package/dist/chunk-HTXP5BMM.js.map +0 -1
  61. package/dist/chunk-JTU7OBYJ.js.map +0 -1
  62. package/dist/chunk-KTPGMJUK.js.map +0 -1
  63. package/dist/chunk-NI5542ZM.js.map +0 -1
  64. package/dist/chunk-NLXQ323J.js.map +0 -1
  65. package/dist/chunk-OIOII5L6.js.map +0 -1
  66. package/dist/chunk-RHWTMTU5.js.map +0 -1
  67. package/dist/chunk-UNS4TGGK.js.map +0 -1
  68. package/dist/chunk-WH2FUFAC.js +0 -15
  69. package/dist/chunk-WH2FUFAC.js.map +0 -1
  70. package/dist/chunk-Z4MCD73B.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
1
  "use client";
2
- import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useCornerInset, NAVBAR_INSET_PRIORITY, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, besideRoom, PANEL_INSET_PRIORITY, Drawer, useRememberedWidth, pxOf, ResizeEdge, LAUNCHER_INSET_PRIORITY, defaultMaxWidth } from './chunk-UNS4TGGK.js';
3
- export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-UNS4TGGK.js';
4
- import { Skeleton, TITLE_TEXT } from './chunk-INGF2CPW.js';
5
- export { Skeleton } from './chunk-INGF2CPW.js';
2
+ import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useCornerInset, NAVBAR_INSET_PRIORITY, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, besideRoom, PANEL_INSET_PRIORITY, Drawer, useRememberedWidth, pxOf, ResizeEdge, LAUNCHER_INSET_PRIORITY, defaultMaxWidth } from './chunk-K6IDOCGE.js';
3
+ export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-K6IDOCGE.js';
4
+ import { Skeleton, TITLE_TEXT } from './chunk-6C2IUMY7.js';
5
+ export { Skeleton } from './chunk-6C2IUMY7.js';
6
6
  import { useScrollEdges, EDGE_FADE } from './chunk-3BRQRKDO.js';
7
- import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-6A5RHW2W.js';
8
- export { Avatar } from './chunk-6A5RHW2W.js';
9
- import { Link } from './chunk-KTPGMJUK.js';
10
- export { CodeBlock, Divider, Link } from './chunk-KTPGMJUK.js';
11
- import { DropdownMenu } from './chunk-Z4MCD73B.js';
12
- export { DropdownMenu } from './chunk-Z4MCD73B.js';
13
- import { useFillHeight, FillContext, useKeyboardScroll } from './chunk-RHWTMTU5.js';
14
- import { Badge } from './chunk-NLXQ323J.js';
15
- export { Badge } from './chunk-NLXQ323J.js';
16
- import { localeCache, startOfDay, addDays, useWeekStart, useDateWords, localeDayFirst, dayKey, moveDay, addMonths, DateSegmentFields, getMonthGrid, isSameMonth, isSameDay, DatePicker, timeSegments, pad2, inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, Checkbox, CardValue, SortIndicator, startOfWeek, endOfWeek, addMonthsClamped, isExcludedDay, CutCell, CutEmail, stepValue, separatorMovesOn, TIME_SEPARATORS, typeDigit, getEventsForDay, layoutWeek, isWeekend, getWeekDays, isBarEvent, layoutPieces, dayPieces, groupEventsByDay, timeToFraction } from './chunk-F2BNJSON.js';
17
- export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-F2BNJSON.js';
18
- 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, OutsideField, NumberInput, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-NI5542ZM.js';
19
- export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-NI5542ZM.js';
7
+ import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-ZASGFL5D.js';
8
+ export { Avatar } from './chunk-ZASGFL5D.js';
9
+ import { Link } from './chunk-SQHKC4HA.js';
10
+ export { CodeBlock, Divider, Link } from './chunk-SQHKC4HA.js';
11
+ import { DropdownMenu } from './chunk-HVGHGBKV.js';
12
+ export { DropdownMenu } from './chunk-HVGHGBKV.js';
13
+ import { useFillHeight, FillContext } from './chunk-DBHVJ7Z3.js';
14
+ import { Badge } from './chunk-BZRZENBS.js';
15
+ export { Badge } from './chunk-BZRZENBS.js';
16
+ import { useKeyboardScroll } from './chunk-ACLKDE5W.js';
17
+ import { localeCache, startOfDay, addDays, useWeekStart, useDateWords, localeDayFirst, dayKey, moveDay, addMonths, DateSegmentFields, getMonthGrid, isSameMonth, isSameDay, DatePicker, timeSegments, pad2, inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, Checkbox, CardValue, SortIndicator, startOfWeek, endOfWeek, addMonthsClamped, isExcludedDay, CutCell, CutEmail, stepValue, separatorMovesOn, TIME_SEPARATORS, typeDigit, getEventsForDay, layoutWeek, isWeekend, getWeekDays, isBarEvent, layoutPieces, dayPieces, groupEventsByDay, timeToFraction } from './chunk-SIWERRP2.js';
18
+ export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-SIWERRP2.js';
19
+ 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, OutsideField, NumberInput, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-USHW523V.js';
20
+ export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-USHW523V.js';
20
21
  import { useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, formatRelativeTime, thresholdOf, toMillis, formatFullTime, datedMillis, preferenceActionKey, DAY, HOUR, MINUTE } from './chunk-TYNDXMBV.js';
21
22
  export { PreferencesContext, formatFullTime, formatRelativeTime, preferenceActionKey, usePreferences } from './chunk-TYNDXMBV.js';
22
23
  import { useFormatLocale, useHydrated, useToday, LocaleContext } from './chunk-LJYSVZMI.js';
@@ -26,26 +27,31 @@ import { useInputModality, inputModality } from './chunk-7RKC5C7G.js';
26
27
  export { INPUT_MODALITY_ATTR, inputModality, installInputModality, useInputModality } from './chunk-7RKC5C7G.js';
27
28
  import { FormChangeCtx, useReportedChange, useOptionalFormContext, FormCtx } from './chunk-72SDAX54.js';
28
29
  export { useFormContext } from './chunk-72SDAX54.js';
29
- import { Button, CardSurfaceCtx, useScrollsInside, SplitPaneCtx, RowsCtx, PageActionsCtx, ControlSizeContext, triggerType, SurfaceBoundary, Spinner, useFramesItself, TableCardCtx } from './chunk-Q36JVJX4.js';
30
- export { Button, ButtonSizeContext, ControlSizeContext, Spinner } from './chunk-Q36JVJX4.js';
30
+ import { Button, CardSurfaceCtx, useScrollsInside, SplitPaneCtx, RowsCtx, PageActionsCtx, ControlSizeContext, triggerType, SurfaceBoundary, Spinner, useFramesItself, TableCardCtx } from './chunk-MIUSSYVE.js';
31
+ export { Button, ButtonSizeContext, ControlSizeContext, Spinner } from './chunk-MIUSSYVE.js';
31
32
  import { elementType } from './chunk-NKUCS67T.js';
32
33
  import { useBreakpoint, readBreakpointPx } from './chunk-ZHUVLBCC.js';
33
34
  export { BreakpointWidthProvider, useBreakpoint } from './chunk-ZHUVLBCC.js';
34
- import { useRevealFocus } from './chunk-HTXP5BMM.js';
35
- export { useRevealFocus } from './chunk-HTXP5BMM.js';
36
- import { focusAfterSelfRemoval, FOCUSABLE, FIELD, ZOOM_KEYS, rovingTabStop, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, usePopupFocus, CONTROL_ANCESTOR, useGridKeyboard, focusAfterRemoval, useNonModalDialog, useReturnFocus } from './chunk-OIOII5L6.js';
37
- export { useGridKeyboard } from './chunk-OIOII5L6.js';
38
- import { useTextOverflow, AutoTooltip } from './chunk-GQVBZ4GW.js';
39
- export { Tooltip, useTextOverflow } from './chunk-GQVBZ4GW.js';
40
- import { mergeRefs } from './chunk-7Q46JXSK.js';
35
+ import { useTextOverflow } from './chunk-ZCDA74RQ.js';
36
+ export { useTextOverflow } from './chunk-ZCDA74RQ.js';
37
+ import { AutoTooltip, useRevealFocus } from './chunk-WWN6CQKI.js';
38
+ export { Tooltip, useRevealFocus } from './chunk-WWN6CQKI.js';
41
39
  import { Icon, slotIcon, warnOnce } from './chunk-L6HWACK7.js';
42
- import { usePosition } from './chunk-HP7WUZPK.js';
43
- import { useLatest } from './chunk-WH2FUFAC.js';
44
- import { cn, FOCUS_RING, GLASS_SURFACE, FOCUS_INSET, PEER_FOCUS_RING, GLASS_BACKDROP, FOCUS_ROOM, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, GROUP_FOCUS_RING, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, GLASS_DROPDOWN, ERROR_FOCUS_RING, FIELD_FOCUS_RING, atLeastFocusRoom } from './chunk-JTU7OBYJ.js';
40
+ import { mergeRefs } from './chunk-7Q46JXSK.js';
41
+ import { focusAfterSelfRemoval, FOCUSABLE, useFocusKeptInList, useLatest, FIELD, ZOOM_KEYS, rovingTabStop, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberOpener, focusInitial, OVERLAY_CLOSE_ATTR, usePopupFocus, usePosition, CONTROL_ANCESTOR, useGridKeyboard, focusAfterRemoval, useNonModalDialog, useReturnFocus } from './chunk-4HJDOZ2M.js';
42
+ export { useGridKeyboard } from './chunk-4HJDOZ2M.js';
43
+ import { cn, FOCUS_RING, GLASS_SURFACE, FOCUS_INSET, PEER_FOCUS_RING, GLASS_BACKDROP, FOCUS_ROOM, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, GROUP_FOCUS_RING, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, GLASS_DROPDOWN, ERROR_FOCUS_RING, FIELD_FOCUS_RING, atLeastFocusRoom } from './chunk-YL5KD5RC.js';
45
44
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
46
- import { forwardRef, useRef, useId, useEffect, useState, createContext, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, memo, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore, useReducer } from 'react';
45
+ import { forwardRef, useRef, useId, useEffect, useState, createContext, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, memo, useImperativeHandle, useSyncExternalStore, Children, Fragment as Fragment$1, cloneElement, useReducer } from 'react';
47
46
  import { createPortal, flushSync } from 'react-dom';
48
47
 
48
+ function selectAllFor(bar) {
49
+ for (let box = bar?.parentElement; bar && box && box !== document.body; box = box.parentElement) {
50
+ const all = Array.from(box.querySelectorAll("[data-ds-select-all] input"));
51
+ if (all.length) return all.find((el) => bar.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING) ?? all[all.length - 1];
52
+ }
53
+ return null;
54
+ }
49
55
  function BulkActionBar({ selectedCount, actions, onClearSelection, className }) {
50
56
  const isMobile = useBreakpoint("sm");
51
57
  if (selectedCount === 0) return null;
@@ -96,7 +102,11 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
96
102
  "button",
97
103
  {
98
104
  type: "button",
99
- onClick: onClearSelection,
105
+ onClick: (e) => {
106
+ const bar = e.currentTarget.closest('[role="toolbar"]');
107
+ focusAfterSelfRemoval(e.currentTarget, { item: bar, to: selectAllFor(bar) });
108
+ onClearSelection();
109
+ },
100
110
  className: cn("ml-auto text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
101
111
  "aria-label": "Clear selection",
102
112
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
@@ -823,7 +833,7 @@ function DateRangePicker({
823
833
  onChange: takeTyped
824
834
  }
825
835
  ) }),
826
- /* @__PURE__ */ jsx(
836
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Choose a date range", children: /* @__PURE__ */ jsx(
827
837
  "button",
828
838
  {
829
839
  ref: buttonRef,
@@ -836,7 +846,7 @@ function DateRangePicker({
836
846
  className: cn("shrink-0 -mr-ds-1 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] disabled:cursor-not-allowed", FOCUS_RING),
837
847
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 })
838
848
  }
839
- )
849
+ ) })
840
850
  ]
841
851
  }
842
852
  ),
@@ -1703,8 +1713,8 @@ var sizeClasses = {
1703
1713
  full: "max-w-[calc(100vw-2rem)]"
1704
1714
  };
1705
1715
  function Dialog({ open, onClose: onCloseProp, title, description, children, footer, variant = "default", size = "md", alert = false, container, onSubmit, dirty, onDiscard }) {
1706
- const { marked, mark } = useOverlayMark(open);
1707
- const guard = useDirtyGuard(dirty ?? marked, onCloseProp, onDiscard);
1716
+ const { marked, pending, mark } = useOverlayMark(open);
1717
+ const guard = useDirtyGuard((dirty ?? marked) || pending, onCloseProp, onDiscard);
1708
1718
  const onClose = guard.requestClose;
1709
1719
  const titleId = useId();
1710
1720
  const descriptionId = useId();
@@ -1713,7 +1723,13 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1713
1723
  const dialogRef = useRef(null);
1714
1724
  const opener = useRef(null);
1715
1725
  const defaultButtonRef = useRef(null);
1716
- const bodyRef = useScrollbarInset();
1726
+ const bodyInset = useScrollbarInset();
1727
+ const [bodyEl, setBodyEl] = useState(null);
1728
+ const bodyRef = useCallback((el) => {
1729
+ bodyInset(el);
1730
+ setBodyEl(el);
1731
+ }, [bodyInset]);
1732
+ useKeyboardScroll(bodyEl, title, open);
1717
1733
  const onCloseRef = useLatest(onClose);
1718
1734
  const onSubmitRef = useLatest(onSubmit);
1719
1735
  const isTopLayer = useOverlayLayer(open);
@@ -1721,8 +1737,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1721
1737
  const before = useFocusBeforeOpen(open);
1722
1738
  useEffect(() => {
1723
1739
  if (!open) return;
1724
- const active = before.current;
1725
- opener.current = active instanceof HTMLElement && active !== document.body && active.isConnected ? rememberFocus(active) : null;
1740
+ opener.current = rememberOpener(before.current, dialogRef.current);
1726
1741
  }, [open, before]);
1727
1742
  useEffect(() => {
1728
1743
  if (!open) return;
@@ -1837,7 +1852,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1837
1852
  ),
1838
1853
  description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description })
1839
1854
  ] }),
1840
- /* @__PURE__ */ jsx(
1855
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Close", children: /* @__PURE__ */ jsx(
1841
1856
  "button",
1842
1857
  {
1843
1858
  type: "button",
@@ -1847,13 +1862,13 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1847
1862
  "aria-label": "Close",
1848
1863
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
1849
1864
  }
1850
- )
1865
+ ) })
1851
1866
  ] }),
1852
1867
  children && /* @__PURE__ */ jsx(
1853
1868
  "div",
1854
1869
  {
1855
1870
  ref: bodyRef,
1856
- className: "min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6",
1871
+ className: cn("min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6", FOCUS_INSET),
1857
1872
  style: {
1858
1873
  paddingLeft: variant === "destructive" ? "calc(var(--ds-page-gutter) + 2.5rem + var(--ds-space-3))" : "var(--ds-page-gutter)",
1859
1874
  paddingRight: insetLessScrollbar("var(--ds-page-gutter)")
@@ -2884,7 +2899,7 @@ function TimePicker({
2884
2899
  }
2885
2900
  )
2886
2901
  ] }),
2887
- /* @__PURE__ */ jsx(
2902
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Choose a time", children: /* @__PURE__ */ jsx(
2888
2903
  "button",
2889
2904
  {
2890
2905
  ref: buttonRef,
@@ -2898,7 +2913,7 @@ function TimePicker({
2898
2913
  className: cn("shrink-0 -mr-ds-1 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] disabled:cursor-not-allowed", FOCUS_RING),
2899
2914
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 })
2900
2915
  }
2901
- )
2916
+ ) })
2902
2917
  ]
2903
2918
  }
2904
2919
  ),
@@ -3099,7 +3114,7 @@ var Tag = forwardRef(function Tag2({
3099
3114
  children: label
3100
3115
  }
3101
3116
  ) : label,
3102
- onRemove && !disabled && /* @__PURE__ */ jsx(
3117
+ onRemove && !disabled && /* @__PURE__ */ jsx(AutoTooltip, { content: typeof children === "string" ? `Remove ${children}` : "Remove", children: /* @__PURE__ */ jsx(
3103
3118
  "button",
3104
3119
  {
3105
3120
  type: "button",
@@ -3115,7 +3130,7 @@ var Tag = forwardRef(function Tag2({
3115
3130
  ),
3116
3131
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: size === "sm" ? 10 : 12 })
3117
3132
  }
3118
- )
3133
+ ) })
3119
3134
  ]
3120
3135
  }
3121
3136
  );
@@ -3164,6 +3179,12 @@ function TagInput({
3164
3179
  const buttons = Array.from(containerRef.current?.querySelectorAll("[data-tag-remove]") ?? []);
3165
3180
  focusAfterRemoval(buttons, pending.index, inputRef.current);
3166
3181
  });
3182
+ const overlayMark = useContext(OverlayMarkCtx);
3183
+ const holdsText = input.trim() !== "";
3184
+ useEffect(() => {
3185
+ if (!holdsText || !overlayMark) return;
3186
+ return overlayMark.pend();
3187
+ }, [holdsText, overlayMark]);
3167
3188
  const handleKeyDown = useCallback(
3168
3189
  (e) => {
3169
3190
  if ((e.key === "Enter" || e.key === ",") && input.trim()) {
@@ -4311,7 +4332,10 @@ function TransferList({
4311
4332
  "button",
4312
4333
  {
4313
4334
  type: "button",
4314
- onClick: moveAllRight,
4335
+ onClick: (e) => {
4336
+ focusAfterSelfRemoval(e.currentTarget);
4337
+ moveAllRight();
4338
+ },
4315
4339
  disabled: !available.filter((i) => !i.disabled).length,
4316
4340
  "aria-label": isStacked ? "Move all down" : "Move all right",
4317
4341
  className: cn(actionButtonClass),
@@ -4322,7 +4346,10 @@ function TransferList({
4322
4346
  "button",
4323
4347
  {
4324
4348
  type: "button",
4325
- onClick: moveRight,
4349
+ onClick: (e) => {
4350
+ focusAfterSelfRemoval(e.currentTarget);
4351
+ moveRight();
4352
+ },
4326
4353
  disabled: !checkedAvailable.size,
4327
4354
  "aria-label": isStacked ? "Move selected down" : "Move selected right",
4328
4355
  className: cn(actionButtonClass),
@@ -4333,7 +4360,10 @@ function TransferList({
4333
4360
  "button",
4334
4361
  {
4335
4362
  type: "button",
4336
- onClick: moveLeft,
4363
+ onClick: (e) => {
4364
+ focusAfterSelfRemoval(e.currentTarget);
4365
+ moveLeft();
4366
+ },
4337
4367
  disabled: !checkedSelected.size,
4338
4368
  "aria-label": isStacked ? "Move selected up" : "Move selected left",
4339
4369
  className: cn(actionButtonClass),
@@ -4344,7 +4374,10 @@ function TransferList({
4344
4374
  "button",
4345
4375
  {
4346
4376
  type: "button",
4347
- onClick: moveAllLeft,
4377
+ onClick: (e) => {
4378
+ focusAfterSelfRemoval(e.currentTarget);
4379
+ moveAllLeft();
4380
+ },
4348
4381
  disabled: !selected.filter((i) => !i.disabled).length,
4349
4382
  "aria-label": isStacked ? "Move all up" : "Move all left",
4350
4383
  className: cn(actionButtonClass),
@@ -5004,7 +5037,7 @@ var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
5004
5037
  const menu = menuItems ? /* @__PURE__ */ jsx(
5005
5038
  DropdownMenu,
5006
5039
  {
5007
- trigger: /* @__PURE__ */ jsx(
5040
+ trigger: /* @__PURE__ */ jsx(AutoTooltip, { content: "More actions", children: /* @__PURE__ */ jsx(
5008
5041
  "button",
5009
5042
  {
5010
5043
  type: "button",
@@ -5018,7 +5051,7 @@ var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
5018
5051
  onClick: (e) => e.stopPropagation(),
5019
5052
  children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
5020
5053
  }
5021
- ),
5054
+ ) }),
5022
5055
  items: menuItems
5023
5056
  }
5024
5057
  ) : null;
@@ -5881,6 +5914,11 @@ function Table({
5881
5914
  useEffect(() => {
5882
5915
  if (unsortable) warnOnce("Table", `the column "${unsortable}" is sortable, but its cells are elements, which can't be compared: give it a sortValue, (row) => the name, number or date it shows (data_display#1).`);
5883
5916
  }, [unsortable]);
5917
+ const pageSorts = !!onSortChange;
5918
+ const refused = pageSorts ? "" : columns.filter((col) => col.sortable && !canSort.has(col.key)).map((col) => col.key).join(", ");
5919
+ useEffect(() => {
5920
+ if (refused) warnOnce("Table", `the column "${refused}" is marked sortable, but its cells are elements the Table can't compare, so it draws no sort button: give it a sortValue, (row) => the name, number or date it shows, or sort the rows yourself with sortKey and onSortChange (data_display#1).`);
5921
+ }, [refused]);
5884
5922
  useEffect(() => {
5885
5923
  if (pager && data.length !== pager.totalItems) warnOnce("Table", `the pager counts ${pager.totalItems} rows but data holds ${data.length}: give the table and usePagination the same rows, every row of the list, and the table draws the pager's part (Sprint 25.13 A3).`);
5886
5924
  }, [pager, data.length]);
@@ -5937,6 +5975,9 @@ function Table({
5937
5975
  const narrowScreen = useBreakpoint(mobileBreakpoint);
5938
5976
  const { cards: isMobile, rootRef } = useCardsSwitch(narrowScreen, cardsBelow, title);
5939
5977
  useRevealFocus(rootRef, isMobile);
5978
+ useFocusKeptInList(rootRef);
5979
+ const [cardsEl, setCardsEl] = useState(null);
5980
+ useKeyboardScroll(cardsEl, title ?? ariaLabel ?? "Table", isMobile);
5940
5981
  const setRoot = useCallback((node) => {
5941
5982
  rootRef.current = node;
5942
5983
  if (typeof ref === "function") ref(node);
@@ -6064,8 +6105,14 @@ function Table({
6064
6105
  cardHeading,
6065
6106
  body
6066
6107
  ] });
6067
- const control = pager && data.length > 0 ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
6108
+ const paged = !!pager && data.length > 0;
6109
+ const control = paged ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
6068
6110
  const listRoot = control ? void 0 : setRoot;
6111
+ const cardsAreRoot = !title && !paged;
6112
+ const setCards = useCallback((el) => {
6113
+ setCardsEl(el);
6114
+ if (cardsAreRoot) setRoot(el);
6115
+ }, [cardsAreRoot, setRoot]);
6069
6116
  const listClass = control ? void 0 : className;
6070
6117
  const withControl = (list2) => control ? /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
6071
6118
  list2,
@@ -6114,7 +6161,7 @@ function Table({
6114
6161
  if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
6115
6162
  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 });
6116
6163
  }
6117
- 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("relative flex flex-col gap-ds-3 overflow-y-auto -m-[4px] p-[4px] scroll-p-[4px]", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
6164
+ const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: setCards, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("relative flex flex-col gap-ds-3 overflow-y-auto -m-[4px] p-[4px] scroll-p-[4px]", FOCUS_INSET, title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
6118
6165
  loading && data.length > 0 && /* @__PURE__ */ jsx(RefreshLine, { className: "inset-x-[4px] rounded-full" }),
6119
6166
  selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
6120
6167
  drawn.map(({ row, originalIdx }) => {
@@ -6205,7 +6252,8 @@ function Table({
6205
6252
  const cellCount = columns.length + lead;
6206
6253
  const table = /* @__PURE__ */ jsxs("table", { ref: tableRef, "aria-busy": loading || void 0, className: cn("w-full text-sm", PINNED_LAYERS), ...title ? { "aria-labelledby": titleId, "aria-describedby": description ? descriptionId : void 0 } : ariaLabel ? { "aria-label": ariaLabel } : {}, children: [
6207
6254
  /* @__PURE__ */ jsx("thead", { className: cn("bg-[var(--ds-bg-muted)]", stickyHeader && "sticky top-0 z-10"), children: /* @__PURE__ */ jsxs("tr", { className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] [--gs-row-tint:var(--ds-bg-muted)]", children: [
6208
- selectable && /* @__PURE__ */ jsx("th", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(
6255
+ selectable && // data-ds-select-all: the selection's own control, where a BulkActionBar's Clear selection sends focus
6256
+ /* @__PURE__ */ jsx("th", { "data-ds-select-all": "", className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(
6209
6257
  Checkbox,
6210
6258
  {
6211
6259
  checked: allSelected,
@@ -6216,8 +6264,8 @@ function Table({
6216
6264
  ) }),
6217
6265
  expandable && /* @__PURE__ */ jsx("th", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(selectable ? 1 : 0, cellCount) }),
6218
6266
  columns.map((col, c) => {
6219
- const isSortable = col.header.trim() !== "" && (col.sortable ?? (!!sortable && canSort.has(col.key)));
6220
- const isActiveSort = sortKey === col.key && !!sortDir && unsortable !== col.key;
6267
+ const isSortable = col.header.trim() !== "" && (pageSorts ? col.sortable ?? (!!sortable && canSort.has(col.key)) : (col.sortable ?? !!sortable) && canSort.has(col.key));
6268
+ const isActiveSort = sortKey === col.key && !!sortDir && (pageSorts || unsortable !== col.key);
6221
6269
  const headerKind = kindOf2(col);
6222
6270
  const headerAlign = col.align ?? (headerKind === "number" ? "right" : "left");
6223
6271
  const shrink = (headerKind === "number" || headerKind === "date") && !col.maxWidth;
@@ -6319,7 +6367,7 @@ function Table({
6319
6367
  } : void 0,
6320
6368
  children: [
6321
6369
  selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3", pinFocus(0, cellCount)), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: (_, { shiftKey: shiftKey2 }) => toggleRow(originalIdx, shiftKey2), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-name-${idPart(id)}` : `${headingId}-select` }) }),
6322
- expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3", pinFocus(selectable ? 1 : 0, cellCount)), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(
6370
+ expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3", pinFocus(selectable ? 1 : 0, cellCount)), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(AutoTooltip, { content: "Details", children: /* @__PURE__ */ jsx(
6323
6371
  "button",
6324
6372
  {
6325
6373
  type: "button",
@@ -6336,7 +6384,7 @@ function Table({
6336
6384
  }
6337
6385
  )
6338
6386
  }
6339
- ) }),
6387
+ ) }) }),
6340
6388
  columns.map((col, c) => {
6341
6389
  const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
6342
6390
  const kind = kindOf2(col);
@@ -7218,6 +7266,12 @@ function WeekView({ date, events, categories, selectedDate, onDayClick, onOpenEv
7218
7266
  useRevealFocus(allDayRef);
7219
7267
  useRevealFocus(scrollerRef);
7220
7268
  const { ref: edgesRef, measure: measureEdges, fadeProps: edgeFade } = useScrollEdges();
7269
+ const [dayStrip, setDayStrip] = useState(null);
7270
+ const setDays = useCallback((el) => {
7271
+ edgesRef(el);
7272
+ setDayStrip(el);
7273
+ }, [edgesRef]);
7274
+ useKeyboardScroll(dayStrip, "Days", true, false, "x");
7221
7275
  const [list2, setList] = useState(null);
7222
7276
  const handleScroll = useCallback((e) => {
7223
7277
  if (syncingScroll.current) return;
@@ -7342,7 +7396,7 @@ function WeekView({ date, events, categories, selectedDate, onDayClick, onOpenEv
7342
7396
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "flex flex-col h-full overflow-hidden", onKeyDown: grid.onKeyDown, children: [
7343
7397
  /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: [
7344
7398
  /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]" }),
7345
- /* @__PURE__ */ jsx("div", { ref: edgesRef, onScroll: measureEdges, ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx("div", { className: "grid", style: { gridTemplateColumns: dayGridColumns, minWidth: stripWidth }, children: days.map((day, i) => /* @__PURE__ */ jsxs("div", { className: cn("text-center py-ds-2", i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", selectedDate && isSameDay(day, selectedDate) && "bg-[var(--ds-accent-whisper)]"), children: [
7399
+ /* @__PURE__ */ jsx("div", { ref: setDays, onScroll: measureEdges, ...edgeFade, className: cn("flex-1 overflow-x-auto gs-scrollbar-none", FOCUS_INSET), "data-week-scroll": true, children: /* @__PURE__ */ jsx("div", { className: "grid", style: { gridTemplateColumns: dayGridColumns, minWidth: stripWidth }, children: days.map((day, i) => /* @__PURE__ */ jsxs("div", { className: cn("text-center py-ds-2", i > 0 && "border-l-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", selectedDate && isSameDay(day, selectedDate) && "bg-[var(--ds-accent-whisper)]"), children: [
7346
7400
  /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] font-medium", children: names[i] }),
7347
7401
  /* @__PURE__ */ jsx("div", { className: cn("text-lg font-semibold mt-ds-0.5 mx-auto w-8 h-8 flex items-center justify-center rounded-[var(--ds-radius-full)]", isToday(day) ? TODAY_CIRCLE : "text-[var(--ds-text-primary)]"), children: day.getDate() })
7348
7402
  ] }, i)) }) })
@@ -8793,7 +8847,9 @@ function ExpandableDescription({ children, className }) {
8793
8847
  );
8794
8848
  }
8795
8849
  function HorizontalLayout({ items, minItemWidth, className }) {
8796
- return /* @__PURE__ */ jsx("div", { "data-timeline-row": "", className: cn("relative flex items-start overflow-x-auto snap-x", className), children: items.map((item, i) => {
8850
+ const [row, setRow] = useState(null);
8851
+ useKeyboardScroll(row, "Timeline", true, false, "x");
8852
+ return /* @__PURE__ */ jsx("div", { ref: setRow, "data-timeline-row": "", className: cn("relative flex items-start overflow-x-auto snap-x", FOCUS_INSET, className), children: items.map((item, i) => {
8797
8853
  const isFirst = i === 0;
8798
8854
  const isLast = i === items.length - 1;
8799
8855
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 shrink-0 flex-col items-center snap-start", style: { minWidth: minItemWidth }, children: [
@@ -9242,6 +9298,7 @@ function TreeNodeRow({
9242
9298
  CheckboxIndicator2,
9243
9299
  {
9244
9300
  state: checkState,
9301
+ label: node.label,
9245
9302
  onClick: (e) => {
9246
9303
  e.stopPropagation();
9247
9304
  handleCheck(node);
@@ -9275,12 +9332,13 @@ function TreeNodeRow({
9275
9332
  )) })
9276
9333
  ] });
9277
9334
  }
9278
- function CheckboxIndicator2({ state, onClick }) {
9335
+ function CheckboxIndicator2({ state, label, onClick }) {
9279
9336
  const filled = state !== "unchecked";
9280
9337
  return /* @__PURE__ */ jsx(
9281
9338
  "span",
9282
9339
  {
9283
9340
  role: "checkbox",
9341
+ "aria-label": label,
9284
9342
  "aria-checked": state === "indeterminate" ? "mixed" : state === "checked",
9285
9343
  className: cn(
9286
9344
  "flex items-center justify-center shrink-0 h-[18px] w-[18px] rounded-[calc(var(--ds-radius-sm)*0.6)] border-[2px] transition-all cursor-pointer",
@@ -9451,7 +9509,7 @@ function Carousel({
9451
9509
  ),
9452
9510
  /* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: said }),
9453
9511
  showArrows && count > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
9454
- /* @__PURE__ */ jsx(
9512
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Previous slide", children: /* @__PURE__ */ jsx(
9455
9513
  "button",
9456
9514
  {
9457
9515
  type: "button",
@@ -9461,8 +9519,8 @@ function Carousel({
9461
9519
  className: cn("absolute left-ds-4 top-1/2 -translate-y-1/2 z-10", ROUND_BUTTON, !canPrev && "opacity-0 pointer-events-none"),
9462
9520
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16, className: "rotate-180" })
9463
9521
  }
9464
- ),
9465
- /* @__PURE__ */ jsx(
9522
+ ) }),
9523
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Next slide", children: /* @__PURE__ */ jsx(
9466
9524
  "button",
9467
9525
  {
9468
9526
  type: "button",
@@ -9472,7 +9530,7 @@ function Carousel({
9472
9530
  className: cn("absolute right-ds-4 top-1/2 -translate-y-1/2 z-10", ROUND_BUTTON, !canNext && "opacity-0 pointer-events-none"),
9473
9531
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
9474
9532
  }
9475
- )
9533
+ ) })
9476
9534
  ] }),
9477
9535
  showIndicators && count > 1 && /* @__PURE__ */ jsx("div", { className: "absolute bottom-ds-3 left-1/2 -translate-x-1/2 flex gap-ds-1.5 z-10", children: children.map((_, i) => /* @__PURE__ */ jsx(
9478
9536
  "button",
@@ -9722,7 +9780,10 @@ function ChatInputBar({ onSend, busy, onStop, onAttach, onVoice, placeholder })
9722
9780
  ) });
9723
9781
  }
9724
9782
  function Suggestions({ items, onPick, className }) {
9725
- return /* @__PURE__ */ jsx("div", { "data-suggestions": "", className: cn("flex flex-wrap gap-ds-2", className), children: items.map((s) => /* @__PURE__ */ jsx(Tag, { variant: "default", size: "md", onClick: () => onPick(s), children: s }, s)) });
9783
+ const pressed = useRef(null);
9784
+ return /* @__PURE__ */ jsx("div", { "data-suggestions": "", className: cn("flex flex-wrap gap-ds-2", className), onClickCapture: (e) => {
9785
+ pressed.current = e.target.closest("button");
9786
+ }, children: items.map((s) => /* @__PURE__ */ jsx(Tag, { variant: "default", size: "md", onClick: () => onPick(s, pressed.current), children: s }, s)) });
9726
9787
  }
9727
9788
  var NEAR_BOTTOM_PX = 24;
9728
9789
  function ChatMessageList({
@@ -9751,7 +9812,7 @@ function ChatMessageList({
9751
9812
  scrollRef.current = node;
9752
9813
  setScroller(node);
9753
9814
  }, []);
9754
- useRevealFocus(scroller);
9815
+ useKeyboardScroll(scroller, "Messages");
9755
9816
  const atBottomRef = useRef(true);
9756
9817
  const [showJump, setShowJump] = useState(false);
9757
9818
  const [prevMessages, setPrevMessages] = useState(messages);
@@ -9790,12 +9851,16 @@ function ChatMessageList({
9790
9851
  return () => observer.disconnect();
9791
9852
  }, [autoScroll, scrollToBottom]);
9792
9853
  const empty = messages.length === 0;
9793
- const pick = (text) => onSend?.(text);
9854
+ const rootRef = useRef(null);
9855
+ const pick = (text, from) => {
9856
+ if (from) focusAfterSelfRemoval(from, { item: from.closest("[data-suggestions]"), to: () => rootRef.current?.querySelector("textarea") });
9857
+ onSend?.(text);
9858
+ };
9794
9859
  const showSuggestionsAfterReply = !empty && suggestionsMode === "always" && !!suggestions?.length;
9795
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col flex-1 min-h-0", className), children: [
9860
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("flex flex-col flex-1 min-h-0", className), children: [
9796
9861
  /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: announcement }),
9797
9862
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-h-0", children: [
9798
- /* @__PURE__ */ jsx("div", { ref: setScroll, onScroll, className: "h-full overflow-y-auto scroll-p-[4px]", children: empty ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-ds-6 px-ds-4 py-ds-8 text-center", children: [
9863
+ /* @__PURE__ */ jsx("div", { ref: setScroll, onScroll, className: cn("h-full overflow-y-auto scroll-p-[4px]", FOCUS_INSET), children: empty ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-ds-6 px-ds-4 py-ds-8 text-center", children: [
9799
9864
  emptyState ?? /* @__PURE__ */ jsx(
9800
9865
  EmptyState,
9801
9866
  {
@@ -9911,8 +9976,8 @@ function ChatPanel({
9911
9976
  ] });
9912
9977
  }
9913
9978
  function Sheet({ open, onClose: onCloseProp, title, children, footer, dirty, onDiscard, snapPoints = [0.5, 0.92], container, flush, keepMounted = false, id, labelledBy }) {
9914
- const { marked, mark } = useOverlayMark(open);
9915
- const guard = useDirtyGuard(dirty ?? marked, onCloseProp, onDiscard);
9979
+ const { marked, pending, mark } = useOverlayMark(open);
9980
+ const guard = useDirtyGuard((dirty ?? marked) || pending, onCloseProp, onDiscard);
9916
9981
  return /* @__PURE__ */ jsx(
9917
9982
  DrawerPanel,
9918
9983
  {
@@ -10220,13 +10285,20 @@ var StackedList = forwardRef(function StackedList2({
10220
10285
  const articles = variant === "articles";
10221
10286
  useWholeListCheck("StackedList", items.length, pager);
10222
10287
  const shown = pagerPart(items, pager);
10288
+ const listRef = useRef(null);
10289
+ useFocusKeptInList(listRef);
10290
+ const setList = useCallback((node) => {
10291
+ listRef.current = node;
10292
+ if (typeof ref === "function") ref(node);
10293
+ else if (ref) ref.current = node;
10294
+ }, [ref]);
10223
10295
  const stackMeta = isPhone && articles;
10224
10296
  const selectable = selectedId !== void 0 || items.some((i) => i.selected !== void 0);
10225
10297
  const inset = articles ? inCard ? "px-ds-5" : "px-0" : inCard ? "px-ds-5" : inPane ? "pl-ds-3 pr-ds-4" : selectable ? "pl-ds-3 pr-0" : "px-0";
10226
10298
  const list2 = /* @__PURE__ */ jsx(
10227
10299
  "ul",
10228
10300
  {
10229
- ref,
10301
+ ref: setList,
10230
10302
  "data-ds-list": "",
10231
10303
  className: cn(
10232
10304
  divided && "divide-y-[length:var(--ds-border-width)] divide-[var(--ds-border-subtle)]",
@@ -11119,11 +11191,11 @@ var TimeViewport = forwardRef(function TimeViewport2({
11119
11191
  /* @__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] }),
11120
11192
  /* @__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 }) })
11121
11193
  ] }),
11122
- /* @__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 }) }),
11194
+ /* @__PURE__ */ jsx(PeriodButton, { direction: -1, store, end: Math.max(0, drawn.width - visibleWidth), onPage: (d) => api.page(d) }),
11123
11195
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: todayAtX === null, onClick: () => {
11124
11196
  if (todayAtX !== null) setLeft(todayAtX - visibleWidth / 2);
11125
11197
  }, children: "Today" }),
11126
- /* @__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 }) }),
11198
+ /* @__PURE__ */ jsx(PeriodButton, { direction: 1, store, end: Math.max(0, drawn.width - visibleWidth), onPage: (d) => api.page(d) }),
11127
11199
  toolbar
11128
11200
  ] })
11129
11201
  );
@@ -11244,6 +11316,13 @@ function TimeBar({ start, end, minWidth = 0, labels, children, className, style,
11244
11316
  }
11245
11317
  );
11246
11318
  }
11319
+ function PeriodButton({ direction, store, end, onPage }) {
11320
+ const left = useSyncExternalStore(store.subscribe, () => store.get().scrollLeft, () => 0);
11321
+ const unavailable = direction < 0 ? left <= 0.5 : end > 0 && left >= end - 0.5;
11322
+ return /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": direction < 0 ? "Previous period" : "Next period", "aria-disabled": unavailable || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => {
11323
+ if (!unavailable) onPage(direction);
11324
+ }, children: /* @__PURE__ */ jsx(Icon, { name: direction < 0 ? "chevron-left" : "chevron-right", size: 14 }) });
11325
+ }
11247
11326
  function LocaleProvider({ lang, acceptLanguage, children }) {
11248
11327
  const value = useMemo(() => localeChoice(lang, acceptLanguage), [lang, acceptLanguage]);
11249
11328
  return /* @__PURE__ */ jsx(LocaleContext.Provider, { value, children });
@@ -12201,7 +12280,7 @@ function useScrollTrack(stopTab, enabled) {
12201
12280
  };
12202
12281
  }
12203
12282
  var SCROLL_TRACK = "overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden";
12204
- function TabStrip({ overflow, fullWidth, track, className, children }) {
12283
+ function TabStrip({ overflow, fullWidth, track, label, className, children }) {
12205
12284
  const scrolls = overflow === "scroll";
12206
12285
  return /* @__PURE__ */ jsx("div", { className: cn("min-w-0 max-w-full", fullWidth && "w-full", className), children: /* @__PURE__ */ jsx(
12207
12286
  "div",
@@ -12209,7 +12288,7 @@ function TabStrip({ overflow, fullWidth, track, className, children }) {
12209
12288
  ...scrolls ? track : {},
12210
12289
  "data-gs-clip": scrolls ? void 0 : "",
12211
12290
  className: cn("relative -m-[4px] p-[4px] scroll-px-[4px]", scrolls ? SCROLL_TRACK : "overflow-hidden"),
12212
- children: /* @__PURE__ */ jsx("div", { role: "tablist", className: cn(trackClasses("horizontal"), scrolls ? "w-max min-w-full" : "w-full"), children })
12291
+ children: /* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": label, className: cn(trackClasses("horizontal"), scrolls ? "w-max min-w-full" : "w-full"), children })
12213
12292
  }
12214
12293
  ) });
12215
12294
  }
@@ -12370,7 +12449,7 @@ function TabButton({
12370
12449
  return btn;
12371
12450
  }
12372
12451
  function TabsList({ children, className }) {
12373
- const { orientation, fullWidth, overflow, stopTab } = useTabsCtx();
12452
+ const { orientation, fullWidth, overflow, stopTab, label } = useTabsCtx();
12374
12453
  const track = useScrollTrack(stopTab, orientation === "horizontal" && overflow === "scroll");
12375
12454
  if (orientation === "vertical") {
12376
12455
  return /* @__PURE__ */ jsx(
@@ -12378,12 +12457,13 @@ function TabsList({ children, className }) {
12378
12457
  {
12379
12458
  role: "tablist",
12380
12459
  "aria-orientation": "vertical",
12460
+ "aria-label": label,
12381
12461
  className: cn(trackClasses("vertical"), className),
12382
12462
  children
12383
12463
  }
12384
12464
  );
12385
12465
  }
12386
- return /* @__PURE__ */ jsx(TabStrip, { overflow, fullWidth, track, className, children });
12466
+ return /* @__PURE__ */ jsx(TabStrip, { overflow, fullWidth, track, label, className, children });
12387
12467
  }
12388
12468
  function TabsTrigger({ value, children, count, icon, disabled, truncate, className }) {
12389
12469
  const { activeTab, onTabChange, orientation, fullWidth, overflow, activation, stopTab, setFocusedTab } = useTabsCtx();
@@ -12430,6 +12510,7 @@ function TabsRoot(props) {
12430
12510
  fullWidth = false,
12431
12511
  overflow = "scroll",
12432
12512
  activation = "automatic",
12513
+ "aria-label": ariaLabel,
12433
12514
  className
12434
12515
  } = props;
12435
12516
  const isMobile = useBreakpoint("md");
@@ -12453,6 +12534,7 @@ function TabsRoot(props) {
12453
12534
  options: tabs.filter((t) => !t.disabled).map((t) => ({ id: t.id, label: t.label, group: t.group })),
12454
12535
  value: activeTab,
12455
12536
  onChange: (v) => onTabChange(v),
12537
+ "aria-label": ariaLabel ?? "Contents",
12456
12538
  className
12457
12539
  }
12458
12540
  ) })
@@ -12464,6 +12546,7 @@ function TabsRoot(props) {
12464
12546
  {
12465
12547
  role: "tablist",
12466
12548
  "aria-orientation": "vertical",
12549
+ "aria-label": ariaLabel,
12467
12550
  className: cn(trackClasses("vertical"), className),
12468
12551
  children: tabs.map((tab, i) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
12469
12552
  tab.group && tab.group !== tabs[i - 1]?.group && /* @__PURE__ */ jsx(
@@ -12482,9 +12565,9 @@ function TabsRoot(props) {
12482
12565
  }
12483
12566
  );
12484
12567
  }
12485
- return /* @__PURE__ */ jsx(TabStrip, { overflow: arrayOverflow, fullWidth, track, className, children: tabs.map((tab, i) => /* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation, activeTab, onTabChange, fullWidth, isTabStop: i === stopIndex, setFocusedTab, onKeyDown: (e) => handleTabKeyDown(e, tab.id, () => tabs, effectiveOrientation, select) }, tab.id)) });
12568
+ return /* @__PURE__ */ jsx(TabStrip, { overflow: arrayOverflow, fullWidth, track, label: ariaLabel, className, children: tabs.map((tab, i) => /* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation, activeTab, onTabChange, fullWidth, isTabStop: i === stopIndex, setFocusedTab, onKeyDown: (e) => handleTabKeyDown(e, tab.id, () => tabs, effectiveOrientation, select) }, tab.id)) });
12486
12569
  }
12487
- return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { activeTab, onTabChange, orientation: effectiveOrientation, fullWidth, overflow, activation, stopTab, setFocusedTab }, children: /* @__PURE__ */ jsx("div", { className, children: props.children }) });
12570
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { activeTab, onTabChange, orientation: effectiveOrientation, fullWidth, overflow, activation, stopTab, setFocusedTab, label: ariaLabel }, children: /* @__PURE__ */ jsx("div", { className, children: props.children }) });
12488
12571
  }
12489
12572
  var Tabs = Object.assign(TabsRoot, {
12490
12573
  List: TabsList,
@@ -12534,7 +12617,7 @@ function SettingsLayout({
12534
12617
  const stickyTop = shell ? "var(--ds-sticky-offset, 0px)" : "calc(var(--ds-navbar-height) + var(--ds-sticky-offset, 0px))";
12535
12618
  if (layout === "tabs") {
12536
12619
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-settings-layout": "tabs", className: cn("flex flex-col gap-ds-6", className), children: [
12537
- /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(Tabs, { orientation: "horizontal", mobile: "dropdown", tabs, activeTab: value, onTabChange: onChange }) }),
12620
+ /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(Tabs, { orientation: "horizontal", mobile: "dropdown", tabs, activeTab: value, onTabChange: onChange, "aria-label": ariaLabel }) }),
12538
12621
  /* @__PURE__ */ jsx("div", { "data-settings-panel": "", className: PANEL_CLASSES, style: PANEL_STYLE, children })
12539
12622
  ] });
12540
12623
  }
@@ -12556,7 +12639,7 @@ function SettingsLayout({
12556
12639
  );
12557
12640
  }
12558
12641
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-settings-layout": "sidebar", className: cn("flex flex-row items-start gap-ds-8", className), children: [
12559
- /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className: "sticky self-start shrink-0", style: { width: `${railWidth}px`, top: stickyTop }, children: /* @__PURE__ */ jsx(Tabs, { orientation: "vertical", tabs, activeTab: value, onTabChange: onChange, className: "w-full" }) }),
12642
+ /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className: "sticky self-start shrink-0", style: { width: `${railWidth}px`, top: stickyTop }, children: /* @__PURE__ */ jsx(Tabs, { orientation: "vertical", tabs, activeTab: value, onTabChange: onChange, "aria-label": ariaLabel, className: "w-full" }) }),
12560
12643
  /* @__PURE__ */ jsx("div", { "data-settings-panel": "", className: cn("flex-1", PANEL_CLASSES), style: PANEL_STYLE, children })
12561
12644
  ] });
12562
12645
  }
@@ -12762,11 +12845,12 @@ function ScrollArea({
12762
12845
  className,
12763
12846
  orientation = "vertical",
12764
12847
  maxHeight,
12765
- maxWidth
12848
+ maxWidth,
12849
+ "aria-label": ariaLabel = "Scrollable content"
12766
12850
  }) {
12767
12851
  const viewportRef = useRef(null);
12768
12852
  const [viewport, setViewport] = useState(null);
12769
- useRevealFocus(viewport);
12853
+ useKeyboardScroll(viewport, ariaLabel, true, false, orientation === "horizontal" ? "x" : orientation === "both" ? "both" : "y");
12770
12854
  const viewportRefs = useCallback((node) => {
12771
12855
  viewportRef.current = node;
12772
12856
  setViewport(node);
@@ -12861,7 +12945,9 @@ function ScrollArea({
12861
12945
  ref: viewportRefs,
12862
12946
  onScroll: updateThumbs,
12863
12947
  className: cn(
12864
- "h-full w-full scroll-p-[4px]",
12948
+ // the frame's corners, so the inset ring follows them rather than being cut by them (as the Table's region)
12949
+ "h-full w-full scroll-p-[4px] rounded-[inherit]",
12950
+ FOCUS_INSET,
12865
12951
  orientation === "vertical" && "overflow-y-auto overflow-x-hidden",
12866
12952
  orientation === "horizontal" && "overflow-x-auto overflow-y-hidden",
12867
12953
  orientation === "both" && "overflow-auto",
@@ -13035,7 +13121,7 @@ var Sidebar = forwardRef(function Sidebar2({
13035
13121
  ]
13036
13122
  }
13037
13123
  );
13038
- return collapsed ? /* @__PURE__ */ jsx(AutoTooltip, { content: "Expand sidebar", side: "right", delay: 100, container: portalEl ?? void 0, children: collapseButton }) : collapseButton;
13124
+ return /* @__PURE__ */ jsx(AutoTooltip, { content: "Expand sidebar", side: "right", delay: 100, container: portalEl ?? void 0, disabled: !collapsed, children: collapseButton });
13039
13125
  })(),
13040
13126
  footer && /* @__PURE__ */ jsx(
13041
13127
  "div",
@@ -13286,6 +13372,8 @@ function SidebarNav({
13286
13372
  item.onClick?.();
13287
13373
  onItemClick?.(item, index);
13288
13374
  },
13375
+ "aria-label": collapsed && isRoot ? item.label : void 0,
13376
+ "aria-current": item.active ? "page" : void 0,
13289
13377
  className: cn(
13290
13378
  "flex items-center gap-ds-2 transition-colors cursor-pointer",
13291
13379
  FOCUS_RING,
@@ -13466,7 +13554,7 @@ function SidebarNav({
13466
13554
  {
13467
13555
  className: cn("flex flex-col", className),
13468
13556
  style: {
13469
- paddingTop: isCompact ? "var(--ds-space-1)" : dropTopInset ? 0 : "var(--ds-space-3)",
13557
+ paddingTop: isCompact ? "var(--ds-space-1)" : dropTopInset ? `${FOCUS_ROOM}px` : "var(--ds-space-3)",
13470
13558
  paddingRight: isCompact ? "var(--ds-space-1)" : "var(--ds-space-2)",
13471
13559
  paddingBottom: isCompact ? "var(--ds-space-1)" : "var(--ds-space-3)",
13472
13560
  paddingLeft: isCompact ? "var(--ds-space-1)" : "var(--ds-space-2)",
@@ -14240,6 +14328,7 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
14240
14328
  {
14241
14329
  type: "button",
14242
14330
  role: "menuitem",
14331
+ "aria-current": item.active ? "page" : void 0,
14243
14332
  onClick: () => {
14244
14333
  onItemClick?.(item, maxVisible - 1 + i);
14245
14334
  closeOverflow();
@@ -14267,23 +14356,27 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
14267
14356
  );
14268
14357
  }
14269
14358
  function NavButton({ item, onClick }) {
14270
- return /* @__PURE__ */ jsxs(
14271
- "button",
14272
- {
14273
- type: "button",
14274
- onClick,
14275
- className: cn(
14276
- "flex flex-col items-center justify-center gap-ds-0.5 flex-1 h-full",
14277
- "text-2xs font-medium transition-colors cursor-pointer",
14278
- // flush with the window's edge (the bar's foot and its ends): the outline sits inside, where it shows whole (D8)
14279
- FOCUS_INSET,
14280
- item.active ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
14281
- ),
14282
- children: [
14283
- /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 20 }),
14284
- /* @__PURE__ */ jsx("span", { children: item.label })
14285
- ]
14286
- }
14359
+ return (
14360
+ // the current page says so, not by its colour alone (Sprint 25.29 item 17)
14361
+ /* @__PURE__ */ jsxs(
14362
+ "button",
14363
+ {
14364
+ type: "button",
14365
+ onClick,
14366
+ "aria-current": item.active ? "page" : void 0,
14367
+ className: cn(
14368
+ "flex flex-col items-center justify-center gap-ds-0.5 flex-1 h-full",
14369
+ "text-2xs font-medium transition-colors cursor-pointer",
14370
+ // flush with the window's edge (the bar's foot and its ends): the outline sits inside, where it shows whole (D8)
14371
+ FOCUS_INSET,
14372
+ item.active ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
14373
+ ),
14374
+ children: [
14375
+ /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 20 }),
14376
+ /* @__PURE__ */ jsx("span", { children: item.label })
14377
+ ]
14378
+ }
14379
+ )
14287
14380
  );
14288
14381
  }
14289
14382