@lensui/lens-table 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -65
- package/dist/index.cjs +558 -140
- package/dist/index.css +56 -28
- package/dist/index.d.cts +79 -38
- package/dist/index.d.ts +79 -38
- package/dist/index.js +559 -141
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -318,16 +318,6 @@ function ContextMenuIcon({ type }) {
|
|
|
318
318
|
};
|
|
319
319
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "rvg-context-menu-svg", viewBox: "0 0 16 16", "aria-hidden": "true", children: paths[type].map((path) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: path }, path)) });
|
|
320
320
|
}
|
|
321
|
-
function RowDragHandleIcon() {
|
|
322
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 16 16", focusable: "false", children: [
|
|
323
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "4", r: "1" }),
|
|
324
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "11", cy: "4", r: "1" }),
|
|
325
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "8", r: "1" }),
|
|
326
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "11", cy: "8", r: "1" }),
|
|
327
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "12", r: "1" }),
|
|
328
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "11", cy: "12", r: "1" })
|
|
329
|
-
] });
|
|
330
|
-
}
|
|
331
321
|
function LoadingSpinnerIcon() {
|
|
332
322
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M20 12a8 8 0 1 1-3.1-6.3" }) });
|
|
333
323
|
}
|
|
@@ -755,6 +745,48 @@ function createRowDragHandleSvg() {
|
|
|
755
745
|
}
|
|
756
746
|
return svg;
|
|
757
747
|
}
|
|
748
|
+
function createHeaderDragHandleSvg() {
|
|
749
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
750
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
751
|
+
svg.setAttribute("aria-hidden", "true");
|
|
752
|
+
for (const cy of [2.5, 7, 11.5]) {
|
|
753
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
754
|
+
circle.setAttribute("cx", "7");
|
|
755
|
+
circle.setAttribute("cy", String(cy));
|
|
756
|
+
circle.setAttribute("r", "1.25");
|
|
757
|
+
svg.appendChild(circle);
|
|
758
|
+
}
|
|
759
|
+
return svg;
|
|
760
|
+
}
|
|
761
|
+
function createHeaderSortSvg(direction) {
|
|
762
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
763
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
764
|
+
svg.setAttribute("aria-hidden", "true");
|
|
765
|
+
for (const [value, active] of [
|
|
766
|
+
["M3 5.5 7 1.5l4 4Z", direction === "asc"],
|
|
767
|
+
["M3 8.5 7 12.5l4-4Z", direction === "desc"]
|
|
768
|
+
]) {
|
|
769
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
770
|
+
path.setAttribute("d", value);
|
|
771
|
+
if (active) path.classList.add("is-active");
|
|
772
|
+
svg.appendChild(path);
|
|
773
|
+
}
|
|
774
|
+
return svg;
|
|
775
|
+
}
|
|
776
|
+
function createHeaderSearchSvg(active) {
|
|
777
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
778
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
779
|
+
svg.setAttribute("aria-hidden", "true");
|
|
780
|
+
if (active) svg.classList.add("is-active");
|
|
781
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
782
|
+
circle.setAttribute("cx", "5.5");
|
|
783
|
+
circle.setAttribute("cy", "5.5");
|
|
784
|
+
circle.setAttribute("r", "4.25");
|
|
785
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
786
|
+
path.setAttribute("d", "m8.75 8.75 2.25 2.25");
|
|
787
|
+
svg.append(circle, path);
|
|
788
|
+
return svg;
|
|
789
|
+
}
|
|
758
790
|
|
|
759
791
|
// src/Table.tsx
|
|
760
792
|
var import_adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
|
|
@@ -775,6 +807,7 @@ function getDisplayLabel(column, row, rowIndex) {
|
|
|
775
807
|
|
|
776
808
|
// src/core/layout.ts
|
|
777
809
|
var DEFAULT_COLUMN_WIDTH = 140;
|
|
810
|
+
var HEADER_ACTION_SLOT_WIDTH = 16;
|
|
778
811
|
function isDataColumn(column) {
|
|
779
812
|
return !column.rowSelection && !column.rowDragHandle && !column.rowNumber;
|
|
780
813
|
}
|
|
@@ -789,7 +822,7 @@ function getHeaderTitleRequiredWidth(column, titleWidth) {
|
|
|
789
822
|
return minimumReadableTitleWidth + (column.align === "center" ? 20 : 22);
|
|
790
823
|
}
|
|
791
824
|
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26) {
|
|
792
|
-
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) /
|
|
825
|
+
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) / HEADER_ACTION_SLOT_WIDTH));
|
|
793
826
|
const candidates = [
|
|
794
827
|
isColumnFilterable(column) ? "filter" : null,
|
|
795
828
|
isColumnSortable(column) ? "sort" : null,
|
|
@@ -868,12 +901,15 @@ var COLORS = {
|
|
|
868
901
|
grid: "#e3e6e8",
|
|
869
902
|
text: "#202124",
|
|
870
903
|
muted: "#5f6368",
|
|
904
|
+
icon: "#9aa0a6",
|
|
905
|
+
borderStrong: "#b8bec4",
|
|
871
906
|
selection: "#1677ff",
|
|
872
907
|
selectionFill: "#edf4ff",
|
|
873
908
|
axisSelectionFill: "#e8f2ff",
|
|
874
909
|
rowHoverFill: "#f6f9fc",
|
|
875
910
|
editedFill: "#fff1b8",
|
|
876
911
|
insertedFill: "#c8ead4",
|
|
912
|
+
columnDropTargetFill: "#eeeeee",
|
|
877
913
|
stripe: "#fafbfc"
|
|
878
914
|
};
|
|
879
915
|
function ellipsizeText(context, text, maxWidth) {
|
|
@@ -893,7 +929,7 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
893
929
|
return `${text.slice(0, start)}${ellipsis}`;
|
|
894
930
|
}
|
|
895
931
|
function paintGrid(options) {
|
|
896
|
-
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;
|
|
932
|
+
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, rowSelectionMode, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget } = options;
|
|
897
933
|
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
898
934
|
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
899
935
|
const colors = { ...COLORS, ...options.colors };
|
|
@@ -939,11 +975,19 @@ function paintGrid(options) {
|
|
|
939
975
|
const getColumnX = (index) => {
|
|
940
976
|
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;
|
|
941
977
|
};
|
|
978
|
+
const getRowDragOffset = (rowIndex) => {
|
|
979
|
+
if (!rowDragPreview || rowIndex === rowDragPreview.sourceIndex) return 0;
|
|
980
|
+
if (rowDragPreview.sourceIndex < rowDragPreview.targetIndex) {
|
|
981
|
+
return rowIndex > rowDragPreview.sourceIndex && rowIndex <= rowDragPreview.targetIndex ? -rowHeight : 0;
|
|
982
|
+
}
|
|
983
|
+
return rowIndex >= rowDragPreview.targetIndex && rowIndex < rowDragPreview.sourceIndex ? rowHeight : 0;
|
|
984
|
+
};
|
|
985
|
+
const rowBelowDragGap = rowDragPreview ? rowDragPreview.sourceIndex <= rowDragPreview.targetIndex ? rowDragPreview.targetIndex + 1 : rowDragPreview.targetIndex : -1;
|
|
942
986
|
const paintBodyColumns = (layer) => {
|
|
943
987
|
const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
|
|
944
988
|
for (let rowIndex = rowStart; rowIndex < range.rowEnd; rowIndex += 1) {
|
|
945
989
|
if (rowDragPreview?.sourceIndex === rowIndex) continue;
|
|
946
|
-
const shift =
|
|
990
|
+
const shift = getRowDragOffset(rowIndex);
|
|
947
991
|
const y = bodyTop + rowIndex * rowHeight - scrollTop + shift;
|
|
948
992
|
const row = rows[rowIndex];
|
|
949
993
|
const rowKey = getRowKey(row, rowIndex);
|
|
@@ -976,6 +1020,10 @@ function paintGrid(options) {
|
|
|
976
1020
|
ctx.fillStyle = colors.rowHoverFill;
|
|
977
1021
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
978
1022
|
}
|
|
1023
|
+
if (columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex) {
|
|
1024
|
+
ctx.fillStyle = colors.columnDropTargetFill;
|
|
1025
|
+
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
1026
|
+
}
|
|
979
1027
|
if (highlightInsertedRows && insertedRowKeys.has(rowKey)) {
|
|
980
1028
|
ctx.fillStyle = colors.insertedFill;
|
|
981
1029
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
@@ -1002,6 +1050,7 @@ function paintGrid(options) {
|
|
|
1002
1050
|
}
|
|
1003
1051
|
ctx.fillStyle = colors.grid;
|
|
1004
1052
|
if (!verticalBorderless) ctx.fillRect(x + cellWidth - 1, y, 1, cellHeight);
|
|
1053
|
+
if (rowIndex === rowBelowDragGap) ctx.fillRect(x, y, cellWidth, 1);
|
|
1005
1054
|
if (!options.suppressLastRowBottomBorder || rowIndex !== rows.length - 1) {
|
|
1006
1055
|
ctx.fillRect(x, y + cellHeight - 1, cellWidth, 1);
|
|
1007
1056
|
}
|
|
@@ -1028,6 +1077,59 @@ function paintGrid(options) {
|
|
|
1028
1077
|
if (columnIndex === rangeColumnStart) ctx.fillRect(x, y, 2, cellHeight);
|
|
1029
1078
|
if (columnIndex === rangeColumnEnd) ctx.fillRect(x + cellWidth - 2, y, 2, cellHeight);
|
|
1030
1079
|
}
|
|
1080
|
+
if (column.rowDragHandle) {
|
|
1081
|
+
const iconLeft = x + (cellWidth - 16) / 2;
|
|
1082
|
+
const iconTop = y + (cellHeight - 16) / 2;
|
|
1083
|
+
ctx.fillStyle = colors.icon;
|
|
1084
|
+
ctx.beginPath();
|
|
1085
|
+
for (const circleX of [5, 11]) {
|
|
1086
|
+
for (const circleY of [4, 8, 12]) {
|
|
1087
|
+
ctx.moveTo(iconLeft + circleX + 1, iconTop + circleY);
|
|
1088
|
+
ctx.arc(iconLeft + circleX, iconTop + circleY, 1, 0, Math.PI * 2);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
ctx.fill();
|
|
1092
|
+
}
|
|
1093
|
+
if (column.rowSelection) {
|
|
1094
|
+
const iconLeft = x + (cellWidth - 16) / 2;
|
|
1095
|
+
const iconTop = y + (cellHeight - 16) / 2;
|
|
1096
|
+
const checked = selectedRowKeys.has(rowKey);
|
|
1097
|
+
ctx.save();
|
|
1098
|
+
ctx.lineWidth = 1;
|
|
1099
|
+
if (rowSelectionMode === "single") {
|
|
1100
|
+
ctx.beginPath();
|
|
1101
|
+
ctx.arc(iconLeft + 8, iconTop + 8, 6.25, 0, Math.PI * 2);
|
|
1102
|
+
ctx.fillStyle = colors.background;
|
|
1103
|
+
ctx.fill();
|
|
1104
|
+
ctx.strokeStyle = checked ? colors.selection : colors.borderStrong;
|
|
1105
|
+
ctx.stroke();
|
|
1106
|
+
if (checked) {
|
|
1107
|
+
ctx.beginPath();
|
|
1108
|
+
ctx.arc(iconLeft + 8, iconTop + 8, 3.25, 0, Math.PI * 2);
|
|
1109
|
+
ctx.fillStyle = colors.selection;
|
|
1110
|
+
ctx.fill();
|
|
1111
|
+
}
|
|
1112
|
+
} else {
|
|
1113
|
+
ctx.beginPath();
|
|
1114
|
+
ctx.roundRect(iconLeft + 1.5, iconTop + 1.5, 13, 13, 3);
|
|
1115
|
+
ctx.fillStyle = checked ? colors.selection : colors.background;
|
|
1116
|
+
ctx.fill();
|
|
1117
|
+
ctx.strokeStyle = checked ? colors.selection : colors.borderStrong;
|
|
1118
|
+
ctx.stroke();
|
|
1119
|
+
if (checked) {
|
|
1120
|
+
ctx.beginPath();
|
|
1121
|
+
ctx.moveTo(iconLeft + 4.1, iconTop + 8);
|
|
1122
|
+
ctx.lineTo(iconLeft + 6.45, iconTop + 10.35);
|
|
1123
|
+
ctx.lineTo(iconLeft + 11.9, iconTop + 5.15);
|
|
1124
|
+
ctx.strokeStyle = colors.background;
|
|
1125
|
+
ctx.lineWidth = 1.75;
|
|
1126
|
+
ctx.lineCap = "round";
|
|
1127
|
+
ctx.lineJoin = "round";
|
|
1128
|
+
ctx.stroke();
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
ctx.restore();
|
|
1132
|
+
}
|
|
1031
1133
|
if (!column.rowDragHandle && !column.rowSelection && !column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
1032
1134
|
let label = "";
|
|
1033
1135
|
try {
|
|
@@ -1083,6 +1185,10 @@ function paintGrid(options) {
|
|
|
1083
1185
|
ctx.fillStyle = colors.selectionFill;
|
|
1084
1186
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1085
1187
|
}
|
|
1188
|
+
if (columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex) {
|
|
1189
|
+
ctx.fillStyle = colors.columnDropTargetFill;
|
|
1190
|
+
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1191
|
+
}
|
|
1086
1192
|
ctx.fillStyle = colors.grid;
|
|
1087
1193
|
if (!verticalBorderless) ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1088
1194
|
ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
@@ -1091,7 +1197,7 @@ function paintGrid(options) {
|
|
|
1091
1197
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1092
1198
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1093
1199
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
1094
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
1200
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
1095
1201
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1096
1202
|
const padding = 10;
|
|
1097
1203
|
const clipWidth = contentWidth;
|
|
@@ -1160,7 +1266,7 @@ function paintGrid(options) {
|
|
|
1160
1266
|
}
|
|
1161
1267
|
const selectedRow = selection ? rows[selection.rowIndex] : void 0;
|
|
1162
1268
|
const hasValidSelection = Boolean(selection && selectedRow && getRowKey(selectedRow, selection.rowIndex) === selection.rowKey);
|
|
1163
|
-
if (selection && hasValidSelection && !selectionRange) {
|
|
1269
|
+
if (selection && hasValidSelection && !selectionRange && !rowDragPreview) {
|
|
1164
1270
|
const metric = metrics[selection.columnIndex];
|
|
1165
1271
|
if (metric) {
|
|
1166
1272
|
const fixedSide = columns[selection.columnIndex].fixed;
|
|
@@ -1169,7 +1275,7 @@ function paintGrid(options) {
|
|
|
1169
1275
|
const selectionWidth = getCellWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
1170
1276
|
const selectionHeight = rowHeight * (span?.rowSpan ?? 1);
|
|
1171
1277
|
const x = Math.round(getColumnX(selection.columnIndex));
|
|
1172
|
-
const y = Math.round(bodyTop + selection.rowIndex * rowHeight - scrollTop);
|
|
1278
|
+
const y = Math.round(bodyTop + selection.rowIndex * rowHeight - scrollTop + getRowDragOffset(selection.rowIndex));
|
|
1173
1279
|
const borderWidth = 2;
|
|
1174
1280
|
const visibleLeft = fixedSide === "left" ? 0 : leftFixedWidth;
|
|
1175
1281
|
const selectionAreaRight = fixedSide === "right" ? width : width - rightFixedWidth;
|
|
@@ -1279,6 +1385,40 @@ function flattenDataColumns(columns, inheritedFixed, insideGroup = false) {
|
|
|
1279
1385
|
return flattenDataColumns(column.children, column.fixed ?? inheritedFixed, true);
|
|
1280
1386
|
});
|
|
1281
1387
|
}
|
|
1388
|
+
function reconcileColumns(current, incoming) {
|
|
1389
|
+
const incomingByKey = new Map(incoming.map((column) => [column.key, column]));
|
|
1390
|
+
const ordered = current.flatMap((column) => {
|
|
1391
|
+
const replacement = incomingByKey.get(column.key);
|
|
1392
|
+
if (!replacement) return [];
|
|
1393
|
+
incomingByKey.delete(column.key);
|
|
1394
|
+
return [{
|
|
1395
|
+
...replacement,
|
|
1396
|
+
children: replacement.children ? reconcileColumns(column.children ?? [], replacement.children) : void 0
|
|
1397
|
+
}];
|
|
1398
|
+
});
|
|
1399
|
+
incoming.forEach((column) => {
|
|
1400
|
+
if (incomingByKey.has(column.key)) ordered.push(column);
|
|
1401
|
+
});
|
|
1402
|
+
return ordered;
|
|
1403
|
+
}
|
|
1404
|
+
function reorderColumns(columns, detail) {
|
|
1405
|
+
const reorder = (items) => {
|
|
1406
|
+
const sourceIndex = items.findIndex((column2) => column2.key === detail.sourceKey);
|
|
1407
|
+
const targetIndex = items.findIndex((column2) => column2.key === detail.targetKey);
|
|
1408
|
+
if (sourceIndex < 0 || targetIndex < 0 || sourceIndex === targetIndex) return items;
|
|
1409
|
+
const next = items.slice();
|
|
1410
|
+
const [column] = next.splice(sourceIndex, 1);
|
|
1411
|
+
let insertIndex = targetIndex + (detail.placement === "after" ? 1 : 0);
|
|
1412
|
+
if (sourceIndex < insertIndex) insertIndex -= 1;
|
|
1413
|
+
next.splice(insertIndex, 0, column);
|
|
1414
|
+
return next;
|
|
1415
|
+
};
|
|
1416
|
+
if (!detail.parentKey) return reorder(columns);
|
|
1417
|
+
return columns.map((column) => {
|
|
1418
|
+
if (column.key === detail.parentKey && column.children) return { ...column, children: reorder(column.children) };
|
|
1419
|
+
return column.children ? { ...column, children: reorderColumns(column.children, detail) } : column;
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1282
1422
|
function buildHeaderCells(sourceColumns, utilityColumnCount, depth) {
|
|
1283
1423
|
const cells = [];
|
|
1284
1424
|
let leafIndex = utilityColumnCount;
|
|
@@ -1382,8 +1522,8 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1382
1522
|
}
|
|
1383
1523
|
return defaults;
|
|
1384
1524
|
}
|
|
1385
|
-
function
|
|
1386
|
-
columns:
|
|
1525
|
+
function TableInner({
|
|
1526
|
+
columns: columnProps,
|
|
1387
1527
|
rows: sourceRows,
|
|
1388
1528
|
rowKey,
|
|
1389
1529
|
width = "100%",
|
|
@@ -1412,31 +1552,35 @@ function Table({
|
|
|
1412
1552
|
rowSelection,
|
|
1413
1553
|
selectedRowKeys,
|
|
1414
1554
|
defaultSelectedRowKeys,
|
|
1415
|
-
|
|
1555
|
+
onSelectedRowChange,
|
|
1416
1556
|
columnSelection,
|
|
1417
1557
|
selectedColumnKeys,
|
|
1418
1558
|
defaultSelectedColumnKeys,
|
|
1419
|
-
|
|
1559
|
+
onSelectedColumnChange,
|
|
1420
1560
|
columnDraggable = true,
|
|
1421
|
-
columnResizable =
|
|
1422
|
-
|
|
1561
|
+
columnResizable = true,
|
|
1562
|
+
onColumnsReorder,
|
|
1423
1563
|
onColumnResize,
|
|
1424
1564
|
rowDraggable = false,
|
|
1425
|
-
|
|
1565
|
+
onRowsReorder,
|
|
1426
1566
|
onInsertRows,
|
|
1427
1567
|
onDeleteRows,
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
filterValues = {},
|
|
1431
|
-
onFilterValuesChange,
|
|
1568
|
+
onSortChange,
|
|
1569
|
+
onFilterChange,
|
|
1432
1570
|
onCellChange,
|
|
1571
|
+
onCellClick,
|
|
1572
|
+
onCellDoubleClick,
|
|
1433
1573
|
onCellContextMenu,
|
|
1434
1574
|
contextMenu: contextMenuConfig = true,
|
|
1435
1575
|
emptyContent,
|
|
1436
1576
|
className = "",
|
|
1437
1577
|
style,
|
|
1438
1578
|
ariaLabel = "Data grid"
|
|
1439
|
-
}) {
|
|
1579
|
+
}, ref) {
|
|
1580
|
+
const [sourceColumns, setSourceColumns] = (0, import_react5.useState)(columnProps);
|
|
1581
|
+
(0, import_react5.useEffect)(() => {
|
|
1582
|
+
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1583
|
+
}, [columnProps]);
|
|
1440
1584
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1441
1585
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1442
1586
|
const headerDepth = (0, import_react5.useMemo)(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
@@ -1478,6 +1622,7 @@ function Table({
|
|
|
1478
1622
|
const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
|
|
1479
1623
|
const [resizedColumnWidths, setResizedColumnWidths] = (0, import_react5.useState)({});
|
|
1480
1624
|
const leafSourceColumns = (0, import_react5.useMemo)(() => flattenDataColumns(sourceColumns), [sourceColumns]);
|
|
1625
|
+
const showRowCheckbox = Boolean(rowSelection) && (typeof rowSelection !== "object" || rowSelection.showCheckbox !== false);
|
|
1481
1626
|
(0, import_react5.useEffect)(() => {
|
|
1482
1627
|
if (!isProductionRuntime() && hasNestedFixedColumns(sourceColumns)) {
|
|
1483
1628
|
console.warn("[Table] Multi-level headers only support fixed columns on top-level columns. Nested fixed values are ignored.");
|
|
@@ -1488,19 +1633,19 @@ function Table({
|
|
|
1488
1633
|
if (rowDraggable) {
|
|
1489
1634
|
utilityColumns.push({ key: "__rvg_row_drag__", title: "", width: 36, align: "center", fixed: "left", rowDragHandle: true });
|
|
1490
1635
|
}
|
|
1491
|
-
if (
|
|
1636
|
+
if (showRowCheckbox) {
|
|
1492
1637
|
utilityColumns.push({ key: "__rvg_row_selection__", title: "", width: 44, align: "center", fixed: "left", rowSelection: true });
|
|
1493
1638
|
}
|
|
1494
1639
|
if (rowNumber) {
|
|
1495
|
-
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: "left", rowNumber: true });
|
|
1640
|
+
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: typeof rowNumber === "object" && rowNumber.fixed === false ? void 0 : "left", rowNumber: true });
|
|
1496
1641
|
}
|
|
1497
1642
|
const dataColumns = leafSourceColumns.map((column) => {
|
|
1498
1643
|
const resizedWidth = resizedColumnWidths[column.key];
|
|
1499
1644
|
return resizedWidth === void 0 ? column : { ...column, width: resizedWidth };
|
|
1500
1645
|
});
|
|
1501
1646
|
return [...utilityColumns, ...dataColumns];
|
|
1502
|
-
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber,
|
|
1503
|
-
const utilityColumnCount = (rowDraggable ? 1 : 0) + (
|
|
1647
|
+
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber, showRowCheckbox, sourceRows.length]);
|
|
1648
|
+
const utilityColumnCount = (rowDraggable ? 1 : 0) + (showRowCheckbox ? 1 : 0) + (rowNumber ? 1 : 0);
|
|
1504
1649
|
const headerCells = (0, import_react5.useMemo)(() => buildHeaderCells(sourceColumns, utilityColumnCount, headerDepth), [headerDepth, sourceColumns, utilityColumnCount]);
|
|
1505
1650
|
const activeCustomHeaderLevels = (0, import_react5.useMemo)(() => {
|
|
1506
1651
|
const levels = /* @__PURE__ */ new Map();
|
|
@@ -1517,7 +1662,6 @@ function Table({
|
|
|
1517
1662
|
const frameRef = (0, import_react5.useRef)(null);
|
|
1518
1663
|
const textFrameRef = (0, import_react5.useRef)(null);
|
|
1519
1664
|
const toastTimerRef = (0, import_react5.useRef)(null);
|
|
1520
|
-
const sortDebounceRef = (0, import_react5.useRef)(null);
|
|
1521
1665
|
const headerTooltipTimerRef = (0, import_react5.useRef)(null);
|
|
1522
1666
|
const cellTooltipTimerRef = (0, import_react5.useRef)(null);
|
|
1523
1667
|
const pendingHeaderTooltipKeyRef = (0, import_react5.useRef)("");
|
|
@@ -1548,6 +1692,7 @@ function Table({
|
|
|
1548
1692
|
const suppressClickRef = (0, import_react5.useRef)(false);
|
|
1549
1693
|
const hasCompletedLoadRef = (0, import_react5.useRef)(!loading);
|
|
1550
1694
|
const columnDragPreviewRef = (0, import_react5.useRef)(null);
|
|
1695
|
+
const validColumnDropRef = (0, import_react5.useRef)(null);
|
|
1551
1696
|
const hoveredHeaderActionRef = (0, import_react5.useRef)(null);
|
|
1552
1697
|
const hoveredRowIndexRef = (0, import_react5.useRef)(null);
|
|
1553
1698
|
const [viewport, setViewport] = (0, import_react5.useState)({ width: 0, height: typeof height === "number" ? height : FALLBACK_HEIGHT });
|
|
@@ -1555,11 +1700,8 @@ function Table({
|
|
|
1555
1700
|
const resolvedHeight = typeof height === "number" ? height : viewport.height || FALLBACK_HEIGHT;
|
|
1556
1701
|
const [scrollPosition, setScrollPosition] = (0, import_react5.useState)({ left: 0, top: 0 });
|
|
1557
1702
|
const scrollRef = (0, import_react5.useRef)({ left: 0, top: 0 });
|
|
1558
|
-
const [selection, setSelection] = useControllableValue(selectedCell, defaultSelectedCell, onSelectedCellChange);
|
|
1559
|
-
const [selectionRange, setSelectionRange] = (0, import_react5.useState)(null);
|
|
1560
|
-
const rangeDragRef = (0, import_react5.useRef)(null);
|
|
1561
1703
|
const [rowKeys, setRowKeys] = useControllableKeys(selectedRowKeys, defaultSelectedRowKeys, (keys) => {
|
|
1562
|
-
if (!
|
|
1704
|
+
if (!onSelectedRowChange) return;
|
|
1563
1705
|
const missing = new Set(keys.filter((key) => !rowByKeyRef.current.has(key)));
|
|
1564
1706
|
if (missing.size > 0) {
|
|
1565
1707
|
for (let index = 0; index < rows.length && missing.size > 0; index += 1) {
|
|
@@ -1576,12 +1718,13 @@ function Table({
|
|
|
1576
1718
|
const index = rowIndexByKeyRef.current.get(key);
|
|
1577
1719
|
return row && index !== void 0 ? [{ row, index }] : [];
|
|
1578
1720
|
});
|
|
1579
|
-
|
|
1721
|
+
onSelectedRowChange(keys, entries.map(({ row }) => row), entries.map(({ index }) => index));
|
|
1580
1722
|
});
|
|
1581
|
-
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys,
|
|
1723
|
+
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys, onSelectedColumnChange);
|
|
1582
1724
|
const [editing, setEditing] = (0, import_react5.useState)(null);
|
|
1583
1725
|
const [draft, setDraft] = (0, import_react5.useState)("");
|
|
1584
1726
|
const [rowDragPreview, setRowDragPreview] = (0, import_react5.useState)(null);
|
|
1727
|
+
const [columnDropTarget, setColumnDropTarget] = (0, import_react5.useState)(null);
|
|
1585
1728
|
(0, import_react5.useEffect)(() => {
|
|
1586
1729
|
if (!loading) hasCompletedLoadRef.current = true;
|
|
1587
1730
|
}, [loading]);
|
|
@@ -1650,6 +1793,8 @@ function Table({
|
|
|
1650
1793
|
return () => observer.disconnect();
|
|
1651
1794
|
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1652
1795
|
const [filterEditor, setFilterEditor] = (0, import_react5.useState)(null);
|
|
1796
|
+
const [filterValues, setFilterValues] = (0, import_react5.useState)({});
|
|
1797
|
+
const [sortState, setSortState] = (0, import_react5.useState)(null);
|
|
1653
1798
|
const [contextMenu, setContextMenu] = (0, import_react5.useState)(null);
|
|
1654
1799
|
const [insertCounts, setInsertCounts] = (0, import_react5.useState)({ before: 1, after: 1 });
|
|
1655
1800
|
const [confirmAction, setConfirmAction] = (0, import_react5.useState)(null);
|
|
@@ -1662,7 +1807,20 @@ function Table({
|
|
|
1662
1807
|
const [hoveredHeaderAction, setHoveredHeaderAction] = (0, import_react5.useState)(null);
|
|
1663
1808
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = (0, import_react5.useState)(null);
|
|
1664
1809
|
const [hoveredCellTooltip, setHoveredCellTooltip] = (0, import_react5.useState)(null);
|
|
1665
|
-
const
|
|
1810
|
+
const hideDragTooltips = (0, import_react5.useCallback)(() => {
|
|
1811
|
+
if (headerTooltipTimerRef.current !== null) {
|
|
1812
|
+
clearTimeout(headerTooltipTimerRef.current);
|
|
1813
|
+
headerTooltipTimerRef.current = null;
|
|
1814
|
+
}
|
|
1815
|
+
if (cellTooltipTimerRef.current !== null) {
|
|
1816
|
+
clearTimeout(cellTooltipTimerRef.current);
|
|
1817
|
+
cellTooltipTimerRef.current = null;
|
|
1818
|
+
}
|
|
1819
|
+
pendingHeaderTooltipKeyRef.current = "";
|
|
1820
|
+
pendingCellTooltipKeyRef.current = "";
|
|
1821
|
+
setVisibleHeaderTooltip(null);
|
|
1822
|
+
setHoveredCellTooltip(null);
|
|
1823
|
+
}, []);
|
|
1666
1824
|
const [editedCellKeys, setEditedCellKeys] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
1667
1825
|
const [cellAnnotations, setCellAnnotations] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
|
|
1668
1826
|
const [annotationType, setAnnotationType] = (0, import_react5.useState)("corner");
|
|
@@ -1674,6 +1832,7 @@ function Table({
|
|
|
1674
1832
|
const [pendingDeletedRowKeys, setPendingDeletedRowKeys] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
1675
1833
|
const [pendingInserts, setPendingInserts] = (0, import_react5.useState)(() => []);
|
|
1676
1834
|
const [insertedRowKeys, setInsertedRowKeys] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
1835
|
+
const [rowOrderKeys, setRowOrderKeys] = (0, import_react5.useState)(null);
|
|
1677
1836
|
const settledPendingInsertIdsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
|
|
1678
1837
|
const getDataRowKey = (0, import_react5.useCallback)((row, index) => {
|
|
1679
1838
|
return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
|
|
@@ -1688,7 +1847,7 @@ function Table({
|
|
|
1688
1847
|
}
|
|
1689
1848
|
return sourceRows.findIndex((sourceRow, index) => getDataRowKey(sourceRow, index) === key);
|
|
1690
1849
|
}, [getDataRowKey, sourceRows]);
|
|
1691
|
-
const
|
|
1850
|
+
const orderedRows = (0, import_react5.useMemo)(() => {
|
|
1692
1851
|
let next = sourceRows;
|
|
1693
1852
|
if (pendingInserts.length > 0) {
|
|
1694
1853
|
const activeInserts = pendingInserts.filter((insert) => {
|
|
@@ -1707,9 +1866,91 @@ function Table({
|
|
|
1707
1866
|
insertedOffset += insert.rows.length;
|
|
1708
1867
|
});
|
|
1709
1868
|
}
|
|
1710
|
-
if (pendingDeletedRowKeys.size
|
|
1711
|
-
|
|
1712
|
-
|
|
1869
|
+
if (pendingDeletedRowKeys.size > 0) {
|
|
1870
|
+
next = next.filter((row, index) => !pendingDeletedRowKeys.has(getDataRowKey(row, index)));
|
|
1871
|
+
}
|
|
1872
|
+
if (!rowOrderKeys) return next;
|
|
1873
|
+
const rowsByKey = new Map(next.map((row, index) => [getDataRowKey(row, index), row]));
|
|
1874
|
+
const ordered = rowOrderKeys.flatMap((key) => {
|
|
1875
|
+
const row = rowsByKey.get(key);
|
|
1876
|
+
if (!row) return [];
|
|
1877
|
+
rowsByKey.delete(key);
|
|
1878
|
+
return [row];
|
|
1879
|
+
});
|
|
1880
|
+
next.forEach((row, index) => {
|
|
1881
|
+
const key = getDataRowKey(row, index);
|
|
1882
|
+
if (rowsByKey.has(key)) ordered.push(row);
|
|
1883
|
+
});
|
|
1884
|
+
return ordered;
|
|
1885
|
+
}, [getDataRowKey, pendingDeletedRowKeys, pendingInserts, rowOrderKeys, sourceRows]);
|
|
1886
|
+
const activeFilterValues = (0, import_react5.useMemo)(() => Object.fromEntries(
|
|
1887
|
+
Object.entries(filterValues).filter(([, value]) => value.trim() !== "")
|
|
1888
|
+
), [filterValues]);
|
|
1889
|
+
const filteredRows = (0, import_react5.useMemo)(() => {
|
|
1890
|
+
if (Object.keys(activeFilterValues).length === 0) return orderedRows;
|
|
1891
|
+
if (onFilterChange) return onFilterChange(orderedRows, activeFilterValues);
|
|
1892
|
+
return orderedRows.filter((row, rowIndex) => Object.entries(activeFilterValues).every(([columnKey, query]) => {
|
|
1893
|
+
const column = columns.find((candidate) => candidate.key === columnKey);
|
|
1894
|
+
if (!column) return true;
|
|
1895
|
+
return getDisplayLabel(column, row, rowIndex).toLocaleLowerCase().includes(query.trim().toLocaleLowerCase());
|
|
1896
|
+
}));
|
|
1897
|
+
}, [activeFilterValues, columns, onFilterChange, orderedRows]);
|
|
1898
|
+
const rows = (0, import_react5.useMemo)(() => {
|
|
1899
|
+
if (!sortState) return filteredRows;
|
|
1900
|
+
if (onSortChange) return onSortChange(filteredRows, sortState);
|
|
1901
|
+
const column = columns.find((candidate) => candidate.key === sortState.columnKey);
|
|
1902
|
+
if (!column) return filteredRows;
|
|
1903
|
+
const direction = sortState.direction === "asc" ? 1 : -1;
|
|
1904
|
+
return filteredRows.slice().sort((left, right) => {
|
|
1905
|
+
const leftValue = column.dataIndex === void 0 ? void 0 : left[column.dataIndex];
|
|
1906
|
+
const rightValue = column.dataIndex === void 0 ? void 0 : right[column.dataIndex];
|
|
1907
|
+
const result = typeof leftValue === "number" && typeof rightValue === "number" ? leftValue - rightValue : getDisplayLabel(column, left, 0).localeCompare(getDisplayLabel(column, right, 0), language);
|
|
1908
|
+
return result * direction;
|
|
1909
|
+
});
|
|
1910
|
+
}, [columns, filteredRows, language, onSortChange, sortState]);
|
|
1911
|
+
const resolveSelectionTarget = (0, import_react5.useCallback)((target) => {
|
|
1912
|
+
if (target == null) return target;
|
|
1913
|
+
const columnIndex = columns.findIndex((column) => column.key === target.columnKey);
|
|
1914
|
+
const rowIndex = target.rowKey !== void 0 ? rows.findIndex((row2, index) => getDataRowKey(row2, index) === target.rowKey) : target.rowIndex ?? -1;
|
|
1915
|
+
const row = rows[rowIndex];
|
|
1916
|
+
if (columnIndex < 0 || !row) return null;
|
|
1917
|
+
return {
|
|
1918
|
+
rowIndex,
|
|
1919
|
+
columnIndex,
|
|
1920
|
+
rowKey: getDataRowKey(row, rowIndex),
|
|
1921
|
+
columnKey: target.columnKey
|
|
1922
|
+
};
|
|
1923
|
+
}, [columns, getDataRowKey, rows]);
|
|
1924
|
+
const resolvedSelectedCell = (0, import_react5.useMemo)(() => resolveSelectionTarget(selectedCell), [resolveSelectionTarget, selectedCell]);
|
|
1925
|
+
const resolvedDefaultSelectedCell = (0, import_react5.useMemo)(() => resolveSelectionTarget(defaultSelectedCell), [defaultSelectedCell, resolveSelectionTarget]);
|
|
1926
|
+
const handleSelectedCellChange = (0, import_react5.useCallback)((next) => {
|
|
1927
|
+
if (!onSelectedCellChange) return;
|
|
1928
|
+
if (!next) {
|
|
1929
|
+
onSelectedCellChange(null);
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
const row = rows[next.rowIndex];
|
|
1933
|
+
const column = columns[next.columnIndex];
|
|
1934
|
+
const value = row && column?.dataIndex !== void 0 ? row[column.dataIndex] : void 0;
|
|
1935
|
+
onSelectedCellChange({ ...next, value });
|
|
1936
|
+
}, [columns, onSelectedCellChange, rows]);
|
|
1937
|
+
const [selection, setSelection] = useControllableValue(resolvedSelectedCell, resolvedDefaultSelectedCell, handleSelectedCellChange);
|
|
1938
|
+
const [selectionRange, setSelectionRange] = (0, import_react5.useState)(null);
|
|
1939
|
+
const rangeDragRef = (0, import_react5.useRef)(null);
|
|
1940
|
+
const applyRowOrder = (0, import_react5.useCallback)((sourceIndex, targetIndex) => {
|
|
1941
|
+
if (sourceIndex === targetIndex || sourceIndex < 0 || targetIndex < 0 || sourceIndex >= rows.length || targetIndex >= rows.length) return;
|
|
1942
|
+
const nextEntries = rows.map((row, index) => ({ row, key: getDataRowKey(row, index) }));
|
|
1943
|
+
const [entry] = nextEntries.splice(sourceIndex, 1);
|
|
1944
|
+
nextEntries.splice(targetIndex, 0, entry);
|
|
1945
|
+
const nextRows = nextEntries.map(({ row }) => row);
|
|
1946
|
+
setRowOrderKeys(nextEntries.map(({ key }) => key));
|
|
1947
|
+
onRowsReorder?.(nextRows, { sourceIndex, targetIndex });
|
|
1948
|
+
}, [getDataRowKey, onRowsReorder, rows]);
|
|
1949
|
+
const applyColumnOrder = (0, import_react5.useCallback)((sourceIndex, targetIndex, detail) => {
|
|
1950
|
+
const nextColumns = reorderColumns(sourceColumns, detail);
|
|
1951
|
+
setSourceColumns(nextColumns);
|
|
1952
|
+
onColumnsReorder?.(nextColumns, { sourceIndex, targetIndex, ...detail });
|
|
1953
|
+
}, [onColumnsReorder, sourceColumns]);
|
|
1713
1954
|
(0, import_react5.useEffect)(() => {
|
|
1714
1955
|
if (insertBusy || settledPendingInsertIdsRef.current.size === 0) return;
|
|
1715
1956
|
setPendingInserts((current) => {
|
|
@@ -1951,19 +2192,22 @@ function Table({
|
|
|
1951
2192
|
grid: readThemeColor(themeStyles, "--rvg-color-grid", "#e3e6e8"),
|
|
1952
2193
|
text: readThemeColor(themeStyles, "--rvg-color-text", "#202124"),
|
|
1953
2194
|
muted: readThemeColor(themeStyles, "--rvg-color-muted", "#5f6368"),
|
|
2195
|
+
icon: readThemeColor(themeStyles, "--rvg-color-icon", "#9aa0a6"),
|
|
2196
|
+
borderStrong: readThemeColor(themeStyles, "--rvg-color-border-strong", "#b8bec4"),
|
|
1954
2197
|
selection: readThemeColor(themeStyles, "--rvg-color-primary", "#1677ff"),
|
|
1955
2198
|
selectionFill: readThemeColor(themeStyles, "--rvg-color-selection-fill", "#edf4ff"),
|
|
1956
2199
|
axisSelectionFill: readThemeColor(themeStyles, "--rvg-color-axis-selection-fill", "#e8f2ff"),
|
|
1957
2200
|
rowHoverFill: readThemeColor(themeStyles, "--rvg-color-row-hover-fill", "#f6f9fc"),
|
|
1958
2201
|
editedFill: editedCellHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-edited-fill", "#fff1b8"),
|
|
1959
2202
|
insertedFill: insertedRowHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-inserted-fill", "#c8ead4"),
|
|
2203
|
+
columnDropTargetFill: readThemeColor(themeStyles, "--rvg-color-column-drop-target-fill", "#eeeeee"),
|
|
1960
2204
|
stripe: stripedColor ?? readThemeColor(themeStyles, "--rvg-color-stripe", "#fafbfc")
|
|
1961
2205
|
};
|
|
1962
2206
|
const scroll = scrollRef.current;
|
|
1963
2207
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1964
2208
|
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 };
|
|
1965
|
-
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 });
|
|
1966
|
-
}, [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]);
|
|
2209
|
+
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, rowSelectionMode, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget, colors: themeColors });
|
|
2210
|
+
}, [bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columnDropTarget, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, getRowKey, hasStripedRows, hasVerticalBorders, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rowSelectionMode, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
1967
2211
|
const scheduleDraw = (0, import_react5.useCallback)(() => {
|
|
1968
2212
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1969
2213
|
}, [draw]);
|
|
@@ -2145,11 +2389,7 @@ function Table({
|
|
|
2145
2389
|
}
|
|
2146
2390
|
};
|
|
2147
2391
|
}, [scheduleDraw]);
|
|
2148
|
-
(0, import_react5.useEffect)(() => {
|
|
2149
|
-
setDisplaySortState(sortState);
|
|
2150
|
-
}, [sortState]);
|
|
2151
2392
|
(0, import_react5.useEffect)(() => () => {
|
|
2152
|
-
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
2153
2393
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
2154
2394
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
2155
2395
|
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
@@ -2524,12 +2764,12 @@ function Table({
|
|
|
2524
2764
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2525
2765
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2526
2766
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2527
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2767
|
+
let right = columnRight - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
2528
2768
|
if (visibleActions.sort) {
|
|
2529
|
-
if (localX >= right -
|
|
2530
|
-
right -=
|
|
2769
|
+
if (localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "sort";
|
|
2770
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
2531
2771
|
}
|
|
2532
|
-
if (visibleActions.filter && localX >= right -
|
|
2772
|
+
if (visibleActions.filter && localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "filter";
|
|
2533
2773
|
return null;
|
|
2534
2774
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2535
2775
|
const isHeaderTitleTruncated = (0, import_react5.useCallback)((columnIndex) => {
|
|
@@ -2539,7 +2779,7 @@ function Table({
|
|
|
2539
2779
|
const metric = metrics[columnIndex];
|
|
2540
2780
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2541
2781
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2542
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
2782
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
2543
2783
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2544
2784
|
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2545
2785
|
const locateHeaderDragHandle = (0, import_react5.useCallback)((clientX, columnIndex) => {
|
|
@@ -2695,6 +2935,7 @@ function Table({
|
|
|
2695
2935
|
}
|
|
2696
2936
|
const sourceIndex = headerDragCell.startIndex;
|
|
2697
2937
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2938
|
+
validColumnDropRef.current = null;
|
|
2698
2939
|
return {
|
|
2699
2940
|
type: "table-column",
|
|
2700
2941
|
sourceIndex,
|
|
@@ -2705,13 +2946,26 @@ function Table({
|
|
|
2705
2946
|
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2706
2947
|
};
|
|
2707
2948
|
},
|
|
2708
|
-
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2949
|
+
onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
|
|
2709
2950
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2951
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
2952
|
+
const input = location.current.input;
|
|
2953
|
+
const previewOffset = source.data.type === "table-row" ? {
|
|
2954
|
+
x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
|
|
2955
|
+
y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
|
|
2956
|
+
} : {
|
|
2957
|
+
x: Math.max(0, Math.min(metrics[sourceIndex].width, input.clientX - canvasRect.left - getDisplayedColumnLeft(sourceIndex))),
|
|
2958
|
+
y: Math.max(0, Math.min(canvasRect.height, input.clientY - canvasRect.top))
|
|
2959
|
+
};
|
|
2710
2960
|
(0, import_set_custom_native_drag_preview.setCustomNativeDragPreview)({
|
|
2711
2961
|
nativeSetDragImage,
|
|
2962
|
+
getOffset: () => previewOffset,
|
|
2712
2963
|
render: ({ container }) => {
|
|
2713
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
2714
2964
|
if (source.data.type === "table-row") {
|
|
2965
|
+
const frame = document.createElement("div");
|
|
2966
|
+
frame.className = "rvg-row-drag-preview-frame";
|
|
2967
|
+
frame.style.width = `${canvasRect.width + 4}px`;
|
|
2968
|
+
frame.style.height = `${rowHeight + 4}px`;
|
|
2715
2969
|
const preview2 = document.createElement("div");
|
|
2716
2970
|
preview2.className = "rvg-row-drag-preview";
|
|
2717
2971
|
preview2.style.width = `${canvasRect.width}px`;
|
|
@@ -2737,10 +2991,14 @@ function Table({
|
|
|
2737
2991
|
} else {
|
|
2738
2992
|
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
2739
2993
|
}
|
|
2994
|
+
if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
|
|
2995
|
+
cell.classList.add("is-selected");
|
|
2996
|
+
}
|
|
2740
2997
|
preview2.appendChild(cell);
|
|
2741
2998
|
});
|
|
2742
|
-
|
|
2743
|
-
|
|
2999
|
+
frame.appendChild(preview2);
|
|
3000
|
+
container.appendChild(frame);
|
|
3001
|
+
return () => frame.remove();
|
|
2744
3002
|
}
|
|
2745
3003
|
const preview = document.createElement("div");
|
|
2746
3004
|
preview.className = "rvg-column-drag-preview";
|
|
@@ -2754,6 +3012,29 @@ function Table({
|
|
|
2754
3012
|
header.style.height = `${headerHeight}px`;
|
|
2755
3013
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
2756
3014
|
header.textContent = column.title;
|
|
3015
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
3016
|
+
let actionRight = 2;
|
|
3017
|
+
if (visibleActions.drag) {
|
|
3018
|
+
const icon = createHeaderDragHandleSvg();
|
|
3019
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
3020
|
+
icon.style.right = `${actionRight}px`;
|
|
3021
|
+
header.appendChild(icon);
|
|
3022
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
3023
|
+
}
|
|
3024
|
+
if (visibleActions.sort) {
|
|
3025
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3026
|
+
const icon = createHeaderSortSvg(direction);
|
|
3027
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
3028
|
+
icon.style.right = `${actionRight}px`;
|
|
3029
|
+
header.appendChild(icon);
|
|
3030
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
3031
|
+
}
|
|
3032
|
+
if (visibleActions.filter) {
|
|
3033
|
+
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3034
|
+
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3035
|
+
icon.style.right = `${actionRight}px`;
|
|
3036
|
+
header.appendChild(icon);
|
|
3037
|
+
}
|
|
2757
3038
|
preview.appendChild(header);
|
|
2758
3039
|
for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
|
|
2759
3040
|
const row = rows[rowIndex];
|
|
@@ -2782,6 +3063,8 @@ function Table({
|
|
|
2782
3063
|
},
|
|
2783
3064
|
onDragStart: ({ source }) => {
|
|
2784
3065
|
suppressClickRef.current = true;
|
|
3066
|
+
hideDragTooltips();
|
|
3067
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
2785
3068
|
canvas.style.cursor = "move";
|
|
2786
3069
|
if (source.data.type === "table-row") {
|
|
2787
3070
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2807,15 +3090,46 @@ function Table({
|
|
|
2807
3090
|
}
|
|
2808
3091
|
const targetIndex = Number(target?.targetIndex);
|
|
2809
3092
|
if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
|
|
3093
|
+
validColumnDropRef.current = null;
|
|
3094
|
+
setColumnDropTarget(null);
|
|
2810
3095
|
setDragGuide(null);
|
|
2811
3096
|
return;
|
|
2812
3097
|
}
|
|
2813
3098
|
const edge = target?.columnEdge;
|
|
2814
3099
|
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2815
3100
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
|
|
3101
|
+
if (destinationIndex === sourceIndex) {
|
|
3102
|
+
validColumnDropRef.current = null;
|
|
3103
|
+
setColumnDropTarget(null);
|
|
3104
|
+
setDragGuide(null);
|
|
3105
|
+
return;
|
|
3106
|
+
}
|
|
3107
|
+
validColumnDropRef.current = {
|
|
3108
|
+
sourceIndex,
|
|
3109
|
+
targetIndex: destinationIndex,
|
|
3110
|
+
rawTargetIndex: targetIndex,
|
|
3111
|
+
targetKey: String(target.targetKey),
|
|
3112
|
+
headerKind: source.data.headerKind === "group" ? "group" : "column",
|
|
3113
|
+
parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
|
|
3114
|
+
fixed: source.data.fixed === "left" || source.data.fixed === "right" ? source.data.fixed : void 0,
|
|
3115
|
+
columnEdge: edge === "right" ? "right" : "left"
|
|
3116
|
+
};
|
|
3117
|
+
const siblingCells = headerCells.filter((cell) => cell.level === Number(source.data.headerLevel) && (cell.leaf ? "column" : "group") === source.data.headerKind && cell.parentKey === source.data.parentKey && columns[cell.startIndex]?.fixed === source.data.fixed);
|
|
3118
|
+
const targetEndIndex = Number.isInteger(target?.targetEndIndex) ? Number(target.targetEndIndex) : targetIndex;
|
|
3119
|
+
const hoveredTargetCell = siblingCells.find((cell) => cell.startIndex === targetIndex && cell.endIndex === targetEndIndex);
|
|
3120
|
+
if (!hoveredTargetCell) {
|
|
3121
|
+
validColumnDropRef.current = null;
|
|
3122
|
+
setColumnDropTarget(null);
|
|
3123
|
+
setDragGuide(null);
|
|
3124
|
+
return;
|
|
3125
|
+
}
|
|
3126
|
+
const highlightedCell = edge === "right" ? hoveredTargetCell : siblingCells.filter((cell) => cell.endIndex < hoveredTargetCell.startIndex).sort((left, right) => right.endIndex - left.endIndex)[0] ?? hoveredTargetCell;
|
|
3127
|
+
setColumnDropTarget({ startIndex: highlightedCell.startIndex, endIndex: highlightedCell.endIndex });
|
|
2816
3128
|
const targetLeft = Number(target?.targetLeft);
|
|
2817
3129
|
const targetWidth = Number(target?.targetWidth);
|
|
2818
3130
|
if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
|
|
3131
|
+
validColumnDropRef.current = null;
|
|
3132
|
+
setColumnDropTarget(null);
|
|
2819
3133
|
setDragGuide(null);
|
|
2820
3134
|
return;
|
|
2821
3135
|
}
|
|
@@ -2823,18 +3137,19 @@ function Table({
|
|
|
2823
3137
|
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2824
3138
|
},
|
|
2825
3139
|
onDrop: ({ source, location }) => {
|
|
3140
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2826
3141
|
const target = location.current.dropTargets[0]?.data;
|
|
2827
3142
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2828
3143
|
if (source.data.type === "table-row") {
|
|
2829
|
-
const
|
|
2830
|
-
let
|
|
2831
|
-
if (sourceIndex <
|
|
2832
|
-
|
|
3144
|
+
const rawTargetIndex = Number(target?.targetIndex);
|
|
3145
|
+
let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
3146
|
+
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3147
|
+
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
2833
3148
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2834
3149
|
setRowDragPreview(null);
|
|
2835
3150
|
setRowDragGuide(null);
|
|
2836
3151
|
canvas.style.cursor = "default";
|
|
2837
|
-
if (Number.isInteger(
|
|
3152
|
+
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
2838
3153
|
requestAnimationFrame(() => {
|
|
2839
3154
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2840
3155
|
});
|
|
@@ -2843,21 +3158,22 @@ function Table({
|
|
|
2843
3158
|
}, 0);
|
|
2844
3159
|
return;
|
|
2845
3160
|
}
|
|
2846
|
-
const
|
|
2847
|
-
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
3161
|
+
const validDrop = validColumnDropRef.current;
|
|
2848
3162
|
canvas.style.cursor = "default";
|
|
2849
3163
|
setDragGuide(null);
|
|
3164
|
+
setColumnDropTarget(null);
|
|
2850
3165
|
columnDragPreviewRef.current = null;
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
3166
|
+
validColumnDropRef.current = null;
|
|
3167
|
+
if (validDrop) {
|
|
3168
|
+
applyColumnOrder(
|
|
3169
|
+
validDrop.sourceIndex - utilityColumnCount,
|
|
3170
|
+
validDrop.targetIndex - utilityColumnCount,
|
|
2855
3171
|
{
|
|
2856
|
-
type:
|
|
3172
|
+
type: validDrop.headerKind,
|
|
2857
3173
|
sourceKey: String(source.data.sourceKey),
|
|
2858
|
-
targetKey:
|
|
2859
|
-
parentKey:
|
|
2860
|
-
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex,
|
|
3174
|
+
targetKey: validDrop.targetKey,
|
|
3175
|
+
parentKey: validDrop.parentKey,
|
|
3176
|
+
placement: getColumnDropPlacement(validDrop.sourceIndex, validDrop.rawTargetIndex, validDrop.columnEdge)
|
|
2861
3177
|
}
|
|
2862
3178
|
);
|
|
2863
3179
|
}
|
|
@@ -2869,6 +3185,7 @@ function Table({
|
|
|
2869
3185
|
const cleanupDrop = (0, import_adapter.dropTargetForElements)({
|
|
2870
3186
|
element: canvas,
|
|
2871
3187
|
canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
|
|
3188
|
+
getDropEffect: () => "move",
|
|
2872
3189
|
getData: ({ input, element, source }) => {
|
|
2873
3190
|
if (source.data.type === "table-row") {
|
|
2874
3191
|
const targetIndex2 = locateRow(input.clientY);
|
|
@@ -2877,7 +3194,8 @@ function Table({
|
|
|
2877
3194
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2878
3195
|
return (0, import_closest_edge.attachClosestEdge)({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2879
3196
|
}
|
|
2880
|
-
const
|
|
3197
|
+
const hoveredColumnIndex = locateColumn(input.clientX);
|
|
3198
|
+
const targetCell = locateHeaderCell(input.clientX, input.clientY) ?? headerCells.find((cell) => hoveredColumnIndex >= cell.startIndex && hoveredColumnIndex <= cell.endIndex && cell.level === Number(source.data.headerLevel) && (cell.leaf ? "column" : "group") === source.data.headerKind && cell.parentKey === source.data.parentKey);
|
|
2881
3199
|
if (!targetCell) return { targetIndex: -1 };
|
|
2882
3200
|
let targetIndex = targetCell.startIndex;
|
|
2883
3201
|
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
@@ -2894,6 +3212,7 @@ function Table({
|
|
|
2894
3212
|
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2895
3213
|
return (0, import_closest_edge.attachClosestEdge)({
|
|
2896
3214
|
targetIndex,
|
|
3215
|
+
targetEndIndex: targetCell.endIndex,
|
|
2897
3216
|
targetKey: targetCell.key,
|
|
2898
3217
|
parentKey: targetCell.parentKey,
|
|
2899
3218
|
headerKind,
|
|
@@ -2905,10 +3224,11 @@ function Table({
|
|
|
2905
3224
|
}
|
|
2906
3225
|
});
|
|
2907
3226
|
return () => {
|
|
3227
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2908
3228
|
cleanupDrag();
|
|
2909
3229
|
cleanupDrop();
|
|
2910
3230
|
};
|
|
2911
|
-
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerHeight, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow,
|
|
3231
|
+
}, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, measureHeaderTitleWidth, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setDragGuide, setRowDragGuide, sortState, utilityColumnCount]);
|
|
2912
3232
|
const locateCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2913
3233
|
const canvas = canvasRef.current;
|
|
2914
3234
|
if (!canvas) return null;
|
|
@@ -3031,9 +3351,15 @@ function Table({
|
|
|
3031
3351
|
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
3032
3352
|
scheduleDraw();
|
|
3033
3353
|
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
3354
|
+
const isCellEditable = (0, import_react5.useCallback)((cell) => {
|
|
3355
|
+
const column = columns[cell.columnIndex];
|
|
3356
|
+
const row = rows[cell.rowIndex];
|
|
3357
|
+
if (!column || !row || column.dataIndex === void 0 || column.rowNumber || column.rowSelection || column.rowDragHandle) return false;
|
|
3358
|
+
return typeof column.editable === "function" ? column.editable(row[column.dataIndex], row, cell.rowIndex) : column.editable === true;
|
|
3359
|
+
}, [columns, rows]);
|
|
3034
3360
|
const beginEdit = (0, import_react5.useCallback)((cell) => {
|
|
3035
3361
|
const column = columns[cell.columnIndex];
|
|
3036
|
-
if (!
|
|
3362
|
+
if (!isCellEditable(cell) || column.dataIndex === void 0) return;
|
|
3037
3363
|
const value = rows[cell.rowIndex]?.[column.dataIndex];
|
|
3038
3364
|
setDraft(value == null ? "" : String(value));
|
|
3039
3365
|
const scroller = scrollerRef.current;
|
|
@@ -3075,7 +3401,7 @@ function Table({
|
|
|
3075
3401
|
return;
|
|
3076
3402
|
}
|
|
3077
3403
|
setEditing(cell);
|
|
3078
|
-
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3404
|
+
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, isCellEditable, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3079
3405
|
const getCellEditKey = (cell) => `${typeof cell.rowKey}:${String(cell.rowKey)}\0${cell.columnKey}`;
|
|
3080
3406
|
const markCellEdited = (cell, previousValue, nextValue) => {
|
|
3081
3407
|
const key = getCellEditKey(cell);
|
|
@@ -3103,6 +3429,10 @@ function Table({
|
|
|
3103
3429
|
};
|
|
3104
3430
|
const commitEdit = (0, import_react5.useCallback)((nextDraft, close = true) => {
|
|
3105
3431
|
if (!editing) return;
|
|
3432
|
+
if (!isCellEditable(editing)) {
|
|
3433
|
+
setEditing(null);
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3106
3436
|
const committedDraft = nextDraft ?? draft;
|
|
3107
3437
|
const column = columns[editing.columnIndex];
|
|
3108
3438
|
const row = rows[editing.rowIndex];
|
|
@@ -3117,7 +3447,7 @@ function Table({
|
|
|
3117
3447
|
onCellChange?.({ ...editing, row, value: committedValue, previousValue });
|
|
3118
3448
|
}
|
|
3119
3449
|
if (close) setEditing(null);
|
|
3120
|
-
}, [columns, draft, editing, onCellChange, rows]);
|
|
3450
|
+
}, [columns, draft, editing, isCellEditable, onCellChange, rows]);
|
|
3121
3451
|
const renderEditor = () => {
|
|
3122
3452
|
if (!editing || !editorStyle) return null;
|
|
3123
3453
|
const column = columns[editing.columnIndex];
|
|
@@ -3315,19 +3645,14 @@ function Table({
|
|
|
3315
3645
|
setResizeGuideTop(0);
|
|
3316
3646
|
}, []);
|
|
3317
3647
|
const queueSortStateChange = (0, import_react5.useCallback)((next) => {
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
sortDebounceRef.current = setTimeout(() => {
|
|
3321
|
-
sortDebounceRef.current = null;
|
|
3322
|
-
onSortStateChange?.(next);
|
|
3323
|
-
}, 200);
|
|
3324
|
-
}, [onSortStateChange]);
|
|
3648
|
+
setSortState(next);
|
|
3649
|
+
}, []);
|
|
3325
3650
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3326
3651
|
const column = columns[columnIndex];
|
|
3327
3652
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3328
3653
|
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
3329
3654
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3330
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3655
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
3331
3656
|
const icons = [];
|
|
3332
3657
|
if (visibleActions.drag) {
|
|
3333
3658
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
@@ -3337,11 +3662,11 @@ function Table({
|
|
|
3337
3662
|
}
|
|
3338
3663
|
if (visibleActions.sort) {
|
|
3339
3664
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3340
|
-
const direction =
|
|
3665
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3341
3666
|
icons.push(
|
|
3342
3667
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - 16, top }, direction }, "sort")
|
|
3343
3668
|
);
|
|
3344
|
-
right -=
|
|
3669
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
3345
3670
|
}
|
|
3346
3671
|
if (visibleActions.filter) {
|
|
3347
3672
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
@@ -3368,7 +3693,7 @@ function Table({
|
|
|
3368
3693
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3369
3694
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3370
3695
|
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3371
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3696
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3372
3697
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3373
3698
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3374
3699
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3387,7 +3712,7 @@ function Table({
|
|
|
3387
3712
|
anchorLeft = anchorX;
|
|
3388
3713
|
label = labels.dragColumn;
|
|
3389
3714
|
} else if (action === "sort") {
|
|
3390
|
-
const direction =
|
|
3715
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3391
3716
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3392
3717
|
anchorX = cellLeft + cellWidth - 22;
|
|
3393
3718
|
anchorLeft = anchorX;
|
|
@@ -3407,7 +3732,7 @@ function Table({
|
|
|
3407
3732
|
label,
|
|
3408
3733
|
placement
|
|
3409
3734
|
};
|
|
3410
|
-
}, [baseHeaderHeight, columnDraggable, columns,
|
|
3735
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3411
3736
|
const isPointerOnHeaderTitle = (0, import_react5.useCallback)((clientX, clientY, cell) => {
|
|
3412
3737
|
const canvas = canvasRef.current;
|
|
3413
3738
|
if (!canvas) return false;
|
|
@@ -3422,7 +3747,7 @@ function Table({
|
|
|
3422
3747
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3423
3748
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3424
3749
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3425
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3750
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3426
3751
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3427
3752
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3428
3753
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
@@ -3662,7 +3987,9 @@ function Table({
|
|
|
3662
3987
|
});
|
|
3663
3988
|
setPendingInserts((current) => [...current, pending]);
|
|
3664
3989
|
try {
|
|
3665
|
-
|
|
3990
|
+
const nextRows = sourceRows.slice();
|
|
3991
|
+
nextRows.splice(insertIndex, 0, ...insertedRows);
|
|
3992
|
+
await Promise.resolve(onInsertRows(nextRows, insertedRows));
|
|
3666
3993
|
await waitForPaint();
|
|
3667
3994
|
setInsertBusy(false);
|
|
3668
3995
|
} catch (error) {
|
|
@@ -3689,28 +4016,10 @@ function Table({
|
|
|
3689
4016
|
const currentScrollTop = scrollRef.current.top;
|
|
3690
4017
|
const top = (fixedHeader ? 0 : bodyTop) + rowIndex * rowHeight - currentScrollTop;
|
|
3691
4018
|
if (column.rowSelection) {
|
|
3692
|
-
|
|
3693
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3694
|
-
"div",
|
|
3695
|
-
{
|
|
3696
|
-
className: "rvg-row-selection-icon",
|
|
3697
|
-
style: { left, top, width: cellWidth, height: cellHeight, opacity: isDraggedSource ? 0 : 1, transform: `translateY(${dragOffset}px)` },
|
|
3698
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SelectionIcon, { checked: selectedRowKeySet.has(rowKey2), radio: rowSelectionMode === "single" })
|
|
3699
|
-
},
|
|
3700
|
-
`selection:${String(rowKey2)}`
|
|
3701
|
-
);
|
|
4019
|
+
return null;
|
|
3702
4020
|
}
|
|
3703
4021
|
if (column.rowDragHandle) {
|
|
3704
|
-
return
|
|
3705
|
-
"div",
|
|
3706
|
-
{
|
|
3707
|
-
className: "rvg-row-drag-icon",
|
|
3708
|
-
style: { left, top, width: cellWidth, height: cellHeight, opacity: isDraggedSource ? 0 : 1, transform: `translateY(${dragOffset}px)` },
|
|
3709
|
-
"aria-hidden": "true",
|
|
3710
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RowDragHandleIcon, {})
|
|
3711
|
-
},
|
|
3712
|
-
`drag:${String(getRowKey(rows[rowIndex], rowIndex))}`
|
|
3713
|
-
);
|
|
4022
|
+
return null;
|
|
3714
4023
|
}
|
|
3715
4024
|
if (column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
3716
4025
|
const row = rows[rowIndex];
|
|
@@ -3737,6 +4046,7 @@ function Table({
|
|
|
3737
4046
|
};
|
|
3738
4047
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
3739
4048
|
const column = columns[columnIndex];
|
|
4049
|
+
const isDropTarget = Boolean(columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex);
|
|
3740
4050
|
const currentScrollTop = scrollRef.current.top;
|
|
3741
4051
|
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3742
4052
|
const leafTop = headerTop + headerLeafTop;
|
|
@@ -3744,7 +4054,7 @@ function Table({
|
|
|
3744
4054
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3745
4055
|
"div",
|
|
3746
4056
|
{
|
|
3747
|
-
className:
|
|
4057
|
+
className: `rvg-header-title${isDropTarget ? " is-drop-target" : ""}`,
|
|
3748
4058
|
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
3749
4059
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: column.title })
|
|
3750
4060
|
},
|
|
@@ -3767,11 +4077,11 @@ function Table({
|
|
|
3767
4077
|
}
|
|
3768
4078
|
if (column.renderHeader) {
|
|
3769
4079
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3770
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4080
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
3771
4081
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3772
4082
|
"div",
|
|
3773
4083
|
{
|
|
3774
|
-
className:
|
|
4084
|
+
className: `rvg-header-title is-custom${isDropTarget ? " is-drop-target" : ""}`,
|
|
3775
4085
|
"data-level": headerDepth - 1,
|
|
3776
4086
|
"data-measure-key": column.key,
|
|
3777
4087
|
style: {
|
|
@@ -3812,11 +4122,12 @@ function Table({
|
|
|
3812
4122
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3813
4123
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3814
4124
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
3815
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4125
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable && !cell.leaf ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
4126
|
+
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
3816
4127
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3817
4128
|
"div",
|
|
3818
4129
|
{
|
|
3819
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}`,
|
|
4130
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
3820
4131
|
"data-level": cell.level,
|
|
3821
4132
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3822
4133
|
style: {
|
|
@@ -3872,6 +4183,7 @@ function Table({
|
|
|
3872
4183
|
})();
|
|
3873
4184
|
const selectionOutlineStyle = (() => {
|
|
3874
4185
|
if (!selection || selectionRange) return null;
|
|
4186
|
+
if (rowDragPreview?.sourceIndex === selection.rowIndex) return null;
|
|
3875
4187
|
const row = rows[selection.rowIndex];
|
|
3876
4188
|
const metric = metrics[selection.columnIndex];
|
|
3877
4189
|
const column = columns[selection.columnIndex];
|
|
@@ -3881,10 +4193,11 @@ function Table({
|
|
|
3881
4193
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
3882
4194
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - scrollPosition.top;
|
|
3883
4195
|
const rawBottom = rawTop + rowHeight * (span?.rowSpan ?? 1);
|
|
4196
|
+
const dragOffset = getRowDragOffset(selection.rowIndex);
|
|
3884
4197
|
const horizontalStart = column.fixed === void 0 ? fixedWidth : 0;
|
|
3885
4198
|
const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
3886
4199
|
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
3887
|
-
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom <= verticalStart || rawTop >= renderHeight) return null;
|
|
4200
|
+
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom + dragOffset <= verticalStart || rawTop + dragOffset >= renderHeight) return null;
|
|
3888
4201
|
const borderWidth = 2;
|
|
3889
4202
|
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
|
|
3890
4203
|
const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
|
|
@@ -3894,7 +4207,8 @@ function Table({
|
|
|
3894
4207
|
left,
|
|
3895
4208
|
top,
|
|
3896
4209
|
width: Math.max(0, right - left),
|
|
3897
|
-
height: Math.max(0, bottom - top)
|
|
4210
|
+
height: Math.max(0, bottom - top),
|
|
4211
|
+
transform: `translateY(${dragOffset}px)`
|
|
3898
4212
|
};
|
|
3899
4213
|
})();
|
|
3900
4214
|
const selectionEdgeIndicator = getSelectionEdgeIndicator(scrollPosition.left, scrollPosition.top);
|
|
@@ -4035,6 +4349,77 @@ function Table({
|
|
|
4035
4349
|
`summary:${column.key}`
|
|
4036
4350
|
);
|
|
4037
4351
|
};
|
|
4352
|
+
(0, import_react5.useImperativeHandle)(ref, () => {
|
|
4353
|
+
const resolveDataCell = (target) => {
|
|
4354
|
+
const cell = resolveSelectionTarget(target);
|
|
4355
|
+
if (!cell) return null;
|
|
4356
|
+
const column = columns[cell.columnIndex];
|
|
4357
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return null;
|
|
4358
|
+
const span = getCellSpan(cell.rowIndex, cell.columnIndex);
|
|
4359
|
+
if (!span) return cell;
|
|
4360
|
+
return {
|
|
4361
|
+
rowIndex: span.rowIndex,
|
|
4362
|
+
columnIndex: span.columnIndex,
|
|
4363
|
+
rowKey: getRowKey(rows[span.rowIndex], span.rowIndex),
|
|
4364
|
+
columnKey: columns[span.columnIndex].key
|
|
4365
|
+
};
|
|
4366
|
+
};
|
|
4367
|
+
return {
|
|
4368
|
+
focus: () => scrollerRef.current?.focus({ preventScroll: true }),
|
|
4369
|
+
scrollToCell: (target) => {
|
|
4370
|
+
const cell = resolveDataCell(target);
|
|
4371
|
+
if (!cell) return false;
|
|
4372
|
+
revealCell(cell);
|
|
4373
|
+
return true;
|
|
4374
|
+
},
|
|
4375
|
+
getSelectedCell: () => {
|
|
4376
|
+
if (!selection) return null;
|
|
4377
|
+
const cell = resolveDataCell(selection);
|
|
4378
|
+
if (!cell) return null;
|
|
4379
|
+
const column = columns[cell.columnIndex];
|
|
4380
|
+
const row = rows[cell.rowIndex];
|
|
4381
|
+
return { ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] };
|
|
4382
|
+
},
|
|
4383
|
+
setSelectedCell: (target) => {
|
|
4384
|
+
const cell = target === null ? null : resolveDataCell(target);
|
|
4385
|
+
if (target !== null && !cell) return false;
|
|
4386
|
+
setSelectionRange(null);
|
|
4387
|
+
setSelection(cell);
|
|
4388
|
+
return true;
|
|
4389
|
+
},
|
|
4390
|
+
getSelectedRowKeys: () => [...rowKeys],
|
|
4391
|
+
getSelectedRows: () => rows.filter((row, index) => selectedRowKeySet.has(getRowKey(row, index))),
|
|
4392
|
+
setSelectedRowKeys: (keys) => {
|
|
4393
|
+
if (!rowSelection) return;
|
|
4394
|
+
const next = [...new Set(keys)];
|
|
4395
|
+
setRowKeys(rowSelectionMode === "single" ? next.slice(0, 1) : next);
|
|
4396
|
+
},
|
|
4397
|
+
getSelectedColumnKeys: () => [...columnKeys],
|
|
4398
|
+
setSelectedColumnKeys: (keys) => {
|
|
4399
|
+
if (!columnSelection) return;
|
|
4400
|
+
const next = [...new Set(keys)].filter((key) => columns.some((column) => column.key === key && !column.rowNumber && !column.rowSelection && !column.rowDragHandle));
|
|
4401
|
+
setColumnKeys(typeof columnSelection === "object" && columnSelection.mode === "single" ? next.slice(0, 1) : next);
|
|
4402
|
+
},
|
|
4403
|
+
clearSelection: () => {
|
|
4404
|
+
setSelectionRange(null);
|
|
4405
|
+
setSelection(null);
|
|
4406
|
+
setRowKeys([]);
|
|
4407
|
+
setColumnKeys([]);
|
|
4408
|
+
rowAnchorRef.current = null;
|
|
4409
|
+
setEditing(null);
|
|
4410
|
+
},
|
|
4411
|
+
startEdit: (target) => {
|
|
4412
|
+
const cell = target ? resolveDataCell(target) : selection ? resolveDataCell(selection) : null;
|
|
4413
|
+
if (!cell || !isCellEditable(cell)) return false;
|
|
4414
|
+
setSelectionRange(null);
|
|
4415
|
+
setSelection(cell);
|
|
4416
|
+
beginEdit(cell);
|
|
4417
|
+
return true;
|
|
4418
|
+
},
|
|
4419
|
+
commitEdit: () => commitEdit(),
|
|
4420
|
+
cancelEdit: () => setEditing(null)
|
|
4421
|
+
};
|
|
4422
|
+
});
|
|
4038
4423
|
const rootStyle = {
|
|
4039
4424
|
width,
|
|
4040
4425
|
height: autoHeight ? effectiveHeight : height,
|
|
@@ -4053,6 +4438,10 @@ function Table({
|
|
|
4053
4438
|
className: "rvg-canvas",
|
|
4054
4439
|
style: { width: viewport.width, height: renderHeight },
|
|
4055
4440
|
onMouseMove: (event) => {
|
|
4441
|
+
if (document.documentElement.classList.contains("rvg-is-dragging")) {
|
|
4442
|
+
hideDragTooltips();
|
|
4443
|
+
return;
|
|
4444
|
+
}
|
|
4056
4445
|
if (columnDragRef.current) return;
|
|
4057
4446
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
4058
4447
|
const localY = event.clientY - rect.top;
|
|
@@ -4155,6 +4544,14 @@ function Table({
|
|
|
4155
4544
|
}
|
|
4156
4545
|
},
|
|
4157
4546
|
onPointerDown: (event) => {
|
|
4547
|
+
const headerDragCell = columnDraggable ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
4548
|
+
const columnIndex = locateColumn(event.clientX);
|
|
4549
|
+
const rowDragHandle = rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(event.clientY) >= 0;
|
|
4550
|
+
if (headerDragCell && locateHeaderCellDragHandle(event.clientX, headerDragCell) || rowDragHandle) {
|
|
4551
|
+
hideDragTooltips();
|
|
4552
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
4553
|
+
event.currentTarget.style.cursor = "move";
|
|
4554
|
+
}
|
|
4158
4555
|
handleColumnPointerDown(event);
|
|
4159
4556
|
beginRangeDrag(event);
|
|
4160
4557
|
},
|
|
@@ -4163,10 +4560,12 @@ function Table({
|
|
|
4163
4560
|
updateRangeDrag(event);
|
|
4164
4561
|
},
|
|
4165
4562
|
onPointerUp: (event) => {
|
|
4563
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4166
4564
|
handleColumnPointerUp(event);
|
|
4167
4565
|
endRangeDrag(event);
|
|
4168
4566
|
},
|
|
4169
4567
|
onPointerCancel: (event) => {
|
|
4568
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4170
4569
|
handleColumnPointerUp(event);
|
|
4171
4570
|
endRangeDrag(event);
|
|
4172
4571
|
},
|
|
@@ -4185,7 +4584,7 @@ function Table({
|
|
|
4185
4584
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
4186
4585
|
if (action === "sort") {
|
|
4187
4586
|
const columnKey = columns[columnIndex].key;
|
|
4188
|
-
const next =
|
|
4587
|
+
const next = sortState?.columnKey !== columnKey ? { columnKey, direction: "asc" } : sortState.direction === "asc" ? { columnKey, direction: "desc" } : null;
|
|
4189
4588
|
queueSortStateChange(next);
|
|
4190
4589
|
return;
|
|
4191
4590
|
}
|
|
@@ -4219,6 +4618,10 @@ function Table({
|
|
|
4219
4618
|
}
|
|
4220
4619
|
if (event.detail > 1) return;
|
|
4221
4620
|
clickedCellRef.current = cell;
|
|
4621
|
+
const column = columns[cell.columnIndex];
|
|
4622
|
+
const row = rows[cell.rowIndex];
|
|
4623
|
+
onCellClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4624
|
+
if (event.defaultPrevented) return;
|
|
4222
4625
|
setSelectionRange(null);
|
|
4223
4626
|
scrollerRef.current?.focus({ preventScroll: true });
|
|
4224
4627
|
setSelection(cell);
|
|
@@ -4229,7 +4632,12 @@ function Table({
|
|
|
4229
4632
|
},
|
|
4230
4633
|
onDoubleClick: (event) => {
|
|
4231
4634
|
const cell = clickedCellRef.current ?? locateCell(event.clientX, event.clientY);
|
|
4232
|
-
if (cell)
|
|
4635
|
+
if (!cell) return;
|
|
4636
|
+
const column = columns[cell.columnIndex];
|
|
4637
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return;
|
|
4638
|
+
const row = rows[cell.rowIndex];
|
|
4639
|
+
onCellDoubleClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4640
|
+
if (!event.defaultPrevented) beginEdit(cell);
|
|
4233
4641
|
},
|
|
4234
4642
|
onContextMenu: handleContextMenu
|
|
4235
4643
|
}
|
|
@@ -4242,7 +4650,7 @@ function Table({
|
|
|
4242
4650
|
className: "rvg-text-scroll-content",
|
|
4243
4651
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
4244
4652
|
children: [
|
|
4245
|
-
columns.map((column, columnIndex) => column.fixed || columnIndex
|
|
4653
|
+
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),
|
|
4246
4654
|
headerCells.map((cell) => {
|
|
4247
4655
|
if (columns[cell.startIndex]?.fixed) return null;
|
|
4248
4656
|
if (cell.endIndex < domRange.columnStart || cell.startIndex >= domRange.columnEnd) return null;
|
|
@@ -4260,7 +4668,7 @@ function Table({
|
|
|
4260
4668
|
const left = column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width;
|
|
4261
4669
|
return renderCellText(rowIndex, columnIndex, left);
|
|
4262
4670
|
})) }),
|
|
4263
|
-
columns.map((column, columnIndex) => columnIndex < utilityColumnCount || headerDepth === 1
|
|
4671
|
+
columns.map((column, columnIndex) => column.fixed && (columnIndex < utilityColumnCount || headerDepth === 1) ? renderHeaderTitle(columnIndex, column.fixed === "right" ? viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width : column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : getScrollableColumnLeft(columnIndex)) : null),
|
|
4264
4672
|
headerCells.map((cell) => columns[cell.startIndex]?.fixed ? renderGroupedHeaderCell(cell) : null),
|
|
4265
4673
|
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
4266
4674
|
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-shadow is-right", style: { right: rightFixedWidth } }),
|
|
@@ -4477,7 +4885,7 @@ function Table({
|
|
|
4477
4885
|
const affectedRows = selectedIndices.includes(cell.rowIndex) ? selectedIndices : [cell.rowIndex];
|
|
4478
4886
|
const cellContext = { ...cell, row, column, value: dataIndex === void 0 ? void 0 : row[dataIndex] };
|
|
4479
4887
|
return renderConfiguredContextMenu(resolveContextMenuSection(customContextMenuConfig?.cell, DEFAULT_CELL_CONTEXT_MENU), cellContext, (item, override) => {
|
|
4480
|
-
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !
|
|
4888
|
+
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !isCellEditable(cell), icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContextMenuIcon, { type: "edit" }) });
|
|
4481
4889
|
if (item === "copy") return renderContextMenuButton("cell-copy", cellContext, labels.copyContent, async () => {
|
|
4482
4890
|
try {
|
|
4483
4891
|
await navigator.clipboard.writeText(getCellLabel(cell.rowIndex, cell.columnIndex));
|
|
@@ -4535,12 +4943,12 @@ function Table({
|
|
|
4535
4943
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: labels.rowUnit })
|
|
4536
4944
|
] });
|
|
4537
4945
|
if (item === "move-up") {
|
|
4538
|
-
if (!rowDraggable
|
|
4539
|
-
return renderContextMenuButton("cell-move-up", cellContext, labels.moveUp, () =>
|
|
4946
|
+
if (!rowDraggable) return null;
|
|
4947
|
+
return renderContextMenuButton("cell-move-up", cellContext, labels.moveUp, () => applyRowOrder(cell.rowIndex, cell.rowIndex - 1), override, { disabled: cell.rowIndex === 0, icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContextMenuIcon, { type: "move-up" }) });
|
|
4540
4948
|
}
|
|
4541
4949
|
if (item === "move-down") {
|
|
4542
|
-
if (!rowDraggable
|
|
4543
|
-
return renderContextMenuButton("cell-move-down", cellContext, labels.moveDown, () =>
|
|
4950
|
+
if (!rowDraggable) return null;
|
|
4951
|
+
return renderContextMenuButton("cell-move-down", cellContext, labels.moveDown, () => applyRowOrder(cell.rowIndex, cell.rowIndex + 1), override, { disabled: cell.rowIndex === rows.length - 1, icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContextMenuIcon, { type: "move-down" }) });
|
|
4544
4952
|
}
|
|
4545
4953
|
if (item === "delete-row") return renderContextMenuButton("cell-delete-row", cellContext, labels.deleteRow, () => setConfirmAction({ type: "delete-row", rows: affectedRows.map((rowIndex) => ({ rowIndex, row: rows[rowIndex] })) }), override, { disabled: !onDeleteRows, danger: true, icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContextMenuIcon, { type: "delete" }) });
|
|
4546
4954
|
return null;
|
|
@@ -4572,21 +4980,30 @@ function Table({
|
|
|
4572
4980
|
await Promise.resolve(onCellChange?.({ ...confirmAction.cell, row: confirmAction.row, previousValue: confirmAction.previousValue, value: "" }));
|
|
4573
4981
|
} else {
|
|
4574
4982
|
const deletingKeys = confirmAction.rows.map(({ row, rowIndex }) => getDataRowKey(row, rowIndex));
|
|
4983
|
+
const deletedRows = confirmAction.rows.map(({ row }) => row);
|
|
4984
|
+
const deletingKeySet = new Set(deletingKeys);
|
|
4985
|
+
const nextRows = sourceRows.filter((row, rowIndex) => !deletingKeySet.has(getDataRowKey(row, rowIndex)));
|
|
4575
4986
|
setConfirmAction(null);
|
|
4576
4987
|
setConfirmLoading(false);
|
|
4988
|
+
setPendingDeletedRowKeys((current) => {
|
|
4989
|
+
const next = new Set(current);
|
|
4990
|
+
deletingKeys.forEach((key) => next.add(key));
|
|
4991
|
+
return next;
|
|
4992
|
+
});
|
|
4577
4993
|
if (onDeleteRows) {
|
|
4578
4994
|
setDeleteBusy(true);
|
|
4579
4995
|
try {
|
|
4580
|
-
await Promise.resolve(onDeleteRows(
|
|
4996
|
+
await Promise.resolve(onDeleteRows(nextRows, deletedRows));
|
|
4997
|
+
} catch (error) {
|
|
4998
|
+
setPendingDeletedRowKeys((current) => {
|
|
4999
|
+
const next = new Set(current);
|
|
5000
|
+
deletingKeys.forEach((key) => next.delete(key));
|
|
5001
|
+
return next;
|
|
5002
|
+
});
|
|
5003
|
+
throw error;
|
|
4581
5004
|
} finally {
|
|
4582
5005
|
setDeleteBusy(false);
|
|
4583
5006
|
}
|
|
4584
|
-
} else {
|
|
4585
|
-
setPendingDeletedRowKeys((current) => {
|
|
4586
|
-
const next = new Set(current);
|
|
4587
|
-
deletingKeys.forEach((key) => next.add(key));
|
|
4588
|
-
return next;
|
|
4589
|
-
});
|
|
4590
5007
|
}
|
|
4591
5008
|
return;
|
|
4592
5009
|
}
|
|
@@ -4659,7 +5076,7 @@ function Table({
|
|
|
4659
5076
|
const next = { ...filterValues };
|
|
4660
5077
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4661
5078
|
else delete next[key];
|
|
4662
|
-
|
|
5079
|
+
setFilterValues(next);
|
|
4663
5080
|
setFilterEditor(null);
|
|
4664
5081
|
}
|
|
4665
5082
|
}
|
|
@@ -4670,7 +5087,7 @@ function Table({
|
|
|
4670
5087
|
const key = columns[filterEditor.columnIndex].key;
|
|
4671
5088
|
const next = { ...filterValues };
|
|
4672
5089
|
delete next[key];
|
|
4673
|
-
|
|
5090
|
+
setFilterValues(next);
|
|
4674
5091
|
setFilterEditor(null);
|
|
4675
5092
|
}, children: labels.reset }),
|
|
4676
5093
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rvg-filter-confirm", onClick: () => {
|
|
@@ -4678,7 +5095,7 @@ function Table({
|
|
|
4678
5095
|
const next = { ...filterValues };
|
|
4679
5096
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4680
5097
|
else delete next[key];
|
|
4681
|
-
|
|
5098
|
+
setFilterValues(next);
|
|
4682
5099
|
setFilterEditor(null);
|
|
4683
5100
|
}, children: labels.confirm })
|
|
4684
5101
|
] })
|
|
@@ -4708,6 +5125,7 @@ function Table({
|
|
|
4708
5125
|
loading && !hasCustomLoading && hasCompletedLoadRef.current && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-refresh-loading", "aria-label": labels.refreshing, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LoadingSpinnerIcon, {}) })
|
|
4709
5126
|
] });
|
|
4710
5127
|
}
|
|
5128
|
+
var Table = (0, import_react5.forwardRef)(TableInner);
|
|
4711
5129
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4712
5130
|
0 && (module.exports = {
|
|
4713
5131
|
Table,
|