gridsmith-ui 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/dist/charts.d.ts +101 -30
  3. package/dist/charts.js +181 -106
  4. package/dist/charts.js.map +1 -1
  5. package/dist/chat.js +6 -6
  6. package/dist/{chunk-OWQ7M6R7.js → chunk-2724SJO2.js} +141 -24
  7. package/dist/chunk-2724SJO2.js.map +1 -0
  8. package/dist/{chunk-BKYWKMUN.js → chunk-DO6DLTFK.js} +11 -9
  9. package/dist/chunk-DO6DLTFK.js.map +1 -0
  10. package/dist/{chunk-GP2COVJC.js → chunk-H732QL56.js} +4 -4
  11. package/dist/{chunk-GP2COVJC.js.map → chunk-H732QL56.js.map} +1 -1
  12. package/dist/{chunk-XSQD3UGY.js → chunk-HCEHTJ5E.js} +17 -4
  13. package/dist/chunk-HCEHTJ5E.js.map +1 -0
  14. package/dist/{chunk-YFHTREH5.js → chunk-HUVZQOU4.js} +5 -5
  15. package/dist/{chunk-YFHTREH5.js.map → chunk-HUVZQOU4.js.map} +1 -1
  16. package/dist/{chunk-EKWXPSTI.js → chunk-JHZ22HQP.js} +75 -24
  17. package/dist/chunk-JHZ22HQP.js.map +1 -0
  18. package/dist/{chunk-3J67NISC.js → chunk-NGZJK57C.js} +15 -11
  19. package/dist/chunk-NGZJK57C.js.map +1 -0
  20. package/dist/{chunk-U7WBI4AV.js → chunk-OVHM55JF.js} +5 -5
  21. package/dist/{chunk-U7WBI4AV.js.map → chunk-OVHM55JF.js.map} +1 -1
  22. package/dist/{chunk-OFACAHRV.js → chunk-QY2RA2HO.js} +5 -5
  23. package/dist/{chunk-OFACAHRV.js.map → chunk-QY2RA2HO.js.map} +1 -1
  24. package/dist/{chunk-HUNEJIKV.js → chunk-R2IAK3J3.js} +3 -3
  25. package/dist/{chunk-HUNEJIKV.js.map → chunk-R2IAK3J3.js.map} +1 -1
  26. package/dist/{chunk-V73LHNRL.js → chunk-RS624TD5.js} +29 -10
  27. package/dist/chunk-RS624TD5.js.map +1 -0
  28. package/dist/{chunk-V2ARGHJN.js → chunk-SIEU4H3H.js} +9 -9
  29. package/dist/chunk-SIEU4H3H.js.map +1 -0
  30. package/dist/{chunk-DBHVJ7Z3.js → chunk-SS3C24IJ.js} +3 -2
  31. package/dist/chunk-SS3C24IJ.js.map +1 -0
  32. package/dist/{chunk-LE72KHIE.js → chunk-TMPPBXX3.js} +3 -3
  33. package/dist/{chunk-LE72KHIE.js.map → chunk-TMPPBXX3.js.map} +1 -1
  34. package/dist/{chunk-GT6M74IZ.js → chunk-WSKPESAX.js} +12 -10
  35. package/dist/chunk-WSKPESAX.js.map +1 -0
  36. package/dist/{chunk-2Q4HOGEI.js → chunk-XBVZIN26.js} +15 -5
  37. package/dist/chunk-XBVZIN26.js.map +1 -0
  38. package/dist/data-grid.js +10 -10
  39. package/dist/data-grid.js.map +1 -1
  40. package/dist/editor-mentions.js +2 -2
  41. package/dist/editor.js +4 -3
  42. package/dist/editor.js.map +1 -1
  43. package/dist/index.d.ts +53 -6
  44. package/dist/index.js +557 -232
  45. package/dist/index.js.map +1 -1
  46. package/dist/kanban.js +10 -9
  47. package/dist/kanban.js.map +1 -1
  48. package/dist/resizable.d.ts +11 -2
  49. package/dist/resizable.js +97 -22
  50. package/dist/resizable.js.map +1 -1
  51. package/dist/roots.css +2 -2
  52. package/dist/tokens.css +6 -6
  53. package/dist/virtualized.js +10 -9
  54. package/dist/virtualized.js.map +1 -1
  55. package/dist-static/tokens.css +6 -6
  56. package/package.json +1 -1
  57. package/dist/chunk-2Q4HOGEI.js.map +0 -1
  58. package/dist/chunk-3J67NISC.js.map +0 -1
  59. package/dist/chunk-BKYWKMUN.js.map +0 -1
  60. package/dist/chunk-DBHVJ7Z3.js.map +0 -1
  61. package/dist/chunk-EKWXPSTI.js.map +0 -1
  62. package/dist/chunk-GT6M74IZ.js.map +0 -1
  63. package/dist/chunk-OWQ7M6R7.js.map +0 -1
  64. package/dist/chunk-V2ARGHJN.js.map +0 -1
  65. package/dist/chunk-V73LHNRL.js.map +0 -1
  66. package/dist/chunk-XSQD3UGY.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,71 +1,216 @@
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-EKWXPSTI.js';
3
- export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-EKWXPSTI.js';
4
- import { Skeleton, TITLE_TEXT, SegmentedControl } from './chunk-U7WBI4AV.js';
5
- export { SegmentedControl, Skeleton } from './chunk-U7WBI4AV.js';
2
+ import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useCornerInset, NAVBAR_INSET_PRIORITY, useOverlayMark, useDirtyGuard, useScrollbarInset, useBulkBarHost, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, BulkBarHostCtx, BulkBarSpacer, bulkBarRoom, insetLessScrollbar, BULK_BAR_LAYER, DiscardConfirm, OVERLAY_ROOT_ATTR, BulkBarPresenceCtx, BULK_BAR_WINDOW_LAYER, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, besideRoom, PANEL_INSET_PRIORITY, Drawer, useRememberedWidth, pxOf, ResizeEdge, LAUNCHER_INSET_PRIORITY, TOAST_INSET_VARS, defaultMaxWidth } from './chunk-JHZ22HQP.js';
3
+ export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-JHZ22HQP.js';
4
+ import { Skeleton, TITLE_TEXT, SegmentedControl } from './chunk-OVHM55JF.js';
5
+ export { SegmentedControl, Skeleton } from './chunk-OVHM55JF.js';
6
6
  import { useScrollEdges, EDGE_FADE } from './chunk-3BRQRKDO.js';
7
- import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-LE72KHIE.js';
8
- export { Avatar } from './chunk-LE72KHIE.js';
9
- import { Link } from './chunk-OFACAHRV.js';
10
- export { CodeBlock, Divider, Link } from './chunk-OFACAHRV.js';
11
- import { DropdownMenu } from './chunk-YFHTREH5.js';
12
- export { DropdownMenu } from './chunk-YFHTREH5.js';
13
- import { useFillHeight, FillContext } from './chunk-DBHVJ7Z3.js';
14
- import { Badge } from './chunk-GT6M74IZ.js';
15
- export { Badge } from './chunk-GT6M74IZ.js';
16
- import { useKeyboardScroll } from './chunk-GP2COVJC.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-3J67NISC.js';
18
- export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-3J67NISC.js';
19
- import { useWholeListCheck, pagerPart, Pagination, NumberInput } from './chunk-V2ARGHJN.js';
20
- export { NumberInput, Pagination, Popover, usePagination } from './chunk-V2ARGHJN.js';
7
+ import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-TMPPBXX3.js';
8
+ export { Avatar } from './chunk-TMPPBXX3.js';
9
+ import { Link } from './chunk-QY2RA2HO.js';
10
+ export { CodeBlock, Divider, Link } from './chunk-QY2RA2HO.js';
11
+ import { DropdownMenu } from './chunk-HUVZQOU4.js';
12
+ export { DropdownMenu } from './chunk-HUVZQOU4.js';
13
+ import { useFillHeight, FillContext } from './chunk-SS3C24IJ.js';
14
+ import { Badge } from './chunk-WSKPESAX.js';
15
+ export { Badge } from './chunk-WSKPESAX.js';
16
+ import { useKeyboardScroll } from './chunk-H732QL56.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-NGZJK57C.js';
18
+ export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-NGZJK57C.js';
19
+ import { useWholeListCheck, pagerPart, Pagination, NumberInput } from './chunk-SIEU4H3H.js';
20
+ export { NumberInput, Pagination, Popover, usePagination } from './chunk-SIEU4H3H.js';
21
21
  import { useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, formatRelativeTime, thresholdOf, toMillis, formatFullTime, datedMillis, preferenceActionKey, DAY, HOUR, MINUTE } from './chunk-QOMP4D6V.js';
22
22
  export { PreferencesContext, formatFullTime, formatRelativeTime, preferenceActionKey, usePreferences } from './chunk-QOMP4D6V.js';
23
23
  import { useFormatLocale, useHydrated, useToday, LocaleContext } from './chunk-LJYSVZMI.js';
24
24
  export { useFormatLocale, useHydrated } from './chunk-LJYSVZMI.js';
