@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.js
CHANGED
|
@@ -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;
|
|
@@ -1353,7 +1493,7 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1353
1493
|
return defaults;
|
|
1354
1494
|
}
|
|
1355
1495
|
function Table({
|
|
1356
|
-
columns:
|
|
1496
|
+
columns: columnProps,
|
|
1357
1497
|
rows: sourceRows,
|
|
1358
1498
|
rowKey,
|
|
1359
1499
|
width = "100%",
|
|
@@ -1382,23 +1522,21 @@ 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,
|
|
1403
1541
|
onCellContextMenu,
|
|
1404
1542
|
contextMenu: contextMenuConfig = true,
|
|
@@ -1407,6 +1545,10 @@ function Table({
|
|
|
1407
1545
|
style,
|
|
1408
1546
|
ariaLabel = "Data grid"
|
|
1409
1547
|
}) {
|
|
1548
|
+
const [sourceColumns, setSourceColumns] = useState4(columnProps);
|
|
1549
|
+
useEffect2(() => {
|
|
1550
|
+
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1551
|
+
}, [columnProps]);
|
|
1410
1552
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1411
1553
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1412
1554
|
const headerDepth = useMemo(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
@@ -1487,7 +1629,6 @@ function Table({
|
|
|
1487
1629
|
const frameRef = useRef2(null);
|
|
1488
1630
|
const textFrameRef = useRef2(null);
|
|
1489
1631
|
const toastTimerRef = useRef2(null);
|
|
1490
|
-
const sortDebounceRef = useRef2(null);
|
|
1491
1632
|
const headerTooltipTimerRef = useRef2(null);
|
|
1492
1633
|
const cellTooltipTimerRef = useRef2(null);
|
|
1493
1634
|
const pendingHeaderTooltipKeyRef = useRef2("");
|
|
@@ -1518,6 +1659,7 @@ function Table({
|
|
|
1518
1659
|
const suppressClickRef = useRef2(false);
|
|
1519
1660
|
const hasCompletedLoadRef = useRef2(!loading);
|
|
1520
1661
|
const columnDragPreviewRef = useRef2(null);
|
|
1662
|
+
const validColumnDropRef = useRef2(null);
|
|
1521
1663
|
const hoveredHeaderActionRef = useRef2(null);
|
|
1522
1664
|
const hoveredRowIndexRef = useRef2(null);
|
|
1523
1665
|
const [viewport, setViewport] = useState4({ width: 0, height: typeof height === "number" ? height : FALLBACK_HEIGHT });
|
|
@@ -1525,11 +1667,8 @@ function Table({
|
|
|
1525
1667
|
const resolvedHeight = typeof height === "number" ? height : viewport.height || FALLBACK_HEIGHT;
|
|
1526
1668
|
const [scrollPosition, setScrollPosition] = useState4({ left: 0, top: 0 });
|
|
1527
1669
|
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
1670
|
const [rowKeys, setRowKeys] = useControllableKeys(selectedRowKeys, defaultSelectedRowKeys, (keys) => {
|
|
1532
|
-
if (!
|
|
1671
|
+
if (!onSelectedRowChange) return;
|
|
1533
1672
|
const missing = new Set(keys.filter((key) => !rowByKeyRef.current.has(key)));
|
|
1534
1673
|
if (missing.size > 0) {
|
|
1535
1674
|
for (let index = 0; index < rows.length && missing.size > 0; index += 1) {
|
|
@@ -1546,12 +1685,13 @@ function Table({
|
|
|
1546
1685
|
const index = rowIndexByKeyRef.current.get(key);
|
|
1547
1686
|
return row && index !== void 0 ? [{ row, index }] : [];
|
|
1548
1687
|
});
|
|
1549
|
-
|
|
1688
|
+
onSelectedRowChange(keys, entries.map(({ row }) => row), entries.map(({ index }) => index));
|
|
1550
1689
|
});
|
|
1551
|
-
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys,
|
|
1690
|
+
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys, onSelectedColumnChange);
|
|
1552
1691
|
const [editing, setEditing] = useState4(null);
|
|
1553
1692
|
const [draft, setDraft] = useState4("");
|
|
1554
1693
|
const [rowDragPreview, setRowDragPreview] = useState4(null);
|
|
1694
|
+
const [columnDropTarget, setColumnDropTarget] = useState4(null);
|
|
1555
1695
|
useEffect2(() => {
|
|
1556
1696
|
if (!loading) hasCompletedLoadRef.current = true;
|
|
1557
1697
|
}, [loading]);
|
|
@@ -1620,6 +1760,8 @@ function Table({
|
|
|
1620
1760
|
return () => observer.disconnect();
|
|
1621
1761
|
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1622
1762
|
const [filterEditor, setFilterEditor] = useState4(null);
|
|
1763
|
+
const [filterValues, setFilterValues] = useState4({});
|
|
1764
|
+
const [sortState, setSortState] = useState4(null);
|
|
1623
1765
|
const [contextMenu, setContextMenu] = useState4(null);
|
|
1624
1766
|
const [insertCounts, setInsertCounts] = useState4({ before: 1, after: 1 });
|
|
1625
1767
|
const [confirmAction, setConfirmAction] = useState4(null);
|
|
@@ -1632,7 +1774,20 @@ function Table({
|
|
|
1632
1774
|
const [hoveredHeaderAction, setHoveredHeaderAction] = useState4(null);
|
|
1633
1775
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = useState4(null);
|
|
1634
1776
|
const [hoveredCellTooltip, setHoveredCellTooltip] = useState4(null);
|
|
1635
|
-
const
|
|
1777
|
+
const hideDragTooltips = useCallback2(() => {
|
|
1778
|
+
if (headerTooltipTimerRef.current !== null) {
|
|
1779
|
+
clearTimeout(headerTooltipTimerRef.current);
|
|
1780
|
+
headerTooltipTimerRef.current = null;
|
|
1781
|
+
}
|
|
1782
|
+
if (cellTooltipTimerRef.current !== null) {
|
|
1783
|
+
clearTimeout(cellTooltipTimerRef.current);
|
|
1784
|
+
cellTooltipTimerRef.current = null;
|
|
1785
|
+
}
|
|
1786
|
+
pendingHeaderTooltipKeyRef.current = "";
|
|
1787
|
+
pendingCellTooltipKeyRef.current = "";
|
|
1788
|
+
setVisibleHeaderTooltip(null);
|
|
1789
|
+
setHoveredCellTooltip(null);
|
|
1790
|
+
}, []);
|
|
1636
1791
|
const [editedCellKeys, setEditedCellKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1637
1792
|
const [cellAnnotations, setCellAnnotations] = useState4(() => /* @__PURE__ */ new Map());
|
|
1638
1793
|
const [annotationType, setAnnotationType] = useState4("corner");
|
|
@@ -1644,6 +1799,7 @@ function Table({
|
|
|
1644
1799
|
const [pendingDeletedRowKeys, setPendingDeletedRowKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1645
1800
|
const [pendingInserts, setPendingInserts] = useState4(() => []);
|
|
1646
1801
|
const [insertedRowKeys, setInsertedRowKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1802
|
+
const [rowOrderKeys, setRowOrderKeys] = useState4(null);
|
|
1647
1803
|
const settledPendingInsertIdsRef = useRef2(/* @__PURE__ */ new Set());
|
|
1648
1804
|
const getDataRowKey = useCallback2((row, index) => {
|
|
1649
1805
|
return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
|
|
@@ -1658,7 +1814,7 @@ function Table({
|
|
|
1658
1814
|
}
|
|
1659
1815
|
return sourceRows.findIndex((sourceRow, index) => getDataRowKey(sourceRow, index) === key);
|
|
1660
1816
|
}, [getDataRowKey, sourceRows]);
|
|
1661
|
-
const
|
|
1817
|
+
const orderedRows = useMemo(() => {
|
|
1662
1818
|
let next = sourceRows;
|
|
1663
1819
|
if (pendingInserts.length > 0) {
|
|
1664
1820
|
const activeInserts = pendingInserts.filter((insert) => {
|
|
@@ -1677,9 +1833,91 @@ function Table({
|
|
|
1677
1833
|
insertedOffset += insert.rows.length;
|
|
1678
1834
|
});
|
|
1679
1835
|
}
|
|
1680
|
-
if (pendingDeletedRowKeys.size
|
|
1681
|
-
|
|
1682
|
-
|
|
1836
|
+
if (pendingDeletedRowKeys.size > 0) {
|
|
1837
|
+
next = next.filter((row, index) => !pendingDeletedRowKeys.has(getDataRowKey(row, index)));
|
|
1838
|
+
}
|
|
1839
|
+
if (!rowOrderKeys) return next;
|
|
1840
|
+
const rowsByKey = new Map(next.map((row, index) => [getDataRowKey(row, index), row]));
|
|
1841
|
+
const ordered = rowOrderKeys.flatMap((key) => {
|
|
1842
|
+
const row = rowsByKey.get(key);
|
|
1843
|
+
if (!row) return [];
|
|
1844
|
+
rowsByKey.delete(key);
|
|
1845
|
+
return [row];
|
|
1846
|
+
});
|
|
1847
|
+
next.forEach((row, index) => {
|
|
1848
|
+
const key = getDataRowKey(row, index);
|
|
1849
|
+
if (rowsByKey.has(key)) ordered.push(row);
|
|
1850
|
+
});
|
|
1851
|
+
return ordered;
|
|
1852
|
+
}, [getDataRowKey, pendingDeletedRowKeys, pendingInserts, rowOrderKeys, sourceRows]);
|
|
1853
|
+
const activeFilterValues = useMemo(() => Object.fromEntries(
|
|
1854
|
+
Object.entries(filterValues).filter(([, value]) => value.trim() !== "")
|
|
1855
|
+
), [filterValues]);
|
|
1856
|
+
const filteredRows = useMemo(() => {
|
|
1857
|
+
if (Object.keys(activeFilterValues).length === 0) return orderedRows;
|
|
1858
|
+
if (onFilterChange) return onFilterChange(orderedRows, activeFilterValues);
|
|
1859
|
+
return orderedRows.filter((row, rowIndex) => Object.entries(activeFilterValues).every(([columnKey, query]) => {
|
|
1860
|
+
const column = columns.find((candidate) => candidate.key === columnKey);
|
|
1861
|
+
if (!column) return true;
|
|
1862
|
+
return getDisplayLabel(column, row, rowIndex).toLocaleLowerCase().includes(query.trim().toLocaleLowerCase());
|
|
1863
|
+
}));
|
|
1864
|
+
}, [activeFilterValues, columns, onFilterChange, orderedRows]);
|
|
1865
|
+
const rows = useMemo(() => {
|
|
1866
|
+
if (!sortState) return filteredRows;
|
|
1867
|
+
if (onSortChange) return onSortChange(filteredRows, sortState);
|
|
1868
|
+
const column = columns.find((candidate) => candidate.key === sortState.columnKey);
|
|
1869
|
+
if (!column) return filteredRows;
|
|
1870
|
+
const direction = sortState.direction === "asc" ? 1 : -1;
|
|
1871
|
+
return filteredRows.slice().sort((left, right) => {
|
|
1872
|
+
const leftValue = column.dataIndex === void 0 ? void 0 : left[column.dataIndex];
|
|
1873
|
+
const rightValue = column.dataIndex === void 0 ? void 0 : right[column.dataIndex];
|
|
1874
|
+
const result = typeof leftValue === "number" && typeof rightValue === "number" ? leftValue - rightValue : getDisplayLabel(column, left, 0).localeCompare(getDisplayLabel(column, right, 0), language);
|
|
1875
|
+
return result * direction;
|
|
1876
|
+
});
|
|
1877
|
+
}, [columns, filteredRows, language, onSortChange, sortState]);
|
|
1878
|
+
const resolveSelectionTarget = useCallback2((target) => {
|
|
1879
|
+
if (target == null) return target;
|
|
1880
|
+
const columnIndex = columns.findIndex((column) => column.key === target.columnKey);
|
|
1881
|
+
const rowIndex = target.rowKey !== void 0 ? rows.findIndex((row2, index) => getDataRowKey(row2, index) === target.rowKey) : target.rowIndex ?? -1;
|
|
1882
|
+
const row = rows[rowIndex];
|
|
1883
|
+
if (columnIndex < 0 || !row) return null;
|
|
1884
|
+
return {
|
|
1885
|
+
rowIndex,
|
|
1886
|
+
columnIndex,
|
|
1887
|
+
rowKey: getDataRowKey(row, rowIndex),
|
|
1888
|
+
columnKey: target.columnKey
|
|
1889
|
+
};
|
|
1890
|
+
}, [columns, getDataRowKey, rows]);
|
|
1891
|
+
const resolvedSelectedCell = useMemo(() => resolveSelectionTarget(selectedCell), [resolveSelectionTarget, selectedCell]);
|
|
1892
|
+
const resolvedDefaultSelectedCell = useMemo(() => resolveSelectionTarget(defaultSelectedCell), [defaultSelectedCell, resolveSelectionTarget]);
|
|
1893
|
+
const handleSelectedCellChange = useCallback2((next) => {
|
|
1894
|
+
if (!onSelectedCellChange) return;
|
|
1895
|
+
if (!next) {
|
|
1896
|
+
onSelectedCellChange(null);
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
const row = rows[next.rowIndex];
|
|
1900
|
+
const column = columns[next.columnIndex];
|
|
1901
|
+
const value = row && column?.dataIndex !== void 0 ? row[column.dataIndex] : void 0;
|
|
1902
|
+
onSelectedCellChange({ ...next, value });
|
|
1903
|
+
}, [columns, onSelectedCellChange, rows]);
|
|
1904
|
+
const [selection, setSelection] = useControllableValue(resolvedSelectedCell, resolvedDefaultSelectedCell, handleSelectedCellChange);
|
|
1905
|
+
const [selectionRange, setSelectionRange] = useState4(null);
|
|
1906
|
+
const rangeDragRef = useRef2(null);
|
|
1907
|
+
const applyRowOrder = useCallback2((sourceIndex, targetIndex) => {
|
|
1908
|
+
if (sourceIndex === targetIndex || sourceIndex < 0 || targetIndex < 0 || sourceIndex >= rows.length || targetIndex >= rows.length) return;
|
|
1909
|
+
const nextEntries = rows.map((row, index) => ({ row, key: getDataRowKey(row, index) }));
|
|
1910
|
+
const [entry] = nextEntries.splice(sourceIndex, 1);
|
|
1911
|
+
nextEntries.splice(targetIndex, 0, entry);
|
|
1912
|
+
const nextRows = nextEntries.map(({ row }) => row);
|
|
1913
|
+
setRowOrderKeys(nextEntries.map(({ key }) => key));
|
|
1914
|
+
onRowsReorder?.(nextRows, { sourceIndex, targetIndex });
|
|
1915
|
+
}, [getDataRowKey, onRowsReorder, rows]);
|
|
1916
|
+
const applyColumnOrder = useCallback2((sourceIndex, targetIndex, detail) => {
|
|
1917
|
+
const nextColumns = reorderColumns(sourceColumns, detail);
|
|
1918
|
+
setSourceColumns(nextColumns);
|
|
1919
|
+
onColumnsReorder?.(nextColumns, { sourceIndex, targetIndex, ...detail });
|
|
1920
|
+
}, [onColumnsReorder, sourceColumns]);
|
|
1683
1921
|
useEffect2(() => {
|
|
1684
1922
|
if (insertBusy || settledPendingInsertIdsRef.current.size === 0) return;
|
|
1685
1923
|
setPendingInserts((current) => {
|
|
@@ -1921,19 +2159,22 @@ function Table({
|
|
|
1921
2159
|
grid: readThemeColor(themeStyles, "--rvg-color-grid", "#e3e6e8"),
|
|
1922
2160
|
text: readThemeColor(themeStyles, "--rvg-color-text", "#202124"),
|
|
1923
2161
|
muted: readThemeColor(themeStyles, "--rvg-color-muted", "#5f6368"),
|
|
2162
|
+
icon: readThemeColor(themeStyles, "--rvg-color-icon", "#9aa0a6"),
|
|
2163
|
+
borderStrong: readThemeColor(themeStyles, "--rvg-color-border-strong", "#b8bec4"),
|
|
1924
2164
|
selection: readThemeColor(themeStyles, "--rvg-color-primary", "#1677ff"),
|
|
1925
2165
|
selectionFill: readThemeColor(themeStyles, "--rvg-color-selection-fill", "#edf4ff"),
|
|
1926
2166
|
axisSelectionFill: readThemeColor(themeStyles, "--rvg-color-axis-selection-fill", "#e8f2ff"),
|
|
1927
2167
|
rowHoverFill: readThemeColor(themeStyles, "--rvg-color-row-hover-fill", "#f6f9fc"),
|
|
1928
2168
|
editedFill: editedCellHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-edited-fill", "#fff1b8"),
|
|
1929
2169
|
insertedFill: insertedRowHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-inserted-fill", "#c8ead4"),
|
|
2170
|
+
columnDropTargetFill: readThemeColor(themeStyles, "--rvg-color-column-drop-target-fill", "#eeeeee"),
|
|
1930
2171
|
stripe: stripedColor ?? readThemeColor(themeStyles, "--rvg-color-stripe", "#fafbfc")
|
|
1931
2172
|
};
|
|
1932
2173
|
const scroll = scrollRef.current;
|
|
1933
2174
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1934
2175
|
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]);
|
|
2176
|
+
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 });
|
|
2177
|
+
}, [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
2178
|
const scheduleDraw = useCallback2(() => {
|
|
1938
2179
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1939
2180
|
}, [draw]);
|
|
@@ -2115,11 +2356,7 @@ function Table({
|
|
|
2115
2356
|
}
|
|
2116
2357
|
};
|
|
2117
2358
|
}, [scheduleDraw]);
|
|
2118
|
-
useEffect2(() => {
|
|
2119
|
-
setDisplaySortState(sortState);
|
|
2120
|
-
}, [sortState]);
|
|
2121
2359
|
useEffect2(() => () => {
|
|
2122
|
-
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
2123
2360
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
2124
2361
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
2125
2362
|
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
@@ -2494,12 +2731,12 @@ function Table({
|
|
|
2494
2731
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2495
2732
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2496
2733
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2497
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2734
|
+
let right = columnRight - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
2498
2735
|
if (visibleActions.sort) {
|
|
2499
|
-
if (localX >= right -
|
|
2500
|
-
right -=
|
|
2736
|
+
if (localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "sort";
|
|
2737
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
2501
2738
|
}
|
|
2502
|
-
if (visibleActions.filter && localX >= right -
|
|
2739
|
+
if (visibleActions.filter && localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "filter";
|
|
2503
2740
|
return null;
|
|
2504
2741
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2505
2742
|
const isHeaderTitleTruncated = useCallback2((columnIndex) => {
|
|
@@ -2509,7 +2746,7 @@ function Table({
|
|
|
2509
2746
|
const metric = metrics[columnIndex];
|
|
2510
2747
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2511
2748
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2512
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
2749
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
2513
2750
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2514
2751
|
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2515
2752
|
const locateHeaderDragHandle = useCallback2((clientX, columnIndex) => {
|
|
@@ -2665,6 +2902,7 @@ function Table({
|
|
|
2665
2902
|
}
|
|
2666
2903
|
const sourceIndex = headerDragCell.startIndex;
|
|
2667
2904
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2905
|
+
validColumnDropRef.current = null;
|
|
2668
2906
|
return {
|
|
2669
2907
|
type: "table-column",
|
|
2670
2908
|
sourceIndex,
|
|
@@ -2675,13 +2913,26 @@ function Table({
|
|
|
2675
2913
|
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2676
2914
|
};
|
|
2677
2915
|
},
|
|
2678
|
-
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2916
|
+
onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
|
|
2679
2917
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2918
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
2919
|
+
const input = location.current.input;
|
|
2920
|
+
const previewOffset = source.data.type === "table-row" ? {
|
|
2921
|
+
x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
|
|
2922
|
+
y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
|
|
2923
|
+
} : {
|
|
2924
|
+
x: Math.max(0, Math.min(metrics[sourceIndex].width, input.clientX - canvasRect.left - getDisplayedColumnLeft(sourceIndex))),
|
|
2925
|
+
y: Math.max(0, Math.min(canvasRect.height, input.clientY - canvasRect.top))
|
|
2926
|
+
};
|
|
2680
2927
|
setCustomNativeDragPreview({
|
|
2681
2928
|
nativeSetDragImage,
|
|
2929
|
+
getOffset: () => previewOffset,
|
|
2682
2930
|
render: ({ container }) => {
|
|
2683
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
2684
2931
|
if (source.data.type === "table-row") {
|
|
2932
|
+
const frame = document.createElement("div");
|
|
2933
|
+
frame.className = "rvg-row-drag-preview-frame";
|
|
2934
|
+
frame.style.width = `${canvasRect.width + 4}px`;
|
|
2935
|
+
frame.style.height = `${rowHeight + 4}px`;
|
|
2685
2936
|
const preview2 = document.createElement("div");
|
|
2686
2937
|
preview2.className = "rvg-row-drag-preview";
|
|
2687
2938
|
preview2.style.width = `${canvasRect.width}px`;
|
|
@@ -2707,10 +2958,14 @@ function Table({
|
|
|
2707
2958
|
} else {
|
|
2708
2959
|
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
2709
2960
|
}
|
|
2961
|
+
if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
|
|
2962
|
+
cell.classList.add("is-selected");
|
|
2963
|
+
}
|
|
2710
2964
|
preview2.appendChild(cell);
|
|
2711
2965
|
});
|
|
2712
|
-
|
|
2713
|
-
|
|
2966
|
+
frame.appendChild(preview2);
|
|
2967
|
+
container.appendChild(frame);
|
|
2968
|
+
return () => frame.remove();
|
|
2714
2969
|
}
|
|
2715
2970
|
const preview = document.createElement("div");
|
|
2716
2971
|
preview.className = "rvg-column-drag-preview";
|
|
@@ -2724,6 +2979,29 @@ function Table({
|
|
|
2724
2979
|
header.style.height = `${headerHeight}px`;
|
|
2725
2980
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
2726
2981
|
header.textContent = column.title;
|
|
2982
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
2983
|
+
let actionRight = 2;
|
|
2984
|
+
if (visibleActions.drag) {
|
|
2985
|
+
const icon = createHeaderDragHandleSvg();
|
|
2986
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
2987
|
+
icon.style.right = `${actionRight}px`;
|
|
2988
|
+
header.appendChild(icon);
|
|
2989
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
2990
|
+
}
|
|
2991
|
+
if (visibleActions.sort) {
|
|
2992
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
2993
|
+
const icon = createHeaderSortSvg(direction);
|
|
2994
|
+
icon.classList.add("rvg-preview-header-icon");
|
|
2995
|
+
icon.style.right = `${actionRight}px`;
|
|
2996
|
+
header.appendChild(icon);
|
|
2997
|
+
actionRight += HEADER_ACTION_SLOT_WIDTH;
|
|
2998
|
+
}
|
|
2999
|
+
if (visibleActions.filter) {
|
|
3000
|
+
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3001
|
+
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3002
|
+
icon.style.right = `${actionRight}px`;
|
|
3003
|
+
header.appendChild(icon);
|
|
3004
|
+
}
|
|
2727
3005
|
preview.appendChild(header);
|
|
2728
3006
|
for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
|
|
2729
3007
|
const row = rows[rowIndex];
|
|
@@ -2752,6 +3030,8 @@ function Table({
|
|
|
2752
3030
|
},
|
|
2753
3031
|
onDragStart: ({ source }) => {
|
|
2754
3032
|
suppressClickRef.current = true;
|
|
3033
|
+
hideDragTooltips();
|
|
3034
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
2755
3035
|
canvas.style.cursor = "move";
|
|
2756
3036
|
if (source.data.type === "table-row") {
|
|
2757
3037
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2777,15 +3057,46 @@ function Table({
|
|
|
2777
3057
|
}
|
|
2778
3058
|
const targetIndex = Number(target?.targetIndex);
|
|
2779
3059
|
if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
|
|
3060
|
+
validColumnDropRef.current = null;
|
|
3061
|
+
setColumnDropTarget(null);
|
|
2780
3062
|
setDragGuide(null);
|
|
2781
3063
|
return;
|
|
2782
3064
|
}
|
|
2783
3065
|
const edge = target?.columnEdge;
|
|
2784
3066
|
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2785
3067
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
|
|
3068
|
+
if (destinationIndex === sourceIndex) {
|
|
3069
|
+
validColumnDropRef.current = null;
|
|
3070
|
+
setColumnDropTarget(null);
|
|
3071
|
+
setDragGuide(null);
|
|
3072
|
+
return;
|
|
3073
|
+
}
|
|
3074
|
+
validColumnDropRef.current = {
|
|
3075
|
+
sourceIndex,
|
|
3076
|
+
targetIndex: destinationIndex,
|
|
3077
|
+
rawTargetIndex: targetIndex,
|
|
3078
|
+
targetKey: String(target.targetKey),
|
|
3079
|
+
headerKind: source.data.headerKind === "group" ? "group" : "column",
|
|
3080
|
+
parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
|
|
3081
|
+
fixed: source.data.fixed === "left" || source.data.fixed === "right" ? source.data.fixed : void 0,
|
|
3082
|
+
columnEdge: edge === "right" ? "right" : "left"
|
|
3083
|
+
};
|
|
3084
|
+
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);
|
|
3085
|
+
const targetEndIndex = Number.isInteger(target?.targetEndIndex) ? Number(target.targetEndIndex) : targetIndex;
|
|
3086
|
+
const hoveredTargetCell = siblingCells.find((cell) => cell.startIndex === targetIndex && cell.endIndex === targetEndIndex);
|
|
3087
|
+
if (!hoveredTargetCell) {
|
|
3088
|
+
validColumnDropRef.current = null;
|
|
3089
|
+
setColumnDropTarget(null);
|
|
3090
|
+
setDragGuide(null);
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
const highlightedCell = edge === "right" ? hoveredTargetCell : siblingCells.filter((cell) => cell.endIndex < hoveredTargetCell.startIndex).sort((left, right) => right.endIndex - left.endIndex)[0] ?? hoveredTargetCell;
|
|
3094
|
+
setColumnDropTarget({ startIndex: highlightedCell.startIndex, endIndex: highlightedCell.endIndex });
|
|
2786
3095
|
const targetLeft = Number(target?.targetLeft);
|
|
2787
3096
|
const targetWidth = Number(target?.targetWidth);
|
|
2788
3097
|
if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
|
|
3098
|
+
validColumnDropRef.current = null;
|
|
3099
|
+
setColumnDropTarget(null);
|
|
2789
3100
|
setDragGuide(null);
|
|
2790
3101
|
return;
|
|
2791
3102
|
}
|
|
@@ -2793,18 +3104,19 @@ function Table({
|
|
|
2793
3104
|
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2794
3105
|
},
|
|
2795
3106
|
onDrop: ({ source, location }) => {
|
|
3107
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2796
3108
|
const target = location.current.dropTargets[0]?.data;
|
|
2797
3109
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2798
3110
|
if (source.data.type === "table-row") {
|
|
2799
|
-
const
|
|
2800
|
-
let
|
|
2801
|
-
if (sourceIndex <
|
|
2802
|
-
|
|
3111
|
+
const rawTargetIndex = Number(target?.targetIndex);
|
|
3112
|
+
let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
3113
|
+
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3114
|
+
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
2803
3115
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2804
3116
|
setRowDragPreview(null);
|
|
2805
3117
|
setRowDragGuide(null);
|
|
2806
3118
|
canvas.style.cursor = "default";
|
|
2807
|
-
if (Number.isInteger(
|
|
3119
|
+
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
2808
3120
|
requestAnimationFrame(() => {
|
|
2809
3121
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2810
3122
|
});
|
|
@@ -2813,21 +3125,22 @@ function Table({
|
|
|
2813
3125
|
}, 0);
|
|
2814
3126
|
return;
|
|
2815
3127
|
}
|
|
2816
|
-
const
|
|
2817
|
-
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
3128
|
+
const validDrop = validColumnDropRef.current;
|
|
2818
3129
|
canvas.style.cursor = "default";
|
|
2819
3130
|
setDragGuide(null);
|
|
3131
|
+
setColumnDropTarget(null);
|
|
2820
3132
|
columnDragPreviewRef.current = null;
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
3133
|
+
validColumnDropRef.current = null;
|
|
3134
|
+
if (validDrop) {
|
|
3135
|
+
applyColumnOrder(
|
|
3136
|
+
validDrop.sourceIndex - utilityColumnCount,
|
|
3137
|
+
validDrop.targetIndex - utilityColumnCount,
|
|
2825
3138
|
{
|
|
2826
|
-
type:
|
|
3139
|
+
type: validDrop.headerKind,
|
|
2827
3140
|
sourceKey: String(source.data.sourceKey),
|
|
2828
|
-
targetKey:
|
|
2829
|
-
parentKey:
|
|
2830
|
-
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex,
|
|
3141
|
+
targetKey: validDrop.targetKey,
|
|
3142
|
+
parentKey: validDrop.parentKey,
|
|
3143
|
+
placement: getColumnDropPlacement(validDrop.sourceIndex, validDrop.rawTargetIndex, validDrop.columnEdge)
|
|
2831
3144
|
}
|
|
2832
3145
|
);
|
|
2833
3146
|
}
|
|
@@ -2839,6 +3152,7 @@ function Table({
|
|
|
2839
3152
|
const cleanupDrop = dropTargetForElements({
|
|
2840
3153
|
element: canvas,
|
|
2841
3154
|
canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
|
|
3155
|
+
getDropEffect: () => "move",
|
|
2842
3156
|
getData: ({ input, element, source }) => {
|
|
2843
3157
|
if (source.data.type === "table-row") {
|
|
2844
3158
|
const targetIndex2 = locateRow(input.clientY);
|
|
@@ -2847,7 +3161,8 @@ function Table({
|
|
|
2847
3161
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2848
3162
|
return attachClosestEdge({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2849
3163
|
}
|
|
2850
|
-
const
|
|
3164
|
+
const hoveredColumnIndex = locateColumn(input.clientX);
|
|
3165
|
+
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
3166
|
if (!targetCell) return { targetIndex: -1 };
|
|
2852
3167
|
let targetIndex = targetCell.startIndex;
|
|
2853
3168
|
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
@@ -2864,6 +3179,7 @@ function Table({
|
|
|
2864
3179
|
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2865
3180
|
return attachClosestEdge({
|
|
2866
3181
|
targetIndex,
|
|
3182
|
+
targetEndIndex: targetCell.endIndex,
|
|
2867
3183
|
targetKey: targetCell.key,
|
|
2868
3184
|
parentKey: targetCell.parentKey,
|
|
2869
3185
|
headerKind,
|
|
@@ -2875,10 +3191,11 @@ function Table({
|
|
|
2875
3191
|
}
|
|
2876
3192
|
});
|
|
2877
3193
|
return () => {
|
|
3194
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2878
3195
|
cleanupDrag();
|
|
2879
3196
|
cleanupDrop();
|
|
2880
3197
|
};
|
|
2881
|
-
}, [bodyTop, columnDraggable, columns, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerHeight, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow,
|
|
3198
|
+
}, [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
3199
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
2883
3200
|
const canvas = canvasRef.current;
|
|
2884
3201
|
if (!canvas) return null;
|
|
@@ -3285,19 +3602,14 @@ function Table({
|
|
|
3285
3602
|
setResizeGuideTop(0);
|
|
3286
3603
|
}, []);
|
|
3287
3604
|
const queueSortStateChange = useCallback2((next) => {
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
sortDebounceRef.current = setTimeout(() => {
|
|
3291
|
-
sortDebounceRef.current = null;
|
|
3292
|
-
onSortStateChange?.(next);
|
|
3293
|
-
}, 200);
|
|
3294
|
-
}, [onSortStateChange]);
|
|
3605
|
+
setSortState(next);
|
|
3606
|
+
}, []);
|
|
3295
3607
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3296
3608
|
const column = columns[columnIndex];
|
|
3297
3609
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3298
3610
|
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
3299
3611
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3300
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3612
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
3301
3613
|
const icons = [];
|
|
3302
3614
|
if (visibleActions.drag) {
|
|
3303
3615
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
@@ -3307,11 +3619,11 @@ function Table({
|
|
|
3307
3619
|
}
|
|
3308
3620
|
if (visibleActions.sort) {
|
|
3309
3621
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3310
|
-
const direction =
|
|
3622
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3311
3623
|
icons.push(
|
|
3312
3624
|
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - 16, top }, direction }, "sort")
|
|
3313
3625
|
);
|
|
3314
|
-
right -=
|
|
3626
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
3315
3627
|
}
|
|
3316
3628
|
if (visibleActions.filter) {
|
|
3317
3629
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
@@ -3338,7 +3650,7 @@ function Table({
|
|
|
3338
3650
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3339
3651
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3340
3652
|
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3341
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3653
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3342
3654
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3343
3655
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3344
3656
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3357,7 +3669,7 @@ function Table({
|
|
|
3357
3669
|
anchorLeft = anchorX;
|
|
3358
3670
|
label = labels.dragColumn;
|
|
3359
3671
|
} else if (action === "sort") {
|
|
3360
|
-
const direction =
|
|
3672
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3361
3673
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3362
3674
|
anchorX = cellLeft + cellWidth - 22;
|
|
3363
3675
|
anchorLeft = anchorX;
|
|
@@ -3377,7 +3689,7 @@ function Table({
|
|
|
3377
3689
|
label,
|
|
3378
3690
|
placement
|
|
3379
3691
|
};
|
|
3380
|
-
}, [baseHeaderHeight, columnDraggable, columns,
|
|
3692
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3381
3693
|
const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
|
|
3382
3694
|
const canvas = canvasRef.current;
|
|
3383
3695
|
if (!canvas) return false;
|
|
@@ -3392,7 +3704,7 @@ function Table({
|
|
|
3392
3704
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3393
3705
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3394
3706
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3395
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3707
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
3396
3708
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3397
3709
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3398
3710
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
@@ -3632,7 +3944,9 @@ function Table({
|
|
|
3632
3944
|
});
|
|
3633
3945
|
setPendingInserts((current) => [...current, pending]);
|
|
3634
3946
|
try {
|
|
3635
|
-
|
|
3947
|
+
const nextRows = sourceRows.slice();
|
|
3948
|
+
nextRows.splice(insertIndex, 0, ...insertedRows);
|
|
3949
|
+
await Promise.resolve(onInsertRows(nextRows, insertedRows));
|
|
3636
3950
|
await waitForPaint();
|
|
3637
3951
|
setInsertBusy(false);
|
|
3638
3952
|
} catch (error) {
|
|
@@ -3659,28 +3973,10 @@ function Table({
|
|
|
3659
3973
|
const currentScrollTop = scrollRef.current.top;
|
|
3660
3974
|
const top = (fixedHeader ? 0 : bodyTop) + rowIndex * rowHeight - currentScrollTop;
|
|
3661
3975
|
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
|
-
);
|
|
3976
|
+
return null;
|
|
3672
3977
|
}
|
|
3673
3978
|
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
|
-
);
|
|
3979
|
+
return null;
|
|
3684
3980
|
}
|
|
3685
3981
|
if (column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
3686
3982
|
const row = rows[rowIndex];
|
|
@@ -3707,6 +4003,7 @@ function Table({
|
|
|
3707
4003
|
};
|
|
3708
4004
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
3709
4005
|
const column = columns[columnIndex];
|
|
4006
|
+
const isDropTarget = Boolean(columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex);
|
|
3710
4007
|
const currentScrollTop = scrollRef.current.top;
|
|
3711
4008
|
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3712
4009
|
const leafTop = headerTop + headerLeafTop;
|
|
@@ -3714,7 +4011,7 @@ function Table({
|
|
|
3714
4011
|
return /* @__PURE__ */ jsx7(
|
|
3715
4012
|
"div",
|
|
3716
4013
|
{
|
|
3717
|
-
className:
|
|
4014
|
+
className: `rvg-header-title${isDropTarget ? " is-drop-target" : ""}`,
|
|
3718
4015
|
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
3719
4016
|
children: /* @__PURE__ */ jsx7("span", { children: column.title })
|
|
3720
4017
|
},
|
|
@@ -3737,11 +4034,11 @@ function Table({
|
|
|
3737
4034
|
}
|
|
3738
4035
|
if (column.renderHeader) {
|
|
3739
4036
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3740
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4037
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH;
|
|
3741
4038
|
return /* @__PURE__ */ jsx7(
|
|
3742
4039
|
"div",
|
|
3743
4040
|
{
|
|
3744
|
-
className:
|
|
4041
|
+
className: `rvg-header-title is-custom${isDropTarget ? " is-drop-target" : ""}`,
|
|
3745
4042
|
"data-level": headerDepth - 1,
|
|
3746
4043
|
"data-measure-key": column.key,
|
|
3747
4044
|
style: {
|
|
@@ -3782,11 +4079,12 @@ function Table({
|
|
|
3782
4079
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3783
4080
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3784
4081
|
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)) *
|
|
4082
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * HEADER_ACTION_SLOT_WIDTH : columnDraggable && !cell.leaf ? HEADER_ACTION_SLOT_WIDTH : 0;
|
|
4083
|
+
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
3786
4084
|
return /* @__PURE__ */ jsxs7(
|
|
3787
4085
|
"div",
|
|
3788
4086
|
{
|
|
3789
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}`,
|
|
4087
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
3790
4088
|
"data-level": cell.level,
|
|
3791
4089
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3792
4090
|
style: {
|
|
@@ -3842,6 +4140,7 @@ function Table({
|
|
|
3842
4140
|
})();
|
|
3843
4141
|
const selectionOutlineStyle = (() => {
|
|
3844
4142
|
if (!selection || selectionRange) return null;
|
|
4143
|
+
if (rowDragPreview?.sourceIndex === selection.rowIndex) return null;
|
|
3845
4144
|
const row = rows[selection.rowIndex];
|
|
3846
4145
|
const metric = metrics[selection.columnIndex];
|
|
3847
4146
|
const column = columns[selection.columnIndex];
|
|
@@ -3851,10 +4150,11 @@ function Table({
|
|
|
3851
4150
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
3852
4151
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - scrollPosition.top;
|
|
3853
4152
|
const rawBottom = rawTop + rowHeight * (span?.rowSpan ?? 1);
|
|
4153
|
+
const dragOffset = getRowDragOffset(selection.rowIndex);
|
|
3854
4154
|
const horizontalStart = column.fixed === void 0 ? fixedWidth : 0;
|
|
3855
4155
|
const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
3856
4156
|
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
3857
|
-
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom <= verticalStart || rawTop >= renderHeight) return null;
|
|
4157
|
+
if (rawRight <= horizontalStart || rawLeft >= horizontalEnd || rawBottom + dragOffset <= verticalStart || rawTop + dragOffset >= renderHeight) return null;
|
|
3858
4158
|
const borderWidth = 2;
|
|
3859
4159
|
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
|
|
3860
4160
|
const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
|
|
@@ -3864,7 +4164,8 @@ function Table({
|
|
|
3864
4164
|
left,
|
|
3865
4165
|
top,
|
|
3866
4166
|
width: Math.max(0, right - left),
|
|
3867
|
-
height: Math.max(0, bottom - top)
|
|
4167
|
+
height: Math.max(0, bottom - top),
|
|
4168
|
+
transform: `translateY(${dragOffset}px)`
|
|
3868
4169
|
};
|
|
3869
4170
|
})();
|
|
3870
4171
|
const selectionEdgeIndicator = getSelectionEdgeIndicator(scrollPosition.left, scrollPosition.top);
|
|
@@ -4023,6 +4324,10 @@ function Table({
|
|
|
4023
4324
|
className: "rvg-canvas",
|
|
4024
4325
|
style: { width: viewport.width, height: renderHeight },
|
|
4025
4326
|
onMouseMove: (event) => {
|
|
4327
|
+
if (document.documentElement.classList.contains("rvg-is-dragging")) {
|
|
4328
|
+
hideDragTooltips();
|
|
4329
|
+
return;
|
|
4330
|
+
}
|
|
4026
4331
|
if (columnDragRef.current) return;
|
|
4027
4332
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
4028
4333
|
const localY = event.clientY - rect.top;
|
|
@@ -4125,6 +4430,14 @@ function Table({
|
|
|
4125
4430
|
}
|
|
4126
4431
|
},
|
|
4127
4432
|
onPointerDown: (event) => {
|
|
4433
|
+
const headerDragCell = columnDraggable ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
4434
|
+
const columnIndex = locateColumn(event.clientX);
|
|
4435
|
+
const rowDragHandle = rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(event.clientY) >= 0;
|
|
4436
|
+
if (headerDragCell && locateHeaderCellDragHandle(event.clientX, headerDragCell) || rowDragHandle) {
|
|
4437
|
+
hideDragTooltips();
|
|
4438
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
4439
|
+
event.currentTarget.style.cursor = "move";
|
|
4440
|
+
}
|
|
4128
4441
|
handleColumnPointerDown(event);
|
|
4129
4442
|
beginRangeDrag(event);
|
|
4130
4443
|
},
|
|
@@ -4133,10 +4446,12 @@ function Table({
|
|
|
4133
4446
|
updateRangeDrag(event);
|
|
4134
4447
|
},
|
|
4135
4448
|
onPointerUp: (event) => {
|
|
4449
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4136
4450
|
handleColumnPointerUp(event);
|
|
4137
4451
|
endRangeDrag(event);
|
|
4138
4452
|
},
|
|
4139
4453
|
onPointerCancel: (event) => {
|
|
4454
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
4140
4455
|
handleColumnPointerUp(event);
|
|
4141
4456
|
endRangeDrag(event);
|
|
4142
4457
|
},
|
|
@@ -4155,7 +4470,7 @@ function Table({
|
|
|
4155
4470
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
4156
4471
|
if (action === "sort") {
|
|
4157
4472
|
const columnKey = columns[columnIndex].key;
|
|
4158
|
-
const next =
|
|
4473
|
+
const next = sortState?.columnKey !== columnKey ? { columnKey, direction: "asc" } : sortState.direction === "asc" ? { columnKey, direction: "desc" } : null;
|
|
4159
4474
|
queueSortStateChange(next);
|
|
4160
4475
|
return;
|
|
4161
4476
|
}
|
|
@@ -4505,12 +4820,12 @@ function Table({
|
|
|
4505
4820
|
/* @__PURE__ */ jsx7("span", { children: labels.rowUnit })
|
|
4506
4821
|
] });
|
|
4507
4822
|
if (item === "move-up") {
|
|
4508
|
-
if (!rowDraggable
|
|
4509
|
-
return renderContextMenuButton("cell-move-up", cellContext, labels.moveUp, () =>
|
|
4823
|
+
if (!rowDraggable) return null;
|
|
4824
|
+
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
4825
|
}
|
|
4511
4826
|
if (item === "move-down") {
|
|
4512
|
-
if (!rowDraggable
|
|
4513
|
-
return renderContextMenuButton("cell-move-down", cellContext, labels.moveDown, () =>
|
|
4827
|
+
if (!rowDraggable) return null;
|
|
4828
|
+
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
4829
|
}
|
|
4515
4830
|
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
4831
|
return null;
|
|
@@ -4542,21 +4857,30 @@ function Table({
|
|
|
4542
4857
|
await Promise.resolve(onCellChange?.({ ...confirmAction.cell, row: confirmAction.row, previousValue: confirmAction.previousValue, value: "" }));
|
|
4543
4858
|
} else {
|
|
4544
4859
|
const deletingKeys = confirmAction.rows.map(({ row, rowIndex }) => getDataRowKey(row, rowIndex));
|
|
4860
|
+
const deletedRows = confirmAction.rows.map(({ row }) => row);
|
|
4861
|
+
const deletingKeySet = new Set(deletingKeys);
|
|
4862
|
+
const nextRows = sourceRows.filter((row, rowIndex) => !deletingKeySet.has(getDataRowKey(row, rowIndex)));
|
|
4545
4863
|
setConfirmAction(null);
|
|
4546
4864
|
setConfirmLoading(false);
|
|
4865
|
+
setPendingDeletedRowKeys((current) => {
|
|
4866
|
+
const next = new Set(current);
|
|
4867
|
+
deletingKeys.forEach((key) => next.add(key));
|
|
4868
|
+
return next;
|
|
4869
|
+
});
|
|
4547
4870
|
if (onDeleteRows) {
|
|
4548
4871
|
setDeleteBusy(true);
|
|
4549
4872
|
try {
|
|
4550
|
-
await Promise.resolve(onDeleteRows(
|
|
4873
|
+
await Promise.resolve(onDeleteRows(nextRows, deletedRows));
|
|
4874
|
+
} catch (error) {
|
|
4875
|
+
setPendingDeletedRowKeys((current) => {
|
|
4876
|
+
const next = new Set(current);
|
|
4877
|
+
deletingKeys.forEach((key) => next.delete(key));
|
|
4878
|
+
return next;
|
|
4879
|
+
});
|
|
4880
|
+
throw error;
|
|
4551
4881
|
} finally {
|
|
4552
4882
|
setDeleteBusy(false);
|
|
4553
4883
|
}
|
|
4554
|
-
} else {
|
|
4555
|
-
setPendingDeletedRowKeys((current) => {
|
|
4556
|
-
const next = new Set(current);
|
|
4557
|
-
deletingKeys.forEach((key) => next.add(key));
|
|
4558
|
-
return next;
|
|
4559
|
-
});
|
|
4560
4884
|
}
|
|
4561
4885
|
return;
|
|
4562
4886
|
}
|
|
@@ -4629,7 +4953,7 @@ function Table({
|
|
|
4629
4953
|
const next = { ...filterValues };
|
|
4630
4954
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4631
4955
|
else delete next[key];
|
|
4632
|
-
|
|
4956
|
+
setFilterValues(next);
|
|
4633
4957
|
setFilterEditor(null);
|
|
4634
4958
|
}
|
|
4635
4959
|
}
|
|
@@ -4640,7 +4964,7 @@ function Table({
|
|
|
4640
4964
|
const key = columns[filterEditor.columnIndex].key;
|
|
4641
4965
|
const next = { ...filterValues };
|
|
4642
4966
|
delete next[key];
|
|
4643
|
-
|
|
4967
|
+
setFilterValues(next);
|
|
4644
4968
|
setFilterEditor(null);
|
|
4645
4969
|
}, children: labels.reset }),
|
|
4646
4970
|
/* @__PURE__ */ jsx7("button", { type: "button", className: "rvg-filter-confirm", onClick: () => {
|
|
@@ -4648,7 +4972,7 @@ function Table({
|
|
|
4648
4972
|
const next = { ...filterValues };
|
|
4649
4973
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4650
4974
|
else delete next[key];
|
|
4651
|
-
|
|
4975
|
+
setFilterValues(next);
|
|
4652
4976
|
setFilterEditor(null);
|
|
4653
4977
|
}, children: labels.confirm })
|
|
4654
4978
|
] })
|