@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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/Table.tsx
|
|
2
|
-
import { Fragment as Fragment2, useCallback as useCallback2, useEffect as useEffect2, useLayoutEffect as useLayoutEffect2, useMemo, useRef as useRef2, useState as useState4 } from "react";
|
|
2
|
+
import { forwardRef, useImperativeHandle, Fragment as Fragment2, useCallback as useCallback2, useEffect as useEffect2, useLayoutEffect as useLayoutEffect2, useMemo, useRef as useRef2, useState as useState4 } from "react";
|
|
3
3
|
import { flushSync } from "react-dom";
|
|
4
4
|
|
|
5
5
|
// src/components/EmptyState.tsx
|
|
@@ -288,16 +288,6 @@ function ContextMenuIcon({ type }) {
|
|
|
288
288
|
};
|
|
289
289
|
return /* @__PURE__ */ jsx2("svg", { className: "rvg-context-menu-svg", viewBox: "0 0 16 16", "aria-hidden": "true", children: paths[type].map((path) => /* @__PURE__ */ jsx2("path", { d: path }, path)) });
|
|
290
290
|
}
|
|
291
|
-
function RowDragHandleIcon() {
|
|
292
|
-
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 16 16", focusable: "false", children: [
|
|
293
|
-
/* @__PURE__ */ jsx2("circle", { cx: "5", cy: "4", r: "1" }),
|
|
294
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "4", r: "1" }),
|
|
295
|
-
/* @__PURE__ */ jsx2("circle", { cx: "5", cy: "8", r: "1" }),
|
|
296
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "8", r: "1" }),
|
|
297
|
-
/* @__PURE__ */ jsx2("circle", { cx: "5", cy: "12", r: "1" }),
|
|
298
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "12", r: "1" })
|
|
299
|
-
] });
|
|
300
|
-
}
|
|
301
291
|
function LoadingSpinnerIcon() {
|
|
302
292
|
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("path", { d: "M20 12a8 8 0 1 1-3.1-6.3" }) });
|
|
303
293
|
}
|
|
@@ -725,6 +715,48 @@ function createRowDragHandleSvg() {
|
|
|
725
715
|
}
|
|
726
716
|
return svg;
|
|
727
717
|
}
|
|
718
|
+
function createHeaderDragHandleSvg() {
|
|
719
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
720
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
721
|
+
svg.setAttribute("aria-hidden", "true");
|
|
722
|
+
for (const cy of [2.5, 7, 11.5]) {
|
|
723
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
724
|
+
circle.setAttribute("cx", "7");
|
|
725
|
+
circle.setAttribute("cy", String(cy));
|
|
726
|
+
circle.setAttribute("r", "1.25");
|
|
727
|
+
svg.appendChild(circle);
|
|
728
|
+
}
|
|
729
|
+
return svg;
|
|
730
|
+
}
|
|
731
|
+
function createHeaderSortSvg(direction) {
|
|
732
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
733
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
734
|
+
svg.setAttribute("aria-hidden", "true");
|
|
735
|
+
for (const [value, active] of [
|
|
736
|
+
["M3 5.5 7 1.5l4 4Z", direction === "asc"],
|
|
737
|
+
["M3 8.5 7 12.5l4-4Z", direction === "desc"]
|
|
738
|
+
]) {
|
|
739
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
740
|
+
path.setAttribute("d", value);
|
|
741
|
+
if (active) path.classList.add("is-active");
|
|
742
|
+
svg.appendChild(path);
|
|
743
|
+
}
|
|
744
|
+
return svg;
|
|
745
|
+
}
|
|
746
|
+
function createHeaderSearchSvg(active) {
|
|
747
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
748
|
+
svg.setAttribute("viewBox", "0 0 14 14");
|
|
749
|
+
svg.setAttribute("aria-hidden", "true");
|
|
750
|
+
if (active) svg.classList.add("is-active");
|
|
751
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
752
|
+
circle.setAttribute("cx", "5.5");
|
|
753
|
+
circle.setAttribute("cy", "5.5");
|
|
754
|
+
circle.setAttribute("r", "4.25");
|
|
755
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
756
|
+
path.setAttribute("d", "m8.75 8.75 2.25 2.25");
|
|
757
|
+
svg.append(circle, path);
|
|
758
|
+
return svg;
|
|
759
|
+
}
|
|
728
760
|
|
|
729
761
|
// src/Table.tsx
|
|
730
762
|
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
@@ -745,6 +777,7 @@ function getDisplayLabel(column, row, rowIndex) {
|
|
|
745
777
|
|
|
746
778
|
// src/core/layout.ts
|
|
747
779
|
var DEFAULT_COLUMN_WIDTH = 140;
|
|
780
|
+
var HEADER_ACTION_SLOT_WIDTH = 16;
|
|
748
781
|
function isDataColumn(column) {
|
|
749
782
|
return !column.rowSelection && !column.rowDragHandle && !column.rowNumber;
|
|
750
783
|
}
|
|
@@ -759,7 +792,7 @@ function getHeaderTitleRequiredWidth(column, titleWidth) {
|
|
|
759
792
|
return minimumReadableTitleWidth + (column.align === "center" ? 20 : 22);
|
|
760
793
|
}
|
|
761
794
|
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26) {
|
|
762
|
-
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) /
|
|
795
|
+
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) / HEADER_ACTION_SLOT_WIDTH));
|
|
763
796
|
const candidates = [
|
|
764
797
|
isColumnFilterable(column) ? "filter" : null,
|
|
765
798
|
isColumnSortable(column) ? "sort" : null,
|
|
@@ -838,12 +871,15 @@ var COLORS = {
|
|
|
838
871
|
grid: "#e3e6e8",
|
|
839
872
|
text: "#202124",
|
|
840
873
|
muted: "#5f6368",
|
|
874
|
+
icon: "#9aa0a6",
|
|
875
|
+
borderStrong: "#b8bec4",
|
|
841
876
|
selection: "#1677ff",
|
|
842
877
|
selectionFill: "#edf4ff",
|
|
843
878
|
axisSelectionFill: "#e8f2ff",
|
|
844
879
|
rowHoverFill: "#f6f9fc",
|
|
845
880
|
editedFill: "#fff1b8",
|
|
846
881
|
insertedFill: "#c8ead4",
|
|
882
|
+
columnDropTargetFill: "#eeeeee",
|
|
847
883
|
stripe: "#fafbfc"
|
|
848
884
|
};
|
|
849
885
|
function ellipsizeText(context, text, maxWidth) {
|
|
@@ -863,7 +899,7 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
863
899
|
return `${text.slice(0, start)}${ellipsis}`;
|
|
864
900
|
}
|
|
865
901
|
function paintGrid(options) {
|
|
866
|
-
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;
|
|
902
|
+
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;
|
|
867
903
|
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
868
904
|
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
869
905
|
const colors = { ...COLORS, ...options.colors };
|
|
@@ -909,11 +945,19 @@ function paintGrid(options) {
|
|
|
909
945
|
const getColumnX = (index) => {
|
|
910
946
|
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;
|
|
911
947
|
};
|
|
948
|
+
const getRowDragOffset = (rowIndex) => {
|
|
949
|
+
if (!rowDragPreview || rowIndex === rowDragPreview.sourceIndex) return 0;
|
|
950
|
+
if (rowDragPreview.sourceIndex < rowDragPreview.targetIndex) {
|
|
951
|
+
return rowIndex > rowDragPreview.sourceIndex && rowIndex <= rowDragPreview.targetIndex ? -rowHeight : 0;
|
|
952
|
+
}
|
|
953
|
+
return rowIndex >= rowDragPreview.targetIndex && rowIndex < rowDragPreview.sourceIndex ? rowHeight : 0;
|
|
954
|
+
};
|
|
955
|
+
const rowBelowDragGap = rowDragPreview ? rowDragPreview.sourceIndex <= rowDragPreview.targetIndex ? rowDragPreview.targetIndex + 1 : rowDragPreview.targetIndex : -1;
|
|
912
956
|
const paintBodyColumns = (layer) => {
|
|
913
957
|
const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
|
|
914
958
|
for (let rowIndex = rowStart; rowIndex < range.rowEnd; rowIndex += 1) {
|
|
915
959
|
if (rowDragPreview?.sourceIndex === rowIndex) continue;
|
|
916
|
-
const shift =
|
|
960
|
+
const shift = getRowDragOffset(rowIndex);
|
|
917
961
|
const y = bodyTop + rowIndex * rowHeight - scrollTop + shift;
|
|
918
962
|
const row = rows[rowIndex];
|
|
919
963
|
const rowKey = getRowKey(row, rowIndex);
|
|
@@ -946,6 +990,10 @@ function paintGrid(options) {
|
|
|
946
990
|
ctx.fillStyle = colors.rowHoverFill;
|
|
947
991
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
948
992
|
}
|
|
993
|
+
if (columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex) {
|
|
994
|
+
ctx.fillStyle = colors.columnDropTargetFill;
|
|
995
|
+
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
996
|
+
}
|
|
949
997
|
if (highlightInsertedRows && insertedRowKeys.has(rowKey)) {
|
|
950
998
|
ctx.fillStyle = colors.insertedFill;
|
|
951
999
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
@@ -972,6 +1020,7 @@ function paintGrid(options) {
|
|
|
972
1020
|
}
|
|
973
1021
|
ctx.fillStyle = colors.grid;
|
|
974
1022
|
if (!verticalBorderless) ctx.fillRect(x + cellWidth - 1, y, 1, cellHeight);
|
|
1023
|
+
if (rowIndex === rowBelowDragGap) ctx.fillRect(x, y, cellWidth, 1);
|
|
975
1024
|
if (!options.suppressLastRowBottomBorder || rowIndex !== rows.length - 1) {
|
|
976
1025
|
ctx.fillRect(x, y + cellHeight - 1, cellWidth, 1);
|
|
977
1026
|
}
|
|
@@ -998,6 +1047,59 @@ function paintGrid(options) {
|
|
|
998
1047
|
if (columnIndex === rangeColumnStart) ctx.fillRect(x, y, 2, cellHeight);
|
|
999
1048
|
if (columnIndex === rangeColumnEnd) ctx.fillRect(x + cellWidth - 2, y, 2, cellHeight);
|
|
1000
1049
|
}
|
|
1050
|
+
if (column.rowDragHandle) {
|
|
1051
|
+
const iconLeft = x + (cellWidth - 16) / 2;
|
|
1052
|
+
const iconTop = y + (cellHeight - 16) / 2;
|
|
1053
|
+
ctx.fillStyle = colors.icon;
|
|
1054
|
+
ctx.beginPath();
|
|
1055
|
+
for (const circleX of [5, 11]) {
|
|
1056
|
+
for (const circleY of [4, 8, 12]) {
|
|
1057
|
+
ctx.moveTo(iconLeft + circleX + 1, iconTop + circleY);
|
|
1058
|
+
ctx.arc(iconLeft + circleX, iconTop + circleY, 1, 0, Math.PI * 2);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
ctx.fill();
|
|
1062
|
+
}
|
|
1063
|
+
if (column.rowSelection) {
|
|
1064
|
+
const iconLeft = x + (cellWidth - 16) / 2;
|
|
1065
|
+
const iconTop = y + (cellHeight - 16) / 2;
|
|
1066
|
+
const checked = selectedRowKeys.has(rowKey);
|
|
1067
|
+
ctx.save();
|
|
1068
|
+
ctx.lineWidth = 1;
|
|
1069
|
+
if (rowSelectionMode === "single") {
|
|
1070
|
+
ctx.beginPath();
|
|
1071
|
+
ctx.arc(iconLeft + 8, iconTop + 8, 6.25, 0, Math.PI * 2);
|
|
1072
|
+
ctx.fillStyle = colors.background;
|
|
1073
|
+
ctx.fill();
|
|
1074
|
+
ctx.strokeStyle = checked ? colors.selection : colors.borderStrong;
|
|
1075
|
+
ctx.stroke();
|
|
1076
|
+
if (checked) {
|
|
1077
|
+
ctx.beginPath();
|
|
1078
|
+
ctx.arc(iconLeft + 8, iconTop + 8, 3.25, 0, Math.PI * 2);
|
|
1079
|
+
ctx.fillStyle = colors.selection;
|
|
1080
|
+
ctx.fill();
|
|
1081
|
+
}
|
|
1082
|
+
} else {
|
|
1083
|
+
ctx.beginPath();
|
|
1084
|
+
ctx.roundRect(iconLeft + 1.5, iconTop + 1.5, 13, 13, 3);
|
|
1085
|
+
ctx.fillStyle = checked ? colors.selection : colors.background;
|
|
1086
|
+
ctx.fill();
|
|
1087
|
+
ctx.strokeStyle = checked ? colors.selection : colors.borderStrong;
|
|
1088
|
+
ctx.stroke();
|
|
1089
|
+
if (checked) {
|
|
1090
|
+
ctx.beginPath();
|
|
1091
|
+
ctx.moveTo(iconLeft + 4.1, iconTop + 8);
|
|
1092
|
+
ctx.lineTo(iconLeft + 6.45, iconTop + 10.35);
|
|
1093
|
+
ctx.lineTo(iconLeft + 11.9, iconTop + 5.15);
|
|
1094
|
+
ctx.strokeStyle = colors.background;
|
|
1095
|
+
ctx.lineWidth = 1.75;
|
|
1096
|
+
ctx.lineCap = "round";
|
|
1097
|
+
ctx.lineJoin = "round";
|
|
1098
|
+
ctx.stroke();
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
ctx.restore();
|
|
1102
|
+
}
|
|
1001
1103
|
if (!column.rowDragHandle && !column.rowSelection && !column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
1002
1104
|
let label = "";
|
|
1003
1105
|
try {
|
|
@@ -1053,6 +1155,10 @@ function paintGrid(options) {
|
|
|
1053
1155
|
ctx.fillStyle = colors.selectionFill;
|
|
1054
1156
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1055
1157
|
}
|
|
1158
|
+
if (columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex) {
|
|
1159
|
+
ctx.fillStyle = colors.columnDropTargetFill;
|
|
1160
|
+
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1161
|
+
}
|
|
1056
1162
|
ctx.fillStyle = colors.grid;
|
|
1057
1163
|
if (!verticalBorderless) ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1058
1164
|
ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
@@ -1061,7 +1167,7 @@ function paintGrid(options) {
|
|
|
1061
1167
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1062
1168
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1063
1169
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
1064
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
1170
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
1065
1171
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1066
1172
|
const padding = 10;
|
|
1067
1173
|
const clipWidth = contentWidth;
|
|
@@ -1130,7 +1236,7 @@ function paintGrid(options) {
|
|
|
1130
1236
|
}
|
|
1131
1237
|
const selectedRow = selection ? rows[selection.rowIndex] : void 0;
|
|
1132
1238
|
const hasValidSelection = Boolean(selection && selectedRow && getRowKey(selectedRow, selection.rowIndex) === selection.rowKey);
|
|
1133
|
-
if (selection && hasValidSelection && !selectionRange) {
|
|
1239
|
+
if (selection && hasValidSelection && !selectionRange && !rowDragPreview) {
|
|
1134
1240
|
const metric = metrics[selection.columnIndex];
|
|
1135
1241
|
if (metric) {
|
|
1136
1242
|
const fixedSide = columns[selection.columnIndex].fixed;
|
|
@@ -1139,7 +1245,7 @@ function paintGrid(options) {
|
|
|
1139
1245
|
const selectionWidth = getCellWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
1140
1246
|
const selectionHeight = rowHeight * (span?.rowSpan ?? 1);
|
|
1141
1247
|
const x = Math.round(getColumnX(selection.columnIndex));
|
|
1142
|
-
const y = Math.round(bodyTop + selection.rowIndex * rowHeight - scrollTop);
|
|
1248
|
+
const y = Math.round(bodyTop + selection.rowIndex * rowHeight - scrollTop + getRowDragOffset(selection.rowIndex));
|
|
1143
1249
|
const borderWidth = 2;
|
|
1144
1250
|
const visibleLeft = fixedSide === "left" ? 0 : leftFixedWidth;
|
|
1145
1251
|
const selectionAreaRight = fixedSide === "right" ? width : width - rightFixedWidth;
|
|
@@ -1249,6 +1355,40 @@ function flattenDataColumns(columns, inheritedFixed, insideGroup = false) {
|
|
|
1249
1355
|
return flattenDataColumns(column.children, column.fixed ?? inheritedFixed, true);
|
|
1250
1356
|
});
|
|
1251
1357
|
}
|
|
1358
|
+
function reconcileColumns(current, incoming) {
|
|
1359
|
+
const incomingByKey = new Map(incoming.map((column) => [column.key, column]));
|
|
1360
|
+
const ordered = current.flatMap((column) => {
|
|
1361
|
+
const replacement = incomingByKey.get(column.key);
|
|
1362
|
+
if (!replacement) return [];
|
|
1363
|
+
incomingByKey.delete(column.key);
|
|
1364
|
+
return [{
|
|
1365
|
+
...replacement,
|
|
1366
|
+
children: replacement.children ? reconcileColumns(column.children ?? [], replacement.children) : void 0
|
|
1367
|
+
}];
|
|
1368
|
+
});
|
|
1369
|
+
incoming.forEach((column) => {
|
|
1370
|
+
if (incomingByKey.has(column.key)) ordered.push(column);
|
|
1371
|
+
});
|
|
1372
|
+
return ordered;
|
|
1373
|
+
}
|
|
1374
|
+
function reorderColumns(columns, detail) {
|
|
1375
|
+
const reorder = (items) => {
|
|
1376
|
+
const sourceIndex = items.findIndex((column2) => column2.key === detail.sourceKey);
|
|
1377
|
+
const targetIndex = items.findIndex((column2) => column2.key === detail.targetKey);
|
|
1378
|
+
if (sourceIndex < 0 || targetIndex < 0 || sourceIndex === targetIndex) return items;
|
|
1379
|
+
const next = items.slice();
|
|
1380
|
+
const [column] = next.splice(sourceIndex, 1);
|
|
1381
|
+
let insertIndex = targetIndex + (detail.placement === "after" ? 1 : 0);
|
|
1382
|
+
if (sourceIndex < insertIndex) insertIndex -= 1;
|
|
1383
|
+
next.splice(insertIndex, 0, column);
|
|
1384
|
+
return next;
|
|
1385
|
+
};
|
|
1386
|
+
if (!detail.parentKey) return reorder(columns);
|
|
1387
|
+
return columns.map((column) => {
|
|
1388
|
+
if (column.key === detail.parentKey && column.children) return { ...column, children: reorder(column.children) };
|
|
1389
|
+
return column.children ? { ...column, children: reorderColumns(column.children, detail) } : column;
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1252
1392
|
function buildHeaderCells(sourceColumns, utilityColumnCount, depth) {
|
|
1253
1393
|
const cells = [];
|
|
1254
1394
|
let leafIndex = utilityColumnCount;
|
|
@@ -1352,8 +1492,8 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1352
1492
|
}
|
|
1353
1493
|
return defaults;
|
|
1354
1494
|
}
|
|
1355
|
-
function
|
|
1356
|
-
columns:
|
|
1495
|
+
function TableInner({
|
|
1496
|
+
columns: columnProps,
|
|
1357
1497
|
rows: sourceRows,
|
|
1358
1498
|
rowKey,
|
|
1359
1499
|
width = "100%",
|
|
@@ -1382,31 +1522,35 @@ function Table({
|
|
|
1382
1522
|
rowSelection,
|
|
1383
1523
|
selectedRowKeys,
|
|
1384
1524
|
defaultSelectedRowKeys,
|
|
1385
|
-
|
|
1525
|
+
onSelectedRowChange,
|
|
1386
1526
|
columnSelection,
|
|
1387
1527
|
selectedColumnKeys,
|
|
1388
1528
|
defaultSelectedColumnKeys,
|
|
1389
|
-
|
|
1529
|
+
onSelectedColumnChange,
|
|
1390
1530
|
columnDraggable = true,
|
|
1391
|
-
columnResizable =
|
|
1392
|
-
|
|
1531
|
+
columnResizable = true,
|
|
1532
|
+
onColumnsReorder,
|
|
1393
1533
|
onColumnResize,
|
|
1394
1534
|
rowDraggable = false,
|
|
1395
|
-
|
|
1535
|
+
onRowsReorder,
|
|
1396
1536
|
onInsertRows,
|
|
1397
1537
|
onDeleteRows,
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
filterValues = {},
|
|
1401
|
-
onFilterValuesChange,
|
|
1538
|
+
onSortChange,
|
|
1539
|
+
onFilterChange,
|
|
1402
1540
|
onCellChange,
|
|
1541
|
+
onCellClick,
|
|
1542
|
+
onCellDoubleClick,
|
|
1403
1543
|
onCellContextMenu,
|
|
1404
1544
|
contextMenu: contextMenuConfig = true,
|
|
1405
1545
|
emptyContent,
|
|
1406
1546
|
className = "",
|
|
1407
1547
|
style,
|
|
1408
1548
|
ariaLabel = "Data grid"
|
|
1409
|
-
}) {
|
|
1549
|
+
}, ref) {
|
|
1550
|
+
const [sourceColumns, setSourceColumns] = useState4(columnProps);
|
|
1551
|
+
useEffect2(() => {
|
|
1552
|
+
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1553
|
+
}, [columnProps]);
|
|
1410
1554
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1411
1555
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1412
1556
|
const headerDepth = useMemo(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
@@ -1448,6 +1592,7 @@ function Table({
|
|
|
1448
1592
|
const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
|
|
1449
1593
|
const [resizedColumnWidths, setResizedColumnWidths] = useState4({});
|
|
1450
1594
|
const leafSourceColumns = useMemo(() => flattenDataColumns(sourceColumns), [sourceColumns]);
|
|
1595
|
+
const showRowCheckbox = Boolean(rowSelection) && (typeof rowSelection !== "object" || rowSelection.showCheckbox !== false);
|
|
1451
1596
|
useEffect2(() => {
|
|
1452
1597
|
if (!isProductionRuntime() && hasNestedFixedColumns(sourceColumns)) {
|
|
1453
1598
|
console.warn("[Table] Multi-level headers only support fixed columns on top-level columns. Nested fixed values are ignored.");
|
|
@@ -1458,19 +1603,19 @@ function Table({
|
|
|
1458
1603
|
if (rowDraggable) {
|
|
1459
1604
|
utilityColumns.push({ key: "__rvg_row_drag__", title: "", width: 36, align: "center", fixed: "left", rowDragHandle: true });
|
|
1460
1605
|
}
|
|
1461
|
-
if (
|
|
1606
|
+
if (showRowCheckbox) {
|
|
1462
1607
|
utilityColumns.push({ key: "__rvg_row_selection__", title: "", width: 44, align: "center", fixed: "left", rowSelection: true });
|
|
1463
1608
|
}
|
|
1464
1609
|
if (rowNumber) {
|
|
1465
|
-
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: "left", rowNumber: true });
|
|
1610
|
+
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 });
|
|
1466
1611
|
}
|
|
1467
1612
|
const dataColumns = leafSourceColumns.map((column) => {
|
|
1468
1613
|
const resizedWidth = resizedColumnWidths[column.key];
|
|
1469
1614
|
return resizedWidth === void 0 ? column : { ...column, width: resizedWidth };
|
|
1470
1615
|
});
|
|
1471
1616
|
return [...utilityColumns, ...dataColumns];
|
|
1472
|
-
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber,
|
|
1473
|
-
const utilityColumnCount = (rowDraggable ? 1 : 0) + (
|
|
1617
|
+
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber, showRowCheckbox, sourceRows.length]);
|
|
1618
|
+
const utilityColumnCount = (rowDraggable ? 1 : 0) + (showRowCheckbox ? 1 : 0) + (rowNumber ? 1 : 0);
|
|
1474
1619
|
const headerCells = useMemo(() => buildHeaderCells(sourceColumns, utilityColumnCount, headerDepth), [headerDepth, sourceColumns, utilityColumnCount]);
|
|
1475
1620
|
const activeCustomHeaderLevels = useMemo(() => {
|
|
1476
1621
|
const levels = /* @__PURE__ */ new Map();
|
|
@@ -1487,7 +1632,6 @@ function Table({
|
|
|
1487
1632
|
const frameRef = useRef2(null);
|
|
1488
1633
|
const textFrameRef = useRef2(null);
|
|
1489
1634
|
const toastTimerRef = useRef2(null);
|
|
1490
|
-
const sortDebounceRef = useRef2(null);
|
|
1491
1635
|
const headerTooltipTimerRef = useRef2(null);
|
|
1492
1636
|
const cellTooltipTimerRef = useRef2(null);
|
|
1493
1637
|
const pendingHeaderTooltipKeyRef = useRef2("");
|
|
@@ -1518,6 +1662,7 @@ function Table({
|
|
|
1518
1662
|
const suppressClickRef = useRef2(false);
|
|
1519
1663
|
const hasCompletedLoadRef = useRef2(!loading);
|
|
1520
1664
|
const columnDragPreviewRef = useRef2(null);
|
|
1665
|
+
const validColumnDropRef = useRef2(null);
|
|
1521
1666
|
const hoveredHeaderActionRef = useRef2(null);
|
|
1522
1667
|
const hoveredRowIndexRef = useRef2(null);
|
|
1523
1668
|
const [viewport, setViewport] = useState4({ width: 0, height: typeof height === "number" ? height : FALLBACK_HEIGHT });
|
|
@@ -1525,11 +1670,8 @@ function Table({
|
|
|
1525
1670
|
const resolvedHeight = typeof height === "number" ? height : viewport.height || FALLBACK_HEIGHT;
|
|
1526
1671
|
const [scrollPosition, setScrollPosition] = useState4({ left: 0, top: 0 });
|
|
1527
1672
|
const scrollRef = useRef2({ left: 0, top: 0 });
|
|
1528
|
-
const [selection, setSelection] = useControllableValue(selectedCell, defaultSelectedCell, onSelectedCellChange);
|
|
1529
|
-
const [selectionRange, setSelectionRange] = useState4(null);
|
|
1530
|
-
const rangeDragRef = useRef2(null);
|
|
1531
1673
|
const [rowKeys, setRowKeys] = useControllableKeys(selectedRowKeys, defaultSelectedRowKeys, (keys) => {
|
|
1532
|
-
if (!
|
|
1674
|
+
if (!onSelectedRowChange) return;
|
|
1533
1675
|
const missing = new Set(keys.filter((key) => !rowByKeyRef.current.has(key)));
|
|
1534
1676
|
if (missing.size > 0) {
|
|
1535
1677
|
for (let index = 0; index < rows.length && missing.size > 0; index += 1) {
|
|
@@ -1546,12 +1688,13 @@ function Table({
|
|
|
1546
1688
|
const index = rowIndexByKeyRef.current.get(key);
|
|
1547
1689
|
return row && index !== void 0 ? [{ row, index }] : [];
|
|
1548
1690
|
});
|
|
1549
|
-
|
|
1691
|
+
onSelectedRowChange(keys, entries.map(({ row }) => row), entries.map(({ index }) => index));
|
|
1550
1692
|
});
|
|
1551
|
-
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys,
|
|
1693
|
+
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys, onSelectedColumnChange);
|
|
1552
1694
|
const [editing, setEditing] = useState4(null);
|
|
1553
1695
|
const [draft, setDraft] = useState4("");
|
|
1554
1696
|
const [rowDragPreview, setRowDragPreview] = useState4(null);
|
|
1697
|
+
const [columnDropTarget, setColumnDropTarget] = useState4(null);
|
|
1555
1698
|
useEffect2(() => {
|
|
1556
1699
|
if (!loading) hasCompletedLoadRef.current = true;
|
|
1557
1700
|
}, [loading]);
|
|
@@ -1620,6 +1763,8 @@ function Table({
|
|
|
1620
1763
|
return () => observer.disconnect();
|
|
1621
1764
|
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1622
1765
|
const [filterEditor, setFilterEditor] = useState4(null);
|
|
1766
|
+
const [filterValues, setFilterValues] = useState4({});
|
|
1767
|
+
const [sortState, setSortState] = useState4(null);
|
|
1623
1768
|
const [contextMenu, setContextMenu] = useState4(null);
|
|
1624
1769
|
const [insertCounts, setInsertCounts] = useState4({ before: 1, after: 1 });
|
|
1625
1770
|
const [confirmAction, setConfirmAction] = useState4(null);
|
|
@@ -1632,7 +1777,20 @@ function Table({
|
|
|
1632
1777
|
const [hoveredHeaderAction, setHoveredHeaderAction] = useState4(null);
|
|
1633
1778
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = useState4(null);
|
|
1634
1779
|
const [hoveredCellTooltip, setHoveredCellTooltip] = useState4(null);
|
|
1635
|
-
const
|
|
1780
|
+
const hideDragTooltips = useCallback2(() => {
|
|
1781
|
+
if (headerTooltipTimerRef.current !== null) {
|
|
1782
|
+
clearTimeout(headerTooltipTimerRef.current);
|
|
1783
|
+
headerTooltipTimerRef.current = null;
|
|
1784
|
+
}
|
|
1785
|
+
if (cellTooltipTimerRef.current !== null) {
|
|
1786
|
+
clearTimeout(cellTooltipTimerRef.current);
|
|
1787
|
+
cellTooltipTimerRef.current = null;
|
|
1788
|
+
}
|
|
1789
|
+
pendingHeaderTooltipKeyRef.current = "";
|
|
1790
|
+
pendingCellTooltipKeyRef.current = "";
|
|
1791
|
+
setVisibleHeaderTooltip(null);
|
|
1792
|
+
setHoveredCellTooltip(null);
|
|
1793
|
+
}, []);
|
|
1636
1794
|
const [editedCellKeys, setEditedCellKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1637
1795
|
const [cellAnnotations, setCellAnnotations] = useState4(() => /* @__PURE__ */ new Map());
|
|
1638
1796
|
const [annotationType, setAnnotationType] = useState4("corner");
|
|
@@ -1644,6 +1802,7 @@ function Table({
|
|
|
1644
1802
|
const [pendingDeletedRowKeys, setPendingDeletedRowKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1645
1803
|
const [pendingInserts, setPendingInserts] = useState4(() => []);
|
|
1646
1804
|
const [insertedRowKeys, setInsertedRowKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1805
|
+
const [rowOrderKeys, setRowOrderKeys] = useState4(null);
|
|
1647
1806
|
const settledPendingInsertIdsRef = useRef2(/* @__PURE__ */ new Set());
|
|
1648
1807
|
const getDataRowKey = useCallback2((row, index) => {
|
|
1649
1808
|
return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
|
|
@@ -1658,7 +1817,7 @@ function Table({
|
|
|
1658
1817
|
}
|
|
1659
1818
|
return sourceRows.findIndex((sourceRow, index) => getDataRowKey(sourceRow, index) === key);
|
|
1660
1819
|
}, [getDataRowKey, sourceRows]);
|
|
1661
|
-
const
|
|
1820
|
+
const orderedRows = useMemo(() => {
|
|
1662
1821
|
let next = sourceRows;
|
|
1663
1822
|
if (pendingInserts.length > 0) {
|
|
1664
1823
|
const activeInserts = pendingInserts.filter((insert) => {
|
|
@@ -1677,9 +1836,91 @@ function Table({
|
|
|
1677
1836
|
insertedOffset += insert.rows.length;
|
|
1678
1837
|
});
|
|
1679
1838
|
}
|
|
1680
|
-
if (pendingDeletedRowKeys.size
|
|
1681
|
-
|
|
1682
|
-
|
|
1839
|
+
if (pendingDeletedRowKeys.size > 0) {
|
|
1840
|
+
next = next.filter((row, index) => !pendingDeletedRowKeys.has(getDataRowKey(row, index)));
|
|
1841
|
+
}
|
|
1842
|
+
if (!rowOrderKeys) return next;
|
|
1843
|
+
const rowsByKey = new Map(next.map((row, index) => [getDataRowKey(row, index), row]));
|
|
1844
|
+
const ordered = rowOrderKeys.flatMap((key) => {
|
|
1845
|
+
const row = rowsByKey.get(key);
|
|
1846
|
+
if (!row) return [];
|
|
1847
|
+
rowsByKey.delete(key);
|
|
1848
|
+
return [row];
|
|
1849
|
+
});
|
|
1850
|
+
next.forEach((row, index) => {
|
|
1851
|
+
const key = getDataRowKey(row, index);
|
|
1852
|
+
if (rowsByKey.has(key)) ordered.push(row);
|
|
1853
|
+
});
|
|
1854
|
+
return ordered;
|
|
1855
|
+
}, [getDataRowKey, pendingDeletedRowKeys, pendingInserts, rowOrderKeys, sourceRows]);
|
|
1856
|
+
const activeFilterValues = useMemo(() => Object.fromEntries(
|
|
1857
|
+
Object.entries(filterValues).filter(([, value]) => value.trim() !== "")
|
|
1858
|
+
), [filterValues]);
|
|
1859
|
+
const filteredRows = useMemo(() => {
|
|
1860
|
+
if (Object.keys(activeFilterValues).length === 0) return orderedRows;
|
|
1861
|
+
if (onFilterChange) return onFilterChange(orderedRows, activeFilterValues);
|
|
1862
|
+
return orderedRows.filter((row, rowIndex) => Object.entries(activeFilterValues).every(([columnKey, query]) => {
|
|
1863
|
+
const column = columns.find((candidate) => candidate.key === columnKey);
|
|
1864
|
+
if (!column) return true;
|
|
1865
|
+
return getDisplayLabel(column, row, rowIndex).toLocaleLowerCase().includes(query.trim().toLocaleLowerCase());
|
|
1866
|
+
}));
|
|
1867
|
+
}, [activeFilterValues, columns, onFilterChange, orderedRows]);
|
|
1868
|
+
const rows = useMemo(() => {
|
|
1869
|
+
if (!sortState) return filteredRows;
|
|
1870
|
+
if (onSortChange) return onSortChange(filteredRows, sortState);
|
|
1871
|
+
const column = columns.find((candidate) => candidate.key === sortState.columnKey);
|
|
1872
|
+
if (!column) return filteredRows;
|
|
1873
|
+
const direction = sortState.direction === "asc" ? 1 : -1;
|
|
1874
|
+
return filteredRows.slice().sort((left, right) => {
|
|
1875
|
+
const leftValue = column.dataIndex === void 0 ? void 0 : left[column.dataIndex];
|
|
1876
|
+
const rightValue = column.dataIndex === void 0 ? void 0 : right[column.dataIndex];
|
|
1877
|
+
const result = typeof leftValue === "number" && typeof rightValue === "number" ? leftValue - rightValue : getDisplayLabel(column, left, 0).localeCompare(getDisplayLabel(column, right, 0), language);
|
|
1878
|
+
return result * direction;
|
|
1879
|
+
});
|
|
1880
|
+
}, [columns, filteredRows, language, onSortChange, sortState]);
|
|
1881
|
+
const resolveSelectionTarget = useCallback2((target) => {
|
|
1882
|
+
if (target == null) return target;
|
|
1883
|
+
const columnIndex = columns.findIndex((column) => column.key === target.columnKey);
|
|
1884
|
+
const rowIndex = target.rowKey !== void 0 ? rows.findIndex((row2, index) => getDataRowKey(row2, index) === target.rowKey) : target.rowIndex ?? -1;
|
|
1885
|
+
const row = rows[rowIndex];
|
|
1886
|
+
if (columnIndex < 0 || !row) return null;
|
|
1887
|
+
return {
|
|
1888
|
+
rowIndex,
|
|
1889
|
+
columnIndex,
|
|
1890
|
+
rowKey: getDataRowKey(row, rowIndex),
|
|
1891
|
+
columnKey: target.columnKey
|
|
1892
|
+
};
|
|
1893
|
+
}, [columns, getDataRowKey, rows]);
|
|
1894
|
+
const resolvedSelectedCell = useMemo(() => resolveSelectionTarget(selectedCell), [resolveSelectionTarget, selectedCell]);
|
|
1895
|
+
const resolvedDefaultSelectedCell = useMemo(() => resolveSelectionTarget(defaultSelectedCell), [defaultSelectedCell, resolveSelectionTarget]);
|
|
1896
|
+
const handleSelectedCellChange = useCallback2((next) => {
|
|
1897
|
+
if (!onSelectedCellChange) return;
|
|
1898
|
+
if (!next) {
|
|
1899
|
+
onSelectedCellChange(null);
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
const row = rows[next.rowIndex];
|
|
1903
|
+
const column = columns[next.columnIndex];
|
|
1904
|
+
const value = row && column?.dataIndex !== void 0 ? row[column.dataIndex] : void 0;
|
|
1905
|
+
onSelectedCellChange({ ...next, value });
|
|
1906
|
+
}, [columns, onSelectedCellChange, rows]);
|
|
1907
|
+
const [selection, setSelection] = useControllableValue(resolvedSelectedCell, resolvedDefaultSelectedCell, handleSelectedCellChange);
|
|
1908
|
+
const [selectionRange, setSelectionRange] = useState4(null);
|
|
1909
|
+
const rangeDragRef = useRef2(null);
|
|
1910
|
+
const applyRowOrder = useCallback2((sourceIndex, targetIndex) => {
|
|
1911
|
+
if (sourceIndex === targetIndex || sourceIndex < 0 || targetIndex < 0 || sourceIndex >= rows.length || targetIndex >= rows.length) return;
|
|
1912
|
+
const nextEntries = rows.map((row, index) => ({ row, key: getDataRowKey(row, index) }));
|
|
1913
|
+
const [entry] = nextEntries.splice(sourceIndex, 1);
|
|
1914
|
+
nextEntries.splice(targetIndex, 0, entry);
|
|
1915
|
+
const nextRows = nextEntries.map(({ row }) => row);
|
|
1916
|
+
setRowOrderKeys(nextEntries.map(({ key }) => key));
|
|
1917
|
+
onRowsReorder?.(nextRows, { sourceIndex, targetIndex });
|
|
1918
|
+
}, [getDataRowKey, onRowsReorder, rows]);
|
|
1919
|
+
const applyColumnOrder = useCallback2((sourceIndex, targetIndex, detail) => {
|
|
1920
|
+
const nextColumns = reorderColumns(sourceColumns, detail);
|
|
1921
|
+
setSourceColumns(nextColumns);
|
|
1922
|
+
onColumnsReorder?.(nextColumns, { sourceIndex, targetIndex, ...detail });
|
|
1923
|
+
}, [onColumnsReorder, sourceColumns]);
|
|
1683
1924
|
useEffect2(() => {
|
|
1684
1925
|
if (insertBusy || settledPendingInsertIdsRef.current.size === 0) return;
|
|
1685
1926
|
setPendingInserts((current) => {
|
|
@@ -1921,19 +2162,22 @@ function Table({
|
|
|
1921
2162
|
grid: readThemeColor(themeStyles, "--rvg-color-grid", "#e3e6e8"),
|
|
1922
2163
|
text: readThemeColor(themeStyles, "--rvg-color-text", "#202124"),
|
|
1923
2164
|
muted: readThemeColor(themeStyles, "--rvg-color-muted", "#5f6368"),
|
|
2165
|
+
icon: readThemeColor(themeStyles, "--rvg-color-icon", "#9aa0a6"),
|
|
2166
|
+
borderStrong: readThemeColor(themeStyles, "--rvg-color-border-strong", "#b8bec4"),
|
|
1924
2167
|
selection: readThemeColor(themeStyles, "--rvg-color-primary", "#1677ff"),
|
|
1925
2168
|
selectionFill: readThemeColor(themeStyles, "--rvg-color-selection-fill", "#edf4ff"),
|
|
1926
2169
|
axisSelectionFill: readThemeColor(themeStyles, "--rvg-color-axis-selection-fill", "#e8f2ff"),
|
|
1927
2170
|
rowHoverFill: readThemeColor(themeStyles, "--rvg-color-row-hover-fill", "#f6f9fc"),
|
|
1928
2171
|
editedFill: editedCellHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-edited-fill", "#fff1b8"),
|
|
1929
2172
|
insertedFill: insertedRowHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-inserted-fill", "#c8ead4"),
|
|
2173
|
+
columnDropTargetFill: readThemeColor(themeStyles, "--rvg-color-column-drop-target-fill", "#eeeeee"),
|
|
1930
2174
|
stripe: stripedColor ?? readThemeColor(themeStyles, "--rvg-color-stripe", "#fafbfc")
|
|
1931
2175
|
};
|
|
1932
2176
|
const scroll = scrollRef.current;
|
|
1933
2177
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1934
2178
|
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 };
|
|
1935
|
-
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 });
|
|
1936
|
-
}, [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]);
|
|
2179
|
+
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 });
|
|
2180
|
+
}, [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]);
|
|
1937
2181
|
const scheduleDraw = useCallback2(() => {
|
|
1938
2182
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1939
2183
|
}, [draw]);
|
|
@@ -2115,11 +2359,7 @@ function Table({
|
|
|
2115
2359
|
}
|
|
2116
2360
|
};
|
|
2117
2361
|
}, [scheduleDraw]);
|
|
2118
|
-
useEffect2(() => {
|
|
2119
|
-
setDisplaySortState(sortState);
|
|
2120
|
-
}, [sortState]);
|
|
2121
2362
|
useEffect2(() => () => {
|
|
2122
|
-
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
2123
2363
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
2124
2364
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
2125
2365
|
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
@@ -2494,12 +2734,12 @@ function Table({
|
|
|
2494
2734
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2495
2735
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2496
2736
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2497
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2737
|
+
let right = columnRight - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
2498
2738
|
if (visibleActions.sort) {
|
|
2499
|
-
if (localX >= right -
|
|
2500
|
-
right -=
|
|
2739
|
+
if (localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "sort";
|
|
2740
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
2501
2741
|
}
|
|
2502
|
-
if (visibleActions.filter && localX >= right -
|
|
2742
|
+
if (visibleActions.filter && localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "filter";
|
|
2503
2743
|
return null;
|
|
2504
2744
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2505
2745
|
const isHeaderTitleTruncated = useCallback2((columnIndex) => {
|
|
@@ -2509,7 +2749,7 @@ function Table({
|
|
|
2509
2749
|
const metric = metrics[columnIndex];
|
|
2510
2750
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2511
2751
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2512
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
2752
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
2513
2753
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2514
2754
|
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2515
2755
|
const locateHeaderDragHandle = useCallback2((clientX, columnIndex) => {
|
|
@@ -2665,6 +2905,7 @@ function Table({
|
|
|
2665
2905
|
}
|
|
2666
2906
|
const sourceIndex = headerDragCell.startIndex;
|
|
2667
2907
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2908
|
+
validColumnDropRef.current = null;
|
|
2668
2909
|
return {
|
|
2669
2910
|
type: "table-column",
|
|
2670
2911
|
sourceIndex,
|
|
@@ -2675,13 +2916,26 @@ function Table({
|
|
|
2675
2916
|
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2676
2917
|
};
|
|
2677
2918
|
},
|
|
2678
|
-
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2919
|
+
onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
|
|
2679
2920
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2921
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
2922
|
+
const input = location.current.input;
|
|
2923
|
+
const previewOffset = source.data.type === "table-row" ? {
|
|
2924
|
+
x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
|
|
2925
|
+
y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
|
|
2926
|
+
} : {
|
|
2927
|
+
x: Math.max(0, Math.min(metrics[sourceIndex].width, input.clientX - canvasRect.left - getDisplayedColumnLeft(sourceIndex))),
|
|
2928
|
+
y: Math.max(0, Math.min(canvasRect.height, input.clientY - canvasRect.top))
|
|
2929
|
+
};
|
|
2680
2930
|
setCustomNativeDragPreview({
|
|
2681
2931
|
nativeSetDragImage,
|
|
2932
|
+
getOffset: () => previewOffset,
|
|
2682
2933
|
render: ({ container }) => {
|
|
2683
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
2684
2934
|
if (source.data.type === "table-row") {
|
|
2935
|
+
const frame = document.createElement("div");
|
|
2936
|
+
frame.className = "rvg-row-drag-preview-frame";
|
|
2937
|
+
frame.style.width = `${canvasRect.width + 4}px`;
|
|
2938
|
+
frame.style.height = `${rowHeight + 4}px`;
|
|
2685
2939
|
const preview2 = document.createElement("div");
|
|
2686
2940
|
preview2.className = "rvg-row-drag-preview";
|
|
2687
2941
|
preview2.style.width = `${canvasRect.width}px`;
|
|
@@ -2707,10 +2961,14 @@ function Table({
|
|
|
2707
2961
|
} else {
|
|
2708
2962
|
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
2709
2963
|
}
|
|
2964
|
+
if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
|
|
2965
|
+
cell.classList.add("is-selected");
|
|
2966
|
+
}
|
|
2710
2967
|
preview2.appendChild(cell);
|
|
2711
2968
|
});
|
|
2712
|
-
|
|
2713
|
-
|
|
2969
|
+
frame.appendChild(preview2);
|
|
2970
|
+
container.appendChild(frame);
|
|
2971
|
+
return () => frame.remove();
|
|
2714
2972
|
}
|
|
2715
2973
|
const preview = document.createElement("div");
|
|
2716
2974
|
preview.className = "rvg-column-drag-preview";
|
|
@@ -2724,6 +2982,29 @@ function Table({
|
|
|
2724
2982
|
header.style.height = `${headerHeight}px`;
|
|
2725
2983
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
2726
2984
|
header.textContent = column.title;
|
|
2985
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
2986
|
+
let actionRight = 2;
|
|
2987
|
+
if (visibleActions.drag) {
|
|
2988
|
+
const icon = createHeaderDragHandleSvg();
|
|
2989
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
2990
|
+
icon.style.right = `${actionRight}px`;
|
|
2991
|
+
header.appendChild(icon);
|
|
2992
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
2993
|
+
}
|
|
2994
|
+
if (visibleActions.sort) {
|
|
2995
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
2996
|
+
const icon = createHeaderSortSvg(direction);
|
|
2997
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
2998
|
+
icon.style.right = `${actionRight}px`;
|
|
2999
|
+
header.appendChild(icon);
|
|
3000
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
3001
|
+
}
|
|
3002
|
+
if (visibleActions.filter) {
|
|
3003
|
+
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3004
|
+
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3005
|
+
icon.style.right = `${actionRight}px`;
|
|
3006
|
+
header.appendChild(icon);
|
|
3007
|
+
}
|
|
2727
3008
|
preview.appendChild(header);
|
|
2728
3009
|
for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
|
|
2729
3010
|
const row = rows[rowIndex];
|
|
@@ -2752,6 +3033,8 @@ function Table({
|
|
|
2752
3033
|
},
|
|
2753
3034
|
onDragStart: ({ source }) => {
|
|
2754
3035
|
suppressClickRef.current = true;
|
|
3036
|
+
hideDragTooltips();
|
|
3037
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
2755
3038
|
canvas.style.cursor = "move";
|
|
2756
3039
|
if (source.data.type === "table-row") {
|
|
2757
3040
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2777,15 +3060,46 @@ function Table({
|
|
|
2777
3060
|
}
|
|
2778
3061
|
const targetIndex = Number(target?.targetIndex);
|
|
2779
3062
|
if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
|
|
3063
|
+
validColumnDropRef.current = null;
|
|
3064
|
+
setColumnDropTarget(null);
|
|
2780
3065
|
setDragGuide(null);
|
|
2781
3066
|
return;
|
|
2782
3067
|
}
|
|
2783
3068
|
const edge = target?.columnEdge;
|
|
2784
3069
|
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2785
3070
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
|
|
3071
|
+
if (destinationIndex === sourceIndex) {
|
|
3072
|
+
validColumnDropRef.current = null;
|
|
3073
|
+
setColumnDropTarget(null);
|
|
3074
|
+
setDragGuide(null);
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
validColumnDropRef.current = {
|
|
3078
|
+
sourceIndex,
|
|
3079
|
+
targetIndex: destinationIndex,
|
|
3080
|
+
rawTargetIndex: targetIndex,
|
|
3081
|
+
targetKey: String(target.targetKey),
|
|
3082
|
+
headerKind: source.data.headerKind === "group" ? "group" : "column",
|
|
3083
|
+
parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
|
|
3084
|
+
fixed: source.data.fixed === "left" || source.data.fixed === "right" ? source.data.fixed : void 0,
|
|
3085
|
+
columnEdge: edge === "right" ? "right" : "left"
|
|
3086
|
+
};
|
|
3087
|
+
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);
|
|
3088
|
+
const targetEndIndex = Number.isInteger(target?.targetEndIndex) ? Number(target.targetEndIndex) : targetIndex;
|
|
3089
|
+
const hoveredTargetCell = siblingCells.find((cell) => cell.startIndex === targetIndex && cell.endIndex === targetEndIndex);
|
|
3090
|
+
if (!hoveredTargetCell) {
|
|
3091
|
+
validColumnDropRef.current = null;
|
|
3092
|
+
setColumnDropTarget(null);
|
|
3093
|
+
setDragGuide(null);
|
|
3094
|
+
return;
|
|
3095
|
+
}
|
|
3096
|
+
const highlightedCell = edge === "right" ? hoveredTargetCell : siblingCells.filter((cell) => cell.endIndex < hoveredTargetCell.startIndex).sort((left, right) => right.endIndex - left.endIndex)[0] ?? hoveredTargetCell;
|
|
3097
|
+
setColumnDropTarget({ startIndex: highlightedCell.startIndex, endIndex: highlightedCell.endIndex });
|
|
2786
3098
|
const targetLeft = Number(target?.targetLeft);
|
|
2787
3099
|
const targetWidth = Number(target?.targetWidth);
|
|
2788
3100
|
if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
|
|
3101
|
+
validColumnDropRef.current = null;
|
|
3102
|
+
setColumnDropTarget(null);
|
|
2789
3103
|
setDragGuide(null);
|
|
2790
3104
|
return;
|
|
2791
3105
|
}
|
|
@@ -2793,18 +3107,19 @@ function Table({
|
|
|
2793
3107
|
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2794
3108
|
},
|
|
2795
3109
|
onDrop: ({ source, location }) => {
|
|
3110
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2796
3111
|
const target = location.current.dropTargets[0]?.data;
|
|
2797
3112
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2798
3113
|
if (source.data.type === "table-row") {
|
|
2799
|
-
const
|
|
2800
|
-
let
|
|
2801
|
-
if (sourceIndex <
|
|
2802
|
-
|
|
3114
|
+
const rawTargetIndex = Number(target?.targetIndex);
|
|
3115
|
+
let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
3116
|
+
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3117
|
+
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
2803
3118
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2804
3119
|
setRowDragPreview(null);
|
|
2805
3120
|
setRowDragGuide(null);
|
|
2806
3121
|
canvas.style.cursor = "default";
|
|
2807
|
-
if (Number.isInteger(
|
|
3122
|
+
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
2808
3123
|
requestAnimationFrame(() => {
|
|
2809
3124
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2810
3125
|
});
|
|
@@ -2813,21 +3128,22 @@ function Table({
|
|
|
2813
3128
|
}, 0);
|
|
2814
3129
|
return;
|
|
2815
3130
|
}
|
|
2816
|
-
const
|
|
2817
|
-
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
3131
|
+
const validDrop = validColumnDropRef.current;
|
|
2818
3132
|
canvas.style.cursor = "default";
|
|
2819
3133
|
setDragGuide(null);
|
|
3134
|
+
setColumnDropTarget(null);
|
|
2820
3135
|
columnDragPreviewRef.current = null;
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
3136
|
+
validColumnDropRef.current = null;
|
|
3137
|
+
if (validDrop) {
|
|
3138
|
+
applyColumnOrder(
|
|
3139
|
+
validDrop.sourceIndex - utilityColumnCount,
|
|
3140
|
+
validDrop.targetIndex - utilityColumnCount,
|
|
2825
3141
|
{
|
|
2826
|
-
type:
|
|
3142
|
+
type: validDrop.headerKind,
|
|
2827
3143
|
sourceKey: String(source.data.sourceKey),
|
|
2828
|
-
targetKey:
|
|
2829
|
-
parentKey:
|
|
2830
|
-
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex,
|
|
3144
|
+
targetKey: validDrop.targetKey,
|
|
3145
|
+
parentKey: validDrop.parentKey,
|
|
3146
|
+
placement: getColumnDropPlacement(validDrop.sourceIndex, validDrop.rawTargetIndex, validDrop.columnEdge)
|
|
2831
3147
|
}
|
|
2832
3148
|
);
|
|
2833
3149
|
}
|
|
@@ -2839,6 +3155,7 @@ function Table({
|
|
|
2839
3155
|
const cleanupDrop = dropTargetForElements({
|
|
2840
3156
|
element: canvas,
|
|
2841
3157
|
canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
|
|
3158
|
+
getDropEffect: () => "move",
|
|
2842
3159
|
getData: ({ input, element, source }) => {
|
|
2843
3160
|
if (source.data.type === "table-row") {
|
|
2844
3161
|
const targetIndex2 = locateRow(input.clientY);
|
|
@@ -2847,7 +3164,8 @@ function Table({
|
|
|
2847
3164
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2848
3165
|
return attachClosestEdge({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2849
3166
|
}
|
|
2850
|
-
const
|
|
3167
|
+
const hoveredColumnIndex = locateColumn(input.clientX);
|
|
3168
|
+
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);
|
|
2851
3169
|
if (!targetCell) return { targetIndex: -1 };
|
|
2852
3170
|
let targetIndex = targetCell.startIndex;
|
|
2853
3171
|
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
@@ -2864,6 +3182,7 @@ function Table({
|
|
|
2864
3182
|
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2865
3183
|
return attachClosestEdge({
|
|
2866
3184
|
targetIndex,
|
|
3185
|
+
targetEndIndex: targetCell.endIndex,
|
|
2867
3186
|
targetKey: targetCell.key,
|
|
2868
3187
|
parentKey: targetCell.parentKey,
|
|
2869
3188
|
headerKind,
|
|
@@ -2875,10 +3194,11 @@ function Table({
|
|
|
2875
3194
|
}
|
|
2876
3195
|
});
|
|
2877
3196
|
return () => {
|
|
3197
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2878
3198
|
cleanupDrag();
|
|
2879
3199
|
cleanupDrop();
|
|
2880
3200
|
};
|
|
2881
|
-
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerHeight, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow,
|
|
3201
|
+
}, [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]);
|
|
2882
3202
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
2883
3203
|
const canvas = canvasRef.current;
|
|
2884
3204
|
if (!canvas) return null;
|
|
@@ -3001,9 +3321,15 @@ function Table({
|
|
|
3001
3321
|
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
3002
3322
|
scheduleDraw();
|
|
3003
3323
|
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
3324
|
+
const isCellEditable = useCallback2((cell) => {
|
|
3325
|
+
const column = columns[cell.columnIndex];
|
|
3326
|
+
const row = rows[cell.rowIndex];
|
|
3327
|
+
if (!column || !row || column.dataIndex === void 0 || column.rowNumber || column.rowSelection || column.rowDragHandle) return false;
|
|
3328
|
+
return typeof column.editable === "function" ? column.editable(row[column.dataIndex], row, cell.rowIndex) : column.editable === true;
|
|
3329
|
+
}, [columns, rows]);
|
|
3004
3330
|
const beginEdit = useCallback2((cell) => {
|
|
3005
3331
|
const column = columns[cell.columnIndex];
|
|
3006
|
-
if (!
|
|
3332
|
+
if (!isCellEditable(cell) || column.dataIndex === void 0) return;
|
|
3007
3333
|
const value = rows[cell.rowIndex]?.[column.dataIndex];
|
|
3008
3334
|
setDraft(value == null ? "" : String(value));
|
|
3009
3335
|
const scroller = scrollerRef.current;
|
|
@@ -3045,7 +3371,7 @@ function Table({
|
|
|
3045
3371
|
return;
|
|
3046
3372
|
}
|
|
3047
3373
|
setEditing(cell);
|
|
3048
|
-
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3374
|
+
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, isCellEditable, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3049
3375
|
const getCellEditKey = (cell) => `${typeof cell.rowKey}:${String(cell.rowKey)}\0${cell.columnKey}`;
|
|
3050
3376
|
const markCellEdited = (cell, previousValue, nextValue) => {
|
|
3051
3377
|
const key = getCellEditKey(cell);
|
|
@@ -3073,6 +3399,10 @@ function Table({
|
|
|
3073
3399
|
};
|
|
3074
3400
|
const commitEdit = useCallback2((nextDraft, close = true) => {
|
|
3075
3401
|
if (!editing) return;
|
|
3402
|
+
if (!isCellEditable(editing)) {
|
|
3403
|
+
setEditing(null);
|
|
3404
|
+
return;
|
|
3405
|
+
}
|
|
3076
3406
|
const committedDraft = nextDraft ?? draft;
|
|
3077
3407
|
const column = columns[editing.columnIndex];
|
|
3078
3408
|
const row = rows[editing.rowIndex];
|
|
@@ -3087,7 +3417,7 @@ function Table({
|
|
|
3087
3417
|
onCellChange?.({ ...editing, row, value: committedValue, previousValue });
|
|
3088
3418
|
}
|
|
3089
3419
|
if (close) setEditing(null);
|
|
3090
|
-
}, [columns, draft, editing, onCellChange, rows]);
|
|
3420
|
+
}, [columns, draft, editing, isCellEditable, onCellChange, rows]);
|
|
3091
3421
|
const renderEditor = () => {
|
|
3092
3422
|
if (!editing || !editorStyle) return null;
|
|
3093
3423
|
const column = columns[editing.columnIndex];
|
|
@@ -3285,19 +3615,14 @@ function Table({
|
|
|
3285
3615
|
setResizeGuideTop(0);
|
|
3286
3616
|
}, []);
|
|
3287
3617
|
const queueSortStateChange = useCallback2((next) => {
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
sortDebounceRef.current = setTimeout(() => {
|
|
3291
|
-
sortDebounceRef.current = null;
|
|
3292
|
-
onSortStateChange?.(next);
|
|
3293
|
-
}, 200);
|
|
3294
|
-
}, [onSortStateChange]);
|
|
3618
|
+
setSortState(next);
|
|
3619
|
+
}, []);
|
|
3295
3620
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3296
3621
|
const column = columns[columnIndex];
|
|
3297
3622
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3298
3623
|
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
3299
3624
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3300
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3625
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
3301
3626
|
const icons = [];
|
|
3302
3627
|
if (visibleActions.drag) {
|
|
3303
3628
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
@@ -3307,11 +3632,11 @@ function Table({
|
|
|
3307
3632
|
}
|
|
3308
3633
|
if (visibleActions.sort) {
|
|
3309
3634
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3310
|
-
const direction =
|
|
3635
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3311
3636
|
icons.push(
|
|
3312
3637
|
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - 16, top }, direction }, "sort")
|
|
3313
3638
|
);
|
|
3314
|
-
right -=
|
|
3639
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
3315
3640
|
}
|
|
3316
3641
|
if (visibleActions.filter) {
|
|
3317
3642
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
@@ -3338,7 +3663,7 @@ function Table({
|
|
|
3338
3663
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3339
3664
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3340
3665
|
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3341
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3666
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3342
3667
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3343
3668
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3344
3669
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3357,7 +3682,7 @@ function Table({
|
|
|
3357
3682
|
anchorLeft = anchorX;
|
|
3358
3683
|
label = labels.dragColumn;
|
|
3359
3684
|
} else if (action === "sort") {
|
|
3360
|
-
const direction =
|
|
3685
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3361
3686
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3362
3687
|
anchorX = cellLeft + cellWidth - 22;
|
|
3363
3688
|
anchorLeft = anchorX;
|
|
@@ -3377,7 +3702,7 @@ function Table({
|
|
|
3377
3702
|
label,
|
|
3378
3703
|
placement
|
|
3379
3704
|
};
|
|
3380
|
-
}, [baseHeaderHeight, columnDraggable, columns,
|
|
3705
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3381
3706
|
const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
|
|
3382
3707
|
const canvas = canvasRef.current;
|
|
3383
3708
|
if (!canvas) return false;
|
|
@@ -3392,7 +3717,7 @@ function Table({
|
|
|
3392
3717
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3393
3718
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3394
3719
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3395
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3720
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3396
3721
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3397
3722
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3398
3723
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
@@ -3632,7 +3957,9 @@ function Table({
|
|
|
3632
3957
|
});
|
|
3633
3958
|
setPendingInserts((current) => [...current, pending]);
|
|
3634
3959
|
try {
|
|
3635
|
-
|
|
3960
|
+
const nextRows = sourceRows.slice();
|
|
3961
|
+
nextRows.splice(insertIndex, 0, ...insertedRows);
|
|
3962
|
+
await Promise.resolve(onInsertRows(nextRows, insertedRows));
|
|
3636
3963
|
await waitForPaint();
|
|
3637
3964
|
setInsertBusy(false);
|
|
3638
3965
|
} catch (error) {
|
|
@@ -3659,28 +3986,10 @@ function Table({
|
|
|
3659
3986
|
const currentScrollTop = scrollRef.current.top;
|
|
3660
3987
|
const top = (fixedHeader ? 0 : bodyTop) + rowIndex * rowHeight - currentScrollTop;
|
|
3661
3988
|
if (column.rowSelection) {
|
|
3662
|
-
|
|
3663
|
-
return /* @__PURE__ */ jsx7(
|
|
3664
|
-
"div",
|
|
3665
|
-
{
|
|
3666
|
-
className: "rvg-row-selection-icon",
|
|
3667
|
-
style: { left, top, width: cellWidth, height: cellHeight, opacity: isDraggedSource ? 0 : 1, transform: `translateY(${dragOffset}px)` },
|
|
3668
|
-
children: /* @__PURE__ */ jsx7(SelectionIcon, { checked: selectedRowKeySet.has(rowKey2), radio: rowSelectionMode === "single" })
|
|
3669
|
-
},
|
|
3670
|
-
`selection:${String(rowKey2)}`
|
|
3671
|
-
);
|
|
3989
|
+
return null;
|
|
3672
3990
|
}
|
|
3673
3991
|
if (column.rowDragHandle) {
|
|
3674
|
-
return
|
|
3675
|
-
"div",
|
|
3676
|
-
{
|
|
3677
|
-
className: "rvg-row-drag-icon",
|
|
3678
|
-
style: { left, top, width: cellWidth, height: cellHeight, opacity: isDraggedSource ? 0 : 1, transform: `translateY(${dragOffset}px)` },
|
|
3679
|
-
"aria-hidden": "true",
|
|
3680
|
-
children: /* @__PURE__ */ jsx7(RowDragHandleIcon, {})
|
|
3681
|
-
},
|
|
3682
|
-
`drag:${String(getRowKey(rows[rowIndex], rowIndex))}`
|
|
3683
|
-
);
|
|
3992
|
+
return null;
|
|
3684
3993
|
}
|
|
3685
3994
|
if (column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
3686
3995
|
const row = rows[rowIndex];
|
|
@@ -3707,6 +4016,7 @@ function Table({
|
|
|
3707
4016
|
};
|
|
3708
4017
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
3709
4018
|
const column = columns[columnIndex];
|
|
4019
|
+
const isDropTarget = Boolean(columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex);
|
|
3710
4020
|
const currentScrollTop = scrollRef.current.top;
|
|
3711
4021
|
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3712
4022
|
const leafTop = headerTop + headerLeafTop;
|
|
@@ -3714,7 +4024,7 @@ function Table({
|
|
|
3714
4024
|
return /* @__PURE__ */ jsx7(
|
|
3715
4025
|
"div",
|
|
3716
4026
|
{
|
|
3717
|
-
className:
|
|
4027
|
+
className: `rvg-header-title${isDropTarget ? " is-drop-target" : ""}`,
|
|
3718
4028
|
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
3719
4029
|
children: /* @__PURE__ */ jsx7("span", { children: column.title })
|
|
3720
4030
|
},
|
|
@@ -3737,11 +4047,11 @@ function Table({
|
|
|
3737
4047
|
}
|
|
3738
4048
|
if (column.renderHeader) {
|
|
3739
4049
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3740
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4050
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
3741
4051
|
return /* @__PURE__ */ jsx7(
|
|
3742
4052
|
"div",
|
|
3743
4053
|
{
|
|
3744
|
-
className:
|
|
4054
|
+
className: `rvg-header-title is-custom${isDropTarget ? " is-drop-target" : ""}`,
|
|
3745
4055
|
"data-level": headerDepth - 1,
|
|
3746
4056
|
"data-measure-key": column.key,
|
|
3747
4057
|
style: {
|
|
@@ -3782,11 +4092,12 @@ function Table({
|
|
|
3782
4092
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3783
4093
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3784
4094
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
3785
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4095
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable && !cell.leaf ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
4096
|
+
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
3786
4097
|
return /* @__PURE__ */ jsxs7(
|
|
3787
4098
|
"div",
|
|
3788
4099
|
{
|
|
3789
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}`,
|
|
4100
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
3790
4101
|
"data-level": cell.level,
|
|
3791
4102
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3792
4103
|
style: {
|
|
@@ -3842,6 +4153,7 @@ function Table({
|
|
|
3842
4153
|
})();
|
|
3843
4154
|
const selectionOutlineStyle = (() => {
|
|
3844
4155
|
if (!selection || selectionRange) return null;
|
|
4156
|
+
if (rowDragPreview?.sourceIndex === selection.rowIndex) return null;
|
|
3845
4157
|
const row = rows[selection.rowIndex];
|
|
3846
4158
|
const metric = metrics[selection.columnIndex];
|
|
3847
4159
|
const column = columns[selection.columnIndex];
|
|
@@ -3851,10 +4163,11 @@ function Table({
|
|
|
3851
4163
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
3852
4164
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - scrollPosition.top;
|
|
3853
4165
|
const rawBottom = rawTop + rowHeight * (span?.rowSpan ?? 1);
|
|
4166
|
+
const dragOffset = getRowDragOffset(selection.rowIndex);
|
|
3854
4167
|
const horizontalStart = column.fixed === void 0 ? fixedWidth : 0;
|
|
3855
4168
|
const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
3856
4169
|
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
3857
|
-
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom <= verticalStart || rawTop >= renderHeight) return null;
|
|
4170
|
+
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom + dragOffset <= verticalStart || rawTop + dragOffset >= renderHeight) return null;
|
|
3858
4171
|
const borderWidth = 2;
|
|
3859
4172
|
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
|
|
3860
4173
|
const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
|
|
@@ -3864,7 +4177,8 @@ function Table({
|
|
|
3864
4177
|
left,
|
|
3865
4178
|
top,
|
|
3866
4179
|
width: Math.max(0, right - left),
|
|
3867
|
-
height: Math.max(0, bottom - top)
|
|
4180
|
+
height: Math.max(0, bottom - top),
|
|
4181
|
+
transform: `translateY(${dragOffset}px)`
|
|
3868
4182
|
};
|
|
3869
4183
|
})();
|
|
3870
4184
|
const selectionEdgeIndicator = getSelectionEdgeIndicator(scrollPosition.left, scrollPosition.top);
|
|
@@ -4005,6 +4319,77 @@ function Table({
|
|
|
4005
4319
|
`summary:${column.key}`
|
|
4006
4320
|
);
|
|
4007
4321
|
};
|
|
4322
|
+
useImperativeHandle(ref, () => {
|
|
4323
|
+
const resolveDataCell = (target) => {
|
|
4324
|
+
const cell = resolveSelectionTarget(target);
|
|
4325
|
+
if (!cell) return null;
|
|
4326
|
+
const column = columns[cell.columnIndex];
|
|
4327
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return null;
|
|
4328
|
+
const span = getCellSpan(cell.rowIndex, cell.columnIndex);
|
|
4329
|
+
if (!span) return cell;
|
|
4330
|
+
return {
|
|
4331
|
+
rowIndex: span.rowIndex,
|
|
4332
|
+
columnIndex: span.columnIndex,
|
|
4333
|
+
rowKey: getRowKey(rows[span.rowIndex], span.rowIndex),
|
|
4334
|
+
columnKey: columns[span.columnIndex].key
|
|
4335
|
+
};
|
|
4336
|
+
};
|
|
4337
|
+
return {
|
|
4338
|
+
focus: () => scrollerRef.current?.focus({ preventScroll: true }),
|
|
4339
|
+
scrollToCell: (target) => {
|
|
4340
|
+
const cell = resolveDataCell(target);
|
|
4341
|
+
if (!cell) return false;
|
|
4342
|
+
revealCell(cell);
|
|
4343
|
+
return true;
|
|
4344
|
+
},
|
|
4345
|
+
getSelectedCell: () => {
|
|
4346
|
+
if (!selection) return null;
|
|
4347
|
+
const cell = resolveDataCell(selection);
|
|
4348
|
+
if (!cell) return null;
|
|
4349
|
+
const column = columns[cell.columnIndex];
|
|
4350
|
+
const row = rows[cell.rowIndex];
|
|
4351
|
+
return { ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] };
|
|
4352
|
+
},
|
|
4353
|
+
setSelectedCell: (target) => {
|
|
4354
|
+
const cell = target === null ? null : resolveDataCell(target);
|
|
4355
|
+
if (target !== null && !cell) return false;
|
|
4356
|
+
setSelectionRange(null);
|
|
4357
|
+
setSelection(cell);
|
|
4358
|
+
return true;
|
|
4359
|
+
},
|
|
4360
|
+
getSelectedRowKeys: () => [...rowKeys],
|
|
4361
|
+
getSelectedRows: () => rows.filter((row, index) => selectedRowKeySet.has(getRowKey(row, index))),
|
|
4362
|
+
setSelectedRowKeys: (keys) => {
|
|
4363
|
+
if (!rowSelection) return;
|
|
4364
|
+
const next = [...new Set(keys)];
|
|
4365
|
+
setRowKeys(rowSelectionMode === "single" ? next.slice(0, 1) : next);
|
|
4366
|
+
},
|
|
4367
|
+
getSelectedColumnKeys: () => [...columnKeys],
|
|
4368
|
+
setSelectedColumnKeys: (keys) => {
|
|
4369
|
+
if (!columnSelection) return;
|
|
4370
|
+
const next = [...new Set(keys)].filter((key) => columns.some((column) => column.key === key && !column.rowNumber && !column.rowSelection && !column.rowDragHandle));
|
|
4371
|
+
setColumnKeys(typeof columnSelection === "object" && columnSelection.mode === "single" ? next.slice(0, 1) : next);
|
|
4372
|
+
},
|
|
4373
|
+
clearSelection: () => {
|
|
4374
|
+
setSelectionRange(null);
|
|
4375
|
+
setSelection(null);
|
|
4376
|
+
setRowKeys([]);
|
|
4377
|
+
setColumnKeys([]);
|
|
4378
|
+
rowAnchorRef.current = null;
|
|
4379
|
+
setEditing(null);
|
|
4380
|
+
},
|
|
4381
|
+
startEdit: (target) => {
|
|
4382
|
+
const cell = target ? resolveDataCell(target) : selection ? resolveDataCell(selection) : null;
|
|
4383
|
+
if (!cell || !isCellEditable(cell)) return false;
|
|
4384
|
+
setSelectionRange(null);
|
|
4385
|
+
setSelection(cell);
|
|
4386
|
+
beginEdit(cell);
|
|
4387
|
+
return true;
|
|
4388
|
+
},
|
|
4389
|
+
commitEdit: () => commitEdit(),
|
|
4390
|
+
cancelEdit: () => setEditing(null)
|
|
4391
|
+
};
|
|
4392
|
+
});
|
|
4008
4393
|
const rootStyle = {
|
|
4009
4394
|
width,
|
|
4010
4395
|
height: autoHeight ? effectiveHeight : height,
|
|
@@ -4023,6 +4408,10 @@ function Table({
|
|
|
4023
4408
|
className: "rvg-canvas",
|
|
4024
4409
|
style: { width: viewport.width, height: renderHeight },
|
|
4025
4410
|
onMouseMove: (event) => {
|
|
4411
|
+
if (document.documentElement.classList.contains("rvg-is-dragging")) {
|
|
4412
|
+
hideDragTooltips();
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4026
4415
|
if (columnDragRef.current) return;
|
|
4027
4416
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
4028
4417
|
const localY = event.clientY - rect.top;
|
|
@@ -4125,6 +4514,14 @@ function Table({
|
|
|
4125
4514
|
}
|
|
4126
4515
|
},
|
|
4127
4516
|
onPointerDown: (event) => {
|
|
4517
|
+
const headerDragCell = columnDraggable ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
4518
|
+
const columnIndex = locateColumn(event.clientX);
|
|
4519
|
+
const rowDragHandle = rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(event.clientY) >= 0;
|
|
4520
|
+
if (headerDragCell && locateHeaderCellDragHandle(event.clientX, headerDragCell) || rowDragHandle) {
|
|
4521
|
+
hideDragTooltips();
|
|
4522
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
4523
|
+
event.currentTarget.style.cursor = "move";
|
|
4524
|
+
}
|
|
4128
4525
|
handleColumnPointerDown(event);
|
|
4129
4526
|
beginRangeDrag(event);
|
|
4130
4527
|
},
|
|
@@ -4133,10 +4530,12 @@ function Table({
|
|
|
4133
4530
|
updateRangeDrag(event);
|
|
4134
4531
|
},
|
|
4135
4532
|
onPointerUp: (event) => {
|
|
4533
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4136
4534
|
handleColumnPointerUp(event);
|
|
4137
4535
|
endRangeDrag(event);
|
|
4138
4536
|
},
|
|
4139
4537
|
onPointerCancel: (event) => {
|
|
4538
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4140
4539
|
handleColumnPointerUp(event);
|
|
4141
4540
|
endRangeDrag(event);
|
|
4142
4541
|
},
|
|
@@ -4155,7 +4554,7 @@ function Table({
|
|
|
4155
4554
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
4156
4555
|
if (action === "sort") {
|
|
4157
4556
|
const columnKey = columns[columnIndex].key;
|
|
4158
|
-
const next =
|
|
4557
|
+
const next = sortState?.columnKey !== columnKey ? { columnKey, direction: "asc" } : sortState.direction === "asc" ? { columnKey, direction: "desc" } : null;
|
|
4159
4558
|
queueSortStateChange(next);
|
|
4160
4559
|
return;
|
|
4161
4560
|
}
|
|
@@ -4189,6 +4588,10 @@ function Table({
|
|
|
4189
4588
|
}
|
|
4190
4589
|
if (event.detail > 1) return;
|
|
4191
4590
|
clickedCellRef.current = cell;
|
|
4591
|
+
const column = columns[cell.columnIndex];
|
|
4592
|
+
const row = rows[cell.rowIndex];
|
|
4593
|
+
onCellClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4594
|
+
if (event.defaultPrevented) return;
|
|
4192
4595
|
setSelectionRange(null);
|
|
4193
4596
|
scrollerRef.current?.focus({ preventScroll: true });
|
|
4194
4597
|
setSelection(cell);
|
|
@@ -4199,7 +4602,12 @@ function Table({
|
|
|
4199
4602
|
},
|
|
4200
4603
|
onDoubleClick: (event) => {
|
|
4201
4604
|
const cell = clickedCellRef.current ?? locateCell(event.clientX, event.clientY);
|
|
4202
|
-
if (cell)
|
|
4605
|
+
if (!cell) return;
|
|
4606
|
+
const column = columns[cell.columnIndex];
|
|
4607
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return;
|
|
4608
|
+
const row = rows[cell.rowIndex];
|
|
4609
|
+
onCellDoubleClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4610
|
+
if (!event.defaultPrevented) beginEdit(cell);
|
|
4203
4611
|
},
|
|
4204
4612
|
onContextMenu: handleContextMenu
|
|
4205
4613
|
}
|
|
@@ -4212,7 +4620,7 @@ function Table({
|
|
|
4212
4620
|
className: "rvg-text-scroll-content",
|
|
4213
4621
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
4214
4622
|
children: [
|
|
4215
|
-
columns.map((column, columnIndex) => column.fixed || columnIndex
|
|
4623
|
+
columns.map((column, columnIndex) => column.fixed || columnIndex >= utilityColumnCount && headerDepth > 1 ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ jsx7("span", { children: renderHeaderTitle(columnIndex, getScrollableColumnLeft(columnIndex)) }, column.key) : null),
|
|
4216
4624
|
headerCells.map((cell) => {
|
|
4217
4625
|
if (columns[cell.startIndex]?.fixed) return null;
|
|
4218
4626
|
if (cell.endIndex < domRange.columnStart || cell.startIndex >= domRange.columnEnd) return null;
|
|
@@ -4230,7 +4638,7 @@ function Table({
|
|
|
4230
4638
|
const left = column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width;
|
|
4231
4639
|
return renderCellText(rowIndex, columnIndex, left);
|
|
4232
4640
|
})) }),
|
|
4233
|
-
columns.map((column, columnIndex) => columnIndex < utilityColumnCount || headerDepth === 1
|
|
4641
|
+
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),
|
|
4234
4642
|
headerCells.map((cell) => columns[cell.startIndex]?.fixed ? renderGroupedHeaderCell(cell) : null),
|
|
4235
4643
|
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
4236
4644
|
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-shadow is-right", style: { right: rightFixedWidth } }),
|
|
@@ -4447,7 +4855,7 @@ function Table({
|
|
|
4447
4855
|
const affectedRows = selectedIndices.includes(cell.rowIndex) ? selectedIndices : [cell.rowIndex];
|
|
4448
4856
|
const cellContext = { ...cell, row, column, value: dataIndex === void 0 ? void 0 : row[dataIndex] };
|
|
4449
4857
|
return renderConfiguredContextMenu(resolveContextMenuSection(customContextMenuConfig?.cell, DEFAULT_CELL_CONTEXT_MENU), cellContext, (item, override) => {
|
|
4450
|
-
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !
|
|
4858
|
+
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !isCellEditable(cell), icon: /* @__PURE__ */ jsx7(ContextMenuIcon, { type: "edit" }) });
|
|
4451
4859
|
if (item === "copy") return renderContextMenuButton("cell-copy", cellContext, labels.copyContent, async () => {
|
|
4452
4860
|
try {
|
|
4453
4861
|
await navigator.clipboard.writeText(getCellLabel(cell.rowIndex, cell.columnIndex));
|
|
@@ -4505,12 +4913,12 @@ function Table({
|
|
|
4505
4913
|
/* @__PURE__ */ jsx7("span", { children: labels.rowUnit })
|
|
4506
4914
|
] });
|
|
4507
4915
|
if (item === "move-up") {
|
|
4508
|
-
if (!rowDraggable
|
|
4509
|
-
return renderContextMenuButton("cell-move-up", cellContext, labels.moveUp, () =>
|
|
4916
|
+
if (!rowDraggable) return null;
|
|
4917
|
+
return renderContextMenuButton("cell-move-up", cellContext, labels.moveUp, () => applyRowOrder(cell.rowIndex, cell.rowIndex - 1), override, { disabled: cell.rowIndex === 0, icon: /* @__PURE__ */ jsx7(ContextMenuIcon, { type: "move-up" }) });
|
|
4510
4918
|
}
|
|
4511
4919
|
if (item === "move-down") {
|
|
4512
|
-
if (!rowDraggable
|
|
4513
|
-
return renderContextMenuButton("cell-move-down", cellContext, labels.moveDown, () =>
|
|
4920
|
+
if (!rowDraggable) return null;
|
|
4921
|
+
return renderContextMenuButton("cell-move-down", cellContext, labels.moveDown, () => applyRowOrder(cell.rowIndex, cell.rowIndex + 1), override, { disabled: cell.rowIndex === rows.length - 1, icon: /* @__PURE__ */ jsx7(ContextMenuIcon, { type: "move-down" }) });
|
|
4514
4922
|
}
|
|
4515
4923
|
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__ */ jsx7(ContextMenuIcon, { type: "delete" }) });
|
|
4516
4924
|
return null;
|
|
@@ -4542,21 +4950,30 @@ function Table({
|
|
|
4542
4950
|
await Promise.resolve(onCellChange?.({ ...confirmAction.cell, row: confirmAction.row, previousValue: confirmAction.previousValue, value: "" }));
|
|
4543
4951
|
} else {
|
|
4544
4952
|
const deletingKeys = confirmAction.rows.map(({ row, rowIndex }) => getDataRowKey(row, rowIndex));
|
|
4953
|
+
const deletedRows = confirmAction.rows.map(({ row }) => row);
|
|
4954
|
+
const deletingKeySet = new Set(deletingKeys);
|
|
4955
|
+
const nextRows = sourceRows.filter((row, rowIndex) => !deletingKeySet.has(getDataRowKey(row, rowIndex)));
|
|
4545
4956
|
setConfirmAction(null);
|
|
4546
4957
|
setConfirmLoading(false);
|
|
4958
|
+
setPendingDeletedRowKeys((current) => {
|
|
4959
|
+
const next = new Set(current);
|
|
4960
|
+
deletingKeys.forEach((key) => next.add(key));
|
|
4961
|
+
return next;
|
|
4962
|
+
});
|
|
4547
4963
|
if (onDeleteRows) {
|
|
4548
4964
|
setDeleteBusy(true);
|
|
4549
4965
|
try {
|
|
4550
|
-
await Promise.resolve(onDeleteRows(
|
|
4966
|
+
await Promise.resolve(onDeleteRows(nextRows, deletedRows));
|
|
4967
|
+
} catch (error) {
|
|
4968
|
+
setPendingDeletedRowKeys((current) => {
|
|
4969
|
+
const next = new Set(current);
|
|
4970
|
+
deletingKeys.forEach((key) => next.delete(key));
|
|
4971
|
+
return next;
|
|
4972
|
+
});
|
|
4973
|
+
throw error;
|
|
4551
4974
|
} finally {
|
|
4552
4975
|
setDeleteBusy(false);
|
|
4553
4976
|
}
|
|
4554
|
-
} else {
|
|
4555
|
-
setPendingDeletedRowKeys((current) => {
|
|
4556
|
-
const next = new Set(current);
|
|
4557
|
-
deletingKeys.forEach((key) => next.add(key));
|
|
4558
|
-
return next;
|
|
4559
|
-
});
|
|
4560
4977
|
}
|
|
4561
4978
|
return;
|
|
4562
4979
|
}
|
|
@@ -4629,7 +5046,7 @@ function Table({
|
|
|
4629
5046
|
const next = { ...filterValues };
|
|
4630
5047
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4631
5048
|
else delete next[key];
|
|
4632
|
-
|
|
5049
|
+
setFilterValues(next);
|
|
4633
5050
|
setFilterEditor(null);
|
|
4634
5051
|
}
|
|
4635
5052
|
}
|
|
@@ -4640,7 +5057,7 @@ function Table({
|
|
|
4640
5057
|
const key = columns[filterEditor.columnIndex].key;
|
|
4641
5058
|
const next = { ...filterValues };
|
|
4642
5059
|
delete next[key];
|
|
4643
|
-
|
|
5060
|
+
setFilterValues(next);
|
|
4644
5061
|
setFilterEditor(null);
|
|
4645
5062
|
}, children: labels.reset }),
|
|
4646
5063
|
/* @__PURE__ */ jsx7("button", { type: "button", className: "rvg-filter-confirm", onClick: () => {
|
|
@@ -4648,7 +5065,7 @@ function Table({
|
|
|
4648
5065
|
const next = { ...filterValues };
|
|
4649
5066
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4650
5067
|
else delete next[key];
|
|
4651
|
-
|
|
5068
|
+
setFilterValues(next);
|
|
4652
5069
|
setFilterEditor(null);
|
|
4653
5070
|
}, children: labels.confirm })
|
|
4654
5071
|
] })
|
|
@@ -4678,6 +5095,7 @@ function Table({
|
|
|
4678
5095
|
loading && !hasCustomLoading && hasCompletedLoadRef.current && /* @__PURE__ */ jsx7("div", { className: "rvg-refresh-loading", "aria-label": labels.refreshing, children: /* @__PURE__ */ jsx7(LoadingSpinnerIcon, {}) })
|
|
4679
5096
|
] });
|
|
4680
5097
|
}
|
|
5098
|
+
var Table = forwardRef(TableInner);
|
|
4681
5099
|
export {
|
|
4682
5100
|
Table,
|
|
4683
5101
|
Table as VelocityGrid,
|