gridsmith-ui 0.29.0 → 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.
- package/CHANGELOG.md +79 -0
- package/README.md +5 -1
- package/dist/DropdownMenu-DqT7ZQ0D.d.ts +39 -0
- package/dist/charts.d.ts +5 -0
- package/dist/charts.js +5 -3
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +5 -5
- package/dist/{chunk-EIWXVICU.js → chunk-6A5RHW2W.js} +3 -3
- package/dist/{chunk-EIWXVICU.js.map → chunk-6A5RHW2W.js.map} +1 -1
- package/dist/{chunk-XVB55M3N.js → chunk-72SDAX54.js} +2 -2
- package/dist/chunk-72SDAX54.js.map +1 -0
- package/dist/{chunk-OYNUU346.js → chunk-7QLXYRPD.js} +3 -12
- package/dist/chunk-7QLXYRPD.js.map +1 -0
- package/dist/chunk-F2BNJSON.js +1348 -0
- package/dist/chunk-F2BNJSON.js.map +1 -0
- package/dist/{chunk-GXMTS3YD.js → chunk-GQVBZ4GW.js} +54 -16
- package/dist/chunk-GQVBZ4GW.js.map +1 -0
- package/dist/{chunk-2ROVDVLZ.js → chunk-INGF2CPW.js} +4 -23
- package/dist/chunk-INGF2CPW.js.map +1 -0
- package/dist/{chunk-66JJCQU3.js → chunk-JTU7OBYJ.js} +5 -3
- package/dist/chunk-JTU7OBYJ.js.map +1 -0
- package/dist/{chunk-DQCHCLEJ.js → chunk-KTPGMJUK.js} +6 -6
- package/dist/{chunk-DQCHCLEJ.js.map → chunk-KTPGMJUK.js.map} +1 -1
- package/dist/{chunk-TJEV7YAY.js → chunk-L6HWACK7.js} +7 -7
- package/dist/chunk-L6HWACK7.js.map +1 -0
- package/dist/chunk-LJYSVZMI.js +25 -0
- package/dist/chunk-LJYSVZMI.js.map +1 -0
- package/dist/{chunk-YUTF2X6B.js → chunk-NI5542ZM.js} +42 -38
- package/dist/chunk-NI5542ZM.js.map +1 -0
- package/dist/chunk-NKUCS67T.js +13 -0
- package/dist/chunk-NKUCS67T.js.map +1 -0
- package/dist/{chunk-TRDXWHD2.js → chunk-NLXQ323J.js} +6 -6
- package/dist/chunk-NLXQ323J.js.map +1 -0
- package/dist/{chunk-ZI3OQDET.js → chunk-OIOII5L6.js} +93 -4
- package/dist/chunk-OIOII5L6.js.map +1 -0
- package/dist/{chunk-R4GXKH4U.js → chunk-Q36JVJX4.js} +52 -93
- package/dist/chunk-Q36JVJX4.js.map +1 -0
- package/dist/{chunk-FD4YED7O.js → chunk-RHWTMTU5.js} +3 -3
- package/dist/{chunk-FD4YED7O.js.map → chunk-RHWTMTU5.js.map} +1 -1
- package/dist/chunk-TYNDXMBV.js +105 -0
- package/dist/chunk-TYNDXMBV.js.map +1 -0
- package/dist/{chunk-OPFJEL3Z.js → chunk-UNS4TGGK.js} +110 -20
- package/dist/chunk-UNS4TGGK.js.map +1 -0
- package/dist/chunk-Z4MCD73B.js +316 -0
- package/dist/chunk-Z4MCD73B.js.map +1 -0
- package/dist/{chunk-CRQ6KCRD.js → chunk-ZHUVLBCC.js} +7 -4
- package/dist/chunk-ZHUVLBCC.js.map +1 -0
- package/dist/data-grid.d.ts +26 -7
- package/dist/data-grid.js +179 -57
- package/dist/data-grid.js.map +1 -1
- package/dist/editor-mentions.js +3 -3
- package/dist/editor.js +5 -5
- package/dist/{feather-FNBQ74RR.js → feather-XFFEFLTV.js} +5 -3
- package/dist/feather-XFFEFLTV.js.map +1 -0
- package/dist/{heroicons-DODCSYWD.js → heroicons-L6DOHBEA.js} +5 -3
- package/dist/heroicons-L6DOHBEA.js.map +1 -0
- package/dist/icons.d.ts +10 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +174 -50
- package/dist/index.js +810 -1731
- package/dist/index.js.map +1 -1
- package/dist/kanban.d.ts +26 -8
- package/dist/kanban.js +203 -79
- package/dist/kanban.js.map +1 -1
- package/dist/{lucide-ZWE3EPGP.js → lucide-JOORDTO6.js} +5 -3
- package/dist/lucide-JOORDTO6.js.map +1 -0
- package/dist/{phosphor-DIHPA4AJ.js → phosphor-TKGDYNGR.js} +5 -3
- package/dist/phosphor-TKGDYNGR.js.map +1 -0
- package/dist/resizable.js +12 -11
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +14 -8
- package/dist/{table-utils-BkjNEWts.d.ts → table-utils-BXkP-2Hx.d.ts} +8 -5
- package/dist/{tabler-D3VYTSGI.js → tabler-YGETLYRU.js} +5 -3
- package/dist/tabler-YGETLYRU.js.map +1 -0
- package/dist/tokens.css +14 -0
- package/dist/{use-pagination-BxcRlNQG.d.ts → use-pagination-QykGSREv.d.ts} +7 -0
- package/dist/utils.js.map +1 -1
- package/dist/virtualized.d.ts +1 -1
- package/dist/virtualized.js +10 -9
- package/dist/virtualized.js.map +1 -1
- package/dist-static/tokens.css +14 -0
- package/package.json +1 -1
- package/dist/chunk-2ROVDVLZ.js.map +0 -1
- package/dist/chunk-66JJCQU3.js.map +0 -1
- package/dist/chunk-BRAXJEEP.js +0 -117
- package/dist/chunk-BRAXJEEP.js.map +0 -1
- package/dist/chunk-CRQ6KCRD.js.map +0 -1
- package/dist/chunk-GXMTS3YD.js.map +0 -1
- package/dist/chunk-OPFJEL3Z.js.map +0 -1
- package/dist/chunk-OYNUU346.js.map +0 -1
- package/dist/chunk-QM4SJKWV.js +0 -51
- package/dist/chunk-QM4SJKWV.js.map +0 -1
- package/dist/chunk-R4GXKH4U.js.map +0 -1
- package/dist/chunk-TJEV7YAY.js.map +0 -1
- package/dist/chunk-TRDXWHD2.js.map +0 -1
- package/dist/chunk-XVB55M3N.js.map +0 -1
- package/dist/chunk-YUTF2X6B.js.map +0 -1
- package/dist/chunk-ZI3OQDET.js.map +0 -1
- package/dist/feather-FNBQ74RR.js.map +0 -1
- package/dist/heroicons-DODCSYWD.js.map +0 -1
- package/dist/lucide-ZWE3EPGP.js.map +0 -1
- package/dist/phosphor-DIHPA4AJ.js.map +0 -1
- 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-
|
|
3
|
-
import { usePagination, useWholeListCheck, pagerPart, Pagination, Input } from './chunk-
|
|
4
|
-
import { useShellPreferences } from './chunk-
|
|
5
|
-
import './chunk-
|
|
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 {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
8
|
+
import { FormChangeCtx } from './chunk-72SDAX54.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-
|
|
12
|
-
import
|
|
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-
|
|
16
|
+
import { Icon, warnOnce } from './chunk-L6HWACK7.js';
|
|
15
17
|
import './chunk-HP7WUZPK.js';
|
|
16
18
|
import './chunk-WH2FUFAC.js';
|
|
17
|
-
import { cn, FOCUS_INSET, FOCUS_RING } from './chunk-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
27
|
-
|
|
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
|
|
117
|
-
|
|
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
|
-
|
|
186
|
-
|
|
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,
|
|
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
|
-
|
|
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__ */
|
|
314
|
-
|
|
315
|
-
{
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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(
|
|
454
|
+
inner = /* @__PURE__ */ jsx(CutCell, { lines: truncLines, children: rendered });
|
|
337
455
|
} else if (kind === "email") {
|
|
338
|
-
inner = /* @__PURE__ */ jsx(
|
|
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
|
package/dist/data-grid.js.map
CHANGED
|
@@ -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 { Tooltip } 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 <Tooltip content={children}>{cell}</Tooltip>;\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"]}
|