@rovula/ui 0.1.27 → 0.1.29

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 (77) hide show
  1. package/dist/cjs/bundle.css +513 -67
  2. package/dist/cjs/bundle.js +589 -589
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Avatar/Avatar.d.ts +1 -1
  5. package/dist/cjs/types/components/Avatar/Avatar.stories.d.ts +1 -1
  6. package/dist/cjs/types/components/Avatar/Avatar.styles.d.ts +1 -0
  7. package/dist/cjs/types/components/DataTable/DataTable.d.ts +195 -4
  8. package/dist/cjs/types/components/DataTable/DataTable.editing.d.ts +20 -0
  9. package/dist/cjs/types/components/DataTable/DataTable.editing.types.d.ts +145 -0
  10. package/dist/cjs/types/components/DataTable/DataTable.stories.d.ts +268 -6
  11. package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +22 -0
  12. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +4 -0
  13. package/dist/cjs/types/components/ScrollArea/ScrollArea.d.ts +3 -3
  14. package/dist/cjs/types/components/ScrollArea/ScrollArea.stories.d.ts +4 -0
  15. package/dist/cjs/types/components/Table/Table.d.ts +33 -3
  16. package/dist/cjs/types/components/Table/Table.stories.d.ts +86 -4
  17. package/dist/cjs/types/components/TextInput/TextInput.stories.d.ts +8 -0
  18. package/dist/cjs/types/components/TextInput/TextInput.styles.d.ts +1 -0
  19. package/dist/components/Avatar/Avatar.js +2 -1
  20. package/dist/components/Avatar/Avatar.styles.js +3 -0
  21. package/dist/components/Avatar/AvatarBase.js +1 -1
  22. package/dist/components/DataTable/DataTable.editing.js +385 -0
  23. package/dist/components/DataTable/DataTable.editing.types.js +1 -0
  24. package/dist/components/DataTable/DataTable.js +983 -50
  25. package/dist/components/DataTable/DataTable.stories.js +1077 -25
  26. package/dist/components/Dropdown/Dropdown.js +8 -6
  27. package/dist/components/ScrollArea/ScrollArea.js +2 -2
  28. package/dist/components/ScrollArea/ScrollArea.stories.js +68 -2
  29. package/dist/components/Table/Table.js +103 -13
  30. package/dist/components/Table/Table.stories.js +226 -9
  31. package/dist/components/TextInput/TextInput.js +6 -4
  32. package/dist/components/TextInput/TextInput.stories.js +8 -0
  33. package/dist/components/TextInput/TextInput.styles.js +7 -1
  34. package/dist/esm/bundle.css +513 -67
  35. package/dist/esm/bundle.js +1545 -1545
  36. package/dist/esm/bundle.js.map +1 -1
  37. package/dist/esm/types/components/Avatar/Avatar.d.ts +1 -1
  38. package/dist/esm/types/components/Avatar/Avatar.stories.d.ts +1 -1
  39. package/dist/esm/types/components/Avatar/Avatar.styles.d.ts +1 -0
  40. package/dist/esm/types/components/DataTable/DataTable.d.ts +195 -4
  41. package/dist/esm/types/components/DataTable/DataTable.editing.d.ts +20 -0
  42. package/dist/esm/types/components/DataTable/DataTable.editing.types.d.ts +145 -0
  43. package/dist/esm/types/components/DataTable/DataTable.stories.d.ts +268 -6
  44. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +22 -0
  45. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +4 -0
  46. package/dist/esm/types/components/ScrollArea/ScrollArea.d.ts +3 -3
  47. package/dist/esm/types/components/ScrollArea/ScrollArea.stories.d.ts +4 -0
  48. package/dist/esm/types/components/Table/Table.d.ts +33 -3
  49. package/dist/esm/types/components/Table/Table.stories.d.ts +86 -4
  50. package/dist/esm/types/components/TextInput/TextInput.stories.d.ts +8 -0
  51. package/dist/esm/types/components/TextInput/TextInput.styles.d.ts +1 -0
  52. package/dist/index.d.ts +493 -122
  53. package/dist/src/theme/global.css +762 -96
  54. package/package.json +14 -2
  55. package/src/components/Avatar/Avatar.styles.ts +4 -1
  56. package/src/components/Avatar/Avatar.tsx +3 -2
  57. package/src/components/Avatar/AvatarBase.tsx +3 -3
  58. package/src/components/DataTable/DataTable.editing.tsx +861 -0
  59. package/src/components/DataTable/DataTable.editing.types.ts +192 -0
  60. package/src/components/DataTable/DataTable.stories.tsx +2169 -31
  61. package/src/components/DataTable/DataTable.test.tsx +696 -0
  62. package/src/components/DataTable/DataTable.tsx +2260 -94
  63. package/src/components/Dropdown/Dropdown.tsx +22 -6
  64. package/src/components/ScrollArea/ScrollArea.stories.tsx +146 -3
  65. package/src/components/ScrollArea/ScrollArea.tsx +6 -6
  66. package/src/components/Table/Table.stories.tsx +789 -44
  67. package/src/components/Table/Table.tsx +294 -28
  68. package/src/components/TextInput/TextInput.stories.tsx +80 -0
  69. package/src/components/TextInput/TextInput.styles.ts +7 -1
  70. package/src/components/TextInput/TextInput.tsx +21 -14
  71. package/src/test/setup.ts +50 -0
  72. package/src/theme/global.css +81 -42
  73. package/src/theme/presets/colors.js +12 -0
  74. package/src/theme/themes/variable.css +27 -28
  75. package/src/theme/tokens/baseline.css +2 -1
  76. package/src/theme/tokens/components/scrollbar.css +9 -4
  77. package/src/theme/tokens/components/table.css +63 -0
