@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.cjs
CHANGED
|
@@ -893,6 +893,8 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
893
893
|
}
|
|
894
894
|
function paintGrid(options) {
|
|
895
895
|
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;
|
|
896
|
+
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
897
|
+
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
896
898
|
const colors = { ...COLORS, ...options.colors };
|
|
897
899
|
const bodyTop = options.bodyTop ?? headerHeight;
|
|
898
900
|
const getCellSpan = (rowIndex, columnIndex) => options.cellSpans.get(getCellCoordKey(rowIndex, columnIndex));
|
|
@@ -909,9 +911,16 @@ function paintGrid(options) {
|
|
|
909
911
|
ctx.fillRect(0, 0, width, height);
|
|
910
912
|
ctx.font = "13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
911
913
|
ctx.textBaseline = "middle";
|
|
912
|
-
const leftFixedWidth = columns.reduce((value, column, index) => column.fixed === "left" ?
|
|
914
|
+
const leftFixedWidth = columns.reduce((value, column, index) => column.fixed === "left" ? value + metrics[index].width : value, 0);
|
|
913
915
|
const rightFixedWidth = columns.reduce((value, column, index) => column.fixed === "right" ? value + metrics[index].width : value, 0);
|
|
914
916
|
const rightFixedLeft = width - rightFixedWidth;
|
|
917
|
+
const leftOffsets = /* @__PURE__ */ new Map();
|
|
918
|
+
let leftOffset = 0;
|
|
919
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
920
|
+
if (columns[index].fixed !== "left") continue;
|
|
921
|
+
leftOffsets.set(index, leftOffset);
|
|
922
|
+
leftOffset += metrics[index].width;
|
|
923
|
+
}
|
|
915
924
|
const rightOffsets = /* @__PURE__ */ new Map();
|
|
916
925
|
let rightOffset = 0;
|
|
917
926
|
for (let index = columns.length - 1; index >= 0; index -= 1) {
|
|
@@ -919,8 +928,14 @@ function paintGrid(options) {
|
|
|
919
928
|
rightOffsets.set(index, rightOffset);
|
|
920
929
|
rightOffset += metrics[index].width;
|
|
921
930
|
}
|
|
931
|
+
const scrollableLefts = /* @__PURE__ */ new Map();
|
|
932
|
+
let scrollableLeft = leftFixedWidth;
|
|
933
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
934
|
+
scrollableLefts.set(index, scrollableLeft);
|
|
935
|
+
if (columns[index].fixed === void 0) scrollableLeft += metrics[index].width;
|
|
936
|
+
}
|
|
922
937
|
const getColumnX = (index) => {
|
|
923
|
-
return columns[index].fixed === "left" ?
|
|
938
|
+
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;
|
|
924
939
|
};
|
|
925
940
|
const paintBodyColumns = (layer) => {
|
|
926
941
|
const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
|
|
@@ -1070,7 +1085,7 @@ function paintGrid(options) {
|
|
|
1070
1085
|
if (!verticalBorderless) ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1071
1086
|
ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
1072
1087
|
const column = columns[columnIndex];
|
|
1073
|
-
if (!column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1088
|
+
if (headerLeafTop === 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1074
1089
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1075
1090
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1076
1091
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
@@ -1087,11 +1102,11 @@ function paintGrid(options) {
|
|
|
1087
1102
|
const textX = titleAlign === "right" ? x + contentWidth - padding : titleAlign === "center" ? x + centeredTextX : x + padding;
|
|
1088
1103
|
ctx.save();
|
|
1089
1104
|
ctx.beginPath();
|
|
1090
|
-
ctx.rect(x + 2, headerY + 1, Math.max(0, clipWidth - 4),
|
|
1105
|
+
ctx.rect(x + 2, headerY + headerLeafTop + 1, Math.max(0, clipWidth - 4), headerLeafHeight - 2);
|
|
1091
1106
|
ctx.clip();
|
|
1092
1107
|
ctx.fillStyle = colors.muted;
|
|
1093
1108
|
ctx.textAlign = titleAlign === "right" ? "right" : titleAlign === "center" ? "center" : "left";
|
|
1094
|
-
ctx.fillText(title, textX, headerY +
|
|
1109
|
+
ctx.fillText(title, textX, headerY + headerLeafTop + headerLeafHeight / 2);
|
|
1095
1110
|
ctx.restore();
|
|
1096
1111
|
}
|
|
1097
1112
|
}
|
|
@@ -1099,22 +1114,6 @@ function paintGrid(options) {
|
|
|
1099
1114
|
paintHeaderColumns("scroll");
|
|
1100
1115
|
paintHeaderColumns("left");
|
|
1101
1116
|
paintHeaderColumns("right");
|
|
1102
|
-
if (leftFixedWidth > 0 && scrollLeft > 0) {
|
|
1103
|
-
const shadowWidth = 10;
|
|
1104
|
-
const shadow = ctx.createLinearGradient(leftFixedWidth, 0, leftFixedWidth + shadowWidth, 0);
|
|
1105
|
-
shadow.addColorStop(0, "rgba(5, 5, 5, 0.06)");
|
|
1106
|
-
shadow.addColorStop(1, "rgba(5, 5, 5, 0)");
|
|
1107
|
-
ctx.fillStyle = shadow;
|
|
1108
|
-
ctx.fillRect(leftFixedWidth, 0, shadowWidth, height);
|
|
1109
|
-
}
|
|
1110
|
-
if (rightFixedWidth > 0 && scrollLeft < (metrics[metrics.length - 1]?.right ?? 0) - width) {
|
|
1111
|
-
const shadowWidth = 10;
|
|
1112
|
-
const shadow = ctx.createLinearGradient(rightFixedLeft - shadowWidth, 0, rightFixedLeft, 0);
|
|
1113
|
-
shadow.addColorStop(0, "rgba(5, 5, 5, 0)");
|
|
1114
|
-
shadow.addColorStop(1, "rgba(5, 5, 5, 0.06)");
|
|
1115
|
-
ctx.fillStyle = shadow;
|
|
1116
|
-
ctx.fillRect(rightFixedLeft - shadowWidth, 0, shadowWidth, height);
|
|
1117
|
-
}
|
|
1118
1117
|
if (rightFixedWidth > 0 && !verticalBorderless) {
|
|
1119
1118
|
ctx.fillStyle = colors.grid;
|
|
1120
1119
|
ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
|
|
@@ -1266,6 +1265,45 @@ var getRowNumberColumnWidth = (rowCount) => {
|
|
|
1266
1265
|
const digits = String(Math.max(1, rowCount)).length;
|
|
1267
1266
|
return digits <= 4 ? 44 : 44 + (digits - 4) * 8;
|
|
1268
1267
|
};
|
|
1268
|
+
function getColumnDepth(column) {
|
|
1269
|
+
if (!column.children?.length) return 1;
|
|
1270
|
+
return 1 + Math.max(...column.children.map(getColumnDepth));
|
|
1271
|
+
}
|
|
1272
|
+
function flattenDataColumns(columns, inheritedFixed, insideGroup = false) {
|
|
1273
|
+
return columns.flatMap((column) => {
|
|
1274
|
+
if (!column.children?.length) {
|
|
1275
|
+
return insideGroup ? [{ ...column, fixed: inheritedFixed }] : [column];
|
|
1276
|
+
}
|
|
1277
|
+
return flattenDataColumns(column.children, column.fixed ?? inheritedFixed, true);
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
function buildHeaderCells(sourceColumns, utilityColumnCount, depth) {
|
|
1281
|
+
const cells = [];
|
|
1282
|
+
let leafIndex = utilityColumnCount;
|
|
1283
|
+
const walk = (column, level, inheritedFixed, insideGroup, rootIndex, parentKey) => {
|
|
1284
|
+
const fixedColumn = insideGroup ? { ...column, fixed: inheritedFixed } : column;
|
|
1285
|
+
if (!fixedColumn.children?.length) {
|
|
1286
|
+
const startIndex2 = leafIndex;
|
|
1287
|
+
leafIndex += 1;
|
|
1288
|
+
cells.push({ key: fixedColumn.key, column: fixedColumn, level: depth - 1, startIndex: startIndex2, endIndex: startIndex2, leaf: true, parentKey, rootIndex });
|
|
1289
|
+
return { startIndex: startIndex2, endIndex: startIndex2 };
|
|
1290
|
+
}
|
|
1291
|
+
const startIndex = leafIndex;
|
|
1292
|
+
fixedColumn.children.forEach((child) => walk(child, level + 1, fixedColumn.fixed, true, rootIndex, fixedColumn.key));
|
|
1293
|
+
const endIndex = leafIndex - 1;
|
|
1294
|
+
cells.push({ key: fixedColumn.key, column: fixedColumn, level, startIndex, endIndex, leaf: false, parentKey, rootIndex });
|
|
1295
|
+
return { startIndex, endIndex };
|
|
1296
|
+
};
|
|
1297
|
+
sourceColumns.forEach((column, index) => walk(column, 0, void 0, false, index));
|
|
1298
|
+
return cells;
|
|
1299
|
+
}
|
|
1300
|
+
function hasNestedFixedColumns(columns, insideGroup = false) {
|
|
1301
|
+
return columns.some((column) => insideGroup && column.fixed !== void 0 || (column.children?.length ? hasNestedFixedColumns(column.children, true) : false));
|
|
1302
|
+
}
|
|
1303
|
+
function isProductionRuntime() {
|
|
1304
|
+
const env = globalThis.process?.env?.NODE_ENV;
|
|
1305
|
+
return env === "production";
|
|
1306
|
+
}
|
|
1269
1307
|
var createPendingInsertId = () => `table-inserted-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;
|
|
1270
1308
|
var waitForPaint = () => new Promise((resolve) => {
|
|
1271
1309
|
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
@@ -1380,10 +1418,24 @@ function Table({
|
|
|
1380
1418
|
}) {
|
|
1381
1419
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1382
1420
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1421
|
+
const headerDepth = (0, import_react5.useMemo)(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
1383
1422
|
const { language, labels } = (0, import_react5.useMemo)(() => resolveGridLocale(locale), [locale]);
|
|
1384
1423
|
const customHeaderContentRefs = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
|
|
1385
|
-
const
|
|
1386
|
-
const
|
|
1424
|
+
const customHeaderMeasurementsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
|
|
1425
|
+
const [measuredHeaderRowHeights, setMeasuredHeaderRowHeights] = (0, import_react5.useState)([]);
|
|
1426
|
+
const headerRowHeights = (0, import_react5.useMemo)(() => Array.from({ length: headerDepth }, (_, level) => Math.max(baseHeaderHeight, measuredHeaderRowHeights[level] ?? 0)), [baseHeaderHeight, headerDepth, measuredHeaderRowHeights]);
|
|
1427
|
+
const headerRowOffsets = (0, import_react5.useMemo)(() => {
|
|
1428
|
+
const offsets = [];
|
|
1429
|
+
let top = 0;
|
|
1430
|
+
headerRowHeights.forEach((height2) => {
|
|
1431
|
+
offsets.push(top);
|
|
1432
|
+
top += height2;
|
|
1433
|
+
});
|
|
1434
|
+
return offsets;
|
|
1435
|
+
}, [headerRowHeights]);
|
|
1436
|
+
const headerHeight = headerRowHeights.reduce((total, height2) => total + height2, 0);
|
|
1437
|
+
const headerLeafTop = headerRowOffsets[headerDepth - 1] ?? 0;
|
|
1438
|
+
const headerLeafHeight = headerRowHeights[headerDepth - 1] ?? baseHeaderHeight;
|
|
1387
1439
|
const hasVerticalBorders = !(borderless ?? verticalBorderless ?? false);
|
|
1388
1440
|
const hasStripedRows = Boolean(striped);
|
|
1389
1441
|
const stripedColor = typeof striped === "string" ? striped : void 0;
|
|
@@ -1403,6 +1455,13 @@ function Table({
|
|
|
1403
1455
|
const summaryEmptyValue = typeof summary === "object" ? summary.emptyValue ?? "" : "";
|
|
1404
1456
|
const contextMenuEnabled = contextMenuConfig !== false;
|
|
1405
1457
|
const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
|
|
1458
|
+
const [resizedColumnWidths, setResizedColumnWidths] = (0, import_react5.useState)({});
|
|
1459
|
+
const leafSourceColumns = (0, import_react5.useMemo)(() => flattenDataColumns(sourceColumns), [sourceColumns]);
|
|
1460
|
+
(0, import_react5.useEffect)(() => {
|
|
1461
|
+
if (!isProductionRuntime() && hasNestedFixedColumns(sourceColumns)) {
|
|
1462
|
+
console.warn("[Table] Multi-level headers only support fixed columns on top-level columns. Nested fixed values are ignored.");
|
|
1463
|
+
}
|
|
1464
|
+
}, [sourceColumns]);
|
|
1406
1465
|
const columns = (0, import_react5.useMemo)(() => {
|
|
1407
1466
|
const utilityColumns = [];
|
|
1408
1467
|
if (rowDraggable) {
|
|
@@ -1414,9 +1473,24 @@ function Table({
|
|
|
1414
1473
|
if (rowNumber) {
|
|
1415
1474
|
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: "left", rowNumber: true });
|
|
1416
1475
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1476
|
+
const dataColumns = leafSourceColumns.map((column) => {
|
|
1477
|
+
const resizedWidth = resizedColumnWidths[column.key];
|
|
1478
|
+
return resizedWidth === void 0 ? column : { ...column, width: resizedWidth };
|
|
1479
|
+
});
|
|
1480
|
+
return [...utilityColumns, ...dataColumns];
|
|
1481
|
+
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber, rowSelection, sourceRows.length]);
|
|
1419
1482
|
const utilityColumnCount = (rowDraggable ? 1 : 0) + (rowSelection ? 1 : 0) + (rowNumber ? 1 : 0);
|
|
1483
|
+
const headerCells = (0, import_react5.useMemo)(() => buildHeaderCells(sourceColumns, utilityColumnCount, headerDepth), [headerDepth, sourceColumns, utilityColumnCount]);
|
|
1484
|
+
const activeCustomHeaderLevels = (0, import_react5.useMemo)(() => {
|
|
1485
|
+
const levels = /* @__PURE__ */ new Map();
|
|
1486
|
+
columns.forEach((column) => {
|
|
1487
|
+
if (column.renderHeader) levels.set(column.key, headerDepth - 1);
|
|
1488
|
+
});
|
|
1489
|
+
headerCells.forEach((cell) => {
|
|
1490
|
+
if (cell.column.renderHeader) levels.set(`group:${cell.key}:${cell.level}`, cell.level);
|
|
1491
|
+
});
|
|
1492
|
+
return levels;
|
|
1493
|
+
}, [columns, headerCells, headerDepth]);
|
|
1420
1494
|
const canvasRef = (0, import_react5.useRef)(null);
|
|
1421
1495
|
const scrollerRef = (0, import_react5.useRef)(null);
|
|
1422
1496
|
const frameRef = (0, import_react5.useRef)(null);
|
|
@@ -1434,6 +1508,14 @@ function Table({
|
|
|
1434
1508
|
const dragGuideRef = (0, import_react5.useRef)(null);
|
|
1435
1509
|
const rowDragGuideRef = (0, import_react5.useRef)(null);
|
|
1436
1510
|
const selectionFocusRef = (0, import_react5.useRef)(null);
|
|
1511
|
+
const verticalScrollbarRef = (0, import_react5.useRef)(null);
|
|
1512
|
+
const verticalScrollbarThumbRef = (0, import_react5.useRef)(null);
|
|
1513
|
+
const verticalScrollbarDragRef = (0, import_react5.useRef)(null);
|
|
1514
|
+
const horizontalScrollbarRef = (0, import_react5.useRef)(null);
|
|
1515
|
+
const horizontalScrollbarThumbRef = (0, import_react5.useRef)(null);
|
|
1516
|
+
const horizontalScrollbarDragRef = (0, import_react5.useRef)(null);
|
|
1517
|
+
const verticalScrollbarVisibilityTimerRef = (0, import_react5.useRef)(null);
|
|
1518
|
+
const horizontalScrollbarVisibilityTimerRef = (0, import_react5.useRef)(null);
|
|
1437
1519
|
const rowByKeyRef = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
|
|
1438
1520
|
const rowIndexByKeyRef = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
|
|
1439
1521
|
const headerIconsRef = (0, import_react5.useRef)(null);
|
|
@@ -1486,24 +1568,57 @@ function Table({
|
|
|
1486
1568
|
rangeDragRef.current = null;
|
|
1487
1569
|
setSelectionRange(null);
|
|
1488
1570
|
}, [rangeSelection]);
|
|
1571
|
+
(0, import_react5.useEffect)(() => {
|
|
1572
|
+
setResizedColumnWidths((current) => {
|
|
1573
|
+
const sourceColumnByKey = new Map(leafSourceColumns.map((column) => [column.key, column]));
|
|
1574
|
+
let changed = false;
|
|
1575
|
+
const next = {};
|
|
1576
|
+
Object.entries(current).forEach(([key, value]) => {
|
|
1577
|
+
const sourceColumn = sourceColumnByKey.get(key);
|
|
1578
|
+
if (!sourceColumn) {
|
|
1579
|
+
changed = true;
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
if (sourceColumn.width !== void 0 && sourceColumn.width !== value) {
|
|
1583
|
+
changed = true;
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
next[key] = value;
|
|
1587
|
+
});
|
|
1588
|
+
return changed ? next : current;
|
|
1589
|
+
});
|
|
1590
|
+
}, [leafSourceColumns]);
|
|
1489
1591
|
(0, import_react5.useEffect)(() => () => {
|
|
1490
1592
|
if (headerTooltipTimerRef.current !== null) clearTimeout(headerTooltipTimerRef.current);
|
|
1491
1593
|
if (cellTooltipTimerRef.current !== null) clearTimeout(cellTooltipTimerRef.current);
|
|
1492
1594
|
}, []);
|
|
1493
1595
|
const measureCustomHeaderHeight = (0, import_react5.useCallback)(() => {
|
|
1494
|
-
|
|
1596
|
+
const nextHeights = Array.from({ length: headerDepth }, () => baseHeaderHeight);
|
|
1495
1597
|
customHeaderContentRefs.current.forEach((node) => {
|
|
1496
|
-
|
|
1598
|
+
const headerCell = node.closest(".rvg-header-title");
|
|
1599
|
+
const key = headerCell?.dataset.measureKey;
|
|
1600
|
+
const level = key ? activeCustomHeaderLevels.get(key) : void 0;
|
|
1601
|
+
if (!key || level === void 0 || level < 0 || level >= nextHeights.length) return;
|
|
1602
|
+
customHeaderMeasurementsRef.current.set(key, { level, height: Math.ceil(node.scrollHeight) + 16 });
|
|
1497
1603
|
});
|
|
1498
|
-
|
|
1499
|
-
|
|
1604
|
+
customHeaderMeasurementsRef.current.forEach((measurement, key) => {
|
|
1605
|
+
if (!activeCustomHeaderLevels.has(key)) return;
|
|
1606
|
+
nextHeights[measurement.level] = Math.max(nextHeights[measurement.level], measurement.height);
|
|
1607
|
+
});
|
|
1608
|
+
setMeasuredHeaderRowHeights((current) => {
|
|
1609
|
+
const changed = nextHeights.length !== current.length || nextHeights.some((height2, index) => height2 !== current[index]);
|
|
1610
|
+
return changed ? nextHeights : current;
|
|
1611
|
+
});
|
|
1612
|
+
}, [activeCustomHeaderLevels, baseHeaderHeight, headerDepth]);
|
|
1500
1613
|
(0, import_react5.useLayoutEffect)(() => {
|
|
1501
|
-
const activeCustomHeaderKeys = new Set(columns.filter((column) => column.renderHeader).map((column) => column.key));
|
|
1502
1614
|
customHeaderContentRefs.current.forEach((_, key) => {
|
|
1503
|
-
if (!
|
|
1615
|
+
if (!activeCustomHeaderLevels.has(key)) customHeaderContentRefs.current.delete(key);
|
|
1616
|
+
});
|
|
1617
|
+
customHeaderMeasurementsRef.current.forEach((_, key) => {
|
|
1618
|
+
if (!activeCustomHeaderLevels.has(key)) customHeaderMeasurementsRef.current.delete(key);
|
|
1504
1619
|
});
|
|
1505
|
-
if (
|
|
1506
|
-
|
|
1620
|
+
if (activeCustomHeaderLevels.size === 0) {
|
|
1621
|
+
setMeasuredHeaderRowHeights([]);
|
|
1507
1622
|
return;
|
|
1508
1623
|
}
|
|
1509
1624
|
measureCustomHeaderHeight();
|
|
@@ -1511,7 +1626,7 @@ function Table({
|
|
|
1511
1626
|
const observer = new ResizeObserver(measureCustomHeaderHeight);
|
|
1512
1627
|
customHeaderContentRefs.current.forEach((node) => observer.observe(node));
|
|
1513
1628
|
return () => observer.disconnect();
|
|
1514
|
-
}, [
|
|
1629
|
+
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1515
1630
|
const [filterEditor, setFilterEditor] = (0, import_react5.useState)(null);
|
|
1516
1631
|
const [contextMenu, setContextMenu] = (0, import_react5.useState)(null);
|
|
1517
1632
|
const [insertCounts, setInsertCounts] = (0, import_react5.useState)({ before: 1, after: 1 });
|
|
@@ -1521,6 +1636,7 @@ function Table({
|
|
|
1521
1636
|
const [deleteBusy, setDeleteBusy] = (0, import_react5.useState)(false);
|
|
1522
1637
|
const [toast, setToast] = (0, import_react5.useState)(null);
|
|
1523
1638
|
const [resizeGuideX, setResizeGuideX] = (0, import_react5.useState)(null);
|
|
1639
|
+
const [resizeGuideTop, setResizeGuideTop] = (0, import_react5.useState)(0);
|
|
1524
1640
|
const [hoveredHeaderAction, setHoveredHeaderAction] = (0, import_react5.useState)(null);
|
|
1525
1641
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = (0, import_react5.useState)(null);
|
|
1526
1642
|
const [hoveredCellTooltip, setHoveredCellTooltip] = (0, import_react5.useState)(null);
|
|
@@ -1605,7 +1721,17 @@ function Table({
|
|
|
1605
1721
|
const metrics = (0, import_react5.useMemo)(() => buildColumnMetrics(columns, { columnDraggable, viewportWidth: viewport.width }), [columnDraggable, columns, viewport.width]);
|
|
1606
1722
|
const contentWidth = metrics.length > 0 ? metrics[metrics.length - 1].right : 0;
|
|
1607
1723
|
const contentHeight = rows.length * rowHeight;
|
|
1608
|
-
const fixedWidth = (0, import_react5.useMemo)(() => columns.reduce((width2, column, index) => column.fixed === "left" ?
|
|
1724
|
+
const fixedWidth = (0, import_react5.useMemo)(() => columns.reduce((width2, column, index) => column.fixed === "left" ? width2 + metrics[index].width : width2, 0), [columns, metrics]);
|
|
1725
|
+
const leftFixedOffsets = (0, import_react5.useMemo)(() => {
|
|
1726
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
1727
|
+
let offset = 0;
|
|
1728
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
1729
|
+
if (columns[index].fixed !== "left") continue;
|
|
1730
|
+
offsets.set(index, offset);
|
|
1731
|
+
offset += metrics[index].width;
|
|
1732
|
+
}
|
|
1733
|
+
return offsets;
|
|
1734
|
+
}, [columns, metrics]);
|
|
1609
1735
|
const rightFixedWidth = (0, import_react5.useMemo)(() => columns.reduce((width2, column, index) => column.fixed === "right" ? width2 + metrics[index].width : width2, 0), [columns, metrics]);
|
|
1610
1736
|
const rightFixedOffsets = (0, import_react5.useMemo)(() => {
|
|
1611
1737
|
const offsets = /* @__PURE__ */ new Map();
|
|
@@ -1617,6 +1743,16 @@ function Table({
|
|
|
1617
1743
|
}
|
|
1618
1744
|
return offsets;
|
|
1619
1745
|
}, [columns, metrics]);
|
|
1746
|
+
const scrollableColumnLefts = (0, import_react5.useMemo)(() => {
|
|
1747
|
+
const lefts = [];
|
|
1748
|
+
let width2 = fixedWidth;
|
|
1749
|
+
for (let index = 0; index < columns.length; index += 1) {
|
|
1750
|
+
lefts[index] = width2;
|
|
1751
|
+
if (columns[index].fixed === void 0) width2 += metrics[index].width;
|
|
1752
|
+
}
|
|
1753
|
+
return lefts;
|
|
1754
|
+
}, [columns, fixedWidth, metrics]);
|
|
1755
|
+
const getScrollableColumnLeft = (0, import_react5.useCallback)((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
|
|
1620
1756
|
const hasRowSelectionColumn = (0, import_react5.useMemo)(() => columns.some((column) => column.rowSelection), [columns]);
|
|
1621
1757
|
const rowSelectionMode = typeof rowSelection === "object" ? rowSelection.mode ?? "multiple" : "multiple";
|
|
1622
1758
|
const hasSummaryRow = (0, import_react5.useMemo)(() => rows.length > 0 && summaryEnabled && columns.some((column) => Boolean(column.summary)), [columns, rows.length, summaryEnabled]);
|
|
@@ -1627,7 +1763,7 @@ function Table({
|
|
|
1627
1763
|
const realContentHeight = bodyTop + bodyContentHeight + bottomSummaryHeight + (contentWidth > viewport.width ? horizontalScrollbarHeight : 0);
|
|
1628
1764
|
const effectiveHeight = autoHeight ? Math.max(bodyTop + bottomSummaryHeight, Math.min(resolvedHeight, realContentHeight)) : resolvedHeight;
|
|
1629
1765
|
const renderHeight = Math.max(0, effectiveHeight - bottomSummaryHeight);
|
|
1630
|
-
const bodyViewportHeight = Math.max(0, renderHeight - (fixedHeader ? headerHeight : 0)
|
|
1766
|
+
const bodyViewportHeight = Math.max(0, renderHeight - (fixedHeader ? headerHeight + topSummaryHeight : 0));
|
|
1631
1767
|
const [summaryState, setSummaryState] = (0, import_react5.useState)(() => ({ columns: null, rows: null, values: /* @__PURE__ */ new Map(), pending: false }));
|
|
1632
1768
|
const summaryPending = hasSummaryRow && (loading || summaryState.pending || summaryState.columns !== columns || summaryState.rows !== rows);
|
|
1633
1769
|
const summaryValues = hasSummaryRow && summaryState.columns === columns && summaryState.rows === rows ? summaryState.values : /* @__PURE__ */ new Map();
|
|
@@ -1803,8 +1939,8 @@ function Table({
|
|
|
1803
1939
|
const scroll = scrollRef.current;
|
|
1804
1940
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1805
1941
|
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 };
|
|
1806
|
-
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 });
|
|
1807
|
-
}, [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]);
|
|
1942
|
+
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 });
|
|
1943
|
+
}, [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]);
|
|
1808
1944
|
const scheduleDraw = (0, import_react5.useCallback)(() => {
|
|
1809
1945
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1810
1946
|
}, [draw]);
|
|
@@ -1841,6 +1977,8 @@ function Table({
|
|
|
1841
1977
|
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
1842
1978
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
1843
1979
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
1980
|
+
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
1981
|
+
if (horizontalScrollbarVisibilityTimerRef.current !== null) clearTimeout(horizontalScrollbarVisibilityTimerRef.current);
|
|
1844
1982
|
}, []);
|
|
1845
1983
|
(0, import_react5.useEffect)(() => {
|
|
1846
1984
|
const scroller = scrollerRef.current;
|
|
@@ -1892,9 +2030,204 @@ function Table({
|
|
|
1892
2030
|
scroller.addEventListener("scroll", lockScroll);
|
|
1893
2031
|
return () => scroller.removeEventListener("scroll", lockScroll);
|
|
1894
2032
|
}, [insertBusy]);
|
|
2033
|
+
const showCustomScrollbar = (0, import_react5.useCallback)((axis, persist = false) => {
|
|
2034
|
+
const showVertical = axis === "vertical" || axis === "both";
|
|
2035
|
+
const showHorizontal = axis === "horizontal" || axis === "both";
|
|
2036
|
+
if (showVertical) {
|
|
2037
|
+
verticalScrollbarRef.current?.classList.add("is-active");
|
|
2038
|
+
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
2039
|
+
if (!persist) {
|
|
2040
|
+
verticalScrollbarVisibilityTimerRef.current = setTimeout(() => {
|
|
2041
|
+
verticalScrollbarRef.current?.classList.remove("is-active");
|
|
2042
|
+
verticalScrollbarVisibilityTimerRef.current = null;
|
|
2043
|
+
}, 900);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
if (showHorizontal) {
|
|
2047
|
+
horizontalScrollbarRef.current?.classList.add("is-active");
|
|
2048
|
+
if (horizontalScrollbarVisibilityTimerRef.current !== null) clearTimeout(horizontalScrollbarVisibilityTimerRef.current);
|
|
2049
|
+
if (!persist) {
|
|
2050
|
+
horizontalScrollbarVisibilityTimerRef.current = setTimeout(() => {
|
|
2051
|
+
horizontalScrollbarRef.current?.classList.remove("is-active");
|
|
2052
|
+
horizontalScrollbarVisibilityTimerRef.current = null;
|
|
2053
|
+
}, 900);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
}, []);
|
|
2057
|
+
const keepCustomScrollbarVisible = (0, import_react5.useCallback)((axis) => {
|
|
2058
|
+
showCustomScrollbar(axis, true);
|
|
2059
|
+
}, [showCustomScrollbar]);
|
|
2060
|
+
const releaseCustomScrollbarVisible = (0, import_react5.useCallback)((axis) => {
|
|
2061
|
+
if (axis === "vertical" && verticalScrollbarDragRef.current) return;
|
|
2062
|
+
if (axis === "horizontal" && horizontalScrollbarDragRef.current) return;
|
|
2063
|
+
showCustomScrollbar(axis);
|
|
2064
|
+
}, [showCustomScrollbar]);
|
|
2065
|
+
const updateCustomScrollbars = (0, import_react5.useCallback)(() => {
|
|
2066
|
+
const scroller = scrollerRef.current;
|
|
2067
|
+
const verticalTrack = verticalScrollbarRef.current;
|
|
2068
|
+
const verticalThumb = verticalScrollbarThumbRef.current;
|
|
2069
|
+
const horizontalTrack = horizontalScrollbarRef.current;
|
|
2070
|
+
const horizontalThumb = horizontalScrollbarThumbRef.current;
|
|
2071
|
+
if (!scroller || !verticalTrack || !verticalThumb || !horizontalTrack || !horizontalThumb) return;
|
|
2072
|
+
const maxScrollTop = scroller.scrollHeight - scroller.clientHeight;
|
|
2073
|
+
if (maxScrollTop <= 1 || renderHeight <= 0) {
|
|
2074
|
+
verticalTrack.style.display = "none";
|
|
2075
|
+
} else {
|
|
2076
|
+
const top = fixedHeader ? bodyTop : 0;
|
|
2077
|
+
const bottom = bottomSummaryHeight;
|
|
2078
|
+
const trackHeight = Math.max(0, effectiveHeight - top - bottom);
|
|
2079
|
+
if (trackHeight <= 0) {
|
|
2080
|
+
verticalTrack.style.display = "none";
|
|
2081
|
+
} else {
|
|
2082
|
+
const thumbHeight = Math.max(28, Math.round(trackHeight * (scroller.clientHeight / scroller.scrollHeight)));
|
|
2083
|
+
const maxThumbTop = Math.max(0, trackHeight - thumbHeight);
|
|
2084
|
+
const thumbTop = maxScrollTop > 0 ? Math.round(scroller.scrollTop / maxScrollTop * maxThumbTop) : 0;
|
|
2085
|
+
verticalTrack.style.display = "block";
|
|
2086
|
+
verticalTrack.style.top = `${top}px`;
|
|
2087
|
+
verticalTrack.style.bottom = `${bottom}px`;
|
|
2088
|
+
verticalThumb.style.height = `${Math.min(trackHeight, thumbHeight)}px`;
|
|
2089
|
+
verticalThumb.style.transform = `translateY(${thumbTop}px)`;
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
const maxScrollLeft = scroller.scrollWidth - scroller.clientWidth;
|
|
2093
|
+
if (maxScrollLeft <= 1 || viewport.width <= 0) {
|
|
2094
|
+
horizontalTrack.style.display = "none";
|
|
2095
|
+
return;
|
|
2096
|
+
}
|
|
2097
|
+
const trackLeft = fixedWidth;
|
|
2098
|
+
const trackRight = rightFixedWidth;
|
|
2099
|
+
const trackWidth = Math.max(0, viewport.width - trackLeft - trackRight);
|
|
2100
|
+
if (trackWidth <= 0) {
|
|
2101
|
+
horizontalTrack.style.display = "none";
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2104
|
+
const thumbWidth = Math.max(36, Math.round(trackWidth * (scroller.clientWidth / scroller.scrollWidth)));
|
|
2105
|
+
const maxThumbLeft = Math.max(0, trackWidth - thumbWidth);
|
|
2106
|
+
const thumbLeft = maxScrollLeft > 0 ? Math.round(scroller.scrollLeft / maxScrollLeft * maxThumbLeft) : 0;
|
|
2107
|
+
horizontalTrack.style.display = "block";
|
|
2108
|
+
horizontalTrack.style.left = `${trackLeft}px`;
|
|
2109
|
+
horizontalTrack.style.right = `${trackRight}px`;
|
|
2110
|
+
horizontalTrack.style.bottom = `${bottomSummaryHeight + 2}px`;
|
|
2111
|
+
horizontalThumb.style.width = `${Math.min(trackWidth, thumbWidth)}px`;
|
|
2112
|
+
horizontalThumb.style.transform = `translateX(${thumbLeft}px)`;
|
|
2113
|
+
}, [bodyTop, bottomSummaryHeight, effectiveHeight, fixedHeader, fixedWidth, renderHeight, rightFixedWidth, viewport.width]);
|
|
2114
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
2115
|
+
updateCustomScrollbars();
|
|
2116
|
+
}, [contentHeight, contentWidth, updateCustomScrollbars, viewport.height, viewport.width]);
|
|
2117
|
+
const handleVerticalScrollbarPointerDown = (0, import_react5.useCallback)((event) => {
|
|
2118
|
+
const scroller = scrollerRef.current;
|
|
2119
|
+
const track = verticalScrollbarRef.current;
|
|
2120
|
+
const thumb = verticalScrollbarThumbRef.current;
|
|
2121
|
+
if (!scroller || !track || !thumb || event.button !== 0) return;
|
|
2122
|
+
event.preventDefault();
|
|
2123
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2124
|
+
const trackRect = track.getBoundingClientRect();
|
|
2125
|
+
const thumbRect = thumb.getBoundingClientRect();
|
|
2126
|
+
const maxScrollTop = scroller.scrollHeight - scroller.clientHeight;
|
|
2127
|
+
const trackHeight = trackRect.height;
|
|
2128
|
+
const thumbHeight = thumbRect.height;
|
|
2129
|
+
showCustomScrollbar("vertical", true);
|
|
2130
|
+
if (event.target === thumb) {
|
|
2131
|
+
verticalScrollbarDragRef.current = {
|
|
2132
|
+
pointerId: event.pointerId,
|
|
2133
|
+
startY: event.clientY,
|
|
2134
|
+
startTop: thumbRect.top - trackRect.top,
|
|
2135
|
+
trackHeight,
|
|
2136
|
+
thumbHeight,
|
|
2137
|
+
maxScrollTop
|
|
2138
|
+
};
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
const nextThumbTop = Math.max(0, Math.min(trackHeight - thumbHeight, event.clientY - trackRect.top - thumbHeight / 2));
|
|
2142
|
+
const maxThumbTop = Math.max(1, trackHeight - thumbHeight);
|
|
2143
|
+
scroller.scrollTop = nextThumbTop / maxThumbTop * maxScrollTop;
|
|
2144
|
+
updateCustomScrollbars();
|
|
2145
|
+
verticalScrollbarDragRef.current = {
|
|
2146
|
+
pointerId: event.pointerId,
|
|
2147
|
+
startY: event.clientY,
|
|
2148
|
+
startTop: nextThumbTop,
|
|
2149
|
+
trackHeight,
|
|
2150
|
+
thumbHeight,
|
|
2151
|
+
maxScrollTop
|
|
2152
|
+
};
|
|
2153
|
+
}, [showCustomScrollbar, updateCustomScrollbars]);
|
|
2154
|
+
const handleVerticalScrollbarPointerMove = (0, import_react5.useCallback)((event) => {
|
|
2155
|
+
const drag = verticalScrollbarDragRef.current;
|
|
2156
|
+
const scroller = scrollerRef.current;
|
|
2157
|
+
if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
|
|
2158
|
+
event.preventDefault();
|
|
2159
|
+
const maxThumbTop = Math.max(1, drag.trackHeight - drag.thumbHeight);
|
|
2160
|
+
const nextThumbTop = Math.max(0, Math.min(maxThumbTop, drag.startTop + event.clientY - drag.startY));
|
|
2161
|
+
scroller.scrollTop = nextThumbTop / maxThumbTop * drag.maxScrollTop;
|
|
2162
|
+
updateCustomScrollbars();
|
|
2163
|
+
}, [updateCustomScrollbars]);
|
|
2164
|
+
const handleVerticalScrollbarPointerUp = (0, import_react5.useCallback)((event) => {
|
|
2165
|
+
const drag = verticalScrollbarDragRef.current;
|
|
2166
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2167
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2168
|
+
verticalScrollbarDragRef.current = null;
|
|
2169
|
+
showCustomScrollbar("vertical");
|
|
2170
|
+
}, [showCustomScrollbar]);
|
|
2171
|
+
const handleHorizontalScrollbarPointerDown = (0, import_react5.useCallback)((event) => {
|
|
2172
|
+
const scroller = scrollerRef.current;
|
|
2173
|
+
const track = horizontalScrollbarRef.current;
|
|
2174
|
+
const thumb = horizontalScrollbarThumbRef.current;
|
|
2175
|
+
if (!scroller || !track || !thumb || event.button !== 0) return;
|
|
2176
|
+
event.preventDefault();
|
|
2177
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2178
|
+
const trackRect = track.getBoundingClientRect();
|
|
2179
|
+
const thumbRect = thumb.getBoundingClientRect();
|
|
2180
|
+
const maxScrollLeft = scroller.scrollWidth - scroller.clientWidth;
|
|
2181
|
+
const trackWidth = trackRect.width;
|
|
2182
|
+
const thumbWidth = thumbRect.width;
|
|
2183
|
+
showCustomScrollbar("horizontal", true);
|
|
2184
|
+
if (event.target === thumb) {
|
|
2185
|
+
horizontalScrollbarDragRef.current = {
|
|
2186
|
+
pointerId: event.pointerId,
|
|
2187
|
+
startX: event.clientX,
|
|
2188
|
+
startLeft: thumbRect.left - trackRect.left,
|
|
2189
|
+
trackWidth,
|
|
2190
|
+
thumbWidth,
|
|
2191
|
+
maxScrollLeft
|
|
2192
|
+
};
|
|
2193
|
+
return;
|
|
2194
|
+
}
|
|
2195
|
+
const nextThumbLeft = Math.max(0, Math.min(trackWidth - thumbWidth, event.clientX - trackRect.left - thumbWidth / 2));
|
|
2196
|
+
const maxThumbLeft = Math.max(1, trackWidth - thumbWidth);
|
|
2197
|
+
scroller.scrollLeft = nextThumbLeft / maxThumbLeft * maxScrollLeft;
|
|
2198
|
+
updateCustomScrollbars();
|
|
2199
|
+
horizontalScrollbarDragRef.current = {
|
|
2200
|
+
pointerId: event.pointerId,
|
|
2201
|
+
startX: event.clientX,
|
|
2202
|
+
startLeft: nextThumbLeft,
|
|
2203
|
+
trackWidth,
|
|
2204
|
+
thumbWidth,
|
|
2205
|
+
maxScrollLeft
|
|
2206
|
+
};
|
|
2207
|
+
}, [showCustomScrollbar, updateCustomScrollbars]);
|
|
2208
|
+
const handleHorizontalScrollbarPointerMove = (0, import_react5.useCallback)((event) => {
|
|
2209
|
+
const drag = horizontalScrollbarDragRef.current;
|
|
2210
|
+
const scroller = scrollerRef.current;
|
|
2211
|
+
if (!drag || !scroller || drag.pointerId !== event.pointerId) return;
|
|
2212
|
+
event.preventDefault();
|
|
2213
|
+
const maxThumbLeft = Math.max(1, drag.trackWidth - drag.thumbWidth);
|
|
2214
|
+
const nextThumbLeft = Math.max(0, Math.min(maxThumbLeft, drag.startLeft + event.clientX - drag.startX));
|
|
2215
|
+
scroller.scrollLeft = nextThumbLeft / maxThumbLeft * drag.maxScrollLeft;
|
|
2216
|
+
updateCustomScrollbars();
|
|
2217
|
+
}, [updateCustomScrollbars]);
|
|
2218
|
+
const handleHorizontalScrollbarPointerUp = (0, import_react5.useCallback)((event) => {
|
|
2219
|
+
const drag = horizontalScrollbarDragRef.current;
|
|
2220
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2221
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2222
|
+
horizontalScrollbarDragRef.current = null;
|
|
2223
|
+
showCustomScrollbar("horizontal");
|
|
2224
|
+
}, [showCustomScrollbar]);
|
|
1895
2225
|
const handleScroll = (0, import_react5.useCallback)(() => {
|
|
1896
2226
|
const element = scrollerRef.current;
|
|
1897
2227
|
if (!element) return;
|
|
2228
|
+
const previousScroll = scrollRef.current;
|
|
2229
|
+
const scrollDeltaX = element.scrollLeft - previousScroll.left;
|
|
2230
|
+
const scrollDeltaY = element.scrollTop - previousScroll.top;
|
|
1898
2231
|
scrollRef.current = { left: element.scrollLeft, top: element.scrollTop };
|
|
1899
2232
|
const focus = selectionFocusRef.current;
|
|
1900
2233
|
if (focus && selection && !selectionRange) {
|
|
@@ -1905,7 +2238,7 @@ function Table({
|
|
|
1905
2238
|
if (!validSelection) {
|
|
1906
2239
|
focus.style.display = "none";
|
|
1907
2240
|
} else {
|
|
1908
|
-
const rawLeft = column.fixed === "left" ?
|
|
2241
|
+
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;
|
|
1909
2242
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - element.scrollTop;
|
|
1910
2243
|
const span = getCellSpan(selection.rowIndex, selection.columnIndex);
|
|
1911
2244
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
@@ -1938,6 +2271,10 @@ function Table({
|
|
|
1938
2271
|
if (scrollingTextRef.current) scrollingTextRef.current.style.transform = `translateX(${-element.scrollLeft}px)`;
|
|
1939
2272
|
if (scrollingHeaderIconsRef.current) scrollingHeaderIconsRef.current.style.transform = `translateX(${-element.scrollLeft}px)`;
|
|
1940
2273
|
if (headerIconsRef.current) headerIconsRef.current.style.transform = `translateY(${fixedHeader ? 0 : -element.scrollTop}px)`;
|
|
2274
|
+
updateCustomScrollbars();
|
|
2275
|
+
if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {
|
|
2276
|
+
showCustomScrollbar(scrollDeltaX !== 0 && scrollDeltaY !== 0 ? "both" : scrollDeltaX !== 0 ? "horizontal" : "vertical");
|
|
2277
|
+
}
|
|
1941
2278
|
if (hoveredHeaderActionRef.current) {
|
|
1942
2279
|
hoveredHeaderActionRef.current = null;
|
|
1943
2280
|
setHoveredHeaderAction(null);
|
|
@@ -1945,7 +2282,7 @@ function Table({
|
|
|
1945
2282
|
setHoveredCellTooltip(null);
|
|
1946
2283
|
scheduleDraw();
|
|
1947
2284
|
setEditing(null);
|
|
1948
|
-
}, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, viewport.width]);
|
|
2285
|
+
}, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, showCustomScrollbar, updateCustomScrollbars, viewport.width]);
|
|
1949
2286
|
const locateColumn = (0, import_react5.useCallback)((clientX) => {
|
|
1950
2287
|
const canvas = canvasRef.current;
|
|
1951
2288
|
if (!canvas) return -1;
|
|
@@ -1953,7 +2290,11 @@ function Table({
|
|
|
1953
2290
|
const localX = clientX - rect.left;
|
|
1954
2291
|
let columnIndex;
|
|
1955
2292
|
if (localX < fixedWidth) {
|
|
1956
|
-
columnIndex =
|
|
2293
|
+
columnIndex = columns.findIndex((column, index) => {
|
|
2294
|
+
if (column.fixed !== "left") return false;
|
|
2295
|
+
const left = leftFixedOffsets.get(index) ?? 0;
|
|
2296
|
+
return localX >= left && localX < left + metrics[index].width;
|
|
2297
|
+
});
|
|
1957
2298
|
} else if (rightFixedWidth > 0 && localX >= viewport.width - rightFixedWidth) {
|
|
1958
2299
|
columnIndex = columns.findIndex((column, index) => {
|
|
1959
2300
|
if (column.fixed !== "right") return false;
|
|
@@ -1961,41 +2302,33 @@ function Table({
|
|
|
1961
2302
|
return localX >= left && localX < left + metrics[index].width;
|
|
1962
2303
|
});
|
|
1963
2304
|
} else {
|
|
1964
|
-
|
|
2305
|
+
const scrollX = localX + scrollRef.current.left;
|
|
2306
|
+
columnIndex = columns.findIndex((column, index) => {
|
|
2307
|
+
if (column.fixed !== void 0) return false;
|
|
2308
|
+
const left = getScrollableColumnLeft(index);
|
|
2309
|
+
return scrollX >= left && scrollX < left + metrics[index].width;
|
|
2310
|
+
});
|
|
1965
2311
|
}
|
|
1966
2312
|
return columnIndex;
|
|
1967
|
-
}, [columns, fixedWidth, metrics, rightFixedOffsets, rightFixedWidth, viewport.width]);
|
|
2313
|
+
}, [columns, fixedWidth, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rightFixedWidth, viewport.width]);
|
|
1968
2314
|
const getDisplayedColumnLeft = (0, import_react5.useCallback)((columnIndex) => {
|
|
1969
2315
|
const metric = metrics[columnIndex];
|
|
1970
|
-
if (columns[columnIndex].fixed === "left") return
|
|
2316
|
+
if (columns[columnIndex].fixed === "left") return leftFixedOffsets.get(columnIndex) ?? 0;
|
|
1971
2317
|
if (columns[columnIndex].fixed === "right") return viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metric.width;
|
|
1972
|
-
return
|
|
1973
|
-
}, [columns, metrics, rightFixedOffsets, viewport.width]);
|
|
1974
|
-
const
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
for (let index = 0; index < columns.length; index += 1) {
|
|
1980
|
-
if (columns[index].rowSelection || columns[index].rowDragHandle || columns[index].rowNumber) continue;
|
|
1981
|
-
const nextDistance = Math.abs(localX - (getDisplayedColumnLeft(index) + metrics[index].width));
|
|
1982
|
-
if (nextDistance < distance) {
|
|
1983
|
-
distance = nextDistance;
|
|
1984
|
-
closest = index;
|
|
1985
|
-
}
|
|
2318
|
+
return getScrollableColumnLeft(columnIndex) - scrollRef.current.left;
|
|
2319
|
+
}, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
|
|
2320
|
+
const getHeaderLevelAtY = (0, import_react5.useCallback)((localY, headerY) => {
|
|
2321
|
+
const y = localY - headerY;
|
|
2322
|
+
for (let level = 0; level < headerRowHeights.length; level += 1) {
|
|
2323
|
+
const top = headerRowOffsets[level] ?? 0;
|
|
2324
|
+
if (y >= top && y < top + headerRowHeights[level]) return level;
|
|
1986
2325
|
}
|
|
1987
|
-
return
|
|
1988
|
-
}, [
|
|
1989
|
-
const
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
if (column.rowSelection || column.rowDragHandle || column.rowNumber) continue;
|
|
1994
|
-
if (resizedColumn?.fixed && column.fixed !== resizedColumn.fixed) return -1;
|
|
1995
|
-
return index;
|
|
1996
|
-
}
|
|
1997
|
-
return -1;
|
|
1998
|
-
}, [columns]);
|
|
2326
|
+
return headerDepth - 1;
|
|
2327
|
+
}, [headerDepth, headerRowHeights, headerRowOffsets]);
|
|
2328
|
+
const resizeColumn = (0, import_react5.useCallback)((columnKey, width2) => {
|
|
2329
|
+
setResizedColumnWidths((current) => current[columnKey] === width2 ? current : { ...current, [columnKey]: width2 });
|
|
2330
|
+
onColumnResize?.(columnKey, width2);
|
|
2331
|
+
}, [onColumnResize]);
|
|
1999
2332
|
const locateHeaderAction = (0, import_react5.useCallback)((clientX, columnIndex) => {
|
|
2000
2333
|
if (columnIndex < 0 || !canvasRef.current) return null;
|
|
2001
2334
|
const column = columns[columnIndex];
|
|
@@ -2030,11 +2363,70 @@ function Table({
|
|
|
2030
2363
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2031
2364
|
return localX >= columnRight - 16 && localX < columnRight - 5;
|
|
2032
2365
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2033
|
-
const
|
|
2366
|
+
const getHeaderCellLeft = (0, import_react5.useCallback)((cell) => {
|
|
2367
|
+
const startMetric = metrics[cell.startIndex];
|
|
2368
|
+
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
2369
|
+
if (!startMetric) return 0;
|
|
2370
|
+
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;
|
|
2371
|
+
}, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
|
|
2372
|
+
const getHeaderCellWidth = (0, import_react5.useCallback)((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
|
|
2373
|
+
const locateHeaderResizeHit = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2374
|
+
if (!columnResizable || !canvasRef.current) return null;
|
|
2375
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
2376
|
+
const localX = clientX - rect.left;
|
|
2377
|
+
const localY = clientY - rect.top;
|
|
2378
|
+
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
2379
|
+
if (localY < headerY || localY >= headerY + headerHeight) return null;
|
|
2380
|
+
const level = getHeaderLevelAtY(localY, headerY);
|
|
2381
|
+
let closest = null;
|
|
2382
|
+
let distance = 6;
|
|
2383
|
+
for (const cell of headerCells) {
|
|
2384
|
+
if (cell.level !== level) continue;
|
|
2385
|
+
if (columns[cell.startIndex]?.rowSelection || columns[cell.startIndex]?.rowDragHandle || columns[cell.startIndex]?.rowNumber) continue;
|
|
2386
|
+
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
2387
|
+
const edge = fixedSide === "right" && cell.leaf ? "left" : "right";
|
|
2388
|
+
const edgeX = getHeaderCellLeft(cell) + (edge === "right" ? getHeaderCellWidth(cell) : 0);
|
|
2389
|
+
const nextDistance = Math.abs(localX - edgeX);
|
|
2390
|
+
if (nextDistance < distance) {
|
|
2391
|
+
distance = nextDistance;
|
|
2392
|
+
closest = { cell, edge };
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
return closest;
|
|
2396
|
+
}, [columnResizable, columns, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
|
|
2397
|
+
const locateHeaderResizeCell = (0, import_react5.useCallback)((clientX, clientY) => locateHeaderResizeHit(clientX, clientY)?.cell ?? null, [locateHeaderResizeHit]);
|
|
2398
|
+
const locateHeaderCellDragHandle = (0, import_react5.useCallback)((clientX, cell) => {
|
|
2399
|
+
if (!columnDraggable || !canvasRef.current) return false;
|
|
2400
|
+
if (cell.leaf) return locateHeaderDragHandle(clientX, cell.startIndex);
|
|
2401
|
+
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2402
|
+
const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
|
|
2403
|
+
return localX >= right - 16 && localX < right - 5;
|
|
2404
|
+
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, locateHeaderDragHandle]);
|
|
2405
|
+
const locateHeaderCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2406
|
+
const canvas = canvasRef.current;
|
|
2407
|
+
if (!canvas) return null;
|
|
2408
|
+
const rect = canvas.getBoundingClientRect();
|
|
2409
|
+
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
2410
|
+
const localX = clientX - rect.left;
|
|
2411
|
+
const localY = clientY - rect.top;
|
|
2412
|
+
if (localY < headerY || localY >= headerY + headerHeight) return null;
|
|
2413
|
+
const level = getHeaderLevelAtY(localY, headerY);
|
|
2414
|
+
for (const cell of headerCells) {
|
|
2415
|
+
if (cell.level !== level) continue;
|
|
2416
|
+
const left = getHeaderCellLeft(cell);
|
|
2417
|
+
const width2 = getHeaderCellWidth(cell);
|
|
2418
|
+
if (localX >= left && localX < left + width2) return cell;
|
|
2419
|
+
}
|
|
2420
|
+
return null;
|
|
2421
|
+
}, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, getHeaderLevelAtY, headerCells, headerHeight]);
|
|
2422
|
+
const setDragGuide = (0, import_react5.useCallback)((x, top = 0) => {
|
|
2034
2423
|
const guide = dragGuideRef.current;
|
|
2035
2424
|
if (!guide) return;
|
|
2036
2425
|
guide.style.display = x === null ? "none" : "block";
|
|
2037
|
-
if (x !== null)
|
|
2426
|
+
if (x !== null) {
|
|
2427
|
+
guide.style.top = `${top}px`;
|
|
2428
|
+
guide.style.transform = `translateX(${Math.round(x)}px)`;
|
|
2429
|
+
}
|
|
2038
2430
|
}, []);
|
|
2039
2431
|
const setRowDragGuide = (0, import_react5.useCallback)((y) => {
|
|
2040
2432
|
const guide = rowDragGuideRef.current;
|
|
@@ -2052,6 +2444,15 @@ function Table({
|
|
|
2052
2444
|
(0, import_react5.useEffect)(() => {
|
|
2053
2445
|
const canvas = canvasRef.current;
|
|
2054
2446
|
if (!canvas || !columnDraggable && !rowDraggable) return;
|
|
2447
|
+
const getColumnDropIndex = (sourceIndex, targetIndex, edge) => {
|
|
2448
|
+
if (edge === "right") return targetIndex;
|
|
2449
|
+
const destinationIndex = targetIndex - (sourceIndex < targetIndex ? 1 : 0);
|
|
2450
|
+
return Math.max(0, Math.min(columns.length - 1, destinationIndex));
|
|
2451
|
+
};
|
|
2452
|
+
const getColumnDropPlacement = (sourceIndex, targetIndex, edge) => {
|
|
2453
|
+
if (edge !== "right") return "before";
|
|
2454
|
+
return targetIndex < sourceIndex ? "before" : "after";
|
|
2455
|
+
};
|
|
2055
2456
|
const getHeaderColumn = (clientX, clientY) => {
|
|
2056
2457
|
const rect = canvas.getBoundingClientRect();
|
|
2057
2458
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
@@ -2059,22 +2460,35 @@ function Table({
|
|
|
2059
2460
|
if (localY < headerY || localY >= headerY + headerHeight) return -1;
|
|
2060
2461
|
return locateColumn(clientX);
|
|
2061
2462
|
};
|
|
2463
|
+
const getHeaderDragCell = (clientX, clientY) => {
|
|
2464
|
+
const cell = locateHeaderCell(clientX, clientY);
|
|
2465
|
+
if (!cell) return null;
|
|
2466
|
+
return locateHeaderCellDragHandle(clientX, cell) && !locateHeaderResizeCell(clientX, clientY) ? cell : null;
|
|
2467
|
+
};
|
|
2062
2468
|
const cleanupDrag = (0, import_adapter.draggable)({
|
|
2063
2469
|
element: canvas,
|
|
2064
2470
|
canDrag: ({ input }) => {
|
|
2065
|
-
const
|
|
2066
|
-
if (
|
|
2471
|
+
const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
|
|
2472
|
+
if (headerDragCell) return true;
|
|
2067
2473
|
const columnIndex = locateColumn(input.clientX);
|
|
2068
2474
|
return rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
|
|
2069
2475
|
},
|
|
2070
2476
|
getInitialData: ({ input }) => {
|
|
2071
|
-
const
|
|
2072
|
-
if (
|
|
2477
|
+
const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
|
|
2478
|
+
if (!headerDragCell) {
|
|
2073
2479
|
return { type: "table-row", sourceIndex: locateRow(input.clientY) };
|
|
2074
2480
|
}
|
|
2075
|
-
const sourceIndex =
|
|
2481
|
+
const sourceIndex = headerDragCell.startIndex;
|
|
2076
2482
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2077
|
-
return {
|
|
2483
|
+
return {
|
|
2484
|
+
type: "table-column",
|
|
2485
|
+
sourceIndex,
|
|
2486
|
+
sourceKey: headerDragCell.key,
|
|
2487
|
+
parentKey: headerDragCell.parentKey,
|
|
2488
|
+
headerLevel: headerDragCell.level,
|
|
2489
|
+
headerKind: headerDragCell.leaf ? "column" : "group",
|
|
2490
|
+
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2491
|
+
};
|
|
2078
2492
|
},
|
|
2079
2493
|
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2080
2494
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2177,31 +2591,31 @@ function Table({
|
|
|
2177
2591
|
return;
|
|
2178
2592
|
}
|
|
2179
2593
|
const targetIndex = Number(target?.targetIndex);
|
|
2180
|
-
if (!Number.isInteger(targetIndex) ||
|
|
2594
|
+
if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
|
|
2181
2595
|
setDragGuide(null);
|
|
2182
2596
|
return;
|
|
2183
2597
|
}
|
|
2184
2598
|
const edge = target?.columnEdge;
|
|
2185
|
-
|
|
2186
|
-
if (sourceIndex < destinationIndex) destinationIndex -= 1;
|
|
2187
|
-
destinationIndex = Math.max(0, Math.min(columns.length - 1, destinationIndex));
|
|
2599
|
+
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2188
2600
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
|
|
2189
|
-
const targetLeft =
|
|
2190
|
-
|
|
2601
|
+
const targetLeft = Number(target?.targetLeft);
|
|
2602
|
+
const targetWidth = Number(target?.targetWidth);
|
|
2603
|
+
const guideTop = headerRowOffsets[Number(source.data.headerLevel)] ?? 0;
|
|
2604
|
+
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2191
2605
|
},
|
|
2192
2606
|
onDrop: ({ source, location }) => {
|
|
2193
2607
|
const target = location.current.dropTargets[0]?.data;
|
|
2194
2608
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2195
2609
|
if (source.data.type === "table-row") {
|
|
2196
|
-
const
|
|
2197
|
-
let targetIndex2 =
|
|
2610
|
+
const rawTargetIndex2 = Number(target?.targetIndex);
|
|
2611
|
+
let targetIndex2 = rawTargetIndex2 + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
2198
2612
|
if (sourceIndex < targetIndex2) targetIndex2 -= 1;
|
|
2199
2613
|
targetIndex2 = Math.max(0, Math.min(rows.length - 1, targetIndex2));
|
|
2200
2614
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2201
2615
|
setRowDragPreview(null);
|
|
2202
2616
|
setRowDragGuide(null);
|
|
2203
2617
|
canvas.style.cursor = "default";
|
|
2204
|
-
if (Number.isInteger(
|
|
2618
|
+
if (Number.isInteger(rawTargetIndex2) && sourceIndex !== targetIndex2) onRowOrderChange?.(sourceIndex, targetIndex2);
|
|
2205
2619
|
requestAnimationFrame(() => {
|
|
2206
2620
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2207
2621
|
});
|
|
@@ -2210,12 +2624,23 @@ function Table({
|
|
|
2210
2624
|
}, 0);
|
|
2211
2625
|
return;
|
|
2212
2626
|
}
|
|
2213
|
-
const
|
|
2627
|
+
const rawTargetIndex = Number(target?.targetIndex);
|
|
2628
|
+
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
2214
2629
|
canvas.style.cursor = "default";
|
|
2215
2630
|
setDragGuide(null);
|
|
2216
2631
|
columnDragPreviewRef.current = null;
|
|
2217
|
-
if (Number.isInteger(targetIndex) && sourceIndex !== targetIndex &&
|
|
2218
|
-
onColumnOrderChange?.(
|
|
2632
|
+
if (Number.isInteger(rawTargetIndex) && Number.isInteger(targetIndex) && sourceIndex !== targetIndex && target?.headerKind === source.data.headerKind && target?.parentKey === source.data.parentKey && target?.fixed === source.data.fixed) {
|
|
2633
|
+
onColumnOrderChange?.(
|
|
2634
|
+
sourceIndex - utilityColumnCount,
|
|
2635
|
+
targetIndex - utilityColumnCount,
|
|
2636
|
+
{
|
|
2637
|
+
type: source.data.headerKind === "group" ? "group" : "column",
|
|
2638
|
+
sourceKey: String(source.data.sourceKey),
|
|
2639
|
+
targetKey: String(target.targetKey),
|
|
2640
|
+
parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
|
|
2641
|
+
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex, target.columnEdge)
|
|
2642
|
+
}
|
|
2643
|
+
);
|
|
2219
2644
|
}
|
|
2220
2645
|
window.setTimeout(() => {
|
|
2221
2646
|
suppressClickRef.current = false;
|
|
@@ -2233,24 +2658,38 @@ function Table({
|
|
|
2233
2658
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2234
2659
|
return (0, import_closest_edge.attachClosestEdge)({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2235
2660
|
}
|
|
2236
|
-
|
|
2237
|
-
if (
|
|
2661
|
+
const targetCell = locateHeaderCell(input.clientX, input.clientY);
|
|
2662
|
+
if (!targetCell) return { targetIndex: -1 };
|
|
2663
|
+
let targetIndex = targetCell.startIndex;
|
|
2664
|
+
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
2665
|
+
const headerKind = targetCell.leaf ? "column" : "group";
|
|
2666
|
+
if (source.data.headerKind !== headerKind || source.data.parentKey !== targetCell.parentKey || source.data.fixed !== targetFixed) return { targetIndex: -1 };
|
|
2238
2667
|
if (columns[targetIndex].rowSelection || columns[targetIndex].rowDragHandle || columns[targetIndex].rowNumber) {
|
|
2239
2668
|
const fixedSide = columns[Number(source.data.sourceIndex)]?.fixed;
|
|
2240
2669
|
targetIndex = columns.findIndex((column, index) => index > targetIndex && column.fixed === fixedSide && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
|
|
2241
2670
|
if (targetIndex < 0) return { targetIndex: -1 };
|
|
2242
2671
|
return { targetIndex, columnEdge: "left" };
|
|
2243
2672
|
}
|
|
2244
|
-
const left =
|
|
2245
|
-
const
|
|
2246
|
-
|
|
2673
|
+
const left = getHeaderCellLeft(targetCell);
|
|
2674
|
+
const targetWidth = targetCell.leaf ? metrics[targetIndex].width : getHeaderCellWidth(targetCell);
|
|
2675
|
+
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2676
|
+
return (0, import_closest_edge.attachClosestEdge)({
|
|
2677
|
+
targetIndex,
|
|
2678
|
+
targetKey: targetCell.key,
|
|
2679
|
+
parentKey: targetCell.parentKey,
|
|
2680
|
+
headerKind,
|
|
2681
|
+
fixed: targetFixed,
|
|
2682
|
+
targetLeft: left,
|
|
2683
|
+
targetWidth,
|
|
2684
|
+
columnEdge
|
|
2685
|
+
}, { element, input, allowedEdges: ["left", "right"] });
|
|
2247
2686
|
}
|
|
2248
2687
|
});
|
|
2249
2688
|
return () => {
|
|
2250
2689
|
cleanupDrag();
|
|
2251
2690
|
cleanupDrop();
|
|
2252
2691
|
};
|
|
2253
|
-
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getRowKey, headerHeight, locateColumn,
|
|
2692
|
+
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerHeight, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, metrics, onColumnOrderChange, onRowOrderChange, rowDraggable, rowHeight, rows, selectedRowKeySet, setDragGuide, setRowDragGuide, utilityColumnCount]);
|
|
2254
2693
|
const locateCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2255
2694
|
const canvas = canvasRef.current;
|
|
2256
2695
|
if (!canvas) return null;
|
|
@@ -2357,8 +2796,9 @@ function Table({
|
|
|
2357
2796
|
const horizontalFocusGap = 0;
|
|
2358
2797
|
const verticalFocusGap = 0;
|
|
2359
2798
|
if (column.fixed === void 0) {
|
|
2360
|
-
|
|
2361
|
-
if (
|
|
2799
|
+
const cellLeft = getScrollableColumnLeft(cell.columnIndex);
|
|
2800
|
+
if (cellLeft - nextLeft < fixedWidth) nextLeft = Math.max(0, cellLeft - fixedWidth - horizontalFocusGap);
|
|
2801
|
+
if (cellLeft + cellWidth - nextLeft > viewport.width - rightFixedWidth) nextLeft = cellLeft + cellWidth - viewport.width + rightFixedWidth + horizontalFocusGap;
|
|
2362
2802
|
}
|
|
2363
2803
|
const rowTop = (fixedHeader ? 0 : bodyTop) + cell.rowIndex * rowHeight;
|
|
2364
2804
|
const rowBottom = rowTop + rowHeight * rowSpan;
|
|
@@ -2371,7 +2811,7 @@ function Table({
|
|
|
2371
2811
|
scroller.scrollTop = nextTop;
|
|
2372
2812
|
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
2373
2813
|
scheduleDraw();
|
|
2374
|
-
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
2814
|
+
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
2375
2815
|
const beginEdit = (0, import_react5.useCallback)((cell) => {
|
|
2376
2816
|
const column = columns[cell.columnIndex];
|
|
2377
2817
|
if (!column?.editable || column.dataIndex === void 0) return;
|
|
@@ -2392,8 +2832,9 @@ function Table({
|
|
|
2392
2832
|
const horizontalFocusGap = 0;
|
|
2393
2833
|
const verticalFocusGap = 0;
|
|
2394
2834
|
if (column.fixed === void 0) {
|
|
2395
|
-
|
|
2396
|
-
if (
|
|
2835
|
+
const cellLeft = getScrollableColumnLeft(cell.columnIndex);
|
|
2836
|
+
if (cellLeft - nextLeft < fixedWidth) nextLeft = Math.max(0, cellLeft - fixedWidth - horizontalFocusGap);
|
|
2837
|
+
if (cellLeft + cellWidth - nextLeft > viewport.width - rightFixedWidth) nextLeft = cellLeft + cellWidth - viewport.width + rightFixedWidth + horizontalFocusGap;
|
|
2397
2838
|
}
|
|
2398
2839
|
const rowTop = (fixedHeader ? 0 : bodyTop) + cell.rowIndex * rowHeight;
|
|
2399
2840
|
const rowBottom = rowTop + rowHeight * rowSpan;
|
|
@@ -2415,7 +2856,7 @@ function Table({
|
|
|
2415
2856
|
return;
|
|
2416
2857
|
}
|
|
2417
2858
|
setEditing(cell);
|
|
2418
|
-
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
2859
|
+
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
2419
2860
|
const getCellEditKey = (cell) => `${typeof cell.rowKey}:${String(cell.rowKey)}\0${cell.columnKey}`;
|
|
2420
2861
|
const markCellEdited = (cell, previousValue, nextValue) => {
|
|
2421
2862
|
const key = getCellEditKey(cell);
|
|
@@ -2546,10 +2987,13 @@ function Table({
|
|
|
2546
2987
|
const visibleRowHeight = fixedHeader ? renderHeight - bodyTop : renderHeight;
|
|
2547
2988
|
if (rowTop < scroller.scrollTop) scroller.scrollTop = rowTop;
|
|
2548
2989
|
if (rowBottom > scroller.scrollTop + visibleRowHeight) scroller.scrollTop = rowBottom - visibleRowHeight;
|
|
2549
|
-
if (columns[columnIndex].fixed === void 0
|
|
2550
|
-
|
|
2990
|
+
if (columns[columnIndex].fixed === void 0) {
|
|
2991
|
+
const cellLeft = getScrollableColumnLeft(columnIndex);
|
|
2992
|
+
if (cellLeft < scroller.scrollLeft + fixedWidth) scroller.scrollLeft = Math.max(0, cellLeft - fixedWidth);
|
|
2993
|
+
if (cellLeft + cellWidth > scroller.scrollLeft + viewport.width - rightFixedWidth) scroller.scrollLeft = cellLeft + cellWidth - viewport.width + rightFixedWidth;
|
|
2994
|
+
}
|
|
2551
2995
|
}
|
|
2552
|
-
}, [beginEdit, bodyTop, columns, editing, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, metrics, rightFixedWidth, rowHeight, rows, selection, setSelection, viewport.width]);
|
|
2996
|
+
}, [beginEdit, bodyTop, columns, editing, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, selection, setSelection, viewport.width]);
|
|
2553
2997
|
const editorStyle = (0, import_react5.useMemo)(() => {
|
|
2554
2998
|
if (!editing) return void 0;
|
|
2555
2999
|
const metric = metrics[editing.columnIndex];
|
|
@@ -2557,64 +3001,82 @@ function Table({
|
|
|
2557
3001
|
const span = getCellSpan(editing.rowIndex, editing.columnIndex);
|
|
2558
3002
|
const cellWidth = getCellDisplayWidth(editing.columnIndex, span?.colSpan ?? 1);
|
|
2559
3003
|
const cellHeight = rowHeight * (span?.rowSpan ?? 1);
|
|
2560
|
-
const cellLeft = fixedSide === "left" ?
|
|
3004
|
+
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;
|
|
2561
3005
|
return {
|
|
2562
3006
|
left: (fixedSide ? cellLeft : Math.max(cellLeft, fixedWidth)) + 1,
|
|
2563
3007
|
top: Math.max(fixedHeader ? bodyTop : 0, bodyTop + editing.rowIndex * rowHeight - scrollRef.current.top) + 1,
|
|
2564
3008
|
width: cellWidth - 2,
|
|
2565
3009
|
height: cellHeight - 2
|
|
2566
3010
|
};
|
|
2567
|
-
}, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, metrics, rightFixedOffsets, rowHeight, viewport.width]);
|
|
3011
|
+
}, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rowHeight, viewport.width]);
|
|
2568
3012
|
const handleColumnPointerDown = (0, import_react5.useCallback)((event) => {
|
|
2569
3013
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
2570
3014
|
const localY = event.clientY - rect.top;
|
|
2571
3015
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
2572
3016
|
if (localY < headerY || localY >= headerY + headerHeight) return;
|
|
2573
|
-
const
|
|
2574
|
-
if (
|
|
3017
|
+
const resizeHit = locateHeaderResizeHit(event.clientX, event.clientY);
|
|
3018
|
+
if (resizeHit) {
|
|
3019
|
+
const { cell: resizeCell, edge: resizeEdge } = resizeHit;
|
|
2575
3020
|
event.preventDefault();
|
|
2576
3021
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2577
|
-
const
|
|
2578
|
-
const
|
|
3022
|
+
const resizeIndex = resizeCell.endIndex;
|
|
3023
|
+
const resizeIndices = resizeCell.leaf ? [resizeIndex] : Array.from({ length: resizeCell.endIndex - resizeCell.startIndex + 1 }, (_, index) => resizeCell.startIndex + index);
|
|
3024
|
+
const startWidths = resizeIndices.map((index) => metrics[index].width);
|
|
3025
|
+
const startGuideX = getHeaderCellLeft(resizeCell) + (resizeEdge === "right" ? getHeaderCellWidth(resizeCell) : 0);
|
|
2579
3026
|
columnDragRef.current = {
|
|
2580
3027
|
type: "resize",
|
|
2581
3028
|
columnIndex: resizeIndex,
|
|
2582
3029
|
startX: event.clientX,
|
|
2583
|
-
startWidth:
|
|
3030
|
+
startWidth: startWidths.reduce((total, width2) => total + width2, 0),
|
|
2584
3031
|
startGuideX,
|
|
2585
|
-
|
|
2586
|
-
|
|
3032
|
+
guideTop: headerRowOffsets[resizeCell.level] ?? 0,
|
|
3033
|
+
resizeEdge,
|
|
3034
|
+
resizeIndices,
|
|
3035
|
+
startWidths
|
|
2587
3036
|
};
|
|
2588
3037
|
suppressClickRef.current = true;
|
|
3038
|
+
setResizeGuideTop(headerRowOffsets[resizeCell.level] ?? 0);
|
|
2589
3039
|
setResizeGuideX(startGuideX);
|
|
2590
3040
|
return;
|
|
2591
3041
|
}
|
|
2592
|
-
}, [
|
|
3042
|
+
}, [fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerHeight, headerRowOffsets, locateHeaderResizeHit, metrics]);
|
|
2593
3043
|
const handleColumnPointerMove = (0, import_react5.useCallback)((event) => {
|
|
2594
3044
|
const drag = columnDragRef.current;
|
|
2595
3045
|
if (!drag) return;
|
|
2596
3046
|
const column = columns[drag.columnIndex];
|
|
2597
3047
|
const minWidth = getMinimumColumnWidth(column, columnDraggable);
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
const
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
3048
|
+
const pointerDelta = Math.round(event.clientX - drag.startX);
|
|
3049
|
+
const delta = drag.resizeEdge === "left" ? -pointerDelta : pointerDelta;
|
|
3050
|
+
if (drag.resizeIndices.length > 1) {
|
|
3051
|
+
const minWidths = drag.resizeIndices.map((index) => getMinimumColumnWidth(columns[index], columnDraggable));
|
|
3052
|
+
const minTotalWidth = minWidths.reduce((total, width3) => total + width3, 0);
|
|
3053
|
+
const targetTotalWidth = Math.max(minTotalWidth, drag.startWidth + delta);
|
|
3054
|
+
const ratio = drag.startWidth > 0 ? targetTotalWidth / drag.startWidth : 1;
|
|
3055
|
+
const nextWidths = drag.startWidths.map((width3, index) => Math.max(minWidths[index], Math.round(width3 * ratio)));
|
|
3056
|
+
let remainder = targetTotalWidth - nextWidths.reduce((total, width3) => total + width3, 0);
|
|
3057
|
+
for (let index = nextWidths.length - 1; index >= 0 && remainder !== 0; index -= 1) {
|
|
3058
|
+
const next = nextWidths[index] + (remainder > 0 ? 1 : -1);
|
|
3059
|
+
if (next < minWidths[index]) continue;
|
|
3060
|
+
nextWidths[index] = next;
|
|
3061
|
+
remainder += remainder > 0 ? -1 : 1;
|
|
3062
|
+
}
|
|
3063
|
+
drag.resizeIndices.forEach((columnIndex, index) => {
|
|
3064
|
+
resizeColumn(columns[columnIndex].key, nextWidths[index]);
|
|
3065
|
+
});
|
|
3066
|
+
setResizeGuideX(drag.startGuideX + (drag.resizeEdge === "left" ? drag.startWidth - targetTotalWidth : targetTotalWidth - drag.startWidth));
|
|
2606
3067
|
return;
|
|
2607
3068
|
}
|
|
2608
3069
|
const width2 = Math.max(minWidth, Math.round(drag.startWidth + delta));
|
|
2609
|
-
|
|
2610
|
-
setResizeGuideX(drag.startGuideX + width2 - drag.startWidth);
|
|
2611
|
-
}, [columnDraggable, columns,
|
|
3070
|
+
resizeColumn(column.key, width2);
|
|
3071
|
+
setResizeGuideX(drag.startGuideX + (drag.resizeEdge === "left" ? drag.startWidth - width2 : width2 - drag.startWidth));
|
|
3072
|
+
}, [columnDraggable, columns, resizeColumn]);
|
|
2612
3073
|
const handleColumnPointerUp = (0, import_react5.useCallback)((event) => {
|
|
2613
3074
|
const drag = columnDragRef.current;
|
|
2614
3075
|
if (!drag) return;
|
|
2615
3076
|
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2616
3077
|
columnDragRef.current = null;
|
|
2617
3078
|
setResizeGuideX(null);
|
|
3079
|
+
setResizeGuideTop(0);
|
|
2618
3080
|
}, []);
|
|
2619
3081
|
const queueSortStateChange = (0, import_react5.useCallback)((next) => {
|
|
2620
3082
|
setDisplaySortState(next);
|
|
@@ -2627,7 +3089,7 @@ function Table({
|
|
|
2627
3089
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
2628
3090
|
const column = columns[columnIndex];
|
|
2629
3091
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
2630
|
-
const top = (
|
|
3092
|
+
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
2631
3093
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2632
3094
|
let right = left + metrics[columnIndex].width - (visibleActions.drag ? 18 : 4);
|
|
2633
3095
|
const icons = [];
|
|
@@ -2653,44 +3115,87 @@ function Table({
|
|
|
2653
3115
|
}
|
|
2654
3116
|
return icons;
|
|
2655
3117
|
};
|
|
2656
|
-
const
|
|
2657
|
-
|
|
2658
|
-
const { columnIndex, action } = visibleHeaderTooltip;
|
|
2659
|
-
const column = columns[columnIndex];
|
|
3118
|
+
const createHeaderTooltip = (0, import_react5.useCallback)((action, columnIndex, cell) => {
|
|
3119
|
+
const column = cell?.column ?? columns[columnIndex];
|
|
2660
3120
|
if (!column) return null;
|
|
2661
|
-
const
|
|
2662
|
-
const
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
3121
|
+
const cellLeft = cell ? getHeaderCellLeft(cell) : getDisplayedColumnLeft(columnIndex);
|
|
3122
|
+
const cellWidth = cell ? getHeaderCellWidth(cell) : metrics[columnIndex]?.width ?? 0;
|
|
3123
|
+
const level = cell?.level ?? headerDepth - 1;
|
|
3124
|
+
const rowTop = (fixedHeader ? 0 : -scrollPosition.top) + (headerRowOffsets[level] ?? 0);
|
|
3125
|
+
const rowHeight2 = headerRowHeights[level] ?? baseHeaderHeight;
|
|
3126
|
+
let anchorX = cellLeft + cellWidth / 2;
|
|
3127
|
+
let anchorLeft = cellLeft;
|
|
3128
|
+
let label = column.title;
|
|
2666
3129
|
if (action === "title") {
|
|
2667
|
-
const
|
|
2668
|
-
const
|
|
2669
|
-
|
|
2670
|
-
const
|
|
2671
|
-
const
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
3130
|
+
const canvas = canvasRef.current;
|
|
3131
|
+
const context = canvas?.getContext("2d");
|
|
3132
|
+
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3133
|
+
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3134
|
+
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3135
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * 18 : columnDraggable ? 18 : 0;
|
|
3136
|
+
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3137
|
+
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3138
|
+
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
3139
|
+
if (column.align === "right") {
|
|
3140
|
+
anchorX = cellLeft + contentWidth2 - 10;
|
|
3141
|
+
anchorLeft = anchorX - textWidth;
|
|
3142
|
+
} else if (column.align === "center") {
|
|
3143
|
+
anchorX = cellLeft + contentWidth2 / 2 + textWidth / 2;
|
|
3144
|
+
anchorLeft = cellLeft + contentWidth2 / 2 - textWidth / 2;
|
|
3145
|
+
} else {
|
|
3146
|
+
anchorLeft = cellLeft + 10;
|
|
3147
|
+
anchorX = anchorLeft + textWidth;
|
|
3148
|
+
}
|
|
2675
3149
|
} else if (action === "drag") {
|
|
2676
|
-
anchorX =
|
|
3150
|
+
anchorX = cellLeft + cellWidth;
|
|
2677
3151
|
anchorLeft = anchorX;
|
|
2678
3152
|
label = labels.dragColumn;
|
|
2679
3153
|
} else if (action === "sort") {
|
|
2680
3154
|
const direction = displaySortState?.columnKey === column.key ? displaySortState.direction : null;
|
|
2681
3155
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
2682
|
-
|
|
2683
|
-
|
|
3156
|
+
anchorX = cellLeft + cellWidth - 22;
|
|
3157
|
+
anchorLeft = anchorX;
|
|
3158
|
+
} else if (action === "filter") {
|
|
2684
3159
|
const value = filterValues[column.key];
|
|
2685
3160
|
label = value ? labels.filterWithValue(value) : labels.filter;
|
|
3161
|
+
anchorX = cellLeft + cellWidth - 40;
|
|
3162
|
+
anchorLeft = anchorX;
|
|
2686
3163
|
}
|
|
2687
3164
|
const placement = anchorX + 328 > viewport.width ? "left" : "right";
|
|
2688
3165
|
return {
|
|
3166
|
+
key: `${action}:${cell ? `cell:${cell.key}:${cell.level}` : `column:${column.key}`}:${Math.round(anchorX)}:${Math.round(rowTop)}`,
|
|
3167
|
+
columnIndex,
|
|
3168
|
+
action,
|
|
2689
3169
|
left: placement === "right" ? anchorX + 8 : Math.max(8, anchorLeft - 8),
|
|
2690
|
-
top:
|
|
3170
|
+
top: rowTop + rowHeight2 / 2,
|
|
2691
3171
|
label,
|
|
2692
3172
|
placement
|
|
2693
3173
|
};
|
|
3174
|
+
}, [baseHeaderHeight, columnDraggable, columns, displaySortState, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, viewport.width]);
|
|
3175
|
+
const isPointerOnHeaderTitle = (0, import_react5.useCallback)((clientX, clientY, cell) => {
|
|
3176
|
+
const canvas = canvasRef.current;
|
|
3177
|
+
if (!canvas) return false;
|
|
3178
|
+
const rect = canvas.getBoundingClientRect();
|
|
3179
|
+
const localX = clientX - rect.left;
|
|
3180
|
+
const localY = clientY - rect.top;
|
|
3181
|
+
const column = cell.column;
|
|
3182
|
+
const cellLeft = getHeaderCellLeft(cell);
|
|
3183
|
+
const cellWidth = getHeaderCellWidth(cell);
|
|
3184
|
+
const rowTop = (fixedHeader ? 0 : -scrollRef.current.top) + (headerRowOffsets[cell.level] ?? 0);
|
|
3185
|
+
const context = canvas.getContext("2d");
|
|
3186
|
+
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3187
|
+
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3188
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3189
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * 18 : columnDraggable ? 18 : 0;
|
|
3190
|
+
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3191
|
+
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3192
|
+
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
3193
|
+
const textTop = rowTop + 8;
|
|
3194
|
+
return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
|
|
3195
|
+
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerRowOffsets]);
|
|
3196
|
+
const headerTooltip = (() => {
|
|
3197
|
+
if (!visibleHeaderTooltip) return null;
|
|
3198
|
+
return visibleHeaderTooltip;
|
|
2694
3199
|
})();
|
|
2695
3200
|
const getRangeBounds = () => selectionRange ? {
|
|
2696
3201
|
rowStart: Math.min(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex),
|
|
@@ -2749,7 +3254,7 @@ function Table({
|
|
|
2749
3254
|
}, 1800);
|
|
2750
3255
|
};
|
|
2751
3256
|
const showHeaderTooltipAfterDelay = (next) => {
|
|
2752
|
-
const nextKey = next ?
|
|
3257
|
+
const nextKey = next ? next.key : "";
|
|
2753
3258
|
if (nextKey && pendingHeaderTooltipKeyRef.current === nextKey) return;
|
|
2754
3259
|
pendingHeaderTooltipKeyRef.current = nextKey;
|
|
2755
3260
|
if (headerTooltipTimerRef.current !== null) clearTimeout(headerTooltipTimerRef.current);
|
|
@@ -2997,12 +3502,14 @@ function Table({
|
|
|
2997
3502
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
2998
3503
|
const column = columns[columnIndex];
|
|
2999
3504
|
const currentScrollTop = scrollRef.current.top;
|
|
3505
|
+
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3506
|
+
const leafTop = headerTop + headerLeafTop;
|
|
3000
3507
|
if (column.rowNumber) {
|
|
3001
3508
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3002
3509
|
"div",
|
|
3003
3510
|
{
|
|
3004
3511
|
className: "rvg-header-title",
|
|
3005
|
-
style: { left, top:
|
|
3512
|
+
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
3006
3513
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: column.title })
|
|
3007
3514
|
},
|
|
3008
3515
|
column.key
|
|
@@ -3016,7 +3523,7 @@ function Table({
|
|
|
3016
3523
|
"div",
|
|
3017
3524
|
{
|
|
3018
3525
|
className: "rvg-header-selection-icon",
|
|
3019
|
-
style: { left, top:
|
|
3526
|
+
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight },
|
|
3020
3527
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectionIcon, { checked: allSelected, indeterminate })
|
|
3021
3528
|
},
|
|
3022
3529
|
column.key
|
|
@@ -3029,11 +3536,13 @@ function Table({
|
|
|
3029
3536
|
"div",
|
|
3030
3537
|
{
|
|
3031
3538
|
className: "rvg-header-title is-custom",
|
|
3539
|
+
"data-level": headerDepth - 1,
|
|
3540
|
+
"data-measure-key": column.key,
|
|
3032
3541
|
style: {
|
|
3033
3542
|
left,
|
|
3034
|
-
top:
|
|
3543
|
+
top: leafTop,
|
|
3035
3544
|
width: Math.max(0, metrics[columnIndex].width - actionWidth),
|
|
3036
|
-
height:
|
|
3545
|
+
height: headerLeafHeight,
|
|
3037
3546
|
justifyContent: column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start",
|
|
3038
3547
|
textAlign: column.align === "right" ? "right" : column.align === "center" ? "center" : "left"
|
|
3039
3548
|
},
|
|
@@ -3041,8 +3550,10 @@ function Table({
|
|
|
3041
3550
|
"span",
|
|
3042
3551
|
{
|
|
3043
3552
|
ref: (node) => {
|
|
3044
|
-
if (node)
|
|
3045
|
-
|
|
3553
|
+
if (node) {
|
|
3554
|
+
customHeaderContentRefs.current.set(column.key, node);
|
|
3555
|
+
requestAnimationFrame(measureCustomHeaderHeight);
|
|
3556
|
+
} else customHeaderContentRefs.current.delete(column.key);
|
|
3046
3557
|
},
|
|
3047
3558
|
children: column.renderHeader(column)
|
|
3048
3559
|
}
|
|
@@ -3053,6 +3564,61 @@ function Table({
|
|
|
3053
3564
|
}
|
|
3054
3565
|
return null;
|
|
3055
3566
|
};
|
|
3567
|
+
const renderGroupedHeaderCell = (cell) => {
|
|
3568
|
+
const startMetric = metrics[cell.startIndex];
|
|
3569
|
+
const endMetric = metrics[cell.endIndex];
|
|
3570
|
+
if (!startMetric || !endMetric) return null;
|
|
3571
|
+
const column = cell.column;
|
|
3572
|
+
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
3573
|
+
const currentScrollTop = scrollRef.current.top;
|
|
3574
|
+
const rowHeightForLevel = headerRowHeights[cell.level] ?? baseHeaderHeight;
|
|
3575
|
+
const headerTop = (fixedHeader ? 0 : -currentScrollTop) + (headerRowOffsets[cell.level] ?? 0);
|
|
3576
|
+
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3577
|
+
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3578
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
3579
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * 18 : columnDraggable && !cell.leaf ? 18 : 0;
|
|
3580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3581
|
+
"div",
|
|
3582
|
+
{
|
|
3583
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}`,
|
|
3584
|
+
"data-level": cell.level,
|
|
3585
|
+
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3586
|
+
style: {
|
|
3587
|
+
left,
|
|
3588
|
+
top: headerTop,
|
|
3589
|
+
width: width2,
|
|
3590
|
+
height: rowHeightForLevel,
|
|
3591
|
+
paddingRight: cell.leaf ? actionWidth + 10 : 10,
|
|
3592
|
+
justifyContent: column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start",
|
|
3593
|
+
textAlign: column.align === "right" ? "right" : column.align === "center" ? "center" : "left"
|
|
3594
|
+
},
|
|
3595
|
+
children: [
|
|
3596
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3597
|
+
"span",
|
|
3598
|
+
{
|
|
3599
|
+
ref: (node) => {
|
|
3600
|
+
if (!column.renderHeader) return;
|
|
3601
|
+
const key = `group:${cell.key}:${cell.level}`;
|
|
3602
|
+
if (node) {
|
|
3603
|
+
customHeaderContentRefs.current.set(key, node);
|
|
3604
|
+
requestAnimationFrame(measureCustomHeaderHeight);
|
|
3605
|
+
} else customHeaderContentRefs.current.delete(key);
|
|
3606
|
+
},
|
|
3607
|
+
children: column.renderHeader ? column.renderHeader(column) : column.title
|
|
3608
|
+
}
|
|
3609
|
+
),
|
|
3610
|
+
!cell.leaf && columnDraggable && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3611
|
+
HeaderDragIcon,
|
|
3612
|
+
{
|
|
3613
|
+
className: `rvg-header-icon rvg-header-drag-icon${hoveredHeaderAction?.columnIndex === cell.startIndex && hoveredHeaderAction.action === "drag" ? " is-hovered" : ""}`,
|
|
3614
|
+
style: { left: width2 - 16, top: (rowHeightForLevel - 14) / 2 }
|
|
3615
|
+
}
|
|
3616
|
+
)
|
|
3617
|
+
]
|
|
3618
|
+
},
|
|
3619
|
+
`group:${cell.key}:${cell.level}`
|
|
3620
|
+
);
|
|
3621
|
+
};
|
|
3056
3622
|
const rangeHandlePosition = (() => {
|
|
3057
3623
|
if (!rangeSelection) return null;
|
|
3058
3624
|
const bounds = getRangeBounds();
|
|
@@ -3244,15 +3810,19 @@ function Table({
|
|
|
3244
3810
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
3245
3811
|
const columnIndex = locateColumn(event.clientX);
|
|
3246
3812
|
const inHeader = localY >= headerY && localY < headerY + headerHeight;
|
|
3247
|
-
const
|
|
3248
|
-
const
|
|
3249
|
-
const
|
|
3250
|
-
const
|
|
3813
|
+
const inLeafHeader = inHeader && localY >= headerY + headerLeafTop;
|
|
3814
|
+
const hoveredHeaderCell = inHeader ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
3815
|
+
const hoveredAction = inLeafHeader ? locateHeaderAction(event.clientX, columnIndex) : null;
|
|
3816
|
+
const hoveredDragHandle = Boolean(hoveredHeaderCell && locateHeaderCellDragHandle(event.clientX, hoveredHeaderCell));
|
|
3817
|
+
const hoveredDragColumnIndex = hoveredHeaderCell?.startIndex ?? columnIndex;
|
|
3818
|
+
const hoveredTitle = inHeader && !hoveredAction && !hoveredDragHandle && hoveredHeaderCell && Boolean(hoveredHeaderCell.column.title) && isPointerOnHeaderTitle(event.clientX, event.clientY, hoveredHeaderCell) && (tooltipConfig.header || hoveredHeaderCell.leaf && isHeaderTitleTruncated(hoveredHeaderCell.startIndex));
|
|
3819
|
+
const nextHover = hoveredAction ? { columnIndex, action: hoveredAction } : hoveredDragHandle ? { columnIndex: hoveredDragColumnIndex, action: "drag" } : hoveredTitle ? { columnIndex: hoveredHeaderCell.startIndex, action: "title" } : null;
|
|
3820
|
+
const nextTooltip = hoveredAction && hoveredHeaderCell ? createHeaderTooltip(hoveredAction, columnIndex, hoveredHeaderCell) : hoveredDragHandle && hoveredHeaderCell ? createHeaderTooltip("drag", hoveredDragColumnIndex, hoveredHeaderCell) : hoveredTitle && hoveredHeaderCell ? createHeaderTooltip("title", hoveredHeaderCell.startIndex, hoveredHeaderCell) : null;
|
|
3251
3821
|
const previousHover = hoveredHeaderActionRef.current;
|
|
3252
3822
|
if (previousHover?.columnIndex !== nextHover?.columnIndex || previousHover?.action !== nextHover?.action) {
|
|
3253
3823
|
hoveredHeaderActionRef.current = nextHover;
|
|
3254
3824
|
setHoveredHeaderAction(nextHover);
|
|
3255
|
-
showHeaderTooltipAfterDelay(
|
|
3825
|
+
showHeaderTooltipAfterDelay(nextTooltip);
|
|
3256
3826
|
scheduleDraw();
|
|
3257
3827
|
}
|
|
3258
3828
|
if (inHeader) {
|
|
@@ -3276,8 +3846,8 @@ function Table({
|
|
|
3276
3846
|
if (annotation?.content.trim()) {
|
|
3277
3847
|
const cellLeft = getDisplayedColumnLeft(cell.columnIndex);
|
|
3278
3848
|
const cellTop = bodyTop + cell.rowIndex * rowHeight - scrollRef.current.top;
|
|
3279
|
-
const
|
|
3280
|
-
showCellTooltip(
|
|
3849
|
+
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 };
|
|
3850
|
+
showCellTooltip(nextTooltip2);
|
|
3281
3851
|
} else {
|
|
3282
3852
|
const label = getCellLabel(cell.rowIndex, cell.columnIndex);
|
|
3283
3853
|
const context = event.currentTarget.getContext("2d");
|
|
@@ -3304,7 +3874,7 @@ function Table({
|
|
|
3304
3874
|
showCellTooltipAfterDelay(null);
|
|
3305
3875
|
} else {
|
|
3306
3876
|
const placement = textRight + 330 > viewport.width ? "left" : "right";
|
|
3307
|
-
const
|
|
3877
|
+
const nextTooltip2 = {
|
|
3308
3878
|
rowIndex: cell.rowIndex,
|
|
3309
3879
|
columnIndex: cell.columnIndex,
|
|
3310
3880
|
left: placement === "right" ? textRight + 16 : Math.max(8, textLeft - 16),
|
|
@@ -3312,13 +3882,13 @@ function Table({
|
|
|
3312
3882
|
label,
|
|
3313
3883
|
placement
|
|
3314
3884
|
};
|
|
3315
|
-
showCellTooltipAfterDelay(
|
|
3885
|
+
showCellTooltipAfterDelay(nextTooltip2);
|
|
3316
3886
|
}
|
|
3317
3887
|
}
|
|
3318
3888
|
}
|
|
3319
3889
|
}
|
|
3320
3890
|
}
|
|
3321
|
-
const cursor = inHeader &&
|
|
3891
|
+
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";
|
|
3322
3892
|
if (event.currentTarget.style.cursor !== cursor) event.currentTarget.style.cursor = cursor;
|
|
3323
3893
|
},
|
|
3324
3894
|
onMouseLeave: (event) => {
|
|
@@ -3361,6 +3931,7 @@ function Table({
|
|
|
3361
3931
|
const headerY = fixedHeader ? 0 : -scrollRef.current.top;
|
|
3362
3932
|
if (localY >= headerY && localY < headerY + headerHeight) {
|
|
3363
3933
|
clickedCellRef.current = null;
|
|
3934
|
+
if (localY < headerY + headerLeafTop) return;
|
|
3364
3935
|
const columnIndex = locateColumn(event.clientX);
|
|
3365
3936
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
3366
3937
|
if (action === "sort") {
|
|
@@ -3422,21 +3993,30 @@ function Table({
|
|
|
3422
3993
|
className: "rvg-text-scroll-content",
|
|
3423
3994
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
3424
3995
|
children: [
|
|
3425
|
-
columns.map((column, columnIndex) => column.fixed ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderTitle(columnIndex,
|
|
3996
|
+
columns.map((column, columnIndex) => column.fixed || columnIndex < utilityColumnCount || headerDepth > 1 ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderTitle(columnIndex, getScrollableColumnLeft(columnIndex)) }, column.key) : null),
|
|
3997
|
+
headerCells.map((cell) => {
|
|
3998
|
+
if (columns[cell.startIndex]?.fixed) return null;
|
|
3999
|
+
if (cell.endIndex < domRange.columnStart || cell.startIndex >= domRange.columnEnd) return null;
|
|
4000
|
+
return renderGroupedHeaderCell(cell);
|
|
4001
|
+
}),
|
|
3426
4002
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("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) => {
|
|
3427
4003
|
if (column.fixed || columnIndex < domRange.columnStart || columnIndex >= domRange.columnEnd) return null;
|
|
3428
|
-
return renderCellText(rowIndex, columnIndex,
|
|
4004
|
+
return renderCellText(rowIndex, columnIndex, getScrollableColumnLeft(columnIndex));
|
|
3429
4005
|
})) })
|
|
3430
4006
|
]
|
|
3431
4007
|
}
|
|
3432
4008
|
) }),
|
|
3433
4009
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("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) => {
|
|
3434
4010
|
if (!column.fixed) return null;
|
|
3435
|
-
const left = column.fixed === "left" ?
|
|
4011
|
+
const left = column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width;
|
|
3436
4012
|
return renderCellText(rowIndex, columnIndex, left);
|
|
3437
4013
|
})) }),
|
|
3438
|
-
columns.map((column, columnIndex) => column.fixed === "left" ? renderHeaderTitle(columnIndex, metrics[columnIndex].left) : null),
|
|
3439
|
-
|
|
4014
|
+
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),
|
|
4015
|
+
headerCells.map((cell) => columns[cell.startIndex]?.fixed ? renderGroupedHeaderCell(cell) : null),
|
|
4016
|
+
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
4017
|
+
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-shadow is-right", style: { right: rightFixedWidth } }),
|
|
4018
|
+
hasVerticalBorders && fixedWidth > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-border is-left", style: { left: fixedWidth - 1 } }),
|
|
4019
|
+
hasVerticalBorders && rightFixedWidth > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-border is-right", style: { right: rightFixedWidth } })
|
|
3440
4020
|
] }),
|
|
3441
4021
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-spacer", style: { width: contentWidth, height: contentHeight + bodyTop, marginTop: -renderHeight } })
|
|
3442
4022
|
] }),
|
|
@@ -3444,18 +4024,18 @@ function Table({
|
|
|
3444
4024
|
"div",
|
|
3445
4025
|
{
|
|
3446
4026
|
className: `rvg-summary-row is-${summaryPosition}${hasVerticalBorders ? "" : " is-vertical-borderless"}`,
|
|
3447
|
-
style: { height: rowHeight, top: summaryPosition === "top" ? headerHeight : void 0 },
|
|
4027
|
+
style: { height: rowHeight, top: summaryPosition === "top" ? fixedHeader ? headerHeight : headerHeight - currentScroll.top : void 0 },
|
|
3448
4028
|
children: [
|
|
3449
4029
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-summary-scroll-clip", style: { left: fixedWidth, right: rightFixedWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3450
4030
|
"div",
|
|
3451
4031
|
{
|
|
3452
4032
|
className: "rvg-summary-scroll-content",
|
|
3453
4033
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
3454
|
-
children: columns.map((column, columnIndex) => column.fixed ? null : renderSummaryCell(columnIndex,
|
|
4034
|
+
children: columns.map((column, columnIndex) => column.fixed ? null : renderSummaryCell(columnIndex, getScrollableColumnLeft(columnIndex)))
|
|
3455
4035
|
}
|
|
3456
4036
|
) }),
|
|
3457
4037
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rvg-summary-fixed-layer", children: [
|
|
3458
|
-
columns.map((column, columnIndex) => column.fixed === "left" ? renderSummaryCell(columnIndex,
|
|
4038
|
+
columns.map((column, columnIndex) => column.fixed === "left" ? renderSummaryCell(columnIndex, leftFixedOffsets.get(columnIndex) ?? 0) : null),
|
|
3459
4039
|
columns.map((column, columnIndex) => column.fixed === "right" ? renderSummaryCell(columnIndex, viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width) : null)
|
|
3460
4040
|
] }),
|
|
3461
4041
|
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-summary-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
@@ -3472,11 +4052,11 @@ function Table({
|
|
|
3472
4052
|
ref: scrollingHeaderIconsRef,
|
|
3473
4053
|
className: "rvg-header-icon-layer rvg-header-icon-layer-scroll",
|
|
3474
4054
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-scrollRef.current.left}px)` },
|
|
3475
|
-
children: columns.map((column, index) => column.fixed ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderIcons(index,
|
|
4055
|
+
children: columns.map((column, index) => column.fixed ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderIcons(index, getScrollableColumnLeft(index)) }, column.key))
|
|
3476
4056
|
}
|
|
3477
4057
|
) }),
|
|
3478
4058
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rvg-header-icon-layer", children: [
|
|
3479
|
-
columns.map((column, index) => column.fixed === "left" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderIcons(index,
|
|
4059
|
+
columns.map((column, index) => column.fixed === "left" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderIcons(index, leftFixedOffsets.get(index) ?? 0) }, column.key) : null),
|
|
3480
4060
|
columns.map((column, index) => column.fixed === "right" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderIcons(index, viewport.width - (rightFixedOffsets.get(index) ?? 0) - metrics[index].width) }, column.key) : null)
|
|
3481
4061
|
] })
|
|
3482
4062
|
] }),
|
|
@@ -3753,12 +4333,40 @@ function Table({
|
|
|
3753
4333
|
] })
|
|
3754
4334
|
] }) }),
|
|
3755
4335
|
toast && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `rvg-toast is-${toast.type}`, role: "status", children: toast.message }),
|
|
4336
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4337
|
+
"div",
|
|
4338
|
+
{
|
|
4339
|
+
ref: verticalScrollbarRef,
|
|
4340
|
+
className: "rvg-vertical-scrollbar",
|
|
4341
|
+
onPointerEnter: () => keepCustomScrollbarVisible("vertical"),
|
|
4342
|
+
onPointerLeave: () => releaseCustomScrollbarVisible("vertical"),
|
|
4343
|
+
onPointerDown: handleVerticalScrollbarPointerDown,
|
|
4344
|
+
onPointerMove: handleVerticalScrollbarPointerMove,
|
|
4345
|
+
onPointerUp: handleVerticalScrollbarPointerUp,
|
|
4346
|
+
onPointerCancel: handleVerticalScrollbarPointerUp,
|
|
4347
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: verticalScrollbarThumbRef, className: "rvg-vertical-scrollbar-thumb" })
|
|
4348
|
+
}
|
|
4349
|
+
),
|
|
4350
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4351
|
+
"div",
|
|
4352
|
+
{
|
|
4353
|
+
ref: horizontalScrollbarRef,
|
|
4354
|
+
className: "rvg-horizontal-scrollbar",
|
|
4355
|
+
onPointerEnter: () => keepCustomScrollbarVisible("horizontal"),
|
|
4356
|
+
onPointerLeave: () => releaseCustomScrollbarVisible("horizontal"),
|
|
4357
|
+
onPointerDown: handleHorizontalScrollbarPointerDown,
|
|
4358
|
+
onPointerMove: handleHorizontalScrollbarPointerMove,
|
|
4359
|
+
onPointerUp: handleHorizontalScrollbarPointerUp,
|
|
4360
|
+
onPointerCancel: handleHorizontalScrollbarPointerUp,
|
|
4361
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: horizontalScrollbarThumbRef, className: "rvg-horizontal-scrollbar-thumb" })
|
|
4362
|
+
}
|
|
4363
|
+
),
|
|
3756
4364
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: dragGuideRef, className: "rvg-column-guide" }),
|
|
3757
4365
|
resizeGuideX !== null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3758
4366
|
"div",
|
|
3759
4367
|
{
|
|
3760
4368
|
className: "rvg-column-guide is-resizing",
|
|
3761
|
-
style: { display: "block", transform: `translateX(${Math.round(resizeGuideX)}px)` }
|
|
4369
|
+
style: { display: "block", top: resizeGuideTop, transform: `translateX(${Math.round(resizeGuideX)}px)` }
|
|
3762
4370
|
}
|
|
3763
4371
|
),
|
|
3764
4372
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: rowDragGuideRef, className: "rvg-row-guide" }),
|