gridsmith-ui 0.30.0 → 0.30.1

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 (64) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/dist/charts.js +21 -8
  3. package/dist/charts.js.map +1 -1
  4. package/dist/chat.js +7 -7
  5. package/dist/{chunk-INGF2CPW.js → chunk-6C2IUMY7.js} +3 -3
  6. package/dist/{chunk-INGF2CPW.js.map → chunk-6C2IUMY7.js.map} +1 -1
  7. package/dist/{chunk-RHWTMTU5.js → chunk-DBHVJ7Z3.js} +5 -49
  8. package/dist/chunk-DBHVJ7Z3.js.map +1 -0
  9. package/dist/chunk-IELIF4PJ.js +110 -0
  10. package/dist/chunk-IELIF4PJ.js.map +1 -0
  11. package/dist/{chunk-Z4MCD73B.js → chunk-ISONVOA7.js} +7 -7
  12. package/dist/{chunk-Z4MCD73B.js.map → chunk-ISONVOA7.js.map} +1 -1
  13. package/dist/{chunk-UNS4TGGK.js → chunk-KMKBOTFR.js} +78 -26
  14. package/dist/chunk-KMKBOTFR.js.map +1 -0
  15. package/dist/{chunk-6A5RHW2W.js → chunk-NEUWZUK6.js} +4 -5
  16. package/dist/chunk-NEUWZUK6.js.map +1 -0
  17. package/dist/{chunk-NLXQ323J.js → chunk-OVHBQT3Z.js} +5 -4
  18. package/dist/chunk-OVHBQT3Z.js.map +1 -0
  19. package/dist/{chunk-KTPGMJUK.js → chunk-OX3NNMWG.js} +4 -4
  20. package/dist/{chunk-KTPGMJUK.js.map → chunk-OX3NNMWG.js.map} +1 -1
  21. package/dist/{chunk-OIOII5L6.js → chunk-R5QXMNW7.js} +210 -17
  22. package/dist/chunk-R5QXMNW7.js.map +1 -0
  23. package/dist/chunk-SJZWEBHL.js +58 -0
  24. package/dist/chunk-SJZWEBHL.js.map +1 -0
  25. package/dist/{chunk-NI5542ZM.js → chunk-SLRTSBCJ.js} +58 -22
  26. package/dist/chunk-SLRTSBCJ.js.map +1 -0
  27. package/dist/{chunk-F2BNJSON.js → chunk-T52LAFKG.js} +71 -69
  28. package/dist/chunk-T52LAFKG.js.map +1 -0
  29. package/dist/{chunk-GQVBZ4GW.js → chunk-UDJOIVKQ.js} +5 -108
  30. package/dist/chunk-UDJOIVKQ.js.map +1 -0
  31. package/dist/{chunk-Q36JVJX4.js → chunk-ULCACQSA.js} +4 -4
  32. package/dist/{chunk-Q36JVJX4.js.map → chunk-ULCACQSA.js.map} +1 -1
  33. package/dist/{chunk-HP7WUZPK.js → chunk-WIUGPZOH.js} +10 -3
  34. package/dist/chunk-WIUGPZOH.js.map +1 -0
  35. package/dist/{chunk-JTU7OBYJ.js → chunk-YL5KD5RC.js} +4 -3
  36. package/dist/chunk-YL5KD5RC.js.map +1 -0
  37. package/dist/data-grid.js +9 -9
  38. package/dist/editor-mentions.js +4 -5
  39. package/dist/editor-mentions.js.map +1 -1
  40. package/dist/editor.js +9 -6
  41. package/dist/editor.js.map +1 -1
  42. package/dist/index.js +178 -91
  43. package/dist/index.js.map +1 -1
  44. package/dist/kanban.js +12 -11
  45. package/dist/kanban.js.map +1 -1
  46. package/dist/resizable.js +43 -13
  47. package/dist/resizable.js.map +1 -1
  48. package/dist/utils.js.map +1 -1
  49. package/dist/virtualized.d.ts +6 -1
  50. package/dist/virtualized.js +14 -11
  51. package/dist/virtualized.js.map +1 -1
  52. package/package.json +1 -1
  53. package/dist/chunk-6A5RHW2W.js.map +0 -1
  54. package/dist/chunk-F2BNJSON.js.map +0 -1
  55. package/dist/chunk-GQVBZ4GW.js.map +0 -1
  56. package/dist/chunk-HP7WUZPK.js.map +0 -1
  57. package/dist/chunk-JTU7OBYJ.js.map +0 -1
  58. package/dist/chunk-NI5542ZM.js.map +0 -1
  59. package/dist/chunk-NLXQ323J.js.map +0 -1
  60. package/dist/chunk-OIOII5L6.js.map +0 -1
  61. package/dist/chunk-RHWTMTU5.js.map +0 -1
  62. package/dist/chunk-UNS4TGGK.js.map +0 -1
  63. package/dist/chunk-WH2FUFAC.js +0 -15
  64. package/dist/chunk-WH2FUFAC.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-KMKBOTFR.js';
