react-glide-table 1.1.0 → 1.1.2
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/README.md +75 -15
- package/dist/compound.cjs +2085 -0
- package/dist/compound.d.cts +63 -0
- package/dist/compound.d.ts +63 -0
- package/dist/compound.js +2067 -0
- package/dist/core.cjs +1198 -0
- package/dist/core.d.cts +255 -0
- package/dist/core.d.ts +255 -0
- package/dist/core.js +1154 -0
- package/dist/index.cjs +948 -3
- package/dist/index.d.cts +5 -414
- package/dist/index.d.ts +5 -414
- package/dist/index.js +942 -0
- package/dist/types-ByOoRY8x.d.cts +177 -0
- package/dist/types-ByOoRY8x.d.ts +177 -0
- package/package.json +12 -1
package/dist/core.js
ADDED
|
@@ -0,0 +1,1154 @@
|
|
|
1
|
+
// src/core/labels.ts
|
|
2
|
+
var DEFAULT_DATA_TABLE_LABELS = {
|
|
3
|
+
empty: "No data",
|
|
4
|
+
loading: "Loading...",
|
|
5
|
+
selection: (selectedCount) => selectedCount > 0 ? `\u2713 ${selectedCount} selected` : null,
|
|
6
|
+
expandRow: "Expand row",
|
|
7
|
+
collapseRow: "Collapse row"
|
|
8
|
+
};
|
|
9
|
+
function resolveDataTableLabels(partial) {
|
|
10
|
+
return {
|
|
11
|
+
...DEFAULT_DATA_TABLE_LABELS,
|
|
12
|
+
...partial
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/core/treeDefaults.ts
|
|
17
|
+
var DEFAULT_TREE_ID_FIELD = "id";
|
|
18
|
+
var DEFAULT_TREE_PARENT_ID_FIELD = "parentId";
|
|
19
|
+
var DEFAULT_TREE_CHILDREN_FIELD = "children";
|
|
20
|
+
var DEFAULT_TREE_QTY_FIELD = "qty";
|
|
21
|
+
|
|
22
|
+
// src/core/useGlideTable.ts
|
|
23
|
+
import {
|
|
24
|
+
getCoreRowModel,
|
|
25
|
+
useReactTable
|
|
26
|
+
} from "@tanstack/react-table";
|
|
27
|
+
import {
|
|
28
|
+
useVirtualizer
|
|
29
|
+
} from "@tanstack/react-virtual";
|
|
30
|
+
import {
|
|
31
|
+
useCallback as useCallback3,
|
|
32
|
+
useEffect as useEffect4,
|
|
33
|
+
useMemo as useMemo2,
|
|
34
|
+
useRef as useRef3,
|
|
35
|
+
useState as useState3
|
|
36
|
+
} from "react";
|
|
37
|
+
|
|
38
|
+
// src/components/ui/table/constants.ts
|
|
39
|
+
var DATA_TABLE_ROW_HEIGHT = 44;
|
|
40
|
+
var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
|
|
41
|
+
|
|
42
|
+
// src/components/ui/table/features/cell-edit/useCellEdit.ts
|
|
43
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
44
|
+
|
|
45
|
+
// src/components/ui/table/features/cell-edit/cellEdit.ts
|
|
46
|
+
function getColumnAccessorKey(columnDef) {
|
|
47
|
+
if (columnDef.accessorKey !== void 0 && columnDef.accessorKey !== null) {
|
|
48
|
+
return String(columnDef.accessorKey);
|
|
49
|
+
}
|
|
50
|
+
return columnDef.id;
|
|
51
|
+
}
|
|
52
|
+
function isColumnEditable(columnDef) {
|
|
53
|
+
return Boolean(columnDef.meta?.editable);
|
|
54
|
+
}
|
|
55
|
+
function getColumnEditType(columnDef) {
|
|
56
|
+
return columnDef.meta?.editType ?? "text";
|
|
57
|
+
}
|
|
58
|
+
function parseCellEditValue(raw, editType) {
|
|
59
|
+
if (editType === "text") {
|
|
60
|
+
return { ok: true, value: raw };
|
|
61
|
+
}
|
|
62
|
+
const trimmed = raw.trim();
|
|
63
|
+
if (trimmed === "") {
|
|
64
|
+
return { ok: true, value: null };
|
|
65
|
+
}
|
|
66
|
+
const parsed = Number(trimmed);
|
|
67
|
+
if (Number.isNaN(parsed)) {
|
|
68
|
+
return { ok: false };
|
|
69
|
+
}
|
|
70
|
+
return { ok: true, value: parsed };
|
|
71
|
+
}
|
|
72
|
+
function getCellEditDraftValue(value) {
|
|
73
|
+
if (value === null || value === void 0) return "";
|
|
74
|
+
return String(value);
|
|
75
|
+
}
|
|
76
|
+
function applyCellEdit(data, rows, rowIndex, colIndex, raw) {
|
|
77
|
+
const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
|
|
78
|
+
if (!cell) return null;
|
|
79
|
+
const columnDef = cell.column.columnDef;
|
|
80
|
+
if (!isColumnEditable(columnDef)) return null;
|
|
81
|
+
const accessorKey = getColumnAccessorKey(columnDef);
|
|
82
|
+
if (!accessorKey) return null;
|
|
83
|
+
const parsed = parseCellEditValue(raw, getColumnEditType(columnDef));
|
|
84
|
+
if (!parsed.ok) return null;
|
|
85
|
+
const newData = data.map((row) => ({ ...row }));
|
|
86
|
+
if (!newData[rowIndex]) return null;
|
|
87
|
+
newData[rowIndex][accessorKey] = parsed.value;
|
|
88
|
+
return newData;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/components/ui/table/features/cell-edit/useCellEdit.ts
|
|
92
|
+
function useCellEdit({
|
|
93
|
+
data,
|
|
94
|
+
rows,
|
|
95
|
+
onDataChange,
|
|
96
|
+
onCellChange
|
|
97
|
+
}) {
|
|
98
|
+
const [editingCell, setEditingCell] = useState(null);
|
|
99
|
+
const [draftValue, setDraftValue] = useState("");
|
|
100
|
+
const draftValueRef = useRef(draftValue);
|
|
101
|
+
const editingCellRef = useRef(editingCell);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
draftValueRef.current = draftValue;
|
|
104
|
+
}, [draftValue]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
editingCellRef.current = editingCell;
|
|
107
|
+
}, [editingCell]);
|
|
108
|
+
const cancelEdit = useCallback(() => {
|
|
109
|
+
setEditingCell(null);
|
|
110
|
+
setDraftValue("");
|
|
111
|
+
}, []);
|
|
112
|
+
const commitEdit = useCallback(
|
|
113
|
+
(raw) => {
|
|
114
|
+
const current = editingCellRef.current;
|
|
115
|
+
if (!current) return true;
|
|
116
|
+
if (!onCellChange && !onDataChange) {
|
|
117
|
+
cancelEdit();
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
const row = rows[current.rowIndex];
|
|
121
|
+
const cell = row?.getVisibleCells()[current.colIndex];
|
|
122
|
+
if (!row || !cell) {
|
|
123
|
+
cancelEdit();
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
const value = raw ?? draftValueRef.current;
|
|
127
|
+
if (!isColumnEditable(cell.column.columnDef)) {
|
|
128
|
+
cancelEdit();
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
const parsed = parseCellEditValue(value, getColumnEditType(cell.column.columnDef));
|
|
132
|
+
if (!parsed.ok) return false;
|
|
133
|
+
if (onCellChange) {
|
|
134
|
+
onCellChange(row.id, cell.column.id, parsed.value);
|
|
135
|
+
cancelEdit();
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
const next = applyCellEdit(data, rows, current.rowIndex, current.colIndex, value);
|
|
139
|
+
if (!next) return false;
|
|
140
|
+
onDataChange?.(next);
|
|
141
|
+
cancelEdit();
|
|
142
|
+
return true;
|
|
143
|
+
},
|
|
144
|
+
[cancelEdit, data, onCellChange, onDataChange, rows]
|
|
145
|
+
);
|
|
146
|
+
const startEdit = useCallback(
|
|
147
|
+
(rowIndex, colIndex) => {
|
|
148
|
+
const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
|
|
149
|
+
if (!cell || !isColumnEditable(cell.column.columnDef)) return;
|
|
150
|
+
const current = editingCellRef.current;
|
|
151
|
+
if (current && (current.rowIndex !== rowIndex || current.colIndex !== colIndex) && !commitEdit()) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
setEditingCell({ rowIndex, colIndex });
|
|
155
|
+
setDraftValue(getCellEditDraftValue(cell.getValue()));
|
|
156
|
+
},
|
|
157
|
+
[commitEdit, rows]
|
|
158
|
+
);
|
|
159
|
+
return {
|
|
160
|
+
editingCell,
|
|
161
|
+
draftValue,
|
|
162
|
+
setDraftValue,
|
|
163
|
+
startEdit,
|
|
164
|
+
commitEdit,
|
|
165
|
+
cancelEdit
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
170
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
171
|
+
|
|
172
|
+
// src/components/ui/table/features/cell-selection/cellSelection.ts
|
|
173
|
+
var INITIAL_DRAG_STATE = {
|
|
174
|
+
isSelecting: false,
|
|
175
|
+
isFillDragging: false,
|
|
176
|
+
start: null,
|
|
177
|
+
end: null,
|
|
178
|
+
fillAnchor: null,
|
|
179
|
+
fillEnd: null
|
|
180
|
+
};
|
|
181
|
+
function getCellSelectionBounds(start, end) {
|
|
182
|
+
if (!start || !end) return null;
|
|
183
|
+
return {
|
|
184
|
+
startRow: Math.min(start.row, end.row),
|
|
185
|
+
endRow: Math.max(start.row, end.row),
|
|
186
|
+
startCol: Math.min(start.col, end.col),
|
|
187
|
+
endCol: Math.max(start.col, end.col)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
|
|
191
|
+
if (rowSpan <= 1) return rowIndex;
|
|
192
|
+
const rect = cellElement.getBoundingClientRect();
|
|
193
|
+
const relativeY = clientY - rect.top;
|
|
194
|
+
const rowHeight = rect.height / rowSpan;
|
|
195
|
+
const offset = Math.min(
|
|
196
|
+
Math.max(Math.floor(relativeY / rowHeight), 0),
|
|
197
|
+
rowSpan - 1
|
|
198
|
+
);
|
|
199
|
+
return rowIndex + offset;
|
|
200
|
+
}
|
|
201
|
+
function isCellInSelection(rowIndex, colIndex, bounds, rowSpan = 1) {
|
|
202
|
+
if (!bounds) return false;
|
|
203
|
+
const cellEndRow = rowIndex + rowSpan - 1;
|
|
204
|
+
return cellEndRow >= bounds.startRow && rowIndex <= bounds.endRow && colIndex >= bounds.startCol && colIndex <= bounds.endCol;
|
|
205
|
+
}
|
|
206
|
+
function getActiveSelectionBounds(dragState, selectionBounds) {
|
|
207
|
+
if (dragState.isFillDragging && dragState.fillAnchor && dragState.fillEnd) {
|
|
208
|
+
return getCellSelectionBounds(dragState.fillAnchor, dragState.fillEnd);
|
|
209
|
+
}
|
|
210
|
+
return selectionBounds;
|
|
211
|
+
}
|
|
212
|
+
var SELECTION_EDGE_WIDTH_PX = 2;
|
|
213
|
+
var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
|
|
214
|
+
var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
|
|
215
|
+
function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt) {
|
|
216
|
+
const cellEndRow = rowIndex + rowSpan - 1;
|
|
217
|
+
const span = cellEndRow - rowIndex + 1;
|
|
218
|
+
if (span <= 1) return [];
|
|
219
|
+
const edges = [];
|
|
220
|
+
const isNeighborSelected = (row, neighborCol) => {
|
|
221
|
+
if (isVisuallySelectedAt) {
|
|
222
|
+
return isVisuallySelectedAt(row, neighborCol);
|
|
223
|
+
}
|
|
224
|
+
return row >= bounds.startRow && row <= bounds.endRow && neighborCol >= bounds.startCol && neighborCol <= bounds.endCol;
|
|
225
|
+
};
|
|
226
|
+
const pushUnselectedRuns = (side, neighborCol, fromRow, toRowExclusive) => {
|
|
227
|
+
let runStart = null;
|
|
228
|
+
for (let row = fromRow; row < toRowExclusive; row++) {
|
|
229
|
+
if (!isNeighborSelected(row, neighborCol)) {
|
|
230
|
+
if (runStart === null) runStart = row;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (runStart !== null) {
|
|
234
|
+
edges.push({
|
|
235
|
+
side,
|
|
236
|
+
offsetRatio: (runStart - rowIndex) / span,
|
|
237
|
+
heightRatio: (row - runStart) / span
|
|
238
|
+
});
|
|
239
|
+
runStart = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (runStart !== null) {
|
|
243
|
+
edges.push({
|
|
244
|
+
side,
|
|
245
|
+
offsetRatio: (runStart - rowIndex) / span,
|
|
246
|
+
heightRatio: (toRowExclusive - runStart) / span
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
const collectSide = (side, neighborCol) => {
|
|
251
|
+
if (bounds.startRow > rowIndex) {
|
|
252
|
+
pushUnselectedRuns(
|
|
253
|
+
side,
|
|
254
|
+
neighborCol,
|
|
255
|
+
rowIndex,
|
|
256
|
+
Math.min(bounds.startRow, cellEndRow + 1)
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
if (bounds.endRow < cellEndRow) {
|
|
260
|
+
pushUnselectedRuns(
|
|
261
|
+
side,
|
|
262
|
+
neighborCol,
|
|
263
|
+
Math.max(bounds.endRow + 1, rowIndex),
|
|
264
|
+
cellEndRow + 1
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
if (colIndex < bounds.endCol) {
|
|
269
|
+
collectSide("right", colIndex + 1);
|
|
270
|
+
}
|
|
271
|
+
if (colIndex > bounds.startCol) {
|
|
272
|
+
collectSide("left", colIndex - 1);
|
|
273
|
+
}
|
|
274
|
+
return edges;
|
|
275
|
+
}
|
|
276
|
+
function buildPartialVerticalGradient(edge) {
|
|
277
|
+
const startPct = edge.offsetRatio * 100;
|
|
278
|
+
const endPct = (edge.offsetRatio + edge.heightRatio) * 100;
|
|
279
|
+
const overlapPx = SELECTION_EDGE_WIDTH_PX + 1;
|
|
280
|
+
const isTopProtrusion = edge.offsetRatio === 0 && edge.heightRatio < 1;
|
|
281
|
+
const isBottomProtrusion = edge.offsetRatio > 0;
|
|
282
|
+
const startStop = isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
|
|
283
|
+
const endStop = isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
|
|
284
|
+
const xPos = edge.side === "left" ? "0" : "100%";
|
|
285
|
+
const layers = [
|
|
286
|
+
{
|
|
287
|
+
image: `linear-gradient(to bottom, transparent 0%, transparent ${startStop}, ${SELECTION_EDGE_COLOR} ${startStop}, ${SELECTION_EDGE_COLOR} ${endStop}, transparent ${endStop}, transparent 100%)`,
|
|
288
|
+
size: `${SELECTION_EDGE_WIDTH_PX}px 100%`,
|
|
289
|
+
position: `${xPos} 0`
|
|
290
|
+
}
|
|
291
|
+
];
|
|
292
|
+
if (isTopProtrusion || isBottomProtrusion) {
|
|
293
|
+
const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
294
|
+
layers.push({
|
|
295
|
+
image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
|
|
296
|
+
size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
|
|
297
|
+
position: `${xPos} ${capTop}`
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return layers;
|
|
301
|
+
}
|
|
302
|
+
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
|
|
303
|
+
if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
|
|
304
|
+
return void 0;
|
|
305
|
+
const cellEndRow = rowIndex + rowSpan - 1;
|
|
306
|
+
const isTopEdge = bounds.startRow >= rowIndex && bounds.startRow <= cellEndRow;
|
|
307
|
+
const isBottomEdge = bounds.endRow >= rowIndex && bounds.endRow <= cellEndRow;
|
|
308
|
+
const isLeftEdge = colIndex === bounds.startCol;
|
|
309
|
+
const isRightEdge = colIndex === bounds.endCol;
|
|
310
|
+
const selectionContinuesBelow = cellEndRow < bounds.endRow;
|
|
311
|
+
const shadows = [];
|
|
312
|
+
if (isTopEdge) {
|
|
313
|
+
shadows.push(
|
|
314
|
+
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
if (isBottomEdge) {
|
|
318
|
+
shadows.push(
|
|
319
|
+
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
if (isLeftEdge) {
|
|
323
|
+
shadows.push(
|
|
324
|
+
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
if (isRightEdge) {
|
|
328
|
+
shadows.push(
|
|
329
|
+
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
const stepEdges = getMergedCellStepEdges(
|
|
333
|
+
rowIndex,
|
|
334
|
+
colIndex,
|
|
335
|
+
bounds,
|
|
336
|
+
rowSpan,
|
|
337
|
+
isVisuallySelectedAt
|
|
338
|
+
);
|
|
339
|
+
const gradients = [];
|
|
340
|
+
const sizes = [];
|
|
341
|
+
const positions = [];
|
|
342
|
+
for (const edge of stepEdges) {
|
|
343
|
+
for (const partial of buildPartialVerticalGradient(edge)) {
|
|
344
|
+
gradients.push(partial.image);
|
|
345
|
+
sizes.push(partial.size);
|
|
346
|
+
positions.push(partial.position);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (shadows.length === 0 && gradients.length === 0 && !selectionContinuesBelow) {
|
|
350
|
+
return void 0;
|
|
351
|
+
}
|
|
352
|
+
const style = {};
|
|
353
|
+
if (shadows.length > 0) {
|
|
354
|
+
style["--selection-edge-shadows"] = shadows.join(", ");
|
|
355
|
+
}
|
|
356
|
+
if (gradients.length > 0) {
|
|
357
|
+
style["--selection-edge-gradients"] = gradients.join(", ");
|
|
358
|
+
style["--selection-edge-sizes"] = sizes.join(", ");
|
|
359
|
+
style["--selection-edge-positions"] = positions.join(", ");
|
|
360
|
+
}
|
|
361
|
+
if (selectionContinuesBelow) {
|
|
362
|
+
style.borderBottomColor = "var(--color-brand-surface)";
|
|
363
|
+
}
|
|
364
|
+
return style;
|
|
365
|
+
}
|
|
366
|
+
function hasCellSelectionEdges(style) {
|
|
367
|
+
return Boolean(
|
|
368
|
+
style?.["--selection-edge-shadows"] || style?.["--selection-edge-gradients"]
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/components/ui/table/features/cell-selection/fillData.ts
|
|
373
|
+
function getColumnAccessorKey2(columnDef) {
|
|
374
|
+
if ("accessorKey" in columnDef && columnDef.accessorKey) {
|
|
375
|
+
return String(columnDef.accessorKey);
|
|
376
|
+
}
|
|
377
|
+
return columnDef.id;
|
|
378
|
+
}
|
|
379
|
+
function collectFillTargets(rows, sourceBounds, fillBounds) {
|
|
380
|
+
const targets = [];
|
|
381
|
+
const sourceHeight = sourceBounds.endRow - sourceBounds.startRow + 1;
|
|
382
|
+
const sourceWidth = sourceBounds.endCol - sourceBounds.startCol + 1;
|
|
383
|
+
for (let rowIndex = fillBounds.startRow; rowIndex <= fillBounds.endRow; rowIndex += 1) {
|
|
384
|
+
for (let colIndex = fillBounds.startCol; colIndex <= fillBounds.endCol; colIndex += 1) {
|
|
385
|
+
if (isCellInSelection(rowIndex, colIndex, sourceBounds)) continue;
|
|
386
|
+
const offsetRow = rowIndex - sourceBounds.startRow;
|
|
387
|
+
const offsetCol = colIndex - sourceBounds.startCol;
|
|
388
|
+
const sourceRowIndex = sourceBounds.startRow + (offsetRow % sourceHeight + sourceHeight) % sourceHeight;
|
|
389
|
+
const sourceColIndex = sourceBounds.startCol + (offsetCol % sourceWidth + sourceWidth) % sourceWidth;
|
|
390
|
+
const targetRow = rows[rowIndex];
|
|
391
|
+
const targetCell = targetRow?.getVisibleCells()[colIndex];
|
|
392
|
+
const sourceCell = rows[sourceRowIndex]?.getVisibleCells()[sourceColIndex];
|
|
393
|
+
if (!targetRow || !targetCell || !sourceCell) continue;
|
|
394
|
+
const accessorKey = getColumnAccessorKey2(
|
|
395
|
+
targetCell.column.columnDef
|
|
396
|
+
);
|
|
397
|
+
if (!accessorKey) continue;
|
|
398
|
+
targets.push({
|
|
399
|
+
rowIndex,
|
|
400
|
+
accessorKey,
|
|
401
|
+
columnId: targetCell.column.id,
|
|
402
|
+
value: sourceCell.getValue(),
|
|
403
|
+
rowId: targetRow.id
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return targets;
|
|
408
|
+
}
|
|
409
|
+
function collectFillChanges(rows, sourceBounds, fillBounds) {
|
|
410
|
+
return collectFillTargets(rows, sourceBounds, fillBounds).map(
|
|
411
|
+
({ rowId, columnId, value }) => ({ rowId, columnId, value })
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
function applyFillData(data, rows, sourceBounds, fillBounds) {
|
|
415
|
+
const newData = data.map((row) => ({ ...row }));
|
|
416
|
+
const targets = collectFillTargets(rows, sourceBounds, fillBounds);
|
|
417
|
+
for (const target of targets) {
|
|
418
|
+
if (!newData[target.rowIndex]) continue;
|
|
419
|
+
newData[target.rowIndex][target.accessorKey] = target.value;
|
|
420
|
+
}
|
|
421
|
+
return newData;
|
|
422
|
+
}
|
|
423
|
+
function hasFillExtension(sourceBounds, fillBounds) {
|
|
424
|
+
if (!sourceBounds) return false;
|
|
425
|
+
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
429
|
+
function useCellSelection({
|
|
430
|
+
data,
|
|
431
|
+
rows,
|
|
432
|
+
enabled = true,
|
|
433
|
+
onDataChange,
|
|
434
|
+
onBatchChange
|
|
435
|
+
}) {
|
|
436
|
+
const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
|
|
437
|
+
const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
|
|
438
|
+
const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
|
|
439
|
+
const handleCellMouseDown = useCallback2(
|
|
440
|
+
(rowIndex, colIndex) => {
|
|
441
|
+
if (!enabled) return;
|
|
442
|
+
setDragState({
|
|
443
|
+
isSelecting: true,
|
|
444
|
+
isFillDragging: false,
|
|
445
|
+
start: { row: rowIndex, col: colIndex },
|
|
446
|
+
end: { row: rowIndex, col: colIndex },
|
|
447
|
+
fillAnchor: null,
|
|
448
|
+
fillEnd: null
|
|
449
|
+
});
|
|
450
|
+
},
|
|
451
|
+
[enabled]
|
|
452
|
+
);
|
|
453
|
+
const handleCellMouseEnter = useCallback2(
|
|
454
|
+
(rowIndex, colIndex) => {
|
|
455
|
+
if (!enabled) return;
|
|
456
|
+
setDragState((prev) => {
|
|
457
|
+
if (prev.isSelecting) {
|
|
458
|
+
return { ...prev, end: { row: rowIndex, col: colIndex } };
|
|
459
|
+
}
|
|
460
|
+
if (prev.isFillDragging) {
|
|
461
|
+
return { ...prev, fillEnd: { row: rowIndex, col: colIndex } };
|
|
462
|
+
}
|
|
463
|
+
return prev;
|
|
464
|
+
});
|
|
465
|
+
},
|
|
466
|
+
[enabled]
|
|
467
|
+
);
|
|
468
|
+
const handleFillHandleMouseDown = useCallback2(
|
|
469
|
+
(rowIndex, colIndex) => {
|
|
470
|
+
if (!enabled) return;
|
|
471
|
+
setDragState((prev) => {
|
|
472
|
+
const bounds = getCellSelectionBounds(prev.start, prev.end);
|
|
473
|
+
if (!bounds) return prev;
|
|
474
|
+
return {
|
|
475
|
+
...prev,
|
|
476
|
+
isSelecting: false,
|
|
477
|
+
isFillDragging: true,
|
|
478
|
+
fillAnchor: { row: bounds.startRow, col: bounds.startCol },
|
|
479
|
+
fillEnd: { row: rowIndex, col: colIndex }
|
|
480
|
+
};
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
[enabled]
|
|
484
|
+
);
|
|
485
|
+
useEffect2(() => {
|
|
486
|
+
if (!enabled) {
|
|
487
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
488
|
+
}
|
|
489
|
+
}, [enabled]);
|
|
490
|
+
useEffect2(() => {
|
|
491
|
+
if (!enabled) return;
|
|
492
|
+
const handleKeyDown = (e) => {
|
|
493
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "c" && activeSelectionBounds) {
|
|
494
|
+
const { startRow, endRow, startCol, endCol } = activeSelectionBounds;
|
|
495
|
+
const selectedData = rows.slice(startRow, endRow + 1).map((row) => {
|
|
496
|
+
const cells = row.getVisibleCells();
|
|
497
|
+
return cells.slice(startCol, endCol + 1).map((cell) => cell.getValue()).join(" ");
|
|
498
|
+
}).join("\n");
|
|
499
|
+
navigator.clipboard.writeText(selectedData);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
503
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
504
|
+
}, [activeSelectionBounds, enabled, rows]);
|
|
505
|
+
useEffect2(() => {
|
|
506
|
+
if (!enabled) return;
|
|
507
|
+
const handleMouseUp = () => {
|
|
508
|
+
setDragState((prev) => {
|
|
509
|
+
if (prev.isFillDragging && prev.fillAnchor && prev.fillEnd) {
|
|
510
|
+
const sourceBounds = getCellSelectionBounds(prev.start, prev.end);
|
|
511
|
+
const newBounds = getCellSelectionBounds(prev.fillAnchor, prev.fillEnd);
|
|
512
|
+
if (newBounds) {
|
|
513
|
+
if (hasFillExtension(sourceBounds, newBounds) && sourceBounds) {
|
|
514
|
+
if (onBatchChange) {
|
|
515
|
+
const changes = collectFillChanges(rows, sourceBounds, newBounds);
|
|
516
|
+
if (changes.length > 0) {
|
|
517
|
+
onBatchChange(changes);
|
|
518
|
+
}
|
|
519
|
+
} else if (onDataChange) {
|
|
520
|
+
onDataChange(applyFillData(data, rows, sourceBounds, newBounds));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return {
|
|
524
|
+
isSelecting: false,
|
|
525
|
+
isFillDragging: false,
|
|
526
|
+
start: { row: newBounds.startRow, col: newBounds.startCol },
|
|
527
|
+
end: { row: newBounds.endRow, col: newBounds.endCol },
|
|
528
|
+
fillAnchor: null,
|
|
529
|
+
fillEnd: null
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (prev.isSelecting) {
|
|
534
|
+
return { ...prev, isSelecting: false };
|
|
535
|
+
}
|
|
536
|
+
if (prev.isFillDragging) {
|
|
537
|
+
return { ...prev, isFillDragging: false, fillAnchor: null, fillEnd: null };
|
|
538
|
+
}
|
|
539
|
+
return prev;
|
|
540
|
+
});
|
|
541
|
+
};
|
|
542
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
543
|
+
return () => window.removeEventListener("mouseup", handleMouseUp);
|
|
544
|
+
}, [data, enabled, onBatchChange, onDataChange, rows]);
|
|
545
|
+
return {
|
|
546
|
+
dragState: enabled ? dragState : INITIAL_DRAG_STATE,
|
|
547
|
+
activeSelectionBounds,
|
|
548
|
+
handleCellMouseDown,
|
|
549
|
+
handleCellMouseEnter,
|
|
550
|
+
handleFillHandleMouseDown
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// src/components/ui/table/features/row-expand/row-expand.ts
|
|
555
|
+
import { useEffect as useEffect3, useMemo, useRef as useRef2 } from "react";
|
|
556
|
+
function getFieldValue(row, key) {
|
|
557
|
+
return row[key];
|
|
558
|
+
}
|
|
559
|
+
function canExpandRow(row) {
|
|
560
|
+
const children = row.children;
|
|
561
|
+
const level = row.level;
|
|
562
|
+
return Array.isArray(children) && children.length > 0 && (level === 0 || level === void 0);
|
|
563
|
+
}
|
|
564
|
+
function toggleExpandedRowId(rowId, previous) {
|
|
565
|
+
const next = new Set(previous);
|
|
566
|
+
if (next.has(rowId)) {
|
|
567
|
+
next.delete(rowId);
|
|
568
|
+
} else {
|
|
569
|
+
next.add(rowId);
|
|
570
|
+
}
|
|
571
|
+
return next;
|
|
572
|
+
}
|
|
573
|
+
var useConvertTreeData = ({
|
|
574
|
+
data,
|
|
575
|
+
enabled = true,
|
|
576
|
+
toggleField = DEFAULT_TREE_ID_FIELD,
|
|
577
|
+
childField = DEFAULT_TREE_PARENT_ID_FIELD,
|
|
578
|
+
flattenField = DEFAULT_TREE_CHILDREN_FIELD,
|
|
579
|
+
qtyField = DEFAULT_TREE_QTY_FIELD,
|
|
580
|
+
preventExpand = false,
|
|
581
|
+
startIndex = 1,
|
|
582
|
+
expandedRows,
|
|
583
|
+
onExpandedRowsChange
|
|
584
|
+
}) => {
|
|
585
|
+
const onExpandedRowsChangeRef = useRef2(onExpandedRowsChange);
|
|
586
|
+
const hasInitializedRef = useRef2(false);
|
|
587
|
+
useEffect3(() => {
|
|
588
|
+
onExpandedRowsChangeRef.current = onExpandedRowsChange;
|
|
589
|
+
}, [onExpandedRowsChange]);
|
|
590
|
+
useEffect3(() => {
|
|
591
|
+
if (!data || data.length === 0) {
|
|
592
|
+
hasInitializedRef.current = false;
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (!enabled || hasInitializedRef.current) return;
|
|
596
|
+
const ids = data.map((item) => getFieldValue(item, toggleField)).filter((value) => typeof value === "string" && value.length > 0);
|
|
597
|
+
onExpandedRowsChangeRef.current?.(new Set(ids));
|
|
598
|
+
hasInitializedRef.current = true;
|
|
599
|
+
}, [enabled, data, toggleField]);
|
|
600
|
+
const processedData = useMemo(() => {
|
|
601
|
+
if (!enabled || !data || data.length === 0) return [];
|
|
602
|
+
const flattenedData = [];
|
|
603
|
+
const flattenItems = (items) => {
|
|
604
|
+
items.forEach((item) => {
|
|
605
|
+
const newItem = { ...item };
|
|
606
|
+
const nested = newItem[flattenField];
|
|
607
|
+
if (Array.isArray(nested)) {
|
|
608
|
+
const children = nested.map(
|
|
609
|
+
(child) => typeof child === "object" && child !== null ? { ...child } : child
|
|
610
|
+
);
|
|
611
|
+
delete newItem[flattenField];
|
|
612
|
+
flattenedData.push(newItem);
|
|
613
|
+
children.forEach((child) => {
|
|
614
|
+
if (typeof child === "object" && child !== null) {
|
|
615
|
+
;
|
|
616
|
+
child[childField] = newItem[toggleField];
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
flattenItems(children);
|
|
620
|
+
} else {
|
|
621
|
+
flattenedData.push(newItem);
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
};
|
|
625
|
+
flattenItems(data);
|
|
626
|
+
const dataWithLevels = flattenedData.map((item) => ({
|
|
627
|
+
...item,
|
|
628
|
+
level: 0,
|
|
629
|
+
children: [],
|
|
630
|
+
processed: false
|
|
631
|
+
}));
|
|
632
|
+
const itemMap = /* @__PURE__ */ new Map();
|
|
633
|
+
dataWithLevels.forEach((item) => {
|
|
634
|
+
const key = getFieldValue(item, toggleField);
|
|
635
|
+
if (typeof key !== "string" || !key) return;
|
|
636
|
+
if (!itemMap.has(key)) {
|
|
637
|
+
itemMap.set(key, []);
|
|
638
|
+
}
|
|
639
|
+
itemMap.get(key)?.push(item);
|
|
640
|
+
});
|
|
641
|
+
const rootItems = [];
|
|
642
|
+
dataWithLevels.forEach((item) => {
|
|
643
|
+
if (!getFieldValue(item, childField)) {
|
|
644
|
+
rootItems.push(item);
|
|
645
|
+
item.processed = true;
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
dataWithLevels.forEach((item) => {
|
|
649
|
+
const parentKey = getFieldValue(item, childField);
|
|
650
|
+
if (!parentKey || item.processed) return;
|
|
651
|
+
const parentItems = dataWithLevels.filter(
|
|
652
|
+
(parent) => getFieldValue(parent, toggleField) === parentKey && !getFieldValue(parent, childField)
|
|
653
|
+
);
|
|
654
|
+
if (parentItems.length > 0) {
|
|
655
|
+
const parent = parentItems[0];
|
|
656
|
+
item.level = parent.level + 1;
|
|
657
|
+
parent.children.push(item);
|
|
658
|
+
item.processed = true;
|
|
659
|
+
} else {
|
|
660
|
+
const otherParents = itemMap.get(String(parentKey)) || [];
|
|
661
|
+
if (otherParents.length > 0) {
|
|
662
|
+
const parent = otherParents[0];
|
|
663
|
+
item.level = parent.level + 1;
|
|
664
|
+
parent.children.push(item);
|
|
665
|
+
item.processed = true;
|
|
666
|
+
} else {
|
|
667
|
+
rootItems.push(item);
|
|
668
|
+
item.processed = true;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
return rootItems;
|
|
673
|
+
}, [enabled, data, toggleField, childField, flattenField]);
|
|
674
|
+
const flattenTree = useMemo(() => {
|
|
675
|
+
if (!enabled) return [];
|
|
676
|
+
const flatten = (nodes, result = [], level = 0) => {
|
|
677
|
+
nodes.forEach((node, index) => {
|
|
678
|
+
const currentIndex = level === 0 ? `${index + startIndex}` : `${level}-${index + 1}`;
|
|
679
|
+
const toggleValue = getFieldValue(node, toggleField);
|
|
680
|
+
const uniqueId = `${index}-${String(toggleValue ?? "")}`;
|
|
681
|
+
result.push({
|
|
682
|
+
...node,
|
|
683
|
+
treeNo: currentIndex,
|
|
684
|
+
uniqueId,
|
|
685
|
+
processed: true
|
|
686
|
+
});
|
|
687
|
+
const shouldExpandChildren = node.children.length > 0 && (preventExpand || typeof toggleValue === "string" && expandedRows?.has(toggleValue));
|
|
688
|
+
if (shouldExpandChildren) {
|
|
689
|
+
flatten(node.children, result, index + startIndex);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
return result;
|
|
693
|
+
};
|
|
694
|
+
const flattenedData = flatten(processedData, [], 0);
|
|
695
|
+
flattenedData.forEach((item) => {
|
|
696
|
+
if (getFieldValue(item, childField)) {
|
|
697
|
+
const parentItem = flattenedData.find(
|
|
698
|
+
(parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
|
|
699
|
+
);
|
|
700
|
+
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
701
|
+
item.parentCount = parentAmount || 1;
|
|
702
|
+
} else {
|
|
703
|
+
item.parentCount = 1;
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
return flattenedData;
|
|
707
|
+
}, [
|
|
708
|
+
enabled,
|
|
709
|
+
processedData,
|
|
710
|
+
startIndex,
|
|
711
|
+
toggleField,
|
|
712
|
+
childField,
|
|
713
|
+
qtyField,
|
|
714
|
+
preventExpand,
|
|
715
|
+
expandedRows
|
|
716
|
+
]);
|
|
717
|
+
const sortedData = useMemo(() => {
|
|
718
|
+
if (!enabled) {
|
|
719
|
+
return data ?? [];
|
|
720
|
+
}
|
|
721
|
+
return [...flattenTree].sort((a, b) => {
|
|
722
|
+
const aParts = String(a.treeNo ?? "").split("-").map(Number);
|
|
723
|
+
const bParts = String(b.treeNo ?? "").split("-").map(Number);
|
|
724
|
+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
|
725
|
+
const aVal = aParts[i] || 0;
|
|
726
|
+
const bVal = bParts[i] || 0;
|
|
727
|
+
if (aVal !== bVal) {
|
|
728
|
+
return aVal - bVal;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return 0;
|
|
732
|
+
});
|
|
733
|
+
}, [enabled, data, flattenTree]);
|
|
734
|
+
return sortedData;
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
// src/components/ui/table/features/row-selection/rowSelection.ts
|
|
738
|
+
function resolveRowSelection(mode, controlledSelection, internalSelection) {
|
|
739
|
+
if (mode === "none") return {};
|
|
740
|
+
return controlledSelection ?? internalSelection;
|
|
741
|
+
}
|
|
742
|
+
function normalizeSingleSelection(next) {
|
|
743
|
+
const selectedIds = Object.keys(next).filter((id) => next[id]);
|
|
744
|
+
if (selectedIds.length <= 1) return next;
|
|
745
|
+
return { [selectedIds[selectedIds.length - 1]]: true };
|
|
746
|
+
}
|
|
747
|
+
function applySelectionUpdater(mode, updater, previous) {
|
|
748
|
+
const next = typeof updater === "function" ? updater(previous) : updater;
|
|
749
|
+
return mode === "single" ? normalizeSingleSelection(next) : next;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/components/ui/table/features/row-span/rowSpan.ts
|
|
753
|
+
function getRowFieldValue(row, key) {
|
|
754
|
+
return row[key];
|
|
755
|
+
}
|
|
756
|
+
function computeRowSpans(data, rowSpanKey) {
|
|
757
|
+
if (data.length === 0) return [];
|
|
758
|
+
const result = [];
|
|
759
|
+
for (let index = 0; index < data.length; index++) {
|
|
760
|
+
const currentValue = getRowFieldValue(data[index], rowSpanKey);
|
|
761
|
+
const previousValue = index > 0 ? getRowFieldValue(data[index - 1], rowSpanKey) : void 0;
|
|
762
|
+
if (index > 0 && currentValue === previousValue) {
|
|
763
|
+
result.push({ rowSpan: 0, isFirstInGroup: false });
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
let span = 1;
|
|
767
|
+
for (let nextIndex = index + 1; nextIndex < data.length; nextIndex++) {
|
|
768
|
+
if (getRowFieldValue(data[nextIndex], rowSpanKey) === currentValue) {
|
|
769
|
+
span++;
|
|
770
|
+
} else {
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
result.push({ rowSpan: span, isFirstInGroup: true });
|
|
775
|
+
}
|
|
776
|
+
return result;
|
|
777
|
+
}
|
|
778
|
+
function resolveRowSpanAt(rowSpans, rowIndex) {
|
|
779
|
+
if (!rowSpans?.[rowIndex]) {
|
|
780
|
+
return { startRow: rowIndex, rowSpan: 1 };
|
|
781
|
+
}
|
|
782
|
+
const current = rowSpans[rowIndex];
|
|
783
|
+
if (current.rowSpan > 0) {
|
|
784
|
+
return { startRow: rowIndex, rowSpan: current.rowSpan };
|
|
785
|
+
}
|
|
786
|
+
for (let row = rowIndex - 1; row >= 0; row--) {
|
|
787
|
+
const info = rowSpans[row];
|
|
788
|
+
if (info && info.rowSpan > 0) {
|
|
789
|
+
return { startRow: row, rowSpan: info.rowSpan };
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return { startRow: rowIndex, rowSpan: 1 };
|
|
793
|
+
}
|
|
794
|
+
function buildColumnRowSpanMap(data, columnKeys) {
|
|
795
|
+
const map = /* @__PURE__ */ new Map();
|
|
796
|
+
for (const { columnId, rowSpanKey } of columnKeys) {
|
|
797
|
+
map.set(columnId, computeRowSpans(data, rowSpanKey));
|
|
798
|
+
}
|
|
799
|
+
return map;
|
|
800
|
+
}
|
|
801
|
+
function collectRowSpanColumns(columns) {
|
|
802
|
+
const result = [];
|
|
803
|
+
const visit = (defs) => {
|
|
804
|
+
for (const columnDef of defs) {
|
|
805
|
+
if ("columns" in columnDef && columnDef.columns?.length) {
|
|
806
|
+
visit(columnDef.columns);
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
const columnId = columnDef.id ?? ("accessorKey" in columnDef && columnDef.accessorKey ? String(columnDef.accessorKey) : void 0);
|
|
810
|
+
if (!columnId || !columnDef.meta?.rowSpan) continue;
|
|
811
|
+
result.push({
|
|
812
|
+
columnId,
|
|
813
|
+
rowSpanKey: columnDef.meta.rowSpanKey ?? columnId
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
visit(columns);
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// src/core/useGlideTable.ts
|
|
822
|
+
function useGlideTable(options) {
|
|
823
|
+
const {
|
|
824
|
+
data,
|
|
825
|
+
columns,
|
|
826
|
+
rowSelectionMode = "none",
|
|
827
|
+
rowSelection: controlledRowSelection,
|
|
828
|
+
onRowSelectionChange,
|
|
829
|
+
selectionLabel,
|
|
830
|
+
emptyText,
|
|
831
|
+
loadingText,
|
|
832
|
+
labels: labelsProp,
|
|
833
|
+
enableRowSpan = false,
|
|
834
|
+
getRowId,
|
|
835
|
+
onRowClick,
|
|
836
|
+
getRowClassName,
|
|
837
|
+
getRowCanSelect,
|
|
838
|
+
selectOnRowClick = true,
|
|
839
|
+
enableCellSelection = true,
|
|
840
|
+
onDataChange,
|
|
841
|
+
onCellChange,
|
|
842
|
+
onBatchChange,
|
|
843
|
+
preserveRowSelection = false,
|
|
844
|
+
toggleField,
|
|
845
|
+
childField,
|
|
846
|
+
flattenField,
|
|
847
|
+
qtyField,
|
|
848
|
+
expandedRows: controlledExpandedRows,
|
|
849
|
+
onExpandedRowsChange,
|
|
850
|
+
preventExpand = false,
|
|
851
|
+
enableVirtualization = true,
|
|
852
|
+
estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
|
|
853
|
+
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
|
|
854
|
+
} = options;
|
|
855
|
+
const labels = useMemo2(() => {
|
|
856
|
+
const resolved = resolveDataTableLabels(labelsProp);
|
|
857
|
+
return {
|
|
858
|
+
...resolved,
|
|
859
|
+
empty: labelsProp?.empty ?? emptyText ?? resolved.empty,
|
|
860
|
+
loading: labelsProp?.loading ?? loadingText ?? resolved.loading,
|
|
861
|
+
selection: labelsProp?.selection ?? selectionLabel ?? resolved.selection
|
|
862
|
+
};
|
|
863
|
+
}, [labelsProp, emptyText, loadingText, selectionLabel]);
|
|
864
|
+
const enableExpand = Boolean(toggleField);
|
|
865
|
+
const [internalRowSelection, setInternalRowSelection] = useState3({});
|
|
866
|
+
const [internalExpandedRows, setInternalExpandedRows] = useState3(
|
|
867
|
+
() => /* @__PURE__ */ new Set()
|
|
868
|
+
);
|
|
869
|
+
const [hoveredRowIndex, setHoveredRowIndex] = useState3(null);
|
|
870
|
+
const [hoveredGroupKey, setHoveredGroupKey] = useState3(null);
|
|
871
|
+
const scrollRef = useRef3(null);
|
|
872
|
+
const shouldVirtualize = enableVirtualization && !enableRowSpan;
|
|
873
|
+
useEffect4(() => {
|
|
874
|
+
if (enableVirtualization && enableRowSpan) {
|
|
875
|
+
console.warn(
|
|
876
|
+
"[useGlideTable] enableRowSpan is on; virtualization is disabled to preserve cell merges."
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
}, [enableVirtualization, enableRowSpan]);
|
|
880
|
+
const rowSelection = resolveRowSelection(
|
|
881
|
+
rowSelectionMode,
|
|
882
|
+
controlledRowSelection,
|
|
883
|
+
internalRowSelection
|
|
884
|
+
);
|
|
885
|
+
const expandedRows = controlledExpandedRows ?? internalExpandedRows;
|
|
886
|
+
const handleExpandedRowsChange = useCallback3(
|
|
887
|
+
(next) => {
|
|
888
|
+
if (onExpandedRowsChange) {
|
|
889
|
+
onExpandedRowsChange(next);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
setInternalExpandedRows(next);
|
|
893
|
+
},
|
|
894
|
+
[onExpandedRowsChange]
|
|
895
|
+
);
|
|
896
|
+
const tableData = useConvertTreeData({
|
|
897
|
+
data,
|
|
898
|
+
enabled: enableExpand,
|
|
899
|
+
toggleField,
|
|
900
|
+
childField,
|
|
901
|
+
flattenField,
|
|
902
|
+
qtyField,
|
|
903
|
+
expandedRows,
|
|
904
|
+
onExpandedRowsChange: enableExpand ? handleExpandedRowsChange : void 0,
|
|
905
|
+
preventExpand
|
|
906
|
+
});
|
|
907
|
+
const table = useReactTable({
|
|
908
|
+
data: tableData,
|
|
909
|
+
columns,
|
|
910
|
+
state: {
|
|
911
|
+
rowSelection: rowSelectionMode === "none" ? {} : rowSelection
|
|
912
|
+
},
|
|
913
|
+
enableRowSelection: rowSelectionMode === "none" ? false : getRowCanSelect ? (row) => getRowCanSelect(row.original, row.index) : true,
|
|
914
|
+
enableMultiRowSelection: rowSelectionMode === "multi",
|
|
915
|
+
onRowSelectionChange: (updater) => {
|
|
916
|
+
if (onRowSelectionChange) {
|
|
917
|
+
onRowSelectionChange(
|
|
918
|
+
(previous) => applySelectionUpdater(rowSelectionMode, updater, previous)
|
|
919
|
+
);
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
setInternalRowSelection(
|
|
923
|
+
(previous) => applySelectionUpdater(rowSelectionMode, updater, previous)
|
|
924
|
+
);
|
|
925
|
+
},
|
|
926
|
+
getCoreRowModel: getCoreRowModel(),
|
|
927
|
+
getRowId: getRowId ? (originalRow, index) => getRowId(originalRow, index) : (_originalRow, index) => String(index)
|
|
928
|
+
});
|
|
929
|
+
const rowSpanColumnKeys = useMemo2(() => {
|
|
930
|
+
if (!enableRowSpan) return [];
|
|
931
|
+
return collectRowSpanColumns(columns);
|
|
932
|
+
}, [enableRowSpan, columns]);
|
|
933
|
+
const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
|
|
934
|
+
const columnRowSpanMap = useMemo2(
|
|
935
|
+
() => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
|
|
936
|
+
[tableData, rowSpanColumnKeys]
|
|
937
|
+
);
|
|
938
|
+
const selectedRows = table.getSelectedRowModel().rows;
|
|
939
|
+
const selectedCount = selectedRows.length;
|
|
940
|
+
const rows = table.getRowModel().rows;
|
|
941
|
+
const columnCount = table.getAllLeafColumns().length || 1;
|
|
942
|
+
const rowVirtualizer = useVirtualizer({
|
|
943
|
+
count: shouldVirtualize ? rows.length : 0,
|
|
944
|
+
getScrollElement: () => scrollRef.current,
|
|
945
|
+
estimateSize: () => estimateRowHeight,
|
|
946
|
+
overscan: virtualOverscan
|
|
947
|
+
});
|
|
948
|
+
const virtualRows = rowVirtualizer.getVirtualItems();
|
|
949
|
+
const totalSize = rowVirtualizer.getTotalSize();
|
|
950
|
+
const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
951
|
+
const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
|
|
952
|
+
const selectedGroupKeys = useMemo2(() => {
|
|
953
|
+
if (!enableRowSpan || !primaryRowSpanKey) return /* @__PURE__ */ new Set();
|
|
954
|
+
const keys = /* @__PURE__ */ new Set();
|
|
955
|
+
for (const selectedRow of selectedRows) {
|
|
956
|
+
const value = selectedRow.original[primaryRowSpanKey];
|
|
957
|
+
if (value !== null && value !== void 0) keys.add(String(value));
|
|
958
|
+
}
|
|
959
|
+
return keys;
|
|
960
|
+
}, [enableRowSpan, primaryRowSpanKey, selectedRows]);
|
|
961
|
+
const {
|
|
962
|
+
dragState,
|
|
963
|
+
activeSelectionBounds,
|
|
964
|
+
handleCellMouseDown,
|
|
965
|
+
handleCellMouseEnter,
|
|
966
|
+
handleFillHandleMouseDown
|
|
967
|
+
} = useCellSelection({
|
|
968
|
+
data: tableData,
|
|
969
|
+
rows,
|
|
970
|
+
enabled: enableCellSelection,
|
|
971
|
+
onDataChange,
|
|
972
|
+
onBatchChange
|
|
973
|
+
});
|
|
974
|
+
const {
|
|
975
|
+
editingCell,
|
|
976
|
+
draftValue,
|
|
977
|
+
setDraftValue,
|
|
978
|
+
startEdit,
|
|
979
|
+
commitEdit,
|
|
980
|
+
cancelEdit
|
|
981
|
+
} = useCellEdit({ data: tableData, rows, onDataChange, onCellChange });
|
|
982
|
+
const handleCellMouseDownWithCommit = useCallback3(
|
|
983
|
+
(rowIndex, colIndex) => {
|
|
984
|
+
const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
|
|
985
|
+
if (editingCell && !isSameEditingCell && !commitEdit()) {
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
handleCellMouseDown(rowIndex, colIndex);
|
|
989
|
+
},
|
|
990
|
+
[commitEdit, editingCell, handleCellMouseDown]
|
|
991
|
+
);
|
|
992
|
+
const clearHover = useCallback3(() => {
|
|
993
|
+
setHoveredRowIndex(null);
|
|
994
|
+
setHoveredGroupKey(null);
|
|
995
|
+
}, []);
|
|
996
|
+
const handleRowHover = useCallback3(
|
|
997
|
+
(rowIndex, rowData) => {
|
|
998
|
+
setHoveredRowIndex(rowIndex);
|
|
999
|
+
if (!primaryRowSpanKey) {
|
|
1000
|
+
setHoveredGroupKey(null);
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
const groupValue = rowData[primaryRowSpanKey];
|
|
1004
|
+
setHoveredGroupKey(
|
|
1005
|
+
groupValue === null || groupValue === void 0 ? null : String(groupValue)
|
|
1006
|
+
);
|
|
1007
|
+
},
|
|
1008
|
+
[primaryRowSpanKey]
|
|
1009
|
+
);
|
|
1010
|
+
const handleToggleSelect = useCallback3(
|
|
1011
|
+
(row) => {
|
|
1012
|
+
if (!row.getCanSelect()) return;
|
|
1013
|
+
if (preserveRowSelection && row.getIsSelected()) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
row.toggleSelected();
|
|
1017
|
+
},
|
|
1018
|
+
[preserveRowSelection]
|
|
1019
|
+
);
|
|
1020
|
+
const handleToggleExpand = useCallback3(
|
|
1021
|
+
(rowKey) => {
|
|
1022
|
+
if (preventExpand) return;
|
|
1023
|
+
handleExpandedRowsChange(toggleExpandedRowId(rowKey, expandedRows));
|
|
1024
|
+
},
|
|
1025
|
+
[preventExpand, handleExpandedRowsChange, expandedRows]
|
|
1026
|
+
);
|
|
1027
|
+
const rowContextValue = useMemo2(() => {
|
|
1028
|
+
return {
|
|
1029
|
+
rowSpan: {
|
|
1030
|
+
enableRowSpan,
|
|
1031
|
+
primaryRowSpanKey,
|
|
1032
|
+
columnRowSpanMap,
|
|
1033
|
+
hoveredRowIndex,
|
|
1034
|
+
hoveredGroupKey,
|
|
1035
|
+
selectedGroupKeys,
|
|
1036
|
+
onRowHover: handleRowHover
|
|
1037
|
+
},
|
|
1038
|
+
selection: {
|
|
1039
|
+
rowSelectionMode,
|
|
1040
|
+
selectOnRowClick,
|
|
1041
|
+
onRowClick,
|
|
1042
|
+
getRowClassName
|
|
1043
|
+
},
|
|
1044
|
+
cellSelection: {
|
|
1045
|
+
enableCellSelection,
|
|
1046
|
+
activeSelectionBounds,
|
|
1047
|
+
dragState,
|
|
1048
|
+
onCellMouseDown: handleCellMouseDownWithCommit,
|
|
1049
|
+
onCellMouseEnter: handleCellMouseEnter,
|
|
1050
|
+
onFillHandleMouseDown: handleFillHandleMouseDown
|
|
1051
|
+
},
|
|
1052
|
+
cellEdit: {
|
|
1053
|
+
editingCell,
|
|
1054
|
+
draftValue,
|
|
1055
|
+
onDraftValueChange: setDraftValue,
|
|
1056
|
+
onStartEdit: startEdit,
|
|
1057
|
+
onCommitEdit: commitEdit,
|
|
1058
|
+
onCancelEdit: cancelEdit
|
|
1059
|
+
},
|
|
1060
|
+
expand: {
|
|
1061
|
+
enableExpand,
|
|
1062
|
+
toggleField,
|
|
1063
|
+
expandedRows,
|
|
1064
|
+
preventExpand,
|
|
1065
|
+
onToggleExpand: handleToggleExpand,
|
|
1066
|
+
expandRowLabel: labels.expandRow,
|
|
1067
|
+
collapseRowLabel: labels.collapseRow
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
}, [
|
|
1071
|
+
enableRowSpan,
|
|
1072
|
+
primaryRowSpanKey,
|
|
1073
|
+
columnRowSpanMap,
|
|
1074
|
+
hoveredRowIndex,
|
|
1075
|
+
hoveredGroupKey,
|
|
1076
|
+
selectedGroupKeys,
|
|
1077
|
+
handleRowHover,
|
|
1078
|
+
rowSelectionMode,
|
|
1079
|
+
selectOnRowClick,
|
|
1080
|
+
onRowClick,
|
|
1081
|
+
getRowClassName,
|
|
1082
|
+
enableCellSelection,
|
|
1083
|
+
activeSelectionBounds,
|
|
1084
|
+
dragState,
|
|
1085
|
+
handleCellMouseDownWithCommit,
|
|
1086
|
+
handleCellMouseEnter,
|
|
1087
|
+
handleFillHandleMouseDown,
|
|
1088
|
+
editingCell,
|
|
1089
|
+
draftValue,
|
|
1090
|
+
setDraftValue,
|
|
1091
|
+
startEdit,
|
|
1092
|
+
commitEdit,
|
|
1093
|
+
cancelEdit,
|
|
1094
|
+
enableExpand,
|
|
1095
|
+
toggleField,
|
|
1096
|
+
expandedRows,
|
|
1097
|
+
preventExpand,
|
|
1098
|
+
handleToggleExpand,
|
|
1099
|
+
labels.expandRow,
|
|
1100
|
+
labels.collapseRow
|
|
1101
|
+
]);
|
|
1102
|
+
return {
|
|
1103
|
+
table,
|
|
1104
|
+
tableData,
|
|
1105
|
+
rows,
|
|
1106
|
+
columnCount,
|
|
1107
|
+
selectedCount,
|
|
1108
|
+
labels,
|
|
1109
|
+
emptyText: labels.empty,
|
|
1110
|
+
loadingText: labels.loading,
|
|
1111
|
+
selectionLabel: labels.selection,
|
|
1112
|
+
enableCellSelection,
|
|
1113
|
+
shouldVirtualize,
|
|
1114
|
+
scrollRef,
|
|
1115
|
+
rowVirtualizer,
|
|
1116
|
+
virtualRows,
|
|
1117
|
+
paddingTop,
|
|
1118
|
+
paddingBottom,
|
|
1119
|
+
rowContextValue,
|
|
1120
|
+
handleToggleSelect,
|
|
1121
|
+
clearHover
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
export {
|
|
1125
|
+
CELL_SELECTION_EDGES_CLASS,
|
|
1126
|
+
DEFAULT_DATA_TABLE_LABELS,
|
|
1127
|
+
DEFAULT_TREE_CHILDREN_FIELD,
|
|
1128
|
+
DEFAULT_TREE_ID_FIELD,
|
|
1129
|
+
DEFAULT_TREE_PARENT_ID_FIELD,
|
|
1130
|
+
DEFAULT_TREE_QTY_FIELD,
|
|
1131
|
+
applyCellEdit,
|
|
1132
|
+
applyFillData,
|
|
1133
|
+
applySelectionUpdater,
|
|
1134
|
+
buildColumnRowSpanMap,
|
|
1135
|
+
canExpandRow,
|
|
1136
|
+
collectFillChanges,
|
|
1137
|
+
collectRowSpanColumns,
|
|
1138
|
+
getCellEditDraftValue,
|
|
1139
|
+
getCellSelectionEdgeStyle,
|
|
1140
|
+
getColumnEditType,
|
|
1141
|
+
getRowIndexInMergedCell,
|
|
1142
|
+
hasCellSelectionEdges,
|
|
1143
|
+
isCellInSelection,
|
|
1144
|
+
isColumnEditable,
|
|
1145
|
+
parseCellEditValue,
|
|
1146
|
+
resolveDataTableLabels,
|
|
1147
|
+
resolveRowSelection,
|
|
1148
|
+
resolveRowSpanAt,
|
|
1149
|
+
toggleExpandedRowId,
|
|
1150
|
+
useCellEdit,
|
|
1151
|
+
useCellSelection,
|
|
1152
|
+
useConvertTreeData,
|
|
1153
|
+
useGlideTable
|
|
1154
|
+
};
|