react-glide-table 1.1.5 → 1.1.7
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 +38 -3
- package/dist/compound.cjs +378 -82
- package/dist/compound.d.cts +2 -2
- package/dist/compound.d.ts +2 -2
- package/dist/compound.js +381 -85
- package/dist/core.cjs +401 -76
- package/dist/core.d.cts +59 -6
- package/dist/core.d.ts +59 -6
- package/dist/core.js +395 -81
- package/dist/index.cjs +424 -84
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +420 -91
- 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 = {
|
|
@@ -444,6 +444,127 @@ function hasCellSelectionEdges(style) {
|
|
|
444
444
|
);
|
|
445
445
|
}
|
|
446
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
|
+
|
|
447
568
|
// src/components/ui/table/features/cell-selection/fillData.ts
|
|
448
569
|
function getColumnAccessorKey2(columnDef) {
|
|
449
570
|
if ("accessorKey" in columnDef && columnDef.accessorKey) {
|
|
@@ -500,15 +621,103 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
500
621
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
501
622
|
}
|
|
502
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
|
+
|
|
503
708
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
504
709
|
function useCellSelection({
|
|
505
710
|
data,
|
|
506
711
|
rows,
|
|
507
712
|
enabled = true,
|
|
713
|
+
enableSubtreeCopy = false,
|
|
714
|
+
enableInsertPaste = true,
|
|
508
715
|
onDataChange,
|
|
509
|
-
onBatchChange
|
|
716
|
+
onBatchChange,
|
|
717
|
+
onRowsPaste
|
|
510
718
|
}) {
|
|
511
719
|
const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
|
|
720
|
+
const pendingPasteModeRef = useRef2(null);
|
|
512
721
|
const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
|
|
513
722
|
const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
|
|
514
723
|
const handleCellMouseDown = useCallback2(
|
|
@@ -562,21 +771,113 @@ function useCellSelection({
|
|
|
562
771
|
setDragState(INITIAL_DRAG_STATE);
|
|
563
772
|
}
|
|
564
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
|
+
);
|
|
565
782
|
useEffect2(() => {
|
|
566
783
|
if (!enabled) return;
|
|
567
784
|
const handleKeyDown = (e) => {
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
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 });
|
|
576
792
|
};
|
|
577
793
|
window.addEventListener("keydown", handleKeyDown);
|
|
578
794
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
579
|
-
}, [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
|
+
]);
|
|
580
881
|
useEffect2(() => {
|
|
581
882
|
if (!enabled) return;
|
|
582
883
|
const handleMouseUp = () => {
|
|
@@ -622,12 +923,13 @@ function useCellSelection({
|
|
|
622
923
|
activeSelectionBounds,
|
|
623
924
|
handleCellMouseDown,
|
|
624
925
|
handleCellMouseEnter,
|
|
625
|
-
handleFillHandleMouseDown
|
|
926
|
+
handleFillHandleMouseDown,
|
|
927
|
+
copySelection
|
|
626
928
|
};
|
|
627
929
|
}
|
|
628
930
|
|
|
629
931
|
// src/components/ui/table/features/row-expand/row-expand.ts
|
|
630
|
-
import { useEffect as useEffect3, useMemo, useRef as
|
|
932
|
+
import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "react";
|
|
631
933
|
function getFieldValue(row, key) {
|
|
632
934
|
return row[key];
|
|
633
935
|
}
|
|
@@ -657,8 +959,8 @@ var useConvertTreeData = ({
|
|
|
657
959
|
expandedRows,
|
|
658
960
|
onExpandedRowsChange
|
|
659
961
|
}) => {
|
|
660
|
-
const onExpandedRowsChangeRef =
|
|
661
|
-
const hasInitializedRef =
|
|
962
|
+
const onExpandedRowsChangeRef = useRef3(onExpandedRowsChange);
|
|
963
|
+
const hasInitializedRef = useRef3(false);
|
|
662
964
|
useEffect3(() => {
|
|
663
965
|
onExpandedRowsChangeRef.current = onExpandedRowsChange;
|
|
664
966
|
}, [onExpandedRowsChange]);
|
|
@@ -704,15 +1006,16 @@ var useConvertTreeData = ({
|
|
|
704
1006
|
children: [],
|
|
705
1007
|
processed: false
|
|
706
1008
|
}));
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
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
|
+
}
|
|
713
1016
|
}
|
|
714
|
-
|
|
715
|
-
}
|
|
1017
|
+
return void 0;
|
|
1018
|
+
};
|
|
716
1019
|
const rootItems = [];
|
|
717
1020
|
dataWithLevels.forEach((item) => {
|
|
718
1021
|
if (!getFieldValue(item, childField)) {
|
|
@@ -720,29 +1023,18 @@ var useConvertTreeData = ({
|
|
|
720
1023
|
item.processed = true;
|
|
721
1024
|
}
|
|
722
1025
|
});
|
|
723
|
-
dataWithLevels.forEach((item) => {
|
|
1026
|
+
dataWithLevels.forEach((item, index) => {
|
|
724
1027
|
const parentKey = getFieldValue(item, childField);
|
|
725
1028
|
if (!parentKey || item.processed) return;
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
);
|
|
729
|
-
if (parentItems.length > 0) {
|
|
730
|
-
const parent = parentItems[0];
|
|
1029
|
+
const parent = findNearestPrecedingParent(index, parentKey);
|
|
1030
|
+
if (parent) {
|
|
731
1031
|
item.level = parent.level + 1;
|
|
732
1032
|
parent.children.push(item);
|
|
733
1033
|
item.processed = true;
|
|
734
|
-
|
|
735
|
-
const otherParents = itemMap.get(String(parentKey)) || [];
|
|
736
|
-
if (otherParents.length > 0) {
|
|
737
|
-
const parent = otherParents[0];
|
|
738
|
-
item.level = parent.level + 1;
|
|
739
|
-
parent.children.push(item);
|
|
740
|
-
item.processed = true;
|
|
741
|
-
} else {
|
|
742
|
-
rootItems.push(item);
|
|
743
|
-
item.processed = true;
|
|
744
|
-
}
|
|
1034
|
+
return;
|
|
745
1035
|
}
|
|
1036
|
+
rootItems.push(item);
|
|
1037
|
+
item.processed = true;
|
|
746
1038
|
});
|
|
747
1039
|
return rootItems;
|
|
748
1040
|
}, [enabled, data, toggleField, childField, flattenField]);
|
|
@@ -767,16 +1059,23 @@ var useConvertTreeData = ({
|
|
|
767
1059
|
return result;
|
|
768
1060
|
};
|
|
769
1061
|
const flattenedData = flatten(processedData, [], 0);
|
|
770
|
-
flattenedData.forEach((item) => {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
(parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
|
|
774
|
-
);
|
|
775
|
-
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
776
|
-
item.parentCount = parentAmount || 1;
|
|
777
|
-
} else {
|
|
1062
|
+
flattenedData.forEach((item, index) => {
|
|
1063
|
+
const parentKey = getFieldValue(item, childField);
|
|
1064
|
+
if (!parentKey) {
|
|
778
1065
|
item.parentCount = 1;
|
|
1066
|
+
return;
|
|
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
|
+
}
|
|
779
1076
|
}
|
|
1077
|
+
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
1078
|
+
item.parentCount = parentAmount || 1;
|
|
780
1079
|
});
|
|
781
1080
|
return flattenedData;
|
|
782
1081
|
}, [
|
|
@@ -923,6 +1222,10 @@ function useGlideTable(options) {
|
|
|
923
1222
|
expandedRows: controlledExpandedRows,
|
|
924
1223
|
onExpandedRowsChange,
|
|
925
1224
|
preventExpand = false,
|
|
1225
|
+
enableSubtreeCopy,
|
|
1226
|
+
onCopyActionsReady,
|
|
1227
|
+
onRowsPaste,
|
|
1228
|
+
enableInsertPaste,
|
|
926
1229
|
enableVirtualization = true,
|
|
927
1230
|
estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
|
|
928
1231
|
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
|
|
@@ -937,13 +1240,13 @@ function useGlideTable(options) {
|
|
|
937
1240
|
};
|
|
938
1241
|
}, [labelsProp, emptyText, loadingText, selectionLabel]);
|
|
939
1242
|
const enableExpand = Boolean(toggleField);
|
|
1243
|
+
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
940
1244
|
const [internalRowSelection, setInternalRowSelection] = useState3({});
|
|
941
1245
|
const [internalExpandedRows, setInternalExpandedRows] = useState3(
|
|
942
1246
|
() => /* @__PURE__ */ new Set()
|
|
943
1247
|
);
|
|
944
1248
|
const [hoveredRowIndex, setHoveredRowIndex] = useState3(null);
|
|
945
|
-
const
|
|
946
|
-
const scrollRef = useRef3(null);
|
|
1249
|
+
const scrollRef = useRef4(null);
|
|
947
1250
|
const shouldVirtualize = enableVirtualization && !enableRowSpan;
|
|
948
1251
|
useEffect4(() => {
|
|
949
1252
|
if (enableVirtualization && enableRowSpan) {
|
|
@@ -1006,6 +1309,7 @@ function useGlideTable(options) {
|
|
|
1006
1309
|
return collectRowSpanColumns(columns);
|
|
1007
1310
|
}, [enableRowSpan, columns]);
|
|
1008
1311
|
const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
|
|
1312
|
+
const primaryRowSpanColumnId = rowSpanColumnKeys[0]?.columnId;
|
|
1009
1313
|
const columnRowSpanMap = useMemo2(
|
|
1010
1314
|
() => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
|
|
1011
1315
|
[tableData, rowSpanColumnKeys]
|
|
@@ -1024,27 +1328,29 @@ function useGlideTable(options) {
|
|
|
1024
1328
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
1025
1329
|
const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
1026
1330
|
const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1331
|
+
const selectedRowIndices = useMemo2(() => {
|
|
1332
|
+
const indices = /* @__PURE__ */ new Set();
|
|
1030
1333
|
for (const selectedRow of selectedRows) {
|
|
1031
|
-
|
|
1032
|
-
if (value !== null && value !== void 0) keys.add(String(value));
|
|
1334
|
+
indices.add(selectedRow.index);
|
|
1033
1335
|
}
|
|
1034
|
-
return
|
|
1035
|
-
}, [
|
|
1336
|
+
return indices;
|
|
1337
|
+
}, [selectedRows]);
|
|
1036
1338
|
const {
|
|
1037
1339
|
dragState,
|
|
1038
1340
|
activeSelectionBounds,
|
|
1039
1341
|
handleCellMouseDown,
|
|
1040
1342
|
handleCellMouseEnter,
|
|
1041
|
-
handleFillHandleMouseDown
|
|
1343
|
+
handleFillHandleMouseDown,
|
|
1344
|
+
copySelection
|
|
1042
1345
|
} = useCellSelection({
|
|
1043
1346
|
data: tableData,
|
|
1044
1347
|
rows,
|
|
1045
1348
|
enabled: enableCellSelection,
|
|
1349
|
+
enableSubtreeCopy: resolvedEnableSubtreeCopy,
|
|
1350
|
+
enableInsertPaste: enableInsertPaste ?? true,
|
|
1046
1351
|
onDataChange,
|
|
1047
|
-
onBatchChange
|
|
1352
|
+
onBatchChange,
|
|
1353
|
+
onRowsPaste
|
|
1048
1354
|
});
|
|
1049
1355
|
const {
|
|
1050
1356
|
editingCell,
|
|
@@ -1066,22 +1372,10 @@ function useGlideTable(options) {
|
|
|
1066
1372
|
);
|
|
1067
1373
|
const clearHover = useCallback3(() => {
|
|
1068
1374
|
setHoveredRowIndex(null);
|
|
1069
|
-
setHoveredGroupKey(null);
|
|
1070
1375
|
}, []);
|
|
1071
|
-
const handleRowHover = useCallback3(
|
|
1072
|
-
(rowIndex
|
|
1073
|
-
|
|
1074
|
-
if (!primaryRowSpanKey) {
|
|
1075
|
-
setHoveredGroupKey(null);
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
const groupValue = rowData[primaryRowSpanKey];
|
|
1079
|
-
setHoveredGroupKey(
|
|
1080
|
-
groupValue === null || groupValue === void 0 ? null : String(groupValue)
|
|
1081
|
-
);
|
|
1082
|
-
},
|
|
1083
|
-
[primaryRowSpanKey]
|
|
1084
|
-
);
|
|
1376
|
+
const handleRowHover = useCallback3((rowIndex, _rowData) => {
|
|
1377
|
+
setHoveredRowIndex(rowIndex);
|
|
1378
|
+
}, []);
|
|
1085
1379
|
const handleToggleSelect = useCallback3(
|
|
1086
1380
|
(row) => {
|
|
1087
1381
|
if (!row.getCanSelect()) return;
|
|
@@ -1104,10 +1398,10 @@ function useGlideTable(options) {
|
|
|
1104
1398
|
rowSpan: {
|
|
1105
1399
|
enableRowSpan,
|
|
1106
1400
|
primaryRowSpanKey,
|
|
1401
|
+
primaryRowSpanColumnId,
|
|
1107
1402
|
columnRowSpanMap,
|
|
1108
1403
|
hoveredRowIndex,
|
|
1109
|
-
|
|
1110
|
-
selectedGroupKeys,
|
|
1404
|
+
selectedRowIndices,
|
|
1111
1405
|
onRowHover: handleRowHover
|
|
1112
1406
|
},
|
|
1113
1407
|
selection: {
|
|
@@ -1145,10 +1439,10 @@ function useGlideTable(options) {
|
|
|
1145
1439
|
}, [
|
|
1146
1440
|
enableRowSpan,
|
|
1147
1441
|
primaryRowSpanKey,
|
|
1442
|
+
primaryRowSpanColumnId,
|
|
1148
1443
|
columnRowSpanMap,
|
|
1149
1444
|
hoveredRowIndex,
|
|
1150
|
-
|
|
1151
|
-
selectedGroupKeys,
|
|
1445
|
+
selectedRowIndices,
|
|
1152
1446
|
handleRowHover,
|
|
1153
1447
|
rowSelectionMode,
|
|
1154
1448
|
selectOnRowClick,
|
|
@@ -1174,6 +1468,14 @@ function useGlideTable(options) {
|
|
|
1174
1468
|
labels.expandRow,
|
|
1175
1469
|
labels.collapseRow
|
|
1176
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]);
|
|
1177
1479
|
return {
|
|
1178
1480
|
table,
|
|
1179
1481
|
tableData,
|
|
@@ -1193,7 +1495,8 @@ function useGlideTable(options) {
|
|
|
1193
1495
|
paddingBottom,
|
|
1194
1496
|
rowContextValue,
|
|
1195
1497
|
handleToggleSelect,
|
|
1196
|
-
clearHover
|
|
1498
|
+
clearHover,
|
|
1499
|
+
copySelection: stableCopySelection
|
|
1197
1500
|
};
|
|
1198
1501
|
}
|
|
1199
1502
|
export {
|
|
@@ -1207,9 +1510,13 @@ export {
|
|
|
1207
1510
|
applyFillData,
|
|
1208
1511
|
applySelectionUpdater,
|
|
1209
1512
|
buildColumnRowSpanMap,
|
|
1513
|
+
buildRowsPastePayload,
|
|
1210
1514
|
canExpandRow,
|
|
1515
|
+
collectCopyRowEntries,
|
|
1516
|
+
collectCopyRows,
|
|
1211
1517
|
collectFillChanges,
|
|
1212
1518
|
collectRowSpanColumns,
|
|
1519
|
+
flattenSubtreeRows,
|
|
1213
1520
|
getCellEditDraftValue,
|
|
1214
1521
|
getCellSelectionEdgeStyle,
|
|
1215
1522
|
getColumnEditType,
|
|
@@ -1217,15 +1524,22 @@ export {
|
|
|
1217
1524
|
hasCellSelectionEdges,
|
|
1218
1525
|
isCellInSelection,
|
|
1219
1526
|
isColumnEditable,
|
|
1527
|
+
isEditablePasteTarget,
|
|
1220
1528
|
measureMergedSpanRowHeights,
|
|
1221
1529
|
parseCellEditValue,
|
|
1530
|
+
parseClipboardTSV,
|
|
1531
|
+
parseClipboardTSVWithDepths,
|
|
1222
1532
|
resolveDataTableLabels,
|
|
1533
|
+
resolvePasteColumnIds,
|
|
1223
1534
|
resolveRowSelection,
|
|
1224
1535
|
resolveRowSpanAt,
|
|
1225
1536
|
rowRangeToHeightRatios,
|
|
1537
|
+
serializeCopyRowsToTSV,
|
|
1538
|
+
serializeSelectionToTSV,
|
|
1226
1539
|
toggleExpandedRowId,
|
|
1227
1540
|
useCellEdit,
|
|
1228
1541
|
useCellSelection,
|
|
1229
1542
|
useConvertTreeData,
|
|
1230
|
-
useGlideTable
|
|
1543
|
+
useGlideTable,
|
|
1544
|
+
writeSelectionToClipboard
|
|
1231
1545
|
};
|