3
+ export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-KMKBOTFR.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-NEUWZUK6.js';
8
+ export { Avatar } from './chunk-NEUWZUK6.js';
9
+ import { Link } from './chunk-OX3NNMWG.js';
10
+ export { CodeBlock, Divider, Link } from './chunk-OX3NNMWG.js';
11
+ import { DropdownMenu } from './chunk-ISONVOA7.js';
12
+ export { DropdownMenu } from './chunk-ISONVOA7.js';
13
+ import { useFillHeight, FillContext } from './chunk-DBHVJ7Z3.js';
14
+ import { useKeyboardScroll } from './chunk-SJZWEBHL.js';
15
+ import { Badge } from './chunk-OVHBQT3Z.js';
16
+ export { Badge } from './chunk-OVHBQT3Z.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-T52LAFKG.js';
18
+ export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-T52LAFKG.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-SLRTSBCJ.js';
20
+ export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-SLRTSBCJ.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,34 @@ 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-ULCACQSA.js';
31
+ export { Button, ButtonSizeContext, ControlSizeContext, Spinner } from './chunk-ULCACQSA.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
35
  import { useRevealFocus } from './chunk-HTXP5BMM.js';
35
36
  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';
37
+ import { focusAfterSelfRemoval, FOCUSABLE, useFocusKeptInList, FIELD, ZOOM_KEYS, rovingTabStop, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberOpener, focusInitial, OVERLAY_CLOSE_ATTR, usePopupFocus, CONTROL_ANCESTOR, useGridKeyboard, focusAfterRemoval, useNonModalDialog, useReturnFocus } from './chunk-R5QXMNW7.js';
38
+ export { useGridKeyboard } from './chunk-R5QXMNW7.js';
39
+ import { useTextOverflow } from './chunk-IELIF4PJ.js';
40
+ export { useTextOverflow } from './chunk-IELIF4PJ.js';
41
+ import { AutoTooltip } from './chunk-UDJOIVKQ.js';
42
+ export { Tooltip } from './chunk-UDJOIVKQ.js';
41
43
  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';
44
+ import { mergeRefs } from './chunk-7Q46JXSK.js';
45
+ import { useLatest, usePosition } from './chunk-WIUGPZOH.js';
46
+ 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
47
  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';
48
+ 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
49
  import { createPortal, flushSync } from 'react-dom';
48
50
 
51
+ function selectAllFor(bar) {
52
+ for (let box = bar?.parentElement; bar && box && box !== document.body; box = box.parentElement) {
53
+ const all = Array.from(box.querySelectorAll("[data-ds-select-all] input"));
54
+ if (all.length) return all.find((el) => bar.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING) ?? all[all.length - 1];
55
+ }
56
+ return null;
57
+ }
49
58
  function BulkActionBar({ selectedCount, actions, onClearSelection, className }) {
50
59
  const isMobile = useBreakpoint("sm");
51
60
  if (selectedCount === 0) return null;
@@ -96,7 +105,11 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
96
105
  "button",
97
106
  {
98
107
  type: "button",
99
- onClick: onClearSelection,
108
+ onClick: (e) => {
109
+ const bar = e.currentTarget.closest('[role="toolbar"]');
110
+ focusAfterSelfRemoval(e.currentTarget, { item: bar, to: selectAllFor(bar) });
111
+ onClearSelection();
112
+ },
100
113
  className: cn("ml-auto text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
101
114
  "aria-label": "Clear selection",
102
115
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
@@ -823,7 +836,7 @@ function DateRangePicker({
823
836
  onChange: takeTyped
824
837
  }
825
838
  ) }),
826
- /* @__PURE__ */ jsx(
839
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Choose a date range", children: /* @__PURE__ */ jsx(
827
840
  "button",
828
841
  {
829
842
  ref: buttonRef,
@@ -836,7 +849,7 @@ function DateRangePicker({
836
849
  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
850
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 })
838
851
  }
839
- )
852
+ ) })
840
853
  ]