25
- import { Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, OutsideField, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-BKYWKMUN.js';
26
- export { Dropdown, Field, InlineFieldError, Input, Label, Textarea, Toggle } from './chunk-BKYWKMUN.js';
25
+ import { Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, OutsideField, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-DO6DLTFK.js';
26
+ export { Dropdown, Field, InlineFieldError, Input, Label, Textarea, Toggle } from './chunk-DO6DLTFK.js';
27
27
  import { formatLocale, localeChoice } from './chunk-7QLXYRPD.js';
28
- import { useInputModality, inputModality } from './chunk-7RKC5C7G.js';
29
- export { INPUT_MODALITY_ATTR, inputModality, installInputModality, useInputModality } from './chunk-7RKC5C7G.js';
30
28
  import { FormChangeCtx, useReportedChange, useOptionalFormContext, FormCtx } from './chunk-72SDAX54.js';
31
29
  export { useFormContext } from './chunk-72SDAX54.js';
32
- import { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, RowsCtx, PageActionsCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-V73LHNRL.js';
33
- import { Button, elementType, ControlSizeContext, triggerType, Spinner } from './chunk-2Q4HOGEI.js';
34
- export { Button, ButtonSizeContext, ControlSizeContext, Spinner } from './chunk-2Q4HOGEI.js';
30
+ import { CardSurfaceCtx, useScrollsInside, useRunsEdgeToEdge, SplitPaneCtx, PanePaddedCtx, RowsCtx, PageActionsCtx, PANE_HEADING_CANCEL, SurfaceBoundary, useFramesItself, TableCardCtx, useWantsInset } from './chunk-RS624TD5.js';
31
+ import { Button, elementType, ControlSizeContext, triggerType, Spinner } from './chunk-XBVZIN26.js';
32
+ export { Button, ButtonSizeContext, ControlSizeContext, Spinner } from './chunk-XBVZIN26.js';
35
33
  import { useBreakpoint, readBreakpointPx } from './chunk-ZHUVLBCC.js';
36
34
  export { BreakpointWidthProvider, useBreakpoint } from './chunk-ZHUVLBCC.js';
37
- import { useTextOverflow } from './chunk-HUNEJIKV.js';
38
- export { useTextOverflow } from './chunk-HUNEJIKV.js';
39
- import { AutoTooltip, mergeRefs, useRevealFocus } from './chunk-XSQD3UGY.js';
40
- export { Tooltip, useRevealFocus } from './chunk-XSQD3UGY.js';
35
+ import { inputModality, useInputModality } from './chunk-7RKC5C7G.js';
36
+ export { INPUT_MODALITY_ATTR, inputModality, installInputModality, useInputModality } from './chunk-7RKC5C7G.js';
37
+ import { useTextOverflow } from './chunk-R2IAK3J3.js';
38
+ export { useTextOverflow } from './chunk-R2IAK3J3.js';
39
+ import { AutoTooltip, mergeRefs, useRevealFocus } from './chunk-HCEHTJ5E.js';
40
+ export { Tooltip, useRevealFocus } from './chunk-HCEHTJ5E.js';
41
41
  import { Icon, slotIcon, warnOnce } from './chunk-53F7GVBQ.js';
42
- import { cn, FOCUS_RING, focusAfterSelfRemoval, FOCUSABLE, GLASS_SURFACE, useFocusKeptInList, FOCUS_INSET, useLatest, PEER_FOCUS_RING, GLASS_BACKDROP, FIELD, ZOOM_KEYS, rovingTabStop, FOCUS_ROOM, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberOpener, focusInitial, lockBodyScroll, unlockBodyScroll, OVERLAY_CLOSE_ATTR, OVERLAY_SURFACE, GLASS_OVERLAY, usePopupFocus, usePosition, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, CONTROL_ANCESTOR, GROUP_FOCUS_RING, useGridKeyboard, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, focusAfterRemoval, GLASS_DROPDOWN, ERROR_FOCUS_RING, FIELD_FOCUS_RING, atLeastFocusRoom, useNonModalDialog, useReturnFocus } from './chunk-OWQ7M6R7.js';
43
- export { useGridKeyboard } from './chunk-OWQ7M6R7.js';
44
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
42
+ import { cn, FOCUS_RING, focusAfterSelfRemoval, FOCUSABLE, GLASS_SURFACE, useFocusKeptInList, FOCUS_INSET, useLatest, PEER_FOCUS_RING, GLASS_BACKDROP, OPEN_TO_FOCUS, focusOutOf, FIELD, ZOOM_KEYS, rovingTabStop, FOCUS_ROOM, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberOpener, focusInitial, lockBodyScroll, unlockBodyScroll, OVERLAY_CLOSE_ATTR, OVERLAY_SURFACE, GLASS_OVERLAY, usePopupFocus, pointOf, pageAddress, registerOpenerRoot, rememberFocus, usePosition, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, CONTROL_ANCESTOR, GROUP_FOCUS_RING, useGridKeyboard, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, focusAfterRemoval, GLASS_DROPDOWN, ERROR_FOCUS_RING, FIELD_FOCUS_RING, openToFocus, atLeastFocusRoom, useNonModalDialog, useReturnFocus, onMovingOn } from './chunk-2724SJO2.js';
43
+ export { useGridKeyboard } from './chunk-2724SJO2.js';
45
44
  import { forwardRef, useRef, useId, useEffect, useState, createContext, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, memo, useImperativeHandle, useSyncExternalStore, Children, Fragment as Fragment$1, cloneElement, useReducer } from 'react';
46
45
  import { createPortal, flushSync } from 'react-dom';
46
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
47
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];
48
+ var selectionControlIn = (table) => table.querySelector("[data-ds-select-all] input") ?? table.querySelector("[data-ds-select-card] input");
49
+ function holdsSelection(table) {
50
+ const all = table.querySelector("[data-ds-select-all]");
51
+ return all ? all.getAttribute("data-selection") !== "none" : !!table.querySelector("[data-ds-select-card] input:checked");
52
+ }
53
+ var tablesIn = (box) => Array.from(box.querySelectorAll('[data-gs="table"]')).filter((t) => selectionControlIn(t));
54
+ function selectionAt(point) {
55
+ const from = point.startContainer;
56
+ for (let box = from instanceof HTMLElement ? from : from.parentElement; box && box !== document.body; box = box.parentElement) {
57
+ const tables = tablesIn(box);
58
+ if (!tables.length) continue;
59
+ const pick = (list2) => list2.filter((t) => point.comparePoint(t, 0) < 0).at(-1) ?? list2.find((t) => point.comparePoint(t, 0) > 0);
60
+ const table = pick(tables.filter(holdsSelection)) ?? pick(tables);
61
+ const control = table && selectionControlIn(table);
62
+ return control ? { box, control } : null;
52
63
  }
53
64
  return null;
54
65
  }
66
+ function selectionIn(box, point) {
67
+ const tables = tablesIn(box);
68
+ const at = (t) => point ? point.comparePoint(t, 0) : 0;
69
+ const table = tables.filter((t) => at(t) < 0).at(-1) ?? tables.find((t) => at(t) > 0) ?? tables[0];
70
+ return table ? selectionControlIn(table) : null;
71
+ }
72
+ var CONTROL = "[data-bulk-bar-control]";
55
73
  function BulkActionBar({ selectedCount, actions, onClearSelection, className }) {
56
- const isMobile = useBreakpoint("sm");
57
- if (selectedCount === 0) return null;
74
+ const isPhone = useBreakpoint("sm");
75
+ const host = useContext(BulkBarHostCtx);
76
+ const presence = useContext(BulkBarPresenceCtx);
77
+ const [anchor, setAnchor] = useState(null);
78
+ const [bearing, setBearing] = useState(null);
79
+ const [bar, setBar] = useState(null);
80
+ const [stop, setStop] = useState(0);
81
+ const labels = actions.map((action) => action.label).join("\0");
82
+ const [fit, setFit] = useState(null);
83
+ const tooWide = !!fit && fit.labels === labels && fit.room > 0 && fit.full > fit.room;
84
+ const compact = isPhone || tooWide;
85
+ const shown = selectedCount > 0;
86
+ const target = host ? host.layer : typeof document === "undefined" ? null : document.body;
87
+ const selection = useRef({ control: null, box: null, page: "" });
88
+ const point = useRef(null);
89
+ const movedOn = useRef(true);
90
+ const quitWatch = useRef(null);
91
+ const watching = useRef(null);
92
+ const watch = (control) => {
93
+ quitWatch.current?.();
94
+ movedOn.current = false;
95
+ watching.current = control;
96
+ quitWatch.current = onMovingOn(control, () => {
97
+ movedOn.current = true;
98
+ });
99
+ };
100
+ useLayoutEffect(() => {
101
+ if (shown && !bearing && anchor?.isConnected) setBearing(pointOf(anchor));
102
+ else if (!shown && bearing) setBearing(null);
103
+ }, [shown, bearing, anchor]);
104
+ useLayoutEffect(() => {
105
+ if (!shown || !bearing) return;
106
+ point.current = bearing;
107
+ const found = selectionAt(bearing);
108
+ selection.current = { control: found?.control ?? null, box: found?.box ?? null, page: pageAddress() };
109
+ });
110
+ useEffect(() => () => quitWatch.current?.(), []);
111
+ const onToolbar = useCallback((el) => {
112
+ setBar(el);
113
+ const unregister = registerOpenerRoot(el, () => selection.current.control?.isConnected ? rememberFocus(selection.current.control) : null);
114
+ return () => {
115
+ unregister();
116
+ setBar(null);
117
+ const active = document.activeElement;
118
+ const moved = movedOn.current;
119
+ const watched = watching.current;
120
+ quitWatch.current?.();
121
+ quitWatch.current = null;
122
+ watching.current = null;
123
+ movedOn.current = true;
124
+ if (!(active instanceof HTMLElement) || !(el.contains(active) || active === watched) || moved || inputModality() === "pointer") return;
125
+ const { control, box, page } = selection.current;
126
+ const at = point.current;
127
+ if (pageAddress() !== page) return;
128
+ focusAfterSelfRemoval(active, {
129
+ group: null,
130
+ point: at ?? void 0,
131
+ to: () => control?.isConnected ? control : box?.isConnected ? selectionIn(box, at) : null,
132
+ samePage: true,
133
+ removedOnly: true
134
+ });
135
+ };
136
+ }, []);
137
+ useLayoutEffect(() => {
138
+ if (!bar) return;
139
+ const report = () => {
140
+ if (host) host.setRoom(bar, bar.offsetHeight);
141
+ else presence?.room(bar, bulkBarRoom(bar.offsetHeight));
142
+ };
143
+ report();
144
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(report);
145
+ observer?.observe(bar);
146
+ return () => {
147
+ observer?.disconnect();
148
+ if (host) host.setRoom(bar, 0);
149
+ else presence?.room(bar, 0);
150
+ };
151
+ }, [bar, host, presence]);
152
+ useLayoutEffect(() => {
153
+ const layer = bar?.parentElement;
154
+ if (!bar || !layer) return;
155
+ const measure = () => {
156
+ const style = getComputedStyle(layer);
157
+ const room = layer.clientWidth - (parseFloat(style.paddingLeft) || 0) - (parseFloat(style.paddingRight) || 0);
158
+ setFit((was) => {
159
+ const full = !compact || !was || was.labels !== labels ? bar.scrollWidth : was.full;
160
+ return was && was.labels === labels && was.full === full && was.room === room ? was : { labels, full, room };
161
+ });
162
+ };
163
+ measure();
164
+ if (typeof ResizeObserver === "undefined") return;
165
+ const observer = new ResizeObserver(measure);
166
+ observer.observe(layer);
167
+ return () => observer.disconnect();
168
+ }, [bar, compact, labels]);
169
+ useEffect(() => {
170
+ if (!bar || inputModality() !== "keyboard") return;
171
+ const frame = requestAnimationFrame(() => {
172
+ const active = document.activeElement;
173
+ if (!(active instanceof HTMLElement) || active === document.body || bar.contains(active)) return;
174
+ if (active.getBoundingClientRect().bottom > bar.getBoundingClientRect().top) active.scrollIntoView({ block: "nearest" });
175
+ });
176
+ return () => cancelAnimationFrame(frame);
177
+ }, [bar]);
178
+ useEffect(() => {
179
+ if (shown) presence?.say(`${selectedCount} selected`);
180
+ }, [presence, shown, selectedCount]);
181
+ if (!shown) return null;
58
182
  const dropdownItems = actions.map((action) => ({
59
183
  label: action.label,
60
184
  icon: action.icon,
61
185
  onClick: action.onClick,
62
186
  variant: action.variant
63
187
  }));
64
- return /* @__PURE__ */ jsxs(
188
+ const count = (compact ? Math.min(actions.length, 1) : actions.length) + 1;
189
+ const current = Math.min(stop, count - 1);
190
+ const controls = () => bar ? Array.from(bar.querySelectorAll(CONTROL)) : [];
191
+ const tab = (i) => ({ "data-bulk-bar-control": "", tabIndex: i === current ? 0 : -1 });
192
+ const onKeyDown = (e) => {
193
+ const list2 = controls();
194
+ const at = list2.indexOf(e.target);
195
+ if (at < 0) return;
196
+ const to = e.key === "ArrowRight" ? (at + 1) % list2.length : e.key === "ArrowLeft" ? (at - 1 + list2.length) % list2.length : e.key === "Home" ? 0 : e.key === "End" ? list2.length - 1 : -1;
197
+ if (to < 0) return;
198
+ e.preventDefault();
199
+ list2[to].focus();
200
+ watch(list2[to]);
201
+ };
202
+ const onFocus = (e) => {
203
+ const at = controls().indexOf(e.target);
204
+ if (at >= 0) setStop(at);
205
+ watch(e.target);
206
+ };
207
+ const toolbar = /* @__PURE__ */ jsxs(
65
208
  "div",
66
209
  {
210
+ ref: onToolbar,
211
+ "data-bulk-bar": "",
67
212
  className: cn(
68
- "flex items-center gap-ds-3 rounded-[var(--ds-radius-md)]",
213
+ "pointer-events-auto max-w-full flex items-center gap-ds-3 rounded-[var(--ds-radius-md)]",
69
214
  "bg-[var(--ds-bg-surface-elevated)] border-[length:var(--ds-border-width)] border-[var(--ds-accent-ink)]",
70
215
  "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
71
216
  "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
@@ -74,16 +219,18 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
74
219
  style: { padding: "var(--ds-space-3) var(--ds-space-4)" },
75
220
  role: "toolbar",
76
221
  "aria-label": `${selectedCount} items selected`,
222
+ onKeyDown,
223
+ onFocus,
77
224
  children: [
78
225
  /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-accent-ink)] tabular-nums whitespace-nowrap", children: [
79
226
  selectedCount,
80
227
  " selected"
81
228
  ] }),
82
- /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-[var(--ds-border-subtle)]" }),
83
- isMobile ? /* @__PURE__ */ jsx(
229
+ actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "h-4 w-px shrink-0 bg-[var(--ds-border-subtle)]" }),
230
+ actions.length > 0 && (compact ? /* @__PURE__ */ jsx(
84
231
  DropdownMenu,
85
232
  {
86
- trigger: /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "more-vertical", size: 14 }), children: "Actions" }),
233
+ trigger: /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "more-vertical", size: 14 }), ...tab(0), children: "Actions" }),
87
234
  items: dropdownItems,
