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/compound.cjs
CHANGED
|
@@ -471,15 +471,16 @@ var useConvertTreeData = ({
|
|
|
471
471
|
children: [],
|
|
472
472
|
processed: false
|
|
473
473
|
}));
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
474
|
+
const findNearestPrecedingParent = (index, parentKey) => {
|
|
475
|
+
for (let i = index - 1; i >= 0; i -= 1) {
|
|
476
|
+
const candidate = dataWithLevels[i];
|
|
477
|
+
if (!candidate) continue;
|
|
478
|
+
if (getFieldValue(candidate, toggleField) === parentKey) {
|
|
479
|
+
return candidate;
|
|
480
|
+
}
|
|
480
481
|
}
|
|
481
|
-
|
|
482
|
-
}
|
|
482
|
+
return void 0;
|
|
483
|
+
};
|
|
483
484
|
const rootItems = [];
|
|
484
485
|
dataWithLevels.forEach((item) => {
|
|
485
486
|
if (!getFieldValue(item, childField)) {
|
|
@@ -487,29 +488,18 @@ var useConvertTreeData = ({
|
|
|
487
488
|
item.processed = true;
|
|
488
489
|
}
|
|
489
490
|
});
|
|
490
|
-
dataWithLevels.forEach((item) => {
|
|
491
|
+
dataWithLevels.forEach((item, index) => {
|
|
491
492
|
const parentKey = getFieldValue(item, childField);
|
|
492
493
|
if (!parentKey || item.processed) return;
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
);
|
|
496
|
-
if (parentItems.length > 0) {
|
|
497
|
-
const parent = parentItems[0];
|
|
494
|
+
const parent = findNearestPrecedingParent(index, parentKey);
|
|
495
|
+
if (parent) {
|
|
498
496
|
item.level = parent.level + 1;
|
|
499
497
|
parent.children.push(item);
|
|
500
498
|
item.processed = true;
|
|
501
|
-
|
|
502
|
-
const otherParents = itemMap.get(String(parentKey)) || [];
|
|
503
|
-
if (otherParents.length > 0) {
|
|
504
|
-
const parent = otherParents[0];
|
|
505
|
-
item.level = parent.level + 1;
|
|
506
|
-
parent.children.push(item);
|
|
507
|
-
item.processed = true;
|
|
508
|
-
} else {
|
|
509
|
-
rootItems.push(item);
|
|
510
|
-
item.processed = true;
|
|
511
|
-
}
|
|
499
|
+
return;
|
|
512
500
|
}
|
|
501
|
+
rootItems.push(item);
|
|
502
|
+
item.processed = true;
|
|
513
503
|
});
|
|
514
504
|
return rootItems;
|
|
515
505
|
}, [enabled, data, toggleField, childField, flattenField]);
|
|
@@ -534,16 +524,23 @@ var useConvertTreeData = ({
|
|
|
534
524
|
return result;
|
|
535
525
|
};
|
|
536
526
|
const flattenedData = flatten(processedData, [], 0);
|
|
537
|
-
flattenedData.forEach((item) => {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
(parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
|
|
541
|
-
);
|
|
542
|
-
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
543
|
-
item.parentCount = parentAmount || 1;
|
|
544
|
-
} else {
|
|
527
|
+
flattenedData.forEach((item, index) => {
|
|
528
|
+
const parentKey = getFieldValue(item, childField);
|
|
529
|
+
if (!parentKey) {
|
|
545
530
|
item.parentCount = 1;
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
let parentItem;
|
|
534
|
+
for (let i = index - 1; i >= 0; i -= 1) {
|
|
535
|
+
const candidate = flattenedData[i];
|
|
536
|
+
if (!candidate) continue;
|
|
537
|
+
if (getFieldValue(candidate, toggleField) === parentKey) {
|
|
538
|
+
parentItem = candidate;
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
546
541
|
}
|
|
542
|
+
const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
|
|
543
|
+
item.parentCount = parentAmount || 1;
|
|
547
544
|
});
|
|
548
545
|
return flattenedData;
|
|
549
546
|
}, [
|
|
@@ -815,11 +812,10 @@ function DataTableRow({
|
|
|
815
812
|
const { classNames, rowSpan, selection, cellSelection, cellEdit, expand } = useDataTableRowContext();
|
|
816
813
|
const {
|
|
817
814
|
enableRowSpan,
|
|
818
|
-
|
|
815
|
+
primaryRowSpanColumnId,
|
|
819
816
|
columnRowSpanMap,
|
|
820
817
|
hoveredRowIndex,
|
|
821
|
-
|
|
822
|
-
selectedGroupKeys,
|
|
818
|
+
selectedRowIndices,
|
|
823
819
|
onRowHover
|
|
824
820
|
} = rowSpan;
|
|
825
821
|
const { rowSelectionMode, selectOnRowClick, onRowClick, getRowClassName } = selection;
|
|
@@ -852,9 +848,11 @@ function DataTableRow({
|
|
|
852
848
|
const rowData = row.original;
|
|
853
849
|
const isRowHovered = hoveredRowIndex === rowIndex;
|
|
854
850
|
const isRowSelected = row.getIsSelected();
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
851
|
+
const { startRow: primaryGroupStart, rowSpan: primaryGroupSpan } = resolveRowSpanAt(
|
|
852
|
+
primaryRowSpanColumnId ? columnRowSpanMap.get(primaryRowSpanColumnId) : void 0,
|
|
853
|
+
rowIndex
|
|
854
|
+
);
|
|
855
|
+
const isGroupHovered = enableRowSpan && hoveredRowIndex !== null && hoveredRowIndex >= primaryGroupStart && hoveredRowIndex <= primaryGroupStart + primaryGroupSpan - 1;
|
|
858
856
|
const visibleCells = row.getVisibleCells();
|
|
859
857
|
const columnIdsByIndex = visibleCells.map((cell) => cell.column.id);
|
|
860
858
|
const isVisuallySelectedAt = activeSelectionBounds ? (targetRow, targetCol) => {
|
|
@@ -931,7 +929,16 @@ function DataTableRow({
|
|
|
931
929
|
const cellRowSpan = rowSpanInfo?.rowSpan ?? 1;
|
|
932
930
|
const isMergedCellHovered = hoveredRowIndex !== null && hoveredRowIndex >= rowIndex && hoveredRowIndex <= rowIndex + cellRowSpan - 1;
|
|
933
931
|
const showCellHover = isRowSpanColumn ? isMergedCellHovered : isRowHovered;
|
|
934
|
-
|
|
932
|
+
let isMergedCellSelected = false;
|
|
933
|
+
if (isRowSpanColumn) {
|
|
934
|
+
for (let r = rowIndex; r < rowIndex + cellRowSpan; r += 1) {
|
|
935
|
+
if (selectedRowIndices.has(r)) {
|
|
936
|
+
isMergedCellSelected = true;
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
const showCellSelected = isRowSpanColumn ? isMergedCellSelected : isRowSelected;
|
|
935
942
|
const isMerged = cellRowSpan > 1;
|
|
936
943
|
const showMergedRightEdge = isMerged && (cellIndex === visibleCells.length - 1 || resolveRowSpanAt(
|
|
937
944
|
columnRowSpanMap.get(columnIdsByIndex[cellIndex + 1]),
|
|
@@ -1256,6 +1263,108 @@ function useCellEdit({
|
|
|
1256
1263
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1257
1264
|
var import_react5 = require("react");
|
|
1258
1265
|
|
|
1266
|
+
// src/components/ui/table/features/cell-selection/copyData.ts
|
|
1267
|
+
function formatCellValue(value) {
|
|
1268
|
+
if (value === null || value === void 0) return "";
|
|
1269
|
+
return String(value);
|
|
1270
|
+
}
|
|
1271
|
+
function getNestedValue(row, path) {
|
|
1272
|
+
if (!path.includes(".")) return row[path];
|
|
1273
|
+
return path.split(".").reduce((current, key) => {
|
|
1274
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
return current[key];
|
|
1278
|
+
}, row);
|
|
1279
|
+
}
|
|
1280
|
+
function readRowColumnValue(rowData, columnDef) {
|
|
1281
|
+
if ("accessorFn" in columnDef && typeof columnDef.accessorFn === "function") {
|
|
1282
|
+
return columnDef.accessorFn(rowData, 0);
|
|
1283
|
+
}
|
|
1284
|
+
if ("accessorKey" in columnDef && columnDef.accessorKey != null && columnDef.accessorKey !== "") {
|
|
1285
|
+
return getNestedValue(rowData, String(columnDef.accessorKey));
|
|
1286
|
+
}
|
|
1287
|
+
return void 0;
|
|
1288
|
+
}
|
|
1289
|
+
function hasSubtree(row) {
|
|
1290
|
+
const children = row.children;
|
|
1291
|
+
return Array.isArray(children) && children.length > 0;
|
|
1292
|
+
}
|
|
1293
|
+
function getOriginalRowId(original) {
|
|
1294
|
+
return String(original.id ?? original.uniqueId ?? "");
|
|
1295
|
+
}
|
|
1296
|
+
function getRowDepth(original) {
|
|
1297
|
+
return typeof original.level === "number" ? original.level : 0;
|
|
1298
|
+
}
|
|
1299
|
+
function collectCopyRowEntries(visibleRows, bounds, mode = "visible") {
|
|
1300
|
+
const { startRow, endRow } = bounds;
|
|
1301
|
+
const result = [];
|
|
1302
|
+
const includedOriginalIds = /* @__PURE__ */ new Set();
|
|
1303
|
+
const appendSubtree = (node, depth) => {
|
|
1304
|
+
const children = node.children;
|
|
1305
|
+
if (!Array.isArray(children) || children.length === 0) return;
|
|
1306
|
+
for (const child of children) {
|
|
1307
|
+
const childId = getOriginalRowId(child);
|
|
1308
|
+
if (!(childId && includedOriginalIds.has(childId))) {
|
|
1309
|
+
result.push({ row: child, depth });
|
|
1310
|
+
if (childId) includedOriginalIds.add(childId);
|
|
1311
|
+
}
|
|
1312
|
+
appendSubtree(child, depth + 1);
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
for (let rowIndex = startRow; rowIndex <= endRow; rowIndex += 1) {
|
|
1316
|
+
const row = visibleRows[rowIndex];
|
|
1317
|
+
if (!row) continue;
|
|
1318
|
+
const originalId = getOriginalRowId(row.original);
|
|
1319
|
+
if (originalId && includedOriginalIds.has(originalId)) continue;
|
|
1320
|
+
const depth = getRowDepth(row.original);
|
|
1321
|
+
result.push({ row: row.original, depth });
|
|
1322
|
+
if (originalId) includedOriginalIds.add(originalId);
|
|
1323
|
+
if (mode !== "subtree" || !hasSubtree(row.original)) continue;
|
|
1324
|
+
appendSubtree(row.original, depth + 1);
|
|
1325
|
+
}
|
|
1326
|
+
return result;
|
|
1327
|
+
}
|
|
1328
|
+
function serializeCopyRowsToTSV(copyRows, visibleRows, bounds, depths) {
|
|
1329
|
+
if (copyRows.length === 0) return "";
|
|
1330
|
+
const { startCol, endCol } = bounds;
|
|
1331
|
+
const columnCells = visibleRows[0]?.getVisibleCells().slice(startCol, endCol + 1) ?? [];
|
|
1332
|
+
if (columnCells.length === 0) return "";
|
|
1333
|
+
const resolvedDepths = depths && depths.length === copyRows.length ? depths : copyRows.map((row) => getRowDepth(row));
|
|
1334
|
+
const minDepth = Math.min(...resolvedDepths);
|
|
1335
|
+
return copyRows.map((rowData, index) => {
|
|
1336
|
+
const relativeDepth = Math.max(0, (resolvedDepths[index] ?? 0) - minDepth);
|
|
1337
|
+
const line = columnCells.map(
|
|
1338
|
+
(cell) => formatCellValue(
|
|
1339
|
+
readRowColumnValue(
|
|
1340
|
+
rowData,
|
|
1341
|
+
cell.column.columnDef
|
|
1342
|
+
)
|
|
1343
|
+
)
|
|
1344
|
+
).join(" ");
|
|
1345
|
+
return `${" ".repeat(relativeDepth)}${line}`;
|
|
1346
|
+
}).join("\n");
|
|
1347
|
+
}
|
|
1348
|
+
function serializeSelectionToTSV(visibleRows, bounds, mode = "visible") {
|
|
1349
|
+
const entries = collectCopyRowEntries(visibleRows, bounds, mode);
|
|
1350
|
+
return serializeCopyRowsToTSV(
|
|
1351
|
+
entries.map((entry) => entry.row),
|
|
1352
|
+
visibleRows,
|
|
1353
|
+
bounds,
|
|
1354
|
+
entries.map((entry) => entry.depth)
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
async function writeSelectionToClipboard(visibleRows, bounds, mode = "visible") {
|
|
1358
|
+
const text = serializeSelectionToTSV(visibleRows, bounds, mode);
|
|
1359
|
+
if (!text) return false;
|
|
1360
|
+
try {
|
|
1361
|
+
await navigator.clipboard.writeText(text);
|
|
1362
|
+
} catch {
|
|
1363
|
+
return false;
|
|
1364
|
+
}
|
|
1365
|
+
return true;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1259
1368
|
// src/components/ui/table/features/cell-selection/fillData.ts
|
|
1260
1369
|
function getColumnAccessorKey2(columnDef) {
|
|
1261
1370
|
if ("accessorKey" in columnDef && columnDef.accessorKey) {
|
|
@@ -1312,15 +1421,100 @@ function hasFillExtension(sourceBounds, fillBounds) {
|
|
|
1312
1421
|
return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
|
|
1313
1422
|
}
|
|
1314
1423
|
|
|
1424
|
+
// src/components/ui/table/features/cell-selection/pasteData.ts
|
|
1425
|
+
function countLeadingEmptyCells(cells) {
|
|
1426
|
+
let depth = 0;
|
|
1427
|
+
while (depth < cells.length && cells[depth] === "") {
|
|
1428
|
+
depth += 1;
|
|
1429
|
+
}
|
|
1430
|
+
return depth;
|
|
1431
|
+
}
|
|
1432
|
+
function looksLikeSubtreeIndentation(leadingEmptyCounts) {
|
|
1433
|
+
if (leadingEmptyCounts.length === 0) return false;
|
|
1434
|
+
const firstDepth = leadingEmptyCounts[0] ?? 0;
|
|
1435
|
+
if (firstDepth !== 0) return false;
|
|
1436
|
+
return leadingEmptyCounts.some((depth) => depth > 0);
|
|
1437
|
+
}
|
|
1438
|
+
function parseClipboardTSVWithDepths(text) {
|
|
1439
|
+
if (!text) return { values: [], depths: [] };
|
|
1440
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1441
|
+
const withoutTrailing = normalized.replace(/\n+$/, "");
|
|
1442
|
+
if (!withoutTrailing) return { values: [], depths: [] };
|
|
1443
|
+
const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
|
|
1444
|
+
const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
|
|
1445
|
+
const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
|
|
1446
|
+
const values = [];
|
|
1447
|
+
const depths = [];
|
|
1448
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
1449
|
+
const cells = rows[index] ?? [];
|
|
1450
|
+
const depth = leadingEmptyCounts[index] ?? 0;
|
|
1451
|
+
if (treatAsDepth) {
|
|
1452
|
+
values.push(cells.slice(depth));
|
|
1453
|
+
depths.push(depth);
|
|
1454
|
+
} else {
|
|
1455
|
+
values.push(cells);
|
|
1456
|
+
depths.push(0);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return { values, depths };
|
|
1460
|
+
}
|
|
1461
|
+
function resolvePasteColumnIds(rows, startCol, width) {
|
|
1462
|
+
if (width <= 0) return [];
|
|
1463
|
+
const cells = rows[0]?.getVisibleCells() ?? [];
|
|
1464
|
+
const columnIds = [];
|
|
1465
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
1466
|
+
const cell = cells[startCol + offset];
|
|
1467
|
+
if (!cell) break;
|
|
1468
|
+
columnIds.push(cell.column.id);
|
|
1469
|
+
}
|
|
1470
|
+
return columnIds;
|
|
1471
|
+
}
|
|
1472
|
+
function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
|
|
1473
|
+
const { values, depths } = parseClipboardTSVWithDepths(text);
|
|
1474
|
+
if (values.length === 0) return null;
|
|
1475
|
+
const width = Math.max(...values.map((row) => row.length), 0);
|
|
1476
|
+
if (width === 0) return null;
|
|
1477
|
+
const columnIds = resolvePasteColumnIds(rows, startCol, width);
|
|
1478
|
+
if (columnIds.length === 0) return null;
|
|
1479
|
+
const rowIds = [];
|
|
1480
|
+
for (let offset = 0; offset < values.length; offset += 1) {
|
|
1481
|
+
const row = rows[startRow + offset];
|
|
1482
|
+
if (!row) break;
|
|
1483
|
+
rowIds.push(row.id);
|
|
1484
|
+
}
|
|
1485
|
+
const anchorRow = rows[endRow] ?? rows[startRow];
|
|
1486
|
+
return {
|
|
1487
|
+
mode,
|
|
1488
|
+
startRow,
|
|
1489
|
+
startCol,
|
|
1490
|
+
endRow,
|
|
1491
|
+
rowIds,
|
|
1492
|
+
anchorRowId: anchorRow?.id ?? "",
|
|
1493
|
+
columnIds,
|
|
1494
|
+
values,
|
|
1495
|
+
depths
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
function isEditablePasteTarget(target) {
|
|
1499
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
1500
|
+
const tag = target.tagName;
|
|
1501
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
1502
|
+
return Boolean(target.isContentEditable);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1315
1505
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
1316
1506
|
function useCellSelection({
|
|
1317
1507
|
data,
|
|
1318
1508
|
rows,
|
|
1319
1509
|
enabled = true,
|
|
1510
|
+
enableSubtreeCopy = false,
|
|
1511
|
+
enableInsertPaste = true,
|
|
1320
1512
|
onDataChange,
|
|
1321
|
-
onBatchChange
|
|
1513
|
+
onBatchChange,
|
|
1514
|
+
onRowsPaste
|
|
1322
1515
|
}) {
|
|
1323
1516
|
const [dragState, setDragState] = (0, import_react5.useState)(INITIAL_DRAG_STATE);
|
|
1517
|
+
const pendingPasteModeRef = (0, import_react5.useRef)(null);
|
|
1324
1518
|
const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
|
|
1325
1519
|
const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
|
|
1326
1520
|
const handleCellMouseDown = (0, import_react5.useCallback)(
|
|
@@ -1374,21 +1568,113 @@ function useCellSelection({
|
|
|
1374
1568
|
setDragState(INITIAL_DRAG_STATE);
|
|
1375
1569
|
}
|
|
1376
1570
|
}, [enabled]);
|
|
1571
|
+
const copySelection = (0, import_react5.useCallback)(
|
|
1572
|
+
async (options) => {
|
|
1573
|
+
if (!enabled || !activeSelectionBounds) return false;
|
|
1574
|
+
const mode = options?.includeDescendants && enableSubtreeCopy ? "subtree" : "visible";
|
|
1575
|
+
return writeSelectionToClipboard(rows, activeSelectionBounds, mode);
|
|
1576
|
+
},
|
|
1577
|
+
[activeSelectionBounds, enableSubtreeCopy, enabled, rows]
|
|
1578
|
+
);
|
|
1377
1579
|
(0, import_react5.useEffect)(() => {
|
|
1378
1580
|
if (!enabled) return;
|
|
1379
1581
|
const handleKeyDown = (e) => {
|
|
1380
|
-
if (
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
}
|
|
1582
|
+
if (!activeSelectionBounds) return;
|
|
1583
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
1584
|
+
const isSubtreeShortcut = enableSubtreeCopy && e.shiftKey && e.key.toLowerCase() === "c";
|
|
1585
|
+
const isVisibleCopyShortcut = !e.shiftKey && e.key.toLowerCase() === "c";
|
|
1586
|
+
if (!isSubtreeShortcut && !isVisibleCopyShortcut) return;
|
|
1587
|
+
e.preventDefault();
|
|
1588
|
+
void copySelection({ includeDescendants: isSubtreeShortcut });
|
|
1388
1589
|
};
|
|
1389
1590
|
window.addEventListener("keydown", handleKeyDown);
|
|
1390
1591
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1391
|
-
}, [activeSelectionBounds,
|
|
1592
|
+
}, [activeSelectionBounds, copySelection, enableSubtreeCopy, enabled]);
|
|
1593
|
+
const emitRowsPaste = (0, import_react5.useCallback)(
|
|
1594
|
+
(text, mode) => {
|
|
1595
|
+
if (!onRowsPaste || !activeSelectionBounds) return false;
|
|
1596
|
+
const payload = buildRowsPastePayload(
|
|
1597
|
+
rows,
|
|
1598
|
+
activeSelectionBounds.startRow,
|
|
1599
|
+
activeSelectionBounds.startCol,
|
|
1600
|
+
text,
|
|
1601
|
+
mode,
|
|
1602
|
+
activeSelectionBounds.endRow
|
|
1603
|
+
);
|
|
1604
|
+
if (!payload) return false;
|
|
1605
|
+
onRowsPaste(payload);
|
|
1606
|
+
return true;
|
|
1607
|
+
},
|
|
1608
|
+
[activeSelectionBounds, onRowsPaste, rows]
|
|
1609
|
+
);
|
|
1610
|
+
(0, import_react5.useEffect)(() => {
|
|
1611
|
+
if (!enabled || !onRowsPaste) return;
|
|
1612
|
+
const pasteHandledRef = { current: false };
|
|
1613
|
+
const ignoreNextPasteRef = { current: false };
|
|
1614
|
+
const handleKeyDown = (e) => {
|
|
1615
|
+
if (!activeSelectionBounds) return;
|
|
1616
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
1617
|
+
if (e.key.toLowerCase() !== "v") return;
|
|
1618
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
if (e.shiftKey && !enableInsertPaste) {
|
|
1622
|
+
ignoreNextPasteRef.current = true;
|
|
1623
|
+
pendingPasteModeRef.current = null;
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
const mode = e.shiftKey ? "insert" : "overwrite";
|
|
1627
|
+
pasteHandledRef.current = false;
|
|
1628
|
+
ignoreNextPasteRef.current = false;
|
|
1629
|
+
pendingPasteModeRef.current = mode;
|
|
1630
|
+
void (async () => {
|
|
1631
|
+
try {
|
|
1632
|
+
const text = await navigator.clipboard.readText();
|
|
1633
|
+
if (pasteHandledRef.current) return;
|
|
1634
|
+
if (pendingPasteModeRef.current !== mode) return;
|
|
1635
|
+
if (!text) return;
|
|
1636
|
+
pasteHandledRef.current = true;
|
|
1637
|
+
emitRowsPaste(text, mode);
|
|
1638
|
+
pendingPasteModeRef.current = null;
|
|
1639
|
+
} catch {
|
|
1640
|
+
}
|
|
1641
|
+
})();
|
|
1642
|
+
};
|
|
1643
|
+
const handlePaste = (e) => {
|
|
1644
|
+
if (!activeSelectionBounds) return;
|
|
1645
|
+
if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
if (ignoreNextPasteRef.current) {
|
|
1649
|
+
ignoreNextPasteRef.current = false;
|
|
1650
|
+
pendingPasteModeRef.current = null;
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
const mode = pendingPasteModeRef.current ?? "overwrite";
|
|
1654
|
+
if (pasteHandledRef.current) {
|
|
1655
|
+
e.preventDefault();
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
const text = e.clipboardData?.getData("text/plain");
|
|
1659
|
+
if (text == null || text === "") return;
|
|
1660
|
+
pasteHandledRef.current = true;
|
|
1661
|
+
e.preventDefault();
|
|
1662
|
+
emitRowsPaste(text, mode);
|
|
1663
|
+
pendingPasteModeRef.current = null;
|
|
1664
|
+
};
|
|
1665
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
1666
|
+
window.addEventListener("paste", handlePaste);
|
|
1667
|
+
return () => {
|
|
1668
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
1669
|
+
window.removeEventListener("paste", handlePaste);
|
|
1670
|
+
};
|
|
1671
|
+
}, [
|
|
1672
|
+
activeSelectionBounds,
|
|
1673
|
+
emitRowsPaste,
|
|
1674
|
+
enableInsertPaste,
|
|
1675
|
+
enabled,
|
|
1676
|
+
onRowsPaste
|
|
1677
|
+
]);
|
|
1392
1678
|
(0, import_react5.useEffect)(() => {
|
|
1393
1679
|
if (!enabled) return;
|
|
1394
1680
|
const handleMouseUp = () => {
|
|
@@ -1434,7 +1720,8 @@ function useCellSelection({
|
|
|
1434
1720
|
activeSelectionBounds,
|
|
1435
1721
|
handleCellMouseDown,
|
|
1436
1722
|
handleCellMouseEnter,
|
|
1437
|
-
handleFillHandleMouseDown
|
|
1723
|
+
handleFillHandleMouseDown,
|
|
1724
|
+
copySelection
|
|
1438
1725
|
};
|
|
1439
1726
|
}
|
|
1440
1727
|
|
|
@@ -1498,6 +1785,10 @@ function useGlideTable(options) {
|
|
|
1498
1785
|
expandedRows: controlledExpandedRows,
|
|
1499
1786
|
onExpandedRowsChange,
|
|
1500
1787
|
preventExpand = false,
|
|
1788
|
+
enableSubtreeCopy,
|
|
1789
|
+
onCopyActionsReady,
|
|
1790
|
+
onRowsPaste,
|
|
1791
|
+
enableInsertPaste,
|
|
1501
1792
|
enableVirtualization = true,
|
|
1502
1793
|
estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
|
|
1503
1794
|
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
|
|
@@ -1512,12 +1803,12 @@ function useGlideTable(options) {
|
|
|
1512
1803
|
};
|
|
1513
1804
|
}, [labelsProp, emptyText, loadingText, selectionLabel]);
|
|
1514
1805
|
const enableExpand = Boolean(toggleField);
|
|
1806
|
+
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
1515
1807
|
const [internalRowSelection, setInternalRowSelection] = (0, import_react6.useState)({});
|
|
1516
1808
|
const [internalExpandedRows, setInternalExpandedRows] = (0, import_react6.useState)(
|
|
1517
1809
|
() => /* @__PURE__ */ new Set()
|
|
1518
1810
|
);
|
|
1519
1811
|
const [hoveredRowIndex, setHoveredRowIndex] = (0, import_react6.useState)(null);
|
|
1520
|
-
const [hoveredGroupKey, setHoveredGroupKey] = (0, import_react6.useState)(null);
|
|
1521
1812
|
const scrollRef = (0, import_react6.useRef)(null);
|
|
1522
1813
|
const shouldVirtualize = enableVirtualization && !enableRowSpan;
|
|
1523
1814
|
(0, import_react6.useEffect)(() => {
|
|
@@ -1581,6 +1872,7 @@ function useGlideTable(options) {
|
|
|
1581
1872
|
return collectRowSpanColumns(columns);
|
|
1582
1873
|
}, [enableRowSpan, columns]);
|
|
1583
1874
|
const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
|
|
1875
|
+
const primaryRowSpanColumnId = rowSpanColumnKeys[0]?.columnId;
|
|
1584
1876
|
const columnRowSpanMap = (0, import_react6.useMemo)(
|
|
1585
1877
|
() => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
|
|
1586
1878
|
[tableData, rowSpanColumnKeys]
|
|
@@ -1599,27 +1891,29 @@ function useGlideTable(options) {
|
|
|
1599
1891
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
1600
1892
|
const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
|
|
1601
1893
|
const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1604
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1894
|
+
const selectedRowIndices = (0, import_react6.useMemo)(() => {
|
|
1895
|
+
const indices = /* @__PURE__ */ new Set();
|
|
1605
1896
|
for (const selectedRow of selectedRows) {
|
|
1606
|
-
|
|
1607
|
-
if (value !== null && value !== void 0) keys.add(String(value));
|
|
1897
|
+
indices.add(selectedRow.index);
|
|
1608
1898
|
}
|
|
1609
|
-
return
|
|
1610
|
-
}, [
|
|
1899
|
+
return indices;
|
|
1900
|
+
}, [selectedRows]);
|
|
1611
1901
|
const {
|
|
1612
1902
|
dragState,
|
|
1613
1903
|
activeSelectionBounds,
|
|
1614
1904
|
handleCellMouseDown,
|
|
1615
1905
|
handleCellMouseEnter,
|
|
1616
|
-
handleFillHandleMouseDown
|
|
1906
|
+
handleFillHandleMouseDown,
|
|
1907
|
+
copySelection
|
|
1617
1908
|
} = useCellSelection({
|
|
1618
1909
|
data: tableData,
|
|
1619
1910
|
rows,
|
|
1620
1911
|
enabled: enableCellSelection,
|
|
1912
|
+
enableSubtreeCopy: resolvedEnableSubtreeCopy,
|
|
1913
|
+
enableInsertPaste: enableInsertPaste ?? true,
|
|
1621
1914
|
onDataChange,
|
|
1622
|
-
onBatchChange
|
|
1915
|
+
onBatchChange,
|
|
1916
|
+
onRowsPaste
|
|
1623
1917
|
});
|
|
1624
1918
|
const {
|
|
1625
1919
|
editingCell,
|
|
@@ -1641,22 +1935,10 @@ function useGlideTable(options) {
|
|
|
1641
1935
|
);
|
|
1642
1936
|
const clearHover = (0, import_react6.useCallback)(() => {
|
|
1643
1937
|
setHoveredRowIndex(null);
|
|
1644
|
-
setHoveredGroupKey(null);
|
|
1645
1938
|
}, []);
|
|
1646
|
-
const handleRowHover = (0, import_react6.useCallback)(
|
|
1647
|
-
(rowIndex
|
|
1648
|
-
|
|
1649
|
-
if (!primaryRowSpanKey) {
|
|
1650
|
-
setHoveredGroupKey(null);
|
|
1651
|
-
return;
|
|
1652
|
-
}
|
|
1653
|
-
const groupValue = rowData[primaryRowSpanKey];
|
|
1654
|
-
setHoveredGroupKey(
|
|
1655
|
-
groupValue === null || groupValue === void 0 ? null : String(groupValue)
|
|
1656
|
-
);
|
|
1657
|
-
},
|
|
1658
|
-
[primaryRowSpanKey]
|
|
1659
|
-
);
|
|
1939
|
+
const handleRowHover = (0, import_react6.useCallback)((rowIndex, _rowData) => {
|
|
1940
|
+
setHoveredRowIndex(rowIndex);
|
|
1941
|
+
}, []);
|
|
1660
1942
|
const handleToggleSelect = (0, import_react6.useCallback)(
|
|
1661
1943
|
(row) => {
|
|
1662
1944
|
if (!row.getCanSelect()) return;
|
|
@@ -1679,10 +1961,10 @@ function useGlideTable(options) {
|
|
|
1679
1961
|
rowSpan: {
|
|
1680
1962
|
enableRowSpan,
|
|
1681
1963
|
primaryRowSpanKey,
|
|
1964
|
+
primaryRowSpanColumnId,
|
|
1682
1965
|
columnRowSpanMap,
|
|
1683
1966
|
hoveredRowIndex,
|
|
1684
|
-
|
|
1685
|
-
selectedGroupKeys,
|
|
1967
|
+
selectedRowIndices,
|
|
1686
1968
|
onRowHover: handleRowHover
|
|
1687
1969
|
},
|
|
1688
1970
|
selection: {
|
|
@@ -1720,10 +2002,10 @@ function useGlideTable(options) {
|
|
|
1720
2002
|
}, [
|
|
1721
2003
|
enableRowSpan,
|
|
1722
2004
|
primaryRowSpanKey,
|
|
2005
|
+
primaryRowSpanColumnId,
|
|
1723
2006
|
columnRowSpanMap,
|
|
1724
2007
|
hoveredRowIndex,
|
|
1725
|
-
|
|
1726
|
-
selectedGroupKeys,
|
|
2008
|
+
selectedRowIndices,
|
|
1727
2009
|
handleRowHover,
|
|
1728
2010
|
rowSelectionMode,
|
|
1729
2011
|
selectOnRowClick,
|
|
@@ -1749,6 +2031,14 @@ function useGlideTable(options) {
|
|
|
1749
2031
|
labels.expandRow,
|
|
1750
2032
|
labels.collapseRow
|
|
1751
2033
|
]);
|
|
2034
|
+
const copySelectionRef = (0, import_react6.useRef)(copySelection);
|
|
2035
|
+
(0, import_react6.useEffect)(() => {
|
|
2036
|
+
copySelectionRef.current = copySelection;
|
|
2037
|
+
}, [copySelection]);
|
|
2038
|
+
const stableCopySelection = (0, import_react6.useCallback)((options2) => copySelectionRef.current(options2), []);
|
|
2039
|
+
(0, import_react6.useEffect)(() => {
|
|
2040
|
+
onCopyActionsReady?.({ copySelection: stableCopySelection });
|
|
2041
|
+
}, [onCopyActionsReady, stableCopySelection]);
|
|
1752
2042
|
return {
|
|
1753
2043
|
table,
|
|
1754
2044
|
tableData,
|
|
@@ -1768,7 +2058,8 @@ function useGlideTable(options) {
|
|
|
1768
2058
|
paddingBottom,
|
|
1769
2059
|
rowContextValue,
|
|
1770
2060
|
handleToggleSelect,
|
|
1771
|
-
clearHover
|
|
2061
|
+
clearHover,
|
|
2062
|
+
copySelection: stableCopySelection
|
|
1772
2063
|
};
|
|
1773
2064
|
}
|
|
1774
2065
|
|
|
@@ -1894,7 +2185,12 @@ function DataTable({
|
|
|
1894
2185
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1895
2186
|
"th",
|
|
1896
2187
|
{
|
|
1897
|
-
style: {
|
|
2188
|
+
style: {
|
|
2189
|
+
width: header.getSize() !== 150 ? header.getSize() : void 0,
|
|
2190
|
+
// Column sizing follows TanStack's `size`, but
|
|
2191
|
+
// ensure the column keeps its min width when the container shrinks.
|
|
2192
|
+
minWidth: header.getSize() !== 150 ? header.getSize() : void 0
|
|
2193
|
+
},
|
|
1898
2194
|
className: cn(
|
|
1899
2195
|
"data-table-head-cell",
|
|
1900
2196
|
CELL_ALIGN_CLASS[align],
|
package/dist/compound.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
export { a as DataTableClassNames,
|
|
3
|
+
import { d as DataTableProps, T as TableColumnProps, g as TableProps } from './types-DOLnknDe.cjs';
|
|
4
|
+
export { a as DataTableClassNames, c as DataTableLabels, e as DataTableSlots, P as PasteMode, R as RowSelectionMode, f as RowsPastePayload } from './types-DOLnknDe.cjs';
|
|
5
5
|
export { ColumnDef, RowSelectionState } from '@tanstack/react-table';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/compound.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
export { a as DataTableClassNames,
|
|
3
|
+
import { d as DataTableProps, T as TableColumnProps, g as TableProps } from './types-DOLnknDe.js';
|
|
4
|
+
export { a as DataTableClassNames, c as DataTableLabels, e as DataTableSlots, P as PasteMode, R as RowSelectionMode, f as RowsPastePayload } from './types-DOLnknDe.js';
|
|
5
5
|
export { ColumnDef, RowSelectionState } from '@tanstack/react-table';
|
|
6
6
|
|
|
7
7
|
/**
|