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/index.cjs
CHANGED
|
@@ -538,6 +538,90 @@ function withCellUpdate(context, commitValue) {
|
|
|
538
538
|
};
|
|
539
539
|
}
|
|
540
540
|
|
|
541
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
542
|
+
function countLeadingEmptyCells(cells) {
|
|
543
|
+
let depth = 0;
|
|
544
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
545
|
+
depth += 1;
|
|
546
|
+
}
|
|
547
|
+
return depth;
|
|
548
|
+
}
|
|
549
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
550
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
551
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
552
|
+
if (firstDepth !== 0) return false;
|
|
553
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
554
|
+
}
|
|
555
|
+
function parseClipboardTSV(text) {
|
|
556
|
+
return parseClipboardTSVWithDepths(text).values;
|
|
557
|
+
}
|
|
558
|
+
function parseClipboardTSVWithDepths(text) {
|
|
559
|
+
if (!text) return { values: [], depths: [] };
|
|
560
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
561
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
562
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
563
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
564
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
565
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
566
|
+
const values = [];
|
|
567
|
+
const depths = [];
|
|
568
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
569
|
+
const cells = rows[index] ?? [];
|
|
570
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
571
|
+
if (treatAsDepth) {
|
|
572
|
+
values.push(cells.slice(depth));
|
|
573
|
+
depths.push(depth);
|
|
574
|
+
} else {
|
|
575
|
+
values.push(cells);
|
|
576
|
+
depths.push(0);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return { values, depths };
|
|
580
|
+
}
|
|
581
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
582
|
+
if (width <= 0) return [];
|
|
583
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
584
|
+
const columnIds = [];
|
|
585
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
586
|
+
const cell = cells[startCol + offset];
|
|
587
|
+
if (!cell) break;
|
|
588
|
+
columnIds.push(cell.column.id);
|
|
589
|
+
}
|
|
590
|
+
return columnIds;
|
|
591
|
+
}
|
|
592
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
593
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
594
|
+
if (values.length === 0) return null;
|
|
595
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
596
|
+
if (width === 0) return null;
|
|
597
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
598
|
+
if (columnIds.length === 0) return null;
|
|
599
|
+
const rowIds = [];
|
|
600
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
601
|
+
const row = rows[startRow + offset];
|
|
602
|
+
if (!row) break;
|
|
603
|
+
rowIds.push(row.id);
|
|
604
|
+
}
|
|
605
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
606
|
+
return {
|
|
607
|
+
mode,
|
|
608
|
+
startRow,
|
|
609
|
+
startCol,
|
|
610
|
+
endRow,
|
|
611
|
+
rowIds,
|
|
612
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
613
|
+
columnIds,
|
|
614
|
+
values,
|
|
615
|
+
depths
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function isEditablePasteTarget(target) {
|
|
619
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
620
|
+
const tag = target.tagName;
|
|
621
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
622
|
+
return Boolean(target.isContentEditable);
|
|
623
|
+
}
|
|
624
|
+
|
|
541
625
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
542
626
|
var import_react3 = require("react");
|
|
543
627
|
|
|
@@ -1271,90 +1355,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
1271
1355
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
1272
1356
|
}
|
|
1273
1357
|
|
|
1274
|
-
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
1275
|
-
function countLeadingEmptyCells(cells) {
|
|
1276
|
-
let depth = 0;
|
|
1277
|
-
while (depth < cells.length && cells[depth] === "") {
|
|
1278
|
-
depth += 1;
|
|
1279
|
-
}
|
|
1280
|
-
return depth;
|
|
1281
|
-
}
|
|
1282
|
-
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
1283
|
-
if (leadingEmptyCounts.length === 0) return false;
|
|
1284
|
-
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
1285
|
-
if (firstDepth !== 0) return false;
|
|
1286
|
-
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
1287
|
-
}
|
|
1288
|
-
function parseClipboardTSV(text) {
|
|
1289
|
-
return parseClipboardTSVWithDepths(text).values;
|
|
1290
|
-
}
|
|
1291
|
-
function parseClipboardTSVWithDepths(text) {
|
|
1292
|
-
if (!text) return { values: [], depths: [] };
|
|
1293
|
-
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1294
|
-
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
1295
|
-
if (!withoutTrailing) return { values: [], depths: [] };
|
|
1296
|
-
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
1297
|
-
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
1298
|
-
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
1299
|
-
const values = [];
|
|
1300
|
-
const depths = [];
|
|
1301
|
-
for (let index = 0; index < rows.length; index += 1) {
|
|
1302
|
-
const cells = rows[index] ?? [];
|
|
1303
|
-
const depth = leadingEmptyCounts[index] ?? 0;
|
|
1304
|
-
if (treatAsDepth) {
|
|
1305
|
-
values.push(cells.slice(depth));
|
|
1306
|
-
depths.push(depth);
|
|
1307
|
-
} else {
|
|
1308
|
-
values.push(cells);
|
|
1309
|
-
depths.push(0);
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
return { values, depths };
|
|
1313
|
-
}
|
|
1314
|
-
function resolvePasteColumnIds(rows, startCol, width) {
|
|
1315
|
-
if (width <= 0) return [];
|
|
1316
|
-
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
1317
|
-
const columnIds = [];
|
|
1318
|
-
for (let offset = 0; offset < width; offset += 1) {
|
|
1319
|
-
const cell = cells[startCol + offset];
|
|
1320
|
-
if (!cell) break;
|
|
1321
|
-
columnIds.push(cell.column.id);
|
|
1322
|
-
}
|
|
1323
|
-
return columnIds;
|
|
1324
|
-
}
|
|
1325
|
-
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
1326
|
-
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
1327
|
-
if (values.length === 0) return null;
|
|
1328
|
-
const width = Math.max(...values.map((row) => row.length), 0);
|
|
1329
|
-
if (width === 0) return null;
|
|
1330
|
-
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
1331
|
-
if (columnIds.length === 0) return null;
|
|
1332
|
-
const rowIds = [];
|
|
1333
|
-
for (let offset = 0; offset < values.length; offset += 1) {
|
|
1334
|
-
const row = rows[startRow + offset];
|
|
1335
|
-
if (!row) break;
|
|
1336
|
-
rowIds.push(row.id);
|
|
1337
|
-
}
|
|
1338
|
-
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
1339
|
-
return {
|
|
1340
|
-
mode,
|
|
1341
|
-
startRow,
|
|
1342
|
-
startCol,
|
|
1343
|
-
endRow,
|
|
1344
|
-
rowIds,
|
|
1345
|
-
anchorRowId: anchorRow?.id ?? "",
|
|
1346
|
-
columnIds,
|
|
1347
|
-
values,
|
|
1348
|
-
depths
|
|
1349
|
-
};
|
|
1350
|
-
}
|
|
1351
|
-
function isEditablePasteTarget(target) {
|
|
1352
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
1353
|
-
const tag = target.tagName;
|
|
1354
|
-
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
1355
|
-
return Boolean(target.isContentEditable);
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
1358
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1359
1359
|
function useCellSelection({
|
|
1360
1360
|
data,
|
|
@@ -1436,11 +1436,19 @@ function useCellSelection({
|
|
|
1436
1436
|
},
|
|
1437
1437
|
[enabled]
|
|
1438
1438
|
);
|
|
1439
|
+
const clearSelection = (0, import_react3.useCallback)(() => {
|
|
1440
|
+
const prev = dragStateRef.current;
|
|
1441
|
+
if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
dragStateRef.current = INITIAL_DRAG_STATE;
|
|
1445
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
1446
|
+
}, []);
|
|
1439
1447
|
(0, import_react3.useEffect)(() => {
|
|
1440
1448
|
if (!enabled) {
|
|
1441
|
-
|
|
1449
|
+
clearSelection();
|
|
1442
1450
|
}
|
|
1443
|
-
}, [enabled]);
|
|
1451
|
+
}, [clearSelection, enabled]);
|
|
1444
1452
|
(0, import_react3.useEffect)(() => {
|
|
1445
1453
|
if (!enabled) return;
|
|
1446
1454
|
const handleKeyDown = (e) => {
|
|
@@ -1654,6 +1662,7 @@ function useCellSelection({
|
|
|
1654
1662
|
handleCellMouseDown,
|
|
1655
1663
|
handleCellMouseEnter,
|
|
1656
1664
|
handleFillHandleMouseDown,
|
|
1665
|
+
clearSelection,
|
|
1657
1666
|
copySelection
|
|
1658
1667
|
};
|
|
1659
1668
|
}
|
|
@@ -2937,6 +2946,7 @@ function useGlideTable(options) {
|
|
|
2937
2946
|
handleCellMouseDown,
|
|
2938
2947
|
handleCellMouseEnter,
|
|
2939
2948
|
handleFillHandleMouseDown,
|
|
2949
|
+
clearSelection: clearCellSelection,
|
|
2940
2950
|
copySelection
|
|
2941
2951
|
} = useCellSelection({
|
|
2942
2952
|
data: tableData,
|
|
@@ -2952,6 +2962,42 @@ function useGlideTable(options) {
|
|
|
2952
2962
|
cellRendererRegistry,
|
|
2953
2963
|
rootRef
|
|
2954
2964
|
});
|
|
2965
|
+
const clearRowSelection = (0, import_react6.useCallback)(() => {
|
|
2966
|
+
if (rowSelectionMode === "none") return;
|
|
2967
|
+
const hasSelection = Object.values(rowSelection).some(Boolean);
|
|
2968
|
+
if (!hasSelection) return;
|
|
2969
|
+
if (onRowSelectionChange) {
|
|
2970
|
+
onRowSelectionChange(() => ({}));
|
|
2971
|
+
return;
|
|
2972
|
+
}
|
|
2973
|
+
setInternalRowSelection({});
|
|
2974
|
+
}, [onRowSelectionChange, rowSelection, rowSelectionMode]);
|
|
2975
|
+
(0, import_react6.useEffect)(() => {
|
|
2976
|
+
const clearAllSelections = () => {
|
|
2977
|
+
clearCellSelection();
|
|
2978
|
+
clearRowSelection();
|
|
2979
|
+
};
|
|
2980
|
+
const handleKeyDown = (event) => {
|
|
2981
|
+
if (event.key !== "Escape") return;
|
|
2982
|
+
if (event.defaultPrevented) return;
|
|
2983
|
+
if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
|
|
2984
|
+
return;
|
|
2985
|
+
}
|
|
2986
|
+
clearAllSelections();
|
|
2987
|
+
};
|
|
2988
|
+
const handleMouseDown = (event) => {
|
|
2989
|
+
const root = rootRef.current;
|
|
2990
|
+
if (!root) return;
|
|
2991
|
+
if (event.target instanceof Node && root.contains(event.target)) return;
|
|
2992
|
+
clearAllSelections();
|
|
2993
|
+
};
|
|
2994
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
2995
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
2996
|
+
return () => {
|
|
2997
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
2998
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
2999
|
+
};
|
|
3000
|
+
}, [clearCellSelection, clearRowSelection]);
|
|
2955
3001
|
const {
|
|
2956
3002
|
editingCell,
|
|
2957
3003
|
draftValue,
|
package/dist/index.js
CHANGED
|
@@ -441,6 +441,90 @@ function withCellUpdate(context, commitValue) {
|
|
|
441
441
|
};
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
445
|
+
function countLeadingEmptyCells(cells) {
|
|
446
|
+
let depth = 0;
|
|
447
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
448
|
+
depth += 1;
|
|
449
|
+
}
|
|
450
|
+
return depth;
|
|
451
|
+
}
|
|
452
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
453
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
454
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
455
|
+
if (firstDepth !== 0) return false;
|
|
456
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
457
|
+
}
|
|
458
|
+
function parseClipboardTSV(text) {
|
|
459
|
+
return parseClipboardTSVWithDepths(text).values;
|
|
460
|
+
}
|
|
461
|
+
function parseClipboardTSVWithDepths(text) {
|
|
462
|
+
if (!text) return { values: [], depths: [] };
|
|
463
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
464
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
465
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
466
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
467
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
468
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
469
|
+
const values = [];
|
|
470
|
+
const depths = [];
|
|
471
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
472
|
+
const cells = rows[index] ?? [];
|
|
473
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
474
|
+
if (treatAsDepth) {
|
|
475
|
+
values.push(cells.slice(depth));
|
|
476
|
+
depths.push(depth);
|
|
477
|
+
} else {
|
|
478
|
+
values.push(cells);
|
|
479
|
+
depths.push(0);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return { values, depths };
|
|
483
|
+
}
|
|
484
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
485
|
+
if (width <= 0) return [];
|
|
486
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
487
|
+
const columnIds = [];
|
|
488
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
489
|
+
const cell = cells[startCol + offset];
|
|
490
|
+
if (!cell) break;
|
|
491
|
+
columnIds.push(cell.column.id);
|
|
492
|
+
}
|
|
493
|
+
return columnIds;
|
|
494
|
+
}
|
|
495
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
496
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
497
|
+
if (values.length === 0) return null;
|
|
498
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
499
|
+
if (width === 0) return null;
|
|
500
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
501
|
+
if (columnIds.length === 0) return null;
|
|
502
|
+
const rowIds = [];
|
|
503
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
504
|
+
const row = rows[startRow + offset];
|
|
505
|
+
if (!row) break;
|
|
506
|
+
rowIds.push(row.id);
|
|
507
|
+
}
|
|
508
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
509
|
+
return {
|
|
510
|
+
mode,
|
|
511
|
+
startRow,
|
|
512
|
+
startCol,
|
|
513
|
+
endRow,
|
|
514
|
+
rowIds,
|
|
515
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
516
|
+
columnIds,
|
|
517
|
+
values,
|
|
518
|
+
depths
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function isEditablePasteTarget(target) {
|
|
522
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
523
|
+
const tag = target.tagName;
|
|
524
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
525
|
+
return Boolean(target.isContentEditable);
|
|
526
|
+
}
|
|
527
|
+
|
|
444
528
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
445
529
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
446
530
|
|
|
@@ -1174,90 +1258,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
1174
1258
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
1175
1259
|
}
|
|
1176
1260
|
|
|
1177
|
-
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
1178
|
-
function countLeadingEmptyCells(cells) {
|
|
1179
|
-
let depth = 0;
|
|
1180
|
-
while (depth < cells.length && cells[depth] === "") {
|
|
1181
|
-
depth += 1;
|
|
1182
|
-
}
|
|
1183
|
-
return depth;
|
|
1184
|
-
}
|
|
1185
|
-
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
1186
|
-
if (leadingEmptyCounts.length === 0) return false;
|
|
1187
|
-
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
1188
|
-
if (firstDepth !== 0) return false;
|
|
1189
|
-
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
1190
|
-
}
|
|
1191
|
-
function parseClipboardTSV(text) {
|
|
1192
|
-
return parseClipboardTSVWithDepths(text).values;
|
|
1193
|
-
}
|
|
1194
|
-
function parseClipboardTSVWithDepths(text) {
|
|
1195
|
-
if (!text) return { values: [], depths: [] };
|
|
1196
|
-
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1197
|
-
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
1198
|
-
if (!withoutTrailing) return { values: [], depths: [] };
|
|
1199
|
-
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
1200
|
-
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
1201
|
-
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
1202
|
-
const values = [];
|
|
1203
|
-
const depths = [];
|
|
1204
|
-
for (let index = 0; index < rows.length; index += 1) {
|
|
1205
|
-
const cells = rows[index] ?? [];
|
|
1206
|
-
const depth = leadingEmptyCounts[index] ?? 0;
|
|
1207
|
-
if (treatAsDepth) {
|
|
1208
|
-
values.push(cells.slice(depth));
|
|
1209
|
-
depths.push(depth);
|
|
1210
|
-
} else {
|
|
1211
|
-
values.push(cells);
|
|
1212
|
-
depths.push(0);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
return { values, depths };
|
|
1216
|
-
}
|
|
1217
|
-
function resolvePasteColumnIds(rows, startCol, width) {
|
|
1218
|
-
if (width <= 0) return [];
|
|
1219
|
-
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
1220
|
-
const columnIds = [];
|
|
1221
|
-
for (let offset = 0; offset < width; offset += 1) {
|
|
1222
|
-
const cell = cells[startCol + offset];
|
|
1223
|
-
if (!cell) break;
|
|
1224
|
-
columnIds.push(cell.column.id);
|
|
1225
|
-
}
|
|
1226
|
-
return columnIds;
|
|
1227
|
-
}
|
|
1228
|
-
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
1229
|
-
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
1230
|
-
if (values.length === 0) return null;
|
|
1231
|
-
const width = Math.max(...values.map((row) => row.length), 0);
|
|
1232
|
-
if (width === 0) return null;
|
|
1233
|
-
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
1234
|
-
if (columnIds.length === 0) return null;
|
|
1235
|
-
const rowIds = [];
|
|
1236
|
-
for (let offset = 0; offset < values.length; offset += 1) {
|
|
1237
|
-
const row = rows[startRow + offset];
|
|
1238
|
-
if (!row) break;
|
|
1239
|
-
rowIds.push(row.id);
|
|
1240
|
-
}
|
|
1241
|
-
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
1242
|
-
return {
|
|
1243
|
-
mode,
|
|
1244
|
-
startRow,
|
|
1245
|
-
startCol,
|
|
1246
|
-
endRow,
|
|
1247
|
-
rowIds,
|
|
1248
|
-
anchorRowId: anchorRow?.id ?? "",
|
|
1249
|
-
columnIds,
|
|
1250
|
-
values,
|
|
1251
|
-
depths
|
|
1252
|
-
};
|
|
1253
|
-
}
|
|
1254
|
-
function isEditablePasteTarget(target) {
|
|
1255
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
1256
|
-
const tag = target.tagName;
|
|
1257
|
-
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
1258
|
-
return Boolean(target.isContentEditable);
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
1261
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1262
1262
|
function useCellSelection({
|
|
1263
1263
|
data,
|
|
@@ -1339,11 +1339,19 @@ function useCellSelection({
|
|
|
1339
1339
|
},
|
|
1340
1340
|
[enabled]
|
|
1341
1341
|
);
|
|
1342
|
+
const clearSelection = useCallback2(() => {
|
|
1343
|
+
const prev = dragStateRef.current;
|
|
1344
|
+
if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
dragStateRef.current = INITIAL_DRAG_STATE;
|
|
1348
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
1349
|
+
}, []);
|
|
1342
1350
|
useEffect2(() => {
|
|
1343
1351
|
if (!enabled) {
|
|
1344
|
-
|
|
1352
|
+
clearSelection();
|
|
1345
1353
|
}
|
|
1346
|
-
}, [enabled]);
|
|
1354
|
+
}, [clearSelection, enabled]);
|
|
1347
1355
|
useEffect2(() => {
|
|
1348
1356
|
if (!enabled) return;
|
|
1349
1357
|
const handleKeyDown = (e) => {
|
|
@@ -1557,6 +1565,7 @@ function useCellSelection({
|
|
|
1557
1565
|
handleCellMouseDown,
|
|
1558
1566
|
handleCellMouseEnter,
|
|
1559
1567
|
handleFillHandleMouseDown,
|
|
1568
|
+
clearSelection,
|
|
1560
1569
|
copySelection
|
|
1561
1570
|
};
|
|
1562
1571
|
}
|
|
@@ -2847,6 +2856,7 @@ function useGlideTable(options) {
|
|
|
2847
2856
|
handleCellMouseDown,
|
|
2848
2857
|
handleCellMouseEnter,
|
|
2849
2858
|
handleFillHandleMouseDown,
|
|
2859
|
+
clearSelection: clearCellSelection,
|
|
2850
2860
|
copySelection
|
|
2851
2861
|
} = useCellSelection({
|
|
2852
2862
|
data: tableData,
|
|
@@ -2862,6 +2872,42 @@ function useGlideTable(options) {
|
|
|
2862
2872
|
cellRendererRegistry,
|
|
2863
2873
|
rootRef
|
|
2864
2874
|
});
|
|
2875
|
+
const clearRowSelection = useCallback4(() => {
|
|
2876
|
+
if (rowSelectionMode === "none") return;
|
|
2877
|
+
const hasSelection = Object.values(rowSelection).some(Boolean);
|
|
2878
|
+
if (!hasSelection) return;
|
|
2879
|
+
if (onRowSelectionChange) {
|
|
2880
|
+
onRowSelectionChange(() => ({}));
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
setInternalRowSelection({});
|
|
2884
|
+
}, [onRowSelectionChange, rowSelection, rowSelectionMode]);
|
|
2885
|
+
useEffect5(() => {
|
|
2886
|
+
const clearAllSelections = () => {
|
|
2887
|
+
clearCellSelection();
|
|
2888
|
+
clearRowSelection();
|
|
2889
|
+
};
|
|
2890
|
+
const handleKeyDown = (event) => {
|
|
2891
|
+
if (event.key !== "Escape") return;
|
|
2892
|
+
if (event.defaultPrevented) return;
|
|
2893
|
+
if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
|
|
2894
|
+
return;
|
|
2895
|
+
}
|
|
2896
|
+
clearAllSelections();
|
|
2897
|
+
};
|
|
2898
|
+
const handleMouseDown = (event) => {
|
|
2899
|
+
const root = rootRef.current;
|
|
2900
|
+
if (!root) return;
|
|
2901
|
+
if (event.target instanceof Node && root.contains(event.target)) return;
|
|
2902
|
+
clearAllSelections();
|
|
2903
|
+
};
|
|
2904
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
2905
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
2906
|
+
return () => {
|
|
2907
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
2908
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
2909
|
+
};
|
|
2910
|
+
}, [clearCellSelection, clearRowSelection]);
|
|
2865
2911
|
const {
|
|
2866
2912
|
editingCell,
|
|
2867
2913
|
draftValue,
|