88
235
  align: "start"
89
236
  }
@@ -93,28 +240,31 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
93
240
  type: "button",
94
241
  variant: "secondary",
95
242
  size: "sm",
243
+ className: "whitespace-nowrap",
96
244
  onClick: action.onClick,
245
+ ...tab(i),
97
246
  children: action.label
98
247
  },
99
248
  i
100
- )) }),
249
+ )) })),
101
250
  /* @__PURE__ */ jsx(
102
251
  "button",
103
252
  {
104
253
  type: "button",
105
- onClick: (e) => {
106
- const bar = e.currentTarget.closest('[role="toolbar"]');
107
- focusAfterSelfRemoval(e.currentTarget, { item: bar, to: selectAllFor(bar) });
108
- onClearSelection();
109
- },
110
- className: cn("ml-auto text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
254
+ onClick: () => onClearSelection(),
255
+ className: cn("ml-auto shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
111
256
  "aria-label": "Clear selection",
257
+ ...tab(count - 1),
112
258
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
113
259
  }
114
260
  )
115
261
  ]
116
262
  }
117
263
  );
264
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
265
+ !bearing && /* @__PURE__ */ jsx("span", { ref: setAnchor, hidden: true, "data-bulk-bar-anchor": "" }),
266
+ target && createPortal(host ? toolbar : /* @__PURE__ */ jsx("div", { className: BULK_BAR_WINDOW_LAYER, "data-bulk-bar-layer": "", children: toolbar }), target)
267
+ ] });
118
268
  }
119
269
  var CONTROL_HEIGHT = {
120
270
  sm: "h-[var(--ds-control-height-sm)]",
@@ -1734,6 +1884,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1734
1884
  setBodyEl(el);
1735
1885
  }, [bodyInset]);
1736
1886
  useKeyboardScroll(bodyEl, title, open);
1887
+ const { setLayer: setBarLayer, room: barStack, value: barHost } = useBulkBarHost();
1737
1888
  const onCloseRef = useLatest(onClose);
1738
1889
  const onSubmitRef = useLatest(onSubmit);
1739
1890
  const isTopLayer = useOverlayLayer(open);
@@ -1868,19 +2019,28 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
1868
2019
  }
1869
2020
  ) })
1870
2021
  ] }),
