gridsmith-ui 0.29.1 → 0.30.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 (88) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +5 -1
  3. package/dist/DropdownMenu-DqT7ZQ0D.d.ts +39 -0
  4. package/dist/charts.js +4 -2
  5. package/dist/charts.js.map +1 -1
  6. package/dist/chat.js +4 -4
  7. package/dist/{chunk-OYNUU346.js → chunk-7QLXYRPD.js} +3 -12
  8. package/dist/chunk-7QLXYRPD.js.map +1 -0
  9. package/dist/chunk-F2BNJSON.js +1348 -0
  10. package/dist/chunk-F2BNJSON.js.map +1 -0
  11. package/dist/{chunk-37WOC7F7.js → chunk-GQVBZ4GW.js} +29 -8
  12. package/dist/chunk-GQVBZ4GW.js.map +1 -0
  13. package/dist/{chunk-MFAWJSMJ.js → chunk-INGF2CPW.js} +3 -22
  14. package/dist/chunk-INGF2CPW.js.map +1 -0
  15. package/dist/{chunk-I3MTQ3CS.js → chunk-KTPGMJUK.js} +5 -5
  16. package/dist/{chunk-I3MTQ3CS.js.map → chunk-KTPGMJUK.js.map} +1 -1
  17. package/dist/{chunk-MKFWHWBK.js → chunk-L6HWACK7.js} +7 -7
  18. package/dist/chunk-L6HWACK7.js.map +1 -0
  19. package/dist/chunk-LJYSVZMI.js +25 -0
  20. package/dist/chunk-LJYSVZMI.js.map +1 -0
  21. package/dist/{chunk-FUKSLQ77.js → chunk-NI5542ZM.js} +39 -35
  22. package/dist/chunk-NI5542ZM.js.map +1 -0
  23. package/dist/chunk-NKUCS67T.js +13 -0
  24. package/dist/chunk-NKUCS67T.js.map +1 -0
  25. package/dist/{chunk-RECCCA7Z.js → chunk-NLXQ323J.js} +4 -4
  26. package/dist/{chunk-RECCCA7Z.js.map → chunk-NLXQ323J.js.map} +1 -1
  27. package/dist/{chunk-ZI3OQDET.js → chunk-OIOII5L6.js} +93 -4
  28. package/dist/chunk-OIOII5L6.js.map +1 -0
  29. package/dist/{chunk-RJEUQ7RL.js → chunk-Q36JVJX4.js} +46 -89
  30. package/dist/chunk-Q36JVJX4.js.map +1 -0
  31. package/dist/{chunk-FD4YED7O.js → chunk-RHWTMTU5.js} +3 -3
  32. package/dist/{chunk-FD4YED7O.js.map → chunk-RHWTMTU5.js.map} +1 -1
  33. package/dist/chunk-TYNDXMBV.js +105 -0
  34. package/dist/chunk-TYNDXMBV.js.map +1 -0
  35. package/dist/{chunk-4TUJXDRU.js → chunk-UNS4TGGK.js} +20 -11
  36. package/dist/chunk-UNS4TGGK.js.map +1 -0
  37. package/dist/chunk-Z4MCD73B.js +316 -0
  38. package/dist/chunk-Z4MCD73B.js.map +1 -0
  39. package/dist/data-grid.d.ts +25 -6
  40. package/dist/data-grid.js +177 -55
  41. package/dist/data-grid.js.map +1 -1
  42. package/dist/editor-mentions.js +1 -1
  43. package/dist/editor.js +3 -3
  44. package/dist/{feather-FNBQ74RR.js → feather-XFFEFLTV.js} +5 -3
  45. package/dist/feather-XFFEFLTV.js.map +1 -0
  46. package/dist/{heroicons-DODCSYWD.js → heroicons-L6DOHBEA.js} +5 -3
  47. package/dist/heroicons-L6DOHBEA.js.map +1 -0
  48. package/dist/icons.d.ts +1 -1
  49. package/dist/icons.js +1 -1
  50. package/dist/index.d.ts +138 -39
  51. package/dist/index.js +660 -1568
  52. package/dist/index.js.map +1 -1
  53. package/dist/kanban.d.ts +26 -8
  54. package/dist/kanban.js +200 -76
  55. package/dist/kanban.js.map +1 -1
  56. package/dist/{lucide-ZWE3EPGP.js → lucide-JOORDTO6.js} +5 -3
  57. package/dist/lucide-JOORDTO6.js.map +1 -0
  58. package/dist/{phosphor-DIHPA4AJ.js → phosphor-TKGDYNGR.js} +5 -3
  59. package/dist/phosphor-TKGDYNGR.js.map +1 -0
  60. package/dist/resizable.js +10 -9
  61. package/dist/resizable.js.map +1 -1
  62. package/dist/roots.css +12 -8
  63. package/dist/{table-utils-CxnpFHRF.d.ts → table-utils-BXkP-2Hx.d.ts} +3 -1
  64. package/dist/{tabler-D3VYTSGI.js → tabler-YGETLYRU.js} +5 -3
  65. package/dist/tabler-YGETLYRU.js.map +1 -0
  66. package/dist/tokens.css +14 -0
  67. package/dist/utils.js.map +1 -1
  68. package/dist/virtualized.js +8 -7
  69. package/dist/virtualized.js.map +1 -1
  70. package/dist-static/tokens.css +14 -0
  71. package/package.json +1 -1
  72. package/dist/chunk-37WOC7F7.js.map +0 -1
  73. package/dist/chunk-4TUJXDRU.js.map +0 -1
  74. package/dist/chunk-FUKSLQ77.js.map +0 -1
  75. package/dist/chunk-MFAWJSMJ.js.map +0 -1
  76. package/dist/chunk-MKFWHWBK.js.map +0 -1
  77. package/dist/chunk-OYNUU346.js.map +0 -1
  78. package/dist/chunk-QM4SJKWV.js +0 -51
  79. package/dist/chunk-QM4SJKWV.js.map +0 -1
  80. package/dist/chunk-QNHVPE2B.js +0 -117
  81. package/dist/chunk-QNHVPE2B.js.map +0 -1
  82. package/dist/chunk-RJEUQ7RL.js.map +0 -1
  83. package/dist/chunk-ZI3OQDET.js.map +0 -1
  84. package/dist/feather-FNBQ74RR.js.map +0 -1
  85. package/dist/heroicons-DODCSYWD.js.map +0 -1
  86. package/dist/lucide-ZWE3EPGP.js.map +0 -1
  87. package/dist/phosphor-DIHPA4AJ.js.map +0 -1
  88. package/dist/tabler-D3VYTSGI.js.map +0 -1
package/dist/data-grid.js CHANGED
@@ -1,31 +1,137 @@
1
1
  "use client";
2
- import { useCardsSwitch, CARDS_BELOW, inferColumnKinds, CardValue } from './chunk-QNHVPE2B.js';
3
- import { usePagination, useWholeListCheck, pagerPart, Pagination, Input } from './chunk-FUKSLQ77.js';
4
- import { useShellPreferences } from './chunk-RJEUQ7RL.js';
5
- import './chunk-OYNUU346.js';
2
+ import { useCardsSwitch, CARDS_BELOW, inferColumnKinds, CardValue, SortIndicator, CutCell, CutEmail, dayKey, DatePicker, Checkbox } from './chunk-F2BNJSON.js';
3
+ import { usePagination, useWholeListCheck, pagerPart, Pagination, Dropdown, Field, NumberInput, Input } from './chunk-NI5542ZM.js';
4
+ import { useShellPreferences } from './chunk-TYNDXMBV.js';
5
+ import './chunk-LJYSVZMI.js';
6
+ import './chunk-7QLXYRPD.js';
6
7
  import './chunk-7RKC5C7G.js';
7
- import { useBreakpoint } from './chunk-ZHUVLBCC.js';
8
8
  import { FormChangeCtx } from './chunk-72SDAX54.js';
9
- import { useFramesItself, TableCardCtx, RowsCtx } from './chunk-QM4SJKWV.js';
9
+ import { useFramesItself, TableCardCtx, RowsCtx } from './chunk-Q36JVJX4.js';
10
+ import './chunk-NKUCS67T.js';
11
+ import { useBreakpoint } from './chunk-ZHUVLBCC.js';
10
12
  import { useRevealFocus } from './chunk-HTXP5BMM.js';
11
- import { useGridKeyboard } from './chunk-ZI3OQDET.js';
12
- import { useTextOverflow, AutoTooltip } from './chunk-37WOC7F7.js';
13
+ import { useGridKeyboard, useFocusLeave, focusInitial } from './chunk-OIOII5L6.js';
14
+ import './chunk-GQVBZ4GW.js';
13
15
  import './chunk-7Q46JXSK.js';
14
- import { Icon } from './chunk-MKFWHWBK.js';
16
+ import { Icon, warnOnce } from './chunk-L6HWACK7.js';
15
17
  import './chunk-HP7WUZPK.js';
16
18
  import './chunk-WH2FUFAC.js';
17
19
  import { cn, FOCUS_INSET, FOCUS_RING } from './chunk-JTU7OBYJ.js';
18
20
  import { useState, useMemo, useCallback, useRef, useEffect, useLayoutEffect } from 'react';
