gridsmith-ui 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +8 -6
  2. package/dist/Breadcrumbs-CGS8GKl-.d.ts +33 -0
  3. package/dist/MentionList-CoNBRFGR.d.ts +8 -0
  4. package/dist/charts.d.ts +42 -1
  5. package/dist/charts.js +320 -89
  6. package/dist/charts.js.map +1 -1
  7. package/dist/chat.js +5 -4
  8. package/dist/chat.js.map +1 -1
  9. package/dist/chunk-2YSEME33.js +118 -0
  10. package/dist/chunk-2YSEME33.js.map +1 -0
  11. package/dist/{chunk-6PL7FXYH.js → chunk-3CUKJ4VP.js} +321 -11
  12. package/dist/chunk-3CUKJ4VP.js.map +1 -0
  13. package/dist/{chunk-SBTBMAIU.js → chunk-FHMCAOAH.js} +6 -6
  14. package/dist/{chunk-SBTBMAIU.js.map → chunk-FHMCAOAH.js.map} +1 -1
  15. package/dist/chunk-HP7WUZPK.js +80 -0
  16. package/dist/chunk-HP7WUZPK.js.map +1 -0
  17. package/dist/{chunk-4LDYR7QP.js → chunk-HYMXAIXN.js} +53 -13
  18. package/dist/chunk-HYMXAIXN.js.map +1 -0
  19. package/dist/{chunk-7TOJ4G7S.js → chunk-HZIP4EJI.js} +14 -9
  20. package/dist/chunk-HZIP4EJI.js.map +1 -0
  21. package/dist/{chunk-RT7RYGC3.js → chunk-JXANCXK6.js} +4 -39
  22. package/dist/chunk-JXANCXK6.js.map +1 -0
  23. package/dist/{chunk-CXMV7SXJ.js → chunk-MD2EFMES.js} +5 -77
  24. package/dist/chunk-MD2EFMES.js.map +1 -0
  25. package/dist/{chunk-IVCVNAXG.js → chunk-OTCEJN64.js} +3 -3
  26. package/dist/{chunk-IVCVNAXG.js.map → chunk-OTCEJN64.js.map} +1 -1
  27. package/dist/{chunk-EYMGLK4M.js → chunk-QGSCF7PN.js} +7 -7
  28. package/dist/chunk-QGSCF7PN.js.map +1 -0
  29. package/dist/{chunk-CKWITUSH.js → chunk-QM4SJKWV.js} +15 -5
  30. package/dist/chunk-QM4SJKWV.js.map +1 -0
  31. package/dist/chunk-RWKCAKN3.js +209 -0
  32. package/dist/chunk-RWKCAKN3.js.map +1 -0
  33. package/dist/{chunk-ICNWPNMM.js → chunk-W7GCEJEH.js} +11 -23
  34. package/dist/chunk-W7GCEJEH.js.map +1 -0
  35. package/dist/chunk-WOVYHFUD.js +50 -0
  36. package/dist/chunk-WOVYHFUD.js.map +1 -0
  37. package/dist/{chunk-NCIZQYXQ.js → chunk-X2HEV7FB.js} +33 -3
  38. package/dist/chunk-X2HEV7FB.js.map +1 -0
  39. package/dist/chunk-XVB55M3N.js +42 -0
  40. package/dist/chunk-XVB55M3N.js.map +1 -0
  41. package/dist/data-grid.d.ts +1 -1
  42. package/dist/data-grid.js +14 -12
  43. package/dist/data-grid.js.map +1 -1
  44. package/dist/editor-mentions.d.ts +30 -0
  45. package/dist/editor-mentions.js +160 -0
  46. package/dist/editor-mentions.js.map +1 -0
  47. package/dist/editor.d.ts +23 -3
  48. package/dist/editor.js +59 -9
  49. package/dist/editor.js.map +1 -1
  50. package/dist/{feather-2JFSFLXN.js → feather-W26ERBQV.js} +11 -3
  51. package/dist/feather-W26ERBQV.js.map +1 -0
  52. package/dist/{heroicons-4AQ4YBVG.js → heroicons-MY43466C.js} +21 -7
  53. package/dist/heroicons-MY43466C.js.map +1 -0
  54. package/dist/icons.d.ts +11 -4
  55. package/dist/icons.js +1 -1
  56. package/dist/index.d.ts +348 -65
  57. package/dist/index.js +886 -576
  58. package/dist/index.js.map +1 -1
  59. package/dist/kanban.js +26 -8
  60. package/dist/kanban.js.map +1 -1
  61. package/dist/{lucide-RZC2FEMS.js → lucide-CMPVM3PS.js} +11 -3
  62. package/dist/lucide-CMPVM3PS.js.map +1 -0
  63. package/dist/{phosphor-CEN25FLM.js → phosphor-RMHZOW2O.js} +11 -3
  64. package/dist/phosphor-RMHZOW2O.js.map +1 -0
  65. package/dist/resizable.d.ts +16 -1
  66. package/dist/resizable.js +91 -23
  67. package/dist/resizable.js.map +1 -1
  68. package/dist/roots.css +15 -0
  69. package/dist/{tabler-YXXC7Y6B.js → tabler-MJVEYHA5.js} +11 -3
  70. package/dist/tabler-MJVEYHA5.js.map +1 -0
  71. package/dist/{use-pagination-DiJo0aW5.d.ts → use-pagination-BnKOnBdz.d.ts} +3 -0
  72. package/dist/virtualized.d.ts +1 -1
  73. package/dist/virtualized.js +8 -6
  74. package/dist/virtualized.js.map +1 -1
  75. package/package.json +29 -21
  76. package/dist/chunk-4LDYR7QP.js.map +0 -1
  77. package/dist/chunk-6PL7FXYH.js.map +0 -1
  78. package/dist/chunk-7TOJ4G7S.js.map +0 -1
  79. package/dist/chunk-CKWITUSH.js.map +0 -1
  80. package/dist/chunk-CXMV7SXJ.js.map +0 -1
  81. package/dist/chunk-EYMGLK4M.js.map +0 -1
  82. package/dist/chunk-ICNWPNMM.js.map +0 -1
  83. package/dist/chunk-NCIZQYXQ.js.map +0 -1
  84. package/dist/chunk-RT7RYGC3.js.map +0 -1
  85. package/dist/feather-2JFSFLXN.js.map +0 -1
  86. package/dist/heroicons-4AQ4YBVG.js.map +0 -1
  87. package/dist/lucide-RZC2FEMS.js.map +0 -1
  88. package/dist/phosphor-CEN25FLM.js.map +0 -1
  89. package/dist/tabler-YXXC7Y6B.js.map +0 -1
package/dist/resizable.js CHANGED
@@ -1,12 +1,16 @@
1
- import { useCompact, useElementWidth, useBelow, useAppShell, Drawer } from './chunk-6PL7FXYH.js';
2
- import { Button } from './chunk-7TOJ4G7S.js';
1
+ import { useCompact, useElementWidth, useBelow, crumbGoes, useAppShell, Breadcrumbs, Drawer } from './chunk-3CUKJ4VP.js';
2
+ import { Button } from './chunk-HZIP4EJI.js';
3
3
  import { useBreakpoint } from './chunk-CRQ6KCRD.js';
4
- import { isTabStop, tabStops, rememberFocus } from './chunk-RT7RYGC3.js';
5
- import { SurfaceBoundary } from './chunk-CKWITUSH.js';
6
- import './chunk-CXMV7SXJ.js';
4
+ import './chunk-XVB55M3N.js';
5
+ import { useKeyboardScroll, FOCUS_INSET } from './chunk-WOVYHFUD.js';
6
+ import { useFillHeight, FillContext } from './chunk-2YSEME33.js';
7
+ import { SurfaceBoundary } from './chunk-QM4SJKWV.js';
8
+ import { isTabStop, tabStops, rememberFocus } from './chunk-JXANCXK6.js';
9
+ import './chunk-MD2EFMES.js';
7
10
  import './chunk-7Q46JXSK.js';
11
+ import { Icon } from './chunk-HYMXAIXN.js';
12
+ import './chunk-HP7WUZPK.js';
8
13
  import './chunk-WH2FUFAC.js';
9
- import { Icon } from './chunk-4LDYR7QP.js';
10
14
  import { cn } from './chunk-M2QRNBDQ.js';
11
15
  import { Group, Panel, Separator } from 'react-resizable-panels';
12
16
  import { createContext, useContext, useRef, useState, useCallback, useLayoutEffect } from 'react';