841
854
  }
842
855
  ),
@@ -1703,8 +1716,8 @@ var sizeClasses = {
1703
1716
  full: "max-w-[calc(100vw-2rem)]"
1704
1717
  };
1705
1718
  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);
1719
+ const { marked, pending, mark } = useOverlayMark(open);
1720
+ const guard = useDirtyGuard((dirty ?? marked) || pending, onCloseProp, onDiscard);
1708
1721
  const onClose = guard.requestClose;
1709
1722
  const titleId = useId();
1710
1723
  const descriptionId = useId();
@@ -1713,7 +1726,13 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1713
1726
  const dialogRef = useRef(null);
1714
1727
  const opener = useRef(null);
1715
1728
  const defaultButtonRef = useRef(null);
1716
- const bodyRef = useScrollbarInset();
1729
+ const bodyInset = useScrollbarInset();
1730
+ const [bodyEl, setBodyEl] = useState(null);
1731
+ const bodyRef = useCallback((el) => {
1732
+ bodyInset(el);
1733
+ setBodyEl(el);
1734
+ }, [bodyInset]);
1735
+ useKeyboardScroll(bodyEl, title, open);
1717
1736
  const onCloseRef = useLatest(onClose);
1718
1737
  const onSubmitRef = useLatest(onSubmit);
1719
1738
  const isTopLayer = useOverlayLayer(open);
@@ -1721,8 +1740,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1721
1740
  const before = useFocusBeforeOpen(open);
1722
1741
  useEffect(() => {
1723
1742
  if (!open) return;
1724
- const active = before.current;
1725
- opener.current = active instanceof HTMLElement && active !== document.body && active.isConnected ? rememberFocus(active) : null;
1743
+ opener.current = rememberOpener(before.current, dialogRef.current);
1726
1744
  }, [open, before]);
1727
1745
  useEffect(() => {
1728
1746
  if (!open) return;
@@ -1837,7 +1855,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1837
1855
  ),
1838
1856
  description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description })
1839
1857
  ] }),
1840
- /* @__PURE__ */ jsx(
1858
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Close", children: /* @__PURE__ */ jsx(
1841
1859
  "button",
1842
1860
  {
1843
1861
  type: "button",
@@ -1847,13 +1865,13 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1847
1865
  "aria-label": "Close",
1848
1866
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
1849
1867
  }
1850
- )
1868
+ ) })
1851
1869
  ] }),
1852
1870
  children && /* @__PURE__ */ jsx(
1853
1871
  "div",
1854
1872
  {
1855
1873
  ref: bodyRef,
1856
- className: "min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6",
1874
+ className: cn("min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6", FOCUS_INSET),
1857
1875
  style: {
1858
1876
  paddingLeft: variant === "destructive" ? "calc(var(--ds-page-gutter) + 2.5rem + var(--ds-space-3))" : "var(--ds-page-gutter)",
1859
1877
  paddingRight: insetLessScrollbar("var(--ds-page-gutter)")
@@ -2884,7 +2902,7 @@ function TimePicker({
2884
2902
  }
2885
2903
  )
2886
2904
  ] }),
2887
- /* @__PURE__ */ jsx(
2905
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Choose a time", children: /* @__PURE__ */ jsx(
2888
2906
  "button",
2889
2907
  {
2890
2908
  ref: buttonRef,
@@ -2898,7 +2916,7 @@ function TimePicker({
2898
2916
  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
2917
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 })
2900
2918
  }
2901
- )
2919
+ ) })
2902
2920
  ]
2903
2921
  }
2904
2922
  ),