19
21
  import { useReactTable, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
20
- import { jsx, jsxs } from 'react/jsx-runtime';
22
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
21
23
 
22
- function TruncCell({ children, lines }) {
23
- const { ref, isTruncated } = useTextOverflow({ lines });
24
- const clampClass = lines === 1 ? "truncate" : `line-clamp-${lines}`;
25
- const cell = /* @__PURE__ */ jsx("span", { ref, className: cn(clampClass, "block"), children });
26
- if (!isTruncated) return cell;
27
- return /* @__PURE__ */ jsx(AutoTooltip, { content: children, children: cell });
24
+ var isEmpty = (v) => v === null || v === void 0 || v === "";
25
+ var isDate = (v) => v instanceof Date && !Number.isNaN(v.getTime());
26
+ function isoDay(v) {
27
+ const m = typeof v === "string" ? /^(\d{4})-(\d{2})-(\d{2})$/.exec(v) : null;
28
+ if (!m) return null;
29
+ const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
30
+ return dayKey(d) === v ? d : null;
28
31
  }
32
+ var sameValue = (a, b) => isDate(a) && isDate(b) ? a.getTime() === b.getTime() : Object.is(a, b);
33
+ function editorFor(kind, raw, meta, firstOfColumn) {
34
+ const parse = meta?.parse;
35
+ if (kind === "choice" && meta?.options?.length) return { editor: "choice", value: raw ?? null, out: (v) => v };
36
+ if (kind === "boolean" && (typeof raw === "boolean" || isEmpty(raw))) return { editor: "boolean", value: raw === true, out: (v) => v };
37
+ if (kind === "number" && typeof raw === "number" && Number.isFinite(raw)) return { editor: "number", value: raw, out: (v) => parse ? parse(String(v)) : v };
38
+ if (kind === "date") {
39
+ const was = isEmpty(raw) ? firstOfColumn() : raw;
40
+ if (isDate(raw)) {
41
+ return { editor: "date", value: raw, out: (v) => isDate(v) ? new Date(v.getFullYear(), v.getMonth(), v.getDate(), raw.getHours(), raw.getMinutes(), raw.getSeconds(), raw.getMilliseconds()) : null };
42
+ }
43
+ if (isoDay(was)) return { editor: "date", value: isoDay(raw), out: (v) => isDate(v) ? dayKey(v) : null };
44
+ if (isEmpty(was) || isDate(was)) return { editor: "date", value: null, out: (v) => isDate(v) ? v : null };
45
+ }
46
+ return { editor: "text", value: String(raw ?? ""), out: (v) => parse ? parse(v) : v };
47
+ }
48
+ function CellEditor({ editor, value, name, options, onChange, onEnd }) {
49
+ const ref = useRef(null);
50
+ const leave = useFocusLeave(() => onEnd(true, false));
51
+ const fromPopup = useRef(false);
52
+ const markPopupEvent = (e) => {
53
+ fromPopup.current = !ref.current?.contains(e.target);
54
+ };
55
+ const opened = useRef(false);
56
+ useLayoutEffect(() => {
57
+ const root = ref.current;
58
+ if (!root) return;
59
+ focusInitial(root);
60
+ const el = document.activeElement;
61
+ if (el instanceof HTMLInputElement && el.type === "text") el.select();
62
+ if (editor === "choice" && !opened.current && el instanceof HTMLButtonElement && root.contains(el)) {
63
+ opened.current = true;
64
+ el.click();
65
+ }
66
+ }, [editor]);
67
+ const picks = editor === "choice" || editor === "boolean";
68
+ const change = (v) => picks || fromPopup.current ? onEnd(true, true, { value: v }) : onChange(v);
69
+ let control;
70
+ if (editor === "number") control = /* @__PURE__ */ jsx(NumberInput, { size: "sm", value, allowDecimals: true, onChange: change });
71
+ else if (editor === "date") control = /* @__PURE__ */ jsx(DatePicker, { size: "sm", value, onChange: change });
72
+ else if (editor === "boolean") control = /* @__PURE__ */ jsx(Checkbox, { checked: value === true, onChange: (checked) => change(checked) });
73
+ else if (editor === "choice" && options) {
74
+ control = /* @__PURE__ */ jsx(
75
+ Dropdown,
76
+ {
77
+ size: "sm",
78
+ options: options.map((o) => ({ id: String(o.value), label: o.label })),
79
+ value: value === null || value === void 0 ? "" : String(value),
80
+ onChange: (id) => change(options.find((o) => String(o.value) === id)?.value ?? id)
81
+ }
82
+ );
83
+ } else control = /* @__PURE__ */ jsx(Input, { size: "sm", value, onChange: (e) => change(e.target.value) });
84
+ return /* @__PURE__ */ jsx(
85
+ "div",
86
+ {
87
+ ref,
88
+ "data-cell-editor": "",
89
+ ...leave,
90
+ onClickCapture: markPopupEvent,
91
+ onKeyDownCapture: markPopupEvent,
92
+ onKeyDown: (e) => {
93
+ if (e.key === "Escape") {
94
+ e.preventDefault();
95
+ e.stopPropagation();
96
+ onEnd(false, true);
97
+ return;
98
+ }
99
+ if (e.key === "Enter" && e.currentTarget.contains(e.target) && !(e.target instanceof HTMLButtonElement)) {
100
+ e.preventDefault();
101
+ onEnd(true, true);
102
+ }
103
+ },
104
+ children: /* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(Field, { label: name, hideLabel: true, children: control }) })
105
+ }
106
+ );
107
+ }
108
+ var EDIT_CUE_ROOM = "pr-[calc(var(--ds-space-4)+var(--ds-space-1)+12px)]";
109
+ var EDITOR_WIDTH = {
110
+ text: "w-[max(calc(100%-var(--ds-space-4)),12rem)]",
111
+ number: "w-[max(calc(100%-var(--ds-space-4)),8rem)]",
112
+ date: "w-[max(calc(100%-var(--ds-space-4)),10.5rem)]",
113
+ choice: "w-[max(calc(100%-var(--ds-space-4)),9rem)]",
114
+ boolean: "w-auto"
115
+ };
116
+ var EDITABLE_MIN_WIDTH = { number: "9rem", date: "11.5rem", choice: "10rem" };
117
+ function editableMinWidth(kind, meta) {
118
+ if (meta?.width || meta?.minWidth) return void 0;
119
+ const editor = kind === "number" ? "number" : kind === "date" ? "date" : kind === "choice" && meta?.options?.length ? "choice" : null;
120
+ return editor ? EDITABLE_MIN_WIDTH[editor] : void 0;
121
+ }
122
+ var EDIT_CUE = /* @__PURE__ */ jsx(
123
+ "span",
124
+ {
125
+ "data-edit-cue": "",
126
+ "aria-hidden": "true",
127
+ className: cn(
128
+ "pointer-events-none absolute top-1/2 -translate-y-1/2 right-ds-4 flex",
129
+ "text-[var(--ds-text-muted)] opacity-0 transition-opacity duration-[var(--ds-transition-speed)]",
130
+ "group-hover/cell:opacity-100 group-focus/cell:opacity-100"
131
+ ),
132
+ children: /* @__PURE__ */ jsx(Icon, { name: "edit", size: 12 })
133
+ }
134
+ );
29
135
  var cellKey = (p) => p.r < 0 ? `h:${p.c}` : `${p.r}:${p.c}`;
30
136
  var SAVED_TICK_MS = 1500;
31
137
  function DataGrid({
@@ -79,6 +185,13 @@ function DataGrid({
79
185
  const header = leafColumns.find((c) => c.id === id)?.columnDef.header;
80
186
  return typeof header === "string" ? header : id;
81
187
  };
188
+ if (editable) {
189
+ for (const column of leafColumns) {
190
+ const meta = column.columnDef.meta;
191
+ if (meta?.kind === "choice" && !meta.options?.length) warnOnce("DataGrid", `column "${column.id}" is a choice with no options, so it edits as text: give its meta the options its cells take.`);
192
+ else if (meta?.options?.length && meta.kind !== "choice") warnOnce("DataGrid", `column "${column.id}" has options but not the choice kind, so they go unused: give its meta kind "choice" to edit it with a Dropdown.`);
193
+ }
194
+ }
82
195
  const gridRef = useRef(null);
83
196
  const [activeId, setActiveId] = useState({ row: null, c: 0 });
84
197
  const lastRow = rows.length - 1;
@@ -111,10 +224,13 @@ function DataGrid({
111
224
  const row = rows[p.r];
112
225
  const column = leafColumns[p.c];
113
226
  if (!row || !column || column.columnDef.meta?.editable === false) return;
227
+ if (editing && !(editing.row === row.id && editing.c === p.c)) finishEdit(true, false);
114
228
  ended.current = false;
115
229
  setActive(p);
116
- const text = String(row.getValue(column.id) ?? "");
117
- setEditing({ row: row.id, c: p.c, value: text, was: text });
230
+ const meta = column.columnDef.meta;
231
+ const firstOfColumn = () => rows.map((x) => x.getValue(column.id)).find((v) => !isEmpty(v));
232
+ const setup = editorFor(kindOf(column.id, meta), row.getValue(column.id), meta, firstOfColumn);
233
+ setEditing({ row: row.id, c: p.c, editor: setup.editor, value: setup.value, was: setup.value, out: setup.out });
118
234
  };
119
235
  const grid = useGridKeyboard({
120
236
  container: gridRef,
@@ -130,6 +246,7 @@ function DataGrid({
130
246
  modifierKeys: true
131
247
  });
132
248
  const onGridKeyDown = (e) => {
249
+ if (e.target instanceof Element && e.target.closest("[data-cell-editor]")) return;
133
250
  if (e.key === "F2" && !editing && current.r >= 0 && e.target instanceof HTMLElement && e.target.getAttribute("data-grid-key") === cellKey(current)) {
134
251
  e.preventDefault();
135
252
  startEdit(current);
@@ -170,7 +287,7 @@ function DataGrid({
170
287
  refocus.current = null;
171
288
  grid.focus({ r, c: want.c });
172
289
  });
173
- const finishEdit = (commit, focusBack) => {
290
+ const finishEdit = (commit, focusBack, picked) => {
174
291
  if (!editing || ended.current) return;
175
292
  ended.current = true;
176
293
  const r = rowAt(editing.row);
@@ -182,13 +299,13 @@ function DataGrid({
182
299
  setActiveId(cell);
183
300
  refocus.current = cell;
184
301
  }
185
- if (!commit || !row || !column || editing.value === editing.was) return;
186
- const meta = column.columnDef.meta;
302
+ const value = picked ? picked.value : editing.value;
303
+ if (!commit || !row || !column || sameValue(value, editing.was)) return;
187
304
  const done = (ok) => {
188
305
  heard.current += 1;
189
306
  setSaved({ ...cell, row: editing.row, n: heard.current, ok });
190
307
  };
191
- const result = onCellEdit?.(row.index, column.id, meta?.parse ? meta.parse(editing.value) : editing.value);
308
+ const result = onCellEdit?.(row.index, column.id, editing.out(value));
192
309
  if (result && typeof result.then === "function") result.then(() => done(true), () => done(false));
193
310
  else done(true);
194
311
  };
@@ -219,10 +336,6 @@ function DataGrid({
219
336
  )) }) }) }) })
220
337
  );
221
338
  }
222
- const sortIcons = (sorted) => /* @__PURE__ */ jsxs("span", { className: "inline-flex flex-col -space-y-ds-1.5", "aria-hidden": "true", children: [
223
- /* @__PURE__ */ jsx(Icon, { name: "chevron-up", size: 10, className: sorted === "asc" ? "text-[var(--ds-accent-ink)]" : "opacity-30" }),
224
- /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 10, className: sorted === "desc" ? "text-[var(--ds-accent-ink)]" : "opacity-30" })
225
- ] });
226
339
  const headerCell = (header, c) => {
227
340
  const canSort = header.column.getCanSort();
228
341
  const sorted = header.column.getIsSorted();
@@ -241,11 +354,15 @@ function DataGrid({
241
354
  className: cn(
242
355
  "inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none [font:inherit] text-inherit",
243
356
  "hover:text-[var(--ds-text-primary)] rounded-[var(--ds-radius-sm)]",
357
+ // in a right-aligned column the indicator goes before the label, so the label ends where the column's values
358
+ // end; the sorted column's label in full colour (the owner's choice at the look check, 14 October)
359
+ headerAlign === "right" && "flex-row-reverse",
360
+ sorted && "text-[var(--ds-text-primary)]",
244
361
  FOCUS_RING
245
362
  ),
246
363
  children: [
247
364
  label,
248
- sortIcons(sorted)
365
+ /* @__PURE__ */ jsx(SortIndicator, { sorted })
249
366
  ]
250
367
  }
251
368
  ) : label;
@@ -260,7 +377,9 @@ function DataGrid({
260
377
  headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left",
261
378
  shrink && "w-px whitespace-nowrap",
262
379
  "text-[var(--ds-text-secondary)]",
263
- FOCUS_INSET
380
+ FOCUS_INSET,
381
+ // an editable column's cells keep room for their cue at their end (item 19): its header keeps the same
382
+ editable && meta?.editable !== false && EDIT_CUE_ROOM
264
383
  ),
265
384
  style: meta?.maxWidth || meta?.width || meta?.minWidth ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth } : void 0,
266
385
  children: /* @__PURE__ */ jsx("span", { className: cn("flex items-center gap-ds-1", headerAlign === "right" && "justify-end", headerAlign === "center" && "justify-center"), children: inside })
@@ -308,60 +427,63 @@ function DataGrid({
308
427
  const at = { r, c };
309
428
  const isEditing = editable && editing?.row === row.id && editing.c === c;
310
429
  const shrink = (kind === "number" || kind === "date") && !meta?.maxWidth;
430
+ const align = meta?.align ?? (kind === "number" ? "right" : "left");
311
431
  let inner;
312
432
  if (isEditing) {
313
- inner = /* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(
314
- Input,
315
- {
316
- size: "sm",
317
- autoFocus: true,
318
- "aria-label": headerText(cell.column.id),
319
- onFocus: (e) => e.currentTarget.select(),
320
- value: editing.value,
321
- onChange: (e) => setEditing({ ...editing, value: e.target.value }),
322
- onBlur: () => finishEdit(true, false),
323
- onKeyDown: (e) => {
324
- if (e.key === "Enter") {
325
- e.preventDefault();
326
- finishEdit(true, true);
327
- } else if (e.key === "Escape") {
328
- e.preventDefault();
329
- e.stopPropagation();
330
- finishEdit(false, true);
331
- }
433
+ inner = /* @__PURE__ */ jsxs(Fragment, { children: [
434
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "invisible", children: rendered }),
435
+ /* @__PURE__ */ jsx("div", { className: cn(
436
+ "absolute inset-y-0 z-30 flex items-center",
437
+ EDITOR_WIDTH[editing.editor],
438
+ // from the cell's end in a right-aligned column, and in the last column, where an editor wider
439
+ // than its cell would run past the grid's edge; over the cell before, it stays in view
440
+ align === "right" || c === row.getVisibleCells().length - 1 ? "right-ds-2" : "left-ds-2"
441
+ ), children: /* @__PURE__ */ jsx(
442
+ CellEditor,
443
+ {
444
+ editor: editing.editor,
445
+ value: editing.value,
446
+ name: headerText(cell.column.id),
447
+ options: meta?.options,
448
+ onChange: (v) => setEditing({ ...editing, value: v }),
449
+ onEnd: finishEdit
332
450
  }
333
- }
334
- ) });
451
+ ) })
452
+ ] });
335
453
  } else if (truncLines > 0) {
336
- inner = /* @__PURE__ */ jsx(TruncCell, { lines: truncLines, children: rendered });
454
+ inner = /* @__PURE__ */ jsx(CutCell, { lines: truncLines, children: rendered });
337
455
  } else if (kind === "email") {
338
- inner = /* @__PURE__ */ jsx("span", { className: "max-w-[40ch] truncate inline-block align-bottom", title: typeof cell.getValue() === "string" ? cell.getValue() : void 0, children: rendered });
456
+ inner = /* @__PURE__ */ jsx(CutEmail, { children: rendered });
339
457
  } else {
340
458
  inner = rendered;
341
459
  }