@@ -39,6 +43,49 @@ function ResizablePanelGroup({
39
43
  function ResizablePanel({ className, ...props }) {
40
44
  return /* @__PURE__ */ jsx(Panel, { className: cn("", className), ...props });
41
45
  }
46
+ function visibleRange(el) {
47
+ const box = el.getBoundingClientRect();
48
+ let top = Math.max(box.top, 0);
49
+ let bottom = Math.min(box.bottom, window.innerHeight);
50
+ for (let node = el.parentElement; node; node = node.parentElement) {
51
+ if (!/(auto|scroll|hidden|clip|overlay)/.test(getComputedStyle(node).overflowY)) continue;
52
+ const r = node.getBoundingClientRect();
53
+ top = Math.max(top, r.top + node.clientTop);
54
+ bottom = Math.min(bottom, r.top + node.clientTop + node.clientHeight);
55
+ }
56
+ return { top, bottom };
57
+ }
58
+ function useGripInView(gripRef, enabled) {
59
+ useLayoutEffect(() => {
60
+ const grip = gripRef.current;
61
+ const handle = grip?.parentElement;
62
+ if (!enabled || !grip || !handle || typeof ResizeObserver === "undefined") return;
63
+ let frame = 0;
64
+ const place = () => {
65
+ frame = 0;
66
+ const box = handle.getBoundingClientRect();
67
+ const { top, bottom } = visibleRange(handle);
68
+ const room = (box.height - grip.offsetHeight) / 2;
69
+ const offset = bottom > top ? Math.max(-room, Math.min(room, (top + bottom) / 2 - (box.top + box.height / 2))) : 0;
70
+ grip.style.transform = Math.abs(offset) >= 1 ? `translateY(${Math.round(offset)}px)` : "";
71
+ };
72
+ const schedule = () => {
73
+ if (!frame) frame = requestAnimationFrame(place);
74
+ };
75
+ place();
76
+ const ro = new ResizeObserver(schedule);
77
+ ro.observe(handle);
78
+ document.addEventListener("scroll", schedule, { capture: true, passive: true });
79
+ window.addEventListener("resize", schedule);
80
+ return () => {
81
+ ro.disconnect();
82
+ document.removeEventListener("scroll", schedule, { capture: true });
83
+ window.removeEventListener("resize", schedule);
84
+ if (frame) cancelAnimationFrame(frame);
85
+ grip.style.transform = "";
86
+ };
87
+ }, [gripRef, enabled]);
88
+ }
42
89
  function ResizableHandle({
43
90
  withHandle,
44
91
  className,
@@ -47,6 +94,8 @@ function ResizableHandle({
47
94
  const direction = useContext(DirectionCtx);
48
95
  const isMobile = useContext(MobileCtx);
49
96
  const isVertical = direction === "vertical";
97
+ const gripRef = useRef(null);
98
+ useGripInView(gripRef, !!withHandle && !isVertical);
50
99
  return /* @__PURE__ */ jsx(
51
100
  Separator,
52
101
  {
@@ -68,6 +117,7 @@ function ResizableHandle({
68
117
  children: withHandle && /* @__PURE__ */ jsx(
69
118
  "div",
70
119
  {
120
+ ref: gripRef,
71
121
  className: cn(
72
122
  "z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]",
73
123
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
@@ -102,6 +152,7 @@ function SplitView({
102
152
  closedDetail = "shown",
103
153
  closeLabel = "Close",
104
154
  backLabel = "Back",
155
+ detailPath,
105
156
  listWidth = 35,
106
157
  listMinWidth = 25,
107
158
  asideWidth = 25,
@@ -130,6 +181,7 @@ function SplitView({
130
181
  if (compact && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);
131
182
  const asideOpen = asideCollapsed && asideWantsOpen;
132
183
  const region = ariaLabel ? { role: "region", "aria-label": ariaLabel } : {};
184
+ const path = detailPath && detailPath.length > 0 ? detailPath.map((crumb, i) => i === detailPath.length - 1 && !crumbGoes(crumb) && onDetailClose ? { ...crumb, onClick: onDetailClose } : crumb) : null;
133
185
  const isFill = frame === "fill";
134
186
  const listHolds = useRef({ framed: 0, scrolls: 0 });
135
187
  const [framesItself, setFramesItself] = useState(false);
@@ -140,7 +192,20 @@ function SplitView({
140
192
  }, []);
141
193
  const onCanvas = isFill || framesItself;
142
194
  const shell = useAppShell();
143
- const fillStyle = isFill && shell?.hasFooter ? { height: "var(--ds-main-height, 100%)" } : void 0;
195
+ const pageFill = useFillHeight(rootRef, !isFill);
196
+ const [listScroll, setListScroll] = useState(null);
197
+ const [detailScroll, setDetailScroll] = useState(null);
198
+ const [asideScroll, setAsideScroll] = useState(null);
199
+ const [stackedListScroll, setStackedListScroll] = useState(null);
200
+ const [stackedDetailScroll, setStackedDetailScroll] = useState(null);
201
+ const listName = ariaLabel ? `${ariaLabel} list` : "List";
202
+ const itemName = ariaLabel ? `${ariaLabel} item` : "Item";
203
+ useKeyboardScroll(listScroll, listName, !compact);
204
+ useKeyboardScroll(detailScroll, itemName, !compact, true);
205
+ useKeyboardScroll(asideScroll, asideTitle, !compact);
206
+ useKeyboardScroll(stackedListScroll, listName, compact);
207
+ useKeyboardScroll(stackedDetailScroll, itemName, compact, true);
208
+ const fillStyle = isFill && shell?.hasFooter ? { height: "var(--ds-main-height, 100%)" } : pageFill != null ? { height: pageFill } : void 0;
144
209
  const itemSurface = !onCanvas ? void 0 : isFill ? "bg-[var(--ds-bg-surface)]" : cn("bg-[var(--ds-bg-surface)] rounded-[var(--ds-radius-md)] overflow-hidden", bordered && "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]");
145
210
  const surface = cn(
146
211
  "h-full min-h-0 w-full",
@@ -149,8 +214,8 @@ function SplitView({
149
214
  bordered && !onCanvas && "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden",
150
215
  className
151
216
  );
152
- const listContent = /* @__PURE__ */ jsx(SurfaceBoundary, { pane: true, framer: reportToList, children: list });
153
- const detailContent = /* @__PURE__ */ jsx(SurfaceBoundary, { pane: true, children: detail });
217
+ const listContent = /* @__PURE__ */ jsx(SurfaceBoundary, { pane: "list", framer: reportToList, children: list });
218
+ const detailContent = /* @__PURE__ */ jsx(SurfaceBoundary, { pane: "detail", children: detail });
154
219
  const [listPct, setListPct] = useState(listWidth);
155
220
  const paneRef = useRef(null);
156
221
  const shown = useRef(null);
@@ -186,26 +251,29 @@ function SplitView({
186
251
  if (compact) {
187
252
  const showDetail2 = detailMode === "stack" && detailOpen;
188
253
  const phoneAside = showDetail2 && !!aside;
189
- return /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-split-view": showDetail2 ? "detail" : "list", "data-frame": frame, ...region, className: cn(surface, "flex flex-col"), style: fillStyle, children: [
254
+ return /* @__PURE__ */ jsx(FillContext, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-split-view": showDetail2 ? "detail" : "list", "data-frame": frame, "data-fill": pageFill != null ? "" : void 0, ...region, className: cn(surface, "flex flex-col"), style: fillStyle, children: [
190
255
  showDetail2 && /* @__PURE__ */ jsxs("div", { className: cn("flex-1 min-h-0 flex flex-col", itemSurface), children: [
191
- /* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center justify-between gap-ds-2 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: [
192
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "arrow-left", size: 14 }), onClick: onDetailClose, children: backLabel }),
256
+ /* @__PURE__ */ jsxs("div", { className: cn("shrink-0 flex items-center justify-between gap-ds-2 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", path ? "px-[var(--ds-page-gutter)]" : "px-ds-3"), children: [
257
+ path ? /* @__PURE__ */ jsx(Breadcrumbs, { items: path, maxItems: 3, "aria-label": "Path", className: "min-w-0" }) : /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "arrow-left", size: 14 }), onClick: onDetailClose, children: backLabel }),
193
258
  phoneAside && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "info", size: 14 }), onClick: () => setAsideWantsOpen(true), "aria-expanded": asideWantsOpen, children: asideTitle })
194
259
  ] }),
195
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: detailContent })
260
+ /* @__PURE__ */ jsx("div", { ref: setStackedDetailScroll, className: cn("flex-1 min-h-0 overflow-y-auto", FOCUS_INSET), children: detailContent })
196
261
  ] }),
197
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", hidden: showDetail2 || void 0, children: listContent }),
262
+ /* @__PURE__ */ jsx("div", { ref: setStackedListScroll, className: cn("flex-1 min-h-0 overflow-y-auto", FOCUS_INSET), hidden: showDetail2 || void 0, children: listContent }),
198
263
  phoneAside && /* @__PURE__ */ jsx(Drawer, { open: asideWantsOpen, onClose: () => setAsideWantsOpen(false), title: asideTitle, position: "right", children: aside })
199
- ] });
264
+ ] }) });
200
265
  }
201
266
  const asideButton = showAside && asideCollapsed ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "info", size: 14 }), onClick: () => setAsideWantsOpen(true), "aria-expanded": asideOpen, children: asideTitle }) : null;
202
267
  const closeButton = hiding && onDetailClose ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": closeLabel, onClick: onDetailClose, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 }) }) : null;
203
- const paneBar = asideButton || closeButton ? /* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center justify-end gap-ds-1 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: [
204
- asideButton,
205
- closeButton
268
+ const paneBar = path || asideButton || closeButton ? /* @__PURE__ */ jsxs("div", { className: cn("shrink-0 flex items-center gap-ds-1 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", path ? "justify-between px-[var(--ds-page-gutter)]" : "justify-end px-ds-3"), children: [
269
+ path && /* @__PURE__ */ jsx(Breadcrumbs, { items: path, "aria-label": "Path", className: "min-w-0" }),
270
+ (asideButton || closeButton) && /* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center gap-ds-1", children: [
271
+ asideButton,
272
+ closeButton
273
+ ] })
206
274
  ] }) : null;
207
275
  const showDetail = !hiding || detailOpen;
208
- return /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-split-view": hiding && !detailOpen ? "list" : "split", "data-frame": frame, ...region, className: surface, style: fillStyle, children: [
276
+ return /* @__PURE__ */ jsx(FillContext, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: rootRef, "data-split-view": hiding && !detailOpen ? "list" : "split", "data-frame": frame, "data-fill": pageFill != null ? "" : void 0, ...region, className: surface, style: fillStyle, children: [
209
277
  /* @__PURE__ */ jsxs(
210
278
  ResizablePanelGroup,
211
279
  {
@@ -217,25 +285,25 @@ function SplitView({
217
285
  if (hiding && layout.detail != null && layout.list != null) setListPct(layout.list);
218
286
  },
219
287
  children: [
220
- /* @__PURE__ */ jsx(ResizablePanel, { id: "list", defaultSize: `${hiding ? detailOpen ? listPct : 100 : listWidth}%`, minSize: `${listMinWidth}%`, children: /* @__PURE__ */ jsx("div", { "data-pane": "list", className: "h-full min-h-0 overflow-y-auto", onFocus: hiding ? (e) => {
288
+ /* @__PURE__ */ jsx(ResizablePanel, { id: "list", defaultSize: `${hiding ? detailOpen ? listPct : 100 : listWidth}%`, minSize: `${listMinWidth}%`, children: /* @__PURE__ */ jsx("div", { ref: setListScroll, "data-pane": "list", className: cn("h-full min-h-0 overflow-y-auto", FOCUS_INSET), onFocus: hiding ? (e) => {
221
289
  lastInList.current = e.target;
222
290
  } : void 0, children: listContent }) }),
223
291
  showDetail && /* @__PURE__ */ jsxs(Fragment, { children: [
224
292
  /* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
225
293
  /* @__PURE__ */ jsx(ResizablePanel, { id: "detail", minSize: "30%", children: /* @__PURE__ */ jsxs("div", { ref: paneRef, "data-pane": "detail", className: cn("h-full min-h-0 flex flex-col", itemSurface), onKeyDown: hiding ? onPaneKeyDown : void 0, children: [
226
294
  paneBar,
227
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: detailContent })
295
+ /* @__PURE__ */ jsx("div", { ref: setDetailScroll, className: cn("flex-1 min-h-0 overflow-y-auto", FOCUS_INSET), children: detailContent })
228
296
  ] }) })
229
297
  ] }),
230
298
  showAside && !asideCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
231
299
  /* @__PURE__ */ jsx(ResizableHandle, { withHandle: true }),
232
- /* @__PURE__ */ jsx(ResizablePanel, { id: "aside", defaultSize: `${asideWidth}%`, minSize: "15%", children: /* @__PURE__ */ jsx("div", { "data-pane": "aside", className: cn("h-full min-h-0 overflow-y-auto py-ds-5 px-[var(--ds-page-gutter)]", itemSurface), children: /* @__PURE__ */ jsx(SurfaceBoundary, { pane: true, children: aside }) }) })
300
+ /* @__PURE__ */ jsx(ResizablePanel, { id: "aside", defaultSize: `${asideWidth}%`, minSize: "15%", children: /* @__PURE__ */ jsx("div", { ref: setAsideScroll, "data-pane": "aside", className: cn("h-full min-h-0 overflow-y-auto py-ds-5 px-[var(--ds-page-gutter)]", itemSurface, FOCUS_INSET), children: /* @__PURE__ */ jsx(SurfaceBoundary, { pane: "aside", children: aside }) }) })
233
301
  ] })
234
302
  ]
235
303
  }
236
304
  ),
237
305
  showAside && asideCollapsed && /* @__PURE__ */ jsx(Drawer, { open: asideOpen, onClose: () => setAsideWantsOpen(false), title: asideTitle, position: "right", children: aside })
238
- ] });
306
+ ] }) });
239
307
  }
240
308
 