1871
- children && /* @__PURE__ */ jsx(
1872
- "div",
1873
- {
1874
- ref: bodyRef,
1875
- className: cn("min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6", FOCUS_INSET),
1876
- style: {
1877
- paddingLeft: variant === "destructive" ? "calc(var(--ds-page-gutter) + 2.5rem + var(--ds-space-3))" : "var(--ds-page-gutter)",
1878
- paddingRight: insetLessScrollbar("var(--ds-page-gutter)")
1879
- },
1880
- children: /* @__PURE__ */ jsx(SurfaceBoundary, { children: /* @__PURE__ */ jsx(DrawerFooterCtx, { value: null, children: /* @__PURE__ */ jsx(OverlayMarkScope, { mark, children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) }) }) })
1881
- }
1882
- ),
1883
- isMobile && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "flex-1 min-h-0" }),
2022
+ children && // the body's box hosts a bulk-action bar from inside: at its foot, above the footer (Sprint 25.33). On a phone it
2023
+ // fills down to the footer, so that foot is the screen's, not the middle of it (the fix pass of 25.33)
2024
+ /* @__PURE__ */ jsxs("div", { className: cn("relative min-h-0 flex flex-col", isMobile ? "flex-1" : "flex-[0_1_auto]"), children: [
2025
+ /* @__PURE__ */ jsxs(
2026
+ "div",
2027
+ {
2028
+ ref: bodyRef,
2029
+ className: cn("min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6", FOCUS_INSET),
2030
+ style: {
2031
+ paddingLeft: variant === "destructive" ? "calc(var(--ds-page-gutter) + 2.5rem + var(--ds-space-3))" : "var(--ds-page-gutter)",
2032
+ paddingRight: insetLessScrollbar("var(--ds-page-gutter)"),
2033
+ ...barStack ? { scrollPaddingBottom: bulkBarRoom(barStack) } : {}
2034
+ },
2035
+ children: [
2036
+ /* @__PURE__ */ jsx(SurfaceBoundary, { children: /* @__PURE__ */ jsx(DrawerFooterCtx, { value: null, children: /* @__PURE__ */ jsx(OverlayMarkScope, { mark, children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children: /* @__PURE__ */ jsx(BulkBarHostCtx, { value: barHost, children }) }) }) }) }),
2037
+ /* @__PURE__ */ jsx(BulkBarSpacer, { room: barStack })
2038
+ ]
2039
+ }
2040
+ ),
2041
+ /* @__PURE__ */ jsx("div", { ref: setBarLayer, "data-bulk-bar-layer": "", className: BULK_BAR_LAYER })
2042
+ ] }),
2043
+ isMobile && !children && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "flex-1 min-h-0" }),
1884
2044
  /* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
1885
2045
  footer && /* @__PURE__ */ jsx("div", { className: cn(
1886
2046
  "shrink-0 flex justify-end gap-ds-2 py-ds-4 px-[var(--ds-page-gutter)]",
@@ -2279,101 +2439,104 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
2279
2439
  const canCancel = !controlled || !!onCancel;
2280
2440
  const canRetry = !controlled || !!onRetry;
2281
2441
  const canRemove = (item) => !!onRemove || !controlled && item.status === "error";
2282
- return /* @__PURE__ */ jsxs("div", { className: cn("space-y-ds-3", className), children: [
2283
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-1.5", children: [
2284
- showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: label }),
2285
- /* @__PURE__ */ jsxs(
2286
- "div",
2287
- {
2288
- onDragOver: (e) => {
2289
- e.preventDefault();
2290
- setDragOver(true);
2291
- },
2292
- onDragLeave: () => setDragOver(false),
2293
- onDrop: handleDrop,
2294
- onClick: () => inputRef.current?.click(),
2295
- className: cn(
2296
- "flex flex-col items-center justify-center gap-ds-2 cursor-pointer group",
2297
- "border-2 border-dashed rounded-[var(--ds-radius-md)]",
2298
- "transition-colors",
2299
- // The real file input is visually hidden inside; Tab lands on it and
2300
- // Enter/Space open the picker natively, so the zone shows its focus.
2301
- invalid ? ERROR_HAS_FOCUS_RING : FIELD_HAS_FOCUS_RING,
2302
- dragOver ? `${ACTIVE_RING} bg-[var(--ds-accent-whisper)]` : invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-whisper)]"
2303
- ),
2304
- style: { padding: "var(--ds-space-8) var(--ds-space-4)" },
2305
- children: [
2306
- /* @__PURE__ */ jsx("div", { className: cn(
2307
- "flex items-center justify-center w-10 h-10 rounded-[var(--ds-radius-full)] transition-colors",
2308
- "bg-[var(--ds-bg-muted)] group-hover:bg-[var(--ds-accent-subtle)]"
2309
- ), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 20, className: "text-[var(--ds-text-muted)] group-hover:text-[var(--ds-accent-subtle-text)] transition-colors" }) }),
2310
- /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2311
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: multiple ? "Drop files here or browse" : "Drop a file here or browse" }),
2312
- constraints && /* @__PURE__ */ jsx("p", { id: constraintsId, className: "text-xs text-[var(--ds-text-muted)] mt-ds-1", children: constraints })
2313
- ] }),
2314
- /* @__PURE__ */ jsx(
2315
- "input",
2316
- {
2317
- ref: inputRef,
2318
- id: inputId,
2319
- type: "file",
2320
- accept,
2321
- multiple,
2322
- className: "sr-only",
2323
- "aria-label": control.labelId ? void 0 : control.label,
2324
- "aria-labelledby": control.labelId,
2325
- "aria-describedby": describedBy,
2326
- "aria-invalid": invalid || void 0,
2327
- onChange: (e) => {
2328
- if (e.target.files?.length) addFiles(e.target.files);
2329
- e.target.value = "";
2442
+ return (
2443
+ // a wide control: in a form, its row fills the form rather than keeping a field's reading width (Sprint 25.33)
2444
+ /* @__PURE__ */ jsxs("div", { "data-wide-control": "", className: cn("space-y-ds-3", className), children: [
2445
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-1.5", children: [
2446
+ showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: label }),
2447
+ /* @__PURE__ */ jsxs(
2448
+ "div",
2449
+ {
2450
+ onDragOver: (e) => {
2451
+ e.preventDefault();
2452
+ setDragOver(true);
2453
+ },
2454
+ onDragLeave: () => setDragOver(false),
2455
+ onDrop: handleDrop,
2456
+ onClick: () => inputRef.current?.click(),
2457
+ className: cn(
2458
+ "flex flex-col items-center justify-center gap-ds-2 cursor-pointer group",
2459
+ "border-2 border-dashed rounded-[var(--ds-radius-md)]",
2460
+ "transition-colors",
2461
+ // The real file input is visually hidden inside; Tab lands on it and
2462
+ // Enter/Space open the picker natively, so the zone shows its focus.
2463
+ invalid ? ERROR_HAS_FOCUS_RING : FIELD_HAS_FOCUS_RING,
2464
+ dragOver ? `${ACTIVE_RING} bg-[var(--ds-accent-whisper)]` : invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-whisper)]"
2465
+ ),
2466
+ style: { padding: "var(--ds-space-8) var(--ds-space-4)" },
2467
+ children: [
2468
+ /* @__PURE__ */ jsx("div", { className: cn(
2469
+ "flex items-center justify-center w-10 h-10 rounded-[var(--ds-radius-full)] transition-colors",
2470
+ "bg-[var(--ds-bg-muted)] group-hover:bg-[var(--ds-accent-subtle)]"
2471
+ ), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 20, className: "text-[var(--ds-text-muted)] group-hover:text-[var(--ds-accent-subtle-text)] transition-colors" }) }),
2472
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2473
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: multiple ? "Drop files here or browse" : "Drop a file here or browse" }),
2474
+ constraints && /* @__PURE__ */ jsx("p", { id: constraintsId, className: "text-xs text-[var(--ds-text-muted)] mt-ds-1", children: constraints })
2475
+ ] }),
2476
+ /* @__PURE__ */ jsx(
2477
+ "input",
2478
+ {
2479
+ ref: inputRef,
2480
+ id: inputId,
2481
+ type: "file",
2482
+ accept,
2483
+ multiple,
2484
+ className: "sr-only",
2485
+ "aria-label": control.labelId ? void 0 : control.label,
2486
+ "aria-labelledby": control.labelId,
2487
+ "aria-describedby": describedBy,
2488
+ "aria-invalid": invalid || void 0,
2489
+ onChange: (e) => {
2490
+ if (e.target.files?.length) addFiles(e.target.files);
2491
+ e.target.value = "";
2492
+ }
2330
2493
  }
2331
- }
2332
- )
2333
- ]
2334
- }
2335
- ),
2336
- rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" }),
2337
- waiting && /* @__PURE__ */ jsx(InlineFieldError, { id: waitingId, message: waiting, className: "mt-0" })
2338
- ] }),
2339
- shown.length > 0 && /* @__PURE__ */ jsx("ul", { ref: listRef, className: "space-y-ds-2", children: shown.map((item) => {
2340
- const progress = percentOf(item.progress);
2341
- const words = item.status === "queued" ? "Waiting" : item.status === "uploading" ? `${Math.round(progress)}%` : item.status === "done" ? "Uploaded" : item.status === "error" ? "Failed" : null;
2342
- return /* @__PURE__ */ jsxs(
2343
- "li",
2344
- {
2345
- "data-upload-id": item.id,
2346
- "data-upload-status": item.status,
2347
- onFocus: (e) => {
2348
- if (e.target instanceof HTMLButtonElement) lastAction.current = { id: item.id, el: e.target };
2494
+ )
2495
+ ]
2496
+ }
2497
+ ),
2498
+ rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" }),
2499
+ waiting && /* @__PURE__ */ jsx(InlineFieldError, { id: waitingId, message: waiting, className: "mt-0" })
2500
+ ] }),
2501
+ shown.length > 0 && /* @__PURE__ */ jsx("ul", { ref: listRef, className: "space-y-ds-2", children: shown.map((item) => {
2502
+ const progress = percentOf(item.progress);
2503
+ const words = item.status === "queued" ? "Waiting" : item.status === "uploading" ? `${Math.round(progress)}%` : item.status === "done" ? "Uploaded" : item.status === "error" ? "Failed" : null;
2504
+ return /* @__PURE__ */ jsxs(
2505
+ "li",
2506
+ {
2507
+ "data-upload-id": item.id,
2508
+ "data-upload-status": item.status,
2509
+ onFocus: (e) => {
2510
+ if (e.target instanceof HTMLButtonElement) lastAction.current = { id: item.id, el: e.target };
2511
+ },
2512
+ className: cn(
2513
+ "flex items-center gap-ds-3 text-sm",
2514
+ "border-[length:var(--ds-border-width)]",
2515
+ item.status === "error" ? "border-[var(--ds-status-error)]" : "border-[var(--ds-border-subtle)]",
2516
+ "rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]"
2517
+ ),
2518
+ style: { padding: "var(--ds-space-3)" },
2519
+ children: [
2520
+ /* @__PURE__ */ jsx(Icon, { name: "folder", size: 16, className: "text-[var(--ds-text-muted)] shrink-0" }),
2521
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2522
+ /* @__PURE__ */ jsx(TruncFileName, { className: "text-[var(--ds-text-primary)]", children: item.name }),
2523
+ (item.size != null || words) && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)]", children: [item.size != null ? formatSize(item.size) : null, words].filter(Boolean).join(" \xB7 ") }),
2524
+ item.status === "uploading" && /* @__PURE__ */ jsx(Progress, { value: progress, size: "sm", label: `Uploading ${item.name}`, className: "mt-ds-1" }),
2525
+ item.status === "error" && /* @__PURE__ */ jsx("p", { className: "mt-ds-1 text-xs text-[var(--ds-status-error-text)]", children: item.error ?? "The upload didn't work." })
2526
+ ] }),
2527
+ item.status === "done" && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, className: "text-[var(--ds-status-success)] shrink-0", "aria-hidden": "true" }),
2528
+ running(item) && canCancel && // the visible word starts the name, which says which file (WCAG 2.5.3)
2529
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => cancel(item), "aria-label": `Cancel ${item.name}`, children: "Cancel" }),
2530
+ item.status === "error" && canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => retry(item), "aria-label": `Retry ${item.name}`, children: "Retry" }),
2531
+ !running(item) && canRemove(item) && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => remove(item), "aria-label": `Remove ${item.name}`, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 }) })
2532
+ ]
2349
2533
  },
2350
- className: cn(
2351
- "flex items-center gap-ds-3 text-sm",
2352
- "border-[length:var(--ds-border-width)]",
2353
- item.status === "error" ? "border-[var(--ds-status-error)]" : "border-[var(--ds-border-subtle)]",
2354
- "rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]"
2355
- ),
2356
- style: { padding: "var(--ds-space-3)" },
2357
- children: [
2358
- /* @__PURE__ */ jsx(Icon, { name: "folder", size: 16, className: "text-[var(--ds-text-muted)] shrink-0" }),
2359
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2360
- /* @__PURE__ */ jsx(TruncFileName, { className: "text-[var(--ds-text-primary)]", children: item.name }),
2361
- (item.size != null || words) && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)]", children: [item.size != null ? formatSize(item.size) : null, words].filter(Boolean).join(" \xB7 ") }),
2362
- item.status === "uploading" && /* @__PURE__ */ jsx(Progress, { value: progress, size: "sm", label: `Uploading ${item.name}`, className: "mt-ds-1" }),
2363
- item.status === "error" && /* @__PURE__ */ jsx("p", { className: "mt-ds-1 text-xs text-[var(--ds-status-error-text)]", children: item.error ?? "The upload didn't work." })
2364
- ] }),
2365
- item.status === "done" && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, className: "text-[var(--ds-status-success)] shrink-0", "aria-hidden": "true" }),
2366
- running(item) && canCancel && // the visible word starts the name, which says which file (WCAG 2.5.3)
2367
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => cancel(item), "aria-label": `Cancel ${item.name}`, children: "Cancel" }),
2368
- item.status === "error" && canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => retry(item), "aria-label": `Retry ${item.name}`, children: "Retry" }),
2369
- !running(item) && canRemove(item) && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => remove(item), "aria-label": `Remove ${item.name}`, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 }) })
2370
- ]
2371
- },
2372
- item.id
2373
- );
2374
- }) }),
2375
- /* @__PURE__ */ jsx("div", { role: "status", className: "sr-only", children: /* @__PURE__ */ jsx("span", { children: heard.text }, heard.n) })
2376
- ] });
2534
+ item.id
2535
+ );
2536
+ }) }),
2537
+ /* @__PURE__ */ jsx("div", { role: "status", className: "sr-only", children: /* @__PURE__ */ jsx("span", { children: heard.text }, heard.n) })
2538
+ ] })
2539
+ );
2377
2540
  }