342
- const align = meta?.align ?? (kind === "number" ? "right" : "left");
343
460
  const value = cell.getValue();
344
461
  if (!isEditing && align !== "left" && typeof value !== "string" && typeof value !== "number" && value !== null && value !== void 0) {
345
462
  inner = /* @__PURE__ */ jsx("div", { className: cn("flex items-center", align === "center" ? "justify-center" : "justify-end"), children: inner });
346
463
  }
347
464
  const tick = editable && saved?.ok && saved.row === row.id && saved.c === c ? /* @__PURE__ */ jsx(Icon, { name: "check", size: 14, className: "ml-ds-1 inline-block align-middle text-[var(--ds-status-success)]" }) : null;
465
+ const edits = editable && meta?.editable !== false;
466
+ const least = edits ? editableMinWidth(kind, meta) : void 0;
348
467
  return /* @__PURE__ */ jsxs(
349
468
  "td",
350
469
  {
351
470
  ...editable ? { role: "gridcell", "data-grid-key": cellKey(at), tabIndex: grid.tabIndexOf(at), onDoubleClick: () => {
352
471
  if (!isEditing) startEdit(at);
353
472
  } } : {},
473
+ "aria-readonly": editable && !edits ? true : void 0,
354
474
  className: cn(
355
475
  "px-ds-4 py-ds-3 text-[var(--ds-text-primary)]",
356
476
  align === "right" && "text-right",
357
477
  align === "center" && "text-center",
358
478
  shrink && "w-px whitespace-nowrap",
359
- editable && FOCUS_INSET
479
+ editable && FOCUS_INSET,
480
+ edits && cn("group/cell relative", EDIT_CUE_ROOM)
360
481
  ),
361
- style: meta?.maxWidth || meta?.width || meta?.minWidth ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth } : void 0,
482
+ style: meta?.maxWidth || meta?.width || meta?.minWidth || least ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth ?? least } : void 0,
362
483
  children: [
363
484
  inner,
364
- tick
485
+ tick,
486
+ edits && !isEditing && EDIT_CUE
365
487
  ]
366
488
  },