241
309
  export { ResizableHandle, ResizablePanel, ResizablePanelGroup, SplitView };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx","../../../showcase/src/components/SplitView.tsx"],"names":["PanelGroup","PanelResizeHandle","jsx","showDetail"],"mappings":"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","file":"resizable.js","sourcesContent":["import {\n Panel,\n Group as PanelGroup,\n Separator as PanelResizeHandle,\n} from \"react-resizable-panels\";\nimport { createContext, useContext, type ComponentProps } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { Icon } from \"../lib/icons\";\n\ntype PanelGroupProps = ComponentProps<typeof PanelGroup>;\n\ntype Direction = \"horizontal\" | \"vertical\";\nconst DirectionCtx = createContext<Direction>(\"horizontal\");\nconst MobileCtx = createContext(false);\n\nexport interface ResizablePanelGroupProps\n extends Omit<PanelGroupProps, \"className\" | \"orientation\"> {\n direction?: Direction;\n stackOnMobile?: boolean;\n className?: string;\n /** Map of panel id → percentage (0–100). Must be an object, never an array. Panels need matching id props. */\n defaultLayout?: { [panelId: string]: number };\n /** Called after resize ends. Receives { [panelId]: number }, not number[]. */\n onLayoutChanged?: (layout: { [panelId: string]: number }) => void;\n}\n\nexport function ResizablePanelGroup({\n className,\n direction = \"horizontal\",\n stackOnMobile = true,\n ...props\n}: ResizablePanelGroupProps) {\n const isMobile = useBreakpoint(\"sm\");\n const shouldStack = stackOnMobile && isMobile && direction === \"horizontal\";\n const effectiveDirection = shouldStack ? \"vertical\" : direction;\n\n return (\n <DirectionCtx.Provider value={effectiveDirection}>\n <MobileCtx.Provider value={isMobile}>\n <PanelGroup\n className={cn(\n \"flex h-full w-full\",\n effectiveDirection === \"vertical\" && \"flex-col\",\n className,\n )}\n orientation={effectiveDirection}\n {...props}\n />\n </MobileCtx.Provider>\n </DirectionCtx.Provider>\n );\n}\n\ntype PanelProps = ComponentProps<typeof Panel>;\n\nexport interface ResizablePanelProps extends Omit<PanelProps, \"className\"> {\n className?: string;\n id?: string;\n /** number = px. \"30%\" or \"30\" = percent. \"28rem\" / \"400px\" also valid. */\n defaultSize?: number | string;\n minSize?: number | string;\n maxSize?: number | string;\n collapsible?: boolean;\n}\n\nexport function ResizablePanel({ className, ...props }: ResizablePanelProps) {\n return <Panel className={cn(\"\", className)} {...props} />;\n}\n\ntype PanelResizeHandleProps = ComponentProps<typeof PanelResizeHandle>;\n\nexport interface ResizableHandleProps\n extends Omit<PanelResizeHandleProps, \"className\"> {\n withHandle?: boolean;\n className?: string;\n}\n\nexport function ResizableHandle({\n withHandle,\n className,\n ...props\n}: ResizableHandleProps) {\n const direction = useContext(DirectionCtx);\n const isMobile = useContext(MobileCtx);\n const isVertical = direction === \"vertical\";\n\n return (\n <PanelResizeHandle\n className={cn(\n \"relative flex items-center justify-center bg-[var(--ds-border-default)]\",\n isVertical\n ? cn(\n \"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']\",\n isMobile ? \"after:-top-3 after:-bottom-3\" : \"after:-top-1 after:-bottom-1\"\n )\n : cn(\n \"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']\",\n isMobile ? \"after:-left-3 after:-right-3\" : \"after:-left-1 after:-right-1\"\n ),\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]\",\n \"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]\",\n className,\n )}\n {...props}\n >\n {withHandle && (\n <div\n className={cn(\n \"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"bg-[var(--ds-bg-surface)]\",\n isVertical\n ? (isMobile ? \"h-4 w-8\" : \"h-3 w-4\")\n : (isMobile ? \"h-8 w-4\" : \"h-4 w-3\"),\n )}\n >\n <Icon\n name=\"grip-vertical\"\n size={isMobile ? 12 : 10}\n className={cn(\n \"text-[var(--ds-text-muted)]\",\n isVertical && \"rotate-90\",\n )}\n />\n </div>\n )}\n </PanelResizeHandle>\n );\n}\n","import { useCallback, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBelow, useCompact, useElementWidth } from \"../lib/use-compact\";\nimport { ResizablePanelGroup, ResizablePanel, ResizableHandle } from \"./ResizablePanels\";\nimport { Button } from \"./Button\";\nimport { Drawer } from \"./Drawer\";\nimport { Icon } from \"../lib/icons\";\nimport { useAppShell } from \"./AppShell\";\nimport { SurfaceBoundary, type SplitListReport } from \"../lib/surface-context\";\nimport { isTabStop, rememberFocus, tabStops, type RememberedFocus } from \"../lib/focus\";\n\nexport type SplitViewFrame = \"fill\" | \"page\";\n\n/**\n * How far past a threshold the layout must go before a collapsed part comes back, in px: a classic scrollbar's width\n * (15 px on a Mac with a mouse, 17 on Windows), whose coming and going with the aside moved the layout back and forth\n * across the threshold (round 27 review). No wider: inside the band the answer depends on the way the width came, so a\n * wider band could keep the aside collapsed at a width where it fits.\n */\nconst THRESHOLD_BAND = 17;\n\nexport interface SplitViewProps {\n /** The list (an inbox, a queue): it scrolls on its own. */\n list: ReactNode;\n /** The selected item (a thread, a record): it fills the height and scrolls on its own. */\n detail: ReactNode;\n /** Context beside the detail (a contact, properties). The pane insets it as the Drawer it collapses into does (the page's gutter, Sprint 25.14 A36), so pass content with no padding classes (round 8). Collapses to a toggle that opens it in a Drawer when the layout is narrower than `asideCollapseBelow`. */\n aside?: ReactNode;\n /** Names the aside's toggle and Drawer. */\n asideTitle?: string;\n /**\n * Below `collapseBelow` the list shows alone; with `detailOpen` the detail replaces it, with a Back button that calls\n * `onDetailClose` (detailMode \"stack\"). The page owns the selection, so it owns this flag.\n */\n detailOpen?: boolean;\n onDetailClose?: () => void;\n /** \"stack\" (default): the detail stacks over the list below the collapse width. \"route\": the app navigates to the detail's own route instead, and this renders the list alone there. */\n detailMode?: \"stack\" | \"route\";\n /**\n * \"shown\" (default): above the collapse width the detail pane is always there — an inbox's reading pane may show a\n * placeholder. \"hidden\" (Sprint 25.7, C3): `detailOpen` decides at every width. Closed, the list takes the whole\n * width; open, the pane appears beside it at the width the user last gave it, with a close control that calls\n * `onDetailClose`. For boards, timelines and lists of records. The list stays mounted, so a board or a timeline keeps\n * its scroll and zoom.\n */\n closedDetail?: \"shown\" | \"hidden\";\n /** The open pane's close control, named for a screen reader (closedDetail=\"hidden\"). Default \"Close\". */\n closeLabel?: string;\n backLabel?: string;\n /** Percent of the width the list takes; the divider is draggable. */\n listWidth?: number;\n listMinWidth?: number;\n asideWidth?: number;\n /** Below this width of the layout itself (px) the list and detail stop sitting side by side. */\n collapseBelow?: number;\n /** Below this width of the layout itself (px) the aside becomes a toggle. */\n asideCollapseBelow?: number;\n /**\n * The narrowest the open item's pane may be beside an aside (px). When the list and the aside would leave it less,\n * the aside becomes its toggle and Drawer, so the item keeps the room its content needs: the aside is the secondary\n * content (round 27, R27-13, the owner: \"which information is more important\"). An item that holds a wide table or a\n * card grid may need more: pass it.\n */\n detailMinWidth?: number;\n /** A bordered, rounded surface (inside a page with padding) instead of edge to edge (filling <main>). */\n bordered?: boolean;\n /** \"fill\": the page root, flush to the shell, h-full against main, each pane owns its inset. \"page\" (default): inside a PageContainer under a PageHeader. */\n frame?: SplitViewFrame;\n \"aria-label\"?: string;\n className?: string;\n}\n\n/**\n * The reading-pane composition (Sprint 25.2, R3): one surface with dividers —\n * list, detail and an optional aside — that fills the height it is given (an\n * AppShell's <main> already gives it) and never three cards with gaps. The\n * panels compose ResizablePanelGroup, so the dividers drag. Below the collapse\n * width, measured on the layout itself, the list shows alone and the detail\n * stacks over it (or the app routes to it); the aside collapses to a toggle.\n * The page owns the selection and assembles the contents; keyboard movement\n * through the list is the list's job (StackedList selectedId).\n */\nexport function SplitView({\n list,\n detail,\n aside,\n asideTitle = \"Details\",\n detailOpen = false,\n onDetailClose,\n detailMode = \"stack\",\n closedDetail = \"shown\",\n closeLabel = \"Close\",\n backLabel = \"Back\",\n listWidth = 35,\n listMinWidth = 25,\n asideWidth = 25,\n collapseBelow = 768,\n asideCollapseBelow = 1024,\n detailMinWidth = 480,\n bordered = false,\n frame = \"page\",\n \"aria-label\": ariaLabel,\n className,\n}: SplitViewProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const compact = useCompact(rootRef, collapseBelow, THRESHOLD_BAND);\n const layoutWidth = useElementWidth(rootRef);\n // The panels' shares as the user left them (the review: the defaults were read, so a list dragged wider left the item\n // under its minimum beside the aside); the aside's last share stands in while it is collapsed.\n const [shares, setShares] = useState<{ list?: number; aside?: number }>({});\n const listShare = shares.list ?? listWidth;\n const asideShare = shares.aside ?? asideWidth;\n // the aside yields when the layout is narrow, or when beside it the item would have less than its minimum\n const itemShare = (100 - listShare - asideShare) / 100;\n const itemBesideAside = aside ? layoutWidth * itemShare : 0;\n // the item moves by its share of the scrollbar's width, so its band is that share of the layout's\n const itemSqueezed = useBelow(itemBesideAside, detailMinWidth, THRESHOLD_BAND * Math.max(0, itemShare));\n const asideCollapsed = useBelow(layoutWidth, asideCollapseBelow, THRESHOLD_BAND) || itemSqueezed;\n const [asideWantsOpen, setAsideWantsOpen] = useState(false);\n const hiding = closedDetail === \"hidden\";\n // Hidden: the aside belongs to the open item, so it (its pane, its toggle, its Drawer) goes with the pane, and a\n // Drawer left open does not come back with the next item (render-time state adjustment).\n const showAside = !!aside && (!hiding || detailOpen);\n if (hiding && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n // on a phone the aside's Drawer belongs to the item on screen: Back closes it with the item\n if (compact && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n const asideOpen = asideCollapsed && asideWantsOpen;\n const region = ariaLabel ? { role: \"region\" as const, \"aria-label\": ariaLabel } : {};\n // fill: the page root, flush to the shell on every side (no border, no radius, no padding of its own); h-full\n // resolves against <main> because the shell is a flex column down to it. page: inside a PageContainer under a\n // PageHeader, where `bordered` draws the surface. Each pane owns its own inset either way.\n const isFill = frame === \"fill\";\n // Sprint 25.14 A44 (P32): the list pane's content reports what it is, as a wrapped PageHeader does to its\n // PageContainer: content that draws its own frame or cards (a KanbanBoard, a CardGrid, a Table), or content with no\n // frame of its own that scrolls inside the pane (a StackedList, a Gantt). No frame around what frames itself: when the\n // pane holds only the first kind, the list sits on the canvas with nothing drawn behind it and the open item on the\n // surface, whatever `bordered` says. Anything that scrolls inside keeps the hairline, which shows where it scrolls.\n const listHolds = useRef({ framed: 0, scrolls: 0 });\n const [framesItself, setFramesItself] = useState(false);\n const reportToList = useCallback<SplitListReport>((kind, present) => {\n const held = listHolds.current;\n held[kind] = Math.max(0, held[kind] + (present ? 1 : -1));\n setFramesItself(held.framed > 0 && held.scrolls === 0);\n }, []);\n const onCanvas = isFill || framesItself;\n // In a shell with an app footer the children wrapper has no definite height, so h-full cannot resolve; the shell\n // publishes main's height and fill takes it (the footer then sits below the fold, as it must under a full pane).\n const shell = useAppShell();\n const fillStyle = isFill && shell?.hasFooter ? { height: \"var(--ds-main-height, 100%)\" } : undefined;\n // Edge to edge the list sits on the page's canvas, like every other page, and the open item (its detail and its aside)\n // on the surface (round 27, R27-12, the owner: the whole split on the surface read as a different page). A page frame,\n // bordered or not, stays one surface: a card on the canvas. Beside a list that frames itself, a page frame's open item\n // is that card (rounded, and bordered when the view is), as the page's other cards are; edge to edge it is square.\n const itemSurface = !onCanvas ? undefined : isFill\n ? \"bg-[var(--ds-bg-surface)]\"\n : cn(\"bg-[var(--ds-bg-surface)] rounded-[var(--ds-radius-md)] overflow-hidden\", bordered && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\");\n const surface = cn(\n \"h-full min-h-0 w-full\",\n !onCanvas && \"bg-[var(--ds-bg-surface)]\",\n isFill && \"rounded-none border-0\",\n bordered && !onCanvas && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden\",\n className,\n );\n // each pane is a surface of its own: what a Card around the view, or the list pane, tells content stops at its edge\n const listContent = <SurfaceBoundary pane framer={reportToList}>{list}</SurfaceBoundary>;\n const detailContent = <SurfaceBoundary pane>{detail}</SurfaceBoundary>;\n\n // closedDetail=\"hidden\" (C3): the pane opens beside the list at the width the user last gave it; closing it returns\n // focus to the item the pane shows, or its neighbour if that item is gone (D14(e)): the list's selected item, else\n // the last list item that took focus, checked on each render while the pane is open, so switching items is followed.\n // A selection kept in the URL changes the path, so the item is remembered whatever the route does. With no item\n // (opened on load, or from outside the list) focus goes to the list's first Tab stop. No overlay layer: an\n // assistant opened earlier keeps Escape.\n const [listPct, setListPct] = useState(listWidth);\n const paneRef = useRef<HTMLDivElement>(null);\n const shown = useRef<RememberedFocus | null>(null);\n const lastInList = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n useLayoutEffect(() => {\n if (!hiding) return;\n const listPane = rootRef.current?.querySelector<HTMLElement>('[data-pane=\"list\"]') ?? null;\n if (detailOpen) {\n wasOpen.current = true;\n const selected = listPane?.querySelector<HTMLElement>('[aria-current=\"true\"], [aria-selected=\"true\"]');\n const last = lastInList.current;\n const item = (selected && (isTabStop(selected) ? selected : tabStops(selected)[0]))\n || (last?.isConnected && listPane?.contains(last) ? last : null);\n if (item && item !== shown.current?.el) shown.current = rememberFocus(item, { ignoreRoute: true });\n return;\n }\n if (!wasOpen.current) return;\n wasOpen.current = false;\n const r = shown.current;\n shown.current = null;\n const active = document.activeElement;\n if (active && active !== document.body && active.isConnected) return;\n const first = listPane ? tabStops(listPane)[0] : undefined;\n if (!r?.restore(first)) first?.focus();\n });\n const onPaneKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !onDetailClose) return;\n const t = e.target as HTMLElement;\n // the pane's own DOM only — a portalled popup inside it bubbles here in React's tree — and never from a field\n if (!paneRef.current?.contains(t) || t.closest(\"input, textarea, select, [contenteditable='true']\")) return;\n e.preventDefault();\n onDetailClose();\n };\n\n if (compact) {\n const showDetail = detailMode === \"stack\" && detailOpen;\n // on a phone the item's aside is a toggle beside Back that opens it in a Drawer, as it is on a narrow desktop (the\n // round 27 review: below the collapse width it could not be reached at all)\n const phoneAside = showDetail && !!aside;\n return (\n <div ref={rootRef} data-split-view={showDetail ? \"detail\" : \"list\"} data-frame={frame} {...region} className={cn(surface, \"flex flex-col\")} style={fillStyle}>\n {showDetail && (\n <div className={cn(\"flex-1 min-h-0 flex flex-col\", itemSurface)}>\n <div className=\"shrink-0 flex items-center justify-between gap-ds-2 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"arrow-left\" size={14} />} onClick={onDetailClose}>{backLabel}</Button>\n {phoneAside && <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideWantsOpen}>{asideTitle}</Button>}\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto\">{detailContent}</div>\n </div>\n )}\n {/* Sprint 25.14 A44 (the review of 30 September): the list stays mounted while the stacked detail is shown, as it\n does beside it on a wider screen, so a board keeps its scroll and its report (the view kept its frame\n off only while the board was on screen), and Back finds the list as the user left it */}\n <div className=\"flex-1 min-h-0 overflow-y-auto\" hidden={showDetail || undefined}>{listContent}</div>\n {phoneAside && (\n <Drawer open={asideWantsOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n }\n\n const asideButton = showAside && asideCollapsed\n ? <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideOpen}>{asideTitle}</Button>\n : null;\n const closeButton = hiding && onDetailClose\n ? <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label={closeLabel} onClick={onDetailClose}><Icon name=\"close\" size={14} /></Button>\n : null;\n const paneBar = asideButton || closeButton ? (\n <div className=\"shrink-0 flex items-center justify-end gap-ds-1 px-ds-3 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\">\n {asideButton}\n {closeButton}\n </div>\n ) : null;\n const showDetail = !hiding || detailOpen;\n\n return (\n <div ref={rootRef} data-split-view={hiding && !detailOpen ? \"list\" : \"split\"} data-frame={frame} {...region} className={surface} style={fillStyle}>\n <ResizablePanelGroup\n direction=\"horizontal\"\n stackOnMobile={false}\n className=\"h-full\"\n // the width the user gives the list is kept, so a closed pane reopens at it; the shares decide when the aside yields\n onLayoutChanged={(layout) => {\n setShares((prev) => (prev.list === (layout.list ?? prev.list) && prev.aside === (layout.aside ?? prev.aside) ? prev : { list: layout.list ?? prev.list, aside: layout.aside ?? prev.aside }));\n if (hiding && layout.detail != null && layout.list != null) setListPct(layout.list);\n }}\n >\n <ResizablePanel id=\"list\" defaultSize={`${hiding ? (detailOpen ? listPct : 100) : listWidth}%`} minSize={`${listMinWidth}%`}>\n <div data-pane=\"list\" className=\"h-full min-h-0 overflow-y-auto\" onFocus={hiding ? (e) => { lastInList.current = e.target; } : undefined}>\n {listContent}\n </div>\n </ResizablePanel>\n {showDetail && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"detail\" minSize=\"30%\">\n <div ref={paneRef} data-pane=\"detail\" className={cn(\"h-full min-h-0 flex flex-col\", itemSurface)} onKeyDown={hiding ? onPaneKeyDown : undefined}>\n {paneBar}\n <div className=\"flex-1 min-h-0 overflow-y-auto\">{detailContent}</div>\n </div>\n </ResizablePanel>\n </>\n )}\n {showAside && !asideCollapsed && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"aside\" defaultSize={`${asideWidth}%`} minSize=\"15%\">\n {/* the Drawer's body inset, so the aside's content sits where it will in the Drawer (Sprint 25.14 A36) */}\n <div data-pane=\"aside\" className={cn(\"h-full min-h-0 overflow-y-auto py-ds-5 px-[var(--ds-page-gutter)]\", itemSurface)}><SurfaceBoundary pane>{aside}</SurfaceBoundary></div>\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n {showAside && asideCollapsed && (\n <Drawer open={asideOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../showcase/src/components/ResizablePanels.tsx","../../../showcase/src/components/SplitView.tsx"],"names":["PanelGroup","PanelResizeHandle","useRef","jsx","useLayoutEffect","showDetail"],"mappings":"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","file":"resizable.js","sourcesContent":["import {\n Panel,\n Group as PanelGroup,\n Separator as PanelResizeHandle,\n} from \"react-resizable-panels\";\nimport { createContext, useContext, useLayoutEffect, useRef, type ComponentProps, type RefObject } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { Icon } from \"../lib/icons\";\n\ntype PanelGroupProps = ComponentProps<typeof PanelGroup>;\n\ntype Direction = \"horizontal\" | \"vertical\";\nconst DirectionCtx = createContext<Direction>(\"horizontal\");\nconst MobileCtx = createContext(false);\n\nexport interface ResizablePanelGroupProps\n extends Omit<PanelGroupProps, \"className\" | \"orientation\"> {\n direction?: Direction;\n stackOnMobile?: boolean;\n className?: string;\n /** Map of panel id → percentage (0–100). Must be an object, never an array. Panels need matching id props. */\n defaultLayout?: { [panelId: string]: number };\n /** Called after resize ends. Receives { [panelId]: number }, not number[]. */\n onLayoutChanged?: (layout: { [panelId: string]: number }) => void;\n}\n\nexport function ResizablePanelGroup({\n className,\n direction = \"horizontal\",\n stackOnMobile = true,\n ...props\n}: ResizablePanelGroupProps) {\n const isMobile = useBreakpoint(\"sm\");\n const shouldStack = stackOnMobile && isMobile && direction === \"horizontal\";\n const effectiveDirection = shouldStack ? \"vertical\" : direction;\n\n return (\n <DirectionCtx.Provider value={effectiveDirection}>\n <MobileCtx.Provider value={isMobile}>\n <PanelGroup\n className={cn(\n \"flex h-full w-full\",\n effectiveDirection === \"vertical\" && \"flex-col\",\n className,\n )}\n orientation={effectiveDirection}\n {...props}\n />\n </MobileCtx.Provider>\n </DirectionCtx.Provider>\n );\n}\n\ntype PanelProps = ComponentProps<typeof Panel>;\n\nexport interface ResizablePanelProps extends Omit<PanelProps, \"className\"> {\n className?: string;\n id?: string;\n /** number = px. \"30%\" or \"30\" = percent. \"28rem\" / \"400px\" also valid. */\n defaultSize?: number | string;\n minSize?: number | string;\n maxSize?: number | string;\n collapsible?: boolean;\n}\n\nexport function ResizablePanel({ className, ...props }: ResizablePanelProps) {\n return <Panel className={cn(\"\", className)} {...props} />;\n}\n\ntype PanelResizeHandleProps = ComponentProps<typeof PanelResizeHandle>;\n\n/** The part of an element on screen, top to bottom: inside the window and every box around it that clips or scrolls. */\nfunction visibleRange(el: HTMLElement): { top: number; bottom: number } {\n const box = el.getBoundingClientRect();\n let top = Math.max(box.top, 0);\n let bottom = Math.min(box.bottom, window.innerHeight);\n for (let node = el.parentElement; node; node = node.parentElement) {\n if (!/(auto|scroll|hidden|clip|overlay)/.test(getComputedStyle(node).overflowY)) continue;\n const r = node.getBoundingClientRect();\n top = Math.max(top, r.top + node.clientTop);\n bottom = Math.min(bottom, r.top + node.clientTop + node.clientHeight);\n }\n return { top, bottom };\n}\n\n/**\n * Sprint 25.16 A42 (P31): the grip stays in the part of the divider on screen, at its middle, so a split taller than\n * the screen (a page that grows) never hides it. It moves with any scroll around it and stays inside the divider; it\n * goes back to the middle when the divider turns (stacked on a phone).\n */\nfunction useGripInView(gripRef: RefObject<HTMLDivElement | null>, enabled: boolean) {\n useLayoutEffect(() => {\n const grip = gripRef.current;\n const handle = grip?.parentElement;\n if (!enabled || !grip || !handle || typeof ResizeObserver === \"undefined\") return;\n let frame = 0;\n const place = () => {\n frame = 0;\n const box = handle.getBoundingClientRect();\n const { top, bottom } = visibleRange(handle);\n const room = (box.height - grip.offsetHeight) / 2;\n const offset = bottom > top ? Math.max(-room, Math.min(room, (top + bottom) / 2 - (box.top + box.height / 2))) : 0;\n grip.style.transform = Math.abs(offset) >= 1 ? `translateY(${Math.round(offset)}px)` : \"\";\n };\n const schedule = () => {\n if (!frame) frame = requestAnimationFrame(place);\n };\n place();\n const ro = new ResizeObserver(schedule);\n ro.observe(handle);\n // a scroll anywhere around it: scroll events don't bubble, so the document hears them as they go down\n document.addEventListener(\"scroll\", schedule, { capture: true, passive: true });\n window.addEventListener(\"resize\", schedule);\n return () => {\n ro.disconnect();\n document.removeEventListener(\"scroll\", schedule, { capture: true });\n window.removeEventListener(\"resize\", schedule);\n if (frame) cancelAnimationFrame(frame);\n grip.style.transform = \"\";\n };\n }, [gripRef, enabled]);\n}\n\nexport interface ResizableHandleProps\n extends Omit<PanelResizeHandleProps, \"className\"> {\n withHandle?: boolean;\n className?: string;\n}\n\nexport function ResizableHandle({\n withHandle,\n className,\n ...props\n}: ResizableHandleProps) {\n const direction = useContext(DirectionCtx);\n const isMobile = useContext(MobileCtx);\n const isVertical = direction === \"vertical\";\n const gripRef = useRef<HTMLDivElement>(null);\n useGripInView(gripRef, !!withHandle && !isVertical);\n\n return (\n <PanelResizeHandle\n className={cn(\n \"relative flex items-center justify-center bg-[var(--ds-border-default)]\",\n isVertical\n ? cn(\n \"h-[var(--ds-border-width)] w-full after:absolute after:left-0 after:right-0 after:content-['']\",\n isMobile ? \"after:-top-3 after:-bottom-3\" : \"after:-top-1 after:-bottom-1\"\n )\n : cn(\n \"w-[var(--ds-border-width)] after:absolute after:inset-y-0 after:content-['']\",\n isMobile ? \"after:-left-3 after:-right-3\" : \"after:-left-1 after:-right-1\"\n ),\n \"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]\",\n \"[&[data-resize-handle-state=drag]]:bg-[var(--ds-accent-primary)]\",\n \"[&[data-resize-handle-state=hover]]:bg-[var(--ds-accent-primary)]\",\n className,\n )}\n {...props}\n >\n {withHandle && (\n <div\n ref={gripRef}\n className={cn(\n \"z-10 flex items-center justify-center rounded-[var(--ds-radius-sm)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"bg-[var(--ds-bg-surface)]\",\n isVertical\n ? (isMobile ? \"h-4 w-8\" : \"h-3 w-4\")\n : (isMobile ? \"h-8 w-4\" : \"h-4 w-3\"),\n )}\n >\n <Icon\n name=\"grip-vertical\"\n size={isMobile ? 12 : 10}\n className={cn(\n \"text-[var(--ds-text-muted)]\",\n isVertical && \"rotate-90\",\n )}\n />\n </div>\n )}\n </PanelResizeHandle>\n );\n}\n","import { useCallback, useLayoutEffect, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useBelow, useCompact, useElementWidth } from \"../lib/use-compact\";\nimport { ResizablePanelGroup, ResizablePanel, ResizableHandle } from \"./ResizablePanels\";\nimport { Button } from \"./Button\";\nimport { Drawer } from \"./Drawer\";\nimport { Icon } from \"../lib/icons\";\nimport { Breadcrumbs, crumbGoes, type BreadcrumbItem } from \"./Breadcrumbs\";\nimport { useAppShell } from \"./AppShell\";\nimport { SurfaceBoundary, type SplitListReport } from \"../lib/surface-context\";\nimport { isTabStop, rememberFocus, tabStops, type RememberedFocus } from \"../lib/focus\";\nimport { FillContext, useFillHeight } from \"../lib/use-fill-height\";\nimport { FOCUS_INSET, useKeyboardScroll } from \"../lib/use-keyboard-scroll\";\n\nexport type SplitViewFrame = \"fill\" | \"page\";\n\n/**\n * How far past a threshold the layout must go before a collapsed part comes back, in px: a classic scrollbar's width\n * (15 px on a Mac with a mouse, 17 on Windows), whose coming and going with the aside moved the layout back and forth\n * across the threshold (round 27 review). No wider: inside the band the answer depends on the way the width came, so a\n * wider band could keep the aside collapsed at a width where it fits.\n */\nconst THRESHOLD_BAND = 17;\n\nexport interface SplitViewProps {\n /** The list (an inbox, a queue): it scrolls on its own. */\n list: ReactNode;\n /** The selected item (a thread, a record): it fills the height and scrolls on its own. */\n detail: ReactNode;\n /** Context beside the detail (a contact, properties). The pane insets it as the Drawer it collapses into does (the page's gutter, Sprint 25.14 A36), so pass content with no padding classes (round 8). Collapses to a toggle that opens it in a Drawer when the layout is narrower than `asideCollapseBelow`. */\n aside?: ReactNode;\n /** Names the aside's toggle and Drawer. */\n asideTitle?: string;\n /**\n * Below `collapseBelow` the list shows alone; with `detailOpen` the detail replaces it, with a Back button that calls\n * `onDetailClose` (detailMode \"stack\"). The page owns the selection, so it owns this flag.\n */\n detailOpen?: boolean;\n onDetailClose?: () => void;\n /** \"stack\" (default): the detail stacks over the list below the collapse width. \"route\": the app navigates to the detail's own route instead, and this renders the list alone there. */\n detailMode?: \"stack\" | \"route\";\n /**\n * \"shown\" (default): above the collapse width the detail pane is always there — an inbox's reading pane may show a\n * placeholder. \"hidden\" (Sprint 25.7, C3): `detailOpen` decides at every width. Closed, the list takes the whole\n * width; open, the pane appears beside it at the width the user last gave it, with a close control that calls\n * `onDetailClose`. For boards, timelines and lists of records. The list stays mounted, so a board or a timeline keeps\n * its scroll and zoom.\n */\n closedDetail?: \"shown\" | \"hidden\";\n /** The open pane's close control, named for a screen reader (closedDetail=\"hidden\"). Default \"Close\". */\n closeLabel?: string;\n backLabel?: string;\n /**\n * The open item's path (Sprint 25.16 A19, P11): crumbs from the top of what the list shows down to the open view's\n * parent, never the view itself (the owner's review of 1 October) — a document in a folder tree passes its folders\n * (\"Documents › Architecture\"), a view below an item passes the item as well (\"… › System Design Overview\", above its\n * metadata). The view's own title, its first heading, names it, as a page's title does under its PageHeader's\n * breadcrumbs. The view draws the path above the detail at every width, where the stacked Back would be, and its last\n * crumb is the way back: the stacked Back goes, and the detail draws no back of its own\n * (gs:breadcrumbs-and-back-button-2). A crumb that is a page takes its href and goes through the shell's navigate; an\n * item held in state, or a folder that isn't a page, takes an onClick (select it in the tree); a last crumb with\n * neither closes the detail. On a phone the path keeps its first crumb and its last two, so the parent always shows.\n * One crumb or more; with none, today's Back.\n */\n detailPath?: BreadcrumbItem[];\n /** Percent of the width the list takes; the divider is draggable. */\n listWidth?: number;\n listMinWidth?: number;\n asideWidth?: number;\n /** Below this width of the layout itself (px) the list and detail stop sitting side by side. */\n collapseBelow?: number;\n /** Below this width of the layout itself (px) the aside becomes a toggle. */\n asideCollapseBelow?: number;\n /**\n * The narrowest the open item's pane may be beside an aside (px). When the list and the aside would leave it less,\n * the aside becomes its toggle and Drawer, so the item keeps the room its content needs: the aside is the secondary\n * content (round 27, R27-13, the owner: \"which information is more important\"). An item that holds a wide table or a\n * card grid may need more: pass it.\n */\n detailMinWidth?: number;\n /** A bordered, rounded surface (inside a page with padding) instead of edge to edge (filling <main>). */\n bordered?: boolean;\n /** \"fill\": the page root, flush to the shell, h-full against main, each pane owns its inset. \"page\" (default): inside a PageContainer under a PageHeader. */\n frame?: SplitViewFrame;\n \"aria-label\"?: string;\n className?: string;\n}\n\n/**\n * The reading-pane composition (Sprint 25.2, R3): one surface with dividers —\n * list, detail and an optional aside — that fills the height it is given (an\n * AppShell's <main> already gives it) and never three cards with gaps. The\n * panels compose ResizablePanelGroup, so the dividers drag. Below the collapse\n * width, measured on the layout itself, the list shows alone and the detail\n * stacks over it (or the app routes to it); the aside collapses to a toggle.\n * The page owns the selection and assembles the contents; keyboard movement\n * through the list is the list's job (StackedList selectedId).\n */\nexport function SplitView({\n list,\n detail,\n aside,\n asideTitle = \"Details\",\n detailOpen = false,\n onDetailClose,\n detailMode = \"stack\",\n closedDetail = \"shown\",\n closeLabel = \"Close\",\n backLabel = \"Back\",\n detailPath,\n listWidth = 35,\n listMinWidth = 25,\n asideWidth = 25,\n collapseBelow = 768,\n asideCollapseBelow = 1024,\n detailMinWidth = 480,\n bordered = false,\n frame = \"page\",\n \"aria-label\": ariaLabel,\n className,\n}: SplitViewProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const compact = useCompact(rootRef, collapseBelow, THRESHOLD_BAND);\n const layoutWidth = useElementWidth(rootRef);\n // The panels' shares as the user left them (the review: the defaults were read, so a list dragged wider left the item\n // under its minimum beside the aside); the aside's last share stands in while it is collapsed.\n const [shares, setShares] = useState<{ list?: number; aside?: number }>({});\n const listShare = shares.list ?? listWidth;\n const asideShare = shares.aside ?? asideWidth;\n // the aside yields when the layout is narrow, or when beside it the item would have less than its minimum\n const itemShare = (100 - listShare - asideShare) / 100;\n const itemBesideAside = aside ? layoutWidth * itemShare : 0;\n // the item moves by its share of the scrollbar's width, so its band is that share of the layout's\n const itemSqueezed = useBelow(itemBesideAside, detailMinWidth, THRESHOLD_BAND * Math.max(0, itemShare));\n const asideCollapsed = useBelow(layoutWidth, asideCollapseBelow, THRESHOLD_BAND) || itemSqueezed;\n const [asideWantsOpen, setAsideWantsOpen] = useState(false);\n const hiding = closedDetail === \"hidden\";\n // Hidden: the aside belongs to the open item, so it (its pane, its toggle, its Drawer) goes with the pane, and a\n // Drawer left open does not come back with the next item (render-time state adjustment).\n const showAside = !!aside && (!hiding || detailOpen);\n if (hiding && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n // on a phone the aside's Drawer belongs to the item on screen: Back closes it with the item\n if (compact && !detailOpen && asideWantsOpen) setAsideWantsOpen(false);\n const asideOpen = asideCollapsed && asideWantsOpen;\n const region = ariaLabel ? { role: \"region\" as const, \"aria-label\": ariaLabel } : {};\n // A19: the item's path stands in for Back, its last crumb (the view's parent) going up one level; its bar insets at the\n // page's gutter, as the aside's content does (Sprint 25.14 A36). A last crumb that goes nowhere of its own closes the\n // detail, as Back did, so the path is always a way back.\n const path = detailPath && detailPath.length > 0\n ? detailPath.map((crumb, i) => (i === detailPath.length - 1 && !crumbGoes(crumb) && onDetailClose ? { ...crumb, onClick: onDetailClose } : crumb))\n : null;\n // fill: the page root, flush to the shell on every side (no border, no radius, no padding of its own); h-full\n // resolves against <main> because the shell is a flex column down to it. page: inside a PageContainer under a\n // PageHeader, where `bordered` draws the surface. Each pane owns its own inset either way.\n const isFill = frame === \"fill\";\n // Sprint 25.14 A44 (P32): the list pane's content reports what it is, as a wrapped PageHeader does to its\n // PageContainer: content that draws its own frame or cards (a KanbanBoard, a CardGrid, a Table), or content with no\n // frame of its own that scrolls inside the pane (a StackedList, a Gantt). No frame around what frames itself: when the\n // pane holds only the first kind, the list sits on the canvas with nothing drawn behind it and the open item on the\n // surface, whatever `bordered` says. Anything that scrolls inside keeps the hairline, which shows where it scrolls.\n const listHolds = useRef({ framed: 0, scrolls: 0 });\n const [framesItself, setFramesItself] = useState(false);\n const reportToList = useCallback<SplitListReport>((kind, present) => {\n const held = listHolds.current;\n held[kind] = Math.max(0, held[kind] + (present ? 1 : -1));\n setFramesItself(held.framed > 0 && held.scrolls === 0);\n }, []);\n const onCanvas = isFill || framesItself;\n // In a shell with an app footer the children wrapper has no definite height, so h-full cannot resolve; the shell\n // publishes main's height and fill takes it (the footer then sits below the fold, as it must under a full pane).\n const shell = useAppShell();\n // Sprint 25.16 A42 (P31): a page frame that is the page's last content takes the height under its header, so its panes\n // scroll inside it and the page doesn't; what's inside the view takes its pane's height (FillContext)\n const pageFill = useFillHeight(rootRef, !isFill);\n // each pane scrolls inside the view: one with nothing in it to Tab to (a message's text) is a Tab stop of its own, so a\n // keyboard can scroll it (WCAG 2.1.1)\n const [listScroll, setListScroll] = useState<HTMLDivElement | null>(null);\n const [detailScroll, setDetailScroll] = useState<HTMLDivElement | null>(null);\n const [asideScroll, setAsideScroll] = useState<HTMLDivElement | null>(null);\n const [stackedListScroll, setStackedListScroll] = useState<HTMLDivElement | null>(null);\n const [stackedDetailScroll, setStackedDetailScroll] = useState<HTMLDivElement | null>(null);\n // named for what they hold (the review of 1 October): the list by the view's own name, the item by its title (its\n // first heading; the path ends at its parent, so never names it)\n const listName = ariaLabel ? `${ariaLabel} list` : \"List\";\n const itemName = ariaLabel ? `${ariaLabel} item` : \"Item\";\n useKeyboardScroll(listScroll, listName, !compact);\n useKeyboardScroll(detailScroll, itemName, !compact, true);\n useKeyboardScroll(asideScroll, asideTitle, !compact);\n useKeyboardScroll(stackedListScroll, listName, compact);\n useKeyboardScroll(stackedDetailScroll, itemName, compact, true);\n const fillStyle = isFill && shell?.hasFooter ? { height: \"var(--ds-main-height, 100%)\" } : pageFill != null ? { height: pageFill } : undefined;\n // Edge to edge the list sits on the page's canvas, like every other page, and the open item (its detail and its aside)\n // on the surface (round 27, R27-12, the owner: the whole split on the surface read as a different page). A page frame,\n // bordered or not, stays one surface: a card on the canvas. Beside a list that frames itself, a page frame's open item\n // is that card (rounded, and bordered when the view is), as the page's other cards are; edge to edge it is square.\n const itemSurface = !onCanvas ? undefined : isFill\n ? \"bg-[var(--ds-bg-surface)]\"\n : cn(\"bg-[var(--ds-bg-surface)] rounded-[var(--ds-radius-md)] overflow-hidden\", bordered && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\");\n const surface = cn(\n \"h-full min-h-0 w-full\",\n !onCanvas && \"bg-[var(--ds-bg-surface)]\",\n isFill && \"rounded-none border-0\",\n bordered && !onCanvas && \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-[var(--ds-radius-md)] overflow-hidden\",\n className,\n );\n // each pane is a surface of its own: what a Card around the view, or the list pane, tells content stops at its edge\n const listContent = <SurfaceBoundary pane=\"list\" framer={reportToList}>{list}</SurfaceBoundary>;\n const detailContent = <SurfaceBoundary pane=\"detail\">{detail}</SurfaceBoundary>;\n\n // closedDetail=\"hidden\" (C3): the pane opens beside the list at the width the user last gave it; closing it returns\n // focus to the item the pane shows, or its neighbour if that item is gone (D14(e)): the list's selected item, else\n // the last list item that took focus, checked on each render while the pane is open, so switching items is followed.\n // A selection kept in the URL changes the path, so the item is remembered whatever the route does. With no item\n // (opened on load, or from outside the list) focus goes to the list's first Tab stop. No overlay layer: an\n // assistant opened earlier keeps Escape.\n const [listPct, setListPct] = useState(listWidth);\n const paneRef = useRef<HTMLDivElement>(null);\n const shown = useRef<RememberedFocus | null>(null);\n const lastInList = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n useLayoutEffect(() => {\n if (!hiding) return;\n const listPane = rootRef.current?.querySelector<HTMLElement>('[data-pane=\"list\"]') ?? null;\n if (detailOpen) {\n wasOpen.current = true;\n const selected = listPane?.querySelector<HTMLElement>('[aria-current=\"true\"], [aria-selected=\"true\"]');\n const last = lastInList.current;\n const item = (selected && (isTabStop(selected) ? selected : tabStops(selected)[0]))\n || (last?.isConnected && listPane?.contains(last) ? last : null);\n if (item && item !== shown.current?.el) shown.current = rememberFocus(item, { ignoreRoute: true });\n return;\n }\n if (!wasOpen.current) return;\n wasOpen.current = false;\n const r = shown.current;\n shown.current = null;\n const active = document.activeElement;\n if (active && active !== document.body && active.isConnected) return;\n const first = listPane ? tabStops(listPane)[0] : undefined;\n if (!r?.restore(first)) first?.focus();\n });\n const onPaneKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !onDetailClose) return;\n const t = e.target as HTMLElement;\n // the pane's own DOM only — a portalled popup inside it bubbles here in React's tree — and never from a field\n if (!paneRef.current?.contains(t) || t.closest(\"input, textarea, select, [contenteditable='true']\")) return;\n e.preventDefault();\n onDetailClose();\n };\n\n if (compact) {\n const showDetail = detailMode === \"stack\" && detailOpen;\n // on a phone the item's aside is a toggle beside Back that opens it in a Drawer, as it is on a narrow desktop (the\n // round 27 review: below the collapse width it could not be reached at all)\n const phoneAside = showDetail && !!aside;\n return (\n <FillContext value={true}>\n <div ref={rootRef} data-split-view={showDetail ? \"detail\" : \"list\"} data-frame={frame} data-fill={pageFill != null ? \"\" : undefined} {...region} className={cn(surface, \"flex flex-col\")} style={fillStyle}>\n {showDetail && (\n <div className={cn(\"flex-1 min-h-0 flex flex-col\", itemSurface)}>\n <div className={cn(\"shrink-0 flex items-center justify-between gap-ds-2 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\", path ? \"px-[var(--ds-page-gutter)]\" : \"px-ds-3\")}>\n {path\n ? <Breadcrumbs items={path} maxItems={3} aria-label=\"Path\" className=\"min-w-0\" />\n : <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"arrow-left\" size={14} />} onClick={onDetailClose}>{backLabel}</Button>}\n {phoneAside && <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideWantsOpen}>{asideTitle}</Button>}\n </div>\n <div ref={setStackedDetailScroll} className={cn(\"flex-1 min-h-0 overflow-y-auto\", FOCUS_INSET)}>{detailContent}</div>\n </div>\n )}\n {/* Sprint 25.14 A44 (the review of 30 September): the list stays mounted while the stacked detail is shown, as it\n does beside it on a wider screen, so a board keeps its scroll and its report (the view kept its frame\n off only while the board was on screen), and Back finds the list as the user left it */}\n <div ref={setStackedListScroll} className={cn(\"flex-1 min-h-0 overflow-y-auto\", FOCUS_INSET)} hidden={showDetail || undefined}>{listContent}</div>\n {phoneAside && (\n <Drawer open={asideWantsOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n </FillContext>\n );\n }\n\n const asideButton = showAside && asideCollapsed\n ? <Button type=\"button\" variant=\"ghost\" size=\"sm\" iconLeft={<Icon name=\"info\" size={14} />} onClick={() => setAsideWantsOpen(true)} aria-expanded={asideOpen}>{asideTitle}</Button>\n : null;\n const closeButton = hiding && onDetailClose\n ? <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label={closeLabel} onClick={onDetailClose}><Icon name=\"close\" size={14} /></Button>\n : null;\n const paneBar = path || asideButton || closeButton ? (\n <div className={cn(\"shrink-0 flex items-center gap-ds-1 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\", path ? \"justify-between px-[var(--ds-page-gutter)]\" : \"justify-end px-ds-3\")}>\n {path && <Breadcrumbs items={path} aria-label=\"Path\" className=\"min-w-0\" />}\n {(asideButton || closeButton) && <div className=\"shrink-0 flex items-center gap-ds-1\">{asideButton}{closeButton}</div>}\n </div>\n ) : null;\n const showDetail = !hiding || detailOpen;\n\n return (\n <FillContext value={true}>\n <div ref={rootRef} data-split-view={hiding && !detailOpen ? \"list\" : \"split\"} data-frame={frame} data-fill={pageFill != null ? \"\" : undefined} {...region} className={surface} style={fillStyle}>\n <ResizablePanelGroup\n direction=\"horizontal\"\n stackOnMobile={false}\n className=\"h-full\"\n // the width the user gives the list is kept, so a closed pane reopens at it; the shares decide when the aside yields\n onLayoutChanged={(layout) => {\n setShares((prev) => (prev.list === (layout.list ?? prev.list) && prev.aside === (layout.aside ?? prev.aside) ? prev : { list: layout.list ?? prev.list, aside: layout.aside ?? prev.aside }));\n if (hiding && layout.detail != null && layout.list != null) setListPct(layout.list);\n }}\n >\n <ResizablePanel id=\"list\" defaultSize={`${hiding ? (detailOpen ? listPct : 100) : listWidth}%`} minSize={`${listMinWidth}%`}>\n <div ref={setListScroll} data-pane=\"list\" className={cn(\"h-full min-h-0 overflow-y-auto\", FOCUS_INSET)} onFocus={hiding ? (e) => { lastInList.current = e.target; } : undefined}>\n {listContent}\n </div>\n </ResizablePanel>\n {showDetail && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"detail\" minSize=\"30%\">\n <div ref={paneRef} data-pane=\"detail\" className={cn(\"h-full min-h-0 flex flex-col\", itemSurface)} onKeyDown={hiding ? onPaneKeyDown : undefined}>\n {paneBar}\n <div ref={setDetailScroll} className={cn(\"flex-1 min-h-0 overflow-y-auto\", FOCUS_INSET)}>{detailContent}</div>\n </div>\n </ResizablePanel>\n </>\n )}\n {showAside && !asideCollapsed && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel id=\"aside\" defaultSize={`${asideWidth}%`} minSize=\"15%\">\n {/* the Drawer's body inset, so the aside's content sits where it will in the Drawer (Sprint 25.14 A36) */}\n <div ref={setAsideScroll} data-pane=\"aside\" className={cn(\"h-full min-h-0 overflow-y-auto py-ds-5 px-[var(--ds-page-gutter)]\", itemSurface, FOCUS_INSET)}><SurfaceBoundary pane=\"aside\">{aside}</SurfaceBoundary></div>\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n {showAside && asideCollapsed && (\n <Drawer open={asideOpen} onClose={() => setAsideWantsOpen(false)} title={asideTitle} position=\"right\">\n {aside}\n </Drawer>\n )}\n </div>\n </FillContext>\n );\n}\n"]}