@@ -3099,7 +3117,7 @@ var Tag = forwardRef(function Tag2({
3099
3117
  children: label
3100
3118
  }
3101
3119
  ) : label,
3102
- onRemove && !disabled && /* @__PURE__ */ jsx(
3120
+ onRemove && !disabled && /* @__PURE__ */ jsx(AutoTooltip, { content: typeof children === "string" ? `Remove ${children}` : "Remove", children: /* @__PURE__ */ jsx(
3103
3121
  "button",
3104
3122
  {
3105
3123
  type: "button",
@@ -3115,7 +3133,7 @@ var Tag = forwardRef(function Tag2({
3115
3133
  ),
3116
3134
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: size === "sm" ? 10 : 12 })
3117
3135
  }
3118
- )
3136
+ ) })
3119
3137
  ]
3120
3138
  }
3121
3139
  );
@@ -3164,6 +3182,12 @@ function TagInput({
3164
3182
  const buttons = Array.from(containerRef.current?.querySelectorAll("[data-tag-remove]") ?? []);
3165
3183
  focusAfterRemoval(buttons, pending.index, inputRef.current);
3166
3184
  });
3185
+ const overlayMark = useContext(OverlayMarkCtx);
3186
+ const holdsText = input.trim() !== "";
3187
+ useEffect(() => {
3188
+ if (!holdsText || !overlayMark) return;
3189
+ return overlayMark.pend();
3190
+ }, [holdsText, overlayMark]);
3167
3191
  const handleKeyDown = useCallback(
3168
3192
  (e) => {
3169
3193
  if ((e.key === "Enter" || e.key === ",") && input.trim()) {
@@ -4311,7 +4335,10 @@ function TransferList({
4311
4335
  "button",
4312
4336
  {
4313
4337
  type: "button",
4314
- onClick: moveAllRight,
4338
+ onClick: (e) => {
4339
+ focusAfterSelfRemoval(e.currentTarget);
4340
+ moveAllRight();
4341
+ },
4315
4342
  disabled: !available.filter((i) => !i.disabled).length,
4316
4343
  "aria-label": isStacked ? "Move all down" : "Move all right",
4317
4344
  className: cn(actionButtonClass),
@@ -4322,7 +4349,10 @@ function TransferList({
4322
4349
  "button",
4323
4350
  {
4324
4351
  type: "button",
4325
- onClick: moveRight,
4352
+ onClick: (e) => {
4353
+ focusAfterSelfRemoval(e.currentTarget);
4354
+ moveRight();
4355
+ },
4326
4356
  disabled: !checkedAvailable.size,
4327
4357
  "aria-label": isStacked ? "Move selected down" : "Move selected right",
4328
4358
  className: cn(actionButtonClass),
@@ -4333,7 +4363,10 @@ function TransferList({
4333
4363
  "button",
4334
4364
  {
4335
4365
  type: "button",
4336
- onClick: moveLeft,
4366
+ onClick: (e) => {
4367
+ focusAfterSelfRemoval(e.currentTarget);
4368
+ moveLeft();
4369
+ },
4337
4370
  disabled: !checkedSelected.size,
4338
4371
  "aria-label": isStacked ? "Move selected up" : "Move selected left",
4339
4372
  className: cn(actionButtonClass),
@@ -4344,7 +4377,10 @@ function TransferList({
4344
4377
  "button",
4345
4378
  {
4346
4379
  type: "button",
4347
- onClick: moveAllLeft,
4380
+ onClick: (e) => {
4381
+ focusAfterSelfRemoval(e.currentTarget);
4382
+ moveAllLeft();
4383
+ },
4348
4384
  disabled: !selected.filter((i) => !i.disabled).length,
4349
4385
  "aria-label": isStacked ? "Move all up" : "Move all left",
4350
4386
  className: cn(actionButtonClass),
@@ -5004,7 +5040,7 @@ var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
5004
5040
  const menu = menuItems ? /* @__PURE__ */ jsx(
5005
5041
  DropdownMenu,
5006
5042
  {
5007
- trigger: /* @__PURE__ */ jsx(
5043
+ trigger: /* @__PURE__ */ jsx(AutoTooltip, { content: "More actions", children: /* @__PURE__ */ jsx(
5008
5044
  "button",
5009
5045
  {
5010
5046
  type: "button",
@@ -5018,7 +5054,7 @@ var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
5018
5054
  onClick: (e) => e.stopPropagation(),
5019
5055
  children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
5020
5056
  }
5021
- ),
5057
+ ) }),
5022
5058
  items: menuItems
5023
5059
  }
5024
5060
  ) : null;
@@ -5881,6 +5917,11 @@ function Table({
5881
5917
  useEffect(() => {
5882
5918
  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
5919
  }, [unsortable]);
5920
+ const pageSorts = !!onSortChange;
5921
+ const refused = pageSorts ? "" : columns.filter((col) => col.sortable && !canSort.has(col.key)).map((col) => col.key).join(", ");
5922
+ useEffect(() => {
5923
+ 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).`);
5924
+ }, [refused]);
5884
5925
  useEffect(() => {
5885
5926
  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
5927
  }, [pager, data.length]);
@@ -5937,6 +5978,9 @@ function Table({
5937
5978
  const narrowScreen = useBreakpoint(mobileBreakpoint);
5938
5979
  const { cards: isMobile, rootRef } = useCardsSwitch(narrowScreen, cardsBelow, title);
5939
5980
  useRevealFocus(rootRef, isMobile);
5981
+ useFocusKeptInList(rootRef);
5982
+ const [cardsEl, setCardsEl] = useState(null);
5983
+ useKeyboardScroll(cardsEl, title ?? ariaLabel ?? "Table", isMobile);
5940
5984
  const setRoot = useCallback((node) => {
5941
5985
  rootRef.current = node;
5942
5986
  if (typeof ref === "function") ref(node);
@@ -6064,8 +6108,14 @@ function Table({
6064
6108
  cardHeading,
6065
6109
  body
6066
6110
  ] });
6067
- const control = pager && data.length > 0 ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
6111
+ const paged = !!pager && data.length > 0;
6112
+ const control = paged ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
6068
6113
  const listRoot = control ? void 0 : setRoot;
6114
+ const cardsAreRoot = !title && !paged;
6115
+ const setCards = useCallback((el) => {
6116
+ setCardsEl(el);
6117
+ if (cardsAreRoot) setRoot(el);
6118
+ }, [cardsAreRoot, setRoot]);
6069
6119
  const listClass = control ? void 0 : className;
6070
6120
  const withControl = (list2) => control ? /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
6071
6121
  list2,
@@ -6114,7 +6164,7 @@ function Table({
6114
6164
  if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
6115
6165
  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
6166
  }
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: [
6167
+ 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
6168
  loading && data.length > 0 && /* @__PURE__ */ jsx(RefreshLine, { className: "inset-x-[4px] rounded-full" }),
6119
6169
  selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
6120
6170
  drawn.map(({ row, originalIdx }) => {
@@ -6205,7 +6255,8 @@ function Table({
6205
6255
  const cellCount = columns.length + lead;
6206
6256
  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
6257
  /* @__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(
6258
+ selectable && // data-ds-select-all: the selection's own control, where a BulkActionBar's Clear selection sends focus
6259
+ /* @__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
6260
  Checkbox,
6210
6261
  {
6211
6262
  checked: allSelected,
@@ -6216,8 +6267,8 @@ function Table({
6216
6267
  ) }),
6217
6268
  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
6269
  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;
6270
+ const isSortable = col.header.trim() !== "" && (pageSorts ? col.sortable ?? (!!sortable && canSort.has(col.key)) : (col.sortable ?? !!sortable) && canSort.has(col.key));
6271
+ const isActiveSort = sortKey === col.key && !!sortDir && (pageSorts || unsortable !== col.key);
6221
6272
  const headerKind = kindOf2(col);
6222
6273
  const headerAlign = col.align ?? (headerKind === "number" ? "right" : "left");
6223
6274
  const shrink = (headerKind === "number" || headerKind === "date") && !col.maxWidth;
@@ -6319,7 +6370,7 @@ function Table({
6319
6370
  } : void 0,
6320
6371
  children: [
6321
6372
  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(
6373
+ 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
6374
  "button",
6324
6375
  {
6325
6376
  type: "button",
@@ -6336,7 +6387,7 @@ function Table({
6336
6387
  }
6337
6388
  )
6338
6389
  }
6339
- ) }),
6390
+ ) }) }),
6340
6391
  columns.map((col, c) => {
6341
6392
  const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
6342
6393
  const kind = kindOf2(col);
@@ -7218,6 +7269,12 @@ function WeekView({ date, events, categories, selectedDate, onDayClick, onOpenEv
7218
7269
  useRevealFocus(allDayRef);
7219
7270
  useRevealFocus(scrollerRef);
7220
7271
  const { ref: edgesRef, measure: measureEdges, fadeProps: edgeFade } = useScrollEdges();
7272
+ const [dayStrip, setDayStrip] = useState(null);
7273
+ const setDays = useCallback((el) => {
7274
+ edgesRef(el);
7275
+ setDayStrip(el);
7276
+ }, [edgesRef]);
7277
+ useKeyboardScroll(dayStrip, "Days", true, false, "x");
7221
7278
  const [list2, setList] = useState(null);
7222
7279
  const handleScroll = useCallback((e) => {
7223
7280
  if (syncingScroll.current) return;
@@ -7342,7 +7399,7 @@ function WeekView({ date, events, categories, selectedDate, onDayClick, onOpenEv
7342
7399
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "flex flex-col h-full overflow-hidden", onKeyDown: grid.onKeyDown, children: [
7343
7400
  /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: [
7344
7401
  /* @__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: [
7402
+ /* @__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
7403
  /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--ds-text-muted)] font-medium", children: names[i] }),
7347
7404
  /* @__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
7405
  ] }, i)) }) })
@@ -9242,6 +9299,7 @@ function TreeNodeRow({
9242
9299
  CheckboxIndicator2,
9243
9300
  {
9244
9301
  state: checkState,
9302
+ label: node.label,
9245
9303
  onClick: (e) => {
9246
9304
  e.stopPropagation();
9247
9305
  handleCheck(node);
@@ -9275,12 +9333,13 @@ function TreeNodeRow({
9275
9333
  )) })
9276
9334
  ] });
9277
9335
  }
9278
- function CheckboxIndicator2({ state, onClick }) {
9336
+ function CheckboxIndicator2({ state, label, onClick }) {
9279
9337
  const filled = state !== "unchecked";
9280
9338
  return /* @__PURE__ */ jsx(
9281
9339
  "span",
9282
9340
  {
9283
9341
  role: "checkbox",
9342
+ "aria-label": label,
9284
9343
  "aria-checked": state === "indeterminate" ? "mixed" : state === "checked",
9285
9344
  className: cn(
9286
9345
  "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 +9510,7 @@ function Carousel({
9451
9510
  ),
9452
9511
  /* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: said }),
9453
9512
  showArrows && count > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
9454
- /* @__PURE__ */ jsx(
9513
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Previous slide", children: /* @__PURE__ */ jsx(
9455
9514
  "button",
9456
9515
  {
9457
9516
  type: "button",
@@ -9461,8 +9520,8 @@ function Carousel({
9461
9520
  className: cn("absolute left-ds-4 top-1/2 -translate-y-1/2 z-10", ROUND_BUTTON, !canPrev && "opacity-0 pointer-events-none"),
9462
9521
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16, className: "rotate-180" })
9463
9522
  }
9464
- ),
9465
- /* @__PURE__ */ jsx(
9523
+ ) }),
9524
+ /* @__PURE__ */ jsx(AutoTooltip, { content: "Next slide", children: /* @__PURE__ */ jsx(
9466
9525
  "button",
9467
9526
  {
9468
9527
  type: "button",
@@ -9472,7 +9531,7 @@ function Carousel({
9472
9531
  className: cn("absolute right-ds-4 top-1/2 -translate-y-1/2 z-10", ROUND_BUTTON, !canNext && "opacity-0 pointer-events-none"),
9473
9532
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
9474
9533
  }
9475
- )
9534
+ ) })
9476
9535
  ] }),
9477
9536
  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
9537
  "button",
@@ -9722,7 +9781,10 @@ function ChatInputBar({ onSend, busy, onStop, onAttach, onVoice, placeholder })
9722
9781
  ) });
9723
9782
  }
9724
9783
  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)) });
9784
+ const pressed = useRef(null);
9785
+ return /* @__PURE__ */ jsx("div", { "data-suggestions": "", className: cn("flex flex-wrap gap-ds-2", className), onClickCapture: (e) => {
9786
+ pressed.current = e.target.closest("button");
9787
+ }, children: items.map((s) => /* @__PURE__ */ jsx(Tag, { variant: "default", size: "md", onClick: () => onPick(s, pressed.current), children: s }, s)) });
9726
9788
  }
9727
9789
  var NEAR_BOTTOM_PX = 24;
9728
9790
  function ChatMessageList({
@@ -9751,7 +9813,7 @@ function ChatMessageList({
9751
9813
  scrollRef.current = node;
9752
9814
  setScroller(node);
9753
9815
  }, []);
9754
- useRevealFocus(scroller);
9816
+ useKeyboardScroll(scroller, "Messages");
9755
9817
  const atBottomRef = useRef(true);
9756
9818
  const [showJump, setShowJump] = useState(false);
9757
9819
  const [prevMessages, setPrevMessages] = useState(messages);
@@ -9790,12 +9852,16 @@ function ChatMessageList({
9790
9852
  return () => observer.disconnect();
9791
9853
  }, [autoScroll, scrollToBottom]);
9792
9854
  const empty = messages.length === 0;
9793
- const pick = (text) => onSend?.(text);
9855
+ const rootRef = useRef(null);
9856
+ const pick = (text, from) => {
9857
+ if (from) focusAfterSelfRemoval(from, { item: from.closest("[data-suggestions]"), to: () => rootRef.current?.querySelector("textarea") });
9858
+ onSend?.(text);
9859
+ };
9794
9860
  const showSuggestionsAfterReply = !empty && suggestionsMode === "always" && !!suggestions?.length;
9795
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col flex-1 min-h-0", className), children: [
9861
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("flex flex-col flex-1 min-h-0", className), children: [
9796
9862
  /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: announcement }),
9797
9863
  /* @__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: [
9864
+ /* @__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
9865
  emptyState ?? /* @__PURE__ */ jsx(
9800
9866
  EmptyState,
9801
9867
  {
@@ -9911,8 +9977,8 @@ function ChatPanel({
9911
9977
  ] });
9912
9978
  }
9913
9979
  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);
9980
+ const { marked, pending, mark } = useOverlayMark(open);
9981
+ const guard = useDirtyGuard((dirty ?? marked) || pending, onCloseProp, onDiscard);
9916
9982
  return /* @__PURE__ */ jsx(
9917
9983
  DrawerPanel,
9918
9984
  {
@@ -10220,13 +10286,20 @@ var StackedList = forwardRef(function StackedList2({
10220
10286
  const articles = variant === "articles";
10221
10287
  useWholeListCheck("StackedList", items.length, pager);
10222
10288
  const shown = pagerPart(items, pager);
10289
+ const listRef = useRef(null);
10290
+ useFocusKeptInList(listRef);
10291
+ const setList = useCallback((node) => {
10292
+ listRef.current = node;
10293
+ if (typeof ref === "function") ref(node);
10294
+ else if (ref) ref.current = node;
10295
+ }, [ref]);
10223
10296
  const stackMeta = isPhone && articles;
10224
10297
  const selectable = selectedId !== void 0 || items.some((i) => i.selected !== void 0);
10225
10298
  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
10299
  const list2 = /* @__PURE__ */ jsx(
10227
10300
  "ul",
10228
10301
  {
10229
- ref,
10302
+ ref: setList,
10230
10303
  "data-ds-list": "",
10231
10304
  className: cn(
10232
10305
  divided && "divide-y-[length:var(--ds-border-width)] divide-[var(--ds-border-subtle)]",
@@ -11119,11 +11192,11 @@ var TimeViewport = forwardRef(function TimeViewport2({
11119
11192
  /* @__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
11193
  /* @__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
11194
  ] }),
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 }) }),
11195
+ /* @__PURE__ */ jsx(PeriodButton, { direction: -1, store, end: Math.max(0, drawn.width - visibleWidth), onPage: (d) => api.page(d) }),
11123
11196
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: todayAtX === null, onClick: () => {
11124
11197
  if (todayAtX !== null) setLeft(todayAtX - visibleWidth / 2);
11125
11198
  }, 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 }) }),
11199
+ /* @__PURE__ */ jsx(PeriodButton, { direction: 1, store, end: Math.max(0, drawn.width - visibleWidth), onPage: (d) => api.page(d) }),
11127
11200
  toolbar
11128
11201
  ] })
11129
11202
  );
@@ -11244,6 +11317,13 @@ function TimeBar({ start, end, minWidth = 0, labels, children, className, style,
11244
11317
  }
11245
11318
  );
11246
11319
  }
11320
+ function PeriodButton({ direction, store, end, onPage }) {
11321
+ const left = useSyncExternalStore(store.subscribe, () => store.get().scrollLeft, () => 0);
11322
+ const unavailable = direction < 0 ? left <= 0.5 : end > 0 && left >= end - 0.5;
11323
+ 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: () => {
11324
+ if (!unavailable) onPage(direction);
11325
+ }, children: /* @__PURE__ */ jsx(Icon, { name: direction < 0 ? "chevron-left" : "chevron-right", size: 14 }) });
11326
+ }
11247
11327
  function LocaleProvider({ lang, acceptLanguage, children }) {
11248
11328
  const value = useMemo(() => localeChoice(lang, acceptLanguage), [lang, acceptLanguage]);
11249
11329
  return /* @__PURE__ */ jsx(LocaleContext.Provider, { value, children });
@@ -13035,7 +13115,7 @@ var Sidebar = forwardRef(function Sidebar2({
13035
13115
  ]
13036
13116
  }
13037
13117
  );
13038
- return collapsed ? /* @__PURE__ */ jsx(AutoTooltip, { content: "Expand sidebar", side: "right", delay: 100, container: portalEl ?? void 0, children: collapseButton }) : collapseButton;
13118
+ return /* @__PURE__ */ jsx(AutoTooltip, { content: "Expand sidebar", side: "right", delay: 100, container: portalEl ?? void 0, disabled: !collapsed, children: collapseButton });
13039
13119
  })(),
13040
13120
  footer && /* @__PURE__ */ jsx(
13041
13121
  "div",
@@ -13286,6 +13366,8 @@ function SidebarNav({
13286
13366
  item.onClick?.();
13287
13367
  onItemClick?.(item, index);
13288
13368
  },
13369
+ "aria-label": collapsed && isRoot ? item.label : void 0,
13370
+ "aria-current": item.active ? "page" : void 0,
13289
13371
  className: cn(
13290
13372
  "flex items-center gap-ds-2 transition-colors cursor-pointer",
13291
13373
  FOCUS_RING,
@@ -13466,7 +13548,7 @@ function SidebarNav({
13466
13548
  {
13467
13549
  className: cn("flex flex-col", className),
13468
13550
  style: {
13469
- paddingTop: isCompact ? "var(--ds-space-1)" : dropTopInset ? 0 : "var(--ds-space-3)",
13551
+ paddingTop: isCompact ? "var(--ds-space-1)" : dropTopInset ? `${FOCUS_ROOM}px` : "var(--ds-space-3)",
13470
13552
  paddingRight: isCompact ? "var(--ds-space-1)" : "var(--ds-space-2)",
13471
13553
  paddingBottom: isCompact ? "var(--ds-space-1)" : "var(--ds-space-3)",
13472
13554
  paddingLeft: isCompact ? "var(--ds-space-1)" : "var(--ds-space-2)",
@@ -14240,6 +14322,7 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
14240
14322
  {
14241
14323
  type: "button",
14242
14324
  role: "menuitem",
14325
+ "aria-current": item.active ? "page" : void 0,
14243
14326
  onClick: () => {
14244
14327
  onItemClick?.(item, maxVisible - 1 + i);
14245
14328
  closeOverflow();
@@ -14267,23 +14350,27 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
14267
14350
  );
14268
14351
  }
14269
14352
  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
- }
14353
+ return (
14354
+ // the current page says so, not by its colour alone (Sprint 25.29 item 17)
14355
+ /* @__PURE__ */ jsxs(
14356
+ "button",
14357
+ {
14358
+ type: "button",
14359
+ onClick,
14360
+ "aria-current": item.active ? "page" : void 0,
14361
+ className: cn(
14362
+ "flex flex-col items-center justify-center gap-ds-0.5 flex-1 h-full",
14363
+ "text-2xs font-medium transition-colors cursor-pointer",
14364
+ // flush with the window's edge (the bar's foot and its ends): the outline sits inside, where it shows whole (D8)
14365
+ FOCUS_INSET,
14366
+ item.active ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
14367
+ ),
14368
+ children: [
14369
+ /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 20 }),
14370
+ /* @__PURE__ */ jsx("span", { children: item.label })
14371
+ ]
14372
+ }
14373
+ )
14287
14374
  );
14288
14375
  }
14289
14376