react-glide-table 2.3.0 → 2.3.2
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 +27 -0
- package/dist/compound.cjs +219 -105
- package/dist/compound.d.cts +2 -2
- package/dist/compound.d.ts +2 -2
- package/dist/compound.js +219 -105
- package/dist/core.cjs +219 -107
- package/dist/core.d.cts +3 -2
- package/dist/core.d.ts +3 -2
- package/dist/core.js +219 -107
- package/dist/index.cjs +222 -108
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +222 -108
- package/dist/{types-DdeVn-9s.d.cts → types-hf2ruVdu.d.cts} +25 -1
- package/dist/{types-DdeVn-9s.d.ts → types-hf2ruVdu.d.ts} +25 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -441,9 +441,126 @@ 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
|
|
|
531
|
+
// src/components/ui/table/features/cell-selection/activeCellSelectionOwner.ts
|
|
532
|
+
var activeOwner = null;
|
|
533
|
+
var clearByOwner = /* @__PURE__ */ new Map();
|
|
534
|
+
function createCellSelectionOwner() {
|
|
535
|
+
return /* @__PURE__ */ Symbol("cell-selection-owner");
|
|
536
|
+
}
|
|
537
|
+
function registerCellSelectionOwner(owner, clearSelection) {
|
|
538
|
+
clearByOwner.set(owner, clearSelection);
|
|
539
|
+
return () => {
|
|
540
|
+
clearByOwner.delete(owner);
|
|
541
|
+
if (activeOwner === owner) {
|
|
542
|
+
activeOwner = null;
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function claimCellSelectionOwner(owner) {
|
|
547
|
+
if (activeOwner === owner) return;
|
|
548
|
+
activeOwner = owner;
|
|
549
|
+
for (const [id, clearSelection] of clearByOwner) {
|
|
550
|
+
if (id !== owner) {
|
|
551
|
+
clearSelection();
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function isActiveCellSelectionOwner(owner) {
|
|
556
|
+
return activeOwner === owner;
|
|
557
|
+
}
|
|
558
|
+
function releaseCellSelectionOwner(owner) {
|
|
559
|
+
if (activeOwner === owner) {
|
|
560
|
+
activeOwner = null;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
447
564
|
// src/components/ui/table/features/cell-selection/cellSelection.ts
|
|
448
565
|
var INITIAL_DRAG_STATE = {
|
|
449
566
|
isSelecting: false,
|
|
@@ -921,19 +1038,31 @@ function extractRenderedCopyText(node, value, cellPosition, root) {
|
|
|
921
1038
|
function formatCopyCellText(rowData, columnDef, columnId, visibleRow, fallbackIndex, sourceCell, cellPosition, options) {
|
|
922
1039
|
const meta = columnDef.meta;
|
|
923
1040
|
const value = sourceCell ? sourceCell.getValue() : readRowColumnValue(rowData, columnDef);
|
|
1041
|
+
const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
|
|
1042
|
+
const ctx = {
|
|
1043
|
+
value,
|
|
1044
|
+
row,
|
|
1045
|
+
index: row.index,
|
|
1046
|
+
columnId,
|
|
1047
|
+
cellProps: meta?.cellProps,
|
|
1048
|
+
update: () => {
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
const copyValue = meta?.copyValue;
|
|
1052
|
+
if (typeof copyValue === "function") {
|
|
1053
|
+
try {
|
|
1054
|
+
return sanitizeClipboardCell(copyValue(ctx));
|
|
1055
|
+
} catch {
|
|
1056
|
+
return formatCellValue(value);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
if (copyValue === "value") {
|
|
1060
|
+
return formatCellValue(value);
|
|
1061
|
+
}
|
|
924
1062
|
const cellRender = meta?.cellRender;
|
|
925
1063
|
if (typeof cellRender === "function") {
|
|
926
1064
|
try {
|
|
927
|
-
const
|
|
928
|
-
const node = cellRender({
|
|
929
|
-
value,
|
|
930
|
-
row,
|
|
931
|
-
index: row.index,
|
|
932
|
-
columnId,
|
|
933
|
-
cellProps: meta?.cellProps,
|
|
934
|
-
update: () => {
|
|
935
|
-
}
|
|
936
|
-
});
|
|
1065
|
+
const node = cellRender(ctx);
|
|
937
1066
|
return extractRenderedCopyText(node, value, cellPosition, options?.root);
|
|
938
1067
|
} catch {
|
|
939
1068
|
return formatCellValue(value);
|
|
@@ -941,16 +1070,6 @@ function formatCopyCellText(rowData, columnDef, columnId, visibleRow, fallbackIn
|
|
|
941
1070
|
}
|
|
942
1071
|
if (options?.registry && meta?.kind && isPrimitiveCopyValue(value)) {
|
|
943
1072
|
try {
|
|
944
|
-
const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
|
|
945
|
-
const ctx = {
|
|
946
|
-
value,
|
|
947
|
-
row,
|
|
948
|
-
index: row.index,
|
|
949
|
-
columnId,
|
|
950
|
-
cellProps: meta.cellProps,
|
|
951
|
-
update: () => {
|
|
952
|
-
}
|
|
953
|
-
};
|
|
954
1073
|
const renderer = resolveCellRenderer(options.registry, meta.kind, ctx);
|
|
955
1074
|
if (renderer) {
|
|
956
1075
|
const node = renderer.render(ctx);
|
|
@@ -1076,11 +1195,16 @@ function serializeCopyRowsToTSV(copyRows, visibleRows, bounds, depths, options)
|
|
|
1076
1195
|
const resolvedDepths = depths && depths.length === copyRows.length ? depths : copyRows.map((row) => getRowDepth(row));
|
|
1077
1196
|
const minDepth = Math.min(...resolvedDepths);
|
|
1078
1197
|
const visibleRowByOriginal = buildVisibleRowLookup(visibleRows);
|
|
1198
|
+
const copyableColumns = columnCells.flatMap((templateCell, colOffset) => {
|
|
1199
|
+
const meta = templateCell.column.columnDef.meta;
|
|
1200
|
+
if (meta?.copyValue === "omit") return [];
|
|
1201
|
+
return [{ templateCell, colOffset }];
|
|
1202
|
+
});
|
|
1079
1203
|
return copyRows.map((rowData, index) => {
|
|
1080
1204
|
const relativeDepth = Math.max(0, (resolvedDepths[index] ?? 0) - minDepth);
|
|
1081
1205
|
const visibleRow = visibleRowByOriginal.get(rowData);
|
|
1082
1206
|
const matchingCells = visibleRow?.getVisibleCells().slice(startCol, endCol + 1);
|
|
1083
|
-
const line =
|
|
1207
|
+
const line = copyableColumns.map(({ templateCell, colOffset }) => {
|
|
1084
1208
|
const sourceCell = matchingCells?.[colOffset];
|
|
1085
1209
|
const column = sourceCell?.column ?? templateCell.column;
|
|
1086
1210
|
return formatCopyCellText(
|
|
@@ -1174,90 +1298,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
1174
1298
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
1175
1299
|
}
|
|
1176
1300
|
|
|
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
1301
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1262
1302
|
function useCellSelection({
|
|
1263
1303
|
data,
|
|
@@ -1273,6 +1313,7 @@ function useCellSelection({
|
|
|
1273
1313
|
cellRendererRegistry,
|
|
1274
1314
|
rootRef
|
|
1275
1315
|
}) {
|
|
1316
|
+
const ownerRef = useRef2(createCellSelectionOwner());
|
|
1276
1317
|
const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
|
|
1277
1318
|
const pendingPasteModeRef = useRef2(null);
|
|
1278
1319
|
const dragStateRef = useRef2(dragState);
|
|
@@ -1284,6 +1325,7 @@ function useCellSelection({
|
|
|
1284
1325
|
const handleCellMouseDown = useCallback2(
|
|
1285
1326
|
(rowIndex, colIndex, options) => {
|
|
1286
1327
|
if (!enabled) return;
|
|
1328
|
+
claimCellSelectionOwner(ownerRef.current);
|
|
1287
1329
|
setDragState((prev) => {
|
|
1288
1330
|
if (options?.shiftKey && prev.start) {
|
|
1289
1331
|
return {
|
|
@@ -1325,6 +1367,7 @@ function useCellSelection({
|
|
|
1325
1367
|
const handleFillHandleMouseDown = useCallback2(
|
|
1326
1368
|
(rowIndex, colIndex) => {
|
|
1327
1369
|
if (!enabled) return;
|
|
1370
|
+
claimCellSelectionOwner(ownerRef.current);
|
|
1328
1371
|
setDragState((prev) => {
|
|
1329
1372
|
const bounds = getCellSelectionBounds(prev.start, prev.end);
|
|
1330
1373
|
if (!bounds) return prev;
|
|
@@ -1339,14 +1382,27 @@ function useCellSelection({
|
|
|
1339
1382
|
},
|
|
1340
1383
|
[enabled]
|
|
1341
1384
|
);
|
|
1385
|
+
const clearSelection = useCallback2(() => {
|
|
1386
|
+
const prev = dragStateRef.current;
|
|
1387
|
+
if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
releaseCellSelectionOwner(ownerRef.current);
|
|
1391
|
+
dragStateRef.current = INITIAL_DRAG_STATE;
|
|
1392
|
+
setDragState(INITIAL_DRAG_STATE);
|
|
1393
|
+
}, []);
|
|
1342
1394
|
useEffect2(() => {
|
|
1343
1395
|
if (!enabled) {
|
|
1344
|
-
|
|
1396
|
+
clearSelection();
|
|
1345
1397
|
}
|
|
1346
|
-
}, [enabled]);
|
|
1398
|
+
}, [clearSelection, enabled]);
|
|
1399
|
+
useEffect2(() => {
|
|
1400
|
+
return registerCellSelectionOwner(ownerRef.current, clearSelection);
|
|
1401
|
+
}, [clearSelection]);
|
|
1347
1402
|
useEffect2(() => {
|
|
1348
1403
|
if (!enabled) return;
|
|
1349
1404
|
const handleKeyDown = (e) => {
|
|
1405
|
+
if (!isActiveCellSelectionOwner(ownerRef.current)) return;
|
|
1350
1406
|
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
1351
1407
|
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
1352
1408
|
return;
|
|
@@ -1412,6 +1468,7 @@ function useCellSelection({
|
|
|
1412
1468
|
useEffect2(() => {
|
|
1413
1469
|
if (!enabled) return;
|
|
1414
1470
|
const handleKeyDown = (e) => {
|
|
1471
|
+
if (!isActiveCellSelectionOwner(ownerRef.current)) return;
|
|
1415
1472
|
if (!activeSelectionBounds) return;
|
|
1416
1473
|
if (!(e.ctrlKey || e.metaKey)) return;
|
|
1417
1474
|
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
@@ -1448,6 +1505,7 @@ function useCellSelection({
|
|
|
1448
1505
|
const pasteHandledRef = { current: false };
|
|
1449
1506
|
const ignoreNextPasteRef = { current: false };
|
|
1450
1507
|
const handleKeyDown = (e) => {
|
|
1508
|
+
if (!isActiveCellSelectionOwner(ownerRef.current)) return;
|
|
1451
1509
|
if (!activeSelectionBounds) return;
|
|
1452
1510
|
if (!(e.ctrlKey || e.metaKey)) return;
|
|
1453
1511
|
if (e.key.toLowerCase() !== "v") return;
|
|
@@ -1468,6 +1526,7 @@ function useCellSelection({
|
|
|
1468
1526
|
const text = await navigator.clipboard.readText();
|
|
1469
1527
|
if (pasteHandledRef.current) return;
|
|
1470
1528
|
if (pendingPasteModeRef.current !== mode) return;
|
|
1529
|
+
if (!isActiveCellSelectionOwner(ownerRef.current)) return;
|
|
1471
1530
|
if (!text) return;
|
|
1472
1531
|
pasteHandledRef.current = true;
|
|
1473
1532
|
emitRowsPaste(text, mode);
|
|
@@ -1477,6 +1536,7 @@ function useCellSelection({
|
|
|
1477
1536
|
})();
|
|
1478
1537
|
};
|
|
1479
1538
|
const handlePaste = (e) => {
|
|
1539
|
+
if (!isActiveCellSelectionOwner(ownerRef.current)) return;
|
|
1480
1540
|
if (!activeSelectionBounds) return;
|
|
1481
1541
|
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
1482
1542
|
return;
|
|
@@ -1557,10 +1617,30 @@ function useCellSelection({
|
|
|
1557
1617
|
handleCellMouseDown,
|
|
1558
1618
|
handleCellMouseEnter,
|
|
1559
1619
|
handleFillHandleMouseDown,
|
|
1620
|
+
clearSelection,
|
|
1560
1621
|
copySelection
|
|
1561
1622
|
};
|
|
1562
1623
|
}
|
|
1563
1624
|
|
|
1625
|
+
// src/components/ui/table/features/selection-dismiss/isOutsideDismissTarget.ts
|
|
1626
|
+
var OVERLAY_DISMISS_IGNORE_SELECTOR = [
|
|
1627
|
+
'[role="dialog"]',
|
|
1628
|
+
'[role="alertdialog"]',
|
|
1629
|
+
'[role="menu"]',
|
|
1630
|
+
'[role="listbox"]',
|
|
1631
|
+
'[role="tooltip"]',
|
|
1632
|
+
'[aria-modal="true"]',
|
|
1633
|
+
"[data-radix-portal]",
|
|
1634
|
+
"[data-radix-popper-content-wrapper]",
|
|
1635
|
+
"[data-floating-ui-portal]",
|
|
1636
|
+
"[data-table-ignore-outside-dismiss]"
|
|
1637
|
+
].join(",");
|
|
1638
|
+
function isOverlayDismissIgnoreTarget(target) {
|
|
1639
|
+
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
1640
|
+
if (!element) return false;
|
|
1641
|
+
return element.closest(OVERLAY_DISMISS_IGNORE_SELECTOR) !== null;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1564
1644
|
// src/components/ui/table/features/column-reorder/columnReorder.ts
|
|
1565
1645
|
function getColumnDefId(column) {
|
|
1566
1646
|
if (column.id != null && column.id !== "") return column.id;
|
|
@@ -2847,6 +2927,7 @@ function useGlideTable(options) {
|
|
|
2847
2927
|
handleCellMouseDown,
|
|
2848
2928
|
handleCellMouseEnter,
|
|
2849
2929
|
handleFillHandleMouseDown,
|
|
2930
|
+
clearSelection: clearCellSelection,
|
|
2850
2931
|
copySelection
|
|
2851
2932
|
} = useCellSelection({
|
|
2852
2933
|
data: tableData,
|
|
@@ -2862,6 +2943,37 @@ function useGlideTable(options) {
|
|
|
2862
2943
|
cellRendererRegistry,
|
|
2863
2944
|
rootRef
|
|
2864
2945
|
});
|
|
2946
|
+
const clearRowSelection = useCallback4(() => {
|
|
2947
|
+
if (rowSelectionMode === "none") return;
|
|
2948
|
+
const hasSelection = Object.values(rowSelection).some(Boolean);
|
|
2949
|
+
if (!hasSelection) return;
|
|
2950
|
+
if (onRowSelectionChange) {
|
|
2951
|
+
onRowSelectionChange(() => ({}));
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
setInternalRowSelection({});
|
|
2955
|
+
}, [onRowSelectionChange, rowSelection, rowSelectionMode]);
|
|
2956
|
+
useEffect5(() => {
|
|
2957
|
+
const clearAllSelections = () => {
|
|
2958
|
+
clearCellSelection();
|
|
2959
|
+
clearRowSelection();
|
|
2960
|
+
};
|
|
2961
|
+
const handleKeyDown = (event) => {
|
|
2962
|
+
if (event.key !== "Escape") return;
|
|
2963
|
+
if (event.defaultPrevented) return;
|
|
2964
|
+
if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
if (isOverlayDismissIgnoreTarget(event.target) || isOverlayDismissIgnoreTarget(document.activeElement)) {
|
|
2968
|
+
return;
|
|
2969
|
+
}
|
|
2970
|
+
clearAllSelections();
|
|
2971
|
+
};
|
|
2972
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
2973
|
+
return () => {
|
|
2974
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
2975
|
+
};
|
|
2976
|
+
}, [clearCellSelection, clearRowSelection]);
|
|
2865
2977
|
const {
|
|
2866
2978
|
editingCell,
|
|
2867
2979
|
draftValue,
|
|
@@ -4956,7 +5068,8 @@ function buildColumnDef(props, sort, onSort) {
|
|
|
4956
5068
|
cellProps,
|
|
4957
5069
|
className,
|
|
4958
5070
|
headerClassName,
|
|
4959
|
-
render
|
|
5071
|
+
render,
|
|
5072
|
+
copyValue
|
|
4960
5073
|
} = props;
|
|
4961
5074
|
return {
|
|
4962
5075
|
id: field,
|
|
@@ -4990,6 +5103,7 @@ function buildColumnDef(props, sort, onSort) {
|
|
|
4990
5103
|
kind,
|
|
4991
5104
|
cellProps,
|
|
4992
5105
|
cellRender: render,
|
|
5106
|
+
copyValue,
|
|
4993
5107
|
frozen,
|
|
4994
5108
|
reorderable,
|
|
4995
5109
|
width,
|
|
@@ -177,6 +177,14 @@ declare function resolveDataTableLabels(partial?: Partial<DataTableLabels>): Dat
|
|
|
177
177
|
type RowSelectionMode = "none" | "single" | "multi";
|
|
178
178
|
type CellEditType = "text" | "number";
|
|
179
179
|
type DataTableEditInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "value" | "defaultValue">;
|
|
180
|
+
/**
|
|
181
|
+
* Per-column clipboard serialization.
|
|
182
|
+
* - `"display"`: text extracted from the rendered cell
|
|
183
|
+
* - `"value"`: raw accessor / field value
|
|
184
|
+
* - `"omit"`: exclude this column from clipboard TSV entirely
|
|
185
|
+
* - function: custom clipboard string
|
|
186
|
+
*/
|
|
187
|
+
type ColumnCopyValue<T extends Record<string, unknown> = Record<string, unknown>, V = unknown> = "display" | "value" | "omit" | ((ctx: CellRenderContext<T, V>) => string);
|
|
180
188
|
|
|
181
189
|
declare module "@tanstack/react-table" {
|
|
182
190
|
interface ColumnMeta<TData, TValue> {
|
|
@@ -209,6 +217,14 @@ declare module "@tanstack/react-table" {
|
|
|
209
217
|
cellProps?: Record<string, unknown>;
|
|
210
218
|
/** Compound `Column.render` stored for `ResolvedTableCell` */
|
|
211
219
|
cellRender?: CellRenderFn<Record<string, unknown>>;
|
|
220
|
+
/**
|
|
221
|
+
* Clipboard serialization for this column.
|
|
222
|
+
* - `"display"`: rendered cell text (default when `render` / `kind` is set)
|
|
223
|
+
* - `"value"`: raw accessor / field value
|
|
224
|
+
* - `"omit"`: exclude this column from clipboard TSV entirely
|
|
225
|
+
* - function: custom string for the clipboard
|
|
226
|
+
*/
|
|
227
|
+
copyValue?: ColumnCopyValue;
|
|
212
228
|
/**
|
|
213
229
|
* Freeze (sticky) this column without reordering.
|
|
214
230
|
* `true` / `"left"` stick to the scrollport left; `"right"` to the right.
|
|
@@ -623,6 +639,14 @@ type TableColumnProps<T extends Record<string, unknown>, K extends string = keyo
|
|
|
623
639
|
* Use `update` to commit via `onCellChange` / `onDataChange`.
|
|
624
640
|
*/
|
|
625
641
|
render?: CellRenderFn<T, K extends keyof T ? T[K] : unknown>;
|
|
642
|
+
/**
|
|
643
|
+
* Clipboard serialization for this column.
|
|
644
|
+
* - `"display"`: rendered cell text (default when `render` / `kind` is set)
|
|
645
|
+
* - `"value"`: raw accessor / field value (useful for button cells that still wrap real data)
|
|
646
|
+
* - `"omit"`: exclude this column from clipboard TSV (shifts neighbors; prefer empty string for in-table paste)
|
|
647
|
+
* - function: custom string for the clipboard
|
|
648
|
+
*/
|
|
649
|
+
copyValue?: ColumnCopyValue<T, K extends keyof T ? T[K] : unknown>;
|
|
626
650
|
};
|
|
627
651
|
/** Declares a multi-row header group wrapping leaf `Table.Column`s. */
|
|
628
652
|
type TableColumnGroupProps = {
|
|
@@ -638,4 +662,4 @@ type TableProps<T extends Record<string, unknown>> = Omit<DataTableProps<T>, "co
|
|
|
638
662
|
children: ReactNode;
|
|
639
663
|
};
|
|
640
664
|
|
|
641
|
-
export {
|
|
665
|
+
export { collectAncestorKeysToExpand as A, type BuiltinCellKind as B, type CellKind as C, DEFAULT_DATA_TABLE_LABELS as D, collectSearchMatchesInRange as E, createSearchRegex as F, escapeSearchRegex as G, formatSearchResultLabel as H, INLINE_SEARCH_MAX_RESULTS as I, getColumnFreezeEdgeAttr as J, getColumnFreezeStyle as K, mapSearchResultToVisibleItem as L, mapSearchResultsToVisibleKeys as M, nextSearchIndex as N, nextSearchStride as O, type PasteMode as P, previousSearchIndex as Q, type RowSelectionMode as R, type SearchCorpusRow as S, type TableColumnGroupProps as T, resolveColumnFreezeSide as U, resolveDataTableLabels as V, resolveHeaderFreezeOffset as W, type CellEditType as X, type CellRenderContext as a, type CellRenderFn as b, type CellRenderer as c, type ColumnCopyValue as d, type ColumnFreezeColumnInput as e, type ColumnFreezeEdgeSide as f, type ColumnFreezeMeta as g, type ColumnFreezeOffset as h, type ColumnFreezeSide as i, type DataTableClassNames as j, type DataTableCopyActions as k, type DataTableLabels as l, type DataTableProps as m, type DataTableScrollSlotProps as n, type DataTableSlots as o, type RowsPastePayload as p, type SearchResultItem as q, type SearchStatus as r, type TableColumnProps as s, type TableProps as t, buildColumnFreezeOffsets as u, buildFlatSearchCorpus as v, buildSearchMatchKey as w, buildSearchMatchKeys as x, buildTreeSearchCorpus as y, cellValueToSearchText as z };
|
|
@@ -177,6 +177,14 @@ declare function resolveDataTableLabels(partial?: Partial<DataTableLabels>): Dat
|
|
|
177
177
|
type RowSelectionMode = "none" | "single" | "multi";
|
|
178
178
|
type CellEditType = "text" | "number";
|
|
179
179
|
type DataTableEditInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "value" | "defaultValue">;
|
|
180
|
+
/**
|
|
181
|
+
* Per-column clipboard serialization.
|
|
182
|
+
* - `"display"`: text extracted from the rendered cell
|
|
183
|
+
* - `"value"`: raw accessor / field value
|
|
184
|
+
* - `"omit"`: exclude this column from clipboard TSV entirely
|
|
185
|
+
* - function: custom clipboard string
|
|
186
|
+
*/
|
|
187
|
+
type ColumnCopyValue<T extends Record<string, unknown> = Record<string, unknown>, V = unknown> = "display" | "value" | "omit" | ((ctx: CellRenderContext<T, V>) => string);
|
|
180
188
|
|
|
181
189
|
declare module "@tanstack/react-table" {
|
|
182
190
|
interface ColumnMeta<TData, TValue> {
|
|
@@ -209,6 +217,14 @@ declare module "@tanstack/react-table" {
|
|
|
209
217
|
cellProps?: Record<string, unknown>;
|
|
210
218
|
/** Compound `Column.render` stored for `ResolvedTableCell` */
|
|
211
219
|
cellRender?: CellRenderFn<Record<string, unknown>>;
|
|
220
|
+
/**
|
|
221
|
+
* Clipboard serialization for this column.
|
|
222
|
+
* - `"display"`: rendered cell text (default when `render` / `kind` is set)
|
|
223
|
+
* - `"value"`: raw accessor / field value
|
|
224
|
+
* - `"omit"`: exclude this column from clipboard TSV entirely
|
|
225
|
+
* - function: custom string for the clipboard
|
|
226
|
+
*/
|
|
227
|
+
copyValue?: ColumnCopyValue;
|
|
212
228
|
/**
|
|
213
229
|
* Freeze (sticky) this column without reordering.
|
|
214
230
|
* `true` / `"left"` stick to the scrollport left; `"right"` to the right.
|
|
@@ -623,6 +639,14 @@ type TableColumnProps<T extends Record<string, unknown>, K extends string = keyo
|
|
|
623
639
|
* Use `update` to commit via `onCellChange` / `onDataChange`.
|
|
624
640
|
*/
|
|
625
641
|
render?: CellRenderFn<T, K extends keyof T ? T[K] : unknown>;
|
|
642
|
+
/**
|
|
643
|
+
* Clipboard serialization for this column.
|
|
644
|
+
* - `"display"`: rendered cell text (default when `render` / `kind` is set)
|
|
645
|
+
* - `"value"`: raw accessor / field value (useful for button cells that still wrap real data)
|
|
646
|
+
* - `"omit"`: exclude this column from clipboard TSV (shifts neighbors; prefer empty string for in-table paste)
|
|
647
|
+
* - function: custom string for the clipboard
|
|
648
|
+
*/
|
|
649
|
+
copyValue?: ColumnCopyValue<T, K extends keyof T ? T[K] : unknown>;
|
|
626
650
|
};
|
|
627
651
|
/** Declares a multi-row header group wrapping leaf `Table.Column`s. */
|
|
628
652
|
type TableColumnGroupProps = {
|
|
@@ -638,4 +662,4 @@ type TableProps<T extends Record<string, unknown>> = Omit<DataTableProps<T>, "co
|
|
|
638
662
|
children: ReactNode;
|
|
639
663
|
};
|
|
640
664
|
|
|
641
|
-
export {
|
|
665
|
+
export { collectAncestorKeysToExpand as A, type BuiltinCellKind as B, type CellKind as C, DEFAULT_DATA_TABLE_LABELS as D, collectSearchMatchesInRange as E, createSearchRegex as F, escapeSearchRegex as G, formatSearchResultLabel as H, INLINE_SEARCH_MAX_RESULTS as I, getColumnFreezeEdgeAttr as J, getColumnFreezeStyle as K, mapSearchResultToVisibleItem as L, mapSearchResultsToVisibleKeys as M, nextSearchIndex as N, nextSearchStride as O, type PasteMode as P, previousSearchIndex as Q, type RowSelectionMode as R, type SearchCorpusRow as S, type TableColumnGroupProps as T, resolveColumnFreezeSide as U, resolveDataTableLabels as V, resolveHeaderFreezeOffset as W, type CellEditType as X, type CellRenderContext as a, type CellRenderFn as b, type CellRenderer as c, type ColumnCopyValue as d, type ColumnFreezeColumnInput as e, type ColumnFreezeEdgeSide as f, type ColumnFreezeMeta as g, type ColumnFreezeOffset as h, type ColumnFreezeSide as i, type DataTableClassNames as j, type DataTableCopyActions as k, type DataTableLabels as l, type DataTableProps as m, type DataTableScrollSlotProps as n, type DataTableSlots as o, type RowsPastePayload as p, type SearchResultItem as q, type SearchStatus as r, type TableColumnProps as s, type TableProps as t, buildColumnFreezeOffsets as u, buildFlatSearchCorpus as v, buildSearchMatchKey as w, buildSearchMatchKeys as x, buildTreeSearchCorpus as y, cellValueToSearchText as z };
|