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.cjs
CHANGED
|
@@ -30,9 +30,13 @@ __export(core_exports, {
|
|
|
30
30
|
applyFillData: () => applyFillData,
|
|
31
31
|
applySelectionUpdater: () => applySelectionUpdater,
|
|
32
32
|
buildColumnRowSpanMap: () => buildColumnRowSpanMap,
|
|
33
|
+
buildRowsPastePayload: () => buildRowsPastePayload,
|
|
33
34
|
canExpandRow: () => canExpandRow,
|
|
35
|
+
collectCopyRowEntries: () => collectCopyRowEntries,
|
|
36
|
+
collectCopyRows: () => collectCopyRows,
|
|
34
37
|
collectFillChanges: () => collectFillChanges,
|
|
35
38
|
collectRowSpanColumns: () => collectRowSpanColumns,
|
|
39
|
+
flattenSubtreeRows: () => flattenSubtreeRows,
|
|
36
40
|
getCellEditDraftValue: () => getCellEditDraftValue,
|
|
37
41
|
getCellSelectionEdgeStyle: () => getCellSelectionEdgeStyle,
|
|
38
42
|
getColumnEditType: () => getColumnEditType,
|
|
@@ -40,15 +44,24 @@ __export(core_exports, {
|
|
|
40
44
|
hasCellSelectionEdges: () => hasCellSelectionEdges,
|
|
41
45
|
isCellInSelection: () => isCellInSelection,
|
|
42
46
|
isColumnEditable: () => isColumnEditable,
|
|
47
|
+
isEditablePasteTarget: () => isEditablePasteTarget,
|
|
48
|
+
measureMergedSpanRowHeights: () => measureMergedSpanRowHeights,
|
|
43
49
|
parseCellEditValue: () => parseCellEditValue,
|
|
50
|
+
parseClipboardTSV: () => parseClipboardTSV,
|
|
51
|
+
parseClipboardTSVWithDepths: () => parseClipboardTSVWithDepths,
|
|
44
52
|
resolveDataTableLabels: () => resolveDataTableLabels,
|
|
53
|
+
resolvePasteColumnIds: () => resolvePasteColumnIds,
|
|
45
54
|
resolveRowSelection: () => resolveRowSelection,
|
|
46
55
|
resolveRowSpanAt: () => resolveRowSpanAt,
|
|
56
|
+
rowRangeToHeightRatios: () => rowRangeToHeightRatios,
|
|
57
|
+
serializeCopyRowsToTSV: () => serializeCopyRowsToTSV,
|
|
58
|
+
serializeSelectionToTSV: () => serializeSelectionToTSV,
|
|
47
59
|
toggleExpandedRowId: () => toggleExpandedRowId,
|
|
48
60
|
useCellEdit: () => useCellEdit,
|
|
49
61
|
useCellSelection: () => useCellSelection,
|
|
50
62
|
useConvertTreeData: () => useConvertTreeData,
|
|
51
|
-
useGlideTable: () => useGlideTable
|
|
63
|
+
useGlideTable: () => useGlideTable,
|
|
64
|
+
writeSelectionToClipboard: () => writeSelectionToClipboard
|
|
52
65
|
});
|
|
53
66
|
module.exports = __toCommonJS(core_exports);
|
|
54
67
|
|
|
@@ -230,10 +243,36 @@ function getCellSelectionBounds(start, end) {
|
|
|
230
243
|
endCol: Math.max(start.col, end.col)
|
|
231
244
|
};
|
|
232
245
|
}
|
|
246
|
+
function measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement) {
|
|
247
|
+
if (rowSpan <= 1) return void 0;
|
|
248
|
+
const tbody = cellElement?.closest("tbody") ?? (typeof document !== "undefined" ? document.querySelector("tbody.data-table-body") : null);
|
|
249
|
+
if (!tbody) return void 0;
|
|
250
|
+
const rows = tbody.querySelectorAll(":scope > tr");
|
|
251
|
+
if (rows.length < rowIndex + rowSpan) return void 0;
|
|
252
|
+
const heights = [];
|
|
253
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
254
|
+
const row = rows[rowIndex + i];
|
|
255
|
+
const height = row?.getBoundingClientRect().height ?? 0;
|
|
256
|
+
if (height <= 0) return void 0;
|
|
257
|
+
heights.push(height);
|
|
258
|
+
}
|
|
259
|
+
return heights;
|
|
260
|
+
}
|
|
233
261
|
function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
|
|
234
262
|
if (rowSpan <= 1) return rowIndex;
|
|
235
263
|
const rect = cellElement.getBoundingClientRect();
|
|
236
264
|
const relativeY = clientY - rect.top;
|
|
265
|
+
const heights = measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement);
|
|
266
|
+
if (heights && heights.length === rowSpan) {
|
|
267
|
+
let accrued = 0;
|
|
268
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
269
|
+
accrued += heights[i];
|
|
270
|
+
if (relativeY < accrued) {
|
|
271
|
+
return rowIndex + i;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return rowIndex + rowSpan - 1;
|
|
275
|
+
}
|
|
237
276
|
const rowHeight = rect.height / rowSpan;
|
|
238
277
|
const offset = Math.min(
|
|
239
278
|
Math.max(Math.floor(relativeY / rowHeight), 0),
|
|
@@ -255,7 +294,35 @@ function getActiveSelectionBounds(dragState, selectionBounds) {
|
|
|
255
294
|
var SELECTION_EDGE_WIDTH_PX = 2;
|
|
256
295
|
var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
|
|
257
296
|
var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
|
|
258
|
-
function
|
|
297
|
+
function rowRangeToHeightRatios(rowIndex, span, fromRow, toRowExclusive, rowHeights) {
|
|
298
|
+
const clampedFrom = Math.max(fromRow, rowIndex);
|
|
299
|
+
const clampedTo = Math.min(toRowExclusive, rowIndex + span);
|
|
300
|
+
if (clampedTo <= clampedFrom) {
|
|
301
|
+
return { offsetRatio: 0, lengthRatio: 0 };
|
|
302
|
+
}
|
|
303
|
+
if (!rowHeights || rowHeights.length !== span) {
|
|
304
|
+
return {
|
|
305
|
+
offsetRatio: (clampedFrom - rowIndex) / span,
|
|
306
|
+
lengthRatio: (clampedTo - clampedFrom) / span
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
const total = rowHeights.reduce((sum, height) => sum + height, 0) || 1;
|
|
310
|
+
let offsetPx = 0;
|
|
311
|
+
for (let i = 0; i < clampedFrom - rowIndex; i++) {
|
|
312
|
+
offsetPx += rowHeights[i] ?? 0;
|
|
313
|
+
}
|
|
314
|
+
let lengthPx = 0;
|
|
315
|
+
for (let i = clampedFrom - rowIndex; i < clampedTo - rowIndex; i++) {
|
|
316
|
+
lengthPx += rowHeights[i] ?? 0;
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
offsetRatio: offsetPx / total,
|
|
320
|
+
lengthRatio: lengthPx / total,
|
|
321
|
+
offsetPx,
|
|
322
|
+
lengthPx
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt, rowHeights) {
|
|
259
326
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
260
327
|
const span = cellEndRow - rowIndex + 1;
|
|
261
328
|
if (span <= 1) return [];
|
|
@@ -274,20 +341,30 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
274
341
|
continue;
|
|
275
342
|
}
|
|
276
343
|
if (runStart !== null) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
344
|
+
const ratios = rowRangeToHeightRatios(
|
|
345
|
+
rowIndex,
|
|
346
|
+
span,
|
|
347
|
+
runStart,
|
|
348
|
+
row,
|
|
349
|
+
rowHeights
|
|
350
|
+
);
|
|
351
|
+
if (ratios.lengthRatio > 0) {
|
|
352
|
+
edges.push({ side, ...ratios });
|
|
353
|
+
}
|
|
282
354
|
runStart = null;
|
|
283
355
|
}
|
|
284
356
|
}
|
|
285
357
|
if (runStart !== null) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
358
|
+
const ratios = rowRangeToHeightRatios(
|
|
359
|
+
rowIndex,
|
|
360
|
+
span,
|
|
361
|
+
runStart,
|
|
362
|
+
toRowExclusive,
|
|
363
|
+
rowHeights
|
|
364
|
+
);
|
|
365
|
+
if (ratios.lengthRatio > 0) {
|
|
366
|
+
edges.push({ side, ...ratios });
|
|
367
|
+
}
|
|
291
368
|
}
|
|
292
369
|
};
|
|
293
370
|
const collectSide = (side, neighborCol) => {
|
|
@@ -316,14 +393,17 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
316
393
|
}
|
|
317
394
|
return edges;
|
|
318
395
|
}
|
|
319
|
-
function
|
|
396
|
+
function buildPartialEdgeGradient(edge) {
|
|
397
|
+
const usePx = edge.offsetPx != null && edge.lengthPx != null;
|
|
320
398
|
const startPct = edge.offsetRatio * 100;
|
|
321
|
-
const endPct = (edge.offsetRatio + edge.
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
const
|
|
326
|
-
const
|
|
399
|
+
const endPct = (edge.offsetRatio + edge.lengthRatio) * 100;
|
|
400
|
+
const startPx = edge.offsetPx ?? 0;
|
|
401
|
+
const endPx = (edge.offsetPx ?? 0) + (edge.lengthPx ?? 0);
|
|
402
|
+
const overlapPx = SELECTION_EDGE_WIDTH_PX;
|
|
403
|
+
const isTopProtrusion = (usePx ? startPx === 0 : edge.offsetRatio === 0) && edge.lengthRatio < 1;
|
|
404
|
+
const isBottomProtrusion = usePx ? startPx > 0 : edge.offsetRatio > 0;
|
|
405
|
+
const startStop = usePx ? isBottomProtrusion ? `${Math.max(0, startPx - overlapPx)}px` : `${startPx}px` : isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
|
|
406
|
+
const endStop = usePx ? isTopProtrusion ? `${endPx + overlapPx}px` : `${endPx}px` : isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
|
|
327
407
|
const xPos = edge.side === "left" ? "0" : "100%";
|
|
328
408
|
const layers = [
|
|
329
409
|
{
|
|
@@ -333,7 +413,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
333
413
|
}
|
|
334
414
|
];
|
|
335
415
|
if (isTopProtrusion || isBottomProtrusion) {
|
|
336
|
-
const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
416
|
+
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)`;
|
|
337
417
|
layers.push({
|
|
338
418
|
image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
|
|
339
419
|
size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
|
|
@@ -342,7 +422,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
342
422
|
}
|
|
343
423
|
return layers;
|
|
344
424
|
}
|
|
345
|
-
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
|
|
425
|
+
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt, rowHeights) {
|
|
346
426
|
if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
|
|
347
427
|
return void 0;
|
|
348
428
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
@@ -351,39 +431,47 @@ function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVi
|
|
|
351
431
|
const isLeftEdge = colIndex === bounds.startCol;
|
|
352
432
|
const isRightEdge = colIndex === bounds.endCol;
|
|
353
433
|
const selectionContinuesBelow = cellEndRow < bounds.endRow;
|
|
354
|
-
const shadows = [];
|
|
355
|
-
if (isTopEdge) {
|
|
356
|
-
shadows.push(
|
|
357
|
-
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
if (isBottomEdge) {
|
|
361
|
-
shadows.push(
|
|
362
|
-
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
if (isLeftEdge) {
|
|
366
|
-
shadows.push(
|
|
367
|
-
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
if (isRightEdge) {
|
|
371
|
-
shadows.push(
|
|
372
|
-
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
434
|
const stepEdges = getMergedCellStepEdges(
|
|
376
435
|
rowIndex,
|
|
377
436
|
colIndex,
|
|
378
437
|
bounds,
|
|
379
438
|
rowSpan,
|
|
380
|
-
isVisuallySelectedAt
|
|
439
|
+
isVisuallySelectedAt,
|
|
440
|
+
rowHeights
|
|
381
441
|
);
|
|
442
|
+
const shadows = [];
|
|
443
|
+
const hasFullPerimeter = isTopEdge && isBottomEdge && isLeftEdge && isRightEdge && stepEdges.length === 0;
|
|
444
|
+
if (hasFullPerimeter) {
|
|
445
|
+
shadows.push(
|
|
446
|
+
`inset 0 0 0 ${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_COLOR}`
|
|
447
|
+
);
|
|
448
|
+
} else {
|
|
449
|
+
if (isTopEdge) {
|
|
450
|
+
shadows.push(
|
|
451
|
+
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
if (isBottomEdge) {
|
|
455
|
+
shadows.push(
|
|
456
|
+
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
if (isLeftEdge) {
|
|
460
|
+
shadows.push(
|
|
461
|
+
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
if (isRightEdge) {
|
|
465
|
+
shadows.push(
|
|
466
|
+
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
382
470
|
const gradients = [];
|
|
383
471
|
const sizes = [];
|
|
384
472
|
const positions = [];
|
|
385
473
|
for (const edge of stepEdges) {
|
|
386
|
-
for (const partial of
|
|
474
|
+
for (const partial of buildPartialEdgeGradient(edge)) {
|
|
387
475
|
gradients.push(partial.image);
|
|
388
476
|
sizes.push(partial.size);
|
|
389
477
|
positions.push(partial.position);
|
|
@@ -412,6 +500,127 @@ function hasCellSelectionEdges(style) {
|
|
|
412
500
|
);
|
|
413
501
|
}
|
|
414
502
|
|
|
503
|
+
// src/components/ui/table/features/cell-selection/copyData.ts
|
|
504
|
+
function formatCellValue(value) {
|
|
505
|
+
if (value === null || value === void 0) return "";
|
|
506
|
+
return String(value);
|
|
507
|
+
}
|
|
508
|
+
function getNestedValue(row, path) {
|
|
509
|
+
if (!path.includes(".")) return row[path];
|
|
510
|
+
return path.split(".").reduce((current, key) => {
|
|
511
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
512
|
+
return void 0;
|
|
513
|
+
}
|
|
514
|
+
return current[key];
|
|
515
|
+
}, row);
|
|
516
|
+
}
|
|
517
|
+
function readRowColumnValue(rowData, columnDef) {
|
|
518
|
+
if ("accessorFn" in columnDef && typeof columnDef.accessorFn === "function") {
|
|
519
|
+
return columnDef.accessorFn(rowData, 0);
|
|
520
|
+
}
|
|
521
|
+
if ("accessorKey" in columnDef && columnDef.accessorKey != null && columnDef.accessorKey !== "") {
|
|
522
|
+
return getNestedValue(rowData, String(columnDef.accessorKey));
|
|
523
|
+
}
|
|
524
|
+
return void 0;
|
|
525
|
+
}
|
|
526
|
+
function flattenSubtreeRows(row) {
|
|
527
|
+
const children = row.children;
|
|
528
|
+
if (!Array.isArray(children) || children.length === 0) return [];
|
|
529
|
+
const result = [];
|
|
530
|
+
const walk = (nodes) => {
|
|
531
|
+
for (const node of nodes) {
|
|
532
|
+
result.push(node);
|
|
533
|
+
const nested = node.children;
|
|
534
|
+
if (Array.isArray(nested) && nested.length > 0) {
|
|
535
|
+
walk(nested);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
walk(children);
|
|
540
|
+
return result;
|
|
541
|
+
}
|
|
542
|
+
function hasSubtree(row) {
|
|
543
|
+
const children = row.children;
|
|
544
|
+
return Array.isArray(children) && children.length > 0;
|
|
545
|
+
}
|
|
546
|
+
function getOriginalRowId(original) {
|
|
547
|
+
return String(original.id ?? original.uniqueId ?? "");
|
|
548
|
+
}
|
|
549
|
+
function getRowDepth(original) {
|
|
550
|
+
return typeof original.level === "number" ? original.level : 0;
|
|
551
|
+
}
|
|
552
|
+
function collectCopyRowEntries(visibleRows, bounds, mode = "visible") {
|
|
553
|
+
const { startRow, endRow } = bounds;
|
|
554
|
+
const result = [];
|
|
555
|
+
const includedOriginalIds = /* @__PURE__ */ new Set();
|
|
556
|
+
const appendSubtree = (node, depth) => {
|
|
557
|
+
const children = node.children;
|
|
558
|
+
if (!Array.isArray(children) || children.length === 0) return;
|
|
559
|
+
for (const child of children) {
|
|
560
|
+
const childId = getOriginalRowId(child);
|
|
561
|
+
if (!(childId && includedOriginalIds.has(childId))) {
|
|
562
|
+
result.push({ row: child, depth });
|
|
563
|
+
if (childId) includedOriginalIds.add(childId);
|
|
564
|
+
}
|
|
565
|
+
appendSubtree(child, depth + 1);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
for (let rowIndex = startRow; rowIndex <= endRow; rowIndex += 1) {
|
|
569
|
+
const row = visibleRows[rowIndex];
|
|
570
|
+
if (!row) continue;
|
|
571
|
+
const originalId = getOriginalRowId(row.original);
|
|
572
|
+
if (originalId && includedOriginalIds.has(originalId)) continue;
|
|
573
|
+
const depth = getRowDepth(row.original);
|
|
574
|
+
result.push({ row: row.original, depth });
|
|
575
|
+
if (originalId) includedOriginalIds.add(originalId);
|
|
576
|
+
if (mode !== "subtree" || !hasSubtree(row.original)) continue;
|
|
577
|
+
appendSubtree(row.original, depth + 1);
|
|
578
|
+
}
|
|
579
|
+
return result;
|
|
580
|
+
}
|
|
581
|
+
function collectCopyRows(visibleRows, bounds, mode = "visible") {
|
|
582
|
+
return collectCopyRowEntries(visibleRows, bounds, mode).map((entry) => entry.row);
|
|
583
|
+
}
|
|
584
|
+
function serializeCopyRowsToTSV(copyRows, visibleRows, bounds, depths) {
|
|
585
|
+
if (copyRows.length === 0) return "";
|
|
586
|
+
const { startCol, endCol } = bounds;
|
|
587
|
+
const columnCells = visibleRows[0]?.getVisibleCells().slice(startCol, endCol + 1) ?? [];
|
|
588
|
+
if (columnCells.length === 0) return "";
|
|
589
|
+
const resolvedDepths = depths && depths.length === copyRows.length ? depths : copyRows.map((row) => getRowDepth(row));
|
|
590
|
+
const minDepth = Math.min(...resolvedDepths);
|
|
591
|
+
return copyRows.map((rowData, index) => {
|
|
592
|
+
const relativeDepth = Math.max(0, (resolvedDepths[index] ?? 0) - minDepth);
|
|
593
|
+
const line = columnCells.map(
|
|
594
|
+
(cell) => formatCellValue(
|
|
595
|
+
readRowColumnValue(
|
|
596
|
+
rowData,
|
|
597
|
+
cell.column.columnDef
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
).join(" ");
|
|
601
|
+
return `${" ".repeat(relativeDepth)}${line}`;
|
|
602
|
+
}).join("\n");
|
|
603
|
+
}
|
|
604
|
+
function serializeSelectionToTSV(visibleRows, bounds, mode = "visible") {
|
|
605
|
+
const entries = collectCopyRowEntries(visibleRows, bounds, mode);
|
|
606
|
+
return serializeCopyRowsToTSV(
|
|
607
|
+
entries.map((entry) => entry.row),
|
|
608
|
+
visibleRows,
|
|
609
|
+
bounds,
|
|
610
|
+
entries.map((entry) => entry.depth)
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
async function writeSelectionToClipboard(visibleRows, bounds, mode = "visible") {
|
|
614
|
+
const text = serializeSelectionToTSV(visibleRows, bounds, mode);
|
|
615
|
+
if (!text) return false;
|
|
616
|
+
try {
|
|
617
|
+
await navigator.clipboard.writeText(text);
|
|
618
|
+
} catch {
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
|
|
415
624
|
// src/components/ui/table/features/cell-selection/fillData.ts
|
|
416
625
|
function getColumnAccessorKey2(columnDef) {
|
|
417
626
|
if ("accessorKey" in columnDef && columnDef.accessorKey) {
|
|
@@ -468,15 +677,103 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
468
677
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
469
678
|
}
|
|
470
679
|
|
|
680
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
681
|
+
function countLeadingEmptyCells(cells) {
|
|
682
|
+
let depth = 0;
|
|
683
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
684
|
+
depth += 1;
|
|
685
|
+
}
|
|
686
|
+
return depth;
|
|
687
|
+
}
|
|
688
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
689
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
690
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
691
|
+
if (firstDepth !== 0) return false;
|
|
692
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
693
|
+
}
|
|
694
|
+
function parseClipboardTSV(text) {
|
|
695
|
+
return parseClipboardTSVWithDepths(text).values;
|
|
696
|
+
}
|
|
697
|
+
function parseClipboardTSVWithDepths(text) {
|
|
698
|
+
if (!text) return { values: [], depths: [] };
|
|
699
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
700
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
701
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
702
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
703
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
704
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
705
|
+
const values = [];
|
|
706
|
+
const depths = [];
|
|
707
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
708
|
+
const cells = rows[index] ?? [];
|
|
709
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
710
|
+
if (treatAsDepth) {
|
|
711
|
+
values.push(cells.slice(depth));
|
|
712
|
+
depths.push(depth);
|
|
713
|
+
} else {
|
|
714
|
+
values.push(cells);
|
|
715
|
+
depths.push(0);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return { values, depths };
|
|
719
|
+
}
|
|
720
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
721
|
+
if (width <= 0) return [];
|
|
722
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
723
|
+
const columnIds = [];
|
|
724
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
725
|
+
const cell = cells[startCol + offset];
|
|
726
|
+
if (!cell) break;
|
|
727
|
+
columnIds.push(cell.column.id);
|
|
728
|
+
}
|
|
729
|
+
return columnIds;
|
|
730
|
+
}
|
|
731
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
732
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
733
|
+
if (values.length === 0) return null;
|
|
734
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
735
|
+
if (width === 0) return null;
|
|
736
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
737
|
+
if (columnIds.length === 0) return null;
|
|
738
|
+
const rowIds = [];
|
|
739
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
740
|
+
const row = rows[startRow + offset];
|
|
741
|
+
if (!row) break;
|
|
742
|
+
rowIds.push(row.id);
|
|
743
|
+
}
|
|
744
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
745
|
+
return {
|
|
746
|
+
mode,
|
|
747
|
+
startRow,
|
|
748
|
+
startCol,
|
|
749
|
+
endRow,
|
|
750
|
+
rowIds,
|
|
751
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
752
|
+
columnIds,
|
|
753
|
+
values,
|
|
754
|
+
depths
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function isEditablePasteTarget(target) {
|
|
758
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
759
|
+
const tag = target.tagName;
|
|
760
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
761
|
+
return Boolean(target.isContentEditable);
|
|
762
|
+
}
|
|
763
|
+
|
|
471
764
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
472
765
|
function useCellSelection({
|
|
473
766
|
data,
|
|
474
767
|
rows,
|
|
475
768
|
enabled = true,
|
|
769
|
+
enableSubtreeCopy = false,
|
|
770
|
+
enableInsertPaste = true,
|
|
476
771
|
onDataChange,
|
|
477
|
-
onBatchChange
|
|
772
|
+
onBatchChange,
|
|
773
|
+
onRowsPaste
|
|
478
774
|
}) {
|
|
479
775
|
const [dragState, setDragState] = (0, import_react2.useState)(INITIAL_DRAG_STATE);
|
|
776
|
+
const pendingPasteModeRef = (0, import_react2.useRef)(null);
|
|
480
777
|
const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
|
|
481
778
|
const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
|
|
482
779
|
const handleCellMouseDown = (0, import_react2.useCallback)(
|
|
@@ -530,21 +827,113 @@ function useCellSelection({
|
|
|
530
827
|
setDragState(INITIAL_DRAG_STATE);
|
|
531
828
|
}
|
|
532
829
|
}, [enabled]);
|
|
830
|
+
const copySelection = (0, import_react2.useCallback)(
|
|
831
|
+
async (options) => {
|
|
832
|
+
if (!enabled || !activeSelectionBounds) return false;
|
|
833
|
+
const mode = options?.includeDescendants && enableSubtreeCopy ? "subtree" : "visible";
|
|
834
|
+
return writeSelectionToClipboard(rows, activeSelectionBounds, mode);
|
|
835
|
+
},
|
|
836
|
+
[activeSelectionBounds, enableSubtreeCopy, enabled, rows]
|
|
837
|
+
);
|
|
533
838
|
(0, import_react2.useEffect)(() => {
|
|
534
839
|
if (!enabled) return;
|
|
535
840
|
const handleKeyDown = (e) => {
|
|
536
|
-
if (
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
841
|
+
if (!activeSelectionBounds) return;
|
|
842
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
843
|
+
const isSubtreeShortcut = enableSubtreeCopy && e.shiftKey && e.key.toLowerCase() === "c";
|
|
844
|
+
const isVisibleCopyShortcut = !e.shiftKey && e.key.toLowerCase() === "c";
|
|
845
|
+
if (!isSubtreeShortcut && !isVisibleCopyShortcut) return;
|
|
846
|
+
e.preventDefault();
|
|
847
|
+
void copySelection({ includeDescendants: isSubtreeShortcut });
|
|
544
848
|
};
|
|
545
849
|
window.addEventListener("keydown", handleKeyDown);
|
|
546
850
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
547
|
-
}, [activeSelectionBounds,
|
|
851
|
+
}, [activeSelectionBounds, copySelection, enableSubtreeCopy, enabled]);
|
|
852
|
+
const emitRowsPaste = (0, import_react2.useCallback)(
|
|
853
|
+
(text, mode) => {
|
|
854
|
+
if (!onRowsPaste || !activeSelectionBounds) return false;
|
|
855
|
+
const payload = buildRowsPastePayload(
|
|
856
|
+
rows,
|
|
857
|
+
activeSelectionBounds.startRow,
|
|
858
|
+
activeSelectionBounds.startCol,
|
|
859
|
+
text,
|
|
860
|
+
mode,
|
|
861
|
+
activeSelectionBounds.endRow
|
|
862
|
+
);
|
|
863
|
+
if (!payload) return false;
|
|
864
|
+
onRowsPaste(payload);
|
|
865
|
+
return true;
|
|
866
|
+
},
|
|
867
|
+
[activeSelectionBounds, onRowsPaste, rows]
|
|
868
|
+
);
|
|
869
|
+
(0, import_react2.useEffect)(() => {
|
|
870
|
+
if (!enabled || !onRowsPaste) return;
|
|
871
|
+
const pasteHandledRef = { current: false };
|
|
872
|
+
const ignoreNextPasteRef = { current: false };
|
|
873
|
+
const handleKeyDown = (e) => {
|
|
874
|
+
if (!activeSelectionBounds) return;
|
|
875
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
876
|
+
if (e.key.toLowerCase() !== "v") return;
|
|
877
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (e.shiftKey && !enableInsertPaste) {
|
|
881
|
+
ignoreNextPasteRef.current = true;
|
|
882
|
+
pendingPasteModeRef.current = null;
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const mode = e.shiftKey ? "insert" : "overwrite";
|
|
886
|
+
pasteHandledRef.current = false;
|
|
887
|
+
ignoreNextPasteRef.current = false;
|
|
888
|
+
pendingPasteModeRef.current = mode;
|
|
889
|
+
void (async () => {
|
|
890
|
+
try {
|
|
891
|
+
const text = await navigator.clipboard.readText();
|
|
892
|
+
if (pasteHandledRef.current) return;
|
|
893
|
+
if (pendingPasteModeRef.current !== mode) return;
|
|
894
|
+
if (!text) return;
|
|
895
|
+
pasteHandledRef.current = true;
|
|
896
|
+
emitRowsPaste(text, mode);
|
|
897
|
+
pendingPasteModeRef.current = null;
|
|
898
|
+
} catch {
|
|
899
|
+
}
|
|
900
|
+
})();
|
|
901
|
+
};
|
|
902
|
+
const handlePaste = (e) => {
|
|
903
|
+
if (!activeSelectionBounds) return;
|
|
904
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
if (ignoreNextPasteRef.current) {
|
|
908
|
+
ignoreNextPasteRef.current = false;
|
|
909
|
+
pendingPasteModeRef.current = null;
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
const mode = pendingPasteModeRef.current ?? "overwrite";
|
|
913
|
+
if (pasteHandledRef.current) {
|
|
914
|
+
e.preventDefault();
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const text = e.clipboardData?.getData("text/plain");
|
|
918
|
+
if (text == null || text === "") return;
|
|
919
|
+
pasteHandledRef.current = true;
|
|
920
|
+
e.preventDefault();
|
|
921
|
+
emitRowsPaste(text, mode);
|
|
922
|
+
pendingPasteModeRef.current = null;
|
|
923
|
+
};
|
|
924
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
925
|
+
window.addEventListener("paste", handlePaste);
|
|
926
|
+
return () => {
|
|
927
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
928
|
+
window.removeEventListener("paste", handlePaste);
|
|
929
|
+
};
|
|
930
|
+
}, [
|
|
931
|
+
activeSelectionBounds,
|
|
932
|
+
emitRowsPaste,
|
|
933
|
+
enableInsertPaste,
|
|
934
|
+
enabled,
|
|
935
|
+
onRowsPaste
|
|
936
|
+
]);
|
|
548
937
|
(0, import_react2.useEffect)(() => {
|
|
549
938
|
if (!enabled) return;
|
|
550
939
|
const handleMouseUp = () => {
|
|
@@ -590,7 +979,8 @@ function useCellSelection({
|
|
|
590
979
|
activeSelectionBounds,
|
|
591
980
|
handleCellMouseDown,
|
|
592
981
|
handleCellMouseEnter,
|
|
593
|
-
handleFillHandleMouseDown
|
|
982
|
+
handleFillHandleMouseDown,
|
|
983
|
+
copySelection
|
|
594
984
|
};
|
|
595
985
|
}
|
|
596
986
|
|
|
@@ -672,15 +1062,16 @@ var useConvertTreeData = ({
|
|
|
672
1062
|
children: [],
|
|
673
1063
|
processed: false
|
|
674
1064
|
}));
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
1065
|
+
const findNearestPrecedingParent = (index, parentKey) => {
|
|
1066
|
+
for (let i = index - 1; i >= 0; i -= 1) {
|
|
1067
|
+
const candidate = dataWithLevels[i];
|
|
1068
|
+
if (!candidate) continue;
|
|
1069
|
+
if (getFieldValue(candidate, toggleField) === parentKey) {
|
|
1070
|
+
return candidate;
|
|
1071
|
+
}
|
|
681
1072
|
}
|
|
682
|
-
|
|
683
|
-
}
|
|
1073
|
+
return void 0;
|
|
1074
|
+
};
|
|
684
1075
|
const rootItems = [];
|
|
685
1076
|
dataWithLevels.forEach((item) => {
|
|
686
1077
|
if (!getFieldValue(item, childField)) {
|
|
@@ -688,29 +1079,18 @@ var useConvertTreeData = ({
|
|
|
688
1079
|
item.processed = true;
|
|
689
1080
|
}
|
|
690
1081
|
});
|
|
691
|
-
dataWithLevels.forEach((item) => {
|
|
1082
|
+
dataWithLevels.forEach((item, index) => {
|
|
692
1083
|
const parentKey = getFieldValue(item, childField);
|
|
693
1084
|
if (!parentKey || item.processed) return;
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
);
|
|
697
|
-
if (parentItems.length > 0) {
|
|
698
|
-
const parent = parentItems[0];
|
|
1085
|
+
const parent = findNearestPrecedingParent(index, parentKey);
|
|
1086
|
+
if (parent) {
|
|
699
1087
|
item.level = parent.level + 1;
|
|
700
1088
|
parent.children.push(item);
|
|
701
1089
|
item.processed = true;
|
|
702
|
-
|
|
703
|
-
const otherParents = itemMap.get(String(parentKey)) || [];
|
|
704
|
-
if (otherParents.length > 0) {
|
|
705
|
-
const parent = otherParents[0];
|
|
706
|
-
item.level = parent.level + 1;
|
|
707
|
-
parent.children.push(item);
|
|
708
|
-
item.processed = true;
|
|
709
|
-
} else {
|
|
710
|
-
rootItems.push(item);
|
|
711
|
-
item.processed = true;
|
|
712
|
-
}
|
|
1090
|
+
return;
|
|
713
1091
|
}
|
|
1092
|
+
rootItems.push(item);
|
|
1093
|
+
item.processed = true;
|
|
714
1094
|
});
|
|
715
1095
|
return rootItems;
|
|
716
1096
|
}, [enabled, data, toggleField, childField, flattenField]);
|
|
@@ -735,16 +1115,23 @@ var useConvertTreeData = ({
|
|
|
735
1115
|
return result;
|
|
736
1116
|
};
|
|
737
1117
|
const flattenedData = flatten(processedData, [], 0);
|
|
738
|
-
flattenedData.forEach((item) => {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
(parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
|
|
742
|
-
);
|
|
743
|
-
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
744
|
-
item.parentCount = parentAmount || 1;
|
|
745
|
-
} else {
|
|
1118
|
+
flattenedData.forEach((item, index) => {
|
|
1119
|
+
const parentKey = getFieldValue(item, childField);
|
|
1120
|
+
if (!parentKey) {
|
|
746
1121
|
item.parentCount = 1;
|
|
1122
|
+
return;
|
|
747
1123
|
}
|
|
1124
|
+
let parentItem;
|
|
1125
|
+
for (let i = index - 1; i >= 0; i -= 1) {
|
|
1126
|
+
const candidate = flattenedData[i];
|
|
1127
|
+
if (!candidate) continue;
|
|
1128
|
+
if (getFieldValue(candidate, toggleField) === parentKey) {
|
|
1129
|
+
parentItem = candidate;
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
1134
|
+
item.parentCount = parentAmount || 1;
|
|
748
1135
|
});
|
|
749
1136
|
return flattenedData;
|
|
750
1137
|
}, [
|
|
@@ -891,6 +1278,10 @@ function useGlideTable(options) {
|
|
|
891
1278
|
expandedRows: controlledExpandedRows,
|
|
892
1279
|
onExpandedRowsChange,
|
|
893
1280
|
preventExpand = false,
|
|
1281
|
+
enableSubtreeCopy,
|
|
1282
|
+
onCopyActionsReady,
|
|
1283
|
+
onRowsPaste,
|
|
1284
|
+
enableInsertPaste,
|
|
894
1285
|
enableVirtualization = true,
|
|
895
1286
|
estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
|
|
896
1287
|
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
|
|
@@ -905,12 +1296,12 @@ function useGlideTable(options) {
|
|
|
905
1296
|
};
|
|
906
1297
|
}, [labelsProp, emptyText, loadingText, selectionLabel]);
|
|
907
1298
|
const enableExpand = Boolean(toggleField);
|
|
1299
|
+
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
908
1300
|
const [internalRowSelection, setInternalRowSelection] = (0, import_react4.useState)({});
|
|
909
1301
|
const [internalExpandedRows, setInternalExpandedRows] = (0, import_react4.useState)(
|
|
910
1302
|
() => /* @__PURE__ */ new Set()
|
|
911
1303
|
);
|
|
912
1304
|
const [hoveredRowIndex, setHoveredRowIndex] = (0, import_react4.useState)(null);
|
|
913
|
-
const [hoveredGroupKey, setHoveredGroupKey] = (0, import_react4.useState)(null);
|
|
914
1305
|
const scrollRef = (0, import_react4.useRef)(null);
|
|
915
1306
|
const shouldVirtualize = enableVirtualization && !enableRowSpan;
|
|
916
1307
|
(0, import_react4.useEffect)(() => {
|
|
@@ -974,6 +1365,7 @@ function useGlideTable(options) {
|
|
|
974
1365
|
return collectRowSpanColumns(columns);
|
|
975
1366
|
}, [enableRowSpan, columns]);
|
|
976
1367
|
const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
|
|
1368
|
+
const primaryRowSpanColumnId = rowSpanColumnKeys[0]?.columnId;
|
|
977
1369
|
const columnRowSpanMap = (0, import_react4.useMemo)(
|
|
978
1370
|
() => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
|
|
979
1371
|
[tableData, rowSpanColumnKeys]
|
|
@@ -992,27 +1384,29 @@ function useGlideTable(options) {
|
|
|
992
1384
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
993
1385
|
const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
994
1386
|
const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1387
|
+
const selectedRowIndices = (0, import_react4.useMemo)(() => {
|
|
1388
|
+
const indices = /* @__PURE__ */ new Set();
|
|
998
1389
|
for (const selectedRow of selectedRows) {
|
|
999
|
-
|
|
1000
|
-
if (value !== null && value !== void 0) keys.add(String(value));
|
|
1390
|
+
indices.add(selectedRow.index);
|
|
1001
1391
|
}
|
|
1002
|
-
return
|
|
1003
|
-
}, [
|
|
1392
|
+
return indices;
|
|
1393
|
+
}, [selectedRows]);
|
|
1004
1394
|
const {
|
|
1005
1395
|
dragState,
|
|
1006
1396
|
activeSelectionBounds,
|
|
1007
1397
|
handleCellMouseDown,
|
|
1008
1398
|
handleCellMouseEnter,
|
|
1009
|
-
handleFillHandleMouseDown
|
|
1399
|
+
handleFillHandleMouseDown,
|
|
1400
|
+
copySelection
|
|
1010
1401
|
} = useCellSelection({
|
|
1011
1402
|
data: tableData,
|
|
1012
1403
|
rows,
|
|
1013
1404
|
enabled: enableCellSelection,
|
|
1405
|
+
enableSubtreeCopy: resolvedEnableSubtreeCopy,
|
|
1406
|
+
enableInsertPaste: enableInsertPaste ?? true,
|
|
1014
1407
|
onDataChange,
|
|
1015
|
-
onBatchChange
|
|
1408
|
+
onBatchChange,
|
|
1409
|
+
onRowsPaste
|
|
1016
1410
|
});
|
|
1017
1411
|
const {
|
|
1018
1412
|
editingCell,
|
|
@@ -1034,22 +1428,10 @@ function useGlideTable(options) {
|
|
|
1034
1428
|
);
|
|
1035
1429
|
const clearHover = (0, import_react4.useCallback)(() => {
|
|
1036
1430
|
setHoveredRowIndex(null);
|
|
1037
|
-
setHoveredGroupKey(null);
|
|
1038
1431
|
}, []);
|
|
1039
|
-
const handleRowHover = (0, import_react4.useCallback)(
|
|
1040
|
-
(rowIndex
|
|
1041
|
-
|
|
1042
|
-
if (!primaryRowSpanKey) {
|
|
1043
|
-
setHoveredGroupKey(null);
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
const groupValue = rowData[primaryRowSpanKey];
|
|
1047
|
-
setHoveredGroupKey(
|
|
1048
|
-
groupValue === null || groupValue === void 0 ? null : String(groupValue)
|
|
1049
|
-
);
|
|
1050
|
-
},
|
|
1051
|
-
[primaryRowSpanKey]
|
|
1052
|
-
);
|
|
1432
|
+
const handleRowHover = (0, import_react4.useCallback)((rowIndex, _rowData) => {
|
|
1433
|
+
setHoveredRowIndex(rowIndex);
|
|
1434
|
+
}, []);
|
|
1053
1435
|
const handleToggleSelect = (0, import_react4.useCallback)(
|
|
1054
1436
|
(row) => {
|
|
1055
1437
|
if (!row.getCanSelect()) return;
|
|
@@ -1072,10 +1454,10 @@ function useGlideTable(options) {
|
|
|
1072
1454
|
rowSpan: {
|
|
1073
1455
|
enableRowSpan,
|
|
1074
1456
|
primaryRowSpanKey,
|
|
1457
|
+
primaryRowSpanColumnId,
|
|
1075
1458
|
columnRowSpanMap,
|
|
1076
1459
|
hoveredRowIndex,
|
|
1077
|
-
|
|
1078
|
-
selectedGroupKeys,
|
|
1460
|
+
selectedRowIndices,
|
|
1079
1461
|
onRowHover: handleRowHover
|
|
1080
1462
|
},
|
|
1081
1463
|
selection: {
|
|
@@ -1113,10 +1495,10 @@ function useGlideTable(options) {
|
|
|
1113
1495
|
}, [
|
|
1114
1496
|
enableRowSpan,
|
|
1115
1497
|
primaryRowSpanKey,
|
|
1498
|
+
primaryRowSpanColumnId,
|
|
1116
1499
|
columnRowSpanMap,
|
|
1117
1500
|
hoveredRowIndex,
|
|
1118
|
-
|
|
1119
|
-
selectedGroupKeys,
|
|
1501
|
+
selectedRowIndices,
|
|
1120
1502
|
handleRowHover,
|
|
1121
1503
|
rowSelectionMode,
|
|
1122
1504
|
selectOnRowClick,
|
|
@@ -1142,6 +1524,14 @@ function useGlideTable(options) {
|
|
|
1142
1524
|
labels.expandRow,
|
|
1143
1525
|
labels.collapseRow
|
|
1144
1526
|
]);
|
|
1527
|
+
const copySelectionRef = (0, import_react4.useRef)(copySelection);
|
|
1528
|
+
(0, import_react4.useEffect)(() => {
|
|
1529
|
+
copySelectionRef.current = copySelection;
|
|
1530
|
+
}, [copySelection]);
|
|
1531
|
+
const stableCopySelection = (0, import_react4.useCallback)((options2) => copySelectionRef.current(options2), []);
|
|
1532
|
+
(0, import_react4.useEffect)(() => {
|
|
1533
|
+
onCopyActionsReady?.({ copySelection: stableCopySelection });
|
|
1534
|
+
}, [onCopyActionsReady, stableCopySelection]);
|
|
1145
1535
|
return {
|
|
1146
1536
|
table,
|
|
1147
1537
|
tableData,
|
|
@@ -1161,7 +1551,8 @@ function useGlideTable(options) {
|
|
|
1161
1551
|
paddingBottom,
|
|
1162
1552
|
rowContextValue,
|
|
1163
1553
|
handleToggleSelect,
|
|
1164
|
-
clearHover
|
|
1554
|
+
clearHover,
|
|
1555
|
+
copySelection: stableCopySelection
|
|
1165
1556
|
};
|
|
1166
1557
|
}
|
|
1167
1558
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1176,9 +1567,13 @@ function useGlideTable(options) {
|
|
|
1176
1567
|
applyFillData,
|
|
1177
1568
|
applySelectionUpdater,
|
|
1178
1569
|
buildColumnRowSpanMap,
|
|
1570
|
+
buildRowsPastePayload,
|
|
1179
1571
|
canExpandRow,
|
|
1572
|
+
collectCopyRowEntries,
|
|
1573
|
+
collectCopyRows,
|
|
1180
1574
|
collectFillChanges,
|
|
1181
1575
|
collectRowSpanColumns,
|
|
1576
|
+
flattenSubtreeRows,
|
|
1182
1577
|
getCellEditDraftValue,
|
|
1183
1578
|
getCellSelectionEdgeStyle,
|
|
1184
1579
|
getColumnEditType,
|
|
@@ -1186,13 +1581,22 @@ function useGlideTable(options) {
|
|
|
1186
1581
|
hasCellSelectionEdges,
|
|
1187
1582
|
isCellInSelection,
|
|
1188
1583
|
isColumnEditable,
|
|
1584
|
+
isEditablePasteTarget,
|
|
1585
|
+
measureMergedSpanRowHeights,
|
|
1189
1586
|
parseCellEditValue,
|
|
1587
|
+
parseClipboardTSV,
|
|
1588
|
+
parseClipboardTSVWithDepths,
|
|
1190
1589
|
resolveDataTableLabels,
|
|
1590
|
+
resolvePasteColumnIds,
|
|
1191
1591
|
resolveRowSelection,
|
|
1192
1592
|
resolveRowSpanAt,
|
|
1593
|
+
rowRangeToHeightRatios,
|
|
1594
|
+
serializeCopyRowsToTSV,
|
|
1595
|
+
serializeSelectionToTSV,
|
|
1193
1596
|
toggleExpandedRowId,
|
|
1194
1597
|
useCellEdit,
|
|
1195
1598
|
useCellSelection,
|
|
1196
1599
|
useConvertTreeData,
|
|
1197
|
-
useGlideTable
|
|
1600
|
+
useGlideTable,
|
|
1601
|
+
writeSelectionToClipboard
|
|
1198
1602
|
});
|