2378
2541
  function SliderRange({
2379
2542
  value,
@@ -3064,6 +3227,7 @@ var Tag = forwardRef(function Tag2({
3064
3227
  size = "md",
3065
3228
  color,
3066
3229
  maxWidth,
3230
+ width,
3067
3231
  onRemove,
3068
3232
  onClick,
3069
3233
  selected,
@@ -3098,8 +3262,9 @@ var Tag = forwardRef(function Tag2({
3098
3262
  "aria-disabled": !clickable && disabled || void 0,
3099
3263
  "data-selected": isSelected ? "" : void 0,
3100
3264
  className: cn(
3101
- "inline-flex items-center font-medium max-w-full min-w-0 whitespace-nowrap",
3265
+ "inline-flex items-center font-medium w-fit max-w-full min-w-0 whitespace-nowrap",
3102
3266
  "rounded-[var(--ds-radius-sm)]",
3267
+ width && "justify-center",
3103
3268
  "transition-colors duration-[var(--ds-transition-speed)]",
3104
3269
  sizeStyles[size],
3105
3270
  colorClasses,
@@ -3107,7 +3272,7 @@ var Tag = forwardRef(function Tag2({
3107
3272
  disabled && "opacity-disabled cursor-not-allowed",
3108
3273
  className
3109
3274
  ),
3110
- style: maxWidth ? { maxWidth } : void 0,
3275
+ style: maxWidth || width ? { ...width ? { width } : {}, ...maxWidth ? { maxWidth } : {} } : void 0,
3111
3276
  children: [
3112
3277
  clickable ? /* @__PURE__ */ jsx(
3113
3278
  "button",
@@ -4057,6 +4222,15 @@ var Alert = forwardRef(function Alert2({
4057
4222
  }
4058
4223
  );
4059
4224
  });
4225
+ var FORM_ROWS = cn(
4226
+ "[--gs-form-default:calc(var(--ds-bp-md)_-_2*var(--ds-space-6))]",
4227
+ "[:where(&)>*]:max-w-[var(--gs-row-cap,var(--ds-form-max,var(--gs-form-default)))]",
4228
+ // the row is the wide control itself (a FileUpload with its own label, written straight into the form), or holds one
4229
+ "[&>[data-wide-control]]:[--gs-row-cap:none]",
4230
+ "[&>*:has([data-wide-control])]:[--gs-row-cap:none]",
4231
+ "[&:has([data-wide-control])>[data-form-actions]]:[--gs-row-cap:none]"
4232
+ );
4233
+ var FORM_CAP = "max-w-[var(--gs-form-cap,var(--ds-form-max,var(--gs-form-default)))] has-[[data-wide-control]]:[--gs-form-cap:none]";
4060
4234
  var isThenable = (value) => !!value && typeof value.then === "function";
4061
4235
  function stampFormId(node, formId) {
4062
4236
  return Children.map(node, (child) => {
@@ -4151,10 +4325,10 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
4151
4325
  return;
4152
4326
  }
4153
4327
  const first = form.querySelector("[aria-invalid='true']");
4154
- if (first) {
4328
+ if (first) openToFocus(first, () => {
4155
4329
  if (typeof first.scrollIntoView === "function") first.scrollIntoView({ block: "center", behavior: "smooth" });
4156
4330
  focusTarget(first).focus({ preventScroll: true });
4157
- }
4331
+ });
4158
4332
  }
4159
4333
  }, [submittedRef, errorSummaryRef, focusSummary]);
4160
4334
  useLayoutEffect(() => {
@@ -4236,18 +4410,19 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
4236
4410
  const focusField = (id) => (e) => {
4237
4411
  e.preventDefault();
4238
4412
  const el = id ? document.getElementById(id) : null;
4239
- if (el) {
4413
+ if (el) openToFocus(el, () => {
4240
4414
  el.scrollIntoView?.({ block: "center" });
4241
4415
  focusTarget(el).focus();
4242
- }
4416
+ });
4243
4417
  };
4244
4418
  const summaryNode = errorSummary && summary.length >= 2 ? typeof errorSummary === "function" ? errorSummary(summary) : /* @__PURE__ */ jsx(Alert, { variant: "error", title: `${summary.length} fields need attention`, className: "mb-ds-4", children: /* @__PURE__ */ jsx("ul", { className: "list-disc pl-ds-5 flex flex-col gap-ds-1", children: summary.map((f) => /* @__PURE__ */ jsxs("li", { children: [
4245
4419
  /* @__PURE__ */ jsx("a", { href: f.id ? `#${f.id}` : void 0, onClick: focusField(f.id), className: cn("underline underline-offset-2 text-[var(--ds-text-primary)]", FOCUS_RING), children: f.label }),
4246
4420
  ": ",
4247
4421
  f.message
4248
4422
  ] }, f.id || f.label)) }) }) : null;
4423
+ const callerWidth = /(?:^|[\s:!])max-w-/.test(className ?? "");
4249
4424
  const actionsNode = actions && !drawerFooter ? /* @__PURE__ */ jsx("div", { "data-form-actions": "", className: cn("flex flex-wrap items-center gap-ds-2 pt-ds-2", actionsAlign === "end" ? "justify-end" : "justify-start"), children: actions }) : null;
4250
- return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsx(FormChangeCtx.Provider, { value: reportChange, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5 max-w-[var(--ds-form-max,calc(var(--ds-bp-md)_-_2*var(--ds-space-6)))]", className), style: fullWidth ? { "--ds-form-max": "none" } : void 0, noValidate: true, children: [
4425
+ return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsx(FormChangeCtx.Provider, { value: reportChange, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5", FORM_ROWS, FORM_CAP, className), style: fullWidth || callerWidth ? { "--ds-form-max": "none" } : void 0, noValidate: true, children: [
4251
4426
  summaryNode && /* @__PURE__ */ jsx("div", { ref: summaryRef, "data-form-error-summary": "", tabIndex: -1, className: cn("rounded-[var(--ds-radius-md)] focus-visible:*:shadow-none", FOCUS_RING), children: summaryNode }),
4252
4427
  children,
4253
4428
  actionsNode
@@ -4381,7 +4556,7 @@ function TransferList({
4381
4556
  setCheckedSelected(allChecked ? /* @__PURE__ */ new Set() : new Set(enabledIds));
4382
4557
  }, [filteredSelected, checkedSelected]);
4383
4558
  const isStacked = useBreakpoint("sm");
4384
- return /* @__PURE__ */ jsxs("div", { ref, className: cn(isStacked ? "flex flex-col gap-ds-2" : "flex items-stretch gap-ds-3", className), children: [
4559
+ return /* @__PURE__ */ jsxs("div", { ref, "data-wide-control": "", className: cn(isStacked ? "flex flex-col gap-ds-2" : "flex items-stretch gap-ds-3", className), children: [
4385
4560
  /* @__PURE__ */ jsx(
4386
4561
  Panel,
4387
4562
  {
@@ -5757,9 +5932,16 @@ var PIN_FOCUS_END = "[tr:focus-visible>&]:after:right-[3px] [tr:focus-visible>&]
5757
5932
  var PINNED_BACKGROUND = "linear-gradient(var(--gs-row-tint, transparent), var(--gs-row-tint, transparent)), linear-gradient(var(--gs-pinned-surface), var(--gs-pinned-surface)), var(--gs-pinned-canvas)";
5758
5933
  var PINNED_LAYERS = cn(
5759
5934
  "[--gs-pinned-surface:var(--ds-bg-surface)] [--gs-pinned-canvas:var(--ds-bg-canvas)]",
5760
- "supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-surface:oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)))]",
5761
5935
  "supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-canvas:oklch(from_var(--ds-bg-canvas)_l_c_h_/_1)]"
5762
5936
  );
5937
+ function drawnText(el) {
5938
+ const copy = el.cloneNode(true);
5939
+ copy.querySelectorAll(".sr-only").forEach((n) => n.remove());
5940
+ return copy.textContent ?? "";
5941
+ }
5942
+ var CELL_ACTION = "button, a[href], [role='button'], [role='link']";
5943
+ var CELL_READ_OR_SET = "input:not([type='hidden']), select, textarea, img:not([alt='']), [role='switch'], [role='checkbox'], [role='radio'], [role='slider'], [role='spinbutton'], [role='combobox'], [role='img']:not([aria-hidden='true'])";
5944
+ var iconActionsOnly = (td) => !td.querySelector(CELL_READ_OR_SET) && !!td.querySelector(CELL_ACTION);
5763
5945
  var PIN_SHADOW = "oklch(0 0 0 / 0.18)";
5764
5946
  var ROW_CONTROL = `${FOCUSABLE}, label, [role="button"], [role="checkbox"], [role="switch"], [role="menuitem"], [role="link"]`;
5765
5947
  function clickIsCard(e) {
@@ -6312,7 +6494,7 @@ function Table({
6312
6494
  const endColumns = columns.filter((c) => c.pin === "end").length;
6313
6495
  const endCount = endColumns + trail;
6314
6496
  const nameIndex = columns.length > endColumns ? lead : -1;
6315
- const { ref: scrollRef, elRef: scrollEl, measure: measureScroll, scrollable, edges, fadeProps } = useScrollEdges({
6497
+ const { ref: scrollRef, elRef: scrollEl, measure: measureScroll, scrollable, overflowing, edges, fadeProps } = useScrollEdges({
6316
6498
  enabled: !isMobile,
6317
6499
  noFade: { left: lead + (pins.nameFits ? 1 : 0) > 0, right: endCount > 0 }
6318
6500
  });
@@ -6358,6 +6540,7 @@ function Table({
6358
6540
  }, [isMobile, lead, trail, endCount, nameIndex, scrollEl, columns, drawn.length, visibleKeys.length]);
6359
6541
  const pinnedStart = lead + (pins.nameFits ? 1 : 0);
6360
6542
  const pinStyle = (position, total) => {
6543
+ if (!overflowing) return void 0;
6361
6544
  if (position < pinnedStart && pins.start[position] !== void 0) {
6362
6545
  const inner = position === pinnedStart - 1;
6363
6546
  return { position: "sticky", left: pins.start[position], zIndex: 1, background: PINNED_BACKGROUND, boxShadow: inner && edges.left ? `6px 0 6px -6px ${PIN_SHADOW}` : void 0 };
@@ -6376,17 +6559,22 @@ function Table({
6376
6559
  };
6377
6560
  const fade = fadeProps;
6378
6561
  const [renderedKinds, setRenderedKinds] = useState(() => /* @__PURE__ */ new Map());
6562
+ const [iconOnlyCols, setIconOnlyCols] = useState(() => /* @__PURE__ */ new Set());
6379
6563
  useLayoutEffect(() => {
6380
6564
  const table2 = tableRef.current;
6381
6565
  if (!table2 || isMobile) return;
6382
6566
  const next = /* @__PURE__ */ new Map();
6567
+ const icons = /* @__PURE__ */ new Set();
6383
6568
  for (const col of columns) {
6569
+ const cells = Array.from(table2.querySelectorAll(`:scope > tbody > tr > td[data-col="${CSS.escape(col.key)}"]`)).slice(0, 50);
6570
+ const texts = cells.map(drawnText);
6571
+ if (cells.length && cells.every((td, i) => !texts[i].trim() && iconActionsOnly(td))) icons.add(col.key);
6384
6572
  if (kindOf2(col)) continue;
6385
- const texts = Array.from(table2.querySelectorAll(`:scope > tbody > tr > td[data-col="${CSS.escape(col.key)}"]`)).slice(0, 50).map((td) => td.textContent ?? "");
6386
6573
  const kind = texts.length ? kindOfRenderedText(texts) : void 0;
6387
6574
  if (kind) next.set(col.key, kind);
6388
6575
  }
6389
6576
  setRenderedKinds((prev) => prev.size === next.size && [...next].every(([k, v]) => prev.get(k) === v) ? prev : next);
6577
+ setIconOnlyCols((prev) => prev.size === icons.size && [...icons].every((k) => prev.has(k)) ? prev : icons);
6390
6578
  }, [columns, kindOf2, drawn, isMobile, visibleKeys.length]);
6391
6579
  const [focusKey, setFocusKey] = useState(null);
6392
6580
  const visibleSet = new Set(visibleKeys);
@@ -6676,7 +6864,7 @@ function Table({
6676
6864
  scrollToRow(key);
6677
6865
  }, [drawnStart, drawn.length, visibleKeys.length, scrollToRow]);
6678
6866
  const cardHeading = title ? /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: false }) : null;
6679
- const titledCards = (body) => /* @__PURE__ */ jsxs("div", { ref: listRoot, "data-ds-list": "", "data-gs": "table", className: cn("flex flex-col", listClass), onFocus: noteFocus, onBlur: forgetFocus, children: [
6867
+ const titledCards = (body) => /* @__PURE__ */ jsxs("div", { ref: listRoot, "data-ds-list": "", "data-gs": "table", "data-wide-control": "", className: cn("flex flex-col", listClass), onFocus: noteFocus, onBlur: forgetFocus, children: [
6680
6868
  cardHeading,
6681
6869
  body
6682
6870
  ] });
@@ -6730,11 +6918,11 @@ function Table({
6730
6918
  ] }, col.key)) }, r)) })
6731
6919
  ] });
6732
6920
  if (title) return titledCards(skeletonCards);
6733
- return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className, children: skeletonCards });
6921
+ return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", "data-wide-control": "", className, children: skeletonCards });
6734
6922
  }
6735
6923
  if (data.length === 0 && emptyState) {
6736
6924
  if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
6737
- 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 });
6925
+ return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", "data-wide-control": "", className: cn("py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", className), children: emptyState });
6738
6926
  }
6739
6927
  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: [
6740
6928
  loading && data.length > 0 && /* @__PURE__ */ jsx(RefreshLine, { className: "inset-x-[4px] rounded-full" }),
@@ -6789,8 +6977,10 @@ function Table({
6789
6977
  }
6790
6978
  } : void 0,
6791
6979
  children: [
6792
- selectable && box && // "Select" and the row's name, as in the table (T15); a parent with some of its rows chosen is mixed
6793
- /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, indeterminate: box.mixed, onChange: (_, { shiftKey: shiftKey2 }) => toggleBox(originalIdx, id, shiftKey2), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-card-name-${idPart(id)}` : `${headingId}-select` }),
6980
+ selectable && box && // "Select" and the row's name, as in the table (T15); a parent with some of its rows chosen is mixed. Marked as
6981
+ // the card's selection box: with no select-all on a phone, the first card's is where a BulkActionBar's
6982
+ // handover finds the selection (the fix pass of 25.33)
6983
+ /* @__PURE__ */ jsx("div", { "data-ds-select-card": "", children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, indeterminate: box.mixed, onChange: (_, { shiftKey: shiftKey2 }) => toggleBox(originalIdx, id, shiftKey2), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-card-name-${idPart(id)}` : `${headingId}-select` }) }),
6794
6984
  columns.map((col, c) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-ds-2 text-sm", children: [
6795
6985
  /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: col.header }),
6796
6986
  /* @__PURE__ */ jsx(CardValue, { value: row[col.key], id: lead + c === nameIndex ? `${headingId}-card-name-${idPart(id)}` : void 0 })
@@ -6864,8 +7054,9 @@ function Table({
6864
7054
  // a tree table is a treegrid (item 14): its rows have levels, and the arrow keys move between them
6865
7055
  /* @__PURE__ */ jsxs("table", { ref: tableRef, role: nested ? "treegrid" : void 0, "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: [
6866
7056
  /* @__PURE__ */ jsx("thead", { className: cn("bg-[var(--ds-bg-muted)]", stickyHeader && "sticky top-0 z-10"), onKeyDown: nested ? onHeadKeyDown : void 0, onFocus: nested ? onHeadFocus : void 0, 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: [
6867
- selectable && // data-ds-select-all: the selection's own control, where a BulkActionBar's Clear selection sends focus
6868
- /* @__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(
7057
+ selectable && // data-ds-select-all: the selection's own control, where a BulkActionBar's Clear selection sends focus; and
7058
+ // whether the table holds a selection, said as it renders (the box's mixed state is set a moment later)
7059
+ /* @__PURE__ */ jsx("th", { "data-ds-select-all": "", "data-selection": allSelected ? "all" : someSelected ? "some" : "none", 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(
6869
7060
  Checkbox,
6870
7061
  {
6871
7062
  ref: selectAllRef,
@@ -6922,6 +7113,9 @@ function Table({
6922
7113
  ]
6923
7114
  }
6924
7115
  )
7116
+ ) : iconOnlyCols.has(col.key) ? (
7117
+ // a column of icon buttons: its name for a screen reader, its width its buttons' (Sprint 25.33)
7118
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: col.header })
6925
7119
  ) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-ds-1", children: col.header })
6926
7120
  },
6927
7121
  col.key
@@ -7104,6 +7298,7 @@ function Table({
7104
7298
  ref: listRoot,
7105
7299
  "data-ds-list": "",
7106
7300
  "data-gs": "table",
7301
+ "data-wide-control": "",
7107
7302
  className: cn("relative w-full min-w-0 flex flex-col", FRAME_CLASSES, FRAME_FOCUS_RING, control && "min-h-0", listClass),
7108
7303
  onFocus: noteFocus,
7109
7304
  onBlur: forgetFocus,
@@ -8718,7 +8913,11 @@ function Calendar({
8718
8913
  }
8719
8914
  check = setTimeout(settle, SETTLE_MS);
8720
8915
  };
8721
- const onOut = () => {
8916
+ const onOut = (e) => {
8917
+ if (!e.target?.closest?.('[role="dialog"], [role="alertdialog"]')) {
8918
+ stop();
8919
+ return;
8920
+ }
8722
8921
  clearTimeout(check);
8723
8922
  check = setTimeout(settle, SETTLE_MS);
8724
8923
  };
@@ -9264,38 +9463,42 @@ function ExpandableDescription({ children, className }) {
9264
9463
  function HorizontalLayout({ items, minItemWidth, label, className }) {
9265
9464
  const [row, setRow] = useState(null);
9266
9465
  useKeyboardScroll(row, label, true, false, "x");
9267
- 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) => {
9268
- const isFirst = i === 0;
9269
- const isLast = i === items.length - 1;
9270
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 shrink-0 flex-col items-center snap-start", style: { minWidth: minItemWidth }, children: [
9271
- /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full", children: [
9272
- /* @__PURE__ */ jsx(
9273
- "div",
9274
- {
9275
- className: cn(
9276
- "flex-1 h-[2px] transition-colors",
9277
- isFirst ? "bg-transparent" : "bg-[var(--ds-border-subtle)]"
9278
- )
9279
- }
9280
- ),
9281
- /* @__PURE__ */ jsx(Marker, { item, vertical: false }),
9282
- /* @__PURE__ */ jsx(
9283
- "div",
9284
- {
9285
- className: cn(
9286
- "flex-1 h-[2px] transition-colors",
9287
- isLast ? "bg-transparent" : "bg-[var(--ds-border-subtle)]"
9288
- )
9289
- }
9290
- )
9291
- ] }),
9292
- /* @__PURE__ */ jsxs("div", { className: "text-center mt-ds-2 px-ds-3", children: [
9293
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: item.title }),
9294
- item.description && /* @__PURE__ */ jsx(ExpandableDescription, { className: "text-center", children: item.description }),
9295
- /* @__PURE__ */ jsx(ItemTime, { item })
9296
- ] })
9297
- ] }, i);
9298
- }) });
9466
+ return (
9467
+ // 4 px of room inside its edges, and snapping that keeps it, so the first marker and the row's own keyboard outline
9468
+ // never meet (Sprint 25.33: the owner's answer to Sprint 25.30's look question)
9469
+ /* @__PURE__ */ jsx("div", { ref: setRow, "data-timeline-row": "", className: cn("relative flex items-start overflow-x-auto snap-x p-[4px] scroll-px-[4px]", FOCUS_INSET, className), children: items.map((item, i) => {
9470
+ const isFirst = i === 0;
9471
+ const isLast = i === items.length - 1;
9472
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 shrink-0 flex-col items-center snap-start", style: { minWidth: minItemWidth }, children: [
9473
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full", children: [
9474
+ /* @__PURE__ */ jsx(
9475
+ "div",
9476
+ {
9477
+ className: cn(
9478
+ "flex-1 h-[2px] transition-colors",
9479
+ isFirst ? "bg-transparent" : "bg-[var(--ds-border-subtle)]"
9480
+ )
9481
+ }
9482
+ ),
9483
+ /* @__PURE__ */ jsx(Marker, { item, vertical: false }),
9484
+ /* @__PURE__ */ jsx(
9485
+ "div",
9486
+ {
9487
+ className: cn(
9488
+ "flex-1 h-[2px] transition-colors",
9489
+ isLast ? "bg-transparent" : "bg-[var(--ds-border-subtle)]"
9490
+ )
9491
+ }
9492
+ )
9493
+ ] }),
9494
+ /* @__PURE__ */ jsxs("div", { className: "text-center mt-ds-2 px-ds-3", children: [
9495
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: item.title }),
9496
+ item.description && /* @__PURE__ */ jsx(ExpandableDescription, { className: "text-center", children: item.description }),
9497
+ /* @__PURE__ */ jsx(ItemTime, { item })
9498
+ ] })
9499
+ ] }, i);
9500
+ }) })
9501
+ );
9299
9502
  }
9300
9503
  var exactFormat = (locale, d) => new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short" }).format(d);
9301
9504
  var exactDayFormat = (locale, d) => new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(d);
@@ -9378,20 +9581,54 @@ function CollapsibleRoot({
9378
9581
  const [internalOpen, setInternalOpen] = useState(defaultOpen);
9379
9582
  const isControlled = controlledOpen !== void 0;
9380
9583
  const isOpen = isControlled ? controlledOpen : internalOpen;
9584
+ const triggerRef = useRef(null);
9585
+ const setTrigger = useCallback((el) => {
9586
+ triggerRef.current = el;
9587
+ }, []);
9588
+ const trigger = useCallback(() => triggerRef.current, []);
9589
+ const open = () => {
9590
+ if (isOpen) return;
9591
+ if (!isControlled) setInternalOpen(true);
9592
+ onOpenChange?.(true);
9593
+ };
9381
9594
  const toggle = () => {
9382
9595
  const next = !isOpen;
9383
9596
  if (!isControlled) setInternalOpen(next);
9384
9597
  onOpenChange?.(next);
9385
9598
  };
9386
- return /* @__PURE__ */ jsx(CollapsibleContext, { value: { isOpen, toggle }, children: /* @__PURE__ */ jsx("div", { className, "data-state": isOpen ? "open" : "closed", children: typeof children === "function" ? children({ isOpen, toggle }) : children }) });
9599
+ return /* @__PURE__ */ jsx(CollapsibleContext, { value: { isOpen, toggle, setTrigger, trigger, open }, children: /* @__PURE__ */ jsx("div", { className, "data-state": isOpen ? "open" : "closed", children: typeof children === "function" ? children({ isOpen, toggle }) : children }) });
9600
+ }
9601
+ var merged = /* @__PURE__ */ new WeakMap();
9602
+ function withTrigger(own, setTrigger) {
9603
+ if (!own) return setTrigger;
9604
+ let bySetter = merged.get(own);
9605
+ if (!bySetter) merged.set(own, bySetter = /* @__PURE__ */ new WeakMap());
9606
+ let attach = bySetter.get(setTrigger);
9607
+ if (!attach) {
9608
+ attach = (el) => {
9609
+ setTrigger(el);
9610
+ let cleanup;
9611
+ if (typeof own === "function") cleanup = own(el);
9612
+ else own.current = el;
9613
+ return () => {
9614
+ setTrigger(null);
9615
+ if (typeof cleanup === "function") cleanup();
9616
+ else if (typeof own === "function") own(null);
9617
+ else own.current = null;
9618
+ };
9619
+ };
9620
+ bySetter.set(setTrigger, attach);
9621
+ }
9622
+ return attach;
9387
9623
  }
9388
9624
  function CollapsibleTrigger({ children, className }) {
9389
- const { isOpen, toggle } = useCollapsible();
9625
+ const { isOpen, toggle, setTrigger } = useCollapsible();
9390
9626
  if (isValidElement(children)) {
9391
9627
  const child = children;
9392
9628
  return cloneElement(child, {
9393
9629
  // a Button trigger in a form toggles; it never submits the form (0.21.0)
9394
9630
  ...triggerType(child),
9631
+ ref: withTrigger(child.props.ref, setTrigger),
9395
9632
  "aria-expanded": isOpen,
9396
9633
  className: cn(child.props.className, className),
9397
9634
  onClick: (e) => {
@@ -9400,29 +9637,92 @@ function CollapsibleTrigger({ children, className }) {
9400
9637
  }
9401
9638
  });
9402
9639
  }
9403
- return /* @__PURE__ */ jsx("button", { type: "button", className: cn("text-left cursor-pointer", FOCUS_RING, className), onClick: toggle, "aria-expanded": isOpen, children });
9640
+ return /* @__PURE__ */ jsx("button", { ref: withTrigger(void 0, setTrigger), type: "button", className: cn("text-left cursor-pointer", FOCUS_RING, className), onClick: toggle, "aria-expanded": isOpen, children });
9404
9641
  }
9405
9642
  function CollapsibleContent({ children, className }) {
9406
- const { isOpen } = useCollapsible();
9643
+ const { isOpen, trigger, open } = useCollapsible();
9407
9644
  const ref = useRef(null);
9408
- const innerRef = useRef(null);
9409
- const [height, setHeight] = useState(void 0);
9410
- useEffect(() => {
9411
- if (innerRef.current) {
9412
- setHeight(isOpen ? innerRef.current.scrollHeight : 0);
9645
+ const asked = useRef(null);
9646
+ const isOpenNow = useLatest(isOpen);
9647
+ const openNow = useLatest(open);
9648
+ useLayoutEffect(() => {
9649
+ const el = ref.current;
9650
+ if (!el) return;
9651
+ const onAsk = (e) => {
9652
+ if (isOpenNow.current) return;
9653
+ asked.current = e.detail;
9654
+ openNow.current();
9655
+ };
9656
+ el.addEventListener(OPEN_TO_FOCUS, onAsk);
9657
+ return () => el.removeEventListener(OPEN_TO_FOCUS, onAsk);
9658
+ }, [isOpenNow, openNow]);
9659
+ useLayoutEffect(() => {
9660
+ if (asked.current && !isOpen) asked.current = null;
9661
+ });
9662
+ const [height, setHeight] = useState(isOpen ? "auto" : 0);
9663
+ const [inertNow, setInertNow] = useState(!isOpen);
9664
+ const was = useRef(isOpen);
9665
+ useLayoutEffect(() => {
9666
+ const el = ref.current;
9667
+ if (was.current === isOpen) return;
9668
+ was.current = isOpen;
9669
+ if (!el) return;
9670
+ if (!isOpen && el.contains(document.activeElement)) {
9671
+ trigger()?.focus();
9672
+ if (el.contains(document.activeElement)) focusOutOf(el);
9673
+ }
9674
+ const ask = asked.current;
9675
+ asked.current = null;
9676
+ if (isOpen && ask && !ask.done && performance.now() - ask.at < 1e3 && !ask.target.closest("[inert]")) {
9677
+ ask.done = true;
9678
+ ask.step();
9679
+ }
9680
+ setInertNow(!isOpen);
9681
+ const seconds = parseFloat(getComputedStyle(el).transitionDuration) || 0;
9682
+ if (seconds <= 0) {
9683
+ setHeight(isOpen ? "auto" : 0);
9684
+ return;
9685
+ }
9686
+ let frame = 0;
9687
+ if (isOpen) setHeight(el.scrollHeight);
9688
+ else {
9689
+ setHeight(el.scrollHeight);
9690
+ frame = requestAnimationFrame(() => {
9691
+ void el.offsetHeight;
9692
+ setHeight(0);
9693
+ });
9413
9694
  }
9414
- }, [isOpen]);
9695
+ let done = false;
9696
+ const settle = () => {
9697
+ if (done) return;
9698
+ done = true;
9699
+ if (isOpen) setHeight("auto");
9700
+ };
9701
+ const onEnd = (e) => {
9702
+ if (e.target === el && e.propertyName === "height") settle();
9703
+ };
9704
+ el.addEventListener("transitionend", onEnd);
9705
+ const timer = setTimeout(settle, seconds * 1e3 + 100);
9706
+ return () => {
9707
+ cancelAnimationFrame(frame);
9708
+ el.removeEventListener("transitionend", onEnd);
9709
+ clearTimeout(timer);
9710
+ };
9711
+ }, [isOpen, trigger]);
9712
+ const moving = typeof height === "number" && height > 0;
9415
9713
  return /* @__PURE__ */ jsx(
9416
9714
  "div",
9417
9715
  {
9418
9716
  ref,
9419
- className: cn("overflow-hidden transition-[height]", className),
9717
+ "data-state": isOpen ? "open" : "closed",
9718
+ inert: inertNow && !isOpen,
9719
+ className: cn((!isOpen || moving) && "overflow-hidden", "transition-[height]", className),
9420
9720
  style: {
9421
- height: height ?? 0,
9721
+ height: height === "auto" ? void 0 : height,
9422
9722
  transitionDuration: "var(--ds-transition-speed)",
9423
9723
  transitionTimingFunction: "var(--ds-transition-ease)"
9424
9724
  },
9425
- children: /* @__PURE__ */ jsx("div", { ref: innerRef, children })
9725
+ children: /* @__PURE__ */ jsx("div", { children })
9426
9726
  }
9427
9727
  );
9428
9728
  }
@@ -9505,6 +9805,7 @@ function TreeView({
9505
9805
  "aria-label": ariaLabel,
9506
9806
  "aria-labelledby": ariaLabelledBy
9507
9807
  }) {
9808
+ useWantsInset();
9508
9809
  const [ownSelected, setOwnSelected] = useState(() => new Set(defaultSelected));
9509
9810
  const selected = useMemo(() => selectedProp ? new Set(selectedProp) : ownSelected, [selectedProp, ownSelected]);
9510
9811
  const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set([...defaultExpanded, ...foldersHolding(nodes, selected)]));
@@ -9659,7 +9960,7 @@ function TreeNodeRow({
9659
9960
  const hasChildren = !!node.children?.length;
9660
9961
  const isExpanded = expanded.has(node.id);
9661
9962
  const isSelected = selected.has(node.id);
9662
- const holdsSelection = !isSelected && holding.has(node.id);
9963
+ const holdsSelection2 = !isSelected && holding.has(node.id);
9663
9964
  const checkState = checkable ? getCheckState(node) : "unchecked";
9664
9965
  return /* @__PURE__ */ jsxs("div", { role: "treeitem", "aria-expanded": hasChildren ? isExpanded : void 0, "aria-selected": selectable ? isSelected : void 0, children: [
9665
9966
  /* @__PURE__ */ jsxs(
@@ -9677,7 +9978,7 @@ function TreeNodeRow({
9677
9978
  isSelected ? "bg-[var(--ds-tree-active-bg)] text-[var(--ds-tree-active-text)] font-medium border-[var(--ds-accent-ink)]" : "border-transparent text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)] hover:text-[var(--ds-text-primary)]",
9678
9979
  // A folder holding the selection, as SidebarNav draws a parent of the current page (Sprint 25.16 A18): no
9679
9980
  // fill, so it reads the plain tokens, never the active set (pill's on-primary text would vanish here).
9680
- holdsSelection && "font-medium",
9981
+ holdsSelection2 && "font-medium",
9681
9982
  node.disabled && "opacity-disabled pointer-events-none"
9682
9983
  ),
9683
9984
  style: { paddingLeft: `calc(var(--ds-space-3) * ${depth} + var(--ds-space-2))` },
@@ -9704,7 +10005,7 @@ function TreeNodeRow({
9704
10005
  {
9705
10006
  name: "chevron-right",
9706
10007
  size: 14,
9707
- className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : holdsSelection ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
10008
+ className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : holdsSelection2 ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
9708
10009
  }
9709
10010
  )
9710
10011
  }
@@ -9720,7 +10021,7 @@ function TreeNodeRow({
9720
10021
  }
9721
10022
  }
9722
10023
  ),
9723
- node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : holdsSelection ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)]") }),
10024
+ node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : holdsSelection2 ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)]") }),
9724
10025
  /* @__PURE__ */ jsx(TruncLabel2, { children: node.label })
9725
10026
  ]
9726
10027
  }
@@ -10694,9 +10995,12 @@ var StackedList = forwardRef(function StackedList2({
10694
10995
  pager
10695
10996
  }, ref) {
10696
10997
  useScrollsInside();
10998
+ useRunsEdgeToEdge();
10697
10999
  const isPhone = useBreakpoint("sm");
10698
11000
  const inCard = useContext(CardSurfaceCtx);
10699
- const inPane = !!useContext(SplitPaneCtx);
11001
+ const pane = useContext(SplitPaneCtx);
11002
+ const panePadded = useContext(PanePaddedCtx);
11003
+ const inPane = !!pane && !panePadded;
10700
11004
  const articles = variant === "articles";
10701
11005
  useWholeListCheck("StackedList", items.length, pager);
10702
11006
  const shown = pagerPart(items, pager);
@@ -11955,6 +12259,7 @@ function Gantt({
11955
12259
  className
11956
12260
  }) {
11957
12261
  useScrollsInside();
12262
+ useRunsEdgeToEdge();
11958
12263
  const [zoomState, setZoomState] = useState(defaultZoom);
11959
12264
  const zoom = zoomProp ?? zoomState;
11960
12265
  const changeZoom = (next) => {
@@ -13261,7 +13566,8 @@ function ScrollArea({
13261
13566
  orientation = "vertical",
13262
13567
  maxHeight,
13263
13568
  maxWidth,
13264
- "aria-label": ariaLabel = "Scrollable content"
13569
+ "aria-label": ariaLabel = "Scrollable content",
13570
+ flush = false
13265
13571
  }) {
13266
13572
  const viewportRef = useRef(null);
13267
13573
  const [viewport, setViewport] = useState(null);
@@ -13362,6 +13668,8 @@ function ScrollArea({
13362
13668
  className: cn(
13363
13669
  // the frame's corners, so the inset ring follows them rather than being cut by them (as the Table's region)
13364
13670
  "h-full w-full scroll-p-[4px] rounded-[inherit]",
13671
+ // room for an outline at its edges (FOCUS_ROOM), unless the content insets itself
13672
+ !flush && "p-[4px]",
13365
13673
  FOCUS_INSET,
13366
13674
  orientation === "vertical" && "overflow-y-auto overflow-x-hidden",
13367
13675
  orientation === "horizontal" && "overflow-x-auto overflow-y-hidden",
@@ -13511,7 +13819,7 @@ var Sidebar = forwardRef(function Sidebar2({
13511
13819
  children: header
13512
13820
  }
13513
13821
  ),
13514
- /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children }),
13822
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", flush: true, children }),
13515
13823
  showCollapse && (() => {
13516
13824
  const isSm = navSize === "sm";
13517
13825
  const collapseButton = /* @__PURE__ */ jsxs(
@@ -14419,6 +14727,16 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
14419
14727
  clearTimers.current.add(timer);
14420
14728
  }, 0);
14421
14729
  }, []);
14730
+ const barRooms = useRef(/* @__PURE__ */ new Map());
14731
+ const [barRoom, setBarRoom] = useState(0);
14732
+ const bulkBar = useMemo(() => ({
14733
+ room: (bar, room) => {
14734
+ if (room > 0) barRooms.current.set(bar, room);
14735
+ else barRooms.current.delete(bar);
14736
+ setBarRoom(Math.max(0, ...barRooms.current.values()));
14737
+ },
14738
+ say: (text) => announce({ id: "bulk-bar", message: text, variant: "default", duration: 0, shown: false, version: 0 })
14739
+ }), [announce]);
14422
14740
  useEffect(() => () => {
14423
14741
  if (heardTimer.current) clearTimeout(heardTimer.current);
14424
14742
  heardTimer.current = void 0;
@@ -14606,8 +14924,10 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
14606
14924
  const waiting = list2.length - shown.length;
14607
14925
  const isTop = position.startsWith("top");
14608
14926
  const hasBottomNav = isMobile && bottomNavs > 0;
14927
+ const navFoot = "var(--ds-space-12) + var(--ds-space-2) + env(safe-area-inset-bottom)";
14928
+ const stackBottom = barRoom > 0 && (isMobile || !isTop) ? hasBottomNav ? `calc(${navFoot} + ${barRoom}px)` : isMobile ? `calc(env(safe-area-inset-bottom) + ${barRoom}px)` : `max(var(${TOAST_INSET_VARS[position]}), calc(env(safe-area-inset-bottom) + ${barRoom}px))` : hasBottomNav ? `calc(${navFoot} + var(--ds-space-4))` : void 0;
14609
14929
  return /* @__PURE__ */ jsx(ToastContext.Provider, { value: api, children: /* @__PURE__ */ jsxs(ToastLedgerCtx.Provider, { value: ledger, children: [
14610
- /* @__PURE__ */ jsx(BottomNavPresenceCtx.Provider, { value: registerBottomNav, children }),
14930
+ /* @__PURE__ */ jsx(BottomNavPresenceCtx.Provider, { value: registerBottomNav, children: /* @__PURE__ */ jsx(BulkBarPresenceCtx, { value: bulkBar, children }) }),
14611
14931
  /* @__PURE__ */ jsx("div", { className: "sr-only", "aria-live": "polite", "data-toast-announcer": "polite", children: heard.filter((h) => !h.assertive).map((h) => /* @__PURE__ */ jsx("p", { children: h.text }, h.id)) }),
14612
14932
  /* @__PURE__ */ jsx("div", { className: "sr-only", "aria-live": "assertive", "data-toast-announcer": "assertive", children: heard.filter((h) => h.assertive).map((h) => /* @__PURE__ */ jsx("p", { children: h.text }, h.id)) }),
14613
14933
  shown.length > 0 && createPortal(
@@ -14639,7 +14959,7 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
14639
14959
  isTop ? "flex-col" : "flex-col-reverse",
14640
14960
  isMobile ? cn("left-ds-4 right-ds-4", !hasBottomNav && "bottom-ds-4") : TOAST_POSITION_CLASSES[position]
14641
14961
  ),
14642
- style: hasBottomNav ? { bottom: "calc(var(--ds-space-12) + var(--ds-space-2) + var(--ds-space-4) + env(safe-area-inset-bottom))" } : void 0,
14962
+ style: stackBottom ? { bottom: stackBottom } : void 0,
14643
14963
  children: [
14644
14964
  shown.map((t) => /* @__PURE__ */ jsx("div", { "data-toast-id": t.id, className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
14645
14965
  Toast,
@@ -15085,6 +15405,7 @@ var PageContainer = forwardRef(function PageContainer2({
15085
15405
  {
15086
15406
  ref: setRoot,
15087
15407
  "data-page-container": wrappedHeader ? "" : void 0,
15408
+ "data-page-column": "",
15088
15409
  "data-width": dataWidth,
15089
15410
  className: cn(
15090
15411
  "w-full",
@@ -15116,7 +15437,7 @@ var PageContainer = forwardRef(function PageContainer2({
15116
15437
  ...floatingHeader ? { paddingRight: "var(--ds-space-3)", paddingLeft: r.sidebarFloating ? 0 : "var(--ds-space-3)" } : {},
15117
15438
  ...overlapActive ? { marginTop: "calc(-1 * var(--ds-overlap, 0px))", position: "relative", zIndex: 1 } : {}
15118
15439
  } : void 0;
15119
- const column = /* @__PURE__ */ jsx(PageContainerContext, { value: { contentMaxWidth: maxWidthValue, placement: "inside", containedBreadcrumbs: false, breadcrumbsInsideHeader: false, noBottomMargin: false, overlap: false, setPinnedHeight, reportHeader, requestContentWidth, insidePaddedColumn: true }, children: /* @__PURE__ */ jsx("div", { ref: columnRef, className: cn(columnClass(contentPadding), bottomPaddingClasses[vPad], className), style: { ...columnStyle, ...launcherPadding }, children: capped(rest) }) });
15440
+ const column = /* @__PURE__ */ jsx(PageContainerContext, { value: { contentMaxWidth: maxWidthValue, placement: "inside", containedBreadcrumbs: false, breadcrumbsInsideHeader: false, noBottomMargin: false, overlap: false, setPinnedHeight, reportHeader, requestContentWidth, insidePaddedColumn: true }, children: /* @__PURE__ */ jsx("div", { ref: columnRef, "data-page-column": "", className: cn(columnClass(contentPadding), bottomPaddingClasses[vPad], className), style: { ...columnStyle, ...launcherPadding }, children: capped(rest) }) });
15120
15441
  return /* @__PURE__ */ jsx(PageActionsCtx, { value: pageActions, children: /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-page-container": "", "data-width": dataWidth, className: "w-full", children: [
15121
15442
  placement === "block" ? /* @__PURE__ */ jsx("div", { style: floatingBlockPadding(r.navbarFloating, r.sidebarFloating, overlapActive), children: /* @__PURE__ */ jsxs("div", { className: FLOATING_BLOCK, children: [
15122
15443
  strip,
@@ -15836,6 +16157,7 @@ function SnappingHeader({
15836
16157
  ([entry]) => {
15837
16158
  if (!entry.isIntersecting && !collapsedRef.current) {
15838
16159
  collapsedRef.current = true;
16160
+ setSpacer(expandedHeightRef.current);
15839
16161
  setCollapsed(true);
15840
16162
  }
15841
16163
  },
@@ -18202,7 +18524,10 @@ var SectionHeading = forwardRef(function SectionHeading2({
18202
18524
  }, ref) {
18203
18525
  const isPhone = useBreakpoint("sm");
18204
18526
  const pane = variant === "pane";
18205
- const inDetail = useContext(SplitPaneCtx) === "detail";
18527
+ const paneKind = useContext(SplitPaneCtx);
18528
+ const inDetail = paneKind === "detail";
18529
+ const panePadded = useContext(PanePaddedCtx);
18530
+ const cancel = pane && panePadded && (paneKind === "list" || paneKind === "detail") ? PANE_HEADING_CANCEL[paneKind] : void 0;
18206
18531
  const editable = !!onTitleChange;
18207
18532
  return /* @__PURE__ */ jsxs(
18208
18533
  "div",
@@ -18211,7 +18536,7 @@ var SectionHeading = forwardRef(function SectionHeading2({
18211
18536
  "data-gs": "section-heading",
18212
18537
  "data-variant": variant,
18213
18538
  className: cn(
18214
- pane ? cn("shrink-0 pt-ds-4 pb-ds-3 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", inDetail ? "px-[var(--ds-page-gutter)]" : "px-ds-4") : "mb-[var(--ds-heading-gap)]",
18539
+ pane ? cn("shrink-0 pt-ds-4 pb-ds-3 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", inDetail ? "px-[var(--ds-page-gutter)]" : "px-ds-4", cancel) : "mb-[var(--ds-heading-gap)]",
18215
18540
  !pane && bordered && "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] pb-ds-4",
18216
18541
  className
18217
18542
  ),