@@ -1,70 +1,1003 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { flexRender, getCoreRowModel, getFilteredRowModel,
3
- // getPaginationRowModel,
4
- getSortedRowModel, useReactTable, } from "@tanstack/react-table";
5
- import { useEffect, useRef, useState } from "react";
6
- import { ArrowDownIcon, ArrowUpIcon, ArrowsUpDownIcon, ClipboardDocumentListIcon, } from "@heroicons/react/16/solid";
7
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../Table/Table";
8
- export function DataTable({ data, columns, manualSorting = false, onSorting, fetchMoreData, }) {
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
+ import { flexRender, getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table";
14
+ import React, { useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react";
15
+ import { useVirtualizer } from "@tanstack/react-virtual";
16
+ function columnMetaAlignClass(meta) {
17
+ switch (meta === null || meta === void 0 ? void 0 : meta.align) {
18
+ case "center":
19
+ return "text-center";
20
+ case "right":
21
+ return "text-right";
22
+ case "left":
23
+ return "text-left";
24
+ default:
25
+ return undefined;
26
+ }
27
+ }
28
+ /**
29
+ * Walk visible body cells left-to-right; when a column defines `meta.colSpan`,
30
+ * emit one `<td>` spanning that many columns and skip the covered cells.
31
+ */
32
+ function getVisibleCellsForRender(cells) {
33
+ const out = [];
34
+ let i = 0;
35
+ while (i < cells.length) {
36
+ const cell = cells[i];
37
+ const meta = cell.column.columnDef.meta;
38
+ let want = 1;
39
+ if ((meta === null || meta === void 0 ? void 0 : meta.colSpan) != null) {
40
+ const raw = typeof meta.colSpan === "function"
41
+ ? meta.colSpan(cell.row)
42
+ : meta.colSpan;
43
+ const n = Math.floor(Number(raw));
44
+ if (Number.isFinite(n) && n >= 1)
45
+ want = n;
46
+ }
47
+ const maxSpan = cells.length - i;
48
+ const colSpan = Math.min(want, maxSpan);
49
+ out.push({ cell, colSpan: Math.max(1, colSpan) });
50
+ i += Math.max(1, colSpan);
51
+ }
52
+ return out;
53
+ }
54
+ function renderDataTableBodyCells(opts) {
55
+ const { row, getSubRows, firstDataCellId, fixedColStyles, flexWidth, lockPxExactWidth, resizable, tableLayout, resizableSlackGrowColId, cellClassName, onCellClick, } = opts;
56
+ return getVisibleCellsForRender(row.getVisibleCells()).map(({ cell, colSpan }) => {
57
+ var _a;
58
+ const isFirstDataCell = Boolean(getSubRows) && cell.id === firstDataCellId(row);
59
+ const usePixelResizeWidth = resizable &&
60
+ tableLayout !== "equal" &&
61
+ !(resizableSlackGrowColId != null &&
62
+ cell.column.id === resizableSlackGrowColId);
63
+ return (_jsx(TableCell, { colSpan: colSpan > 1 ? colSpan : undefined, style: resolveBodyCellWidthStyle(cell.column.columnDef, fixedColStyles === null || fixedColStyles === void 0 ? void 0 : fixedColStyles.get(cell.column.id), flexWidth, lockPxExactWidth, usePixelResizeWidth ? cell.column.getSize() : undefined), className: cn(columnMetaAlignClass(cell.column.columnDef.meta), (_a = cell.column.columnDef.meta) === null || _a === void 0 ? void 0 : _a.cellClassName, cellClassName === null || cellClassName === void 0 ? void 0 : cellClassName(cell, row)), onClick: onCellClick
64
+ ? (e) => onCellClick(cell, row, e)
65
+ : undefined, children: isFirstDataCell ? (_jsxs("div", { className: "flex items-center gap-1", style: { paddingLeft: `${row.depth * 20}px` }, children: [row.getCanExpand() ? (_jsx("button", { type: "button", onClick: row.getToggleExpandedHandler(), className: "flex items-center justify-center size-5 rounded hover:bg-table-c-hover shrink-0 transition-colors", "aria-label": row.getIsExpanded() ? "Collapse" : "Expand", children: row.getIsExpanded() ? (_jsx(ChevronDown, { className: "size-4" })) : (_jsx(ChevronRight, { className: "size-4" })) })) : (_jsx("span", { className: "size-5 shrink-0" })), flexRender(cell.column.columnDef.cell, cell.getContext())] })) : (flexRender(cell.column.columnDef.cell, cell.getContext())) }, cell.id));
66
+ });
67
+ }
68
+ import * as Portal from "@radix-ui/react-portal";
69
+ import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, useSensors, } from "@dnd-kit/core";
70
+ import { restrictToVerticalAxis, restrictToParentElement, } from "@dnd-kit/modifiers";
71
+ import { SortableContext, arrayMove, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable";
72
+ import { CSS } from "@dnd-kit/utilities";
73
+ import { ArrowDown, ArrowUp, ArrowUpDown, ChevronDown, ChevronRight, ClipboardList, Columns3, EllipsisVertical, Equal, EyeOff, Loader2, } from "lucide-react";
74
+ import ActionButton from "@/components/ActionButton/ActionButton";
75
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/DropdownMenu/DropdownMenu";
76
+ import { Checkbox } from "../Checkbox/Checkbox";
77
+ import { Switch } from "../Switch/Switch";
78
+ import Button from "../Button/Button";
79
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TablePagination, TableRow, } from "../Table/Table";
80
+ import { cn } from "@/utils/cn";
81
+ import { EditContext, useDataTableEditing, resolveEditableColumns, detectEditableColumnIds, } from "./DataTable.editing";
82
+ // ---------------------------------------------------------------------------
83
+ // Checkbox column builder
84
+ // ---------------------------------------------------------------------------
85
+ function buildCheckboxColumn() {
86
+ return {
87
+ id: "__select__",
88
+ header: ({ table }) => (_jsx(Checkbox, { checked: table.getIsSomeRowsSelected()
89
+ ? "indeterminate"
90
+ : table.getIsAllRowsSelected(), onCheckedChange: (v) => table.toggleAllRowsSelected(!!v), "aria-label": "Select all" })),
91
+ cell: ({ row }) => (_jsx(Checkbox, { checked: row.getIsSelected(), onCheckedChange: (v) => row.toggleSelected(!!v), "aria-label": "Select row", disabled: !row.getCanSelect() })),
92
+ enableSorting: false,
93
+ enableHiding: false,
94
+ enableResizing: false,
95
+ size: 42,
96
+ maxSize: 42,
97
+ minSize: 42,
98
+ meta: { exactWidth: 42 },
99
+ };
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // Row-actions column builder
103
+ // ---------------------------------------------------------------------------
104
+ function buildActionsColumn(render) {
105
+ return {
106
+ id: "__actions__",
107
+ header: () => null,
108
+ cell: ({ row }) => (_jsx("div", { className: "flex items-center justify-center gap-1", children: render(row) })),
109
+ enableSorting: false,
110
+ enableHiding: false,
111
+ enableResizing: false,
112
+ size: 80,
113
+ maxSize: 80,
114
+ minSize: 80,
115
+ meta: { exactWidth: 80 },
116
+ };
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Row-reorder drag-handle column
120
+ // ---------------------------------------------------------------------------
121
+ function buildReorderColumn() {
122
+ return {
123
+ id: "__reorder__",
124
+ header: () => null,
125
+ cell: ({ row }) => _jsx(RowDragHandle, { rowId: row.id }),
126
+ enableSorting: false,
127
+ enableHiding: false,
128
+ enableResizing: false,
129
+ size: 54,
130
+ maxSize: 54,
131
+ minSize: 54,
132
+ meta: { exactWidth: 54 },
133
+ };
134
+ }
135
+ function RowDragHandle({ rowId }) {
136
+ const { attributes, listeners, setNodeRef, isDragging } = useSortable({
137
+ id: rowId,
138
+ });
139
+ return (_jsx(ActionButton, Object.assign({ ref: setNodeRef }, attributes, listeners, { variant: "icon", size: "sm", active: isDragging, className: cn("touch-none", isDragging ? "cursor-grabbing" : "cursor-grab"), "aria-label": "Drag to reorder", children: _jsx(Equal, { className: "!size-4" }) })));
140
+ }
141
+ // ---------------------------------------------------------------------------
142
+ // SortableTableRow — wraps a <TableRow> with dnd-kit sortable transform
143
+ // ---------------------------------------------------------------------------
144
+ function SortableTableRow(_a) {
145
+ var { id, children } = _a, props = __rest(_a, ["id", "children"]);
146
+ const { transform, transition, isDragging, setNodeRef } = useSortable({
147
+ id,
148
+ });
149
+ const style = {
150
+ transform: CSS.Transform.toString(transform ? Object.assign(Object.assign({}, transform), { scaleX: 1, scaleY: 1 }) : null),
151
+ transition,
152
+ opacity: isDragging ? 0.5 : 1,
153
+ position: "relative",
154
+ zIndex: isDragging ? 50 : undefined,
155
+ };
156
+ return (_jsx(TableRow, Object.assign({ ref: setNodeRef, style: style }, props, { children: children })));
157
+ }
158
+ const PINNED_START = ["__reorder__", "__select__"];
159
+ const PINNED_END = ["__actions__"];
160
+ /** Label for column-management menu (“Hide {name} column”). */
161
+ function manageColumnHeaderLabel(header) {
162
+ const h = header.column.columnDef.header;
163
+ return typeof h === "string" ? h : header.column.id;
164
+ }
165
+ /**
166
+ * If a column carries `meta.exactWidth`, return CSS that locks the cell to
167
+ * exactly that width. Accepts a number (px) or any CSS value / calc().
168
+ *
169
+ * Works in every `tableLayout` mode — `minWidth` + `maxWidth` constrain the
170
+ * cell even in `table-layout: auto` without requiring `table-fixed` on the
171
+ * table element. `overflow: hidden` prevents content from pushing wider.
172
+ */
173
+ function getExactWidthStyle(colDef, lock) {
174
+ var _a;
175
+ const w = (_a = colDef.meta) === null || _a === void 0 ? void 0 : _a.exactWidth;
176
+ if (w == null)
177
+ return undefined;
178
+ // Only "lock" when the value is safely lockable (number or px string).
179
+ // For `calc()`, `%`, `rem`, etc. we apply only `width` even in fixed mode,
180
+ // otherwise the column becomes rigid in ways that surprise callers.
181
+ const lockable = exactWidthToPx(w) != null;
182
+ const shouldLock = lock && lockable;
183
+ // Lockable = number or "123px" — set all three to that fixed width.
184
+ // Do NOT use `calc(100% - ${w}px)` here: that means “fill minus w”, not “width = w”.
185
+ const locked = typeof w === "number" ? `${w}px` : w.trim();
186
+ return shouldLock
187
+ ? {
188
+ width: locked,
189
+ minWidth: locked,
190
+ maxWidth: locked,
191
+ overflow: "hidden",
192
+ boxSizing: "border-box",
193
+ }
194
+ : {
195
+ width: w,
196
+ };
197
+ }
198
+ /**
199
+ * Convert `meta.exactWidth` to a numeric px value (only when possible).
200
+ * - `number` => px
201
+ * - `"123px"` => 123
202
+ * - other string formats => null (can't be summed at build time)
203
+ */
204
+ function exactWidthToPx(exactWidth) {
205
+ if (typeof exactWidth === "number") {
206
+ return Number.isFinite(exactWidth) ? exactWidth : null;
207
+ }
208
+ if (typeof exactWidth === "string") {
209
+ const m = exactWidth.trim().match(/^(-?\d*\.?\d+)\s*px$/i);
210
+ return m ? parseFloat(m[1]) : null;
211
+ }
212
+ return null;
213
+ }
214
+ /**
215
+ * Compute the auto-fill width for columns that do NOT have `exactWidth`.
216
+ * Formula: `calc((100% - <totalExactPx>px) / <flexCount>)`
217
+ *
218
+ * Only values convertible to numeric px participate in the subtraction.
219
+ */
220
+ function useFlexColumnWidth(table) {
221
+ return React.useMemo(() => {
222
+ var _a;
223
+ const visible = table.getVisibleLeafColumns();
224
+ let totalExactPx = 0;
225
+ let flexCount = 0;
226
+ for (const col of visible) {
227
+ const ew = (_a = col.columnDef.meta) === null || _a === void 0 ? void 0 : _a.exactWidth;
228
+ const asPx = exactWidthToPx(ew);
229
+ if (asPx != null) {
230
+ totalExactPx += asPx;
231
+ }
232
+ else if (ew == null) {
233
+ flexCount += 1;
234
+ }
235
+ }
236
+ if (flexCount === 0)
237
+ return undefined;
238
+ if (totalExactPx === 0)
239
+ return undefined;
240
+ return `calc((100% - ${totalExactPx}px) / ${flexCount})`;
241
+ }, [table.getVisibleLeafColumns()]);
242
+ }
243
+ /**
244
+ * Resolve the inline style for a **header** cell (th).
245
+ * - Has `exactWidth` → locked width (min/max/overflow)
246
+ * - `resizableWidth` (TanStack `getSize()`) → drag-resize width (`fixed`/`auto` only)
247
+ * - flexWidth available → equal calc() (`equal` + `resizable` uses this, not getSize)
248
+ * - Otherwise → fallback (e.g. fixed layout map or undefined)
249
+ */
250
+ function resolveHeaderWidthStyle(colDef, flexWidth, fallback, lockExactWidth, resizableWidth) {
251
+ const exact = getExactWidthStyle(colDef, lockExactWidth);
252
+ if (exact)
253
+ return exact;
254
+ if (resizableWidth != null) {
255
+ const colMax = colDef.maxSize;
256
+ return Object.assign({ width: resizableWidth }, (colMax != null &&
257
+ colMax !== Number.MAX_SAFE_INTEGER && { maxWidth: colMax }));
258
+ }
259
+ if (flexWidth)
260
+ return { width: flexWidth };
261
+ return fallback;
262
+ }
263
+ /**
264
+ * Resolve the inline style for a **body** cell (td).
265
+ * - Has `exactWidth` → locked width via min/maxWidth + overflow:hidden
266
+ * - `resizableWidth` (TanStack column `getSize()`) → matches header when resizable
267
+ * - fixedCellStyle available → "fixed" layout map
268
+ * - flexWidth available → equal calc()
269
+ * - Otherwise → undefined
270
+ */
271
+ function resolveBodyCellWidthStyle(colDef, fixedCellStyle, flexWidth, lockExactWidth, resizableWidth) {
272
+ const exact = getExactWidthStyle(colDef, lockExactWidth);
273
+ if (exact)
274
+ return exact;
275
+ if (resizableWidth != null) {
276
+ const colMax = colDef.maxSize;
277
+ return Object.assign({ width: resizableWidth }, (colMax != null &&
278
+ colMax !== Number.MAX_SAFE_INTEGER && { maxWidth: colMax }));
279
+ }
280
+ if (fixedCellStyle)
281
+ return fixedCellStyle;
282
+ if (flexWidth)
283
+ return { width: flexWidth };
284
+ return undefined;
285
+ }
286
+ function SortableColumnRow({ col, label, isLastVisible, showReorder, showVisibility, }) {
287
+ var _a;
288
+ const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging, } = useSortable({ id: col.id });
289
+ const style = {
290
+ transform: isDragging
291
+ ? `translateY(${(_a = transform === null || transform === void 0 ? void 0 : transform.y) !== null && _a !== void 0 ? _a : 0}px)`
292
+ : CSS.Transform.toString(transform),
293
+ transition: isDragging ? undefined : transition,
294
+ };
295
+ return (_jsxs("div", { ref: setNodeRef, style: style, className: cn("flex h-14 items-center gap-4 pl-6 pr-8 bg-modal-surface", "relative select-none", isDragging &&
296
+ "z-50 border border-primary-500/40 shadow-[0_8px_24px_-4px_rgba(0,0,0,0.24)] scale-[1.01]"), children: [showReorder && (_jsx(ActionButton, Object.assign({ ref: setActivatorNodeRef }, attributes, listeners, { variant: "icon", size: "sm", active: isDragging, "aria-label": `Drag to reorder ${label}`, className: cn("shrink-0 touch-none", isDragging ? "cursor-grabbing" : "cursor-grab"), children: _jsx(Equal, { className: "size-[14px]" }) }))), showVisibility && (_jsx(Switch, { checked: col.getIsVisible(), onCheckedChange: (v) => col.toggleVisibility(v), disabled: isLastVisible })), _jsx("span", { className: cn("flex-1 typography-subtitle4", isDragging ? "text-text-contrast-max" : "text-text-g-contrast-high"), children: label })] }));
297
+ }
298
+ function ManageColumnPanel({ table, onClose, maxListHeight = 400, options = {}, }) {
299
+ const { reorder = true, visibility = true, hideAll = true, showAll = true, } = options;
300
+ const hideable = table.getAllLeafColumns().filter((col) => col.getCanHide());
301
+ const visibleCount = hideable.filter((col) => col.getIsVisible()).length;
302
+ const headerLabel = (col) => {
303
+ const h = col.columnDef.header;
304
+ return typeof h === "string" ? h : col.id;
305
+ };
306
+ const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
307
+ coordinateGetter: sortableKeyboardCoordinates,
308
+ }));
309
+ const handleDragEnd = (event) => {
310
+ const { active, over } = event;
311
+ if (!over || active.id === over.id)
312
+ return;
313
+ const allColIds = table.getAllLeafColumns().map((c) => c.id);
314
+ const movable = allColIds.filter((id) => !PINNED_START.includes(id) &&
315
+ !PINNED_END.includes(id));
316
+ const oldIndex = movable.indexOf(active.id);
317
+ const newIndex = movable.indexOf(over.id);
318
+ if (oldIndex === -1 || newIndex === -1)
319
+ return;
320
+ const fixedStart = allColIds.filter((id) => PINNED_START.includes(id));
321
+ const fixedEnd = allColIds.filter((id) => PINNED_END.includes(id));
322
+ table.setColumnOrder([
323
+ ...fixedStart,
324
+ ...arrayMove(movable, oldIndex, newIndex),
325
+ ...fixedEnd,
326
+ ]);
327
+ };
328
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 px-6 pt-4 pb-3 border-b border-modal-line", children: [_jsx("span", { className: "flex-1 typography-subtitle3 text-text-contrast-max", children: "Manage column" }), hideAll && (_jsx(Button, { variant: "text", color: "secondary", size: "sm", disabled: visibleCount <= 1, onClick: () => {
329
+ var _a;
330
+ const firstVisible = (_a = hideable.find((col) => col.getIsVisible())) !== null && _a !== void 0 ? _a : hideable[0];
331
+ hideable.forEach((col) => col.toggleVisibility(col.id === firstVisible.id));
332
+ }, children: "Hide all" })), showAll && (_jsx(Button, { variant: "text", color: "primary", size: "sm", onClick: () => table.toggleAllColumnsVisible(true), children: "Show all" })), _jsx(Button, { variant: "outline", color: "primary", size: "sm", onClick: onClose, children: "Done" })] }), _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, modifiers: [restrictToVerticalAxis, restrictToParentElement], onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: hideable.map((c) => c.id), strategy: verticalListSortingStrategy, children: _jsx("div", { className: "overflow-y-auto ui-scrollbar", style: { maxHeight: maxListHeight }, children: hideable.map((col) => (_jsx(SortableColumnRow, { col: col, label: headerLabel(col), isLastVisible: col.getIsVisible() && visibleCount === 1, showReorder: reorder, showVisibility: visibility }, col.id))) }) }) })] }));
333
+ }
334
+ // ---------------------------------------------------------------------------
335
+ // DataTable
336
+ // ---------------------------------------------------------------------------
337
+ export function DataTable({ data, columns, manualSorting = false, onSorting, paginationMode = "infinite", totalCount, pageIndex: controlledPageIndex, pageSize: controlledPageSize, onPaginationChange, pageSizeOptions, fetchMoreData, fetchMoreOffset, fetchingMore = false, fetchingMoreLabel = "Loading more…", loading = false, loadingLabel = "Loading…", highlightRowId, scrollToHighlightOnMouseLeave = false, selectable = false, onRowSelectionChange, rowActions, reorderable = false, getRowId: getRowIdProp, onRowReorder, isRowReorderLocked, onRowClick, onCellClick, getSubRows, defaultExpanded, expanded: controlledExpanded, onExpandedChange, bordered = true, surface = "default", striped = false, divided = true, rowClassName, cellClassName, headerCellClassName, headerClassName, headerRowClassName, sortIndicatorVisibility = "hover", tableLayout = "auto", columnManagement: columnManagementProp = false, resizable = false, columnMinSize = 60, columnMaxSize = Number.MAX_SAFE_INTEGER, virtualized = false, virtualRowEstimate, className, enableEditing = false, editDisplayMode = "cell", editTrigger = "click", onCellCommit, alwaysEditing, enableCellTabTraversal, editableColumnIds: editableColumnIdsProp, testId, }) {
9
338
  var _a;
10
- const tableBodyRef = useRef(null);
339
+ // scrollable container ref — lives on the wrapper div, not tbody
340
+ const scrollRef = useRef(null);
341
+ const tableHeaderRef = useRef(null);
342
+ const userInteractingRef = useRef(false);
343
+ /** Suppresses marking user scroll during highlight-driven `scrollTo` / `scrollIntoView`. */
344
+ const programmaticScrollLockRef = useRef(0);
345
+ const [stickyHeaderHeight, setStickyHeaderHeight] = useState(48);
346
+ const scheduleProgrammaticScrollEnd = useCallback(() => {
347
+ const el = scrollRef.current;
348
+ let settled = false;
349
+ const unlock = () => {
350
+ if (settled)
351
+ return;
352
+ settled = true;
353
+ programmaticScrollLockRef.current = Math.max(0, programmaticScrollLockRef.current - 1);
354
+ };
355
+ el === null || el === void 0 ? void 0 : el.addEventListener("scrollend", unlock, { once: true });
356
+ window.setTimeout(unlock, 550);
357
+ }, []);
358
+ const virtualMeasureRowElement = useCallback((element, entry, instance) => {
359
+ var _a, _b;
360
+ const direction = instance.scrollDirection;
361
+ if (direction === "forward" || direction === null) {
362
+ const box = (_a = entry === null || entry === void 0 ? void 0 : entry.borderBoxSize) === null || _a === void 0 ? void 0 : _a[0];
363
+ if (box) {
364
+ return Math.round(box.blockSize);
365
+ }
366
+ return Math.round(element.getBoundingClientRect().height);
367
+ }
368
+ const raw = element.getAttribute("data-index");
369
+ const indexKey = raw != null ? Number.parseInt(raw, 10) : NaN;
370
+ const cache = instance.measurementsCache;
371
+ const cached = Number.isFinite(indexKey) && (cache === null || cache === void 0 ? void 0 : cache[indexKey])
372
+ ? cache[indexKey].size
373
+ : undefined;
374
+ if (typeof cached === "number") {
375
+ return cached;
376
+ }
377
+ const box = (_b = entry === null || entry === void 0 ? void 0 : entry.borderBoxSize) === null || _b === void 0 ? void 0 : _b[0];
378
+ if (box) {
379
+ return Math.round(box.blockSize);
380
+ }
381
+ return Math.round(element.getBoundingClientRect().height);
382
+ }, []);
383
+ // Normalize columnManagement: boolean | options → boolean + options object
384
+ const columnManagement = !!columnManagementProp;
385
+ const columnManagementOptions = typeof columnManagementProp === "object" ? columnManagementProp : {};
386
+ // ---- state ----
11
387
  const [sorting, setSorting] = useState([]);
12
388
  const [columnFilters, setColumnFilters] = useState([]);
13
389
  const [columnVisibility, setColumnVisibility] = useState({});
390
+ const [columnOrder, setColumnOrder] = useState([]);
391
+ const [columnSizing, setColumnSizing] = useState({});
392
+ const [columnSizingInfo, setColumnSizingInfo] = useState({
393
+ startOffset: null,
394
+ startSize: null,
395
+ deltaOffset: null,
396
+ deltaPercentage: null,
397
+ isResizingColumn: false,
398
+ columnSizingStart: [],
399
+ });
14
400
  const [rowSelection, setRowSelection] = useState({});
15
- const table = useReactTable({
16
- data,
401
+ const [internalExpanded, setInternalExpanded] = useState((_a = defaultExpanded) !== null && _a !== void 0 ? _a : {});
402
+ // Controlled: use prop directly every render; uncontrolled: use internal state
403
+ const isExpandedControlled = controlledExpanded !== undefined;
404
+ const expanded = isExpandedControlled ? controlledExpanded : internalExpanded;
405
+ const [pagination, setPagination] = useState({
406
+ pageIndex: controlledPageIndex !== null && controlledPageIndex !== void 0 ? controlledPageIndex : 0,
407
+ pageSize: controlledPageSize !== null && controlledPageSize !== void 0 ? controlledPageSize : 10,
408
+ });
409
+ // ---- column-management panel state (lifted here so hiding a column doesn't unmount it) ----
410
+ const [manageOpen, setManageOpen] = useState(false);
411
+ const [manageAnchorId, setManageAnchorId] = useState(null);
412
+ const [columnManageMenuOpenId, setColumnManageMenuOpenId] = useState(null);
413
+ const [managePanelPos, setManagePanelPos] = useState({ top: 0, right: 0, maxListHeight: 400 });
414
+ const manageMenuTriggerRef = useRef(new Map());
415
+ const openManagePanelAt = useCallback((colId, anchorRect) => {
416
+ const PANEL_W = 460;
417
+ const MARGIN = 8;
418
+ setColumnManageMenuOpenId(null);
419
+ const idealRight = window.innerWidth - anchorRect.right;
420
+ const right = Math.min(Math.max(idealRight, MARGIN), window.innerWidth - PANEL_W - MARGIN);
421
+ const top = anchorRect.bottom + MARGIN;
422
+ const maxListHeight = Math.max(80, window.innerHeight - top - 80);
423
+ setManagePanelPos({ top, right, maxListHeight });
424
+ setManageAnchorId(colId);
425
+ setManageOpen(true);
426
+ }, []);
427
+ // Close manage panel on Escape
428
+ useEffect(() => {
429
+ if (!manageOpen)
430
+ return;
431
+ const onKey = (e) => {
432
+ if (e.key === "Escape")
433
+ setManageOpen(false);
434
+ };
435
+ document.addEventListener("keydown", onKey);
436
+ return () => document.removeEventListener("keydown", onKey);
437
+ }, [manageOpen]);
438
+ // Sync controlled pagination (server mode)
439
+ useEffect(() => {
440
+ if (paginationMode === "server") {
441
+ setPagination({
442
+ pageIndex: controlledPageIndex !== null && controlledPageIndex !== void 0 ? controlledPageIndex : 0,
443
+ pageSize: controlledPageSize !== null && controlledPageSize !== void 0 ? controlledPageSize : 10,
444
+ });
445
+ }
446
+ }, [paginationMode, controlledPageIndex, controlledPageSize]);
447
+ // ---- editing engine ----
448
+ const editableColIds = React.useMemo(() => editableColumnIdsProp !== null && editableColumnIdsProp !== void 0 ? editableColumnIdsProp : (enableEditing
449
+ ? detectEditableColumnIds(columns)
450
+ : []), [enableEditing, editableColumnIdsProp, columns]);
451
+ const editingState = useDataTableEditing({
452
+ enabled: enableEditing,
453
+ editDisplayMode,
454
+ editTrigger,
455
+ editableColumnIds: editableColIds,
456
+ });
457
+ // ---- build final columns ----
458
+ const finalColumns = React.useMemo(() => {
459
+ let cols;
460
+ if (enableEditing) {
461
+ cols = resolveEditableColumns(columns, {
462
+ editing: editingState,
463
+ onCellCommit: onCellCommit,
464
+ alwaysEditing: alwaysEditing,
465
+ enableCellTabTraversal: enableCellTabTraversal !== null && enableCellTabTraversal !== void 0 ? enableCellTabTraversal : true,
466
+ editableColumnIds: editableColIds,
467
+ });
468
+ }
469
+ else {
470
+ cols = [...columns];
471
+ }
472
+ if (reorderable)
473
+ cols.unshift(buildReorderColumn());
474
+ if (selectable)
475
+ cols.unshift(buildCheckboxColumn());
476
+ if (rowActions)
477
+ cols.push(buildActionsColumn(rowActions));
478
+ return cols;
479
+ }, [
17
480
  columns,
18
- manualSorting,
19
- onSortingChange: setSorting,
20
- onColumnFiltersChange: setColumnFilters,
21
- getCoreRowModel: getCoreRowModel(),
22
- // getPaginationRowModel: getPaginationRowModel(),
23
- getSortedRowModel: getSortedRowModel(),
24
- getFilteredRowModel: getFilteredRowModel(),
25
- onColumnVisibilityChange: setColumnVisibility,
26
- onRowSelectionChange: setRowSelection,
27
- state: {
28
- sorting,
481
+ selectable,
482
+ reorderable,
483
+ rowActions,
484
+ enableEditing,
485
+ editingState,
486
+ onCellCommit,
487
+ alwaysEditing,
488
+ enableCellTabTraversal,
489
+ ]);
490
+ // ---- table instance ----
491
+ const isPaginated = paginationMode === "client" || paginationMode === "server";
492
+ const table = useReactTable(Object.assign(Object.assign(Object.assign(Object.assign({ data, columns: finalColumns, columnResizeMode: "onChange", defaultColumn: {
493
+ minSize: columnMinSize,
494
+ maxSize: columnMaxSize,
495
+ } }, (getRowIdProp
496
+ ? { getRowId: (row) => getRowIdProp(row) }
497
+ : { getRowId: (row) => row.id })), { manualSorting, manualPagination: paginationMode === "server", rowCount: paginationMode === "server" ? totalCount !== null && totalCount !== void 0 ? totalCount : data.length : undefined, getSubRows, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onColumnVisibilityChange: setColumnVisibility, onColumnOrderChange: setColumnOrder, onColumnSizingChange: setColumnSizing, onColumnSizingInfoChange: setColumnSizingInfo, onRowSelectionChange: setRowSelection, onExpandedChange: (updater) => {
498
+ const next = typeof updater === "function" ? updater(expanded) : updater;
499
+ if (!isExpandedControlled)
500
+ setInternalExpanded(next);
501
+ onExpandedChange === null || onExpandedChange === void 0 ? void 0 : onExpandedChange(next);
502
+ }, onPaginationChange: (updater) => {
503
+ const next = typeof updater === "function" ? updater(pagination) : updater;
504
+ setPagination(next);
505
+ onPaginationChange === null || onPaginationChange === void 0 ? void 0 : onPaginationChange(next);
506
+ }, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), getExpandedRowModel: getExpandedRowModel() }), (isPaginated ? { getPaginationRowModel: getPaginationRowModel() } : {})), { enableRowSelection: selectable, enableColumnResizing: resizable, state: Object.assign({ sorting,
29
507
  columnFilters,
30
508
  columnVisibility,
509
+ columnOrder,
510
+ columnSizing,
511
+ columnSizingInfo,
31
512
  rowSelection,
32
- // pagination: {
33
- // pageSize: 100,
34
- // pageIndex: 0,
35
- // },
36
- },
37
- });
513
+ expanded }, (isPaginated ? { pagination } : {})) }));
514
+ /** Body row order: sortable rows follow header sort; locked rows stay at the bottom. */
515
+ const tableRowsForView = React.useMemo(() => {
516
+ const rows = table.getRowModel().rows;
517
+ if (!isRowReorderLocked)
518
+ return rows;
519
+ const locked = rows.filter((r) => isRowReorderLocked(r));
520
+ const unlocked = rows.filter((r) => !isRowReorderLocked(r));
521
+ if (locked.length === 0)
522
+ return rows;
523
+ const order = new Map(data.map((row, index) => [
524
+ getRowIdProp
525
+ ? getRowIdProp(row)
526
+ : String(row.id),
527
+ index,
528
+ ]));
529
+ locked.sort((a, b) => { var _a, _b; return ((_a = order.get(a.id)) !== null && _a !== void 0 ? _a : 0) - ((_b = order.get(b.id)) !== null && _b !== void 0 ? _b : 0); });
530
+ return [...unlocked, ...locked];
531
+ }, [table.getRowModel().rows, isRowReorderLocked, data, getRowIdProp]);
532
+ // ---- side-effects ----
38
533
  useEffect(() => {
39
534
  onSorting === null || onSorting === void 0 ? void 0 : onSorting(sorting);
40
535
  }, [sorting, onSorting]);
