react-glide-table 2.3.0 → 2.3.1
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/dist/compound.cjs +129 -83
- package/dist/compound.js +129 -83
- package/dist/core.cjs +132 -86
- package/dist/core.d.cts +1 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +132 -86
- package/dist/index.cjs +132 -86
- package/dist/index.js +132 -86
- package/package.json +1 -1
package/dist/core.cjs
CHANGED
|
@@ -526,6 +526,90 @@ function withCellUpdate(context, commitValue) {
|
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
530
|
+
function countLeadingEmptyCells(cells) {
|
|
531
|
+
let depth = 0;
|
|
532
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
533
|
+
depth += 1;
|
|
534
|
+
}
|
|
535
|
+
return depth;
|
|
536
|
+
}
|
|
537
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
538
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
539
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
540
|
+
if (firstDepth !== 0) return false;
|
|
541
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
542
|
+
}
|
|
543
|
+
function parseClipboardTSV(text) {
|
|
544
|
+
return parseClipboardTSVWithDepths(text).values;
|
|
545
|
+
}
|
|
546
|
+
function parseClipboardTSVWithDepths(text) {
|
|
547
|
+
if (!text) return { values: [], depths: [] };
|
|
548
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
549
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
550
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
551
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
552
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
553
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
554
|
+
const values = [];
|
|
555
|
+
const depths = [];
|
|
556
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
557
|
+
const cells = rows[index] ?? [];
|
|
558
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
559
|
+
if (treatAsDepth) {
|
|
560
|
+
values.push(cells.slice(depth));
|
|
561
|
+
depths.push(depth);
|
|
562
|
+
} else {
|
|
563
|
+
values.push(cells);
|
|
564
|
+
depths.push(0);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return { values, depths };
|
|
568
|
+
}
|
|
569
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
570
|
+
if (width <= 0) return [];
|
|
571
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
572
|
+
const columnIds = [];
|
|
573
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
574
|
+
const cell = cells[startCol + offset];
|
|
575
|
+
if (!cell) break;
|
|
576
|
+
columnIds.push(cell.column.id);
|
|
577
|
+
}
|
|
578
|
+
return columnIds;
|
|
579
|
+
}
|
|
580
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
581
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
582
|
+
if (values.length === 0) return null;
|
|
583
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
584
|
+
if (width === 0) return null;
|
|
585
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
586
|
+
if (columnIds.length === 0) return null;
|
|
587
|
+
const rowIds = [];
|
|
588
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
589
|
+
const row = rows[startRow + offset];
|
|
590
|
+
if (!row) break;
|
|
591
|
+
rowIds.push(row.id);
|
|
592
|
+
}
|
|
593
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
594
|
+
return {
|
|
595
|
+
mode,
|
|
596
|
+
startRow,
|
|
597
|
+
startCol,
|
|
598
|
+
endRow,
|
|
599
|
+
rowIds,
|
|
600
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
601
|
+
columnIds,
|
|
602
|
+
values,
|
|
603
|
+
depths
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function isEditablePasteTarget(target) {
|
|
607
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
608
|
+
const tag = target.tagName;
|
|
609
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
610
|
+
return Boolean(target.isContentEditable);
|
|
611
|
+
}
|
|
612
|
+
|
|
529
613
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
530
614
|
var import_react3 = require("react");
|
|
531
615
|
|
|
@@ -1259,90 +1343,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
1259
1343
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
1260
1344
|
}
|
|
1261
1345
|
|
|
1262
|
-
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
1263
|
-
function countLeadingEmptyCells(cells) {
|
|
1264
|
-
let depth = 0;
|
|
1265
|
-
while (depth < cells.length && cells[depth] === "") {
|
|
1266
|
-
depth += 1;
|
|
1267
|
-
}
|
|
1268
|
-
return depth;
|
|
1269
|
-
}
|
|
1270
|
-
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
1271
|
-
if (leadingEmptyCounts.length === 0) return false;
|
|
1272
|
-
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
1273
|
-
if (firstDepth !== 0) return false;
|
|
1274
|
-
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
1275
|
-
}
|
|
1276
|
-
function parseClipboardTSV(text) {
|
|
1277
|
-
return parseClipboardTSVWithDepths(text).values;
|
|
1278
|
-
}
|
|
1279
|
-
function parseClipboardTSVWithDepths(text) {
|
|
1280
|
-
if (!text) return { values: [], depths: [] };
|
|
1281
|
-
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1282
|
-
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
1283
|
-
if (!withoutTrailing) return { values: [], depths: [] };
|
|
1284
|
-
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
1285
|
-
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
1286
|
-
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
1287
|
-
const values = [];
|
|
1288
|
-
const depths = [];
|
|
1289
|
-
for (let index = 0; index < rows.length; index += 1) {
|
|
1290
|
-
const cells = rows[index] ?? [];
|
|
1291
|
-
const depth = leadingEmptyCounts[index] ?? 0;
|
|
1292
|
-
if (treatAsDepth) {
|
|
1293
|
-
values.push(cells.slice(depth));
|
|
1294
|
-
depths.push(depth);
|
|
1295
|
-
} else {
|
|
1296
|
-
values.push(cells);
|
|
1297
|
-
depths.push(0);
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
return { values, depths };
|
|
1301
|
-
}
|
|
1302
|
-
function resolvePasteColumnIds(rows, startCol, width) {
|
|
1303
|
-
if (width <= 0) return [];
|
|
1304
|
-
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
1305
|
-
const columnIds = [];
|
|
1306
|
-
for (let offset = 0; offset < width; offset += 1) {
|
|
1307
|
-
const cell = cells[startCol + offset];
|
|
1308
|
-
if (!cell) break;
|
|
1309
|
-
columnIds.push(cell.column.id);
|
|
1310
|
-
}
|
|
1311
|
-
return columnIds;
|
|
1312
|
-
}
|
|
1313
|
-
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
1314
|
-
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
1315
|
-
if (values.length === 0) return null;
|
|
1316
|
-
const width = Math.max(...values.map((row) => row.length), 0);
|
|
1317
|
-
if (width === 0) return null;
|
|
1318
|
-
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
1319
|
-
if (columnIds.length === 0) return null;
|
|
1320
|
-
const rowIds = [];
|
|
1321
|
-
for (let offset = 0; offset < values.length; offset += 1) {
|
|
1322
|
-
const row = rows[startRow + offset];
|
|
1323
|
-
if (!row) break;
|
|
1324
|
-
rowIds.push(row.id);
|
|
1325
|
-
}
|
|
1326
|
-
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
1327
|
-
return {
|
|
1328
|
-
mode,
|
|
1329
|
-
startRow,
|
|
1330
|
-
startCol,
|
|
1331
|
-
endRow,
|
|
1332
|
-
rowIds,
|
|
1333
|
-
anchorRowId: anchorRow?.id ?? "",
|
|
1334
|
-
columnIds,
|
|
1335
|
-
values,
|
|
1336
|
-
depths
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
function isEditablePasteTarget(target) {
|
|
1340
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
1341
|
-
const tag = target.tagName;
|
|
1342
|
-
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
1343
|
-
return Boolean(target.isContentEditable);
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
1346
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1347
1347
|
function useCellSelection({
|
|
1348
1348
|
data,
|
|
@@ -1424,11 +1424,19 @@ function useCellSelection({
|
|
|
1424
1424
|
},
|
|
1425
1425
|
[enabled]
|
|
1426
1426
|
);
|
|
1427
|
+
const clearSelection = (0, import_react3.useCallback)(() => {
|
|
1428
|
+
const prev = dragStateRef.current;
|
|
1429
|
+
if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
dragStateRef.current = INITIAL_DRAG_STATE;
|
|
1433
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
1434
|
+
}, []);
|
|
1427
1435
|
(0, import_react3.useEffect)(() => {
|
|
1428
1436
|
if (!enabled) {
|
|
1429
|
-
|
|
1437
|
+
clearSelection();
|
|
1430
1438
|
}
|
|
1431
|
-
}, [enabled]);
|
|
1439
|
+
}, [clearSelection, enabled]);
|
|
1432
1440
|
(0, import_react3.useEffect)(() => {
|
|
1433
1441
|
if (!enabled) return;
|
|
1434
1442
|
const handleKeyDown = (e) => {
|
|
@@ -1642,6 +1650,7 @@ function useCellSelection({
|
|
|
1642
1650
|
handleCellMouseDown,
|
|
1643
1651
|
handleCellMouseEnter,
|
|
1644
1652
|
handleFillHandleMouseDown,
|
|
1653
|
+
clearSelection,
|
|
1645
1654
|
copySelection
|
|
1646
1655
|
};
|
|
1647
1656
|
}
|
|
@@ -2919,6 +2928,7 @@ function useGlideTable(options) {
|
|
|
2919
2928
|
handleCellMouseDown,
|
|
2920
2929
|
handleCellMouseEnter,
|
|
2921
2930
|
handleFillHandleMouseDown,
|
|
2931
|
+
clearSelection: clearCellSelection,
|
|
2922
2932
|
copySelection
|
|
2923
2933
|
} = useCellSelection({
|
|
2924
2934
|
data: tableData,
|
|
@@ -2934,6 +2944,42 @@ function useGlideTable(options) {
|
|
|
2934
2944
|
cellRendererRegistry,
|
|
2935
2945
|
rootRef
|
|
2936
2946
|
});
|
|
2947
|
+
const clearRowSelection = (0, import_react6.useCallback)(() => {
|
|
2948
|
+
if (rowSelectionMode === "none") return;
|
|
2949
|
+
const hasSelection = Object.values(rowSelection).some(Boolean);
|
|
2950
|
+
if (!hasSelection) return;
|
|
2951
|
+
if (onRowSelectionChange) {
|
|
2952
|
+
onRowSelectionChange(() => ({}));
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2955
|
+
setInternalRowSelection({});
|
|
2956
|
+
}, [onRowSelectionChange, rowSelection, rowSelectionMode]);
|
|
2957
|
+
(0, import_react6.useEffect)(() => {
|
|
2958
|
+
const clearAllSelections = () => {
|
|
2959
|
+
clearCellSelection();
|
|
2960
|
+
clearRowSelection();
|
|
2961
|
+
};
|
|
2962
|
+
const handleKeyDown = (event) => {
|
|
2963
|
+
if (event.key !== "Escape") return;
|
|
2964
|
+
if (event.defaultPrevented) return;
|
|
2965
|
+
if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
|
|
2966
|
+
return;
|
|
2967
|
+
}
|
|
2968
|
+
clearAllSelections();
|
|
2969
|
+
};
|
|
2970
|
+
const handleMouseDown = (event) => {
|
|
2971
|
+
const root = rootRef.current;
|
|
2972
|
+
if (!root) return;
|
|
2973
|
+
if (event.target instanceof Node && root.contains(event.target)) return;
|
|
2974
|
+
clearAllSelections();
|
|
2975
|
+
};
|
|
2976
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
2977
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
2978
|
+
return () => {
|
|
2979
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
2980
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
2981
|
+
};
|
|
2982
|
+
}, [clearCellSelection, clearRowSelection]);
|
|
2937
2983
|
const {
|
|
2938
2984
|
editingCell,
|
|
2939
2985
|
draftValue,
|
package/dist/core.d.cts
CHANGED
|
@@ -463,6 +463,7 @@ declare function useCellSelection<T extends Record<string, unknown>>({ data, row
|
|
|
463
463
|
handleCellMouseDown: (rowIndex: number, colIndex: number, options?: CellMouseDownOptions) => void;
|
|
464
464
|
handleCellMouseEnter: (rowIndex: number, colIndex: number) => void;
|
|
465
465
|
handleFillHandleMouseDown: (rowIndex: number, colIndex: number) => void;
|
|
466
|
+
clearSelection: () => void;
|
|
466
467
|
copySelection: (options?: CopySelectionOptions) => Promise<boolean>;
|
|
467
468
|
};
|
|
468
469
|
|
package/dist/core.d.ts
CHANGED
|
@@ -463,6 +463,7 @@ declare function useCellSelection<T extends Record<string, unknown>>({ data, row
|
|
|
463
463
|
handleCellMouseDown: (rowIndex: number, colIndex: number, options?: CellMouseDownOptions) => void;
|
|
464
464
|
handleCellMouseEnter: (rowIndex: number, colIndex: number) => void;
|
|
465
465
|
handleFillHandleMouseDown: (rowIndex: number, colIndex: number) => void;
|
|
466
|
+
clearSelection: () => void;
|
|
466
467
|
copySelection: (options?: CopySelectionOptions) => Promise<boolean>;
|
|
467
468
|
};
|
|
468
469
|
|
package/dist/core.js
CHANGED
|
@@ -432,6 +432,90 @@ function withCellUpdate(context, commitValue) {
|
|
|
432
432
|
};
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
436
|
+
function countLeadingEmptyCells(cells) {
|
|
437
|
+
let depth = 0;
|
|
438
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
439
|
+
depth += 1;
|
|
440
|
+
}
|
|
441
|
+
return depth;
|
|
442
|
+
}
|
|
443
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
444
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
445
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
446
|
+
if (firstDepth !== 0) return false;
|
|
447
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
448
|
+
}
|
|
449
|
+
function parseClipboardTSV(text) {
|
|
450
|
+
return parseClipboardTSVWithDepths(text).values;
|
|
451
|
+
}
|
|
452
|
+
function parseClipboardTSVWithDepths(text) {
|
|
453
|
+
if (!text) return { values: [], depths: [] };
|
|
454
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
455
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
456
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
457
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
458
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
459
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
460
|
+
const values = [];
|
|
461
|
+
const depths = [];
|
|
462
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
463
|
+
const cells = rows[index] ?? [];
|
|
464
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
465
|
+
if (treatAsDepth) {
|
|
466
|
+
values.push(cells.slice(depth));
|
|
467
|
+
depths.push(depth);
|
|
468
|
+
} else {
|
|
469
|
+
values.push(cells);
|
|
470
|
+
depths.push(0);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return { values, depths };
|
|
474
|
+
}
|
|
475
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
476
|
+
if (width <= 0) return [];
|
|
477
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
478
|
+
const columnIds = [];
|
|
479
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
480
|
+
const cell = cells[startCol + offset];
|
|
481
|
+
if (!cell) break;
|
|
482
|
+
columnIds.push(cell.column.id);
|
|
483
|
+
}
|
|
484
|
+
return columnIds;
|
|
485
|
+
}
|
|
486
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
487
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
488
|
+
if (values.length === 0) return null;
|
|
489
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
490
|
+
if (width === 0) return null;
|
|
491
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
492
|
+
if (columnIds.length === 0) return null;
|
|
493
|
+
const rowIds = [];
|
|
494
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
495
|
+
const row = rows[startRow + offset];
|
|
496
|
+
if (!row) break;
|
|
497
|
+
rowIds.push(row.id);
|
|
498
|
+
}
|
|
499
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
500
|
+
return {
|
|
501
|
+
mode,
|
|
502
|
+
startRow,
|
|
503
|
+
startCol,
|
|
504
|
+
endRow,
|
|
505
|
+
rowIds,
|
|
506
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
507
|
+
columnIds,
|
|
508
|
+
values,
|
|
509
|
+
depths
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function isEditablePasteTarget(target) {
|
|
513
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
514
|
+
const tag = target.tagName;
|
|
515
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
516
|
+
return Boolean(target.isContentEditable);
|
|
517
|
+
}
|
|
518
|
+
|
|
435
519
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
436
520
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
437
521
|
|
|
@@ -1165,90 +1249,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
1165
1249
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
1166
1250
|
}
|
|
1167
1251
|
|
|
1168
|
-
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
1169
|
-
function countLeadingEmptyCells(cells) {
|
|
1170
|
-
let depth = 0;
|
|
1171
|
-
while (depth < cells.length && cells[depth] === "") {
|
|
1172
|
-
depth += 1;
|
|
1173
|
-
}
|
|
1174
|
-
return depth;
|
|
1175
|
-
}
|
|
1176
|
-
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
1177
|
-
if (leadingEmptyCounts.length === 0) return false;
|
|
1178
|
-
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
1179
|
-
if (firstDepth !== 0) return false;
|
|
1180
|
-
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
1181
|
-
}
|
|
1182
|
-
function parseClipboardTSV(text) {
|
|
1183
|
-
return parseClipboardTSVWithDepths(text).values;
|
|
1184
|
-
}
|
|
1185
|
-
function parseClipboardTSVWithDepths(text) {
|
|
1186
|
-
if (!text) return { values: [], depths: [] };
|
|
1187
|
-
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1188
|
-
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
1189
|
-
if (!withoutTrailing) return { values: [], depths: [] };
|
|
1190
|
-
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
1191
|
-
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
1192
|
-
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
1193
|
-
const values = [];
|
|
1194
|
-
const depths = [];
|
|
1195
|
-
for (let index = 0; index < rows.length; index += 1) {
|
|
1196
|
-
const cells = rows[index] ?? [];
|
|
1197
|
-
const depth = leadingEmptyCounts[index] ?? 0;
|
|
1198
|
-
if (treatAsDepth) {
|
|
1199
|
-
values.push(cells.slice(depth));
|
|
1200
|
-
depths.push(depth);
|
|
1201
|
-
} else {
|
|
1202
|
-
values.push(cells);
|
|
1203
|
-
depths.push(0);
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
return { values, depths };
|
|
1207
|
-
}
|
|
1208
|
-
function resolvePasteColumnIds(rows, startCol, width) {
|
|
1209
|
-
if (width <= 0) return [];
|
|
1210
|
-
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
1211
|
-
const columnIds = [];
|
|
1212
|
-
for (let offset = 0; offset < width; offset += 1) {
|
|
1213
|
-
const cell = cells[startCol + offset];
|
|
1214
|
-
if (!cell) break;
|
|
1215
|
-
columnIds.push(cell.column.id);
|
|
1216
|
-
}
|
|
1217
|
-
return columnIds;
|
|
1218
|
-
}
|
|
1219
|
-
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
1220
|
-
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
1221
|
-
if (values.length === 0) return null;
|
|
1222
|
-
const width = Math.max(...values.map((row) => row.length), 0);
|
|
1223
|
-
if (width === 0) return null;
|
|
1224
|
-
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
1225
|
-
if (columnIds.length === 0) return null;
|
|
1226
|
-
const rowIds = [];
|
|
1227
|
-
for (let offset = 0; offset < values.length; offset += 1) {
|
|
1228
|
-
const row = rows[startRow + offset];
|
|
1229
|
-
if (!row) break;
|
|
1230
|
-
rowIds.push(row.id);
|
|
1231
|
-
}
|
|
1232
|
-
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
1233
|
-
return {
|
|
1234
|
-
mode,
|
|
1235
|
-
startRow,
|
|
1236
|
-
startCol,
|
|
1237
|
-
endRow,
|
|
1238
|
-
rowIds,
|
|
1239
|
-
anchorRowId: anchorRow?.id ?? "",
|
|
1240
|
-
columnIds,
|
|
1241
|
-
values,
|
|
1242
|
-
depths
|
|
1243
|
-
};
|
|
1244
|
-
}
|
|
1245
|
-
function isEditablePasteTarget(target) {
|
|
1246
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
1247
|
-
const tag = target.tagName;
|
|
1248
|
-
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
1249
|
-
return Boolean(target.isContentEditable);
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
1252
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1253
1253
|
function useCellSelection({
|
|
1254
1254
|
data,
|
|
@@ -1330,11 +1330,19 @@ function useCellSelection({
|
|
|
1330
1330
|
},
|
|
1331
1331
|
[enabled]
|
|
1332
1332
|
);
|
|
1333
|
+
const clearSelection = useCallback2(() => {
|
|
1334
|
+
const prev = dragStateRef.current;
|
|
1335
|
+
if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
dragStateRef.current = INITIAL_DRAG_STATE;
|
|
1339
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
1340
|
+
}, []);
|
|
1333
1341
|
useEffect2(() => {
|
|
1334
1342
|
if (!enabled) {
|
|
1335
|
-
|
|
1343
|
+
clearSelection();
|
|
1336
1344
|
}
|
|
1337
|
-
}, [enabled]);
|
|
1345
|
+
}, [clearSelection, enabled]);
|
|
1338
1346
|
useEffect2(() => {
|
|
1339
1347
|
if (!enabled) return;
|
|
1340
1348
|
const handleKeyDown = (e) => {
|
|
@@ -1548,6 +1556,7 @@ function useCellSelection({
|
|
|
1548
1556
|
handleCellMouseDown,
|
|
1549
1557
|
handleCellMouseEnter,
|
|
1550
1558
|
handleFillHandleMouseDown,
|
|
1559
|
+
clearSelection,
|
|
1551
1560
|
copySelection
|
|
1552
1561
|
};
|
|
1553
1562
|
}
|
|
@@ -2832,6 +2841,7 @@ function useGlideTable(options) {
|
|
|
2832
2841
|
handleCellMouseDown,
|
|
2833
2842
|
handleCellMouseEnter,
|
|
2834
2843
|
handleFillHandleMouseDown,
|
|
2844
|
+
clearSelection: clearCellSelection,
|
|
2835
2845
|
copySelection
|
|
2836
2846
|
} = useCellSelection({
|
|
2837
2847
|
data: tableData,
|
|
@@ -2847,6 +2857,42 @@ function useGlideTable(options) {
|
|
|
2847
2857
|
cellRendererRegistry,
|
|
2848
2858
|
rootRef
|
|
2849
2859
|
});
|
|
2860
|
+
const clearRowSelection = useCallback4(() => {
|
|
2861
|
+
if (rowSelectionMode === "none") return;
|
|
2862
|
+
const hasSelection = Object.values(rowSelection).some(Boolean);
|
|
2863
|
+
if (!hasSelection) return;
|
|
2864
|
+
if (onRowSelectionChange) {
|
|
2865
|
+
onRowSelectionChange(() => ({}));
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
setInternalRowSelection({});
|
|
2869
|
+
}, [onRowSelectionChange, rowSelection, rowSelectionMode]);
|
|
2870
|
+
useEffect5(() => {
|
|
2871
|
+
const clearAllSelections = () => {
|
|
2872
|
+
clearCellSelection();
|
|
2873
|
+
clearRowSelection();
|
|
2874
|
+
};
|
|
2875
|
+
const handleKeyDown = (event) => {
|
|
2876
|
+
if (event.key !== "Escape") return;
|
|
2877
|
+
if (event.defaultPrevented) return;
|
|
2878
|
+
if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
clearAllSelections();
|
|
2882
|
+
};
|
|
2883
|
+
const handleMouseDown = (event) => {
|
|
2884
|
+
const root = rootRef.current;
|
|
2885
|
+
if (!root) return;
|
|
2886
|
+
if (event.target instanceof Node && root.contains(event.target)) return;
|
|
2887
|
+
clearAllSelections();
|
|
2888
|
+
};
|
|
2889
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
2890
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
2891
|
+
return () => {
|
|
2892
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
2893
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
2894
|
+
};
|
|
2895
|
+
}, [clearCellSelection, clearRowSelection]);
|
|
2850
2896
|
const {
|
|
2851
2897
|
editingCell,
|
|
2852
2898
|
draftValue,
|