@lensui/lens-table 0.1.5 → 0.1.6
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 +46 -61
- package/dist/index.cjs +451 -127
- package/dist/index.css +56 -28
- package/dist/index.d.cts +38 -33
- package/dist/index.d.ts +38 -33
- package/dist/index.js +451 -127
- 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;
|
|
@@ -1383,7 +1523,7 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1383
1523
|
return defaults;
|
|
1384
1524
|
}
|
|
1385
1525
|
function Table({
|
|
1386
|
-
columns:
|
|
1526
|
+
columns: columnProps,
|
|
1387
1527
|
rows: sourceRows,
|
|
1388
1528
|
rowKey,
|
|
1389
1529
|
width = "100%",
|
|
@@ -1412,23 +1552,21 @@ 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,
|
|
1433
1571
|
onCellContextMenu,
|
|
1434
1572
|
contextMenu: contextMenuConfig = true,
|
|
@@ -1437,6 +1575,10 @@ function Table({
|
|
|
1437
1575
|
style,
|
|
1438
1576
|
ariaLabel = "Data grid"
|
|
1439
1577
|
}) {
|
|
1578
|
+
const [sourceColumns, setSourceColumns] = (0, import_react5.useState)(columnProps);
|
|
1579
|
+
(0, import_react5.useEffect)(() => {
|
|
1580
|
+
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1581
|
+
}, [columnProps]);
|
|
1440
1582
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1441
1583
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1442
1584
|
const headerDepth = (0, import_react5.useMemo)(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
@@ -1517,7 +1659,6 @@ function Table({
|
|
|
1517
1659
|
const frameRef = (0, import_react5.useRef)(null);
|
|
1518
1660
|
const textFrameRef = (0, import_react5.useRef)(null);
|
|
1519
1661
|
const toastTimerRef = (0, import_react5.useRef)(null);
|
|
1520
|
-
const sortDebounceRef = (0, import_react5.useRef)(null);
|
|
1521
1662
|
const headerTooltipTimerRef = (0, import_react5.useRef)(null);
|
|
1522
1663
|
const cellTooltipTimerRef = (0, import_react5.useRef)(null);
|
|
1523
1664
|
const pendingHeaderTooltipKeyRef = (0, import_react5.useRef)("");
|
|
@@ -1548,6 +1689,7 @@ function Table({
|
|
|
1548
1689
|
const suppressClickRef = (0, import_react5.useRef)(false);
|
|
1549
1690
|
const hasCompletedLoadRef = (0, import_react5.useRef)(!loading);
|
|
1550
1691
|
const columnDragPreviewRef = (0, import_react5.useRef)(null);
|
|
1692
|
+
const validColumnDropRef = (0, import_react5.useRef)(null);
|
|
1551
1693
|
const hoveredHeaderActionRef = (0, import_react5.useRef)(null);
|
|
1552
1694
|
const hoveredRowIndexRef = (0, import_react5.useRef)(null);
|
|
1553
1695
|
const [viewport, setViewport] = (0, import_react5.useState)({ width: 0, height: typeof height === "number" ? height : FALLBACK_HEIGHT });
|
|
@@ -1555,11 +1697,8 @@ function Table({
|
|
|
1555
1697
|
const resolvedHeight = typeof height === "number" ? height : viewport.height || FALLBACK_HEIGHT;
|
|
1556
1698
|
const [scrollPosition, setScrollPosition] = (0, import_react5.useState)({ left: 0, top: 0 });
|
|
1557
1699
|
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
1700
|
const [rowKeys, setRowKeys] = useControllableKeys(selectedRowKeys, defaultSelectedRowKeys, (keys) => {
|
|
1562
|
-
if (!
|
|
1701
|
+
if (!onSelectedRowChange) return;
|
|
1563
1702
|
const missing = new Set(keys.filter((key) => !rowByKeyRef.current.has(key)));
|
|
1564
1703
|
if (missing.size > 0) {
|
|
1565
1704
|
for (let index = 0; index < rows.length && missing.size > 0; index += 1) {
|
|
@@ -1576,12 +1715,13 @@ function Table({
|
|
|
1576
1715
|
const index = rowIndexByKeyRef.current.get(key);
|
|
1577
1716
|
return row && index !== void 0 ? [{ row, index }] : [];
|
|
1578
1717
|
});
|
|
1579
|
-
|
|
1718
|
+
onSelectedRowChange(keys, entries.map(({ row }) => row), entries.map(({ index }) => index));
|
|
1580
1719
|
});
|
|
1581
|
-
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys,
|
|
1720
|
+
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys, onSelectedColumnChange);
|
|
1582
1721
|
const [editing, setEditing] = (0, import_react5.useState)(null);
|
|
1583
1722
|
const [draft, setDraft] = (0, import_react5.useState)("");
|
|
1584
1723
|
const [rowDragPreview, setRowDragPreview] = (0, import_react5.useState)(null);
|
|
1724
|
+
const [columnDropTarget, setColumnDropTarget] = (0, import_react5.useState)(null);
|
|
1585
1725
|
(0, import_react5.useEffect)(() => {
|
|
1586
1726
|
if (!loading) hasCompletedLoadRef.current = true;
|
|
1587
1727
|
}, [loading]);
|
|
@@ -1650,6 +1790,8 @@ function Table({
|
|
|
1650
1790
|
return () => observer.disconnect();
|
|
1651
1791
|
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1652
1792
|
const [filterEditor, setFilterEditor] = (0, import_react5.useState)(null);
|
|
1793
|
+
const [filterValues, setFilterValues] = (0, import_react5.useState)({});
|
|
1794
|
+
const [sortState, setSortState] = (0, import_react5.useState)(null);
|
|
1653
1795
|
const [contextMenu, setContextMenu] = (0, import_react5.useState)(null);
|
|
1654
1796
|
const [insertCounts, setInsertCounts] = (0, import_react5.useState)({ before: 1, after: 1 });
|
|
1655
1797
|
const [confirmAction, setConfirmAction] = (0, import_react5.useState)(null);
|
|
@@ -1662,7 +1804,20 @@ function Table({
|
|
|
1662
1804
|
const [hoveredHeaderAction, setHoveredHeaderAction] = (0, import_react5.useState)(null);
|
|
1663
1805
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = (0, import_react5.useState)(null);
|
|
1664
1806
|
const [hoveredCellTooltip, setHoveredCellTooltip] = (0, import_react5.useState)(null);
|
|
1665
|
-
const
|
|
1807
|
+
const hideDragTooltips = (0, import_react5.useCallback)(() => {
|
|
1808
|
+
if (headerTooltipTimerRef.current !== null) {
|
|
1809
|
+
clearTimeout(headerTooltipTimerRef.current);
|
|
1810
|
+
headerTooltipTimerRef.current = null;
|
|
1811
|
+
}
|
|
1812
|
+
if (cellTooltipTimerRef.current !== null) {
|
|
1813
|
+
clearTimeout(cellTooltipTimerRef.current);
|
|
1814
|
+
cellTooltipTimerRef.current = null;
|
|
1815
|
+
}
|
|
1816
|
+
pendingHeaderTooltipKeyRef.current = "";
|
|
1817
|
+
pendingCellTooltipKeyRef.current = "";
|
|
1818
|
+
setVisibleHeaderTooltip(null);
|
|
1819
|
+
setHoveredCellTooltip(null);
|
|
1820
|
+
}, []);
|
|
1666
1821
|
const [editedCellKeys, setEditedCellKeys] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
1667
1822
|
const [cellAnnotations, setCellAnnotations] = (0, import_react5.useState)(() => /* @__PURE__ */ new Map());
|
|
1668
1823
|
const [annotationType, setAnnotationType] = (0, import_react5.useState)("corner");
|
|
@@ -1674,6 +1829,7 @@ function Table({
|
|
|
1674
1829
|
const [pendingDeletedRowKeys, setPendingDeletedRowKeys] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
1675
1830
|
const [pendingInserts, setPendingInserts] = (0, import_react5.useState)(() => []);
|
|
1676
1831
|
const [insertedRowKeys, setInsertedRowKeys] = (0, import_react5.useState)(() => /* @__PURE__ */ new Set());
|
|
1832
|
+
const [rowOrderKeys, setRowOrderKeys] = (0, import_react5.useState)(null);
|
|
1677
1833
|
const settledPendingInsertIdsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
|
|
1678
1834
|
const getDataRowKey = (0, import_react5.useCallback)((row, index) => {
|
|
1679
1835
|
return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
|
|
@@ -1688,7 +1844,7 @@ function Table({
|
|
|
1688
1844
|
}
|
|
1689
1845
|
return sourceRows.findIndex((sourceRow, index) => getDataRowKey(sourceRow, index) === key);
|
|
1690
1846
|
}, [getDataRowKey, sourceRows]);
|
|
1691
|
-
const
|
|
1847
|
+
const orderedRows = (0, import_react5.useMemo)(() => {
|
|
1692
1848
|
let next = sourceRows;
|
|
1693
1849
|
if (pendingInserts.length > 0) {
|
|
1694
1850
|
const activeInserts = pendingInserts.filter((insert) => {
|
|
@@ -1707,9 +1863,91 @@ function Table({
|
|
|
1707
1863
|
insertedOffset += insert.rows.length;
|
|
1708
1864
|
});
|
|
1709
1865
|
}
|
|
1710
|
-
if (pendingDeletedRowKeys.size
|
|
1711
|
-
|
|
1712
|
-
|
|
1866
|
+
if (pendingDeletedRowKeys.size > 0) {
|
|
1867
|
+
next = next.filter((row, index) => !pendingDeletedRowKeys.has(getDataRowKey(row, index)));
|
|
1868
|
+
}
|
|
1869
|
+
if (!rowOrderKeys) return next;
|
|
1870
|
+
const rowsByKey = new Map(next.map((row, index) => [getDataRowKey(row, index), row]));
|
|
1871
|
+
const ordered = rowOrderKeys.flatMap((key) => {
|
|
1872
|
+
const row = rowsByKey.get(key);
|
|
1873
|
+
if (!row) return [];
|
|
1874
|
+
rowsByKey.delete(key);
|
|
1875
|
+
return [row];
|
|
1876
|
+
});
|
|
1877
|
+
next.forEach((row, index) => {
|
|
1878
|
+
const key = getDataRowKey(row, index);
|
|
1879
|
+
if (rowsByKey.has(key)) ordered.push(row);
|
|
1880
|
+
});
|
|
1881
|
+
return ordered;
|
|
1882
|
+
}, [getDataRowKey, pendingDeletedRowKeys, pendingInserts, rowOrderKeys, sourceRows]);
|
|
1883
|
+
const activeFilterValues = (0, import_react5.useMemo)(() => Object.fromEntries(
|
|
1884
|
+
Object.entries(filterValues).filter(([, value]) => value.trim() !== "")
|
|
1885
|
+
), [filterValues]);
|
|
1886
|
+
const filteredRows = (0, import_react5.useMemo)(() => {
|
|
1887
|
+
if (Object.keys(activeFilterValues).length === 0) return orderedRows;
|
|
1888
|
+
if (onFilterChange) return onFilterChange(orderedRows, activeFilterValues);
|
|
1889
|
+
return orderedRows.filter((row, rowIndex) => Object.entries(activeFilterValues).every(([columnKey, query]) => {
|
|
1890
|
+
const column = columns.find((candidate) => candidate.key === columnKey);
|
|
1891
|
+
if (!column) return true;
|
|
1892
|
+
return getDisplayLabel(column, row, rowIndex).toLocaleLowerCase().includes(query.trim().toLocaleLowerCase());
|
|
1893
|
+
}));
|
|
1894
|
+
}, [activeFilterValues, columns, onFilterChange, orderedRows]);
|
|
1895
|
+
const rows = (0, import_react5.useMemo)(() => {
|
|
1896
|
+
if (!sortState) return filteredRows;
|
|
1897
|
+
if (onSortChange) return onSortChange(filteredRows, sortState);
|
|
1898
|
+
const column = columns.find((candidate) => candidate.key === sortState.columnKey);
|
|
1899
|
+
if (!column) return filteredRows;
|
|
1900
|
+
const direction = sortState.direction === "asc" ? 1 : -1;
|
|
1901
|
+
return filteredRows.slice().sort((left, right) => {
|
|
1902
|
+
const leftValue = column.dataIndex === void 0 ? void 0 : left[column.dataIndex];
|
|
1903
|
+
const rightValue = column.dataIndex === void 0 ? void 0 : right[column.dataIndex];
|
|
1904
|
+
const result = typeof leftValue === "number" && typeof rightValue === "number" ? leftValue - rightValue : getDisplayLabel(column, left, 0).localeCompare(getDisplayLabel(column, right, 0), language);
|
|
1905
|
+
return result * direction;
|
|
1906
|
+
});
|
|
1907
|
+
}, [columns, filteredRows, language, onSortChange, sortState]);
|
|
1908
|
+
const resolveSelectionTarget = (0, import_react5.useCallback)((target) => {
|
|
1909
|
+
if (target == null) return target;
|
|
1910
|
+
const columnIndex = columns.findIndex((column) => column.key === target.columnKey);
|
|
1911
|
+
const rowIndex = target.rowKey !== void 0 ? rows.findIndex((row2, index) => getDataRowKey(row2, index) === target.rowKey) : target.rowIndex ?? -1;
|
|
1912
|
+
const row = rows[rowIndex];
|
|
1913
|
+
if (columnIndex < 0 || !row) return null;
|
|
1914
|
+
return {
|
|
1915
|
+
rowIndex,
|
|
1916
|
+
columnIndex,
|
|
1917
|
+
rowKey: getDataRowKey(row, rowIndex),
|
|
1918
|
+
columnKey: target.columnKey
|
|
1919
|
+
};
|
|
1920
|
+
}, [columns, getDataRowKey, rows]);
|
|
1921
|
+
const resolvedSelectedCell = (0, import_react5.useMemo)(() => resolveSelectionTarget(selectedCell), [resolveSelectionTarget, selectedCell]);
|
|
1922
|
+
const resolvedDefaultSelectedCell = (0, import_react5.useMemo)(() => resolveSelectionTarget(defaultSelectedCell), [defaultSelectedCell, resolveSelectionTarget]);
|
|
1923
|
+
const handleSelectedCellChange = (0, import_react5.useCallback)((next) => {
|
|
1924
|
+
if (!onSelectedCellChange) return;
|
|
1925
|
+
if (!next) {
|
|
1926
|
+
onSelectedCellChange(null);
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
const row = rows[next.rowIndex];
|
|
1930
|
+
const column = columns[next.columnIndex];
|
|
1931
|
+
const value = row && column?.dataIndex !== void 0 ? row[column.dataIndex] : void 0;
|
|
1932
|
+
onSelectedCellChange({ ...next, value });
|
|
1933
|
+
}, [columns, onSelectedCellChange, rows]);
|
|
1934
|
+
const [selection, setSelection] = useControllableValue(resolvedSelectedCell, resolvedDefaultSelectedCell, handleSelectedCellChange);
|
|
1935
|
+
const [selectionRange, setSelectionRange] = (0, import_react5.useState)(null);
|
|
1936
|
+
const rangeDragRef = (0, import_react5.useRef)(null);
|
|
1937
|
+
const applyRowOrder = (0, import_react5.useCallback)((sourceIndex, targetIndex) => {
|
|
1938
|
+
if (sourceIndex === targetIndex || sourceIndex < 0 || targetIndex < 0 || sourceIndex >= rows.length || targetIndex >= rows.length) return;
|
|
1939
|
+
const nextEntries = rows.map((row, index) => ({ row, key: getDataRowKey(row, index) }));
|
|
1940
|
+
const [entry] = nextEntries.splice(sourceIndex, 1);
|
|
1941
|
+
nextEntries.splice(targetIndex, 0, entry);
|
|
1942
|
+
const nextRows = nextEntries.map(({ row }) => row);
|
|
1943
|
+
setRowOrderKeys(nextEntries.map(({ key }) => key));
|
|
1944
|
+
onRowsReorder?.(nextRows, { sourceIndex, targetIndex });
|
|
1945
|
+
}, [getDataRowKey, onRowsReorder, rows]);
|
|
1946
|
+
const applyColumnOrder = (0, import_react5.useCallback)((sourceIndex, targetIndex, detail) => {
|
|
1947
|
+
const nextColumns = reorderColumns(sourceColumns, detail);
|
|
1948
|
+
setSourceColumns(nextColumns);
|
|
1949
|
+
onColumnsReorder?.(nextColumns, { sourceIndex, targetIndex, ...detail });
|
|
1950
|
+
}, [onColumnsReorder, sourceColumns]);
|
|
1713
1951
|
(0, import_react5.useEffect)(() => {
|
|
1714
1952
|
if (insertBusy || settledPendingInsertIdsRef.current.size === 0) return;
|
|
1715
1953
|
setPendingInserts((current) => {
|
|
@@ -1951,19 +2189,22 @@ function Table({
|
|
|
1951
2189
|
grid: readThemeColor(themeStyles, "--rvg-color-grid", "#e3e6e8"),
|
|
1952
2190
|
text: readThemeColor(themeStyles, "--rvg-color-text", "#202124"),
|
|
1953
2191
|
muted: readThemeColor(themeStyles, "--rvg-color-muted", "#5f6368"),
|
|
2192
|
+
icon: readThemeColor(themeStyles, "--rvg-color-icon", "#9aa0a6"),
|
|
2193
|
+
borderStrong: readThemeColor(themeStyles, "--rvg-color-border-strong", "#b8bec4"),
|
|
1954
2194
|
selection: readThemeColor(themeStyles, "--rvg-color-primary", "#1677ff"),
|
|
1955
2195
|
selectionFill: readThemeColor(themeStyles, "--rvg-color-selection-fill", "#edf4ff"),
|
|
1956
2196
|
axisSelectionFill: readThemeColor(themeStyles, "--rvg-color-axis-selection-fill", "#e8f2ff"),
|
|
1957
2197
|
rowHoverFill: readThemeColor(themeStyles, "--rvg-color-row-hover-fill", "#f6f9fc"),
|
|
1958
2198
|
editedFill: editedCellHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-edited-fill", "#fff1b8"),
|
|
1959
2199
|
insertedFill: insertedRowHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-inserted-fill", "#c8ead4"),
|
|
2200
|
+
columnDropTargetFill: readThemeColor(themeStyles, "--rvg-color-column-drop-target-fill", "#eeeeee"),
|
|
1960
2201
|
stripe: stripedColor ?? readThemeColor(themeStyles, "--rvg-color-stripe", "#fafbfc")
|
|
1961
2202
|
};
|
|
1962
2203
|
const scroll = scrollRef.current;
|
|
1963
2204
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1964
2205
|
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]);
|
|
2206
|
+
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 });
|
|
2207
|
+
}, [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
2208
|
const scheduleDraw = (0, import_react5.useCallback)(() => {
|
|
1968
2209
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1969
2210
|
}, [draw]);
|
|
@@ -2145,11 +2386,7 @@ function Table({
|
|
|
2145
2386
|
}
|
|
2146
2387
|
};
|
|
2147
2388
|
}, [scheduleDraw]);
|
|
2148
|
-
(0, import_react5.useEffect)(() => {
|
|
2149
|
-
setDisplaySortState(sortState);
|
|
2150
|
-
}, [sortState]);
|
|
2151
2389
|
(0, import_react5.useEffect)(() => () => {
|
|
2152
|
-
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
2153
2390
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
2154
2391
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
2155
2392
|
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
@@ -2524,12 +2761,12 @@ function Table({
|
|
|
2524
2761
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2525
2762
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2526
2763
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2527
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2764
|
+
let right = columnRight - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
2528
2765
|
if (visibleActions.sort) {
|
|
2529
|
-
if (localX >= right -
|
|
2530
|
-
right -=
|
|
2766
|
+
if (localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "sort";
|
|
2767
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
2531
2768
|
}
|
|
2532
|
-
if (visibleActions.filter && localX >= right -
|
|
2769
|
+
if (visibleActions.filter && localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "filter";
|
|
2533
2770
|
return null;
|
|
2534
2771
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2535
2772
|
const isHeaderTitleTruncated = (0, import_react5.useCallback)((columnIndex) => {
|
|
@@ -2539,7 +2776,7 @@ function Table({
|
|
|
2539
2776
|
const metric = metrics[columnIndex];
|
|
2540
2777
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2541
2778
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2542
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
2779
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
2543
2780
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2544
2781
|
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2545
2782
|
const locateHeaderDragHandle = (0, import_react5.useCallback)((clientX, columnIndex) => {
|
|
@@ -2695,6 +2932,7 @@ function Table({
|
|
|
2695
2932
|
}
|
|
2696
2933
|
const sourceIndex = headerDragCell.startIndex;
|
|
2697
2934
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2935
|
+
validColumnDropRef.current = null;
|
|
2698
2936
|
return {
|
|
2699
2937
|
type: "table-column",
|
|
2700
2938
|
sourceIndex,
|
|
@@ -2705,13 +2943,26 @@ function Table({
|
|
|
2705
2943
|
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2706
2944
|
};
|
|
2707
2945
|
},
|
|
2708
|
-
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2946
|
+
onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
|
|
2709
2947
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2948
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
2949
|
+
const input = location.current.input;
|
|
2950
|
+
const previewOffset = source.data.type === "table-row" ? {
|
|
2951
|
+
x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
|
|
2952
|
+
y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
|
|
2953
|
+
} : {
|
|
2954
|
+
x: Math.max(0, Math.min(metrics[sourceIndex].width, input.clientX - canvasRect.left - getDisplayedColumnLeft(sourceIndex))),
|
|
2955
|
+
y: Math.max(0, Math.min(canvasRect.height, input.clientY - canvasRect.top))
|
|
2956
|
+
};
|
|
2710
2957
|
(0, import_set_custom_native_drag_preview.setCustomNativeDragPreview)({
|
|
2711
2958
|
nativeSetDragImage,
|
|
2959
|
+
getOffset: () => previewOffset,
|
|
2712
2960
|
render: ({ container }) => {
|
|
2713
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
2714
2961
|
if (source.data.type === "table-row") {
|
|
2962
|
+
const frame = document.createElement("div");
|
|
2963
|
+
frame.className = "rvg-row-drag-preview-frame";
|
|
2964
|
+
frame.style.width = `${canvasRect.width + 4}px`;
|
|
2965
|
+
frame.style.height = `${rowHeight + 4}px`;
|
|
2715
2966
|
const preview2 = document.createElement("div");
|
|
2716
2967
|
preview2.className = "rvg-row-drag-preview";
|
|
2717
2968
|
preview2.style.width = `${canvasRect.width}px`;
|
|
@@ -2737,10 +2988,14 @@ function Table({
|
|
|
2737
2988
|
} else {
|
|
2738
2989
|
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
2739
2990
|
}
|
|
2991
|
+
if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
|
|
2992
|
+
cell.classList.add("is-selected");
|
|
2993
|
+
}
|
|
2740
2994
|
preview2.appendChild(cell);
|
|
2741
2995
|
});
|
|
2742
|
-
|
|
2743
|
-
|
|
2996
|
+
frame.appendChild(preview2);
|
|
2997
|
+
container.appendChild(frame);
|
|
2998
|
+
return () => frame.remove();
|
|
2744
2999
|
}
|
|
2745
3000
|
const preview = document.createElement("div");
|
|
2746
3001
|
preview.className = "rvg-column-drag-preview";
|
|
@@ -2754,6 +3009,29 @@ function Table({
|
|
|
2754
3009
|
header.style.height = `${headerHeight}px`;
|
|
2755
3010
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
2756
3011
|
header.textContent = column.title;
|
|
3012
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
3013
|
+
let actionRight = 2;
|
|
3014
|
+
if (visibleActions.drag) {
|
|
3015
|
+
const icon = createHeaderDragHandleSvg();
|
|
3016
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
3017
|
+
icon.style.right = `${actionRight}px`;
|
|
3018
|
+
header.appendChild(icon);
|
|
3019
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
3020
|
+
}
|
|
3021
|
+
if (visibleActions.sort) {
|
|
3022
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3023
|
+
const icon = createHeaderSortSvg(direction);
|
|
3024
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
3025
|
+
icon.style.right = `${actionRight}px`;
|
|
3026
|
+
header.appendChild(icon);
|
|
3027
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
3028
|
+
}
|
|
3029
|
+
if (visibleActions.filter) {
|
|
3030
|
+
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3031
|
+
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3032
|
+
icon.style.right = `${actionRight}px`;
|
|
3033
|
+
header.appendChild(icon);
|
|
3034
|
+
}
|
|
2757
3035
|
preview.appendChild(header);
|
|
2758
3036
|
for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
|
|
2759
3037
|
const row = rows[rowIndex];
|
|
@@ -2782,6 +3060,8 @@ function Table({
|
|
|
2782
3060
|
},
|
|
2783
3061
|
onDragStart: ({ source }) => {
|
|
2784
3062
|
suppressClickRef.current = true;
|
|
3063
|
+
hideDragTooltips();
|
|
3064
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
2785
3065
|
canvas.style.cursor = "move";
|
|
2786
3066
|
if (source.data.type === "table-row") {
|
|
2787
3067
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2807,15 +3087,46 @@ function Table({
|
|
|
2807
3087
|
}
|
|
2808
3088
|
const targetIndex = Number(target?.targetIndex);
|
|
2809
3089
|
if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
|
|
3090
|
+
validColumnDropRef.current = null;
|
|
3091
|
+
setColumnDropTarget(null);
|
|
2810
3092
|
setDragGuide(null);
|
|
2811
3093
|
return;
|
|
2812
3094
|
}
|
|
2813
3095
|
const edge = target?.columnEdge;
|
|
2814
3096
|
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2815
3097
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
|
|
3098
|
+
if (destinationIndex === sourceIndex) {
|
|
3099
|
+
validColumnDropRef.current = null;
|
|
3100
|
+
setColumnDropTarget(null);
|
|
3101
|
+
setDragGuide(null);
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
validColumnDropRef.current = {
|
|
3105
|
+
sourceIndex,
|
|
3106
|
+
targetIndex: destinationIndex,
|
|
3107
|
+
rawTargetIndex: targetIndex,
|
|
3108
|
+
targetKey: String(target.targetKey),
|
|
3109
|
+
headerKind: source.data.headerKind === "group" ? "group" : "column",
|
|
3110
|
+
parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
|
|
3111
|
+
fixed: source.data.fixed === "left" || source.data.fixed === "right" ? source.data.fixed : void 0,
|
|
3112
|
+
columnEdge: edge === "right" ? "right" : "left"
|
|
3113
|
+
};
|
|
3114
|
+
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);
|
|
3115
|
+
const targetEndIndex = Number.isInteger(target?.targetEndIndex) ? Number(target.targetEndIndex) : targetIndex;
|
|
3116
|
+
const hoveredTargetCell = siblingCells.find((cell) => cell.startIndex === targetIndex && cell.endIndex === targetEndIndex);
|
|
3117
|
+
if (!hoveredTargetCell) {
|
|
3118
|
+
validColumnDropRef.current = null;
|
|
3119
|
+
setColumnDropTarget(null);
|
|
3120
|
+
setDragGuide(null);
|
|
3121
|
+
return;
|
|
3122
|
+
}
|
|
3123
|
+
const highlightedCell = edge === "right" ? hoveredTargetCell : siblingCells.filter((cell) => cell.endIndex < hoveredTargetCell.startIndex).sort((left, right) => right.endIndex - left.endIndex)[0] ?? hoveredTargetCell;
|
|
3124
|
+
setColumnDropTarget({ startIndex: highlightedCell.startIndex, endIndex: highlightedCell.endIndex });
|
|
2816
3125
|
const targetLeft = Number(target?.targetLeft);
|
|
2817
3126
|
const targetWidth = Number(target?.targetWidth);
|
|
2818
3127
|
if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
|
|
3128
|
+
validColumnDropRef.current = null;
|
|
3129
|
+
setColumnDropTarget(null);
|
|
2819
3130
|
setDragGuide(null);
|
|
2820
3131
|
return;
|
|
2821
3132
|
}
|
|
@@ -2823,18 +3134,19 @@ function Table({
|
|
|
2823
3134
|
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2824
3135
|
},
|
|
2825
3136
|
onDrop: ({ source, location }) => {
|
|
3137
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2826
3138
|
const target = location.current.dropTargets[0]?.data;
|
|
2827
3139
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2828
3140
|
if (source.data.type === "table-row") {
|
|
2829
|
-
const
|
|
2830
|
-
let
|
|
2831
|
-
if (sourceIndex <
|
|
2832
|
-
|
|
3141
|
+
const rawTargetIndex = Number(target?.targetIndex);
|
|
3142
|
+
let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
3143
|
+
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3144
|
+
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
2833
3145
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2834
3146
|
setRowDragPreview(null);
|
|
2835
3147
|
setRowDragGuide(null);
|
|
2836
3148
|
canvas.style.cursor = "default";
|
|
2837
|
-
if (Number.isInteger(
|
|
3149
|
+
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
2838
3150
|
requestAnimationFrame(() => {
|
|
2839
3151
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2840
3152
|
});
|
|
@@ -2843,21 +3155,22 @@ function Table({
|
|
|
2843
3155
|
}, 0);
|
|
2844
3156
|
return;
|
|
2845
3157
|
}
|
|
2846
|
-
const
|
|
2847
|
-
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
3158
|
+
const validDrop = validColumnDropRef.current;
|
|
2848
3159
|
canvas.style.cursor = "default";
|
|
2849
3160
|
setDragGuide(null);
|
|
3161
|
+
setColumnDropTarget(null);
|
|
2850
3162
|
columnDragPreviewRef.current = null;
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
3163
|
+
validColumnDropRef.current = null;
|
|
3164
|
+
if (validDrop) {
|
|
3165
|
+
applyColumnOrder(
|
|
3166
|
+
validDrop.sourceIndex - utilityColumnCount,
|
|
3167
|
+
validDrop.targetIndex - utilityColumnCount,
|
|
2855
3168
|
{
|
|
2856
|
-
type:
|
|
3169
|
+
type: validDrop.headerKind,
|
|
2857
3170
|
sourceKey: String(source.data.sourceKey),
|
|
2858
|
-
targetKey:
|
|
2859
|
-
parentKey:
|
|
2860
|
-
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex,
|
|
3171
|
+
targetKey: validDrop.targetKey,
|
|
3172
|
+
parentKey: validDrop.parentKey,
|
|
3173
|
+
placement: getColumnDropPlacement(validDrop.sourceIndex, validDrop.rawTargetIndex, validDrop.columnEdge)
|
|
2861
3174
|
}
|
|
2862
3175
|
);
|
|
2863
3176
|
}
|
|
@@ -2869,6 +3182,7 @@ function Table({
|
|
|
2869
3182
|
const cleanupDrop = (0, import_adapter.dropTargetForElements)({
|
|
2870
3183
|
element: canvas,
|
|
2871
3184
|
canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
|
|
3185
|
+
getDropEffect: () => "move",
|
|
2872
3186
|
getData: ({ input, element, source }) => {
|
|
2873
3187
|
if (source.data.type === "table-row") {
|
|
2874
3188
|
const targetIndex2 = locateRow(input.clientY);
|
|
@@ -2877,7 +3191,8 @@ function Table({
|
|
|
2877
3191
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2878
3192
|
return (0, import_closest_edge.attachClosestEdge)({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2879
3193
|
}
|
|
2880
|
-
const
|
|
3194
|
+
const hoveredColumnIndex = locateColumn(input.clientX);
|
|
3195
|
+
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
3196
|
if (!targetCell) return { targetIndex: -1 };
|
|
2882
3197
|
let targetIndex = targetCell.startIndex;
|
|
2883
3198
|
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
@@ -2894,6 +3209,7 @@ function Table({
|
|
|
2894
3209
|
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2895
3210
|
return (0, import_closest_edge.attachClosestEdge)({
|
|
2896
3211
|
targetIndex,
|
|
3212
|
+
targetEndIndex: targetCell.endIndex,
|
|
2897
3213
|
targetKey: targetCell.key,
|
|
2898
3214
|
parentKey: targetCell.parentKey,
|
|
2899
3215
|
headerKind,
|
|
@@ -2905,10 +3221,11 @@ function Table({
|
|
|
2905
3221
|
}
|
|
2906
3222
|
});
|
|
2907
3223
|
return () => {
|
|
3224
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2908
3225
|
cleanupDrag();
|
|
2909
3226
|
cleanupDrop();
|
|
2910
3227
|
};
|
|
2911
|
-
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerHeight, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow,
|
|
3228
|
+
}, [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
3229
|
const locateCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2913
3230
|
const canvas = canvasRef.current;
|
|
2914
3231
|
if (!canvas) return null;
|
|
@@ -3315,19 +3632,14 @@ function Table({
|
|
|
3315
3632
|
setResizeGuideTop(0);
|
|
3316
3633
|
}, []);
|
|
3317
3634
|
const queueSortStateChange = (0, import_react5.useCallback)((next) => {
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
sortDebounceRef.current = setTimeout(() => {
|
|
3321
|
-
sortDebounceRef.current = null;
|
|
3322
|
-
onSortStateChange?.(next);
|
|
3323
|
-
}, 200);
|
|
3324
|
-
}, [onSortStateChange]);
|
|
3635
|
+
setSortState(next);
|
|
3636
|
+
}, []);
|
|
3325
3637
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3326
3638
|
const column = columns[columnIndex];
|
|
3327
3639
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3328
3640
|
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
3329
3641
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3330
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3642
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
3331
3643
|
const icons = [];
|
|
3332
3644
|
if (visibleActions.drag) {
|
|
3333
3645
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
@@ -3337,11 +3649,11 @@ function Table({
|
|
|
3337
3649
|
}
|
|
3338
3650
|
if (visibleActions.sort) {
|
|
3339
3651
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3340
|
-
const direction =
|
|
3652
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3341
3653
|
icons.push(
|
|
3342
3654
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - 16, top }, direction }, "sort")
|
|
3343
3655
|
);
|
|
3344
|
-
right -=
|
|
3656
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
3345
3657
|
}
|
|
3346
3658
|
if (visibleActions.filter) {
|
|
3347
3659
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
@@ -3368,7 +3680,7 @@ function Table({
|
|
|
3368
3680
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3369
3681
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3370
3682
|
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3371
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3683
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3372
3684
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3373
3685
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3374
3686
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3387,7 +3699,7 @@ function Table({
|
|
|
3387
3699
|
anchorLeft = anchorX;
|
|
3388
3700
|
label = labels.dragColumn;
|
|
3389
3701
|
} else if (action === "sort") {
|
|
3390
|
-
const direction =
|
|
3702
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3391
3703
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3392
3704
|
anchorX = cellLeft + cellWidth - 22;
|
|
3393
3705
|
anchorLeft = anchorX;
|
|
@@ -3407,7 +3719,7 @@ function Table({
|
|
|
3407
3719
|
label,
|
|
3408
3720
|
placement
|
|
3409
3721
|
};
|
|
3410
|
-
}, [baseHeaderHeight, columnDraggable, columns,
|
|
3722
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3411
3723
|
const isPointerOnHeaderTitle = (0, import_react5.useCallback)((clientX, clientY, cell) => {
|
|
3412
3724
|
const canvas = canvasRef.current;
|
|
3413
3725
|
if (!canvas) return false;
|
|
@@ -3422,7 +3734,7 @@ function Table({
|
|
|
3422
3734
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3423
3735
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3424
3736
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3425
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3737
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3426
3738
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3427
3739
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3428
3740
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
@@ -3662,7 +3974,9 @@ function Table({
|
|
|
3662
3974
|
});
|
|
3663
3975
|
setPendingInserts((current) => [...current, pending]);
|
|
3664
3976
|
try {
|
|
3665
|
-
|
|
3977
|
+
const nextRows = sourceRows.slice();
|
|
3978
|
+
nextRows.splice(insertIndex, 0, ...insertedRows);
|
|
3979
|
+
await Promise.resolve(onInsertRows(nextRows, insertedRows));
|
|
3666
3980
|
await waitForPaint();
|
|
3667
3981
|
setInsertBusy(false);
|
|
3668
3982
|
} catch (error) {
|
|
@@ -3689,28 +4003,10 @@ function Table({
|
|
|
3689
4003
|
const currentScrollTop = scrollRef.current.top;
|
|
3690
4004
|
const top = (fixedHeader ? 0 : bodyTop) + rowIndex * rowHeight - currentScrollTop;
|
|
3691
4005
|
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
|
-
);
|
|
4006
|
+
return null;
|
|
3702
4007
|
}
|
|
3703
4008
|
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
|
-
);
|
|
4009
|
+
return null;
|
|
3714
4010
|
}
|
|
3715
4011
|
if (column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
3716
4012
|
const row = rows[rowIndex];
|
|
@@ -3737,6 +4033,7 @@ function Table({
|
|
|
3737
4033
|
};
|
|
3738
4034
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
3739
4035
|
const column = columns[columnIndex];
|
|
4036
|
+
const isDropTarget = Boolean(columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex);
|
|
3740
4037
|
const currentScrollTop = scrollRef.current.top;
|
|
3741
4038
|
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3742
4039
|
const leafTop = headerTop + headerLeafTop;
|
|
@@ -3744,7 +4041,7 @@ function Table({
|
|
|
3744
4041
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3745
4042
|
"div",
|
|
3746
4043
|
{
|
|
3747
|
-
className:
|
|
4044
|
+
className: `rvg-header-title${isDropTarget ? " is-drop-target" : ""}`,
|
|
3748
4045
|
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
3749
4046
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: column.title })
|
|
3750
4047
|
},
|
|
@@ -3767,11 +4064,11 @@ function Table({
|
|
|
3767
4064
|
}
|
|
3768
4065
|
if (column.renderHeader) {
|
|
3769
4066
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3770
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4067
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
3771
4068
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3772
4069
|
"div",
|
|
3773
4070
|
{
|
|
3774
|
-
className:
|
|
4071
|
+
className: `rvg-header-title is-custom${isDropTarget ? " is-drop-target" : ""}`,
|
|
3775
4072
|
"data-level": headerDepth - 1,
|
|
3776
4073
|
"data-measure-key": column.key,
|
|
3777
4074
|
style: {
|
|
@@ -3812,11 +4109,12 @@ function Table({
|
|
|
3812
4109
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3813
4110
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3814
4111
|
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)) *
|
|
4112
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable && !cell.leaf ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
4113
|
+
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
3816
4114
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3817
4115
|
"div",
|
|
3818
4116
|
{
|
|
3819
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}`,
|
|
4117
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
3820
4118
|
"data-level": cell.level,
|
|
3821
4119
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3822
4120
|
style: {
|
|
@@ -3872,6 +4170,7 @@ function Table({
|
|
|
3872
4170
|
})();
|
|
3873
4171
|
const selectionOutlineStyle = (() => {
|
|
3874
4172
|
if (!selection || selectionRange) return null;
|
|
4173
|
+
if (rowDragPreview?.sourceIndex === selection.rowIndex) return null;
|
|
3875
4174
|
const row = rows[selection.rowIndex];
|
|
3876
4175
|
const metric = metrics[selection.columnIndex];
|
|
3877
4176
|
const column = columns[selection.columnIndex];
|
|
@@ -3881,10 +4180,11 @@ function Table({
|
|
|
3881
4180
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
3882
4181
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - scrollPosition.top;
|
|
3883
4182
|
const rawBottom = rawTop + rowHeight * (span?.rowSpan ?? 1);
|
|
4183
|
+
const dragOffset = getRowDragOffset(selection.rowIndex);
|
|
3884
4184
|
const horizontalStart = column.fixed === void 0 ? fixedWidth : 0;
|
|
3885
4185
|
const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
3886
4186
|
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
3887
|
-
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom <= verticalStart || rawTop >= renderHeight) return null;
|
|
4187
|
+
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom + dragOffset <= verticalStart || rawTop + dragOffset >= renderHeight) return null;
|
|
3888
4188
|
const borderWidth = 2;
|
|
3889
4189
|
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
|
|
3890
4190
|
const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
|
|
@@ -3894,7 +4194,8 @@ function Table({
|
|
|
3894
4194
|
left,
|
|
3895
4195
|
top,
|
|
3896
4196
|
width: Math.max(0, right - left),
|
|
3897
|
-
height: Math.max(0, bottom - top)
|
|
4197
|
+
height: Math.max(0, bottom - top),
|
|
4198
|
+
transform: `translateY(${dragOffset}px)`
|
|
3898
4199
|
};
|
|
3899
4200
|
})();
|
|
3900
4201
|
const selectionEdgeIndicator = getSelectionEdgeIndicator(scrollPosition.left, scrollPosition.top);
|
|
@@ -4053,6 +4354,10 @@ function Table({
|
|
|
4053
4354
|
className: "rvg-canvas",
|
|
4054
4355
|
style: { width: viewport.width, height: renderHeight },
|
|
4055
4356
|
onMouseMove: (event) => {
|
|
4357
|
+
if (document.documentElement.classList.contains("rvg-is-dragging")) {
|
|
4358
|
+
hideDragTooltips();
|
|
4359
|
+
return;
|
|
4360
|
+
}
|
|
4056
4361
|
if (columnDragRef.current) return;
|
|
4057
4362
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
4058
4363
|
const localY = event.clientY - rect.top;
|
|
@@ -4155,6 +4460,14 @@ function Table({
|
|
|
4155
4460
|
}
|
|
4156
4461
|
},
|
|
4157
4462
|
onPointerDown: (event) => {
|
|
4463
|
+
const headerDragCell = columnDraggable ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
4464
|
+
const columnIndex = locateColumn(event.clientX);
|
|
4465
|
+
const rowDragHandle = rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(event.clientY) >= 0;
|
|
4466
|
+
if (headerDragCell && locateHeaderCellDragHandle(event.clientX, headerDragCell) || rowDragHandle) {
|
|
4467
|
+
hideDragTooltips();
|
|
4468
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
4469
|
+
event.currentTarget.style.cursor = "move";
|
|
4470
|
+
}
|
|
4158
4471
|
handleColumnPointerDown(event);
|
|
4159
4472
|
beginRangeDrag(event);
|
|
4160
4473
|
},
|
|
@@ -4163,10 +4476,12 @@ function Table({
|
|
|
4163
4476
|
updateRangeDrag(event);
|
|
4164
4477
|
},
|
|
4165
4478
|
onPointerUp: (event) => {
|
|
4479
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4166
4480
|
handleColumnPointerUp(event);
|
|
4167
4481
|
endRangeDrag(event);
|
|
4168
4482
|
},
|
|
4169
4483
|
onPointerCancel: (event) => {
|
|
4484
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4170
4485
|
handleColumnPointerUp(event);
|
|
4171
4486
|
endRangeDrag(event);
|
|
4172
4487
|
},
|
|
@@ -4185,7 +4500,7 @@ function Table({
|
|
|
4185
4500
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
4186
4501
|
if (action === "sort") {
|
|
4187
4502
|
const columnKey = columns[columnIndex].key;
|
|
4188
|
-
const next =
|
|
4503
|
+
const next = sortState?.columnKey !== columnKey ? { columnKey, direction: "asc" } : sortState.direction === "asc" ? { columnKey, direction: "desc" } : null;
|
|
4189
4504
|
queueSortStateChange(next);
|
|
4190
4505
|
return;
|
|
4191
4506
|
}
|
|
@@ -4535,12 +4850,12 @@ function Table({
|
|
|
4535
4850
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: labels.rowUnit })
|
|
4536
4851
|
] });
|
|
4537
4852
|
if (item === "move-up") {
|
|
4538
|
-
if (!rowDraggable
|
|
4539
|
-
return renderContextMenuButton("cell-move-up", cellContext, labels.moveUp, () =>
|
|
4853
|
+
if (!rowDraggable) return null;
|
|
4854
|
+
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
4855
|
}
|
|
4541
4856
|
if (item === "move-down") {
|
|
4542
|
-
if (!rowDraggable
|
|
4543
|
-
return renderContextMenuButton("cell-move-down", cellContext, labels.moveDown, () =>
|
|
4857
|
+
if (!rowDraggable) return null;
|
|
4858
|
+
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
4859
|
}
|
|
4545
4860
|
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
4861
|
return null;
|
|
@@ -4572,21 +4887,30 @@ function Table({
|
|
|
4572
4887
|
await Promise.resolve(onCellChange?.({ ...confirmAction.cell, row: confirmAction.row, previousValue: confirmAction.previousValue, value: "" }));
|
|
4573
4888
|
} else {
|
|
4574
4889
|
const deletingKeys = confirmAction.rows.map(({ row, rowIndex }) => getDataRowKey(row, rowIndex));
|
|
4890
|
+
const deletedRows = confirmAction.rows.map(({ row }) => row);
|
|
4891
|
+
const deletingKeySet = new Set(deletingKeys);
|
|
4892
|
+
const nextRows = sourceRows.filter((row, rowIndex) => !deletingKeySet.has(getDataRowKey(row, rowIndex)));
|
|
4575
4893
|
setConfirmAction(null);
|
|
4576
4894
|
setConfirmLoading(false);
|
|
4895
|
+
setPendingDeletedRowKeys((current) => {
|
|
4896
|
+
const next = new Set(current);
|
|
4897
|
+
deletingKeys.forEach((key) => next.add(key));
|
|
4898
|
+
return next;
|
|
4899
|
+
});
|
|
4577
4900
|
if (onDeleteRows) {
|
|
4578
4901
|
setDeleteBusy(true);
|
|
4579
4902
|
try {
|
|
4580
|
-
await Promise.resolve(onDeleteRows(
|
|
4903
|
+
await Promise.resolve(onDeleteRows(nextRows, deletedRows));
|
|
4904
|
+
} catch (error) {
|
|
4905
|
+
setPendingDeletedRowKeys((current) => {
|
|
4906
|
+
const next = new Set(current);
|
|
4907
|
+
deletingKeys.forEach((key) => next.delete(key));
|
|
4908
|
+
return next;
|
|
4909
|
+
});
|
|
4910
|
+
throw error;
|
|
4581
4911
|
} finally {
|
|
4582
4912
|
setDeleteBusy(false);
|
|
4583
4913
|
}
|
|
4584
|
-
} else {
|
|
4585
|
-
setPendingDeletedRowKeys((current) => {
|
|
4586
|
-
const next = new Set(current);
|
|
4587
|
-
deletingKeys.forEach((key) => next.add(key));
|
|
4588
|
-
return next;
|
|
4589
|
-
});
|
|
4590
4914
|
}
|
|
4591
4915
|
return;
|
|
4592
4916
|
}
|
|
@@ -4659,7 +4983,7 @@ function Table({
|
|
|
4659
4983
|
const next = { ...filterValues };
|
|
4660
4984
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4661
4985
|
else delete next[key];
|
|
4662
|
-
|
|
4986
|
+
setFilterValues(next);
|
|
4663
4987
|
setFilterEditor(null);
|
|
4664
4988
|
}
|
|
4665
4989
|
}
|
|
@@ -4670,7 +4994,7 @@ function Table({
|
|
|
4670
4994
|
const key = columns[filterEditor.columnIndex].key;
|
|
4671
4995
|
const next = { ...filterValues };
|
|
4672
4996
|
delete next[key];
|
|
4673
|
-
|
|
4997
|
+
setFilterValues(next);
|
|
4674
4998
|
setFilterEditor(null);
|
|
4675
4999
|
}, children: labels.reset }),
|
|
4676
5000
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rvg-filter-confirm", onClick: () => {
|
|
@@ -4678,7 +5002,7 @@ function Table({
|
|
|
4678
5002
|
const next = { ...filterValues };
|
|
4679
5003
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4680
5004
|
else delete next[key];
|
|
4681
|
-
|
|
5005
|
+
setFilterValues(next);
|
|
4682
5006
|
setFilterEditor(null);
|
|
4683
5007
|
}, children: labels.confirm })
|
|
4684
5008
|
] })
|