package/dist/roots.css CHANGED
@@ -917,6 +917,11 @@ body {
917
917
  border-radius: var(--ds-sketch-wobble-sm);
918
918
  }
919
919
 
920
+ /* A segmented control's segments, inside its frame */
921
+ [data-sketch] [class*="rounded-[var(--ds-segment-radius)"] {
922
+ border-radius: var(--ds-sketch-wobble-md);
923
+ }
924
+
920
925
  /* RichTextEditor's content styles sit in Tailwind's components layer (the round 27 review): above the base layer's
921
926
  preflight, which they must beat, and below the utilities, so an app can restyle the editor's content with classes. */
922
927
  @layer components {
@@ -988,6 +993,16 @@ body {
988
993
  cursor: pointer;
989
994
  }
990
995
 
996
+ /* Sprint 25.17 A17: a mention is one token, in the library's accent tint (a chat bubble's, a date range's) */
997
+ .rte-content .tiptap .rte-mention {
998
+ color: var(--ds-accent-subtle-text);
999
+ background-color: var(--ds-accent-subtle);
1000
+ border-radius: var(--ds-radius-sm);
1001
+ padding: 0 0.2em;
1002
+ box-decoration-break: clone;
1003
+ -webkit-box-decoration-break: clone;
1004
+ }
1005
+
991
1006
  .rte-content .tiptap hr {
992
1007
  border: none;
993
1008
  border-top: var(--ds-border-width) solid var(--ds-border-subtle);
@@ -57,7 +57,15 @@ var CURATED = {
57
57
  "bookmark": "IconBookmark",
58
58
  "download": "IconDownload",
59
59
  "upload": "IconUpload",
60
- "sparkles": "IconSparkles"
60
+ "sparkles": "IconSparkles",
61
+ "file": "IconFile",
62
+ "file-text": "IconFileText",
63
+ "eye": "IconEye",
64
+ "eye-off": "IconEyeOff",
65
+ "copy": "IconCopy",
66
+ "external-link": "IconExternalLink",
67
+ "filter": "IconFilter",
68
+ "lock": "IconLock"
61
69
  };
62
70
  async function peer() {
63
71
  return await import('@tabler/icons-react');
@@ -73,5 +81,5 @@ async function loadExtended() {
73
81
  }
74
82
 
75
83
  export { loadCurated, loadExtended };
76
- //# sourceMappingURL=tabler-YXXC7Y6B.js.map
77
- //# sourceMappingURL=tabler-YXXC7Y6B.js.map
84
+ //# sourceMappingURL=tabler-MJVEYHA5.js.map
85
+ //# sourceMappingURL=tabler-MJVEYHA5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../showcase/src/lib/icon-packs/tabler.ts"],"names":[],"mappings":"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","file":"tabler-MJVEYHA5.js","sourcesContent":["import type { IconMap } from './types'\nimport { buildExtendedMap, pickCurated } from './utils'\n\n/**\n * Tabler icons.\n *\n * The pack is reached only through the dynamic import in peer() — never a\n * static named import. A static import of an optional peer makes a consumer's\n * production build fail on Vite 8 when the peer is not installed: Vite\n * substitutes an export-less stub and the bundler treats every missing name as\n * fatal (Sprint 22 bench finding 1, 13 Sep 2026; showcase/src/test/\n * vite8-optional-peers-build.test.ts guards it). The curated names are strings\n * for the same reason; icon-completeness.test.tsx proves every one resolves in\n * the installed pack. If the pack is missing, peer() rejects and loadPack in\n * icons.tsx reports which package to install.\n */\nconst CURATED: Record<string, string> = {\n \"home\": \"IconHome\",\n \"folder\": \"IconFolder\",\n \"chart\": \"IconChartBar\",\n \"settings\": \"IconSettings\",\n \"chevron-right\": \"IconChevronRight\",\n \"close\": \"IconX\",\n \"plus\": \"IconPlus\",\n \"search\": \"IconSearch\",\n \"bell\": \"IconBell\",\n \"user\": \"IconUser\",\n \"check\": \"IconCheck\",\n \"warning\": \"IconAlertTriangle\",\n \"info\": \"IconInfoCircle\",\n \"error\": \"IconAlertCircle\",\n \"clock\": \"IconClock\",\n \"calendar\": \"IconCalendar\",\n \"bold\": \"IconBold\",\n \"italic\": \"IconItalic\",\n \"underline\": \"IconUnderline\",\n \"strikethrough\": \"IconStrikethrough\",\n \"align-left\": \"IconAlignLeft\",\n \"align-center\": \"IconAlignCenter\",\n \"align-right\": \"IconAlignRight\",\n \"list\": \"IconList\",\n \"list-ordered\": \"IconListNumbers\",\n \"list-checks\": \"IconListCheck\",\n \"link\": \"IconLink\",\n \"image\": \"IconPhoto\",\n \"table\": \"IconTable\",\n \"code\": \"IconCode\",\n \"quote\": \"IconQuote\",\n \"minus\": \"IconMinus\",\n \"superscript\": \"IconSuperscript\",\n \"subscript\": \"IconSubscript\",\n \"highlight\": \"IconHighlight\",\n \"type\": \"IconTypography\",\n \"chevron-up\": \"IconChevronUp\",\n \"chevron-down\": \"IconChevronDown\",\n \"chevron-left\": \"IconChevronLeft\",\n \"trash\": \"IconTrash\",\n \"undo\": \"IconArrowBackUp\",\n \"redo\": \"IconArrowForwardUp\",\n \"arrow-left\": \"IconArrowLeft\",\n \"grip-vertical\": \"IconGripVertical\",\n \"mic\": \"IconMicrophone\",\n \"paperclip\": \"IconPaperclip\",\n \"send\": \"IconSend\",\n \"log-out\": \"IconLogout\",\n \"edit\": \"IconPencil\",\n \"menu\": \"IconMenu2\",\n \"more-horizontal\": \"IconDots\",\n \"star\": \"IconStar\",\n \"bookmark\": \"IconBookmark\",\n \"download\": \"IconDownload\",\n \"upload\": \"IconUpload\",\n \"sparkles\": \"IconSparkles\",\n \"file\": \"IconFile\",\n \"file-text\": \"IconFileText\",\n \"eye\": \"IconEye\",\n \"eye-off\": \"IconEyeOff\",\n \"copy\": \"IconCopy\",\n \"external-link\": \"IconExternalLink\",\n \"filter\": \"IconFilter\",\n \"lock\": \"IconLock\",\n}\n\nasync function peer(): Promise<Record<string, unknown>> {\n return (await import(\"@tabler/icons-react\")) as unknown as Record<string, unknown>\n}\n\nexport async function loadCurated(): Promise<IconMap> {\n return pickCurated(await peer(), CURATED)\n}\n\nexport async function loadExtended(): Promise<IconMap> {\n const mod = await peer()\n const extended = buildExtendedMap(mod, {}, { stripPrefix: \"Icon\" })\n Object.assign(extended, pickCurated(mod, CURATED))\n return extended\n}\n"]}
@@ -33,6 +33,8 @@ interface AppShellPreferences {
33
33
  typeToConfirmActions?: string[];
34
34
  /** destructiveActions.undoWindowSeconds — how long the Undo toast stays. */
35
35
  undoWindowSeconds?: number;
36
+ /** dateTime.relativeThresholdHours — within this many hours a time reads relative ("2 hours ago"), older the date (RelativeTime). */
37
+ relativeThresholdHours?: number;
36
38
  }
37
39
  declare const PreferencesContext: react.Context<AppShellPreferences | null>;
38
40
  /** Every preference in force, the shell's value or the house default — what app code reads. */
@@ -51,6 +53,7 @@ interface ResolvedPreferences {
51
53
  highSeverityActions: string[];
52
54
  typeToConfirmActions: string[];
53
55
  undoWindowSeconds: number;
56
+ relativeThresholdHours: number;
54
57
  }
55
58
  /**
56
59
  * For app code: every preference in force — the shell's value, else the house default — so a page never writes a
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, Ref } from 'react';
3
3
  import { VirtualItem } from '@tanstack/react-virtual';
4
- import { P as Pager } from './use-pagination-DiJo0aW5.js';
4
+ import { P as Pager } from './use-pagination-BnKOnBdz.js';
5
5
 
6
6
  interface VirtualizedListProps<T> {
7
7
  items: T[];
@@ -1,11 +1,13 @@
1
- import { useWholeListCheck, pagerPart, Pagination } from './chunk-ICNWPNMM.js';
2
- import './chunk-7TOJ4G7S.js';
3
- import './chunk-RT7RYGC3.js';
4
- import { useScrollsInside } from './chunk-CKWITUSH.js';
5
- import './chunk-CXMV7SXJ.js';
1
+ import { useWholeListCheck, pagerPart, Pagination } from './chunk-W7GCEJEH.js';
2
+ import './chunk-HZIP4EJI.js';
3
+ import './chunk-XVB55M3N.js';
4
+ import { useScrollsInside } from './chunk-QM4SJKWV.js';
5
+ import './chunk-JXANCXK6.js';
6
+ import './chunk-MD2EFMES.js';
6
7
  import './chunk-7Q46JXSK.js';
8
+ import './chunk-HYMXAIXN.js';
9
+ import './chunk-HP7WUZPK.js';
7
10
  import { useLatest } from './chunk-WH2FUFAC.js';
8
- import './chunk-4LDYR7QP.js';
9
11
  import { cn } from './chunk-M2QRNBDQ.js';
10
12
  import { useRef, useEffect } from 'react';
11
13
  import { useVirtualizer } from '@tanstack/react-virtual';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../showcase/src/components/VirtualizedList.tsx"],"names":[],"mappings":"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","file":"virtualized.js","sourcesContent":["import { useEffect, useRef, type ReactNode, type Ref } from \"react\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport { cn } from \"../lib/utils\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { Pagination } from \"./Pagination\";\nimport { pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { useScrollsInside } from \"../lib/surface-context\";\n\nexport interface VirtualizedListProps<T> {\n items: T[];\n estimateSize: (index: number) => number;\n /** An item, with its index in `items` (the whole list, when the list is paged). */\n renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;\n overscan?: number;\n height?: number | string;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n /**\n * The list's pager (Sprint 25.13 A49): paging and drawing only the rows on screen combine. Pass every item and\n * `usePagination(items)`'s pager: the list mounts only the rows on screen of the pager's part, and beneath it draws the\n * control in the project's style. A new page starts at its top; with infinite scroll, scrolling inside the list loads\n * more. For a long page (logs, feeds) the user asked to page differently, pass the size to the hook\n * (`usePagination(rows, { pageSize: 100 })`) with its override note.\n */\n pager?: Pager<unknown>;\n}\n\nexport function VirtualizedList<T>({\n items: allItems,\n estimateSize,\n renderItem,\n overscan = 5,\n height = 400,\n className,\n ref,\n pager,\n}: VirtualizedListProps<T>) {\n // Sprint 25.14 A44: a list with no frame of its own: a SplitView's list pane keeps its hairline around it\n useScrollsInside();\n const parentRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n useWholeListCheck(\"VirtualizedList\", allItems.length, pager);\n const items = pagerPart(allItems, pager);\n const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;\n\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual is not compiler-compatible (informational; the project does not use the React Compiler)\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => parentRef.current,\n estimateSize: (index) => estimateSize(offset + index),\n // a row is known by its place in the whole list, so page 2's third row isn't page 1's (the review of 30 September:\n // an entry opened on page 1 showed opened on page 2, and page 1's heights carried over)\n getItemKey: (index) => offset + index,\n overscan,\n });\n\n // A49: a new page starts at its top, and so does a growing list that starts again at its first page (a new order, a\n // search): left scrolled to its end, it loaded the next page at once (the review of 30 September)\n const page = pager ? pager.page : null;\n const pageBefore = useRef(page);\n const numbered = pager?.style === \"pagination\";\n useEffect(() => {\n const before = pageBefore.current;\n pageBefore.current = page;\n if (page === null || !parentRef.current) return;\n if (numbered ? page !== before : before !== null && page < before) parentRef.current.scrollTop = 0;\n }, [page, numbered]);\n\n // A49: with infinite scroll, the trigger sits at the end of the list's own content and watches the list's scroller\n // (it watched the viewport, so scrolling inside the list never loaded more); it loads once per growth of the list\n const loadMore = useLatest(pager?.loadMore);\n const growing = pager?.style === \"infinite-scroll\" && pager.hasMore;\n const loadedAt = useRef(-1);\n useEffect(() => {\n const root = parentRef.current;\n const end = endRef.current;\n // the list's length changed since the last load (it grew, or started again at page 1): it may load again (the\n // review of 30 September: after a reset to the first page it never loaded again)\n if (loadedAt.current !== items.length) loadedAt.current = -1;\n if (!growing || !root || !end || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver((entries) => {\n if (!entries.some((e) => e.isIntersecting) || loadedAt.current === items.length) return;\n loadedAt.current = items.length;\n loadMore.current?.();\n }, { root, rootMargin: \"200px 0px\" });\n observer.observe(end);\n return () => observer.disconnect();\n }, [growing, items.length, loadMore]);\n\n const list = (\n <div\n ref={(node) => {\n (parentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }}\n data-ds-list={pager ? \"\" : undefined}\n className={cn(\n \"overflow-auto\",\n \"rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)]\",\n !pager && className,\n )}\n style={{ height }}\n >\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n className=\"absolute top-0 left-0 w-full\"\n style={{ transform: `translateY(${virtualItem.start}px)` }}\n >\n {renderItem(items[virtualItem.index], offset + virtualItem.index, virtualItem)}\n </div>\n ))}\n </div>\n {growing && <div ref={endRef} data-load-more-trigger=\"\" aria-hidden=\"true\" className=\"h-px w-full\" />}\n </div>\n );\n // A3: the pager's control is the list's next sibling, as <Pagination {...pager.props} /> would be. With infinite\n // scroll it is the Load more button alone, for keyboard users: the list's own trigger loads as it scrolls (A49). The\n // two are one element, which takes the className, so in a grid or a flex row they stay one item, and the list keeps\n // its element while its items come and go (the review of 30 September).\n if (!pager) return list;\n return (\n <div data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>\n {list}\n {allItems.length > 0 && <Pagination {...pager.props} mode={pager.style === \"infinite-scroll\" ? \"load-more\" : pager.props.mode} />}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../showcase/src/components/VirtualizedList.tsx"],"names":[],"mappings":"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","file":"virtualized.js","sourcesContent":["import { useEffect, useRef, type ReactNode, type Ref } from \"react\";\nimport { useVirtualizer, type VirtualItem } from \"@tanstack/react-virtual\";\nimport { cn } from \"../lib/utils\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { Pagination } from \"./Pagination\";\nimport { pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { useScrollsInside } from \"../lib/surface-context\";\n\nexport interface VirtualizedListProps<T> {\n items: T[];\n estimateSize: (index: number) => number;\n /** An item, with its index in `items` (the whole list, when the list is paged). */\n renderItem: (item: T, index: number, virtualItem: VirtualItem) => ReactNode;\n overscan?: number;\n height?: number | string;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n /**\n * The list's pager (Sprint 25.13 A49): paging and drawing only the rows on screen combine. Pass every item and\n * `usePagination(items)`'s pager: the list mounts only the rows on screen of the pager's part, and beneath it draws the\n * control in the project's style. A new page starts at its top; with infinite scroll, scrolling inside the list loads\n * more. For a long page (logs, feeds) the user asked to page differently, pass the size to the hook\n * (`usePagination(rows, { pageSize: 100 })`) with its override note.\n */\n pager?: Pager<unknown>;\n}\n\nexport function VirtualizedList<T>({\n items: allItems,\n estimateSize,\n renderItem,\n overscan = 5,\n height = 400,\n className,\n ref,\n pager,\n}: VirtualizedListProps<T>) {\n // Sprint 25.14 A44: a list with no frame of its own: a SplitView's list pane keeps its hairline around it\n useScrollsInside();\n const parentRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n useWholeListCheck(\"VirtualizedList\", allItems.length, pager);\n const items = pagerPart(allItems, pager);\n const offset = pager ? Math.max(0, pager.range[0] - 1) : 0;\n\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Virtual is not compiler-compatible (informational; the project does not use the React Compiler)\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => parentRef.current,\n estimateSize: (index) => estimateSize(offset + index),\n // a row is known by its place in the whole list, so page 2's third row isn't page 1's (the review of 30 September:\n // an entry opened on page 1 showed opened on page 2, and page 1's heights carried over)\n getItemKey: (index) => offset + index,\n overscan,\n });\n\n // A49: a new page starts at its top, and so does a growing list that starts again at its first page (a new order, a\n // search): left scrolled to its end, it loaded the next page at once (the review of 30 September)\n const page = pager ? pager.page : null;\n const pageBefore = useRef(page);\n const numbered = pager?.style === \"pagination\";\n useEffect(() => {\n const before = pageBefore.current;\n pageBefore.current = page;\n if (page === null || !parentRef.current) return;\n if (numbered ? page !== before : before !== null && page < before) parentRef.current.scrollTop = 0;\n }, [page, numbered]);\n\n // A49: with infinite scroll, the trigger sits at the end of the list's own content and watches the list's scroller\n // (it watched the viewport, so scrolling inside the list never loaded more); it loads once per growth of the list\n const loadMore = useLatest(pager?.loadMore);\n const growing = pager?.style === \"infinite-scroll\" && pager.hasMore;\n const loadedAt = useRef(-1);\n useEffect(() => {\n const root = parentRef.current;\n const end = endRef.current;\n // the list's length changed since the last load (it grew, or started again at page 1): it may load again (the\n // review of 30 September: after a reset to the first page it never loaded again)\n if (loadedAt.current !== items.length) loadedAt.current = -1;\n if (!growing || !root || !end || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver((entries) => {\n if (!entries.some((e) => e.isIntersecting) || loadedAt.current === items.length) return;\n loadedAt.current = items.length;\n loadMore.current?.();\n }, { root, rootMargin: \"200px 0px\" });\n observer.observe(end);\n return () => observer.disconnect();\n }, [growing, items.length, loadMore]);\n\n const list = (\n <div\n ref={(node) => {\n (parentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }}\n data-ds-list={pager ? \"\" : undefined}\n className={cn(\n \"overflow-auto\",\n \"rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"bg-[var(--ds-bg-surface)]\",\n !pager && className,\n )}\n style={{ height }}\n >\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n className=\"absolute top-0 left-0 w-full\"\n style={{ transform: `translateY(${virtualItem.start}px)` }}\n >\n {renderItem(items[virtualItem.index], offset + virtualItem.index, virtualItem)}\n </div>\n ))}\n </div>\n {growing && <div ref={endRef} data-load-more-trigger=\"\" aria-hidden=\"true\" className=\"h-px w-full\" />}\n </div>\n );\n // A3: the pager's control is the list's next sibling, as <Pagination {...pager.props} /> would be. With infinite\n // scroll it is the Load more button alone, for keyboard users: the list's own trigger loads as it scrolls (A49). The\n // two are one element, which takes the className, so in a grid or a flex row they stay one item, and the list keeps\n // its element while its items come and go (the review of 30 September).\n if (!pager) return list;\n return (\n <div data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>\n {list}\n {allItems.length > 0 && <Pagination {...pager.props} mode={pager.style === \"infinite-scroll\" ? \"load-more\" : pager.props.mode} />}\n </div>\n );\n}\n"]}