@lensui/lens-table 0.1.3 → 0.1.4
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 +28 -2
- package/dist/index.cjs +784 -176
- package/dist/index.css +109 -2
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +784 -176
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -863,6 +863,8 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
863
863
|
}
|
|
864
864
|
function paintGrid(options) {
|
|
865
865
|
const { context: ctx, width, height, pixelRatio, scrollLeft, scrollTop, rowHeight, headerHeight, fixedHeader, verticalBorderless, striped, columnDraggable, sortState, filterValues, hoveredHeaderAction, rows, columns, metrics, range, selection, editing, hoveredRowIndex, selectionRange, selectedRowKeys, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview } = options;
|
|
866
|
+
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
867
|
+
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
866
868
|
const colors = { ...COLORS, ...options.colors };
|
|
867
869
|
const bodyTop = options.bodyTop ?? headerHeight;
|
|
868
870
|
const getCellSpan = (rowIndex, columnIndex) => options.cellSpans.get(getCellCoordKey(rowIndex, columnIndex));
|
|
@@ -879,9 +881,16 @@ function paintGrid(options) {
|
|
|
879
881
|
ctx.fillRect(0, 0, width, height);
|
|
880
882
|
ctx.font = "13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
881
883
|
ctx.textBaseline = "middle";
|
|
882
|
-
const leftFixedWidth = columns.reduce((value, column, index) => column.fixed === "left" ?
|
|
884
|
+
const leftFixedWidth = columns.reduce((value, column, index) => column.fixed === "left" ? value + metrics[index].width : value, 0);
|
|
883
885
|
const rightFixedWidth = columns.reduce((value, column, index) => column.fixed === "right" ? value + metrics[index].width : value, 0);
|
|
884
886
|
const rightFixedLeft = width - rightFixedWidth;
|
|
887
|
+
const leftOffsets = /* @__PURE__ */ new Map();
|
|
888
|
+
let leftOffset = 0;
|
|
889
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
890
|
+
if (columns[index].fixed !== "left") continue;
|
|
891
|
+
leftOffsets.set(index, leftOffset);
|
|
892
|
+
leftOffset += metrics[index].width;
|
|
893
|
+
}
|
|
885
894
|
const rightOffsets = /* @__PURE__ */ new Map();
|
|
886
895
|
let rightOffset = 0;
|
|
887
896
|
for (let index = columns.length - 1; index >= 0; index -= 1) {
|
|
@@ -889,8 +898,14 @@ function paintGrid(options) {
|
|
|
889
898
|
rightOffsets.set(index, rightOffset);
|
|
890
899
|
rightOffset += metrics[index].width;
|
|
891
900
|
}
|
|
901
|
+
const scrollableLefts = /* @__PURE__ */ new Map();
|
|
902
|
+
let scrollableLeft = leftFixedWidth;
|
|
903
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
904
|
+
scrollableLefts.set(index, scrollableLeft);
|
|
905
|
+
if (columns[index].fixed === void 0) scrollableLeft += metrics[index].width;
|
|
906
|
+
}
|
|
892
907
|
const getColumnX = (index) => {
|
|
893
|
-
return columns[index].fixed === "left" ?
|
|
908
|
+
return columns[index].fixed === "left" ? leftOffsets.get(index) ?? 0 : columns[index].fixed === "right" ? width - (rightOffsets.get(index) ?? 0) - metrics[index].width : (scrollableLefts.get(index) ?? leftFixedWidth) - scrollLeft;
|
|
894
909
|
};
|
|
895
910
|
const paintBodyColumns = (layer) => {
|
|
896
911
|
const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
|
|
@@ -1040,7 +1055,7 @@ function paintGrid(options) {
|
|
|
1040
1055
|
if (!verticalBorderless) ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1041
1056
|
ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
1042
1057
|
const column = columns[columnIndex];
|
|
1043
|
-
if (!column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1058
|
+
if (headerLeafTop === 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1044
1059
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1045
1060
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1046
1061
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
@@ -1057,11 +1072,11 @@ function paintGrid(options) {
|
|
|
1057
1072
|
const textX = titleAlign === "right" ? x + contentWidth - padding : titleAlign === "center" ? x + centeredTextX : x + padding;
|
|
1058
1073
|
ctx.save();
|
|
1059
1074
|
ctx.beginPath();
|
|
1060
|
-
ctx.rect(x + 2, headerY + 1, Math.max(0, clipWidth - 4),
|
|
1075
|
+
ctx.rect(x + 2, headerY + headerLeafTop + 1, Math.max(0, clipWidth - 4), headerLeafHeight - 2);
|
|
1061
1076
|
ctx.clip();
|
|
1062
1077
|
ctx.fillStyle = colors.muted;
|
|
1063
1078
|
ctx.textAlign = titleAlign === "right" ? "right" : titleAlign === "center" ? "center" : "left";
|
|
1064
|
-
ctx.fillText(title, textX, headerY +
|
|
1079
|
+
ctx.fillText(title, textX, headerY + headerLeafTop + headerLeafHeight / 2);
|
|
1065
1080
|
ctx.restore();
|
|
1066
1081
|
}
|
|
1067
1082
|
}
|
|
@@ -1069,22 +1084,6 @@ function paintGrid(options) {
|
|
|
1069
1084
|
paintHeaderColumns("scroll");
|
|
1070
1085
|
paintHeaderColumns("left");
|
|
1071
1086
|
paintHeaderColumns("right");
|
|
1072
|
-
if (leftFixedWidth > 0 && scrollLeft > 0) {
|
|
1073
|
-
const shadowWidth = 10;
|
|
1074
|
-
const shadow = ctx.createLinearGradient(leftFixedWidth, 0, leftFixedWidth + shadowWidth, 0);
|
|
1075
|
-
shadow.addColorStop(0, "rgba(5, 5, 5, 0.06)");
|
|
1076
|
-
shadow.addColorStop(1, "rgba(5, 5, 5, 0)");
|
|
1077
|
-
ctx.fillStyle = shadow;
|
|
1078
|
-
ctx.fillRect(leftFixedWidth, 0, shadowWidth, height);
|
|
1079
|
-
}
|
|
1080
|
-
if (rightFixedWidth > 0 && scrollLeft < (metrics[metrics.length - 1]?.right ?? 0) - width) {
|
|
1081
|
-
const shadowWidth = 10;
|
|
1082
|
-
const shadow = ctx.createLinearGradient(rightFixedLeft - shadowWidth, 0, rightFixedLeft, 0);
|
|
1083
|
-
shadow.addColorStop(0, "rgba(5, 5, 5, 0)");
|
|
1084
|
-
shadow.addColorStop(1, "rgba(5, 5, 5, 0.06)");
|
|
1085
|
-
ctx.fillStyle = shadow;
|
|
1086
|
-
ctx.fillRect(rightFixedLeft - shadowWidth, 0, shadowWidth, height);
|
|
1087
|
-
}
|
|
1088
1087
|
if (rightFixedWidth > 0 && !verticalBorderless) {
|
|
1089
1088
|
ctx.fillStyle = colors.grid;
|
|
1090
1089
|
ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
|
|
@@ -1236,6 +1235,45 @@ var getRowNumberColumnWidth = (rowCount) => {
|
|
|
1236
1235
|
const digits = String(Math.max(1, rowCount)).length;
|
|
1237
1236
|
return digits <= 4 ? 44 : 44 + (digits - 4) * 8;
|
|
1238
1237
|
};
|
|
1238
|
+
function getColumnDepth(column) {
|
|
1239
|
+
if (!column.children?.length) return 1;
|
|
1240
|
+
return 1 + Math.max(...column.children.map(getColumnDepth));
|
|
1241
|
+
}
|
|
1242
|
+
function flattenDataColumns(columns, inheritedFixed, insideGroup = false) {
|
|
1243
|
+
return columns.flatMap((column) => {
|
|
1244
|
+
if (!column.children?.length) {
|
|
1245
|
+
return insideGroup ? [{ ...column, fixed: inheritedFixed }] : [column];
|
|
1246
|
+
}
|
|
1247
|
+
return flattenDataColumns(column.children, column.fixed ?? inheritedFixed, true);
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
function buildHeaderCells(sourceColumns, utilityColumnCount, depth) {
|
|
1251
|
+
const cells = [];
|
|
1252
|
+
let leafIndex = utilityColumnCount;
|
|
1253
|
+
const walk = (column, level, inheritedFixed, insideGroup, rootIndex, parentKey) => {
|
|
1254
|
+
const fixedColumn = insideGroup ? { ...column, fixed: inheritedFixed } : column;
|
|
1255
|
+
if (!fixedColumn.children?.length) {
|
|
1256
|
+
const startIndex2 = leafIndex;
|
|
1257
|
+
leafIndex += 1;
|
|
1258
|
+
cells.push({ key: fixedColumn.key, column: fixedColumn, level: depth - 1, startIndex: startIndex2, endIndex: startIndex2, leaf: true, parentKey, rootIndex });
|
|
1259
|
+
return { startIndex: startIndex2, endIndex: startIndex2 };
|
|
1260
|
+
}
|
|
1261
|
+
const startIndex = leafIndex;
|
|
1262
|
+
fixedColumn.children.forEach((child) => walk(child, level + 1, fixedColumn.fixed, true, rootIndex, fixedColumn.key));
|
|
1263
|
+
const endIndex = leafIndex - 1;
|
|
1264
|
+
cells.push({ key: fixedColumn.key, column: fixedColumn, level, startIndex, endIndex, leaf: false, parentKey, rootIndex });
|
|
1265
|
+
return { startIndex, endIndex };
|
|
1266
|
+
};
|
|
1267
|
+
sourceColumns.forEach((column, index) => walk(column, 0, void 0, false, index));
|
|
1268
|
+
return cells;
|
|
1269
|
+
}
|
|
1270
|
+
function hasNestedFixedColumns(columns, insideGroup = false) {
|
|
1271
|
+
return columns.some((column) => insideGroup && column.fixed !== void 0 || (column.children?.length ? hasNestedFixedColumns(column.children, true) : false));
|
|
1272
|
+
}
|
|
1273
|
+
function isProductionRuntime() {
|
|
1274
|
+
const env = globalThis.process?.env?.NODE_ENV;
|
|
1275
|
+
return env === "production";
|
|
1276
|
+
}
|
|
1239
1277
|
var createPendingInsertId = () => `table-inserted-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;
|
|
1240
1278
|
var waitForPaint = () => new Promise((resolve) => {
|
|
1241
1279
|
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
@@ -1350,10 +1388,24 @@ function Table({
|
|
|
1350
1388
|
}) {
|
|
1351
1389
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1352
1390
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1391
|
+
const headerDepth = useMemo(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
1353
1392
|
const { language, labels } = useMemo(() => resolveGridLocale(locale), [locale]);
|
|
1354
1393
|
const customHeaderContentRefs = useRef2(/* @__PURE__ */ new Map());
|
|
1355
|
-
const
|
|
1356
|
-
const
|
|
1394
|
+
const customHeaderMeasurementsRef = useRef2(/* @__PURE__ */ new Map());
|
|
1395
|
+
const [measuredHeaderRowHeights, setMeasuredHeaderRowHeights] = useState4([]);
|
|
1396
|
+
const headerRowHeights = useMemo(() => Array.from({ length: headerDepth }, (_, level) => Math.max(baseHeaderHeight, measuredHeaderRowHeights[level] ?? 0)), [baseHeaderHeight, headerDepth, measuredHeaderRowHeights]);
|
|
1397
|
+
const headerRowOffsets = useMemo(() => {
|
|
1398
|
+
const offsets = [];
|
|
1399
|
+
let top = 0;
|
|
1400
|
+
headerRowHeights.forEach((height2) => {
|
|
1401
|
+
offsets.push(top);
|
|
1402
|
+
top += height2;
|
|
1403
|
+
});
|
|
1404
|
+
return offsets;
|
|
1405
|
+
}, [headerRowHeights]);
|
|
1406
|
+
const headerHeight = headerRowHeights.reduce((total, height2) => total + height2, 0);
|
|
1407
|
+
const headerLeafTop = headerRowOffsets[headerDepth - 1] ?? 0;
|
|
1408
|
+
const headerLeafHeight = headerRowHeights[headerDepth - 1] ?? baseHeaderHeight;
|
|
1357
1409
|
const hasVerticalBorders = !(borderless ?? verticalBorderless ?? false);
|
|
1358
1410
|
const hasStripedRows = Boolean(striped);
|
|
1359
1411
|
const stripedColor = typeof striped === "string" ? striped : void 0;
|
|
@@ -1373,6 +1425,13 @@ function Table({
|
|
|
1373
1425
|
const summaryEmptyValue = typeof summary === "object" ? summary.emptyValue ?? "" : "";
|
|
1374
1426
|
const contextMenuEnabled = contextMenuConfig !== false;
|
|
1375
1427
|
const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
|
|
1428
|
+
const [resizedColumnWidths, setResizedColumnWidths] = useState4({});
|
|
1429
|
+
const leafSourceColumns = useMemo(() => flattenDataColumns(sourceColumns), [sourceColumns]);
|
|
1430
|
+
useEffect2(() => {
|
|
1431
|
+
if (!isProductionRuntime() && hasNestedFixedColumns(sourceColumns)) {
|
|
1432
|
+
console.warn("[Table] Multi-level headers only support fixed columns on top-level columns. Nested fixed values are ignored.");
|
|
1433
|
+
}
|
|
1434
|
+
}, [sourceColumns]);
|
|
1376
1435
|
const columns = useMemo(() => {
|
|
1377
1436
|
const utilityColumns = [];
|
|
1378
1437
|
if (rowDraggable) {
|
|
@@ -1384,9 +1443,24 @@ function Table({
|
|
|
1384
1443
|
if (rowNumber) {
|
|
1385
1444
|
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: "left", rowNumber: true });
|
|
1386
1445
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1446
|
+
const dataColumns = leafSourceColumns.map((column) => {
|
|
1447
|
+
const resizedWidth = resizedColumnWidths[column.key];
|
|
1448
|
+
return resizedWidth === void 0 ? column : { ...column, width: resizedWidth };
|
|
1449
|
+
});
|
|
1450
|
+
return [...utilityColumns, ...dataColumns];
|
|
1451
|
+
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber, rowSelection, sourceRows.length]);
|
|
1389
1452
|
const utilityColumnCount = (rowDraggable ? 1 : 0) + (rowSelection ? 1 : 0) + (rowNumber ? 1 : 0);
|
|
1453
|
+
const headerCells = useMemo(() => buildHeaderCells(sourceColumns, utilityColumnCount, headerDepth), [headerDepth, sourceColumns, utilityColumnCount]);
|
|
1454
|
+
const activeCustomHeaderLevels = useMemo(() => {
|
|
1455
|
+
const levels = /* @__PURE__ */ new Map();
|
|
1456
|
+
columns.forEach((column) => {
|
|
1457
|
+
if (column.renderHeader) levels.set(column.key, headerDepth - 1);
|
|
1458
|
+
});
|
|
1459
|
+
headerCells.forEach((cell) => {
|
|
1460
|
+
if (cell.column.renderHeader) levels.set(`group:${cell.key}:${cell.level}`, cell.level);
|
|
1461
|
+
});
|
|
1462
|
+
return levels;
|
|
1463
|
+
}, [columns, headerCells, headerDepth]);
|
|
1390
1464
|
const canvasRef = useRef2(null);
|
|
1391
1465
|
const scrollerRef = useRef2(null);
|
|
1392
1466
|
const frameRef = useRef2(null);
|
|
@@ -1404,6 +1478,14 @@ function Table({
|
|
|
1404
1478
|
const dragGuideRef = useRef2(null);
|
|
1405
1479
|
const rowDragGuideRef = useRef2(null);
|
|
1406
1480
|
const selectionFocusRef = useRef2(null);
|
|
1481
|
+
const verticalScrollbarRef = useRef2(null);
|
|
1482
|
+
const verticalScrollbarThumbRef = useRef2(null);
|
|
1483
|
+
const verticalScrollbarDragRef = useRef2(null);
|
|
1484
|
+
const horizontalScrollbarRef = useRef2(null);
|
|
1485
|
+
const horizontalScrollbarThumbRef = useRef2(null);
|
|
1486
|
+
const horizontalScrollbarDragRef = useRef2(null);
|
|
1487
|
+
const verticalScrollbarVisibilityTimerRef = useRef2(null);
|
|
1488
|
+
const horizontalScrollbarVisibilityTimerRef = useRef2(null);
|
|
1407
1489
|
const rowByKeyRef = useRef2(/* @__PURE__ */ new Map());
|
|
1408
1490
|
const rowIndexByKeyRef = useRef2(/* @__PURE__ */ new Map());
|
|
1409
1491
|
const headerIconsRef = useRef2(null);
|
|
@@ -1456,24 +1538,57 @@ function Table({
|
|
|
1456
1538
|
rangeDragRef.current = null;
|
|
1457
1539
|
setSelectionRange(null);
|
|
1458
1540
|
}, [rangeSelection]);
|
|
1541
|
+
useEffect2(() => {
|
|
1542
|
+
setResizedColumnWidths((current) => {
|
|
1543
|
+
const sourceColumnByKey = new Map(leafSourceColumns.map((column) => [column.key, column]));
|
|
1544
|
+
let changed = false;
|
|
1545
|
+
const next = {};
|
|
1546
|
+
Object.entries(current).forEach(([key, value]) => {
|
|
1547
|
+
const sourceColumn = sourceColumnByKey.get(key);
|
|
1548
|
+
if (!sourceColumn) {
|
|
1549
|
+
changed = true;
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
if (sourceColumn.width !== void 0 && sourceColumn.width !== value) {
|
|
1553
|
+
changed = true;
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
next[key] = value;
|
|
1557
|
+
});
|
|
1558
|
+
return changed ? next : current;
|
|
1559
|
+
});
|
|
1560
|
+
}, [leafSourceColumns]);
|
|
1459
1561
|
useEffect2(() => () => {
|
|
1460
1562
|
if (headerTooltipTimerRef.current !== null) clearTimeout(headerTooltipTimerRef.current);
|
|
1461
1563
|
if (cellTooltipTimerRef.current !== null) clearTimeout(cellTooltipTimerRef.current);
|
|
1462
1564
|
}, []);
|
|
1463
1565
|
const measureCustomHeaderHeight = useCallback2(() => {
|
|
1464
|
-
|
|
1566
|
+
const nextHeights = Array.from({ length: headerDepth }, () => baseHeaderHeight);
|
|
1465
1567
|
customHeaderContentRefs.current.forEach((node) => {
|
|
1466
|
-
|
|
1568
|
+
const headerCell = node.closest(".rvg-header-title");
|
|
1569
|
+
const key = headerCell?.dataset.measureKey;
|
|
1570
|
+
const level = key ? activeCustomHeaderLevels.get(key) : void 0;
|
|
1571
|
+
if (!key || level === void 0 || level < 0 || level >= nextHeights.length) return;
|
|
1572
|
+
customHeaderMeasurementsRef.current.set(key, { level, height: Math.ceil(node.scrollHeight) + 16 });
|
|
1467
1573
|
});
|
|
1468
|
-
|
|
1469
|
-
|
|
1574
|
+
customHeaderMeasurementsRef.current.forEach((measurement, key) => {
|
|
1575
|
+
if (!activeCustomHeaderLevels.has(key)) return;
|
|
1576
|
+
nextHeights[measurement.level] = Math.max(nextHeights[measurement.level], measurement.height);
|
|
1577
|
+
});
|
|
1578
|
+
setMeasuredHeaderRowHeights((current) => {
|
|
1579
|
+
const changed = nextHeights.length !== current.length || nextHeights.some((height2, index) => height2 !== current[index]);
|
|
1580
|
+
return changed ? nextHeights : current;
|
|
1581
|
+
});
|
|
1582
|
+
}, [activeCustomHeaderLevels, baseHeaderHeight, headerDepth]);
|
|
1470
1583
|
useLayoutEffect2(() => {
|
|
1471
|
-
const activeCustomHeaderKeys = new Set(columns.filter((column) => column.renderHeader).map((column) => column.key));
|
|
1472
1584
|
customHeaderContentRefs.current.forEach((_, key) => {
|
|
1473
|
-
if (!
|
|
1585
|
+
if (!activeCustomHeaderLevels.has(key)) customHeaderContentRefs.current.delete(key);
|
|
1586
|
+
});
|
|
1587
|
+
customHeaderMeasurementsRef.current.forEach((_, key) => {
|
|
1588
|
+
if (!activeCustomHeaderLevels.has(key)) customHeaderMeasurementsRef.current.delete(key);
|
|
1474
1589
|
});
|
|
1475
|
-
if (
|
|
1476
|
-
|
|
1590
|
+
if (activeCustomHeaderLevels.size === 0) {
|
|
1591
|
+
setMeasuredHeaderRowHeights([]);
|
|
1477
1592
|
return;
|
|
1478
1593
|
}
|
|
1479
1594
|
measureCustomHeaderHeight();
|
|
@@ -1481,7 +1596,7 @@ function Table({
|
|
|
1481
1596
|
const observer = new ResizeObserver(measureCustomHeaderHeight);
|
|
1482
1597
|
customHeaderContentRefs.current.forEach((node) => observer.observe(node));
|
|
1483
1598
|
return () => observer.disconnect();
|
|
1484
|
-
}, [
|
|
1599
|
+
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1485
1600
|
const [filterEditor, setFilterEditor] = useState4(null);
|
|
1486
1601
|
const [contextMenu, setContextMenu] = useState4(null);
|
|
1487
1602
|
const [insertCounts, setInsertCounts] = useState4({ before: 1, after: 1 });
|
|
@@ -1491,6 +1606,7 @@ function Table({
|
|
|
1491
1606
|
const [deleteBusy, setDeleteBusy] = useState4(false);
|
|
1492
1607
|
const [toast, setToast] = useState4(null);
|
|
1493
1608
|
const [resizeGuideX, setResizeGuideX] = useState4(null);
|
|
1609
|
+
const [resizeGuideTop, setResizeGuideTop] = useState4(0);
|
|
1494
1610
|
const [hoveredHeaderAction, setHoveredHeaderAction] = useState4(null);
|
|
1495
1611
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = useState4(null);
|
|
1496
1612
|
const [hoveredCellTooltip, setHoveredCellTooltip] = useState4(null);
|
|
@@ -1575,7 +1691,17 @@ function Table({
|
|
|
1575
1691
|
const metrics = useMemo(() => buildColumnMetrics(columns, { columnDraggable, viewportWidth: viewport.width }), [columnDraggable, columns, viewport.width]);
|
|
1576
1692
|
const contentWidth = metrics.length > 0 ? metrics[metrics.length - 1].right : 0;
|
|
1577
1693
|
const contentHeight = rows.length * rowHeight;
|
|
1578
|
-
const fixedWidth = useMemo(() => columns.reduce((width2, column, index) => column.fixed === "left" ?
|
|
1694
|
+
const fixedWidth = useMemo(() => columns.reduce((width2, column, index) => column.fixed === "left" ? width2 + metrics[index].width : width2, 0), [columns, metrics]);
|
|
1695
|
+
const leftFixedOffsets = useMemo(() => {
|
|
1696
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
1697
|
+
let offset = 0;
|
|
1698
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
1699
|
+
if (columns[index].fixed !== "left") continue;
|
|
1700
|
+
offsets.set(index, offset);
|
|
1701
|
+
offset += metrics[index].width;
|
|
1702
|
+
}
|
|
1703
|
+
return offsets;
|
|
1704
|
+
}, [columns, metrics]);
|
|
1579
1705
|
const rightFixedWidth = useMemo(() => columns.reduce((width2, column, index) => column.fixed === "right" ? width2 + metrics[index].width : width2, 0), [columns, metrics]);
|
|
1580
1706
|
const rightFixedOffsets = useMemo(() => {
|
|
1581
1707
|
const offsets = /* @__PURE__ */ new Map();
|
|
@@ -1587,6 +1713,16 @@ function Table({
|
|
|
1587
1713
|
}
|
|
1588
1714
|
return offsets;
|
|
1589
1715
|
}, [columns, metrics]);
|
|
1716
|
+
const scrollableColumnLefts = useMemo(() => {
|
|
1717
|
+
const lefts = [];
|
|
1718
|
+
let width2 = fixedWidth;
|
|
1719
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
1720
|
+
lefts[index] = width2;
|
|
1721
|
+
if (columns[index].fixed === void 0) width2 += metrics[index].width;
|
|
1722
|
+
}
|
|
1723
|
+
return lefts;
|
|
1724
|
+
}, [columns, fixedWidth, metrics]);
|
|
1725
|
+
const getScrollableColumnLeft = useCallback2((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
|
|
1590
1726
|
const hasRowSelectionColumn = useMemo(() => columns.some((column) => column.rowSelection), [columns]);
|
|
1591
1727
|
const rowSelectionMode = typeof rowSelection === "object" ? rowSelection.mode ?? "multiple" : "multiple";
|
|
1592
1728
|
const hasSummaryRow = useMemo(() => rows.length > 0 && summaryEnabled && columns.some((column) => Boolean(column.summary)), [columns, rows.length, summaryEnabled]);
|
|
@@ -1597,7 +1733,7 @@ function Table({
|
|
|
1597
1733
|
const realContentHeight = bodyTop + bodyContentHeight + bottomSummaryHeight + (contentWidth > viewport.width ? horizontalScrollbarHeight : 0);
|
|
1598
1734
|
const effectiveHeight = autoHeight ? Math.max(bodyTop + bottomSummaryHeight, Math.min(resolvedHeight, realContentHeight)) : resolvedHeight;
|
|
1599
1735
|
const renderHeight = Math.max(0, effectiveHeight - bottomSummaryHeight);
|
|
1600
|
-
const bodyViewportHeight = Math.max(0, renderHeight - (fixedHeader ? headerHeight : 0)
|
|
1736
|
+
const bodyViewportHeight = Math.max(0, renderHeight - (fixedHeader ? headerHeight + topSummaryHeight : 0));
|
|
1601
1737
|
const [summaryState, setSummaryState] = useState4(() => ({ columns: null, rows: null, values: /* @__PURE__ */ new Map(), pending: false }));
|
|
1602
1738
|
const summaryPending = hasSummaryRow && (loading || summaryState.pending || summaryState.columns !== columns || summaryState.rows !== rows);
|
|
1603
1739
|
const summaryValues = hasSummaryRow && summaryState.columns === columns && summaryState.rows === rows ? summaryState.values : /* @__PURE__ */ new Map();
|
|
@@ -1773,8 +1909,8 @@ function Table({
|
|
|
1773
1909
|
const scroll = scrollRef.current;
|
|
1774
1910
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1775
1911
|
const range = isVirtualized ? getViewportRange(scroll.left, rowScrollTop, viewport.width, bodyViewportHeight, rows.length, rowHeight, metrics, virtualOverscan) : { rowStart: 0, rowEnd: rows.length, columnStart: 0, columnEnd: columns.length };
|
|
1776
|
-
paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, headerHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, colors: themeColors });
|
|
1777
|
-
}, [bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, getRowKey, hasStripedRows, hasVerticalBorders, headerHeight, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
1912
|
+
paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, headerHeight, headerLeafTop, headerLeafHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, colors: themeColors });
|
|
1913
|
+
}, [bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, getRowKey, hasStripedRows, hasVerticalBorders, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
1778
1914
|
const scheduleDraw = useCallback2(() => {
|
|
1779
1915
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1780
1916
|
}, [draw]);
|
|
@@ -1811,6 +1947,8 @@ function Table({
|
|
|
1811
1947
|
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
1812
1948
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
1813
1949
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
1950
|
+
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
1951
|
+
if (horizontalScrollbarVisibilityTimerRef.current !== null) clearTimeout(horizontalScrollbarVisibilityTimerRef.current);
|
|
1814
1952
|
}, []);
|
|
1815
1953
|
useEffect2(() => {
|
|
1816
1954
|
const scroller = scrollerRef.current;
|
|
@@ -1862,9 +2000,204 @@ function Table({
|
|
|
1862
2000
|
scroller.addEventListener("scroll", lockScroll);
|
|
1863
2001
|
return () => scroller.removeEventListener("scroll", lockScroll);
|
|
1864
2002
|
}, [insertBusy]);
|
|
2003
|
+
const showCustomScrollbar = useCallback2((axis, persist = false) => {
|
|
2004
|
+
const showVertical = axis === "vertical" || axis === "both";
|
|
2005
|
+
const showHorizontal = axis === "horizontal" || axis === "both";
|
|
2006
|
+
if (showVertical) {
|
|
2007
|
+
verticalScrollbarRef.current?.classList.add("is-active");
|
|
2008
|
+
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
2009
|
+
if (!persist) {
|
|
2010
|
+
verticalScrollbarVisibilityTimerRef.current = setTimeout(() => {
|
|
2011
|
+
verticalScrollbarRef.current?.classList.remove("is-active");
|
|
2012
|
+
verticalScrollbarVisibilityTimerRef.current = null;
|
|
2013
|
+
}, 900);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
if (showHorizontal) {
|
|
2017
|
+
horizontalScrollbarRef.current?.classList.add("is-active");
|
|
2018
|
+
if (horizontalScrollbarVisibilityTimerRef.current !== null) clearTimeout(horizontalScrollbarVisibilityTimerRef.current);
|
|
2019
|
+
if (!persist) {
|
|
2020
|
+
horizontalScrollbarVisibilityTimerRef.current = setTimeout(() => {
|
|
2021
|
+
horizontalScrollbarRef.current?.classList.remove("is-active");
|
|
2022
|
+
horizontalScrollbarVisibilityTimerRef.current = null;
|
|
2023
|
+
}, 900);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
}, []);
|
|
2027
|
+
const keepCustomScrollbarVisible = useCallback2((axis) => {
|
|
2028
|
+
showCustomScrollbar(axis, true);
|
|
2029
|
+
}, [showCustomScrollbar]);
|
|
2030
|
+
const releaseCustomScrollbarVisible = useCallback2((axis) => {
|
|
2031
|
+
if (axis === "vertical" && verticalScrollbarDragRef.current) return;
|
|
2032
|
+
if (axis === "horizontal" && horizontalScrollbarDragRef.current) return;
|
|
2033
|
+
showCustomScrollbar(axis);
|
|
2034
|
+
}, [showCustomScrollbar]);
|
|
2035
|
+
const updateCustomScrollbars = useCallback2(() => {
|
|
2036
|
+
const scroller = scrollerRef.current;
|
|
2037
|
+
const verticalTrack = verticalScrollbarRef.current;
|
|
2038
|
+
const verticalThumb = verticalScrollbarThumbRef.current;
|
|
2039
|
+
const horizontalTrack = horizontalScrollbarRef.current;
|
|
2040
|
+
const horizontalThumb = horizontalScrollbarThumbRef.current;
|
|
2041
|
+
if (!scroller || !verticalTrack || !verticalThumb || !horizontalTrack || !horizontalThumb) return;
|
|
2042
|
+
const maxScrollTop = scroller.scrollHeight - scroller.clientHeight;
|
|
2043
|
+
if (maxScrollTop <= 1 || renderHeight <= 0) {
|
|
2044
|
+
verticalTrack.style.display = "none";
|
|
2045
|
+
} else {
|
|
2046
|
+
const top = fixedHeader ? bodyTop : 0;
|
|
2047
|
+
const bottom = bottomSummaryHeight;
|
|
2048
|
+
const trackHeight = Math.max(0, effectiveHeight - top - bottom);
|
|
2049
|
+
if (trackHeight <= 0) {
|
|
2050
|
+
verticalTrack.style.display = "none";
|
|
2051
|
+
} else {
|
|
2052
|
+
const thumbHeight = Math.max(28, Math.round(trackHeight * (scroller.clientHeight / scroller.scrollHeight)));
|
|
2053
|
+
const maxThumbTop = Math.max(0, trackHeight - thumbHeight);
|
|
2054
|
+
const thumbTop = maxScrollTop > 0 ? Math.round(scroller.scrollTop / maxScrollTop * maxThumbTop) : 0;
|
|
2055
|
+
verticalTrack.style.display = "block";
|
|
2056
|
+
verticalTrack.style.top = `${top}px`;
|
|
2057
|
+
verticalTrack.style.bottom = `${bottom}px`;
|
|
2058
|
+
verticalThumb.style.height = `${Math.min(trackHeight, thumbHeight)}px`;
|
|
2059
|
+
verticalThumb.style.transform = `translateY(${thumbTop}px)`;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
const maxScrollLeft = scroller.scrollWidth - scroller.clientWidth;
|
|
2063
|
+
if (maxScrollLeft <= 1 || viewport.width <= 0) {
|
|
2064
|
+
horizontalTrack.style.display = "none";
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
const trackLeft = fixedWidth;
|
|
2068
|
+
const trackRight = rightFixedWidth;
|
|
2069
|
+
const trackWidth = Math.max(0, viewport.width - trackLeft - trackRight);
|
|
2070
|
+
if (trackWidth <= 0) {
|
|
2071
|
+
horizontalTrack.style.display = "none";
|
|
2072
|
+
return;
|
|
2073
|
+
}
|
|
2074
|
+
const thumbWidth = Math.max(36, Math.round(trackWidth * (scroller.clientWidth / scroller.scrollWidth)));
|
|
2075
|
+
const maxThumbLeft = Math.max(0, trackWidth - thumbWidth);
|
|
2076
|
+
const thumbLeft = maxScrollLeft > 0 ? Math.round(scroller.scrollLeft / maxScrollLeft * maxThumbLeft) : 0;
|
|
2077
|
+
horizontalTrack.style.display = "block";
|
|
2078
|
+
horizontalTrack.style.left = `${trackLeft}px`;
|
|
2079
|
+
horizontalTrack.style.right = `${trackRight}px`;
|
|
2080
|
+
horizontalTrack.style.bottom = `${bottomSummaryHeight + 2}px`;
|
|
2081
|
+
horizontalThumb.style.width = `${Math.min(trackWidth, thumbWidth)}px`;
|
|
2082
|
+
horizontalThumb.style.transform = `translateX(${thumbLeft}px)`;
|
|
2083
|
+
}, [bodyTop, bottomSummaryHeight, effectiveHeight, fixedHeader, fixedWidth, renderHeight, rightFixedWidth, viewport.width]);
|
|
2084
|
+
useLayoutEffect2(() => {
|
|
2085
|
+
updateCustomScrollbars();
|
|
2086
|
+
}, [contentHeight, contentWidth, updateCustomScrollbars, viewport.height, viewport.width]);
|
|
2087
|
+
const handleVerticalScrollbarPointerDown = useCallback2((event) => {
|
|
2088
|
+
const scroller = scrollerRef.current;
|
|
2089
|
+
const track = verticalScrollbarRef.current;
|
|
2090
|
+
const thumb = verticalScrollbarThumbRef.current;
|
|
2091
|
+
if (!scroller || !track || !thumb || event.button !== 0) return;
|
|
2092
|
+
event.preventDefault();
|
|
2093
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2094
|
+
const trackRect = track.getBoundingClientRect();
|
|
2095
|
+
const thumbRect = thumb.getBoundingClientRect();
|
|
2096
|
+
const maxScrollTop = scroller.scrollHeight - scroller.clientHeight;
|
|
2097
|
+
const trackHeight = trackRect.height;
|
|
2098
|
+
const thumbHeight = thumbRect.height;
|
|
2099
|
+
showCustomScrollbar("vertical", true);
|
|
2100
|
+
if (event.target === thumb) {
|
|
2101
|
+
verticalScrollbarDragRef.current = {
|
|
2102
|
+
pointerId: event.pointerId,
|
|
2103
|
+
startY: event.clientY,
|
|
2104
|
+
startTop: thumbRect.top - trackRect.top,
|
|
2105
|
+
trackHeight,
|
|
2106
|
+
thumbHeight,
|
|
2107
|
+
maxScrollTop
|
|
2108
|
+
};
|
|
2109
|
+
return;
|
|
2110
|
+
}
|
|
2111
|
+
const nextThumbTop = Math.max(0, Math.min(trackHeight - thumbHeight, event.clientY - trackRect.top - thumbHeight / 2));
|
|
2112
|
+
const maxThumbTop = Math.max(1, trackHeight - thumbHeight);
|
|
2113
|
+
scroller.scrollTop = nextThumbTop / maxThumbTop * maxScrollTop;
|
|
2114
|
+
updateCustomScrollbars();
|
|
2115
|
+
verticalScrollbarDragRef.current = {
|
|
2116
|
+
pointerId: event.pointerId,
|
|
2117
|
+
startY: event.clientY,
|
|
2118
|
+
startTop: nextThumbTop,
|
|
2119
|
+
trackHeight,
|
|
2120
|
+
thumbHeight,
|
|
2121
|
+
maxScrollTop
|
|
2122
|
+
};
|
|
2123
|
+
}, [showCustomScrollbar, updateCustomScrollbars]);
|
|
2124
|
+
const handleVerticalScrollbarPointerMove = useCallback2((event) => {
|
|
2125
|
+
const drag = verticalScrollbarDragRef.current;
|
|
2126
|
+
const scroller = scrollerRef.current;
|
|
2127
|
+
if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
|
|
2128
|
+
event.preventDefault();
|
|
2129
|
+
const maxThumbTop = Math.max(1, drag.trackHeight - drag.thumbHeight);
|
|
2130
|
+
const nextThumbTop = Math.max(0, Math.min(maxThumbTop, drag.startTop + event.clientY - drag.startY));
|
|
2131
|
+
scroller.scrollTop = nextThumbTop / maxThumbTop * drag.maxScrollTop;
|
|
2132
|
+
updateCustomScrollbars();
|
|
2133
|
+
}, [updateCustomScrollbars]);
|
|
2134
|
+
const handleVerticalScrollbarPointerUp = useCallback2((event) => {
|
|
2135
|
+
const drag = verticalScrollbarDragRef.current;
|
|
2136
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2137
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2138
|
+
verticalScrollbarDragRef.current = null;
|
|
2139
|
+
showCustomScrollbar("vertical");
|
|
2140
|
+
}, [showCustomScrollbar]);
|
|
2141
|
+
const handleHorizontalScrollbarPointerDown = useCallback2((event) => {
|
|
2142
|
+
const scroller = scrollerRef.current;
|
|
2143
|
+
const track = horizontalScrollbarRef.current;
|
|
2144
|
+
const thumb = horizontalScrollbarThumbRef.current;
|
|
2145
|
+
if (!scroller || !track || !thumb || event.button !== 0) return;
|
|
2146
|
+
event.preventDefault();
|
|
2147
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2148
|
+
const trackRect = track.getBoundingClientRect();
|
|
2149
|
+
const thumbRect = thumb.getBoundingClientRect();
|
|
2150
|
+
const maxScrollLeft = scroller.scrollWidth - scroller.clientWidth;
|
|
2151
|
+
const trackWidth = trackRect.width;
|
|
2152
|
+
const thumbWidth = thumbRect.width;
|
|
2153
|
+
showCustomScrollbar("horizontal", true);
|
|
2154
|
+
if (event.target === thumb) {
|
|
2155
|
+
horizontalScrollbarDragRef.current = {
|
|
2156
|
+
pointerId: event.pointerId,
|
|
2157
|
+
startX: event.clientX,
|
|
2158
|
+
startLeft: thumbRect.left - trackRect.left,
|
|
2159
|
+
trackWidth,
|
|
2160
|
+
thumbWidth,
|
|
2161
|
+
maxScrollLeft
|
|
2162
|
+
};
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
const nextThumbLeft = Math.max(0, Math.min(trackWidth - thumbWidth, event.clientX - trackRect.left - thumbWidth / 2));
|
|
2166
|
+
const maxThumbLeft = Math.max(1, trackWidth - thumbWidth);
|
|
2167
|
+
scroller.scrollLeft = nextThumbLeft / maxThumbLeft * maxScrollLeft;
|
|
2168
|
+
updateCustomScrollbars();
|
|
2169
|
+
horizontalScrollbarDragRef.current = {
|
|
2170
|
+
pointerId: event.pointerId,
|
|
2171
|
+
startX: event.clientX,
|
|
2172
|
+
startLeft: nextThumbLeft,
|
|
2173
|
+
trackWidth,
|
|
2174
|
+
thumbWidth,
|
|
2175
|
+
maxScrollLeft
|
|
2176
|
+
};
|
|
2177
|
+
}, [showCustomScrollbar, updateCustomScrollbars]);
|
|
2178
|
+
const handleHorizontalScrollbarPointerMove = useCallback2((event) => {
|
|
2179
|
+
const drag = horizontalScrollbarDragRef.current;
|
|
2180
|
+
const scroller = scrollerRef.current;
|
|
2181
|
+
if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
|
|
2182
|
+
event.preventDefault();
|
|
2183
|
+
const maxThumbLeft = Math.max(1, drag.trackWidth - drag.thumbWidth);
|
|
2184
|
+
const nextThumbLeft = Math.max(0, Math.min(maxThumbLeft, drag.startLeft + event.clientX - drag.startX));
|
|
2185
|
+
scroller.scrollLeft = nextThumbLeft / maxThumbLeft * drag.maxScrollLeft;
|
|
2186
|
+
updateCustomScrollbars();
|
|
2187
|
+
}, [updateCustomScrollbars]);
|
|
2188
|
+
const handleHorizontalScrollbarPointerUp = useCallback2((event) => {
|
|
2189
|
+
const drag = horizontalScrollbarDragRef.current;
|
|
2190
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2191
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2192
|
+
horizontalScrollbarDragRef.current = null;
|
|
2193
|
+
showCustomScrollbar("horizontal");
|
|
2194
|
+
}, [showCustomScrollbar]);
|
|
1865
2195
|
const handleScroll = useCallback2(() => {
|
|
1866
2196
|
const element = scrollerRef.current;
|
|
1867
2197
|
if (!element) return;
|
|
2198
|
+
const previousScroll = scrollRef.current;
|
|
2199
|
+
const scrollDeltaX = element.scrollLeft - previousScroll.left;
|
|
2200
|
+
const scrollDeltaY = element.scrollTop - previousScroll.top;
|
|
1868
2201
|
scrollRef.current = { left: element.scrollLeft, top: element.scrollTop };
|
|
1869
2202
|
const focus = selectionFocusRef.current;
|
|
1870
2203
|
if (focus && selection && !selectionRange) {
|
|
@@ -1875,7 +2208,7 @@ function Table({
|
|
|
1875
2208
|
if (!validSelection) {
|
|
1876
2209
|
focus.style.display = "none";
|
|
1877
2210
|
} else {
|
|
1878
|
-
const rawLeft = column.fixed === "left" ?
|
|
2211
|
+
const rawLeft = column.fixed === "left" ? leftFixedOffsets.get(selection.columnIndex) ?? 0 : column.fixed === "right" ? viewport.width - (rightFixedOffsets.get(selection.columnIndex) ?? 0) - metric.width : getScrollableColumnLeft(selection.columnIndex) - element.scrollLeft;
|
|
1879
2212
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - element.scrollTop;
|
|
1880
2213
|
const span = getCellSpan(selection.rowIndex, selection.columnIndex);
|
|
1881
2214
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
@@ -1908,6 +2241,10 @@ function Table({
|
|
|
1908
2241
|
if (scrollingTextRef.current) scrollingTextRef.current.style.transform = `translateX(${-element.scrollLeft}px)`;
|
|
1909
2242
|
if (scrollingHeaderIconsRef.current) scrollingHeaderIconsRef.current.style.transform = `translateX(${-element.scrollLeft}px)`;
|
|
1910
2243
|
if (headerIconsRef.current) headerIconsRef.current.style.transform = `translateY(${fixedHeader ? 0 : -element.scrollTop}px)`;
|
|
2244
|
+
updateCustomScrollbars();
|
|
2245
|
+
if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {
|
|
2246
|
+
showCustomScrollbar(scrollDeltaX !== 0 && scrollDeltaY !== 0 ? "both" : scrollDeltaX !== 0 ? "horizontal" : "vertical");
|
|
2247
|
+
}
|
|
1911
2248
|
if (hoveredHeaderActionRef.current) {
|
|
1912
2249
|
hoveredHeaderActionRef.current = null;
|
|
1913
2250
|
setHoveredHeaderAction(null);
|
|
@@ -1915,7 +2252,7 @@ function Table({
|
|
|
1915
2252
|
setHoveredCellTooltip(null);
|
|
1916
2253
|
scheduleDraw();
|
|
1917
2254
|
setEditing(null);
|
|
1918
|
-
}, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, viewport.width]);
|
|
2255
|
+
}, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, showCustomScrollbar, updateCustomScrollbars, viewport.width]);
|
|
1919
2256
|
const locateColumn = useCallback2((clientX) => {
|
|
1920
2257
|
const canvas = canvasRef.current;
|
|
1921
2258
|
if (!canvas) return -1;
|
|
@@ -1923,7 +2260,11 @@ function Table({
|
|
|
1923
2260
|
const localX = clientX - rect.left;
|
|
1924
2261
|
let columnIndex;
|
|
1925
2262
|
if (localX < fixedWidth) {
|
|
1926
|
-
columnIndex =
|
|
2263
|
+
columnIndex = columns.findIndex((column, index) => {
|
|
2264
|
+
if (column.fixed !== "left") return false;
|
|
2265
|
+
const left = leftFixedOffsets.get(index) ?? 0;
|
|
2266
|
+
return localX >= left && localX < left + metrics[index].width;
|
|
2267
|
+
});
|
|
1927
2268
|
} else if (rightFixedWidth > 0 && localX >= viewport.width - rightFixedWidth) {
|
|
1928
2269
|
columnIndex = columns.findIndex((column, index) => {
|
|
1929
2270
|
if (column.fixed !== "right") return false;
|
|
@@ -1931,41 +2272,33 @@ function Table({
|
|
|
1931
2272
|
return localX >= left && localX < left + metrics[index].width;
|
|
1932
2273
|
});
|
|
1933
2274
|
} else {
|
|
1934
|
-
|
|
2275
|
+
const scrollX = localX + scrollRef.current.left;
|
|
2276
|
+
columnIndex = columns.findIndex((column, index) => {
|
|
2277
|
+
if (column.fixed !== void 0) return false;
|
|
2278
|
+
const left = getScrollableColumnLeft(index);
|
|
2279
|
+
return scrollX >= left && scrollX < left + metrics[index].width;
|
|
2280
|
+
});
|
|
1935
2281
|
}
|
|
1936
2282
|
return columnIndex;
|
|
1937
|
-
}, [columns, fixedWidth, metrics, rightFixedOffsets, rightFixedWidth, viewport.width]);
|
|
2283
|
+
}, [columns, fixedWidth, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rightFixedWidth, viewport.width]);
|
|
1938
2284
|
const getDisplayedColumnLeft = useCallback2((columnIndex) => {
|
|
1939
2285
|
const metric = metrics[columnIndex];
|
|
1940
|
-
if (columns[columnIndex].fixed === "left") return
|
|
2286
|
+
if (columns[columnIndex].fixed === "left") return leftFixedOffsets.get(columnIndex) ?? 0;
|
|
1941
2287
|
if (columns[columnIndex].fixed === "right") return viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metric.width;
|
|
1942
|
-
return
|
|
1943
|
-
}, [columns, metrics, rightFixedOffsets, viewport.width]);
|
|
1944
|
-
const
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
for (let index = 0; index < columns.length; index += 1) {
|
|
1950
|
-
if (columns[index].rowSelection || columns[index].rowDragHandle || columns[index].rowNumber) continue;
|
|
1951
|
-
const nextDistance = Math.abs(localX - (getDisplayedColumnLeft(index) + metrics[index].width));
|
|
1952
|
-
if (nextDistance < distance) {
|
|
1953
|
-
distance = nextDistance;
|
|
1954
|
-
closest = index;
|
|
1955
|
-
}
|
|
2288
|
+
return getScrollableColumnLeft(columnIndex) - scrollRef.current.left;
|
|
2289
|
+
}, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
|
|
2290
|
+
const getHeaderLevelAtY = useCallback2((localY, headerY) => {
|
|
2291
|
+
const y = localY - headerY;
|
|
2292
|
+
for (let level = 0; level < headerRowHeights.length; level += 1) {
|
|
2293
|
+
const top = headerRowOffsets[level] ?? 0;
|
|
2294
|
+
if (y >= top && y < top + headerRowHeights[level]) return level;
|
|
1956
2295
|
}
|
|
1957
|
-
return
|
|
1958
|
-
}, [
|
|
1959
|
-
const
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
if (column.rowSelection || column.rowDragHandle || column.rowNumber) continue;
|
|
1964
|
-
if (resizedColumn?.fixed && column.fixed !== resizedColumn.fixed) return -1;
|
|
1965
|
-
return index;
|
|
1966
|
-
}
|
|
1967
|
-
return -1;
|
|
1968
|
-
}, [columns]);
|
|
2296
|
+
return headerDepth - 1;
|
|
2297
|
+
}, [headerDepth, headerRowHeights, headerRowOffsets]);
|
|
2298
|
+
const resizeColumn = useCallback2((columnKey, width2) => {
|
|
2299
|
+
setResizedColumnWidths((current) => current[columnKey] === width2 ? current : { ...current, [columnKey]: width2 });
|
|
2300
|
+
onColumnResize?.(columnKey, width2);
|
|
2301
|
+
}, [onColumnResize]);
|
|
1969
2302
|
const locateHeaderAction = useCallback2((clientX, columnIndex) => {
|
|
1970
2303
|
if (columnIndex < 0 || !canvasRef.current) return null;
|
|
1971
2304
|
const column = columns[columnIndex];
|
|
@@ -2000,11 +2333,70 @@ function Table({
|
|
|
2000
2333
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2001
2334
|
return localX >= columnRight - 16 && localX < columnRight - 5;
|
|
2002
2335
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2003
|
-
const
|
|
2336
|
+
const getHeaderCellLeft = useCallback2((cell) => {
|
|
2337
|
+
const startMetric = metrics[cell.startIndex];
|
|
2338
|
+
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
2339
|
+
if (!startMetric) return 0;
|
|
2340
|
+
return fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex) - scrollRef.current.left;
|
|
2341
|
+
}, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
|
|
2342
|
+
const getHeaderCellWidth = useCallback2((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
|
|
2343
|
+
const locateHeaderResizeHit = useCallback2((clientX, clientY) => {
|
|
2344
|
+
if (!columnResizable || !canvasRef.current) return null;
|
|
2345
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
2346
|
+
const localX = clientX - rect.left;
|
|
2347
|
+
const localY = clientY - rect.top;
|
|
2348
|
+
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
2349
|
+
if (localY < headerY || localY >= headerY + headerHeight) return null;
|
|
2350
|
+
const level = getHeaderLevelAtY(localY, headerY);
|
|
2351
|
+
let closest = null;
|
|
2352
|
+
let distance = 6;
|
|
2353
|
+
for (const cell of headerCells) {
|
|
2354
|
+
if (cell.level !== level) continue;
|
|
2355
|
+
if (columns[cell.startIndex]?.rowSelection || columns[cell.startIndex]?.rowDragHandle || columns[cell.startIndex]?.rowNumber) continue;
|
|
2356
|
+
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
2357
|
+
const edge = fixedSide === "right" && cell.leaf ? "left" : "right";
|
|
2358
|
+
const edgeX = getHeaderCellLeft(cell) + (edge === "right" ? getHeaderCellWidth(cell) : 0);
|
|
2359
|
+
const nextDistance = Math.abs(localX - edgeX);
|
|
2360
|
+
if (nextDistance < distance) {
|
|
2361
|
+
distance = nextDistance;
|
|
2362
|
+
closest = { cell, edge };
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
return closest;
|
|
2366
|
+
}, [columnResizable, columns, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
|
|
2367
|
+
const locateHeaderResizeCell = useCallback2((clientX, clientY) => locateHeaderResizeHit(clientX, clientY)?.cell ?? null, [locateHeaderResizeHit]);
|
|
2368
|
+
const locateHeaderCellDragHandle = useCallback2((clientX, cell) => {
|
|
2369
|
+
if (!columnDraggable || !canvasRef.current) return false;
|
|
2370
|
+
if (cell.leaf) return locateHeaderDragHandle(clientX, cell.startIndex);
|
|
2371
|
+
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2372
|
+
const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
|
|
2373
|
+
return localX >= right - 16 && localX < right - 5;
|
|
2374
|
+
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, locateHeaderDragHandle]);
|
|
2375
|
+
const locateHeaderCell = useCallback2((clientX, clientY) => {
|
|
2376
|
+
const canvas = canvasRef.current;
|
|
2377
|
+
if (!canvas) return null;
|
|
2378
|
+
const rect = canvas.getBoundingClientRect();
|
|
2379
|
+
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
2380
|
+
const localX = clientX - rect.left;
|
|
2381
|
+
const localY = clientY - rect.top;
|
|
2382
|
+
if (localY < headerY || localY >= headerY + headerHeight) return null;
|
|
2383
|
+
const level = getHeaderLevelAtY(localY, headerY);
|
|
2384
|
+
for (const cell of headerCells) {
|
|
2385
|
+
if (cell.level !== level) continue;
|
|
2386
|
+
const left = getHeaderCellLeft(cell);
|
|
2387
|
+
const width2 = getHeaderCellWidth(cell);
|
|
2388
|
+
if (localX >= left && localX < left + width2) return cell;
|
|
2389
|
+
}
|
|
2390
|
+
return null;
|
|
2391
|
+
}, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
|
|
2392
|
+
const setDragGuide = useCallback2((x, top = 0) => {
|
|
2004
2393
|
const guide = dragGuideRef.current;
|
|
2005
2394
|
if (!guide) return;
|
|
2006
2395
|
guide.style.display = x === null ? "none" : "block";
|
|
2007
|
-
if (x !== null)
|
|
2396
|
+
if (x !== null) {
|
|
2397
|
+
guide.style.top = `${top}px`;
|
|
2398
|
+
guide.style.transform = `translateX(${Math.round(x)}px)`;
|
|
2399
|
+
}
|
|
2008
2400
|
}, []);
|
|
2009
2401
|
const setRowDragGuide = useCallback2((y) => {
|
|
2010
2402
|
const guide = rowDragGuideRef.current;
|
|
@@ -2022,6 +2414,15 @@ function Table({
|
|
|
2022
2414
|
useEffect2(() => {
|
|
2023
2415
|
const canvas = canvasRef.current;
|
|
2024
2416
|
if (!canvas || !columnDraggable && !rowDraggable) return;
|
|
2417
|
+
const getColumnDropIndex = (sourceIndex, targetIndex, edge) => {
|
|
2418
|
+
if (edge === "right") return targetIndex;
|
|
2419
|
+
const destinationIndex = targetIndex - (sourceIndex < targetIndex ? 1 : 0);
|
|
2420
|
+
return Math.max(0, Math.min(columns.length - 1, destinationIndex));
|
|
2421
|
+
};
|
|
2422
|
+
const getColumnDropPlacement = (sourceIndex, targetIndex, edge) => {
|
|
2423
|
+
if (edge !== "right") return "before";
|
|
2424
|
+
return targetIndex < sourceIndex ? "before" : "after";
|
|
2425
|
+
};
|
|
2025
2426
|
const getHeaderColumn = (clientX, clientY) => {
|
|
2026
2427
|
const rect = canvas.getBoundingClientRect();
|
|
2027
2428
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
@@ -2029,22 +2430,35 @@ function Table({
|
|
|
2029
2430
|
if (localY < headerY || localY >= headerY + headerHeight) return -1;
|
|
2030
2431
|
return locateColumn(clientX);
|
|
2031
2432
|
};
|
|
2433
|
+
const getHeaderDragCell = (clientX, clientY) => {
|
|
2434
|
+
const cell = locateHeaderCell(clientX, clientY);
|
|
2435
|
+
if (!cell) return null;
|
|
2436
|
+
return locateHeaderCellDragHandle(clientX, cell) && !locateHeaderResizeCell(clientX, clientY) ? cell : null;
|
|
2437
|
+
};
|
|
2032
2438
|
const cleanupDrag = draggable({
|
|
2033
2439
|
element: canvas,
|
|
2034
2440
|
canDrag: ({ input }) => {
|
|
2035
|
-
const
|
|
2036
|
-
if (
|
|
2441
|
+
const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
|
|
2442
|
+
if (headerDragCell) return true;
|
|
2037
2443
|
const columnIndex = locateColumn(input.clientX);
|
|
2038
2444
|
return rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
|
|
2039
2445
|
},
|
|
2040
2446
|
getInitialData: ({ input }) => {
|
|
2041
|
-
const
|
|
2042
|
-
if (
|
|
2447
|
+
const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
|
|
2448
|
+
if (!headerDragCell) {
|
|
2043
2449
|
return { type: "table-row", sourceIndex: locateRow(input.clientY) };
|
|
2044
2450
|
}
|
|
2045
|
-
const sourceIndex =
|
|
2451
|
+
const sourceIndex = headerDragCell.startIndex;
|
|
2046
2452
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2047
|
-
return {
|
|
2453
|
+
return {
|
|
2454
|
+
type: "table-column",
|
|
2455
|
+
sourceIndex,
|
|
2456
|
+
sourceKey: headerDragCell.key,
|
|
2457
|
+
parentKey: headerDragCell.parentKey,
|
|
2458
|
+
headerLevel: headerDragCell.level,
|
|
2459
|
+
headerKind: headerDragCell.leaf ? "column" : "group",
|
|
2460
|
+
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2461
|
+
};
|
|
2048
2462
|
},
|
|
2049
2463
|
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2050
2464
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2147,31 +2561,31 @@ function Table({
|
|
|
2147
2561
|
return;
|
|
2148
2562
|
}
|
|
2149
2563
|
const targetIndex = Number(target?.targetIndex);
|
|
2150
|
-
if (!Number.isInteger(targetIndex) ||
|
|
2564
|
+
if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
|
|
2151
2565
|
setDragGuide(null);
|
|
2152
2566
|
return;
|
|
2153
2567
|
}
|
|
2154
2568
|
const edge = target?.columnEdge;
|
|
2155
|
-
|
|
2156
|
-
if (sourceIndex < destinationIndex) destinationIndex -= 1;
|
|
2157
|
-
destinationIndex = Math.max(0, Math.min(columns.length - 1, destinationIndex));
|
|
2569
|
+
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2158
2570
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
|
|
2159
|
-
const targetLeft =
|
|
2160
|
-
|
|
2571
|
+
const targetLeft = Number(target?.targetLeft);
|
|
2572
|
+
const targetWidth = Number(target?.targetWidth);
|
|
2573
|
+
const guideTop = headerRowOffsets[Number(source.data.headerLevel)] ?? 0;
|
|
2574
|
+
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2161
2575
|
},
|
|
2162
2576
|
onDrop: ({ source, location }) => {
|
|
2163
2577
|
const target = location.current.dropTargets[0]?.data;
|
|
2164
2578
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2165
2579
|
if (source.data.type === "table-row") {
|
|
2166
|
-
const
|
|
2167
|
-
let targetIndex2 =
|
|
2580
|
+
const rawTargetIndex2 = Number(target?.targetIndex);
|
|
2581
|
+
let targetIndex2 = rawTargetIndex2 + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
2168
2582
|
if (sourceIndex < targetIndex2) targetIndex2 -= 1;
|
|
2169
2583
|
targetIndex2 = Math.max(0, Math.min(rows.length - 1, targetIndex2));
|
|
2170
2584
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2171
2585
|
setRowDragPreview(null);
|
|
2172
2586
|
setRowDragGuide(null);
|
|
2173
2587
|
canvas.style.cursor = "default";
|
|
2174
|
-
if (Number.isInteger(
|
|
2588
|
+
if (Number.isInteger(rawTargetIndex2) && sourceIndex !== targetIndex2) onRowOrderChange?.(sourceIndex, targetIndex2);
|
|
2175
2589
|
requestAnimationFrame(() => {
|
|
2176
2590
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2177
2591
|
});
|
|
@@ -2180,12 +2594,23 @@ function Table({
|
|
|
2180
2594
|
}, 0);
|
|
2181
2595
|
return;
|
|
2182
2596
|
}
|
|
2183
|
-
const
|
|
2597
|
+
const rawTargetIndex = Number(target?.targetIndex);
|
|
2598
|
+
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
2184
2599
|
canvas.style.cursor = "default";
|
|
2185
2600
|
setDragGuide(null);
|
|
2186
2601
|
columnDragPreviewRef.current = null;
|
|
2187
|
-
if (Number.isInteger(targetIndex) && sourceIndex !== targetIndex &&
|
|
2188
|
-
onColumnOrderChange?.(
|
|
2602
|
+
if (Number.isInteger(rawTargetIndex) && Number.isInteger(targetIndex) && sourceIndex !== targetIndex && target?.headerKind === source.data.headerKind && target?.parentKey === source.data.parentKey && target?.fixed === source.data.fixed) {
|
|
2603
|
+
onColumnOrderChange?.(
|
|
2604
|
+
sourceIndex - utilityColumnCount,
|
|
2605
|
+
targetIndex - utilityColumnCount,
|
|
2606
|
+
{
|
|
2607
|
+
type: source.data.headerKind === "group" ? "group" : "column",
|
|
2608
|
+
sourceKey: String(source.data.sourceKey),
|
|
2609
|
+
targetKey: String(target.targetKey),
|
|
2610
|
+
parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
|
|
2611
|
+
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex, target.columnEdge)
|
|
2612
|
+
}
|
|
2613
|
+
);
|
|
2189
2614
|
}
|
|
2190
2615
|
window.setTimeout(() => {
|
|
2191
2616
|
suppressClickRef.current = false;
|
|
@@ -2203,24 +2628,38 @@ function Table({
|
|
|
2203
2628
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2204
2629
|
return attachClosestEdge({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2205
2630
|
}
|
|
2206
|
-
|
|
2207
|
-
if (
|
|
2631
|
+
const targetCell = locateHeaderCell(input.clientX, input.clientY);
|
|
2632
|
+
if (!targetCell) return { targetIndex: -1 };
|
|
2633
|
+
let targetIndex = targetCell.startIndex;
|
|
2634
|
+
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
2635
|
+
const headerKind = targetCell.leaf ? "column" : "group";
|
|
2636
|
+
if (source.data.headerKind !== headerKind || source.data.parentKey !== targetCell.parentKey || source.data.fixed !== targetFixed) return { targetIndex: -1 };
|
|
2208
2637
|
if (columns[targetIndex].rowSelection || columns[targetIndex].rowDragHandle || columns[targetIndex].rowNumber) {
|
|
2209
2638
|
const fixedSide = columns[Number(source.data.sourceIndex)]?.fixed;
|
|
2210
2639
|
targetIndex = columns.findIndex((column, index) => index > targetIndex && column.fixed === fixedSide && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
|
|
2211
2640
|
if (targetIndex < 0) return { targetIndex: -1 };
|
|
2212
2641
|
return { targetIndex, columnEdge: "left" };
|
|
2213
2642
|
}
|
|
2214
|
-
const left =
|
|
2215
|
-
const
|
|
2216
|
-
|
|
2643
|
+
const left = getHeaderCellLeft(targetCell);
|
|
2644
|
+
const targetWidth = targetCell.leaf ? metrics[targetIndex].width : getHeaderCellWidth(targetCell);
|
|
2645
|
+
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2646
|
+
return attachClosestEdge({
|
|
2647
|
+
targetIndex,
|
|
2648
|
+
targetKey: targetCell.key,
|
|
2649
|
+
parentKey: targetCell.parentKey,
|
|
2650
|
+
headerKind,
|
|
2651
|
+
fixed: targetFixed,
|
|
2652
|
+
targetLeft: left,
|
|
2653
|
+
targetWidth,
|
|
2654
|
+
columnEdge
|
|
2655
|
+
}, { element, input, allowedEdges: ["left", "right"] });
|
|
2217
2656
|
}
|
|
2218
2657
|
});
|
|
2219
2658
|
return () => {
|
|
2220
2659
|
cleanupDrag();
|
|
2221
2660
|
cleanupDrop();
|
|
2222
2661
|
};
|
|
2223
|
-
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getRowKey, headerHeight, locateColumn,
|
|
2662
|
+
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerHeight, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, metrics, onColumnOrderChange, onRowOrderChange, rowDraggable, rowHeight, rows, selectedRowKeySet, setDragGuide, setRowDragGuide, utilityColumnCount]);
|
|
2224
2663
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
2225
2664
|
const canvas = canvasRef.current;
|
|
2226
2665
|
if (!canvas) return null;
|
|
@@ -2327,8 +2766,9 @@ function Table({
|
|
|
2327
2766
|
const horizontalFocusGap = 0;
|
|
2328
2767
|
const verticalFocusGap = 0;
|
|
2329
2768
|
if (column.fixed === void 0) {
|
|
2330
|
-
|
|
2331
|
-
if (
|
|
2769
|
+
const cellLeft = getScrollableColumnLeft(cell.columnIndex);
|
|
2770
|
+
if (cellLeft - nextLeft < fixedWidth) nextLeft = Math.max(0, cellLeft - fixedWidth - horizontalFocusGap);
|
|
2771
|
+
if (cellLeft + cellWidth - nextLeft > viewport.width - rightFixedWidth) nextLeft = cellLeft + cellWidth - viewport.width + rightFixedWidth + horizontalFocusGap;
|
|
2332
2772
|
}
|
|
2333
2773
|
const rowTop = (fixedHeader ? 0 : bodyTop) + cell.rowIndex * rowHeight;
|
|
2334
2774
|
const rowBottom = rowTop + rowHeight * rowSpan;
|
|
@@ -2341,7 +2781,7 @@ function Table({
|
|
|
2341
2781
|
scroller.scrollTop = nextTop;
|
|
2342
2782
|
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
2343
2783
|
scheduleDraw();
|
|
2344
|
-
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
2784
|
+
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
2345
2785
|
const beginEdit = useCallback2((cell) => {
|
|
2346
2786
|
const column = columns[cell.columnIndex];
|
|
2347
2787
|
if (!column?.editable || column.dataIndex === void 0) return;
|
|
@@ -2362,8 +2802,9 @@ function Table({
|
|
|
2362
2802
|
const horizontalFocusGap = 0;
|
|
2363
2803
|
const verticalFocusGap = 0;
|
|
2364
2804
|
if (column.fixed === void 0) {
|
|
2365
|
-
|
|
2366
|
-
if (
|
|
2805
|
+
const cellLeft = getScrollableColumnLeft(cell.columnIndex);
|
|
2806
|
+
if (cellLeft - nextLeft < fixedWidth) nextLeft = Math.max(0, cellLeft - fixedWidth - horizontalFocusGap);
|
|
2807
|
+
if (cellLeft + cellWidth - nextLeft > viewport.width - rightFixedWidth) nextLeft = cellLeft + cellWidth - viewport.width + rightFixedWidth + horizontalFocusGap;
|
|
2367
2808
|
}
|
|
2368
2809
|
const rowTop = (fixedHeader ? 0 : bodyTop) + cell.rowIndex * rowHeight;
|
|
2369
2810
|
const rowBottom = rowTop + rowHeight * rowSpan;
|
|
@@ -2385,7 +2826,7 @@ function Table({
|
|
|
2385
2826
|
return;
|
|
2386
2827
|
}
|
|
2387
2828
|
setEditing(cell);
|
|
2388
|
-
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
2829
|
+
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
2389
2830
|
const getCellEditKey = (cell) => `${typeof cell.rowKey}:${String(cell.rowKey)}\0${cell.columnKey}`;
|
|
2390
2831
|
const markCellEdited = (cell, previousValue, nextValue) => {
|
|
2391
2832
|
const key = getCellEditKey(cell);
|
|
@@ -2516,10 +2957,13 @@ function Table({
|
|
|
2516
2957
|
const visibleRowHeight = fixedHeader ? renderHeight - bodyTop : renderHeight;
|
|
2517
2958
|
if (rowTop < scroller.scrollTop) scroller.scrollTop = rowTop;
|
|
2518
2959
|
if (rowBottom > scroller.scrollTop + visibleRowHeight) scroller.scrollTop = rowBottom - visibleRowHeight;
|
|
2519
|
-
if (columns[columnIndex].fixed === void 0
|
|
2520
|
-
|
|
2960
|
+
if (columns[columnIndex].fixed === void 0) {
|
|
2961
|
+
const cellLeft = getScrollableColumnLeft(columnIndex);
|
|
2962
|
+
if (cellLeft < scroller.scrollLeft + fixedWidth) scroller.scrollLeft = Math.max(0, cellLeft - fixedWidth);
|
|
2963
|
+
if (cellLeft + cellWidth > scroller.scrollLeft + viewport.width - rightFixedWidth) scroller.scrollLeft = cellLeft + cellWidth - viewport.width + rightFixedWidth;
|
|
2964
|
+
}
|
|
2521
2965
|
}
|
|
2522
|
-
}, [beginEdit, bodyTop, columns, editing, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, metrics, rightFixedWidth, rowHeight, rows, selection, setSelection, viewport.width]);
|
|
2966
|
+
}, [beginEdit, bodyTop, columns, editing, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, selection, setSelection, viewport.width]);
|
|
2523
2967
|
const editorStyle = useMemo(() => {
|
|
2524
2968
|
if (!editing) return void 0;
|
|
2525
2969
|
const metric = metrics[editing.columnIndex];
|
|
@@ -2527,64 +2971,82 @@ function Table({
|
|
|
2527
2971
|
const span = getCellSpan(editing.rowIndex, editing.columnIndex);
|
|
2528
2972
|
const cellWidth = getCellDisplayWidth(editing.columnIndex, span?.colSpan ?? 1);
|
|
2529
2973
|
const cellHeight = rowHeight * (span?.rowSpan ?? 1);
|
|
2530
|
-
const cellLeft = fixedSide === "left" ?
|
|
2974
|
+
const cellLeft = fixedSide === "left" ? leftFixedOffsets.get(editing.columnIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(editing.columnIndex) ?? 0) - metric.width : getScrollableColumnLeft(editing.columnIndex) - scrollRef.current.left;
|
|
2531
2975
|
return {
|
|
2532
2976
|
left: (fixedSide ? cellLeft : Math.max(cellLeft, fixedWidth)) + 1,
|
|
2533
2977
|
top: Math.max(fixedHeader ? bodyTop : 0, bodyTop + editing.rowIndex * rowHeight - scrollRef.current.top) + 1,
|
|
2534
2978
|
width: cellWidth - 2,
|
|
2535
2979
|
height: cellHeight - 2
|
|
2536
2980
|
};
|
|
2537
|
-
}, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, metrics, rightFixedOffsets, rowHeight, viewport.width]);
|
|
2981
|
+
}, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rowHeight, viewport.width]);
|
|
2538
2982
|
const handleColumnPointerDown = useCallback2((event) => {
|
|
2539
2983
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
2540
2984
|
const localY = event.clientY - rect.top;
|
|
2541
2985
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
2542
2986
|
if (localY < headerY || localY >= headerY + headerHeight) return;
|
|
2543
|
-
const
|
|
2544
|
-
if (
|
|
2987
|
+
const resizeHit = locateHeaderResizeHit(event.clientX, event.clientY);
|
|
2988
|
+
if (resizeHit) {
|
|
2989
|
+
const { cell: resizeCell, edge: resizeEdge } = resizeHit;
|
|
2545
2990
|
event.preventDefault();
|
|
2546
2991
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2547
|
-
const
|
|
2548
|
-
const
|
|
2992
|
+
const resizeIndex = resizeCell.endIndex;
|
|
2993
|
+
const resizeIndices = resizeCell.leaf ? [resizeIndex] : Array.from({ length: resizeCell.endIndex - resizeCell.startIndex + 1 }, (_, index) => resizeCell.startIndex + index);
|
|
2994
|
+
const startWidths = resizeIndices.map((index) => metrics[index].width);
|
|
2995
|
+
const startGuideX = getHeaderCellLeft(resizeCell) + (resizeEdge === "right" ? getHeaderCellWidth(resizeCell) : 0);
|
|
2549
2996
|
columnDragRef.current = {
|
|
2550
2997
|
type: "resize",
|
|
2551
2998
|
columnIndex: resizeIndex,
|
|
2552
2999
|
startX: event.clientX,
|
|
2553
|
-
startWidth:
|
|
3000
|
+
startWidth: startWidths.reduce((total, width2) => total + width2, 0),
|
|
2554
3001
|
startGuideX,
|
|
2555
|
-
|
|
2556
|
-
|
|
3002
|
+
guideTop: headerRowOffsets[resizeCell.level] ?? 0,
|
|
3003
|
+
resizeEdge,
|
|
3004
|
+
resizeIndices,
|
|
3005
|
+
startWidths
|
|
2557
3006
|
};
|
|
2558
3007
|
suppressClickRef.current = true;
|
|
3008
|
+
setResizeGuideTop(headerRowOffsets[resizeCell.level] ?? 0);
|
|
2559
3009
|
setResizeGuideX(startGuideX);
|
|
2560
3010
|
return;
|
|
2561
3011
|
}
|
|
2562
|
-
}, [
|
|
3012
|
+
}, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerHeight, headerRowOffsets, locateHeaderResizeHit, metrics]);
|
|
2563
3013
|
const handleColumnPointerMove = useCallback2((event) => {
|
|
2564
3014
|
const drag = columnDragRef.current;
|
|
2565
3015
|
if (!drag) return;
|
|
2566
3016
|
const column = columns[drag.columnIndex];
|
|
2567
3017
|
const minWidth = getMinimumColumnWidth(column, columnDraggable);
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
const
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
3018
|
+
const pointerDelta = Math.round(event.clientX - drag.startX);
|
|
3019
|
+
const delta = drag.resizeEdge === "left" ? -pointerDelta : pointerDelta;
|
|
3020
|
+
if (drag.resizeIndices.length > 1) {
|
|
3021
|
+
const minWidths = drag.resizeIndices.map((index) => getMinimumColumnWidth(columns[index], columnDraggable));
|
|
3022
|
+
const minTotalWidth = minWidths.reduce((total, width3) => total + width3, 0);
|
|
3023
|
+
const targetTotalWidth = Math.max(minTotalWidth, drag.startWidth + delta);
|
|
3024
|
+
const ratio = drag.startWidth > 0 ? targetTotalWidth / drag.startWidth : 1;
|
|
3025
|
+
const nextWidths = drag.startWidths.map((width3, index) => Math.max(minWidths[index], Math.round(width3 * ratio)));
|
|
3026
|
+
let remainder = targetTotalWidth - nextWidths.reduce((total, width3) => total + width3, 0);
|
|
3027
|
+
for (let index = nextWidths.length - 1; index >= 0 && remainder !== 0; index -= 1) {
|
|
3028
|
+
const next = nextWidths[index] + (remainder > 0 ? 1 : -1);
|
|
3029
|
+
if (next < minWidths[index]) continue;
|
|
3030
|
+
nextWidths[index] = next;
|
|
3031
|
+
remainder += remainder > 0 ? -1 : 1;
|
|
3032
|
+
}
|
|
3033
|
+
drag.resizeIndices.forEach((columnIndex, index) => {
|
|
3034
|
+
resizeColumn(columns[columnIndex].key, nextWidths[index]);
|
|
3035
|
+
});
|
|
3036
|
+
setResizeGuideX(drag.startGuideX + (drag.resizeEdge === "left" ? drag.startWidth - targetTotalWidth : targetTotalWidth - drag.startWidth));
|
|
2576
3037
|
return;
|
|
2577
3038
|
}
|
|
2578
3039
|
const width2 = Math.max(minWidth, Math.round(drag.startWidth + delta));
|
|
2579
|
-
|
|
2580
|
-
setResizeGuideX(drag.startGuideX + width2 - drag.startWidth);
|
|
2581
|
-
}, [columnDraggable, columns,
|
|
3040
|
+
resizeColumn(column.key, width2);
|
|
3041
|
+
setResizeGuideX(drag.startGuideX + (drag.resizeEdge === "left" ? drag.startWidth - width2 : width2 - drag.startWidth));
|
|
3042
|
+
}, [columnDraggable, columns, resizeColumn]);
|
|
2582
3043
|
const handleColumnPointerUp = useCallback2((event) => {
|
|
2583
3044
|
const drag = columnDragRef.current;
|
|
2584
3045
|
if (!drag) return;
|
|
2585
3046
|
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2586
3047
|
columnDragRef.current = null;
|
|
2587
3048
|
setResizeGuideX(null);
|
|
3049
|
+
setResizeGuideTop(0);
|
|
2588
3050
|
}, []);
|
|
2589
3051
|
const queueSortStateChange = useCallback2((next) => {
|
|
2590
3052
|
setDisplaySortState(next);
|
|
@@ -2597,7 +3059,7 @@ function Table({
|
|
|
2597
3059
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
2598
3060
|
const column = columns[columnIndex];
|
|
2599
3061
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
2600
|
-
const top = (
|
|
3062
|
+
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
2601
3063
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2602
3064
|
let right = left + metrics[columnIndex].width - (visibleActions.drag ? 18 : 4);
|
|
2603
3065
|
const icons = [];
|
|
@@ -2623,44 +3085,87 @@ function Table({
|
|
|
2623
3085
|
}
|
|
2624
3086
|
return icons;
|
|
2625
3087
|
};
|
|
2626
|
-
const
|
|
2627
|
-
|
|
2628
|
-
const { columnIndex, action } = visibleHeaderTooltip;
|
|
2629
|
-
const column = columns[columnIndex];
|
|
3088
|
+
const createHeaderTooltip = useCallback2((action, columnIndex, cell) => {
|
|
3089
|
+
const column = cell?.column ?? columns[columnIndex];
|
|
2630
3090
|
if (!column) return null;
|
|
2631
|
-
const
|
|
2632
|
-
const
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3091
|
+
const cellLeft = cell ? getHeaderCellLeft(cell) : getDisplayedColumnLeft(columnIndex);
|
|
3092
|
+
const cellWidth = cell ? getHeaderCellWidth(cell) : metrics[columnIndex]?.width ?? 0;
|
|
3093
|
+
const level = cell?.level ?? headerDepth - 1;
|
|
3094
|
+
const rowTop = (fixedHeader ? 0 : -scrollPosition.top) + (headerRowOffsets[level] ?? 0);
|
|
3095
|
+
const rowHeight2 = headerRowHeights[level] ?? baseHeaderHeight;
|
|
3096
|
+
let anchorX = cellLeft + cellWidth / 2;
|
|
3097
|
+
let anchorLeft = cellLeft;
|
|
3098
|
+
let label = column.title;
|
|
2636
3099
|
if (action === "title") {
|
|
2637
|
-
const
|
|
2638
|
-
const
|
|
2639
|
-
|
|
2640
|
-
const
|
|
2641
|
-
const
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
3100
|
+
const canvas = canvasRef.current;
|
|
3101
|
+
const context = canvas?.getContext("2d");
|
|
3102
|
+
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3103
|
+
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3104
|
+
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3105
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * 18 : columnDraggable ? 18 : 0;
|
|
3106
|
+
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3107
|
+
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3108
|
+
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
3109
|
+
if (column.align === "right") {
|
|
3110
|
+
anchorX = cellLeft + contentWidth2 - 10;
|
|
3111
|
+
anchorLeft = anchorX - textWidth;
|
|
3112
|
+
} else if (column.align === "center") {
|
|
3113
|
+
anchorX = cellLeft + contentWidth2 / 2 + textWidth / 2;
|
|
3114
|
+
anchorLeft = cellLeft + contentWidth2 / 2 - textWidth / 2;
|
|
3115
|
+
} else {
|
|
3116
|
+
anchorLeft = cellLeft + 10;
|
|
3117
|
+
anchorX = anchorLeft + textWidth;
|
|
3118
|
+
}
|
|
2645
3119
|
} else if (action === "drag") {
|
|
2646
|
-
anchorX =
|
|
3120
|
+
anchorX = cellLeft + cellWidth;
|
|
2647
3121
|
anchorLeft = anchorX;
|
|
2648
3122
|
label = labels.dragColumn;
|
|
2649
3123
|
} else if (action === "sort") {
|
|
2650
3124
|
const direction = displaySortState?.columnKey === column.key ? displaySortState.direction : null;
|
|
2651
3125
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
2652
|
-
|
|
2653
|
-
|
|
3126
|
+
anchorX = cellLeft + cellWidth - 22;
|
|
3127
|
+
anchorLeft = anchorX;
|
|
3128
|
+
} else if (action === "filter") {
|
|
2654
3129
|
const value = filterValues[column.key];
|
|
2655
3130
|
label = value ? labels.filterWithValue(value) : labels.filter;
|
|
3131
|
+
anchorX = cellLeft + cellWidth - 40;
|
|
3132
|
+
anchorLeft = anchorX;
|
|
2656
3133
|
}
|
|
2657
3134
|
const placement = anchorX + 328 > viewport.width ? "left" : "right";
|
|
2658
3135
|
return {
|
|
3136
|
+
key: `${action}:${cell ? `cell:${cell.key}:${cell.level}` : `column:${column.key}`}:${Math.round(anchorX)}:${Math.round(rowTop)}`,
|
|
3137
|
+
columnIndex,
|
|
3138
|
+
action,
|
|
2659
3139
|
left: placement === "right" ? anchorX + 8 : Math.max(8, anchorLeft - 8),
|
|
2660
|
-
top:
|
|
3140
|
+
top: rowTop + rowHeight2 / 2,
|
|
2661
3141
|
label,
|
|
2662
3142
|
placement
|
|
2663
3143
|
};
|
|
3144
|
+
}, [baseHeaderHeight, columnDraggable, columns, displaySortState, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, viewport.width]);
|
|
3145
|
+
const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
|
|
3146
|
+
const canvas = canvasRef.current;
|
|
3147
|
+
if (!canvas) return false;
|
|
3148
|
+
const rect = canvas.getBoundingClientRect();
|
|
3149
|
+
const localX = clientX - rect.left;
|
|
3150
|
+
const localY = clientY - rect.top;
|
|
3151
|
+
const column = cell.column;
|
|
3152
|
+
const cellLeft = getHeaderCellLeft(cell);
|
|
3153
|
+
const cellWidth = getHeaderCellWidth(cell);
|
|
3154
|
+
const rowTop = (fixedHeader ? 0 : -scrollRef.current.top) + (headerRowOffsets[cell.level] ?? 0);
|
|
3155
|
+
const context = canvas.getContext("2d");
|
|
3156
|
+
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3157
|
+
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3158
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3159
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * 18 : columnDraggable ? 18 : 0;
|
|
3160
|
+
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3161
|
+
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3162
|
+
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
3163
|
+
const textTop = rowTop + 8;
|
|
3164
|
+
return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
|
|
3165
|
+
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerRowOffsets]);
|
|
3166
|
+
const headerTooltip = (() => {
|
|
3167
|
+
if (!visibleHeaderTooltip) return null;
|
|
3168
|
+
return visibleHeaderTooltip;
|
|
2664
3169
|
})();
|
|
2665
3170
|
const getRangeBounds = () => selectionRange ? {
|
|
2666
3171
|
rowStart: Math.min(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex),
|
|
@@ -2719,7 +3224,7 @@ function Table({
|
|
|
2719
3224
|
}, 1800);
|
|
2720
3225
|
};
|
|
2721
3226
|
const showHeaderTooltipAfterDelay = (next) => {
|
|
2722
|
-
const nextKey = next ?
|
|
3227
|
+
const nextKey = next ? next.key : "";
|
|
2723
3228
|
if (nextKey && pendingHeaderTooltipKeyRef.current === nextKey) return;
|
|
2724
3229
|
pendingHeaderTooltipKeyRef.current = nextKey;
|
|
2725
3230
|
if (headerTooltipTimerRef.current !== null) clearTimeout(headerTooltipTimerRef.current);
|
|
@@ -2967,12 +3472,14 @@ function Table({
|
|
|
2967
3472
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
2968
3473
|
const column = columns[columnIndex];
|
|
2969
3474
|
const currentScrollTop = scrollRef.current.top;
|
|
3475
|
+
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3476
|
+
const leafTop = headerTop + headerLeafTop;
|
|
2970
3477
|
if (column.rowNumber) {
|
|
2971
3478
|
return /* @__PURE__ */ jsx7(
|
|
2972
3479
|
"div",
|
|
2973
3480
|
{
|
|
2974
3481
|
className: "rvg-header-title",
|
|
2975
|
-
style: { left, top:
|
|
3482
|
+
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
2976
3483
|
children: /* @__PURE__ */ jsx7("span", { children: column.title })
|
|
2977
3484
|
},
|
|
2978
3485
|
column.key
|
|
@@ -2986,7 +3493,7 @@ function Table({
|
|
|
2986
3493
|
"div",
|
|
2987
3494
|
{
|
|
2988
3495
|
className: "rvg-header-selection-icon",
|
|
2989
|
-
style: { left, top:
|
|
3496
|
+
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight },
|
|
2990
3497
|
children: /* @__PURE__ */ jsx7(SelectionIcon, { checked: allSelected, indeterminate })
|
|
2991
3498
|
},
|
|
2992
3499
|
column.key
|
|
@@ -2999,11 +3506,13 @@ function Table({
|
|
|
2999
3506
|
"div",
|
|
3000
3507
|
{
|
|
3001
3508
|
className: "rvg-header-title is-custom",
|
|
3509
|
+
"data-level": headerDepth - 1,
|
|
3510
|
+
"data-measure-key": column.key,
|
|
3002
3511
|
style: {
|
|
3003
3512
|
left,
|
|
3004
|
-
top:
|
|
3513
|
+
top: leafTop,
|
|
3005
3514
|
width: Math.max(0, metrics[columnIndex].width - actionWidth),
|
|
3006
|
-
height:
|
|
3515
|
+
height: headerLeafHeight,
|
|
3007
3516
|
justifyContent: column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start",
|
|
3008
3517
|
textAlign: column.align === "right" ? "right" : column.align === "center" ? "center" : "left"
|
|
3009
3518
|
},
|
|
@@ -3011,8 +3520,10 @@ function Table({
|
|
|
3011
3520
|
"span",
|
|
3012
3521
|
{
|
|
3013
3522
|
ref: (node) => {
|
|
3014
|
-
if (node)
|
|
3015
|
-
|
|
3523
|
+
if (node) {
|
|
3524
|
+
customHeaderContentRefs.current.set(column.key, node);
|
|
3525
|
+
requestAnimationFrame(measureCustomHeaderHeight);
|
|
3526
|
+
} else customHeaderContentRefs.current.delete(column.key);
|
|
3016
3527
|
},
|
|
3017
3528
|
children: column.renderHeader(column)
|
|
3018
3529
|
}
|
|
@@ -3023,6 +3534,61 @@ function Table({
|
|
|
3023
3534
|
}
|
|
3024
3535
|
return null;
|
|
3025
3536
|
};
|
|
3537
|
+
const renderGroupedHeaderCell = (cell) => {
|
|
3538
|
+
const startMetric = metrics[cell.startIndex];
|
|
3539
|
+
const endMetric = metrics[cell.endIndex];
|
|
3540
|
+
if (!startMetric || !endMetric) return null;
|
|
3541
|
+
const column = cell.column;
|
|
3542
|
+
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
3543
|
+
const currentScrollTop = scrollRef.current.top;
|
|
3544
|
+
const rowHeightForLevel = headerRowHeights[cell.level] ?? baseHeaderHeight;
|
|
3545
|
+
const headerTop = (fixedHeader ? 0 : -currentScrollTop) + (headerRowOffsets[cell.level] ?? 0);
|
|
3546
|
+
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3547
|
+
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3548
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
3549
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * 18 : columnDraggable && !cell.leaf ? 18 : 0;
|
|
3550
|
+
return /* @__PURE__ */ jsxs7(
|
|
3551
|
+
"div",
|
|
3552
|
+
{
|
|
3553
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}`,
|
|
3554
|
+
"data-level": cell.level,
|
|
3555
|
+
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3556
|
+
style: {
|
|
3557
|
+
left,
|
|
3558
|
+
top: headerTop,
|
|
3559
|
+
width: width2,
|
|
3560
|
+
height: rowHeightForLevel,
|
|
3561
|
+
paddingRight: cell.leaf ? actionWidth + 10 : 10,
|
|
3562
|
+
justifyContent: column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start",
|
|
3563
|
+
textAlign: column.align === "right" ? "right" : column.align === "center" ? "center" : "left"
|
|
3564
|
+
},
|
|
3565
|
+
children: [
|
|
3566
|
+
/* @__PURE__ */ jsx7(
|
|
3567
|
+
"span",
|
|
3568
|
+
{
|
|
3569
|
+
ref: (node) => {
|
|
3570
|
+
if (!column.renderHeader) return;
|
|
3571
|
+
const key = `group:${cell.key}:${cell.level}`;
|
|
3572
|
+
if (node) {
|
|
3573
|
+
customHeaderContentRefs.current.set(key, node);
|
|
3574
|
+
requestAnimationFrame(measureCustomHeaderHeight);
|
|
3575
|
+
} else customHeaderContentRefs.current.delete(key);
|
|
3576
|
+
},
|
|
3577
|
+
children: column.renderHeader ? column.renderHeader(column) : column.title
|
|
3578
|
+
}
|
|
3579
|
+
),
|
|
3580
|
+
!cell.leaf && columnDraggable && /* @__PURE__ */ jsx7(
|
|
3581
|
+
HeaderDragIcon,
|
|
3582
|
+
{
|
|
3583
|
+
className: `rvg-header-icon rvg-header-drag-icon${hoveredHeaderAction?.columnIndex === cell.startIndex && hoveredHeaderAction.action === "drag" ? " is-hovered" : ""}`,
|
|
3584
|
+
style: { left: width2 - 16, top: (rowHeightForLevel - 14) / 2 }
|
|
3585
|
+
}
|
|
3586
|
+
)
|
|
3587
|
+
]
|
|
3588
|
+
},
|
|
3589
|
+
`group:${cell.key}:${cell.level}`
|
|
3590
|
+
);
|
|
3591
|
+
};
|
|
3026
3592
|
const rangeHandlePosition = (() => {
|
|
3027
3593
|
if (!rangeSelection) return null;
|
|
3028
3594
|
const bounds = getRangeBounds();
|
|
@@ -3214,15 +3780,19 @@ function Table({
|
|
|
3214
3780
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
3215
3781
|
const columnIndex = locateColumn(event.clientX);
|
|
3216
3782
|
const inHeader = localY >= headerY && localY < headerY + headerHeight;
|
|
3217
|
-
const
|
|
3218
|
-
const
|
|
3219
|
-
const
|
|
3220
|
-
const
|
|
3783
|
+
const inLeafHeader = inHeader && localY >= headerY + headerLeafTop;
|
|
3784
|
+
const hoveredHeaderCell = inHeader ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
3785
|
+
const hoveredAction = inLeafHeader ? locateHeaderAction(event.clientX, columnIndex) : null;
|
|
3786
|
+
const hoveredDragHandle = Boolean(hoveredHeaderCell && locateHeaderCellDragHandle(event.clientX, hoveredHeaderCell));
|
|
3787
|
+
const hoveredDragColumnIndex = hoveredHeaderCell?.startIndex ?? columnIndex;
|
|
3788
|
+
const hoveredTitle = inHeader && !hoveredAction && !hoveredDragHandle && hoveredHeaderCell && Boolean(hoveredHeaderCell.column.title) && isPointerOnHeaderTitle(event.clientX, event.clientY, hoveredHeaderCell) && (tooltipConfig.header || hoveredHeaderCell.leaf && isHeaderTitleTruncated(hoveredHeaderCell.startIndex));
|
|
3789
|
+
const nextHover = hoveredAction ? { columnIndex, action: hoveredAction } : hoveredDragHandle ? { columnIndex: hoveredDragColumnIndex, action: "drag" } : hoveredTitle ? { columnIndex: hoveredHeaderCell.startIndex, action: "title" } : null;
|
|
3790
|
+
const nextTooltip = hoveredAction && hoveredHeaderCell ? createHeaderTooltip(hoveredAction, columnIndex, hoveredHeaderCell) : hoveredDragHandle && hoveredHeaderCell ? createHeaderTooltip("drag", hoveredDragColumnIndex, hoveredHeaderCell) : hoveredTitle && hoveredHeaderCell ? createHeaderTooltip("title", hoveredHeaderCell.startIndex, hoveredHeaderCell) : null;
|
|
3221
3791
|
const previousHover = hoveredHeaderActionRef.current;
|
|
3222
3792
|
if (previousHover?.columnIndex !== nextHover?.columnIndex || previousHover?.action !== nextHover?.action) {
|
|
3223
3793
|
hoveredHeaderActionRef.current = nextHover;
|
|
3224
3794
|
setHoveredHeaderAction(nextHover);
|
|
3225
|
-
showHeaderTooltipAfterDelay(
|
|
3795
|
+
showHeaderTooltipAfterDelay(nextTooltip);
|
|
3226
3796
|
scheduleDraw();
|
|
3227
3797
|
}
|
|
3228
3798
|
if (inHeader) {
|
|
@@ -3246,8 +3816,8 @@ function Table({
|
|
|
3246
3816
|
if (annotation?.content.trim()) {
|
|
3247
3817
|
const cellLeft = getDisplayedColumnLeft(cell.columnIndex);
|
|
3248
3818
|
const cellTop = bodyTop + cell.rowIndex * rowHeight - scrollRef.current.top;
|
|
3249
|
-
const
|
|
3250
|
-
showCellTooltip(
|
|
3819
|
+
const nextTooltip2 = { rowIndex: cell.rowIndex, columnIndex: cell.columnIndex, left: cellLeft + metrics[cell.columnIndex].width + 6, top: cellTop + rowHeight / 2, label: annotation.content, color: annotation.color, annotation: true };
|
|
3820
|
+
showCellTooltip(nextTooltip2);
|
|
3251
3821
|
} else {
|
|
3252
3822
|
const label = getCellLabel(cell.rowIndex, cell.columnIndex);
|
|
3253
3823
|
const context = event.currentTarget.getContext("2d");
|
|
@@ -3274,7 +3844,7 @@ function Table({
|
|
|
3274
3844
|
showCellTooltipAfterDelay(null);
|
|
3275
3845
|
} else {
|
|
3276
3846
|
const placement = textRight + 330 > viewport.width ? "left" : "right";
|
|
3277
|
-
const
|
|
3847
|
+
const nextTooltip2 = {
|
|
3278
3848
|
rowIndex: cell.rowIndex,
|
|
3279
3849
|
columnIndex: cell.columnIndex,
|
|
3280
3850
|
left: placement === "right" ? textRight + 16 : Math.max(8, textLeft - 16),
|
|
@@ -3282,13 +3852,13 @@ function Table({
|
|
|
3282
3852
|
label,
|
|
3283
3853
|
placement
|
|
3284
3854
|
};
|
|
3285
|
-
showCellTooltipAfterDelay(
|
|
3855
|
+
showCellTooltipAfterDelay(nextTooltip2);
|
|
3286
3856
|
}
|
|
3287
3857
|
}
|
|
3288
3858
|
}
|
|
3289
3859
|
}
|
|
3290
3860
|
}
|
|
3291
|
-
const cursor = inHeader &&
|
|
3861
|
+
const cursor = inHeader && locateHeaderResizeCell(event.clientX, event.clientY) ? "col-resize" : hoveredAction ? "pointer" : hoveredDragHandle ? "move" : columnIndex >= 0 && columns[columnIndex].rowSelection ? "pointer" : !inHeader && rowDraggable && columnIndex >= 0 && columns[columnIndex].rowDragHandle ? "move" : "default";
|
|
3292
3862
|
if (event.currentTarget.style.cursor !== cursor) event.currentTarget.style.cursor = cursor;
|
|
3293
3863
|
},
|
|
3294
3864
|
onMouseLeave: (event) => {
|
|
@@ -3331,6 +3901,7 @@ function Table({
|
|
|
3331
3901
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
3332
3902
|
if (localY >= headerY && localY < headerY + headerHeight) {
|
|
3333
3903
|
clickedCellRef.current = null;
|
|
3904
|
+
if (localY < headerY + headerLeafTop) return;
|
|
3334
3905
|
const columnIndex = locateColumn(event.clientX);
|
|
3335
3906
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
3336
3907
|
if (action === "sort") {
|
|
@@ -3392,21 +3963,30 @@ function Table({
|
|
|
3392
3963
|
className: "rvg-text-scroll-content",
|
|
3393
3964
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
3394
3965
|
children: [
|
|
3395
|
-
columns.map((column, columnIndex) => column.fixed ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ jsx7("span", { children: renderHeaderTitle(columnIndex,
|
|
3966
|
+
columns.map((column, columnIndex) => column.fixed || columnIndex < utilityColumnCount || headerDepth > 1 ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ jsx7("span", { children: renderHeaderTitle(columnIndex, getScrollableColumnLeft(columnIndex)) }, column.key) : null),
|
|
3967
|
+
headerCells.map((cell) => {
|
|
3968
|
+
if (columns[cell.startIndex]?.fixed) return null;
|
|
3969
|
+
if (cell.endIndex < domRange.columnStart || cell.startIndex >= domRange.columnEnd) return null;
|
|
3970
|
+
return renderGroupedHeaderCell(cell);
|
|
3971
|
+
}),
|
|
3396
3972
|
/* @__PURE__ */ jsx7("div", { className: "rvg-body-text-clip", style: { top: fixedHeader ? bodyTop : 0, bottom: 0 }, children: Array.from({ length: domRange.rowEnd - domRange.rowStart }, (_, offset) => domRange.rowStart + offset).flatMap((rowIndex) => columns.map((column, columnIndex) => {
|
|
3397
3973
|
if (column.fixed || columnIndex < domRange.columnStart || columnIndex >= domRange.columnEnd) return null;
|
|
3398
|
-
return renderCellText(rowIndex, columnIndex,
|
|
3974
|
+
return renderCellText(rowIndex, columnIndex, getScrollableColumnLeft(columnIndex));
|
|
3399
3975
|
})) })
|
|
3400
3976
|
]
|
|
3401
3977
|
}
|
|
3402
3978
|
) }),
|
|
3403
3979
|
/* @__PURE__ */ jsx7("div", { className: "rvg-body-text-clip", style: { top: fixedHeader ? bodyTop : 0, bottom: 0 }, children: Array.from({ length: domRange.rowEnd - domRange.rowStart }, (_, offset) => domRange.rowStart + offset).flatMap((rowIndex) => columns.map((column, columnIndex) => {
|
|
3404
3980
|
if (!column.fixed) return null;
|
|
3405
|
-
const left = column.fixed === "left" ?
|
|
3981
|
+
const left = column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width;
|
|
3406
3982
|
return renderCellText(rowIndex, columnIndex, left);
|
|
3407
3983
|
})) }),
|
|
3408
|
-
columns.map((column, columnIndex) => column.fixed === "left" ? renderHeaderTitle(columnIndex, metrics[columnIndex].left) : null),
|
|
3409
|
-
|
|
3984
|
+
columns.map((column, columnIndex) => columnIndex < utilityColumnCount || headerDepth === 1 && (column.fixed === "left" || column.fixed === "right") ? renderHeaderTitle(columnIndex, column.fixed === "right" ? viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width : column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : getScrollableColumnLeft(columnIndex)) : null),
|
|
3985
|
+
headerCells.map((cell) => columns[cell.startIndex]?.fixed ? renderGroupedHeaderCell(cell) : null),
|
|
3986
|
+
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
3987
|
+
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-shadow is-right", style: { right: rightFixedWidth } }),
|
|
3988
|
+
hasVerticalBorders && fixedWidth > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-border is-left", style: { left: fixedWidth - 1 } }),
|
|
3989
|
+
hasVerticalBorders && rightFixedWidth > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-border is-right", style: { right: rightFixedWidth } })
|
|
3410
3990
|
] }),
|
|
3411
3991
|
/* @__PURE__ */ jsx7("div", { className: "rvg-spacer", style: { width: contentWidth, height: contentHeight + bodyTop, marginTop: -renderHeight } })
|
|
3412
3992
|
] }),
|
|
@@ -3414,18 +3994,18 @@ function Table({
|
|
|
3414
3994
|
"div",
|
|
3415
3995
|
{
|
|
3416
3996
|
className: `rvg-summary-row is-${summaryPosition}${hasVerticalBorders ? "" : " is-vertical-borderless"}`,
|
|
3417
|
-
style: { height: rowHeight, top: summaryPosition === "top" ? headerHeight : void 0 },
|
|
3997
|
+
style: { height: rowHeight, top: summaryPosition === "top" ? fixedHeader ? headerHeight : headerHeight - currentScroll.top : void 0 },
|
|
3418
3998
|
children: [
|
|
3419
3999
|
/* @__PURE__ */ jsx7("div", { className: "rvg-summary-scroll-clip", style: { left: fixedWidth, right: rightFixedWidth }, children: /* @__PURE__ */ jsx7(
|
|
3420
4000
|
"div",
|
|
3421
4001
|
{
|
|
3422
4002
|
className: "rvg-summary-scroll-content",
|
|
3423
4003
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
3424
|
-
children: columns.map((column, columnIndex) => column.fixed ? null : renderSummaryCell(columnIndex,
|
|
4004
|
+
children: columns.map((column, columnIndex) => column.fixed ? null : renderSummaryCell(columnIndex, getScrollableColumnLeft(columnIndex)))
|
|
3425
4005
|
}
|
|
3426
4006
|
) }),
|
|
3427
4007
|
/* @__PURE__ */ jsxs7("div", { className: "rvg-summary-fixed-layer", children: [
|
|
3428
|
-
columns.map((column, columnIndex) => column.fixed === "left" ? renderSummaryCell(columnIndex,
|
|
4008
|
+
columns.map((column, columnIndex) => column.fixed === "left" ? renderSummaryCell(columnIndex, leftFixedOffsets.get(columnIndex) ?? 0) : null),
|
|
3429
4009
|
columns.map((column, columnIndex) => column.fixed === "right" ? renderSummaryCell(columnIndex, viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width) : null)
|
|
3430
4010
|
] }),
|
|
3431
4011
|
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-summary-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
@@ -3442,11 +4022,11 @@ function Table({
|
|
|
3442
4022
|
ref: scrollingHeaderIconsRef,
|
|
3443
4023
|
className: "rvg-header-icon-layer rvg-header-icon-layer-scroll",
|
|
3444
4024
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-scrollRef.current.left}px)` },
|
|
3445
|
-
children: columns.map((column, index) => column.fixed ? null : /* @__PURE__ */ jsx7("span", { children: renderHeaderIcons(index,
|
|
4025
|
+
children: columns.map((column, index) => column.fixed ? null : /* @__PURE__ */ jsx7("span", { children: renderHeaderIcons(index, getScrollableColumnLeft(index)) }, column.key))
|
|
3446
4026
|
}
|
|
3447
4027
|
) }),
|
|
3448
4028
|
/* @__PURE__ */ jsxs7("div", { className: "rvg-header-icon-layer", children: [
|
|
3449
|
-
columns.map((column, index) => column.fixed === "left" ? /* @__PURE__ */ jsx7("span", { children: renderHeaderIcons(index,
|
|
4029
|
+
columns.map((column, index) => column.fixed === "left" ? /* @__PURE__ */ jsx7("span", { children: renderHeaderIcons(index, leftFixedOffsets.get(index) ?? 0) }, column.key) : null),
|
|
3450
4030
|
columns.map((column, index) => column.fixed === "right" ? /* @__PURE__ */ jsx7("span", { children: renderHeaderIcons(index, viewport.width - (rightFixedOffsets.get(index) ?? 0) - metrics[index].width) }, column.key) : null)
|
|
3451
4031
|
] })
|
|
3452
4032
|
] }),
|
|
@@ -3723,12 +4303,40 @@ function Table({
|
|
|
3723
4303
|
] })
|
|
3724
4304
|
] }) }),
|
|
3725
4305
|
toast && /* @__PURE__ */ jsx7("div", { className: `rvg-toast is-${toast.type}`, role: "status", children: toast.message }),
|
|
4306
|
+
/* @__PURE__ */ jsx7(
|
|
4307
|
+
"div",
|
|
4308
|
+
{
|
|
4309
|
+
ref: verticalScrollbarRef,
|
|
4310
|
+
className: "rvg-vertical-scrollbar",
|
|
4311
|
+
onPointerEnter: () => keepCustomScrollbarVisible("vertical"),
|
|
4312
|
+
onPointerLeave: () => releaseCustomScrollbarVisible("vertical"),
|
|
4313
|
+
onPointerDown: handleVerticalScrollbarPointerDown,
|
|
4314
|
+
onPointerMove: handleVerticalScrollbarPointerMove,
|
|
4315
|
+
onPointerUp: handleVerticalScrollbarPointerUp,
|
|
4316
|
+
onPointerCancel: handleVerticalScrollbarPointerUp,
|
|
4317
|
+
children: /* @__PURE__ */ jsx7("div", { ref: verticalScrollbarThumbRef, className: "rvg-vertical-scrollbar-thumb" })
|
|
4318
|
+
}
|
|
4319
|
+
),
|
|
4320
|
+
/* @__PURE__ */ jsx7(
|
|
4321
|
+
"div",
|
|
4322
|
+
{
|
|
4323
|
+
ref: horizontalScrollbarRef,
|
|
4324
|
+
className: "rvg-horizontal-scrollbar",
|
|
4325
|
+
onPointerEnter: () => keepCustomScrollbarVisible("horizontal"),
|
|
4326
|
+
onPointerLeave: () => releaseCustomScrollbarVisible("horizontal"),
|
|
4327
|
+
onPointerDown: handleHorizontalScrollbarPointerDown,
|
|
4328
|
+
onPointerMove: handleHorizontalScrollbarPointerMove,
|
|
4329
|
+
onPointerUp: handleHorizontalScrollbarPointerUp,
|
|
4330
|
+
onPointerCancel: handleHorizontalScrollbarPointerUp,
|
|
4331
|
+
children: /* @__PURE__ */ jsx7("div", { ref: horizontalScrollbarThumbRef, className: "rvg-horizontal-scrollbar-thumb" })
|
|
4332
|
+
}
|
|
4333
|
+
),
|
|
3726
4334
|
/* @__PURE__ */ jsx7("div", { ref: dragGuideRef, className: "rvg-column-guide" }),
|
|
3727
4335
|
resizeGuideX !== null && /* @__PURE__ */ jsx7(
|
|
3728
4336
|
"div",
|
|
3729
4337
|
{
|
|
3730
4338
|
className: "rvg-column-guide is-resizing",
|
|
3731
|
-
style: { display: "block", transform: `translateX(${Math.round(resizeGuideX)}px)` }
|
|
4339
|
+
style: { display: "block", top: resizeGuideTop, transform: `translateX(${Math.round(resizeGuideX)}px)` }
|
|
3732
4340
|
}
|
|
3733
4341
|
),
|
|
3734
4342
|
/* @__PURE__ */ jsx7("div", { ref: rowDragGuideRef, className: "rvg-row-guide" }),
|