41
536
  useEffect(() => {
537
+ onRowSelectionChange === null || onRowSelectionChange === void 0 ? void 0 : onRowSelectionChange(rowSelection);
538
+ }, [rowSelection, onRowSelectionChange]);
539
+ // Infinite scroll — listener on the wrapper div
540
+ useEffect(() => {
541
+ if (paginationMode !== "infinite")
542
+ return;
543
+ const el = scrollRef.current;
544
+ if (!el)
545
+ return;
42
546
  const handleScroll = () => {
43
- if (tableBodyRef.current) {
44
- const { scrollTop, scrollHeight, clientHeight } = tableBodyRef.current;
45
- if (scrollTop + clientHeight >= scrollHeight - 10) {
46
- fetchMoreData === null || fetchMoreData === void 0 ? void 0 : fetchMoreData();
47
- }
547
+ if (programmaticScrollLockRef.current > 0)
548
+ return;
549
+ // Do not set userInteractingRef here: programmatic highlight scroll (often
550
+ // `behavior: "smooth"`) emits many scroll events after the programmatic
551
+ // lock unlocks, which would flip userInteracting and block the next follow.
552
+ // Pause is handled only via wheel / pointer when scrollToHighlightOnMouseLeave.
553
+ const { scrollTop, scrollHeight, clientHeight } = el;
554
+ if (fetchingMore || loading)
555
+ return;
556
+ const offset = typeof fetchMoreOffset === "number" ? fetchMoreOffset : 10;
557
+ if (scrollTop + clientHeight >= scrollHeight - offset) {
558
+ fetchMoreData === null || fetchMoreData === void 0 ? void 0 : fetchMoreData();
48
559
  }
49
560
  };
50
- const tableBodyElement = tableBodyRef.current;
51
- if (tableBodyElement) {
52
- tableBodyElement.addEventListener("scroll", handleScroll);
561
+ el.addEventListener("scroll", handleScroll);
562
+ return () => el.removeEventListener("scroll", handleScroll);
563
+ }, [paginationMode, fetchMoreData, fetchingMore, loading, fetchMoreOffset]);
564
+ const isEmpty = tableRowsForView.length === 0;
565
+ // Virtualizer row offsets must match scroll coordinates: tbody starts below <thead>.
566
+ useLayoutEffect(() => {
567
+ if (!virtualized)
568
+ return;
569
+ const el = tableHeaderRef.current;
570
+ if (!el)
571
+ return;
572
+ const update = () => {
573
+ setStickyHeaderHeight(Math.round(el.getBoundingClientRect().height));
574
+ };
575
+ update();
576
+ const ro = new ResizeObserver(update);
577
+ ro.observe(el);
578
+ return () => ro.disconnect();
579
+ }, [virtualized]);
580
+ const scrollHighlightIntoViewRef = useRef(() => { });
581
+ const hadVirtualScrollSizeRef = useRef(false);
582
+ const rowVirtualizer = useVirtualizer({
583
+ count: virtualized ? tableRowsForView.length : 0,
584
+ getScrollElement: () => scrollRef.current,
585
+ estimateSize: () => virtualRowEstimate !== null && virtualRowEstimate !== void 0 ? virtualRowEstimate : 40,
586
+ overscan: 4,
587
+ // Offsets must include sticky thead height so item.start matches document offsets inside the scrollport.
588
+ paddingStart: virtualized ? stickyHeaderHeight : 0,
589
+ scrollPaddingStart: 0,
590
+ measureElement: virtualMeasureRowElement,
591
+ onChange: () => {
592
+ var _a, _b;
593
+ if (!virtualized || !highlightRowId)
594
+ return;
595
+ const h = (_b = (_a = scrollRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) !== null && _b !== void 0 ? _b : 0;
596
+ if (h < 1) {
597
+ hadVirtualScrollSizeRef.current = false;
598
+ return;
599
+ }
600
+ if (hadVirtualScrollSizeRef.current)
601
+ return;
602
+ hadVirtualScrollSizeRef.current = true;
603
+ requestAnimationFrame(() => {
604
+ if (userInteractingRef.current)
605
+ return;
606
+ scrollHighlightIntoViewRef.current("auto");
607
+ });
608
+ },
609
+ });
610
+ const scrollHighlightIntoView = useCallback((behavior = "smooth") => {
611
+ var _a, _b;
612
+ if (!highlightRowId)
613
+ return;
614
+ if (userInteractingRef.current)
615
+ return;
616
+ const container = scrollRef.current;
617
+ if (!container)
618
+ return;
619
+ const ids = Array.isArray(highlightRowId)
620
+ ? highlightRowId
621
+ : [highlightRowId];
622
+ // Virtualized: off-screen rows are not in the DOM, so querySelector fails.
623
+ // Drive scroll via the virtualizer so the target row mounts, then DOM path can fine-tune if needed.
624
+ if (virtualized) {
625
+ void rowVirtualizer.getTotalSize();
626
+ for (const id of ids) {
627
+ const idx = tableRowsForView.findIndex((r) => r.id === id);
628
+ if (idx !== -1) {
629
+ // `scrollToIndex({ align: "center" })` aligns item *start* to viewport center
630
+ // in TanStack Virtual; also thead was throwing off scroll coords — use
631
+ // paddingStart + explicit center of row in the scrollport.
632
+ const estimate = virtualRowEstimate !== null && virtualRowEstimate !== void 0 ? virtualRowEstimate : 40;
633
+ const startOffset = rowVirtualizer.getOffsetForIndex(idx, "start");
634
+ if (!startOffset)
635
+ continue;
636
+ const [scrollTopAlignStart] = startOffset;
637
+ const vzWithCache = rowVirtualizer;
638
+ const measured = (_b = (_a = vzWithCache.measurementsCache) === null || _a === void 0 ? void 0 : _a[idx]) === null || _b === void 0 ? void 0 : _b.size;
639
+ const rowH = typeof measured === "number" ? measured : estimate;
640
+ const target = scrollTopAlignStart + rowH / 2 - container.clientHeight / 2;
641
+ programmaticScrollLockRef.current += 1;
642
+ scheduleProgrammaticScrollEnd();
643
+ rowVirtualizer.scrollToOffset(Math.max(0, target), {
644
+ align: "start",
645
+ behavior: behavior === "smooth" ? "smooth" : "auto",
646
+ });
647
+ return;
648
+ }
649
+ }
650
+ return;
53
651
  }
54
- return () => {
55
- if (tableBodyElement) {
56
- tableBodyElement.removeEventListener("scroll", handleScroll);
652
+ for (const id of ids) {
653
+ const rowEl = container.querySelector(`[data-row-id="${id}"]`);
654
+ if (rowEl) {
655
+ programmaticScrollLockRef.current += 1;
656
+ scheduleProgrammaticScrollEnd();
657
+ rowEl.scrollIntoView({ block: "center", behavior });
658
+ break;
57
659
  }
660
+ }
661
+ }, [
662
+ highlightRowId,
663
+ tableRowsForView,
664
+ virtualized,
665
+ rowVirtualizer,
666
+ virtualRowEstimate,
667
+ stickyHeaderHeight,
668
+ scheduleProgrammaticScrollEnd,
669
+ ]);
670
+ scrollHighlightIntoViewRef.current = scrollHighlightIntoView;
671
+ // Allow one onChange retry when the highlight target or virtualization toggles
672
+ // (e.g. scrollport height was 0 on first layout).
673
+ useLayoutEffect(() => {
674
+ hadVirtualScrollSizeRef.current = false;
675
+ }, [virtualized, highlightRowId]);
676
+ // Scroll to highlighted row(s) when the value changes (e.g. user picks one).
677
+ // When `scrollToHighlightOnMouseLeave` is set, auto-scroll is skipped while
678
+ // `userInteractingRef` is true (wheel / pointer on table only; not raw scroll).
679
+ useLayoutEffect(() => {
680
+ scrollHighlightIntoView("smooth");
681
+ }, [virtualized, scrollHighlightIntoView, highlightRowId]);
682
+ // ---- pagination bar props ----
683
+ const paginationBarProps = {
684
+ pageIndex: pagination.pageIndex,
685
+ pageSize: pagination.pageSize,
686
+ totalCount: paginationMode === "server"
687
+ ? totalCount !== null && totalCount !== void 0 ? totalCount : data.length
688
+ : table.getFilteredRowModel().rows.length,
689
+ pageSizeOptions,
690
+ onPageChange: (idx) => table.setPagination((prev) => (Object.assign(Object.assign({}, prev), { pageIndex: idx }))),
691
+ onPageSizeChange: (size) => table.setPagination({ pageIndex: 0, pageSize: size }),
692
+ };
693
+ const computedFlexWidth = useFlexColumnWidth(table);
694
+ const flexWidth = tableLayout === "equal" ? computedFlexWidth : undefined;
695
+ const fixedColStyles = React.useMemo(() => {
696
+ if (tableLayout !== "fixed")
697
+ return null;
698
+ const cols = table.getVisibleLeafColumns();
699
+ const isPxExactCol = (col) => {
700
+ var _a;
701
+ const ew = (_a = col.columnDef.meta) === null || _a === void 0 ? void 0 : _a.exactWidth;
702
+ return exactWidthToPx(ew) != null;
58
703
  };
59
- }, [fetchMoreData]);
60
- const isEmpty = ((_a = table.getRowModel().rows) === null || _a === void 0 ? void 0 : _a.length) === 0;
61
- return (_jsx("div", { className: "flex w-full h-full rounded-xl overflow-hidden border border-primary-10", children: _jsxs(Table, { className: isEmpty ? "h-full" : "", rootRef: tableBodyRef, children: [_jsx(TableHeader, { className: "sticky top-0", children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: "", children: headerGroup.headers.map((header, i) => {
62
- var _a;
63
- return (_jsx(TableHead, { children: _jsxs("div", { className: "flex flex-row items-center cursor-pointer", onClick: header.column.getToggleSortingHandler(), children: [header.isPlaceholder
64
- ? null
65
- : flexRender(header.column.columnDef.header, header.getContext()), (_a = {
66
- asc: _jsx(ArrowUpIcon, { className: "ml-3 h-4 w-4" }),
67
- desc: _jsx(ArrowDownIcon, { className: "ml-3 h-4 w-4" }),
68
- }[header.column.getIsSorted()]) !== null && _a !== void 0 ? _a : (header.column.getCanSort() ? (_jsx(ArrowsUpDownIcon, { className: "ml-3 h-4 w-4 text-text-g-contrast-high" })) : null)] }) }, header.id));
69
- }) }, headerGroup.id))) }), _jsx(TableBody, { className: "overflow-y-scroll", children: !isEmpty ? (table.getRowModel().rows.map((row) => (_jsx(TableRow, { "data-state": row.getIsSelected() && "selected", className: "", children: row.getVisibleCells().map((cell) => (_jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id)))) : (_jsx(TableRow, { className: "h-full self-stretch", children: _jsx(TableCell, { colSpan: columns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full", children: _jsxs("div", { className: "flex flex-1 h-full flex-col items-center justify-center gap-3", children: [_jsx(ClipboardDocumentListIcon, { className: "w-8 text-secondary-120" }), "There is no information yet."] }) }) })) })] }) }));
704
+ // Full-width table + honour `size` as px: lock every non-exact column to
705
+ // its `size`, except the last “flex” column which absorbs leftover width
706
+ // (avoids `calc()` on every <col>/<th> browsers often distribute badly).
707
+ const flexColIndices = cols
708
+ .map((c, i) => (!isPxExactCol(c) ? i : -1))
709
+ .filter((i) => i >= 0);
710
+ const growColIndex = flexColIndices.length > 0
711
+ ? flexColIndices[flexColIndices.length - 1]
712
+ : -1;
713
+ const map = new Map();
714
+ cols.forEach((col, index) => {
715
+ var _a, _b, _c;
716
+ if (isPxExactCol(col))
717
+ return;
718
+ if (index === growColIndex) {
719
+ // No entry → <col> has no width; cell styles omit width — column grows.
720
+ return;
721
+ }
722
+ const colSize = (_c = (_a = col.columnDef.size) !== null && _a !== void 0 ? _a : (_b = col.getSize) === null || _b === void 0 ? void 0 : _b.call(col)) !== null && _c !== void 0 ? _c : 150;
723
+ const px = typeof colSize === "number"
724
+ ? colSize
725
+ : Number.isFinite(parseFloat(String(colSize)))
726
+ ? parseFloat(String(colSize))
727
+ : 150;
728
+ map.set(col.id, {
729
+ width: `${px}px`,
730
+ minWidth: `${px}px`,
731
+ maxWidth: `${px}px`,
732
+ overflow: "hidden",
733
+ boxSizing: "border-box",
734
+ });
735
+ });
736
+ return map;
737
+ }, [tableLayout, table.getVisibleLeafColumns()]);
738
+ /**
739
+ * When `resizable` + `table-layout: fixed`, the table is often wider than
740
+ * `getTotalSize()` (`max(100%, …)`). Browsers then redistribute slack across
741
+ * *all* columns — even `<col>` + `th` locked to 42px can visually grow.
742
+ * Pick one non-exact column to absorb slack (empty `<col>`, no pixel width on
743
+ * cells) like the non-resizable `fixed` “grow” column. Not used for `equal`
744
+ * — there we leave non-exact `<col>`s empty and use `flexWidth` on cells only.
745
+ */
746
+ const resizableSlackGrowColId = React.useMemo(() => {
747
+ var _a, _b;
748
+ if (!resizable || tableLayout === "equal")
749
+ return null;
750
+ const cols = table.getVisibleLeafColumns();
751
+ const flexIndices = cols
752
+ .map((c, i) => {
753
+ var _a;
754
+ const ew = (_a = c.columnDef.meta) === null || _a === void 0 ? void 0 : _a.exactWidth;
755
+ return exactWidthToPx(ew) == null ? i : -1;
756
+ })
757
+ .filter((i) => i >= 0);
758
+ if (flexIndices.length === 0)
759
+ return null;
760
+ return (_b = (_a = cols[flexIndices[flexIndices.length - 1]]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
761
+ }, [resizable, tableLayout, table.getVisibleLeafColumns()]);
762
+ // Helper: find the first data cell (not checkbox/actions) for expand toggle
763
+ const firstDataCellId = (row) => {
764
+ var _a;
765
+ return (_a = row
766
+ .getVisibleCells()
767
+ .find((c) => c.column.id !== "__select__" &&
768
+ c.column.id !== "__actions__" &&
769
+ c.column.id !== "__reorder__")) === null || _a === void 0 ? void 0 : _a.id;
770
+ };
771
+ // ---- row reorder (drag-and-drop) ----
772
+ const rowReorderSensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
773
+ coordinateGetter: sortableKeyboardCoordinates,
774
+ }));
775
+ const rowIds = React.useMemo(() => tableRowsForView.filter((r) => !(isRowReorderLocked === null || isRowReorderLocked === void 0 ? void 0 : isRowReorderLocked(r))).map((r) => r.id), [tableRowsForView, isRowReorderLocked]);
776
+ const handleRowDragEnd = (event) => {
777
+ const { active, over } = event;
778
+ if (!over || active.id === over.id || !onRowReorder)
779
+ return;
780
+ const oldIndex = data.findIndex((item) => (getRowIdProp
781
+ ? getRowIdProp(item)
782
+ : item.id) === active.id);
783
+ const newIndex = data.findIndex((item) => (getRowIdProp
784
+ ? getRowIdProp(item)
785
+ : item.id) === over.id);
786
+ if (oldIndex === -1 || newIndex === -1)
787
+ return;
788
+ onRowReorder(arrayMove([...data], oldIndex, newIndex));
789
+ };
790
+ // `resizable` uses `table-layout: fixed`; without min/max on `meta.exactWidth`
791
+ // (e.g. __select__), those columns absorb extra table width even when inline
792
+ // `width: 42px` is set. Lock px-based exactWidth whenever fixed layout applies.
793
+ const lockPxExactWidth = tableLayout === "fixed" || resizable;
794
+ const showColumnMenuVisibility = columnManagement && columnManagementOptions.visibility !== false;
795
+ const visibleHideableLeafCount = columnManagement
796
+ ? table
797
+ .getAllLeafColumns()
798
+ .filter((c) => c.getCanHide() && c.getIsVisible()).length
799
+ : 0;
800
+ // ---- render ----
801
+ const editContextValue = enableEditing ? editingState : null;
802
+ return (_jsx(EditContext.Provider, { value: editContextValue, children: _jsxs("div", { className: cn("flex flex-col w-full h-full min-h-0", bordered && "overflow-hidden rounded-md border border-table-c-border", !bordered && "overflow-hidden rounded-none", className), "data-surface": surface === "panel" ? "panel" : undefined, "data-testid": testId, children: [_jsx("div", { ref: scrollRef, className: cn("relative min-h-0 overflow-auto", "ui-scrollbar ui-scrollbar-x-m ui-scrollbar-y-s", isPaginated ? "flex-1" : "h-full"), onWheel: scrollToHighlightOnMouseLeave
803
+ ? () => {
804
+ userInteractingRef.current = true;
805
+ }
806
+ : undefined, onPointerDownCapture: scrollToHighlightOnMouseLeave
807
+ ? () => {
808
+ userInteractingRef.current = true;
809
+ }
810
+ : undefined, onMouseLeave: scrollToHighlightOnMouseLeave
811
+ ? () => {
812
+ userInteractingRef.current = false;
813
+ scrollHighlightIntoView("smooth");
814
+ }
815
+ : undefined, children: _jsxs(Table, { scrollableWrapper: false, className: cn((tableLayout === "fixed" ||
816
+ tableLayout === "equal" ||
817
+ resizable) &&
818
+ "table-fixed", isEmpty && "h-full"), style: resizable
819
+ ? {
820
+ // At least full scroll width, but grow when column sum exceeds it.
821
+ width: `max(100%, ${table.getTotalSize()}px)`,
822
+ }
823
+ : { width: "100%" }, children: [tableLayout === "fixed" && !resizable && (_jsx("colgroup", { children: table.getVisibleLeafColumns().map((col) => {
824
+ const colDef = col.columnDef;
825
+ const exact = getExactWidthStyle(colDef, lockPxExactWidth);
826
+ const style = exact !== null && exact !== void 0 ? exact : fixedColStyles === null || fixedColStyles === void 0 ? void 0 : fixedColStyles.get(col.id);
827
+ return _jsx("col", { style: style }, col.id);
828
+ }) })), resizable && (_jsx("colgroup", { children: table.getVisibleLeafColumns().map((col) => {
829
+ const colDef = col.columnDef;
830
+ const exact = getExactWidthStyle(colDef, lockPxExactWidth);
831
+ if (exact)
832
+ return _jsx("col", { style: exact }, col.id);
833
+ // Equal: only lock exact cols; flex columns share via flexWidth on th/td.
834
+ if (tableLayout === "equal")
835
+ return _jsx("col", {}, col.id);
836
+ if (resizableSlackGrowColId != null &&
837
+ col.id === resizableSlackGrowColId) {
838
+ return _jsx("col", {}, col.id);
839
+ }
840
+ return _jsx("col", { style: { width: col.getSize() } }, col.id);
841
+ }) })), _jsx(TableHeader, { ref: tableHeaderRef, className: cn("sticky top-0 z-10", headerClassName), "data-testid": testId ? `${testId}-thead` : undefined, children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { divided: false, colDivided: divided, className: cn("hover:bg-transparent", headerRowClassName), children: headerGroup.headers.map((header) => {
842
+ var _a;
843
+ const canSort = header.column.getCanSort();
844
+ const isSorted = header.column.getIsSorted();
845
+ const showManage = columnManagement && header.column.getCanHide();
846
+ const canResize = resizable &&
847
+ tableLayout !== "equal" &&
848
+ header.column.getCanResize();
849
+ const isResizing = header.column.getIsResizing();
850
+ const fixedFallback = !resizable && fixedColStyles
851
+ ? fixedColStyles.get(header.column.id)
852
+ : undefined;
853
+ const usePixelResizeWidth = resizable &&
854
+ tableLayout !== "equal" &&
855
+ !(resizableSlackGrowColId != null &&
856
+ header.column.id === resizableSlackGrowColId);
857
+ const headerStyle = resolveHeaderWidthStyle(header.column.columnDef, flexWidth, fixedFallback, lockPxExactWidth, usePixelResizeWidth ? header.getSize() : undefined);
858
+ return (_jsxs(TableHead, { colSpan: header.colSpan, style: headerStyle, className: cn("relative overflow-visible group/col", isResizing && "select-none", (_a = header.column.columnDef.meta) === null || _a === void 0 ? void 0 : _a.headerCellClassName, headerCellClassName === null || headerCellClassName === void 0 ? void 0 : headerCellClassName(header)), children: [_jsxs("div", { className: "flex flex-row items-center gap-1 group/header", children: [_jsx("div", { className: cn("flex flex-1 flex-row items-center overflow-hidden", canSort && "cursor-pointer select-none", columnMetaAlignClass(header.column.columnDef.meta)), onClick: header.column.getToggleSortingHandler(), children: header.isPlaceholder
859
+ ? null
860
+ : flexRender(header.column.columnDef.header, header.getContext()) }), canSort && (_jsx(ActionButton, { variant: "icon", size: "sm", className: cn("shrink-0 transition-opacity", isSorted
861
+ ? "opacity-100"
862
+ : sortIndicatorVisibility === "always"
863
+ ? "opacity-100"
864
+ : "opacity-0 group-hover/header:opacity-100"), onClick: header.column.getToggleSortingHandler(), "aria-label": isSorted === "asc"
865
+ ? "Sorted ascending — click to sort descending"
866
+ : isSorted === "desc"
867
+ ? "Sorted descending — click to clear sort"
868
+ : "Sort column", children: isSorted === "asc" ? (_jsx(ArrowUp, { className: "!size-4" })) : isSorted === "desc" ? (_jsx(ArrowDown, { className: "!size-4" })) : (_jsx(ArrowUpDown, { className: "!size-4 text-text-g-contrast-medium" })) })), showManage && (_jsxs(DropdownMenu, { open: columnManageMenuOpenId === header.column.id, onOpenChange: (open) => setColumnManageMenuOpenId(open ? header.column.id : null), modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", size: "sm", active: (manageOpen &&
869
+ manageAnchorId === header.column.id) ||
870
+ columnManageMenuOpenId === header.column.id, "aria-haspopup": "menu", "aria-expanded": columnManageMenuOpenId === header.column.id, "aria-label": "Column options", className: "shrink-0", ref: (el) => {
871
+ if (el) {
872
+ manageMenuTriggerRef.current.set(header.column.id, el);
873
+ }
874
+ else {
875
+ manageMenuTriggerRef.current.delete(header.column.id);
876
+ }
877
+ }, onClick: (e) => e.stopPropagation(), children: _jsx(EllipsisVertical, { className: "!size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 4, className: "min-w-[220px] py-1", onCloseAutoFocus: (e) => e.preventDefault(), children: [showColumnMenuVisibility && (_jsxs(DropdownMenuItem, { className: "py-3", disabled: header.column.getIsVisible() &&
878
+ visibleHideableLeafCount <= 1, icon: _jsx(EyeOff, { className: "size-4", "aria-hidden": true }), onSelect: () => {
879
+ header.column.toggleVisibility(false);
880
+ }, children: ["Hide ", manageColumnHeaderLabel(header), " ", "column"] })), _jsx(DropdownMenuItem, { className: "py-3", icon: _jsx(Columns3, { className: "size-4", "aria-hidden": true }), onSelect: () => {
881
+ requestAnimationFrame(() => {
882
+ const el = manageMenuTriggerRef.current.get(header.column.id);
883
+ if (el) {
884
+ openManagePanelAt(header.column.id, el.getBoundingClientRect());
885
+ }
886
+ });
887
+ }, children: "Manage columns" })] })] }))] }), canResize && (_jsx("div", { onMouseDown: header.getResizeHandler(document), onTouchStart: header.getResizeHandler(document), onClick: (e) => e.stopPropagation(), className: cn("absolute right-0 top-0 h-full w-[5px] z-10", "cursor-col-resize select-none touch-none", "flex items-center justify-center group/resize"), children: _jsx("div", { className: cn("h-4/5 w-1.5 rounded-full transition-all duration-150", isResizing
888
+ ? "opacity-100 w-0.5 bg-primary-500"
889
+ : "opacity-0 bg-table-c-col-line group-hover/col:opacity-100 group-hover/resize:bg-primary-400") }) }))] }, header.id));
890
+ }) }, headerGroup.id))) }), _jsx(TableBody, { striped: striped, "data-testid": testId ? `${testId}-tbody` : undefined, children: !isEmpty ? (virtualized ? ((() => {
891
+ var _a;
892
+ const virtualItems = rowVirtualizer.getVirtualItems();
893
+ if (!virtualItems.length)
894
+ return null;
895
+ // paddingStart models thead height in *scroll* coords; tbody spacers are only
896
+ // for rows inside tbody — subtract it or the first row is pushed down twice.
897
+ const top = Math.max(0, virtualItems[0].start - stickyHeaderHeight);
898
+ const bottom = rowVirtualizer.getTotalSize() -
899
+ ((_a = virtualItems[virtualItems.length - 1].end) !== null && _a !== void 0 ? _a : 0);
900
+ return (_jsxs(_Fragment, { children: [top > 0 && (_jsx("tr", { "aria-hidden": true, children: _jsx("td", { colSpan: finalColumns.length, style: { height: top } }) })), virtualItems.map((item) => {
901
+ const row = tableRowsForView[item.index];
902
+ const isExpandable = Boolean(getSubRows);
903
+ const rowBg = isExpandable && !striped
904
+ ? "bg-table-bg-a"
905
+ : undefined;
906
+ const isHighlighted = Array.isArray(highlightRowId)
907
+ ? highlightRowId.includes(row.id)
908
+ : highlightRowId === row.id;
909
+ const rowProps = {
910
+ divided: isExpandable && !striped ? true : !striped,
911
+ colDivided: divided,
912
+ "data-state": row.getIsSelected()
913
+ ? "selected"
914
+ : undefined,
915
+ "data-highlighted": isHighlighted
916
+ ? "true"
917
+ : undefined,
918
+ className: cn(rowBg, onRowClick && "cursor-pointer", rowClassName === null || rowClassName === void 0 ? void 0 : rowClassName(row, item.index)),
919
+ onClick: onRowClick
920
+ ? (e) => onRowClick(row, e)
921
+ : undefined,
922
+ };
923
+ return (_jsx(TableRow, Object.assign({ ref: rowVirtualizer.measureElement, "data-index": item.index, "data-row-id": row.id }, rowProps, { children: renderDataTableBodyCells({
924
+ row,
925
+ getSubRows,
926
+ firstDataCellId,
927
+ fixedColStyles,
928
+ flexWidth,
929
+ lockPxExactWidth,
930
+ resizable,
931
+ tableLayout,
932
+ resizableSlackGrowColId,
933
+ cellClassName,
934
+ onCellClick,
935
+ }) }), row.id));
936
+ }), bottom > 0 && (_jsx("tr", { "aria-hidden": true, children: _jsx("td", { colSpan: finalColumns.length, style: { height: bottom } }) }))] }));
937
+ })()) : reorderable ? (_jsx(DndContext, { sensors: rowReorderSensors, collisionDetection: closestCenter, modifiers: [restrictToVerticalAxis], onDragEnd: handleRowDragEnd, children: _jsx(SortableContext, { items: rowIds, strategy: verticalListSortingStrategy, children: tableRowsForView.map((row, rowIndex) => {
938
+ const isExpandable = Boolean(getSubRows);
939
+ const rowBg = isExpandable && !striped
940
+ ? "bg-table-bg-a"
941
+ : undefined;
942
+ const locked = isRowReorderLocked === null || isRowReorderLocked === void 0 ? void 0 : isRowReorderLocked(row);
943
+ const isHighlighted = Array.isArray(highlightRowId)
944
+ ? highlightRowId.includes(row.id)
945
+ : highlightRowId === row.id;
946
+ const rowProps = {
947
+ divided: isExpandable && !striped ? true : !striped,
948
+ colDivided: divided,
949
+ "data-state": row.getIsSelected()
950
+ ? "selected"
951
+ : undefined,
952
+ "data-highlighted": isHighlighted
953
+ ? "true"
954
+ : undefined,
955
+ className: cn(rowBg, onRowClick && "cursor-pointer", rowClassName === null || rowClassName === void 0 ? void 0 : rowClassName(row, rowIndex)),
956
+ onClick: onRowClick
957
+ ? (e) => onRowClick(row, e)
958
+ : undefined,
959
+ };
960
+ const cells = renderDataTableBodyCells({
961
+ row,
962
+ getSubRows,
963
+ firstDataCellId,
964
+ fixedColStyles,
965
+ flexWidth,
966
+ lockPxExactWidth,
967
+ resizable,
968
+ tableLayout,
969
+ resizableSlackGrowColId,
970
+ cellClassName,
971
+ onCellClick,
972
+ });
973
+ return locked ? (_jsx(TableRow, Object.assign({ "data-row-id": row.id }, rowProps, { children: cells }), row.id)) : (_jsx(SortableTableRow, Object.assign({ id: row.id, "data-row-id": row.id }, rowProps, { children: cells }), row.id));
974
+ }) }) })) : (tableRowsForView.map((row, rowIndex) => {
975
+ const isExpandable = Boolean(getSubRows);
976
+ // Non-striped expandable: solid bg-a on every row
977
+ const rowBg = isExpandable && !striped ? "bg-table-bg-a" : undefined;
978
+ const isHighlighted = Array.isArray(highlightRowId)
979
+ ? highlightRowId.includes(row.id)
980
+ : highlightRowId === row.id;
981
+ return (_jsx(TableRow, { divided: isExpandable && !striped ? true : !striped, colDivided: divided, "data-state": row.getIsSelected() ? "selected" : undefined, className: cn(rowBg, onRowClick && "cursor-pointer", rowClassName === null || rowClassName === void 0 ? void 0 : rowClassName(row, rowIndex)), "data-highlighted": isHighlighted ? "true" : undefined, onClick: onRowClick
982
+ ? (e) => onRowClick(row, e)
983
+ : undefined, "data-row-id": row.id, children: renderDataTableBodyCells({
984
+ row,
985
+ getSubRows,
986
+ firstDataCellId,
987
+ fixedColStyles,
988
+ flexWidth,
989
+ lockPxExactWidth,
990
+ resizable,
991
+ tableLayout,
992
+ resizableSlackGrowColId,
993
+ cellClassName,
994
+ onCellClick,
995
+ }) }, row.id));
996
+ }))) : loading ? (_jsx(TableRow, { className: "h-full hover:bg-transparent", divided: false, children: _jsx(TableCell, { colSpan: finalColumns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full min-h-[200px]", children: _jsxs("div", { className: "flex flex-1 min-h-[200px] h-full flex-col items-center justify-center gap-3 py-16", role: "status", "aria-live": "polite", "aria-busy": "true", children: [_jsx(Loader2, { className: "size-8 shrink-0 animate-spin text-secondary-120", "aria-hidden": true }), loadingLabel] }) }) })) : (_jsx(TableRow, { className: "h-full hover:bg-transparent", divided: false, children: _jsx(TableCell, { colSpan: finalColumns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full", children: _jsxs("div", { className: "flex flex-1 h-full flex-col items-center justify-center gap-3 py-16", children: [_jsx(ClipboardList, { className: "w-8 text-secondary-120" }), "There is no information yet."] }) }) })) }), paginationMode === "infinite" &&
997
+ fetchingMore &&
998
+ !isEmpty &&
999
+ table.getVisibleLeafColumns().length > 0 && (_jsx("tfoot", { className: "[&_tr]:bg-table-c-row-bg", children: _jsx(TableRow, { divided: false, className: "hover:!bg-table-c-row-bg border-t border-t-table-c-row-line", children: _jsx(TableCell, { colSpan: table.getVisibleLeafColumns().length, className: "py-3 text-center typography-body3 text-text-g-contrast-medium bg-inherit", children: _jsxs("span", { role: "status", "aria-live": "polite", className: "inline-flex items-center justify-center gap-2", children: [_jsx(Loader2, { className: "size-4 shrink-0 animate-spin", "aria-hidden": true }), fetchingMoreLabel] }) }) }) }))] }) }), isPaginated && _jsx(TablePagination, Object.assign({}, paginationBarProps)), columnManagement && manageOpen && (_jsxs(Portal.Root, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: () => setManageOpen(false) }), _jsx("div", { className: "fixed z-50 w-[460px] rounded-lg bg-modal-surface shadow-[0px_12px_24px_-4px_rgba(0,0,0,0.12)] overflow-hidden", style: {
1000
+ top: managePanelPos.top,
1001
+ right: managePanelPos.right,
1002
+ }, onClick: (e) => e.stopPropagation(), children: _jsx(ManageColumnPanel, { table: table, onClose: () => setManageOpen(false), maxListHeight: managePanelPos.maxListHeight, options: columnManagementOptions }) })] }))] }) }));
70
1003
  }