367
489
  cell.id
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../showcase/src/components/DataGrid.tsx"],"names":[],"mappings":"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","file":"data-grid.js","sourcesContent":["import { useState, useCallback, useEffect, useLayoutEffect, useMemo, useRef, type ReactNode, type KeyboardEvent as ReactKeyboardEvent } from \"react\";\nimport { useShellPreferences } from \"../lib/preferences\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n flexRender,\n type CellContext,\n type ColumnDef,\n type Header,\n type SortingState,\n} from \"@tanstack/react-table\";\nimport { cn, FOCUS_INSET, FOCUS_RING } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { AutoTooltip } from \"./Tooltip\";\nimport { Input } from \"./Input\";\nimport { Pagination } from \"./Pagination\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { useBreakpoint, type BreakpointKey } from \"../lib/use-breakpoint\";\nimport { useRevealFocus } from \"../lib/reveal-focus\";\nimport { inferColumnKinds, type ColumnKind } from \"../lib/table-utils\";\nimport { CardValue } from \"../lib/card-cell\";\nimport { TableCardCtx, RowsCtx, useFramesItself } from \"../lib/surface-context\";\nimport { FormChangeCtx } from \"../lib/form-context\";\nimport { useGridKeyboard } from \"../lib/focus\";\nimport { usePagination, pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { CARDS_BELOW, useCardsSwitch } from \"../lib/use-cards-switch\";\n\n/** Column meta for opt-in truncation. Set on ColumnDef.meta. */\nexport interface DataGridColumnMeta {\n /** true = single-line, or { lines: N } for multi-line clamp. */\n truncate?: boolean | { lines: number };\n /** CSS max-width for the column. */\n maxWidth?: string;\n /** CSS width for the column — sibling grids that share a column set line up when their columns carry the same widths (round 14). */\n width?: string;\n /** CSS min-width for the column. */\n minWidth?: string;\n /** Explicit column kind. When omitted the DataGrid infers it from data values. */\n kind?: ColumnKind;\n /** Horizontal alignment of the header and the cells; a block element (a Checkbox, a Button) is laid out with flex so it follows too (round 14). Default: numbers right, everything else left. */\n align?: \"left\" | \"center\" | \"right\";\n /** In an editable grid, whether this column's cells edit (default true); false for a column that shows (a status, actions). */\n editable?: boolean;\n /**\n * In an editable grid, the value onCellEdit gets from the text typed (default the text itself): a number column's\n * `(text) => Number(text)`, so a salary stays a number (the review of 30 September).\n */\n parse?: (text: string) => unknown;\n}\n\nfunction TruncCell({ children, lines }: { children: ReactNode; lines: number }) {\n const { ref, isTruncated } = useTextOverflow({ lines });\n const clampClass = lines === 1 ? \"truncate\" : `line-clamp-${lines}`;\n const cell = <span ref={ref} className={cn(clampClass, \"block\")}>{children}</span>;\n if (!isTruncated) return cell;\n return <AutoTooltip content={children}>{cell}</AutoTooltip>;\n}\n\nexport interface DataGridProps<T> {\n data: T[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- public API: columns may carry any value type\n columns: ColumnDef<T, any>[];\n /**\n * Rows a page, over the project's (dataDisplay.itemsPerPage), for a grid the user asked to page differently. Leave it\n * out: the grid pages as the project says, with the project's control (Sprint 25.13 A5; it was 10).\n */\n pageSize?: number;\n /**\n * Cells edit in place, as the APG's grid (Sprint 25.13 A5): the grid is one Tab stop and the arrow keys move between\n * cells; Enter or F2 (or a double-click) opens a cell's editor, Enter or leaving it saves and Escape cancels, and a\n * brief tick, announced as \"Saved\", shows the save. A grid saves as you go, so it never marks a form around it.\n */\n editable?: boolean;\n /**\n * A saved edit: the row's index in `data`, the column's id and the new value (the text typed, or the column's\n * `meta.parse` of it). Called only when the value changed. Return a promise to have the tick and \"Saved\" wait for it:\n * a rejection is announced as \"Not saved\", and the page says why and keeps the old value.\n */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void | Promise<unknown>;\n /** The screen width below which the grid shows cards: the project's responsive.tableToCardsBreakpoint, else \"md\". */\n mobileBreakpoint?: BreakpointKey;\n /**\n * The grid's own width below which it shows cards when it doesn't fit, in px (Sprint 25.13 A35): about a phone's; 0\n * never switches by width. An editable grid never shows cards: it stays the APG's grid, scrolling sideways.\n */\n cardsBelow?: number;\n /**\n * The list's pager (Sprint 25.13 A3), from `usePagination(data)` over the same rows: pass it when the page also shows\n * the count (TableToolbar). Without it the grid pages itself the same way.\n */\n pager?: Pager<unknown>;\n /** The grid's name for assistive tech. */\n \"aria-label\"?: string;\n className?: string;\n}\n\n/** A cell of an editable grid: its row among those drawn (-1 for the header) and its column. */\ninterface CellAt { r: number; c: number }\nconst cellKey = (p: CellAt) => (p.r < 0 ? `h:${p.c}` : `${p.r}:${p.c}`);\n/** A cell by its row's id (null for the header), which a sort or a save that re-sorts never moves to another row. */\ninterface CellId { row: string | null; c: number }\n/** How long the saved tick shows, in ms (A5). */\nconst SAVED_TICK_MS = 1500;\n\nexport function DataGrid<T>({\n data,\n columns,\n pageSize,\n editable = false,\n onCellEdit,\n mobileBreakpoint: mobileBreakpointProp,\n cardsBelow = CARDS_BELOW,\n pager: pagerProp,\n \"aria-label\": ariaLabel,\n className,\n}: DataGridProps<T>) {\n // Sprint 25.14 A44: a grid draws its own frame, so a SplitView's list pane draws none around it\n useFramesItself();\n // Sprint 25.6 (B9): responsive.tableToCardsBreakpoint reaches the table through the shell; a prop wins; md outside any shell.\n const preferences = useShellPreferences();\n const mobileBreakpoint: BreakpointKey = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? \"md\";\n const narrowScreen = useBreakpoint(mobileBreakpoint);\n // A35: cards only on a narrow screen or where the grid's own width is a phone's. An editable grid stays the APG's grid\n // at every width, scrolling sideways: its cards have no editor (the review of 30 September: in a default Drawer, whose\n // body is 359 px, the grid went to cards and could no longer be edited).\n const { cards: isMobile, rootRef } = useCardsSwitch(editable ? false : narrowScreen, editable ? 0 : cardsBelow);\n const [sorting, setSorting] = useState<SortingState>([]);\n // the scroll area: a header or a cell the keyboard reaches is scrolled in whole, with its outline (Sprint 30, P3)\n const [scrollArea, setScrollArea] = useState<HTMLDivElement | null>(null);\n useRevealFocus(scrollArea);\n const [editing, setEditing] = useState<(CellId & { value: string; was: string }) | null>(null);\n\n /* ── Column kind inference ─────────────────────────────────────────── */\n const columnKeys = useMemo(() => columns.map((c) => c.id ?? (\"accessorKey\" in c ? String(c.accessorKey) : \"\")).filter(Boolean), [columns]);\n const inferredKinds = useMemo(\n () => inferColumnKinds(data as Record<string, unknown>[], columnKeys),\n [data, columnKeys],\n );\n const kindOf = useCallback(\n (colId: string, meta: DataGridColumnMeta | undefined) => meta?.kind ?? inferredKinds.get(colId),\n [inferredKinds],\n );\n\n // TanStack Table returns functions the React Compiler cannot memoise; the\n // compiler would skip this component, which is fine — the project does not\n // use it. The note is informational, not a defect.\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table is not compiler-compatible\n const table = useReactTable({\n data,\n columns,\n state: { sorting },\n onSortingChange: (updater) => { setSorting(updater); pagerProp?.setPage(1); },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n });\n\n // ── A5 / A3: the project's page size and list style, through the pager, over every row sorted ──\n const sortedRows = table.getRowModel().rows;\n const ownPager = usePagination(sortedRows, { pageSize, resetOn: sorting });\n const pager = pagerProp ?? ownPager;\n useWholeListCheck(\"DataGrid\", data.length, pagerProp);\n const rows = pagerPart(sortedRows, pager);\n const leafColumns = table.getVisibleLeafColumns();\n const headerText = (id: string) => {\n const header = leafColumns.find((c) => c.id === id)?.columnDef.header;\n return typeof header === \"string\" ? header : id;\n };\n\n // ── A5: the grid's keyboard (the APG's grid), when editable ──\n // The Tab stop, the editor and the saved tick are kept by the row's id, so a sort, or a save that re-sorts the rows,\n // keeps each on its row (the review of 30 September: the tick and the Tab stop went to the row now in the old place).\n const gridRef = useRef<HTMLTableElement>(null);\n const [activeId, setActiveId] = useState<CellId>({ row: null, c: 0 });\n const lastRow = rows.length - 1;\n const rowAt = (id: string | null) => (id === null ? -1 : rows.findIndex((row) => row.id === id));\n const idAt = (p: CellAt): CellId => ({ row: p.r < 0 ? null : rows[p.r]?.id ?? null, c: p.c });\n const current: CellAt = { r: Math.min(rowAt(activeId.row), lastRow), c: Math.min(activeId.c, Math.max(0, leafColumns.length - 1)) };\n const setActive = (p: CellAt) => setActiveId(idAt(p));\n const move = (p: CellAt, e: ReactKeyboardEvent): CellAt | null => {\n // Alt with an arrow is the browser's (Back, Forward), and Ctrl or ⌘ with one too; Ctrl or ⌘ with Home or End goes to\n // the grid's first or last cell (the APG's grid)\n if (e.altKey) return null;\n const toCorner = e.ctrlKey || e.metaKey;\n switch (e.key) {\n case \"ArrowRight\": return !toCorner && p.c < leafColumns.length - 1 ? { ...p, c: p.c + 1 } : null;\n case \"ArrowLeft\": return !toCorner && p.c > 0 ? { ...p, c: p.c - 1 } : null;\n case \"ArrowDown\": return !toCorner && p.r < lastRow ? { ...p, r: p.r + 1 } : null;\n case \"ArrowUp\": return !toCorner && p.r > -1 ? { ...p, r: p.r - 1 } : null;\n case \"Home\": return toCorner ? { r: -1, c: 0 } : { ...p, c: 0 };\n case \"End\": return toCorner ? { r: lastRow, c: leafColumns.length - 1 } : { ...p, c: leafColumns.length - 1 };\n default: return null;\n }\n };\n // an edit ends once: Enter saves and unmounts the editor, whose blur must not save it again\n const ended = useRef(false);\n const startEdit = (p: CellAt) => {\n const row = rows[p.r];\n const column = leafColumns[p.c];\n if (!row || !column || (column.columnDef.meta as DataGridColumnMeta | undefined)?.editable === false) return;\n ended.current = false;\n setActive(p);\n const text = String(row.getValue(column.id) ?? \"\");\n setEditing({ row: row.id, c: p.c, value: text, was: text });\n };\n const grid = useGridKeyboard<CellAt>({\n container: gridRef,\n active: current,\n setActive,\n keyOf: cellKey,\n move,\n onActivate: (p, e) => {\n if (p.r < 0) { if (leafColumns[p.c]?.getCanSort()) leafColumns[p.c].toggleSorting(); }\n else if (e.key === \"Enter\") startEdit(p);\n },\n modifierKeys: true,\n });\n const onGridKeyDown = (e: ReactKeyboardEvent) => {\n // F2 opens the cell's editor too (the APG's grid)\n if (e.key === \"F2\" && !editing && current.r >= 0 && e.target instanceof HTMLElement && e.target.getAttribute(\"data-grid-key\") === cellKey(current)) {\n e.preventDefault();\n startEdit(current);\n return;\n }\n grid.onKeyDown(e);\n };\n // the Tab stop follows focus, however it got there: a click, a screen reader's command, a double-click (the hook's\n // contract; the review of 30 September: a clicked cell took no Enter, and ArrowDown went from the header)\n const onGridFocus = (e: React.FocusEvent) => {\n const key = e.target instanceof HTMLElement ? e.target.getAttribute(\"data-grid-key\") : null;\n if (!key) return;\n const [r, c] = key.startsWith(\"h:\") ? [-1, Number(key.slice(2))] : key.split(\":\").map(Number);\n if (Number.isFinite(r) && Number.isFinite(c) && cellKey(current) !== key) setActive({ r, c });\n };\n\n // ── A5: the save, its tick and its announcement ──\n const [saved, setSaved] = useState<{ row: string; c: number; n: number; ok: boolean } | null>(null);\n useEffect(() => {\n if (!saved) return;\n const t = setTimeout(() => setSaved((s) => (s && s.n === saved.n ? null : s)), SAVED_TICK_MS);\n return () => clearTimeout(t);\n }, [saved]);\n const heard = useRef(0);\n // after Enter or Escape focus comes back to the cell, on its row wherever a save that re-sorts puts it: its page first\n const refocus = useRef<CellId | null>(null);\n useLayoutEffect(() => {\n const want = refocus.current;\n if (!want) return;\n const r = rowAt(want.row);\n if (r < 0) {\n const all = sortedRows.findIndex((row) => row.id === want.row);\n if (all >= 0 && pager.style === \"pagination\") { const page = Math.floor(all / pager.pageSize) + 1; if (page !== pager.page) { pager.setPage(page); return; } }\n refocus.current = null;\n return;\n }\n refocus.current = null;\n grid.focus({ r, c: want.c });\n });\n const finishEdit = (commit: boolean, focusBack: boolean) => {\n if (!editing || ended.current) return;\n ended.current = true;\n const r = rowAt(editing.row);\n const row = rows[r];\n const column = leafColumns[editing.c];\n const cell = { row: editing.row, c: editing.c };\n setEditing(null);\n // leaving the editor (a click elsewhere, Tab) saves and lets focus go where it went (the review of 30 September:\n // it pulled focus back, and the next keys were lost)\n if (focusBack) { setActiveId(cell); refocus.current = cell; }\n // a save that changes nothing isn't one\n if (!commit || !row || !column || editing.value === editing.was) return;\n const meta = column.columnDef.meta as DataGridColumnMeta | undefined;\n const done = (ok: boolean) => { heard.current += 1; setSaved({ ...cell, row: editing.row!, n: heard.current, ok }); };\n const result = onCellEdit?.(row.index, column.id, meta?.parse ? meta.parse(editing.value) : editing.value);\n if (result && typeof (result as Promise<unknown>).then === \"function\") (result as Promise<unknown>).then(() => done(true), () => done(false));\n else done(true);\n };\n\n // A3: the grid and its control are one element, as in 0.21, which takes the className: in a grid or a flex row they\n // stay one item (the review of 30 September: the control became an item of its own beside the grid)\n const control = data.length > 0 ? <Pagination {...pager.props} /> : null;\n const setRoot = (node: HTMLDivElement | null) => { rootRef.current = node; };\n const withControl = (list: ReactNode) => <div ref={setRoot} data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>{list}{control}</div>;\n\n if (isMobile) {\n return withControl(\n <div data-ds-list=\"\" className=\"space-y-ds-3\">\n <TableCardCtx value={true}><RowsCtx value={true}>\n <div className=\"flex flex-col gap-ds-3\">\n {rows.map((row) => (\n <div\n key={row.id}\n className={cn(\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]\",\n \"p-ds-4 space-y-ds-3\",\n )}\n >\n {row.getVisibleCells().map((cell) => (\n <div key={cell.id} className=\"flex justify-between gap-ds-2 text-sm\">\n <span className=\"shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider\">\n {typeof cell.column.columnDef.header === \"string\"\n ? cell.column.columnDef.header\n : cell.column.id}\n </span>\n <CardValue value={flexRender(cell.column.columnDef.cell, cell.getContext())} />\n </div>\n ))}\n </div>\n ))}\n </div>\n </RowsCtx></TableCardCtx>\n </div>\n );\n }\n\n const sortIcons = (sorted: false | \"asc\" | \"desc\") => (\n <span className=\"inline-flex flex-col -space-y-ds-1.5\" aria-hidden=\"true\">\n <Icon name=\"chevron-up\" size={10} className={sorted === \"asc\" ? \"text-[var(--ds-accent-ink)]\" : \"opacity-30\"} />\n <Icon name=\"chevron-down\" size={10} className={sorted === \"desc\" ? \"text-[var(--ds-accent-ink)]\" : \"opacity-30\"} />\n </span>\n );\n const headerCell = (header: Header<T, unknown>, c: number) => {\n const canSort = header.column.getCanSort();\n const sorted = header.column.getIsSorted();\n const meta = header.column.columnDef.meta as DataGridColumnMeta | undefined;\n const headerKind = kindOf(header.column.id, meta);\n const headerAlign = meta?.align ?? (headerKind === \"number\" ? \"right\" : \"left\");\n const shrink = (headerKind === \"number\" || headerKind === \"date\") && !meta?.maxWidth;\n const at = { r: -1, c };\n const label = flexRender(header.column.columnDef.header, header.getContext());\n // A47: a sortable header holds a button: a Tab stop in a read-only grid, a cell the arrows reach in an editable one\n const inside = canSort ? (\n <button\n type=\"button\"\n onClick={header.column.getToggleSortingHandler()}\n {...(editable ? { \"data-grid-key\": cellKey(at), tabIndex: grid.tabIndexOf(at) } : {})}\n className={cn(\n \"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none [font:inherit] text-inherit\",\n \"hover:text-[var(--ds-text-primary)] rounded-[var(--ds-radius-sm)]\",\n FOCUS_RING,\n )}\n >\n {label}\n {sortIcons(sorted)}\n </button>\n ) : label;\n return (\n <th\n key={header.id}\n role={editable ? \"columnheader\" : undefined}\n aria-sort={sorted === \"asc\" ? \"ascending\" : sorted === \"desc\" ? \"descending\" : undefined}\n {...(editable && !canSort ? { \"data-grid-key\": cellKey(at), tabIndex: grid.tabIndexOf(at) } : {})}\n className={cn(\n \"px-ds-4 py-ds-3 text-xs font-[var(--ds-weight-heading)] uppercase tracking-wider\",\n headerAlign === \"right\" ? \"text-right\" : headerAlign === \"center\" ? \"text-center\" : \"text-left\",\n shrink && \"w-px whitespace-nowrap\",\n \"text-[var(--ds-text-secondary)]\",\n FOCUS_INSET,\n )}\n style={meta?.maxWidth || meta?.width || meta?.minWidth ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth } : undefined}\n >\n <span className={cn(\"flex items-center gap-ds-1\", headerAlign === \"right\" && \"justify-end\", headerAlign === \"center\" && \"justify-center\")}>\n {inside}\n </span>\n </th>\n );\n };\n\n return withControl(\n <div data-ds-list=\"\" className=\"min-w-0\">\n <div\n ref={setScrollArea}\n // the scroll area the width switch reads (A35), as the Table's\n data-table-scroll=\"\"\n className={cn(\n \"relative w-full overflow-auto scroll-p-[4px] rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"shadow-[var(--ds-shadow-card)]\",\n \"bg-[var(--ds-bg-surface)]\",\n )}\n >\n <table\n ref={gridRef}\n role={editable ? \"grid\" : undefined}\n aria-label={ariaLabel}\n onKeyDown={editable ? onGridKeyDown : undefined}\n onFocus={editable ? onGridFocus : undefined}\n className=\"w-full text-sm\"\n >\n <thead className=\"bg-[var(--ds-bg-muted)]\">\n {table.getHeaderGroups().map((hg) => (\n <tr key={hg.id} role={editable ? \"row\" : undefined} className=\"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]\">\n {hg.headers.map((header, c) => headerCell(header, c))}\n </tr>\n ))}\n </thead>\n <tbody><RowsCtx value={true}>\n {rows.map((row, r) => (\n <tr\n key={row.id}\n role={editable ? \"row\" : undefined}\n className={cn(\n \"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0\",\n \"hover:bg-[var(--ds-bg-muted)] transition-colors\",\n )}\n >\n {row.getVisibleCells().map((cell, c) => {\n const meta = cell.column.columnDef.meta as DataGridColumnMeta | undefined;\n const truncLines = meta?.truncate === true ? 1 : meta?.truncate ? meta.truncate.lines : 0;\n const kind = kindOf(cell.column.id, meta);\n const rendered = flexRender(cell.column.columnDef.cell, cell.getContext() as CellContext<T, unknown>);\n const at = { r, c };\n const isEditing = editable && editing?.row === row.id && editing.c === c;\n\n const shrink = (kind === \"number\" || kind === \"date\") && !meta?.maxWidth;\n let inner: ReactNode;\n if (isEditing) {\n // the library's Input, named for its column; Enter or leaving it saves, Escape cancels. A grid saves as\n // you go, so its editor never marks a form around it; the cells' own controls still do (the review\n // of 30 September: the whole grid opted out, and a Drawer closed on a changed checkbox unasked)\n inner = (\n <FormChangeCtx value={null}>\n <Input\n size=\"sm\"\n autoFocus\n aria-label={headerText(cell.column.id)}\n // the value opens selected: typing replaces it, an arrow key keeps it\n onFocus={(e) => e.currentTarget.select()}\n value={editing.value}\n onChange={(e) => setEditing({ ...editing, value: e.target.value })}\n onBlur={() => finishEdit(true, false)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") { e.preventDefault(); finishEdit(true, true); }\n else if (e.key === \"Escape\") { e.preventDefault(); e.stopPropagation(); finishEdit(false, true); }\n }}\n />\n </FormChangeCtx>\n );\n } else if (truncLines > 0) {\n inner = <TruncCell lines={truncLines}>{rendered}</TruncCell>;\n } else if (kind === \"email\") {\n inner = (\n <span className=\"max-w-[40ch] truncate inline-block align-bottom\" title={typeof cell.getValue() === \"string\" ? cell.getValue() as string : undefined}>\n {rendered}\n </span>\n );\n } else {\n inner = rendered;\n }\n // Round 14 (50.2): a centred or right-aligned column lays a block element out with flex — text-align moves inline content only.\n const align = meta?.align ?? (kind === \"number\" ? \"right\" : \"left\");\n const value = cell.getValue();\n if (!isEditing && align !== \"left\" && typeof value !== \"string\" && typeof value !== \"number\" && value !== null && value !== undefined) {\n inner = <div className={cn(\"flex items-center\", align === \"center\" ? \"justify-center\" : \"justify-end\")}>{inner}</div>;\n }\n const tick = editable && saved?.ok && saved.row === row.id && saved.c === c\n ? <Icon name=\"check\" size={14} className=\"ml-ds-1 inline-block align-middle text-[var(--ds-status-success)]\" />\n : null;\n\n return (\n <td\n key={cell.id}\n // a double-click in the open editor selects a word, and never reopens it over what was typed\n {...(editable ? { role: \"gridcell\", \"data-grid-key\": cellKey(at), tabIndex: grid.tabIndexOf(at), onDoubleClick: () => { if (!isEditing) startEdit(at); } } : {})}\n className={cn(\n \"px-ds-4 py-ds-3 text-[var(--ds-text-primary)]\",\n align === \"right\" && \"text-right\",\n align === \"center\" && \"text-center\",\n shrink && \"w-px whitespace-nowrap\",\n editable && FOCUS_INSET,\n )}\n style={meta?.maxWidth || meta?.width || meta?.minWidth ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth } : undefined}\n >\n {inner}\n {tick}\n </td>\n );\n })}\n </tr>\n ))}\n </RowsCtx></tbody>\n </table>\n </div>\n {/* A5: a save is heard, politely (WCAG 4.1.3); each one is a new line, so two saves are heard twice */}\n {editable && <div role=\"status\" className=\"sr-only\"><span key={saved?.n ?? 0}>{saved ? (saved.ok ? \"Saved\" : \"Not saved\") : \"\"}</span></div>}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../showcase/src/components/DataGrid.tsx"],"names":[],"mappings":"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","file":"data-grid.js","sourcesContent":["import { useState, useCallback, useEffect, useLayoutEffect, useMemo, useRef, type ReactElement, type ReactNode, type SyntheticEvent, type KeyboardEvent as ReactKeyboardEvent } from \"react\";\nimport { useShellPreferences } from \"../lib/preferences\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n flexRender,\n type CellContext,\n type ColumnDef,\n type Header,\n type SortingState,\n} from \"@tanstack/react-table\";\nimport { cn, FOCUS_INSET, FOCUS_RING } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { CutCell, CutEmail } from \"./TextOverflow\";\nimport { Input } from \"./Input\";\nimport { NumberInput } from \"./NumberInput\";\nimport { DatePicker } from \"./DatePicker\";\nimport { Dropdown } from \"./Dropdown\";\nimport { Checkbox } from \"./Checkbox\";\nimport { Field } from \"./Field\";\nimport { Pagination } from \"./Pagination\";\nimport { useBreakpoint, type BreakpointKey } from \"../lib/use-breakpoint\";\nimport { useRevealFocus } from \"../lib/reveal-focus\";\nimport { inferColumnKinds, type ColumnKind } from \"../lib/table-utils\";\nimport { CardValue } from \"../lib/card-cell\";\nimport { TableCardCtx, RowsCtx, useFramesItself } from \"../lib/surface-context\";\nimport { FormChangeCtx } from \"../lib/form-context\";\nimport { focusInitial, useFocusLeave, useGridKeyboard } from \"../lib/focus\";\nimport { dayKey } from \"../lib/date-grid\";\nimport { SortIndicator } from \"../lib/sort-indicator\";\nimport { warnOnce } from \"../lib/dev-warn\";\nimport { usePagination, pagerPart, useWholeListCheck, type Pager } from \"../lib/use-pagination\";\nimport { CARDS_BELOW, useCardsSwitch } from \"../lib/use-cards-switch\";\n\n/** One of a choice column's options: the value its cells hold, and the words shown for it. */\nexport interface DataGridOption {\n value: string | number;\n label: string;\n}\n\n/** Column meta for opt-in truncation. Set on ColumnDef.meta. */\nexport interface DataGridColumnMeta {\n /** true = single-line, or { lines: N } for multi-line clamp. */\n truncate?: boolean | { lines: number };\n /** CSS max-width for the column. */\n maxWidth?: string;\n /** CSS width for the column — sibling grids that share a column set line up when their columns carry the same widths (round 14). */\n width?: string;\n /** CSS min-width for the column. */\n minWidth?: string;\n /**\n * Explicit column kind. When omitted the DataGrid infers it from data values (a yes or no too; never a choice). In an\n * editable grid it chooses the editor, where the control can hold the cell's value: \"number\" a NumberInput for a\n * number, \"date\" a DatePicker for a Date or an ISO date (\"2026-10-14\"), \"choice\" a Dropdown of `options`, \"boolean\" a\n * Checkbox; any other kind, and a number or a date written as text (\"18 KB\", \"12 Jan 2026\"), a text Input.\n */\n kind?: ColumnKind;\n /** Horizontal alignment of the header and the cells; a block element (a Checkbox, a Button) is laid out with flex so it follows too (round 14). Default: numbers right, everything else left. */\n align?: \"left\" | \"center\" | \"right\";\n /**\n * In an editable grid, whether this column's cells edit (default true); false for a column that shows (a status, a\n * calculated value, actions): its cells show no edit cue, and assistive tech hears them as read-only.\n */\n editable?: boolean;\n /**\n * A choice column's options (with `kind: \"choice\"`): its cells edit with a Dropdown of them, and a save gives the\n * option's `value`. Give the column a `cell` that shows the option's label.\n */\n options?: readonly DataGridOption[];\n /**\n * In an editable grid, the value onCellEdit gets from what was typed in a text cell, or in a number cell as its text\n * (default the text itself, or the number): a price written as text, `(text) => Number(text.replace(/[$,]/g, \"\"))`.\n * A date, a choice and a yes or no are given as their own values.\n */\n parse?: (text: string) => unknown;\n}\n\n/** The control a cell edits with (Sprint 25.8.7 item 19): its column's kind, where that control can hold the cell's value. */\ntype CellEditorKind = \"text\" | \"number\" | \"date\" | \"choice\" | \"boolean\";\n\n/** What an edit starts from: its control, the control's value, and how a saved value goes back in the cell's own form. */\ninterface EditorSetup {\n editor: CellEditorKind;\n value: unknown;\n out: (value: unknown) => unknown;\n}\n\nconst isEmpty = (v: unknown) => v === null || v === undefined || v === \"\";\nconst isDate = (v: unknown): v is Date => v instanceof Date && !Number.isNaN(v.getTime());\n/** An ISO date's text (\"2026-10-14\") as the local day it names, else null; the date grid's day key is the same text. */\nfunction isoDay(v: unknown): Date | null {\n const m = typeof v === \"string\" ? /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(v) : null;\n if (!m) return null;\n const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n return dayKey(d) === v ? d : null;\n}\n/** Two of an editor's values are one: a date by its time, anything else by itself. */\nconst sameValue = (a: unknown, b: unknown) => (isDate(a) && isDate(b) ? a.getTime() === b.getTime() : Object.is(a, b));\n\n/**\n * The editor for a cell. A control edits only a value it can hold: a NumberInput holds no empty cell and no \"18 KB\", a\n * DatePicker gives back no \"12 Jan 2026\", so those keep the text Input. A date goes back in the form it came: a Date,\n * keeping its time of day, or an ISO date's text; an empty cell's, as the column's first date is (a Date when it has\n * none).\n */\nfunction editorFor(kind: ColumnKind | undefined, raw: unknown, meta: DataGridColumnMeta | undefined, firstOfColumn: () => unknown): EditorSetup {\n const parse = meta?.parse;\n if (kind === \"choice\" && meta?.options?.length) return { editor: \"choice\", value: raw ?? null, out: (v) => v };\n if (kind === \"boolean\" && (typeof raw === \"boolean\" || isEmpty(raw))) return { editor: \"boolean\", value: raw === true, out: (v) => v };\n if (kind === \"number\" && typeof raw === \"number\" && Number.isFinite(raw)) return { editor: \"number\", value: raw, out: (v) => (parse ? parse(String(v)) : v) };\n if (kind === \"date\") {\n const was = isEmpty(raw) ? firstOfColumn() : raw;\n if (isDate(raw)) {\n return { editor: \"date\", value: raw, out: (v) => (isDate(v) ? new Date(v.getFullYear(), v.getMonth(), v.getDate(), raw.getHours(), raw.getMinutes(), raw.getSeconds(), raw.getMilliseconds()) : null) };\n }\n if (isoDay(was)) return { editor: \"date\", value: isoDay(raw), out: (v) => (isDate(v) ? dayKey(v) : null) };\n if (isEmpty(was) || isDate(was)) return { editor: \"date\", value: null, out: (v) => (isDate(v) ? v : null) };\n }\n return { editor: \"text\", value: String(raw ?? \"\"), out: (v) => (parse ? parse(v as string) : v) };\n}\n\n/**\n * A cell's editor (Sprint 25.8.7 item 19): the library's control for its column's kind, named for the column by a\n * hidden Field label. What is typed (text, a number, a date's parts) saves with Enter or by leaving the editor; a value\n * picked by a press (an option, a calendar's day, the box) is the edit, and saves at once; Escape, in the field or in\n * its popup, leaves the cell as it was. Leaving is the Field's own check (lib/focus.ts, useFocusLeave): focus moving\n * into the editor's popup, the Dropdown's list or the DatePicker's calendar, is not leaving it.\n */\nfunction CellEditor({ editor, value, name, options, onChange, onEnd }: {\n editor: CellEditorKind;\n value: unknown;\n name: string;\n options?: readonly DataGridOption[];\n onChange: (value: unknown) => void;\n onEnd: (save: boolean, focusBack: boolean, picked?: { value: unknown }) => void;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n // leaving the editor saves it and lets focus go where it went (the review of 30 September: it pulled focus back, and\n // the next keys were lost)\n const leave = useFocusLeave(() => onEnd(true, false));\n // a value chosen in a popup (the calendar's day, by a click or by Enter) is the edit itself. React passes the popup's\n // events up through its portal, so a key or a press from outside this editor's own box came from there. The flag is\n // where the latest one came from, never reset by a timer: Chrome runs a capture handler and the bubbling handler that\n // changes the value as separate listeners, with a microtask checkpoint between them\n const fromPopup = useRef(false);\n const markPopupEvent = (e: SyntheticEvent) => { fromPopup.current = !ref.current?.contains(e.target as Node); };\n const opened = useRef(false);\n useLayoutEffect(() => {\n const root = ref.current;\n if (!root) return;\n focusInitial(root);\n const el = document.activeElement;\n // the value opens selected: typing replaces it, an arrow key keeps it\n if (el instanceof HTMLInputElement && el.type === \"text\") el.select();\n // a choice opens on its list, the edit itself; once, though a development build runs this twice\n if (editor === \"choice\" && !opened.current && el instanceof HTMLButtonElement && root.contains(el)) {\n opened.current = true;\n el.click();\n }\n }, [editor]);\n // a choice and the box change only when picked, and a pick saves at once; what is typed or stepped (text, a number, a\n // date's parts) waits for Enter or for leaving the editor\n const picks = editor === \"choice\" || editor === \"boolean\";\n const change = (v: unknown) => (picks || fromPopup.current ? onEnd(true, true, { value: v }) : onChange(v));\n let control: ReactElement;\n if (editor === \"number\") control = <NumberInput size=\"sm\" value={value as number} allowDecimals onChange={change} />;\n else if (editor === \"date\") control = <DatePicker size=\"sm\" value={value as Date | null} onChange={change} />;\n else if (editor === \"boolean\") control = <Checkbox checked={value === true} onChange={(checked) => change(checked)} />;\n else if (editor === \"choice\" && options) {\n control = (\n <Dropdown\n size=\"sm\"\n options={options.map((o) => ({ id: String(o.value), label: o.label }))}\n value={value === null || value === undefined ? \"\" : String(value)}\n onChange={(id) => change(options.find((o) => String(o.value) === id)?.value ?? id)}\n />\n );\n } else control = <Input size=\"sm\" value={value as string} onChange={(e) => change(e.target.value)} />;\n return (\n <div\n ref={ref}\n data-cell-editor=\"\"\n {...leave}\n onClickCapture={markPopupEvent}\n onKeyDownCapture={markPopupEvent}\n onKeyDown={(e) => {\n // Escape, in the field or its popup, leaves the cell as it was, and goes no further: a Drawer round the grid stays\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n onEnd(false, true);\n return;\n }\n // Enter saves what was typed; on a button (the Dropdown's, the calendar's) it is the button's, which opens its\n // popup, and in the popup it picks\n if (e.key === \"Enter\" && e.currentTarget.contains(e.target as Node) && !(e.target instanceof HTMLButtonElement)) {\n e.preventDefault();\n onEnd(true, true);\n }\n }}\n >\n {/* a grid saves as you go, so its editor never marks a form around it; the cells' own controls still do (the\n review of 30 September: the whole grid opted out, and a Drawer closed on a changed checkbox unasked) */}\n <FormChangeCtx value={null}>\n <Field label={name} hideLabel>{control}</Field>\n </FormChangeCtx>\n </div>\n );\n}\n\n/**\n * Sprint 25.8.7 item 19 (collections-5): an editable cell says so before it is tried, a pencil shown while the cell is\n * hovered or focused (focused too: a touch screen has no hover); a calculated or locked cell shows none. It sits in room\n * an editable column keeps at its cells' end, header too, so a value never moves and a number stays under its header.\n */\nconst EDIT_CUE_ROOM = \"pr-[calc(var(--ds-space-4)+var(--ds-space-1)+12px)]\";\n\n/** How wide an editor sits over its cell: the cell's width inside its padding, and never less than its control needs. */\nconst EDITOR_WIDTH: Record<CellEditorKind, string> = {\n text: \"w-[max(calc(100%-var(--ds-space-4)),12rem)]\",\n number: \"w-[max(calc(100%-var(--ds-space-4)),8rem)]\",\n date: \"w-[max(calc(100%-var(--ds-space-4)),10.5rem)]\",\n choice: \"w-[max(calc(100%-var(--ds-space-4)),9rem)]\",\n boolean: \"w-auto\",\n};\n/**\n * The least an editable column of numbers, dates or choices is wide, at rest too: its editor's room and the cell's\n * padding, so the editor fits in its own cell and never covers the next one (a text column is wide by its words, and\n * a text editor may run over). A page's own width or min-width for the column wins.\n */\nconst EDITABLE_MIN_WIDTH: Partial<Record<CellEditorKind, string>> = { number: \"9rem\", date: \"11.5rem\", choice: \"10rem\" };\nfunction editableMinWidth(kind: ColumnKind | undefined, meta: DataGridColumnMeta | undefined): string | undefined {\n if (meta?.width || meta?.minWidth) return undefined;\n const editor: CellEditorKind | null = kind === \"number\" ? \"number\" : kind === \"date\" ? \"date\" : kind === \"choice\" && meta?.options?.length ? \"choice\" : null;\n return editor ? EDITABLE_MIN_WIDTH[editor] : undefined;\n}\nconst EDIT_CUE = (\n <span\n data-edit-cue=\"\"\n aria-hidden=\"true\"\n className={cn(\n \"pointer-events-none absolute top-1/2 -translate-y-1/2 right-ds-4 flex\",\n \"text-[var(--ds-text-muted)] opacity-0 transition-opacity duration-[var(--ds-transition-speed)]\",\n \"group-hover/cell:opacity-100 group-focus/cell:opacity-100\",\n )}\n >\n <Icon name=\"edit\" size={12} />\n </span>\n);\n\n\nexport interface DataGridProps<T> {\n data: T[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- public API: columns may carry any value type\n columns: ColumnDef<T, any>[];\n /**\n * Rows a page, over the project's (dataDisplay.itemsPerPage), for a grid the user asked to page differently. Leave it\n * out: the grid pages as the project says, with the project's control (Sprint 25.13 A5; it was 10).\n */\n pageSize?: number;\n /**\n * Cells edit in place, as the APG's grid (Sprint 25.13 A5): the grid is one Tab stop and the arrow keys move between\n * cells; Enter or F2 (or a double-click) opens a cell's editor, Enter or leaving it saves and Escape cancels, and a\n * brief tick, announced as \"Saved\", shows the save. A grid saves as you go, so it never marks a form around it.\n */\n editable?: boolean;\n /**\n * A saved edit: the row's index in `data`, the column's id and the new value (the text typed, or the column's\n * `meta.parse` of it). Called only when the value changed. Return a promise to have the tick and \"Saved\" wait for it:\n * a rejection is announced as \"Not saved\", and the page says why and keeps the old value.\n */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void | Promise<unknown>;\n /** The screen width below which the grid shows cards: the project's responsive.tableToCardsBreakpoint, else \"md\". */\n mobileBreakpoint?: BreakpointKey;\n /**\n * The grid's own width below which it shows cards when it doesn't fit, in px (Sprint 25.13 A35): about a phone's; 0\n * never switches by width. An editable grid never shows cards: it stays the APG's grid, scrolling sideways.\n */\n cardsBelow?: number;\n /**\n * The list's pager (Sprint 25.13 A3), from `usePagination(data)` over the same rows: pass it when the page also shows\n * the count (TableToolbar). Without it the grid pages itself the same way.\n */\n pager?: Pager<unknown>;\n /** The grid's name for assistive tech. */\n \"aria-label\"?: string;\n className?: string;\n}\n\n/** A cell of an editable grid: its row among those drawn (-1 for the header) and its column. */\ninterface CellAt { r: number; c: number }\nconst cellKey = (p: CellAt) => (p.r < 0 ? `h:${p.c}` : `${p.r}:${p.c}`);\n/** A cell by its row's id (null for the header), which a sort or a save that re-sorts never moves to another row. */\ninterface CellId { row: string | null; c: number }\n/** How long the saved tick shows, in ms (A5). */\nconst SAVED_TICK_MS = 1500;\n\nexport function DataGrid<T>({\n data,\n columns,\n pageSize,\n editable = false,\n onCellEdit,\n mobileBreakpoint: mobileBreakpointProp,\n cardsBelow = CARDS_BELOW,\n pager: pagerProp,\n \"aria-label\": ariaLabel,\n className,\n}: DataGridProps<T>) {\n // Sprint 25.14 A44: a grid draws its own frame, so a SplitView's list pane draws none around it\n useFramesItself();\n // Sprint 25.6 (B9): responsive.tableToCardsBreakpoint reaches the table through the shell; a prop wins; md outside any shell.\n const preferences = useShellPreferences();\n const mobileBreakpoint: BreakpointKey = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? \"md\";\n const narrowScreen = useBreakpoint(mobileBreakpoint);\n // A35: cards only on a narrow screen or where the grid's own width is a phone's. An editable grid stays the APG's grid\n // at every width, scrolling sideways: its cards have no editor (the review of 30 September: in a default Drawer, whose\n // body is 359 px, the grid went to cards and could no longer be edited).\n const { cards: isMobile, rootRef } = useCardsSwitch(editable ? false : narrowScreen, editable ? 0 : cardsBelow);\n const [sorting, setSorting] = useState<SortingState>([]);\n // the scroll area: a header or a cell the keyboard reaches is scrolled in whole, with its outline (Sprint 30, P3)\n const [scrollArea, setScrollArea] = useState<HTMLDivElement | null>(null);\n useRevealFocus(scrollArea);\n // the open editor (Sprint 25.8.7 item 19): its control, its value as the control holds it, and how a save gives it back\n const [editing, setEditing] = useState<(CellId & { editor: CellEditorKind; value: unknown; was: unknown; out: (value: unknown) => unknown }) | null>(null);\n\n /* ── Column kind inference ─────────────────────────────────────────── */\n const columnKeys = useMemo(() => columns.map((c) => c.id ?? (\"accessorKey\" in c ? String(c.accessorKey) : \"\")).filter(Boolean), [columns]);\n const inferredKinds = useMemo(\n () => inferColumnKinds(data as Record<string, unknown>[], columnKeys),\n [data, columnKeys],\n );\n const kindOf = useCallback(\n (colId: string, meta: DataGridColumnMeta | undefined) => meta?.kind ?? inferredKinds.get(colId),\n [inferredKinds],\n );\n\n // TanStack Table returns functions the React Compiler cannot memoise; the\n // compiler would skip this component, which is fine — the project does not\n // use it. The note is informational, not a defect.\n // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table is not compiler-compatible\n const table = useReactTable({\n data,\n columns,\n state: { sorting },\n onSortingChange: (updater) => { setSorting(updater); pagerProp?.setPage(1); },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n });\n\n // ── A5 / A3: the project's page size and list style, through the pager, over every row sorted ──\n const sortedRows = table.getRowModel().rows;\n const ownPager = usePagination(sortedRows, { pageSize, resetOn: sorting });\n const pager = pagerProp ?? ownPager;\n useWholeListCheck(\"DataGrid\", data.length, pagerProp);\n const rows = pagerPart(sortedRows, pager);\n const leafColumns = table.getVisibleLeafColumns();\n const headerText = (id: string) => {\n const header = leafColumns.find((c) => c.id === id)?.columnDef.header;\n return typeof header === \"string\" ? header : id;\n };\n // a column's kind chooses its editor: a choice needs its options, and options alone choose nothing (told in development)\n if (editable) {\n for (const column of leafColumns) {\n const meta = column.columnDef.meta as DataGridColumnMeta | undefined;\n if (meta?.kind === \"choice\" && !meta.options?.length) warnOnce(\"DataGrid\", `column \"${column.id}\" is a choice with no options, so it edits as text: give its meta the options its cells take.`);\n else if (meta?.options?.length && meta.kind !== \"choice\") warnOnce(\"DataGrid\", `column \"${column.id}\" has options but not the choice kind, so they go unused: give its meta kind \"choice\" to edit it with a Dropdown.`);\n }\n }\n\n // ── A5: the grid's keyboard (the APG's grid), when editable ──\n // The Tab stop, the editor and the saved tick are kept by the row's id, so a sort, or a save that re-sorts the rows,\n // keeps each on its row (the review of 30 September: the tick and the Tab stop went to the row now in the old place).\n const gridRef = useRef<HTMLTableElement>(null);\n const [activeId, setActiveId] = useState<CellId>({ row: null, c: 0 });\n const lastRow = rows.length - 1;\n const rowAt = (id: string | null) => (id === null ? -1 : rows.findIndex((row) => row.id === id));\n const idAt = (p: CellAt): CellId => ({ row: p.r < 0 ? null : rows[p.r]?.id ?? null, c: p.c });\n const current: CellAt = { r: Math.min(rowAt(activeId.row), lastRow), c: Math.min(activeId.c, Math.max(0, leafColumns.length - 1)) };\n const setActive = (p: CellAt) => setActiveId(idAt(p));\n const move = (p: CellAt, e: ReactKeyboardEvent): CellAt | null => {\n // Alt with an arrow is the browser's (Back, Forward), and Ctrl or ⌘ with one too; Ctrl or ⌘ with Home or End goes to\n // the grid's first or last cell (the APG's grid)\n if (e.altKey) return null;\n const toCorner = e.ctrlKey || e.metaKey;\n switch (e.key) {\n case \"ArrowRight\": return !toCorner && p.c < leafColumns.length - 1 ? { ...p, c: p.c + 1 } : null;\n case \"ArrowLeft\": return !toCorner && p.c > 0 ? { ...p, c: p.c - 1 } : null;\n case \"ArrowDown\": return !toCorner && p.r < lastRow ? { ...p, r: p.r + 1 } : null;\n case \"ArrowUp\": return !toCorner && p.r > -1 ? { ...p, r: p.r - 1 } : null;\n case \"Home\": return toCorner ? { r: -1, c: 0 } : { ...p, c: 0 };\n case \"End\": return toCorner ? { r: lastRow, c: leafColumns.length - 1 } : { ...p, c: leafColumns.length - 1 };\n default: return null;\n }\n };\n // an edit ends once: Enter saves and unmounts the editor, whose blur must not save it again\n const ended = useRef(false);\n const startEdit = (p: CellAt) => {\n const row = rows[p.r];\n const column = leafColumns[p.c];\n if (!row || !column || (column.columnDef.meta as DataGridColumnMeta | undefined)?.editable === false) return;\n // another cell's edit still open (its leave is told a moment after its blur) is left now, and saves\n if (editing && !(editing.row === row.id && editing.c === p.c)) finishEdit(true, false);\n ended.current = false;\n setActive(p);\n const meta = column.columnDef.meta as DataGridColumnMeta | undefined;\n // an empty date cell edits as the column's dates are held: the first of them, read only if it's needed\n const firstOfColumn = () => rows.map((x) => x.getValue(column.id)).find((v) => !isEmpty(v));\n const setup = editorFor(kindOf(column.id, meta), row.getValue(column.id), meta, firstOfColumn);\n setEditing({ row: row.id, c: p.c, editor: setup.editor, value: setup.value, was: setup.value, out: setup.out });\n };\n const grid = useGridKeyboard<CellAt>({\n container: gridRef,\n active: current,\n setActive,\n keyOf: cellKey,\n move,\n onActivate: (p, e) => {\n if (p.r < 0) { if (leafColumns[p.c]?.getCanSort()) leafColumns[p.c].toggleSorting(); }\n else if (e.key === \"Enter\") startEdit(p);\n },\n modifierKeys: true,\n });\n const onGridKeyDown = (e: ReactKeyboardEvent) => {\n // while a cell is edited its keys are its editor's, a button's arrows too: they never move to another cell (the\n // APG's grid, editing within a cell)\n if (e.target instanceof Element && e.target.closest(\"[data-cell-editor]\")) return;\n // F2 opens the cell's editor too (the APG's grid)\n if (e.key === \"F2\" && !editing && current.r >= 0 && e.target instanceof HTMLElement && e.target.getAttribute(\"data-grid-key\") === cellKey(current)) {\n e.preventDefault();\n startEdit(current);\n return;\n }\n grid.onKeyDown(e);\n };\n // the Tab stop follows focus, however it got there: a click, a screen reader's command, a double-click (the hook's\n // contract; the review of 30 September: a clicked cell took no Enter, and ArrowDown went from the header)\n const onGridFocus = (e: React.FocusEvent) => {\n const key = e.target instanceof HTMLElement ? e.target.getAttribute(\"data-grid-key\") : null;\n if (!key) return;\n const [r, c] = key.startsWith(\"h:\") ? [-1, Number(key.slice(2))] : key.split(\":\").map(Number);\n if (Number.isFinite(r) && Number.isFinite(c) && cellKey(current) !== key) setActive({ r, c });\n };\n\n // ── A5: the save, its tick and its announcement ──\n const [saved, setSaved] = useState<{ row: string; c: number; n: number; ok: boolean } | null>(null);\n useEffect(() => {\n if (!saved) return;\n const t = setTimeout(() => setSaved((s) => (s && s.n === saved.n ? null : s)), SAVED_TICK_MS);\n return () => clearTimeout(t);\n }, [saved]);\n const heard = useRef(0);\n // after Enter or Escape focus comes back to the cell, on its row wherever a save that re-sorts puts it: its page first\n const refocus = useRef<CellId | null>(null);\n useLayoutEffect(() => {\n const want = refocus.current;\n if (!want) return;\n const r = rowAt(want.row);\n if (r < 0) {\n const all = sortedRows.findIndex((row) => row.id === want.row);\n if (all >= 0 && pager.style === \"pagination\") { const page = Math.floor(all / pager.pageSize) + 1; if (page !== pager.page) { pager.setPage(page); return; } }\n refocus.current = null;\n return;\n }\n refocus.current = null;\n grid.focus({ r, c: want.c });\n });\n // `picked`: a value chosen by a press (an option, a day, the box), which is the edit itself and saves at once\n const finishEdit = (commit: boolean, focusBack: boolean, picked?: { value: unknown }) => {\n if (!editing || ended.current) return;\n ended.current = true;\n const r = rowAt(editing.row);\n const row = rows[r];\n const column = leafColumns[editing.c];\n const cell = { row: editing.row, c: editing.c };\n setEditing(null);\n // leaving the editor (a click elsewhere, Tab) saves and lets focus go where it went (the review of 30 September:\n // it pulled focus back, and the next keys were lost)\n if (focusBack) { setActiveId(cell); refocus.current = cell; }\n // a save that changes nothing isn't one\n const value = picked ? picked.value : editing.value;\n if (!commit || !row || !column || sameValue(value, editing.was)) return;\n const done = (ok: boolean) => { heard.current += 1; setSaved({ ...cell, row: editing.row!, n: heard.current, ok }); };\n const result = onCellEdit?.(row.index, column.id, editing.out(value));\n if (result && typeof (result as Promise<unknown>).then === \"function\") (result as Promise<unknown>).then(() => done(true), () => done(false));\n else done(true);\n };\n\n // A3: the grid and its control are one element, as in 0.21, which takes the className: in a grid or a flex row they\n // stay one item (the review of 30 September: the control became an item of its own beside the grid)\n const control = data.length > 0 ? <Pagination {...pager.props} /> : null;\n const setRoot = (node: HTMLDivElement | null) => { rootRef.current = node; };\n const withControl = (list: ReactNode) => <div ref={setRoot} data-gs-paged=\"\" className={cn(\"flex flex-col min-w-0\", className)}>{list}{control}</div>;\n\n if (isMobile) {\n return withControl(\n <div data-ds-list=\"\" className=\"space-y-ds-3\">\n <TableCardCtx value={true}><RowsCtx value={true}>\n <div className=\"flex flex-col gap-ds-3\">\n {rows.map((row) => (\n <div\n key={row.id}\n className={cn(\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]\",\n \"p-ds-4 space-y-ds-3\",\n )}\n >\n {row.getVisibleCells().map((cell) => (\n <div key={cell.id} className=\"flex justify-between gap-ds-2 text-sm\">\n <span className=\"shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider\">\n {typeof cell.column.columnDef.header === \"string\"\n ? cell.column.columnDef.header\n : cell.column.id}\n </span>\n <CardValue value={flexRender(cell.column.columnDef.cell, cell.getContext())} />\n </div>\n ))}\n </div>\n ))}\n </div>\n </RowsCtx></TableCardCtx>\n </div>\n );\n }\n\n const headerCell = (header: Header<T, unknown>, c: number) => {\n const canSort = header.column.getCanSort();\n const sorted = header.column.getIsSorted();\n const meta = header.column.columnDef.meta as DataGridColumnMeta | undefined;\n const headerKind = kindOf(header.column.id, meta);\n const headerAlign = meta?.align ?? (headerKind === \"number\" ? \"right\" : \"left\");\n const shrink = (headerKind === \"number\" || headerKind === \"date\") && !meta?.maxWidth;\n const at = { r: -1, c };\n const label = flexRender(header.column.columnDef.header, header.getContext());\n // A47: a sortable header holds a button: a Tab stop in a read-only grid, a cell the arrows reach in an editable one\n const inside = canSort ? (\n <button\n type=\"button\"\n onClick={header.column.getToggleSortingHandler()}\n {...(editable ? { \"data-grid-key\": cellKey(at), tabIndex: grid.tabIndexOf(at) } : {})}\n className={cn(\n \"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none [font:inherit] text-inherit\",\n \"hover:text-[var(--ds-text-primary)] rounded-[var(--ds-radius-sm)]\",\n // in a right-aligned column the indicator goes before the label, so the label ends where the column's values\n // end; the sorted column's label in full colour (the owner's choice at the look check, 14 October)\n headerAlign === \"right\" && \"flex-row-reverse\",\n sorted && \"text-[var(--ds-text-primary)]\",\n FOCUS_RING,\n )}\n >\n {label}\n <SortIndicator sorted={sorted} />\n </button>\n ) : label;\n return (\n <th\n key={header.id}\n role={editable ? \"columnheader\" : undefined}\n aria-sort={sorted === \"asc\" ? \"ascending\" : sorted === \"desc\" ? \"descending\" : undefined}\n {...(editable && !canSort ? { \"data-grid-key\": cellKey(at), tabIndex: grid.tabIndexOf(at) } : {})}\n className={cn(\n \"px-ds-4 py-ds-3 text-xs font-[var(--ds-weight-heading)] uppercase tracking-wider\",\n headerAlign === \"right\" ? \"text-right\" : headerAlign === \"center\" ? \"text-center\" : \"text-left\",\n shrink && \"w-px whitespace-nowrap\",\n \"text-[var(--ds-text-secondary)]\",\n FOCUS_INSET,\n // an editable column's cells keep room for their cue at their end (item 19): its header keeps the same\n editable && meta?.editable !== false && EDIT_CUE_ROOM,\n )}\n style={meta?.maxWidth || meta?.width || meta?.minWidth ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth } : undefined}\n >\n <span className={cn(\"flex items-center gap-ds-1\", headerAlign === \"right\" && \"justify-end\", headerAlign === \"center\" && \"justify-center\")}>\n {inside}\n </span>\n </th>\n );\n };\n\n return withControl(\n <div data-ds-list=\"\" className=\"min-w-0\">\n <div\n ref={setScrollArea}\n // the scroll area the width switch reads (A35), as the Table's\n data-table-scroll=\"\"\n className={cn(\n \"relative w-full overflow-auto scroll-p-[4px] rounded-[var(--ds-radius-md)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"shadow-[var(--ds-shadow-card)]\",\n \"bg-[var(--ds-bg-surface)]\",\n )}\n >\n <table\n ref={gridRef}\n role={editable ? \"grid\" : undefined}\n aria-label={ariaLabel}\n onKeyDown={editable ? onGridKeyDown : undefined}\n onFocus={editable ? onGridFocus : undefined}\n className=\"w-full text-sm\"\n >\n <thead className=\"bg-[var(--ds-bg-muted)]\">\n {table.getHeaderGroups().map((hg) => (\n <tr key={hg.id} role={editable ? \"row\" : undefined} className=\"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]\">\n {hg.headers.map((header, c) => headerCell(header, c))}\n </tr>\n ))}\n </thead>\n <tbody><RowsCtx value={true}>\n {rows.map((row, r) => (\n <tr\n key={row.id}\n role={editable ? \"row\" : undefined}\n className={cn(\n \"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0\",\n \"hover:bg-[var(--ds-bg-muted)] transition-colors\",\n )}\n >\n {row.getVisibleCells().map((cell, c) => {\n const meta = cell.column.columnDef.meta as DataGridColumnMeta | undefined;\n const truncLines = meta?.truncate === true ? 1 : meta?.truncate ? meta.truncate.lines : 0;\n const kind = kindOf(cell.column.id, meta);\n const rendered = flexRender(cell.column.columnDef.cell, cell.getContext() as CellContext<T, unknown>);\n const at = { r, c };\n const isEditing = editable && editing?.row === row.id && editing.c === c;\n\n const shrink = (kind === \"number\" || kind === \"date\") && !meta?.maxWidth;\n // Round 14 (50.2): a centred or right-aligned column lays a block element out with flex — text-align moves inline content only.\n const align = meta?.align ?? (kind === \"number\" ? \"right\" : \"left\");\n let inner: ReactNode;\n if (isEditing) {\n // the library's control for the column's kind, named for its column (CellEditor). The cell keeps its\n // size while it is edited: its value holds the room, unseen, and the editor sits over it, from the\n // cell's start (its end, in a right-aligned column), as wide as its control needs. So no column moves\n // and the row keeps its height (the look check's second round: a number's field had no room in its\n // narrow column, and a date's widened every column)\n inner = (\n <>\n <span aria-hidden=\"true\" className=\"invisible\">{rendered}</span>\n <div className={cn(\n \"absolute inset-y-0 z-30 flex items-center\", EDITOR_WIDTH[editing.editor],\n // from the cell's end in a right-aligned column, and in the last column, where an editor wider\n // than its cell would run past the grid's edge; over the cell before, it stays in view\n align === \"right\" || c === row.getVisibleCells().length - 1 ? \"right-ds-2\" : \"left-ds-2\",\n )}>\n <CellEditor\n editor={editing.editor}\n value={editing.value}\n name={headerText(cell.column.id)}\n options={meta?.options}\n onChange={(v) => setEditing({ ...editing, value: v })}\n onEnd={finishEdit}\n />\n </div>\n </>\n );\n } else if (truncLines > 0) {\n inner = <CutCell lines={truncLines}>{rendered}</CutCell>;\n } else if (kind === \"email\") {\n inner = <CutEmail>{rendered}</CutEmail>;\n } else {\n inner = rendered;\n }\n const value = cell.getValue();\n if (!isEditing && align !== \"left\" && typeof value !== \"string\" && typeof value !== \"number\" && value !== null && value !== undefined) {\n inner = <div className={cn(\"flex items-center\", align === \"center\" ? \"justify-center\" : \"justify-end\")}>{inner}</div>;\n }\n const tick = editable && saved?.ok && saved.row === row.id && saved.c === c\n ? <Icon name=\"check\" size={14} className=\"ml-ds-1 inline-block align-middle text-[var(--ds-status-success)]\" />\n : null;\n\n // item 19: an editable cell says so before it is tried; a calculated or locked one is read-only\n const edits = editable && meta?.editable !== false;\n const least = edits ? editableMinWidth(kind, meta) : undefined;\n return (\n <td\n key={cell.id}\n // a double-click in the open editor selects a word, and never reopens it over what was typed\n {...(editable ? { role: \"gridcell\", \"data-grid-key\": cellKey(at), tabIndex: grid.tabIndexOf(at), onDoubleClick: () => { if (!isEditing) startEdit(at); } } : {})}\n aria-readonly={editable && !edits ? true : undefined}\n className={cn(\n \"px-ds-4 py-ds-3 text-[var(--ds-text-primary)]\",\n align === \"right\" && \"text-right\",\n align === \"center\" && \"text-center\",\n shrink && \"w-px whitespace-nowrap\",\n editable && FOCUS_INSET,\n edits && cn(\"group/cell relative\", EDIT_CUE_ROOM),\n )}\n style={meta?.maxWidth || meta?.width || meta?.minWidth || least ? { maxWidth: meta?.maxWidth, width: meta?.width, minWidth: meta?.minWidth ?? least } : undefined}\n >\n {inner}\n {tick}\n {edits && !isEditing && EDIT_CUE}\n </td>\n );\n })}\n </tr>\n ))}\n </RowsCtx></tbody>\n </table>\n </div>\n {/* A5: a save is heard, politely (WCAG 4.1.3); each one is a new line, so two saves are heard twice */}\n {editable && <div role=\"status\" className=\"sr-only\"><span key={saved?.n ?? 0}>{saved ? (saved.ok ? \"Saved\" : \"Not saved\") : \"\"}</span></div>}\n </div>\n );\n}\n"]}