react-glide-table 1.1.4 → 1.1.6
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/LICENSE +21 -0
- package/README.md +38 -3
- package/dist/compound.cjs +515 -128
- package/dist/compound.d.cts +2 -2
- package/dist/compound.d.ts +2 -2
- package/dist/compound.js +519 -132
- package/dist/core.cjs +523 -119
- package/dist/core.d.cts +82 -8
- package/dist/core.d.ts +82 -8
- package/dist/core.js +515 -124
- package/dist/index.cjs +565 -130
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +560 -138
- package/dist/{types-BfthylVR.d.cts → types-DOLnknDe.d.cts} +52 -1
- package/dist/{types-BfthylVR.d.ts → types-DOLnknDe.d.ts} +52 -1
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
useCallback as useCallback3,
|
|
32
32
|
useEffect as useEffect4,
|
|
33
33
|
useMemo as useMemo2,
|
|
34
|
-
useRef as
|
|
34
|
+
useRef as useRef4,
|
|
35
35
|
useState as useState3
|
|
36
36
|
} from "react";
|
|
37
37
|
|
|
@@ -167,7 +167,7 @@ function useCellEdit({
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
170
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
170
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
171
171
|
|
|
172
172
|
// src/components/ui/table/features/cell-selection/cellSelection.ts
|
|
173
173
|
var INITIAL_DRAG_STATE = {
|
|
@@ -187,10 +187,36 @@ function getCellSelectionBounds(start, end) {
|
|
|
187
187
|
endCol: Math.max(start.col, end.col)
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
|
+
function measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement) {
|
|
191
|
+
if (rowSpan <= 1) return void 0;
|
|
192
|
+
const tbody = cellElement?.closest("tbody") ?? (typeof document !== "undefined" ? document.querySelector("tbody.data-table-body") : null);
|
|
193
|
+
if (!tbody) return void 0;
|
|
194
|
+
const rows = tbody.querySelectorAll(":scope > tr");
|
|
195
|
+
if (rows.length < rowIndex + rowSpan) return void 0;
|
|
196
|
+
const heights = [];
|
|
197
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
198
|
+
const row = rows[rowIndex + i];
|
|
199
|
+
const height = row?.getBoundingClientRect().height ?? 0;
|
|
200
|
+
if (height <= 0) return void 0;
|
|
201
|
+
heights.push(height);
|
|
202
|
+
}
|
|
203
|
+
return heights;
|
|
204
|
+
}
|
|
190
205
|
function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
|
|
191
206
|
if (rowSpan <= 1) return rowIndex;
|
|
192
207
|
const rect = cellElement.getBoundingClientRect();
|
|
193
208
|
const relativeY = clientY - rect.top;
|
|
209
|
+
const heights = measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement);
|
|
210
|
+
if (heights && heights.length === rowSpan) {
|
|
211
|
+
let accrued = 0;
|
|
212
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
213
|
+
accrued += heights[i];
|
|
214
|
+
if (relativeY < accrued) {
|
|
215
|
+
return rowIndex + i;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return rowIndex + rowSpan - 1;
|
|
219
|
+
}
|
|
194
220
|
const rowHeight = rect.height / rowSpan;
|
|
195
221
|
const offset = Math.min(
|
|
196
222
|
Math.max(Math.floor(relativeY / rowHeight), 0),
|
|
@@ -212,7 +238,35 @@ function getActiveSelectionBounds(dragState, selectionBounds) {
|
|
|
212
238
|
var SELECTION_EDGE_WIDTH_PX = 2;
|
|
213
239
|
var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
|
|
214
240
|
var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
|
|
215
|
-
function
|
|
241
|
+
function rowRangeToHeightRatios(rowIndex, span, fromRow, toRowExclusive, rowHeights) {
|
|
242
|
+
const clampedFrom = Math.max(fromRow, rowIndex);
|
|
243
|
+
const clampedTo = Math.min(toRowExclusive, rowIndex + span);
|
|
244
|
+
if (clampedTo <= clampedFrom) {
|
|
245
|
+
return { offsetRatio: 0, lengthRatio: 0 };
|
|
246
|
+
}
|
|
247
|
+
if (!rowHeights || rowHeights.length !== span) {
|
|
248
|
+
return {
|
|
249
|
+
offsetRatio: (clampedFrom - rowIndex) / span,
|
|
250
|
+
lengthRatio: (clampedTo - clampedFrom) / span
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const total = rowHeights.reduce((sum, height) => sum + height, 0) || 1;
|
|
254
|
+
let offsetPx = 0;
|
|
255
|
+
for (let i = 0; i < clampedFrom - rowIndex; i++) {
|
|
256
|
+
offsetPx += rowHeights[i] ?? 0;
|
|
257
|
+
}
|
|
258
|
+
let lengthPx = 0;
|
|
259
|
+
for (let i = clampedFrom - rowIndex; i < clampedTo - rowIndex; i++) {
|
|
260
|
+
lengthPx += rowHeights[i] ?? 0;
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
offsetRatio: offsetPx / total,
|
|
264
|
+
lengthRatio: lengthPx / total,
|
|
265
|
+
offsetPx,
|
|
266
|
+
lengthPx
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt, rowHeights) {
|
|
216
270
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
217
271
|
const span = cellEndRow - rowIndex + 1;
|
|
218
272
|
if (span <= 1) return [];
|
|
@@ -231,20 +285,30 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
231
285
|
continue;
|
|
232
286
|
}
|
|
233
287
|
if (runStart !== null) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
288
|
+
const ratios = rowRangeToHeightRatios(
|
|
289
|
+
rowIndex,
|
|
290
|
+
span,
|
|
291
|
+
runStart,
|
|
292
|
+
row,
|
|
293
|
+
rowHeights
|
|
294
|
+
);
|
|
295
|
+
if (ratios.lengthRatio > 0) {
|
|
296
|
+
edges.push({ side, ...ratios });
|
|
297
|
+
}
|
|
239
298
|
runStart = null;
|
|
240
299
|
}
|
|
241
300
|
}
|
|
242
301
|
if (runStart !== null) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
302
|
+
const ratios = rowRangeToHeightRatios(
|
|
303
|
+
rowIndex,
|
|
304
|
+
span,
|
|
305
|
+
runStart,
|
|
306
|
+
toRowExclusive,
|
|
307
|
+
rowHeights
|
|
308
|
+
);
|
|
309
|
+
if (ratios.lengthRatio > 0) {
|
|
310
|
+
edges.push({ side, ...ratios });
|
|
311
|
+
}
|
|
248
312
|
}
|
|
249
313
|
};
|
|
250
314
|
const collectSide = (side, neighborCol) => {
|
|
@@ -273,14 +337,17 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
273
337
|
}
|
|
274
338
|
return edges;
|
|
275
339
|
}
|
|
276
|
-
function
|
|
340
|
+
function buildPartialEdgeGradient(edge) {
|
|
341
|
+
const usePx = edge.offsetPx != null && edge.lengthPx != null;
|
|
277
342
|
const startPct = edge.offsetRatio * 100;
|
|
278
|
-
const endPct = (edge.offsetRatio + edge.
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const
|
|
343
|
+
const endPct = (edge.offsetRatio + edge.lengthRatio) * 100;
|
|
344
|
+
const startPx = edge.offsetPx ?? 0;
|
|
345
|
+
const endPx = (edge.offsetPx ?? 0) + (edge.lengthPx ?? 0);
|
|
346
|
+
const overlapPx = SELECTION_EDGE_WIDTH_PX;
|
|
347
|
+
const isTopProtrusion = (usePx ? startPx === 0 : edge.offsetRatio === 0) && edge.lengthRatio < 1;
|
|
348
|
+
const isBottomProtrusion = usePx ? startPx > 0 : edge.offsetRatio > 0;
|
|
349
|
+
const startStop = usePx ? isBottomProtrusion ? `${Math.max(0, startPx - overlapPx)}px` : `${startPx}px` : isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
|
|
350
|
+
const endStop = usePx ? isTopProtrusion ? `${endPx + overlapPx}px` : `${endPx}px` : isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
|
|
284
351
|
const xPos = edge.side === "left" ? "0" : "100%";
|
|
285
352
|
const layers = [
|
|
286
353
|
{
|
|
@@ -290,7 +357,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
290
357
|
}
|
|
291
358
|
];
|
|
292
359
|
if (isTopProtrusion || isBottomProtrusion) {
|
|
293
|
-
const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
360
|
+
const capTop = usePx ? isTopProtrusion ? `${Math.max(0, endPx - SELECTION_EDGE_WIDTH_PX)}px` : `${Math.max(0, startPx - SELECTION_EDGE_WIDTH_PX)}px` : isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
294
361
|
layers.push({
|
|
295
362
|
image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
|
|
296
363
|
size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
|
|
@@ -299,7 +366,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
299
366
|
}
|
|
300
367
|
return layers;
|
|
301
368
|
}
|
|
302
|
-
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
|
|
369
|
+
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt, rowHeights) {
|
|
303
370
|
if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
|
|
304
371
|
return void 0;
|
|
305
372
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
@@ -308,39 +375,47 @@ function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVi
|
|
|
308
375
|
const isLeftEdge = colIndex === bounds.startCol;
|
|
309
376
|
const isRightEdge = colIndex === bounds.endCol;
|
|
310
377
|
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
378
|
const stepEdges = getMergedCellStepEdges(
|
|
333
379
|
rowIndex,
|
|
334
380
|
colIndex,
|
|
335
381
|
bounds,
|
|
336
382
|
rowSpan,
|
|
337
|
-
isVisuallySelectedAt
|
|
383
|
+
isVisuallySelectedAt,
|
|
384
|
+
rowHeights
|
|
338
385
|
);
|
|
386
|
+
const shadows = [];
|
|
387
|
+
const hasFullPerimeter = isTopEdge && isBottomEdge && isLeftEdge && isRightEdge && stepEdges.length === 0;
|
|
388
|
+
if (hasFullPerimeter) {
|
|
389
|
+
shadows.push(
|
|
390
|
+
`inset 0 0 0 ${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_COLOR}`
|
|
391
|
+
);
|
|
392
|
+
} else {
|
|
393
|
+
if (isTopEdge) {
|
|
394
|
+
shadows.push(
|
|
395
|
+
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
if (isBottomEdge) {
|
|
399
|
+
shadows.push(
|
|
400
|
+
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
if (isLeftEdge) {
|
|
404
|
+
shadows.push(
|
|
405
|
+
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
if (isRightEdge) {
|
|
409
|
+
shadows.push(
|
|
410
|
+
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
339
414
|
const gradients = [];
|
|
340
415
|
const sizes = [];
|
|
341
416
|
const positions = [];
|
|
342
417
|
for (const edge of stepEdges) {
|
|
343
|
-
for (const partial of
|
|
418
|
+
for (const partial of buildPartialEdgeGradient(edge)) {
|
|
344
419
|
gradients.push(partial.image);
|
|
345
420
|
sizes.push(partial.size);
|
|
346
421
|
positions.push(partial.position);
|
|
@@ -369,6 +444,127 @@ function hasCellSelectionEdges(style) {
|
|
|
369
444
|
);
|
|
370
445
|
}
|
|
371
446
|
|
|
447
|
+
// src/components/ui/table/features/cell-selection/copyData.ts
|
|
448
|
+
function formatCellValue(value) {
|
|
449
|
+
if (value === null || value === void 0) return "";
|
|
450
|
+
return String(value);
|
|
451
|
+
}
|
|
452
|
+
function getNestedValue(row, path) {
|
|
453
|
+
if (!path.includes(".")) return row[path];
|
|
454
|
+
return path.split(".").reduce((current, key) => {
|
|
455
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
456
|
+
return void 0;
|
|
457
|
+
}
|
|
458
|
+
return current[key];
|
|
459
|
+
}, row);
|
|
460
|
+
}
|
|
461
|
+
function readRowColumnValue(rowData, columnDef) {
|
|
462
|
+
if ("accessorFn" in columnDef && typeof columnDef.accessorFn === "function") {
|
|
463
|
+
return columnDef.accessorFn(rowData, 0);
|
|
464
|
+
}
|
|
465
|
+
if ("accessorKey" in columnDef && columnDef.accessorKey != null && columnDef.accessorKey !== "") {
|
|
466
|
+
return getNestedValue(rowData, String(columnDef.accessorKey));
|
|
467
|
+
}
|
|
468
|
+
return void 0;
|
|
469
|
+
}
|
|
470
|
+
function flattenSubtreeRows(row) {
|
|
471
|
+
const children = row.children;
|
|
472
|
+
if (!Array.isArray(children) || children.length === 0) return [];
|
|
473
|
+
const result = [];
|
|
474
|
+
const walk = (nodes) => {
|
|
475
|
+
for (const node of nodes) {
|
|
476
|
+
result.push(node);
|
|
477
|
+
const nested = node.children;
|
|
478
|
+
if (Array.isArray(nested) && nested.length > 0) {
|
|
479
|
+
walk(nested);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
walk(children);
|
|
484
|
+
return result;
|
|
485
|
+
}
|
|
486
|
+
function hasSubtree(row) {
|
|
487
|
+
const children = row.children;
|
|
488
|
+
return Array.isArray(children) && children.length > 0;
|
|
489
|
+
}
|
|
490
|
+
function getOriginalRowId(original) {
|
|
491
|
+
return String(original.id ?? original.uniqueId ?? "");
|
|
492
|
+
}
|
|
493
|
+
function getRowDepth(original) {
|
|
494
|
+
return typeof original.level === "number" ? original.level : 0;
|
|
495
|
+
}
|
|
496
|
+
function collectCopyRowEntries(visibleRows, bounds, mode = "visible") {
|
|
497
|
+
const { startRow, endRow } = bounds;
|
|
498
|
+
const result = [];
|
|
499
|
+
const includedOriginalIds = /* @__PURE__ */ new Set();
|
|
500
|
+
const appendSubtree = (node, depth) => {
|
|
501
|
+
const children = node.children;
|
|
502
|
+
if (!Array.isArray(children) || children.length === 0) return;
|
|
503
|
+
for (const child of children) {
|
|
504
|
+
const childId = getOriginalRowId(child);
|
|
505
|
+
if (!(childId && includedOriginalIds.has(childId))) {
|
|
506
|
+
result.push({ row: child, depth });
|
|
507
|
+
if (childId) includedOriginalIds.add(childId);
|
|
508
|
+
}
|
|
509
|
+
appendSubtree(child, depth + 1);
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
for (let rowIndex = startRow; rowIndex <= endRow; rowIndex += 1) {
|
|
513
|
+
const row = visibleRows[rowIndex];
|
|
514
|
+
if (!row) continue;
|
|
515
|
+
const originalId = getOriginalRowId(row.original);
|
|
516
|
+
if (originalId && includedOriginalIds.has(originalId)) continue;
|
|
517
|
+
const depth = getRowDepth(row.original);
|
|
518
|
+
result.push({ row: row.original, depth });
|
|
519
|
+
if (originalId) includedOriginalIds.add(originalId);
|
|
520
|
+
if (mode !== "subtree" || !hasSubtree(row.original)) continue;
|
|
521
|
+
appendSubtree(row.original, depth + 1);
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
525
|
+
function collectCopyRows(visibleRows, bounds, mode = "visible") {
|
|
526
|
+
return collectCopyRowEntries(visibleRows, bounds, mode).map((entry) => entry.row);
|
|
527
|
+
}
|
|
528
|
+
function serializeCopyRowsToTSV(copyRows, visibleRows, bounds, depths) {
|
|
529
|
+
if (copyRows.length === 0) return "";
|
|
530
|
+
const { startCol, endCol } = bounds;
|
|
531
|
+
const columnCells = visibleRows[0]?.getVisibleCells().slice(startCol, endCol + 1) ?? [];
|
|
532
|
+
if (columnCells.length === 0) return "";
|
|
533
|
+
const resolvedDepths = depths && depths.length === copyRows.length ? depths : copyRows.map((row) => getRowDepth(row));
|
|
534
|
+
const minDepth = Math.min(...resolvedDepths);
|
|
535
|
+
return copyRows.map((rowData, index) => {
|
|
536
|
+
const relativeDepth = Math.max(0, (resolvedDepths[index] ?? 0) - minDepth);
|
|
537
|
+
const line = columnCells.map(
|
|
538
|
+
(cell) => formatCellValue(
|
|
539
|
+
readRowColumnValue(
|
|
540
|
+
rowData,
|
|
541
|
+
cell.column.columnDef
|
|
542
|
+
)
|
|
543
|
+
)
|
|
544
|
+
).join(" ");
|
|
545
|
+
return `${" ".repeat(relativeDepth)}${line}`;
|
|
546
|
+
}).join("\n");
|
|
547
|
+
}
|
|
548
|
+
function serializeSelectionToTSV(visibleRows, bounds, mode = "visible") {
|
|
549
|
+
const entries = collectCopyRowEntries(visibleRows, bounds, mode);
|
|
550
|
+
return serializeCopyRowsToTSV(
|
|
551
|
+
entries.map((entry) => entry.row),
|
|
552
|
+
visibleRows,
|
|
553
|
+
bounds,
|
|
554
|
+
entries.map((entry) => entry.depth)
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
async function writeSelectionToClipboard(visibleRows, bounds, mode = "visible") {
|
|
558
|
+
const text = serializeSelectionToTSV(visibleRows, bounds, mode);
|
|
559
|
+
if (!text) return false;
|
|
560
|
+
try {
|
|
561
|
+
await navigator.clipboard.writeText(text);
|
|
562
|
+
} catch {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
|
|
372
568
|
// src/components/ui/table/features/cell-selection/fillData.ts
|
|
373
569
|
function getColumnAccessorKey2(columnDef) {
|
|
374
570
|
if ("accessorKey" in columnDef && columnDef.accessorKey) {
|
|
@@ -425,15 +621,103 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
425
621
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
426
622
|
}
|
|
427
623
|
|
|
624
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
625
|
+
function countLeadingEmptyCells(cells) {
|
|
626
|
+
let depth = 0;
|
|
627
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
628
|
+
depth += 1;
|
|
629
|
+
}
|
|
630
|
+
return depth;
|
|
631
|
+
}
|
|
632
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
633
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
634
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
635
|
+
if (firstDepth !== 0) return false;
|
|
636
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
637
|
+
}
|
|
638
|
+
function parseClipboardTSV(text) {
|
|
639
|
+
return parseClipboardTSVWithDepths(text).values;
|
|
640
|
+
}
|
|
641
|
+
function parseClipboardTSVWithDepths(text) {
|
|
642
|
+
if (!text) return { values: [], depths: [] };
|
|
643
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
644
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
645
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
646
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
647
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
648
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
649
|
+
const values = [];
|
|
650
|
+
const depths = [];
|
|
651
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
652
|
+
const cells = rows[index] ?? [];
|
|
653
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
654
|
+
if (treatAsDepth) {
|
|
655
|
+
values.push(cells.slice(depth));
|
|
656
|
+
depths.push(depth);
|
|
657
|
+
} else {
|
|
658
|
+
values.push(cells);
|
|
659
|
+
depths.push(0);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return { values, depths };
|
|
663
|
+
}
|
|
664
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
665
|
+
if (width <= 0) return [];
|
|
666
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
667
|
+
const columnIds = [];
|
|
668
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
669
|
+
const cell = cells[startCol + offset];
|
|
670
|
+
if (!cell) break;
|
|
671
|
+
columnIds.push(cell.column.id);
|
|
672
|
+
}
|
|
673
|
+
return columnIds;
|
|
674
|
+
}
|
|
675
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
676
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
677
|
+
if (values.length === 0) return null;
|
|
678
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
679
|
+
if (width === 0) return null;
|
|
680
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
681
|
+
if (columnIds.length === 0) return null;
|
|
682
|
+
const rowIds = [];
|
|
683
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
684
|
+
const row = rows[startRow + offset];
|
|
685
|
+
if (!row) break;
|
|
686
|
+
rowIds.push(row.id);
|
|
687
|
+
}
|
|
688
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
689
|
+
return {
|
|
690
|
+
mode,
|
|
691
|
+
startRow,
|
|
692
|
+
startCol,
|
|
693
|
+
endRow,
|
|
694
|
+
rowIds,
|
|
695
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
696
|
+
columnIds,
|
|
697
|
+
values,
|
|
698
|
+
depths
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
function isEditablePasteTarget(target) {
|
|
702
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
703
|
+
const tag = target.tagName;
|
|
704
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
705
|
+
return Boolean(target.isContentEditable);
|
|
706
|
+
}
|
|
707
|
+
|
|
428
708
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
429
709
|
function useCellSelection({
|
|
430
710
|
data,
|
|
431
711
|
rows,
|
|
432
712
|
enabled = true,
|
|
713
|
+
enableSubtreeCopy = false,
|
|
714
|
+
enableInsertPaste = true,
|
|
433
715
|
onDataChange,
|
|
434
|
-
onBatchChange
|
|
716
|
+
onBatchChange,
|
|
717
|
+
onRowsPaste
|
|
435
718
|
}) {
|
|
436
719
|
const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
|
|
720
|
+
const pendingPasteModeRef = useRef2(null);
|
|
437
721
|
const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
|
|
438
722
|
const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
|
|
439
723
|
const handleCellMouseDown = useCallback2(
|
|
@@ -487,21 +771,113 @@ function useCellSelection({
|
|
|
487
771
|
setDragState(INITIAL_DRAG_STATE);
|
|
488
772
|
}
|
|
489
773
|
}, [enabled]);
|
|
774
|
+
const copySelection = useCallback2(
|
|
775
|
+
async (options) => {
|
|
776
|
+
if (!enabled || !activeSelectionBounds) return false;
|
|
777
|
+
const mode = options?.includeDescendants && enableSubtreeCopy ? "subtree" : "visible";
|
|
778
|
+
return writeSelectionToClipboard(rows, activeSelectionBounds, mode);
|
|
779
|
+
},
|
|
780
|
+
[activeSelectionBounds, enableSubtreeCopy, enabled, rows]
|
|
781
|
+
);
|
|
490
782
|
useEffect2(() => {
|
|
491
783
|
if (!enabled) return;
|
|
492
784
|
const handleKeyDown = (e) => {
|
|
493
|
-
if (
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}
|
|
785
|
+
if (!activeSelectionBounds) return;
|
|
786
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
787
|
+
const isSubtreeShortcut = enableSubtreeCopy && e.shiftKey && e.key.toLowerCase() === "c";
|
|
788
|
+
const isVisibleCopyShortcut = !e.shiftKey && e.key.toLowerCase() === "c";
|
|
789
|
+
if (!isSubtreeShortcut && !isVisibleCopyShortcut) return;
|
|
790
|
+
e.preventDefault();
|
|
791
|
+
void copySelection({ includeDescendants: isSubtreeShortcut });
|
|
501
792
|
};
|
|
502
793
|
window.addEventListener("keydown", handleKeyDown);
|
|
503
794
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
504
|
-
}, [activeSelectionBounds,
|
|
795
|
+
}, [activeSelectionBounds, copySelection, enableSubtreeCopy, enabled]);
|
|
796
|
+
const emitRowsPaste = useCallback2(
|
|
797
|
+
(text, mode) => {
|
|
798
|
+
if (!onRowsPaste || !activeSelectionBounds) return false;
|
|
799
|
+
const payload = buildRowsPastePayload(
|
|
800
|
+
rows,
|
|
801
|
+
activeSelectionBounds.startRow,
|
|
802
|
+
activeSelectionBounds.startCol,
|
|
803
|
+
text,
|
|
804
|
+
mode,
|
|
805
|
+
activeSelectionBounds.endRow
|
|
806
|
+
);
|
|
807
|
+
if (!payload) return false;
|
|
808
|
+
onRowsPaste(payload);
|
|
809
|
+
return true;
|
|
810
|
+
},
|
|
811
|
+
[activeSelectionBounds, onRowsPaste, rows]
|
|
812
|
+
);
|
|
813
|
+
useEffect2(() => {
|
|
814
|
+
if (!enabled || !onRowsPaste) return;
|
|
815
|
+
const pasteHandledRef = { current: false };
|
|
816
|
+
const ignoreNextPasteRef = { current: false };
|
|
817
|
+
const handleKeyDown = (e) => {
|
|
818
|
+
if (!activeSelectionBounds) return;
|
|
819
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
820
|
+
if (e.key.toLowerCase() !== "v") return;
|
|
821
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (e.shiftKey && !enableInsertPaste) {
|
|
825
|
+
ignoreNextPasteRef.current = true;
|
|
826
|
+
pendingPasteModeRef.current = null;
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const mode = e.shiftKey ? "insert" : "overwrite";
|
|
830
|
+
pasteHandledRef.current = false;
|
|
831
|
+
ignoreNextPasteRef.current = false;
|
|
832
|
+
pendingPasteModeRef.current = mode;
|
|
833
|
+
void (async () => {
|
|
834
|
+
try {
|
|
835
|
+
const text = await navigator.clipboard.readText();
|
|
836
|
+
if (pasteHandledRef.current) return;
|
|
837
|
+
if (pendingPasteModeRef.current !== mode) return;
|
|
838
|
+
if (!text) return;
|
|
839
|
+
pasteHandledRef.current = true;
|
|
840
|
+
emitRowsPaste(text, mode);
|
|
841
|
+
pendingPasteModeRef.current = null;
|
|
842
|
+
} catch {
|
|
843
|
+
}
|
|
844
|
+
})();
|
|
845
|
+
};
|
|
846
|
+
const handlePaste = (e) => {
|
|
847
|
+
if (!activeSelectionBounds) return;
|
|
848
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (ignoreNextPasteRef.current) {
|
|
852
|
+
ignoreNextPasteRef.current = false;
|
|
853
|
+
pendingPasteModeRef.current = null;
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const mode = pendingPasteModeRef.current ?? "overwrite";
|
|
857
|
+
if (pasteHandledRef.current) {
|
|
858
|
+
e.preventDefault();
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
const text = e.clipboardData?.getData("text/plain");
|
|
862
|
+
if (text == null || text === "") return;
|
|
863
|
+
pasteHandledRef.current = true;
|
|
864
|
+
e.preventDefault();
|
|
865
|
+
emitRowsPaste(text, mode);
|
|
866
|
+
pendingPasteModeRef.current = null;
|
|
867
|
+
};
|
|
868
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
869
|
+
window.addEventListener("paste", handlePaste);
|
|
870
|
+
return () => {
|
|
871
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
872
|
+
window.removeEventListener("paste", handlePaste);
|
|
873
|
+
};
|
|
874
|
+
}, [
|
|
875
|
+
activeSelectionBounds,
|
|
876
|
+
emitRowsPaste,
|
|
877
|
+
enableInsertPaste,
|
|
878
|
+
enabled,
|
|
879
|
+
onRowsPaste
|
|
880
|
+
]);
|
|
505
881
|
useEffect2(() => {
|
|
506
882
|
if (!enabled) return;
|
|
507
883
|
const handleMouseUp = () => {
|
|
@@ -547,12 +923,13 @@ function useCellSelection({
|
|
|
547
923
|
activeSelectionBounds,
|
|
548
924
|
handleCellMouseDown,
|
|
549
925
|
handleCellMouseEnter,
|
|
550
|
-
handleFillHandleMouseDown
|
|
926
|
+
handleFillHandleMouseDown,
|
|
927
|
+
copySelection
|
|
551
928
|
};
|
|
552
929
|
}
|
|
553
930
|
|
|
554
931
|
// src/components/ui/table/features/row-expand/row-expand.ts
|
|
555
|
-
import { useEffect as useEffect3, useMemo, useRef as
|
|
932
|
+
import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "react";
|
|
556
933
|
function getFieldValue(row, key) {
|
|
557
934
|
return row[key];
|
|
558
935
|
}
|
|
@@ -582,8 +959,8 @@ var useConvertTreeData = ({
|
|
|
582
959
|
expandedRows,
|
|
583
960
|
onExpandedRowsChange
|
|
584
961
|
}) => {
|
|
585
|
-
const onExpandedRowsChangeRef =
|
|
586
|
-
const hasInitializedRef =
|
|
962
|
+
const onExpandedRowsChangeRef = useRef3(onExpandedRowsChange);
|
|
963
|
+
const hasInitializedRef = useRef3(false);
|
|
587
964
|
useEffect3(() => {
|
|
588
965
|
onExpandedRowsChangeRef.current = onExpandedRowsChange;
|
|
589
966
|
}, [onExpandedRowsChange]);
|
|
@@ -629,15 +1006,16 @@ var useConvertTreeData = ({
|
|
|
629
1006
|
children: [],
|
|
630
1007
|
processed: false
|
|
631
1008
|
}));
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
1009
|
+
const findNearestPrecedingParent = (index, parentKey) => {
|
|
1010
|
+
for (let i = index - 1; i >= 0; i -= 1) {
|
|
1011
|
+
const candidate = dataWithLevels[i];
|
|
1012
|
+
if (!candidate) continue;
|
|
1013
|
+
if (getFieldValue(candidate, toggleField) === parentKey) {
|
|
1014
|
+
return candidate;
|
|
1015
|
+
}
|
|
638
1016
|
}
|
|
639
|
-
|
|
640
|
-
}
|
|
1017
|
+
return void 0;
|
|
1018
|
+
};
|
|
641
1019
|
const rootItems = [];
|
|
642
1020
|
dataWithLevels.forEach((item) => {
|
|
643
1021
|
if (!getFieldValue(item, childField)) {
|
|
@@ -645,29 +1023,18 @@ var useConvertTreeData = ({
|
|
|
645
1023
|
item.processed = true;
|
|
646
1024
|
}
|
|
647
1025
|
});
|
|
648
|
-
dataWithLevels.forEach((item) => {
|
|
1026
|
+
dataWithLevels.forEach((item, index) => {
|
|
649
1027
|
const parentKey = getFieldValue(item, childField);
|
|
650
1028
|
if (!parentKey || item.processed) return;
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
);
|
|
654
|
-
if (parentItems.length > 0) {
|
|
655
|
-
const parent = parentItems[0];
|
|
1029
|
+
const parent = findNearestPrecedingParent(index, parentKey);
|
|
1030
|
+
if (parent) {
|
|
656
1031
|
item.level = parent.level + 1;
|
|
657
1032
|
parent.children.push(item);
|
|
658
1033
|
item.processed = true;
|
|
659
|
-
|
|
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
|
-
}
|
|
1034
|
+
return;
|
|
670
1035
|
}
|
|
1036
|
+
rootItems.push(item);
|
|
1037
|
+
item.processed = true;
|
|
671
1038
|
});
|
|
672
1039
|
return rootItems;
|
|
673
1040
|
}, [enabled, data, toggleField, childField, flattenField]);
|
|
@@ -692,16 +1059,23 @@ var useConvertTreeData = ({
|
|
|
692
1059
|
return result;
|
|
693
1060
|
};
|
|
694
1061
|
const flattenedData = flatten(processedData, [], 0);
|
|
695
|
-
flattenedData.forEach((item) => {
|
|
696
|
-
|
|
697
|
-
|
|
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 {
|
|
1062
|
+
flattenedData.forEach((item, index) => {
|
|
1063
|
+
const parentKey = getFieldValue(item, childField);
|
|
1064
|
+
if (!parentKey) {
|
|
703
1065
|
item.parentCount = 1;
|
|
1066
|
+
return;
|
|
704
1067
|
}
|
|
1068
|
+
let parentItem;
|
|
1069
|
+
for (let i = index - 1; i >= 0; i -= 1) {
|
|
1070
|
+
const candidate = flattenedData[i];
|
|
1071
|
+
if (!candidate) continue;
|
|
1072
|
+
if (getFieldValue(candidate, toggleField) === parentKey) {
|
|
1073
|
+
parentItem = candidate;
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
1078
|
+
item.parentCount = parentAmount || 1;
|
|
705
1079
|
});
|
|
706
1080
|
return flattenedData;
|
|
707
1081
|
}, [
|
|
@@ -848,6 +1222,10 @@ function useGlideTable(options) {
|
|
|
848
1222
|
expandedRows: controlledExpandedRows,
|
|
849
1223
|
onExpandedRowsChange,
|
|
850
1224
|
preventExpand = false,
|
|
1225
|
+
enableSubtreeCopy,
|
|
1226
|
+
onCopyActionsReady,
|
|
1227
|
+
onRowsPaste,
|
|
1228
|
+
enableInsertPaste,
|
|
851
1229
|
enableVirtualization = true,
|
|
852
1230
|
estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
|
|
853
1231
|
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
|
|
@@ -862,13 +1240,13 @@ function useGlideTable(options) {
|
|
|
862
1240
|
};
|
|
863
1241
|
}, [labelsProp, emptyText, loadingText, selectionLabel]);
|
|
864
1242
|
const enableExpand = Boolean(toggleField);
|
|
1243
|
+
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
865
1244
|
const [internalRowSelection, setInternalRowSelection] = useState3({});
|
|
866
1245
|
const [internalExpandedRows, setInternalExpandedRows] = useState3(
|
|
867
1246
|
() => /* @__PURE__ */ new Set()
|
|
868
1247
|
);
|
|
869
1248
|
const [hoveredRowIndex, setHoveredRowIndex] = useState3(null);
|
|
870
|
-
const
|
|
871
|
-
const scrollRef = useRef3(null);
|
|
1249
|
+
const scrollRef = useRef4(null);
|
|
872
1250
|
const shouldVirtualize = enableVirtualization && !enableRowSpan;
|
|
873
1251
|
useEffect4(() => {
|
|
874
1252
|
if (enableVirtualization && enableRowSpan) {
|
|
@@ -931,6 +1309,7 @@ function useGlideTable(options) {
|
|
|
931
1309
|
return collectRowSpanColumns(columns);
|
|
932
1310
|
}, [enableRowSpan, columns]);
|
|
933
1311
|
const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
|
|
1312
|
+
const primaryRowSpanColumnId = rowSpanColumnKeys[0]?.columnId;
|
|
934
1313
|
const columnRowSpanMap = useMemo2(
|
|
935
1314
|
() => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
|
|
936
1315
|
[tableData, rowSpanColumnKeys]
|
|
@@ -949,27 +1328,29 @@ function useGlideTable(options) {
|
|
|
949
1328
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
950
1329
|
const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
951
1330
|
const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1331
|
+
const selectedRowIndices = useMemo2(() => {
|
|
1332
|
+
const indices = /* @__PURE__ */ new Set();
|
|
955
1333
|
for (const selectedRow of selectedRows) {
|
|
956
|
-
|
|
957
|
-
if (value !== null && value !== void 0) keys.add(String(value));
|
|
1334
|
+
indices.add(selectedRow.index);
|
|
958
1335
|
}
|
|
959
|
-
return
|
|
960
|
-
}, [
|
|
1336
|
+
return indices;
|
|
1337
|
+
}, [selectedRows]);
|
|
961
1338
|
const {
|
|
962
1339
|
dragState,
|
|
963
1340
|
activeSelectionBounds,
|
|
964
1341
|
handleCellMouseDown,
|
|
965
1342
|
handleCellMouseEnter,
|
|
966
|
-
handleFillHandleMouseDown
|
|
1343
|
+
handleFillHandleMouseDown,
|
|
1344
|
+
copySelection
|
|
967
1345
|
} = useCellSelection({
|
|
968
1346
|
data: tableData,
|
|
969
1347
|
rows,
|
|
970
1348
|
enabled: enableCellSelection,
|
|
1349
|
+
enableSubtreeCopy: resolvedEnableSubtreeCopy,
|
|
1350
|
+
enableInsertPaste: enableInsertPaste ?? true,
|
|
971
1351
|
onDataChange,
|
|
972
|
-
onBatchChange
|
|
1352
|
+
onBatchChange,
|
|
1353
|
+
onRowsPaste
|
|
973
1354
|
});
|
|
974
1355
|
const {
|
|
975
1356
|
editingCell,
|
|
@@ -991,22 +1372,10 @@ function useGlideTable(options) {
|
|
|
991
1372
|
);
|
|
992
1373
|
const clearHover = useCallback3(() => {
|
|
993
1374
|
setHoveredRowIndex(null);
|
|
994
|
-
setHoveredGroupKey(null);
|
|
995
1375
|
}, []);
|
|
996
|
-
const handleRowHover = useCallback3(
|
|
997
|
-
(rowIndex
|
|
998
|
-
|
|
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
|
-
);
|
|
1376
|
+
const handleRowHover = useCallback3((rowIndex, _rowData) => {
|
|
1377
|
+
setHoveredRowIndex(rowIndex);
|
|
1378
|
+
}, []);
|
|
1010
1379
|
const handleToggleSelect = useCallback3(
|
|
1011
1380
|
(row) => {
|
|
1012
1381
|
if (!row.getCanSelect()) return;
|
|
@@ -1029,10 +1398,10 @@ function useGlideTable(options) {
|
|
|
1029
1398
|
rowSpan: {
|
|
1030
1399
|
enableRowSpan,
|
|
1031
1400
|
primaryRowSpanKey,
|
|
1401
|
+
primaryRowSpanColumnId,
|
|
1032
1402
|
columnRowSpanMap,
|
|
1033
1403
|
hoveredRowIndex,
|
|
1034
|
-
|
|
1035
|
-
selectedGroupKeys,
|
|
1404
|
+
selectedRowIndices,
|
|
1036
1405
|
onRowHover: handleRowHover
|
|
1037
1406
|
},
|
|
1038
1407
|
selection: {
|
|
@@ -1070,10 +1439,10 @@ function useGlideTable(options) {
|
|
|
1070
1439
|
}, [
|
|
1071
1440
|
enableRowSpan,
|
|
1072
1441
|
primaryRowSpanKey,
|
|
1442
|
+
primaryRowSpanColumnId,
|
|
1073
1443
|
columnRowSpanMap,
|
|
1074
1444
|
hoveredRowIndex,
|
|
1075
|
-
|
|
1076
|
-
selectedGroupKeys,
|
|
1445
|
+
selectedRowIndices,
|
|
1077
1446
|
handleRowHover,
|
|
1078
1447
|
rowSelectionMode,
|
|
1079
1448
|
selectOnRowClick,
|
|
@@ -1099,6 +1468,14 @@ function useGlideTable(options) {
|
|
|
1099
1468
|
labels.expandRow,
|
|
1100
1469
|
labels.collapseRow
|
|
1101
1470
|
]);
|
|
1471
|
+
const copySelectionRef = useRef4(copySelection);
|
|
1472
|
+
useEffect4(() => {
|
|
1473
|
+
copySelectionRef.current = copySelection;
|
|
1474
|
+
}, [copySelection]);
|
|
1475
|
+
const stableCopySelection = useCallback3((options2) => copySelectionRef.current(options2), []);
|
|
1476
|
+
useEffect4(() => {
|
|
1477
|
+
onCopyActionsReady?.({ copySelection: stableCopySelection });
|
|
1478
|
+
}, [onCopyActionsReady, stableCopySelection]);
|
|
1102
1479
|
return {
|
|
1103
1480
|
table,
|
|
1104
1481
|
tableData,
|
|
@@ -1118,7 +1495,8 @@ function useGlideTable(options) {
|
|
|
1118
1495
|
paddingBottom,
|
|
1119
1496
|
rowContextValue,
|
|
1120
1497
|
handleToggleSelect,
|
|
1121
|
-
clearHover
|
|
1498
|
+
clearHover,
|
|
1499
|
+
copySelection: stableCopySelection
|
|
1122
1500
|
};
|
|
1123
1501
|
}
|
|
1124
1502
|
export {
|
|
@@ -1132,9 +1510,13 @@ export {
|
|
|
1132
1510
|
applyFillData,
|
|
1133
1511
|
applySelectionUpdater,
|
|
1134
1512
|
buildColumnRowSpanMap,
|
|
1513
|
+
buildRowsPastePayload,
|
|
1135
1514
|
canExpandRow,
|
|
1515
|
+
collectCopyRowEntries,
|
|
1516
|
+
collectCopyRows,
|
|
1136
1517
|
collectFillChanges,
|
|
1137
1518
|
collectRowSpanColumns,
|
|
1519
|
+
flattenSubtreeRows,
|
|
1138
1520
|
getCellEditDraftValue,
|
|
1139
1521
|
getCellSelectionEdgeStyle,
|
|
1140
1522
|
getColumnEditType,
|
|
@@ -1142,13 +1524,22 @@ export {
|
|
|
1142
1524
|
hasCellSelectionEdges,
|
|
1143
1525
|
isCellInSelection,
|
|
1144
1526
|
isColumnEditable,
|
|
1527
|
+
isEditablePasteTarget,
|
|
1528
|
+
measureMergedSpanRowHeights,
|
|
1145
1529
|
parseCellEditValue,
|
|
1530
|
+
parseClipboardTSV,
|
|
1531
|
+
parseClipboardTSVWithDepths,
|
|
1146
1532
|
resolveDataTableLabels,
|
|
1533
|
+
resolvePasteColumnIds,
|
|
1147
1534
|
resolveRowSelection,
|
|
1148
1535
|
resolveRowSpanAt,
|
|
1536
|
+
rowRangeToHeightRatios,
|
|
1537
|
+
serializeCopyRowsToTSV,
|
|
1538
|
+
serializeSelectionToTSV,
|
|
1149
1539
|
toggleExpandedRowId,
|
|
1150
1540
|
useCellEdit,
|
|
1151
1541
|
useCellSelection,
|
|
1152
1542
|
useConvertTreeData,
|
|
1153
|
-
useGlideTable
|
|
1543
|
+
useGlideTable,
|
|
1544
|
+
writeSelectionToClipboard
|
|
1154
1545
|
};
|