@lensui/lens-table 0.1.4 → 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 +764 -170
- package/dist/index.css +362 -31
- package/dist/index.d.cts +39 -33
- package/dist/index.d.ts +39 -33
- package/dist/index.js +764 -170
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ var ZH_CN_GRID_LABELS = {
|
|
|
27
27
|
sortDesc: "\u5F53\u524D\uFF1A\u964D\u5E8F",
|
|
28
28
|
sortBoth: "\u5347\u5E8F / \u964D\u5E8F",
|
|
29
29
|
dragColumn: "\u62D6\u52A8\u5217\u6392\u5E8F",
|
|
30
|
+
revealSelectedCell: "\u5B9A\u4F4D\u5230\u9009\u4E2D\u5355\u5143\u683C",
|
|
30
31
|
previousYear: "\u4E0A\u4E00\u5E74",
|
|
31
32
|
nextYear: "\u4E0B\u4E00\u5E74",
|
|
32
33
|
previousMonth: "\u4E0A\u4E2A\u6708",
|
|
@@ -95,6 +96,7 @@ var EN_US_GRID_LABELS = {
|
|
|
95
96
|
sortDesc: "Current: descending",
|
|
96
97
|
sortBoth: "Ascending / descending",
|
|
97
98
|
dragColumn: "Drag column to reorder",
|
|
99
|
+
revealSelectedCell: "Reveal selected cell",
|
|
98
100
|
previousYear: "Previous year",
|
|
99
101
|
nextYear: "Next year",
|
|
100
102
|
previousMonth: "Previous month",
|
|
@@ -286,16 +288,6 @@ function ContextMenuIcon({ type }) {
|
|
|
286
288
|
};
|
|
287
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)) });
|
|
288
290
|
}
|
|
289
|
-
function RowDragHandleIcon() {
|
|
290
|
-
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 16 16", focusable: "false", children: [
|
|
291
|
-
/* @__PURE__ */ jsx2("circle", { cx: "5", cy: "4", r: "1" }),
|
|
292
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "4", r: "1" }),
|
|
293
|
-
/* @__PURE__ */ jsx2("circle", { cx: "5", cy: "8", r: "1" }),
|
|
294
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "8", r: "1" }),
|
|
295
|
-
/* @__PURE__ */ jsx2("circle", { cx: "5", cy: "12", r: "1" }),
|
|
296
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "12", r: "1" })
|
|
297
|
-
] });
|
|
298
|
-
}
|
|
299
291
|
function LoadingSpinnerIcon() {
|
|
300
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" }) });
|
|
301
293
|
}
|
|
@@ -303,7 +295,6 @@ function LoadingSpinnerIcon() {
|
|
|
303
295
|
// src/components/editors/ChoiceEditor.tsx
|
|
304
296
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
305
297
|
function ChoiceEditor({ value, options, style, labels, onChange, onCommit, onCancel }) {
|
|
306
|
-
const editorStyle = typeof style.width === "number" ? { ...style, width: Math.max(0, style.width - 1) } : style;
|
|
307
298
|
const collection = createListCollection({
|
|
308
299
|
items: options,
|
|
309
300
|
itemToValue: (item) => item.value,
|
|
@@ -313,7 +304,7 @@ function ChoiceEditor({ value, options, style, labels, onChange, onCommit, onCan
|
|
|
313
304
|
Select.Root,
|
|
314
305
|
{
|
|
315
306
|
className: "rvg-choice-editor",
|
|
316
|
-
style
|
|
307
|
+
style,
|
|
317
308
|
collection,
|
|
318
309
|
value: value ? [value] : [],
|
|
319
310
|
defaultOpen: true,
|
|
@@ -724,6 +715,48 @@ function createRowDragHandleSvg() {
|
|
|
724
715
|
}
|
|
725
716
|
return svg;
|
|
726
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
|
+
}
|
|
727
760
|
|
|
728
761
|
// src/Table.tsx
|
|
729
762
|
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
@@ -744,6 +777,7 @@ function getDisplayLabel(column, row, rowIndex) {
|
|
|
744
777
|
|
|
745
778
|
// src/core/layout.ts
|
|
746
779
|
var DEFAULT_COLUMN_WIDTH = 140;
|
|
780
|
+
var HEADER_ACTION_SLOT_WIDTH = 16;
|
|
747
781
|
function isDataColumn(column) {
|
|
748
782
|
return !column.rowSelection && !column.rowDragHandle && !column.rowNumber;
|
|
749
783
|
}
|
|
@@ -758,7 +792,7 @@ function getHeaderTitleRequiredWidth(column, titleWidth) {
|
|
|
758
792
|
return minimumReadableTitleWidth + (column.align === "center" ? 20 : 22);
|
|
759
793
|
}
|
|
760
794
|
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26) {
|
|
761
|
-
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));
|
|
762
796
|
const candidates = [
|
|
763
797
|
isColumnFilterable(column) ? "filter" : null,
|
|
764
798
|
isColumnSortable(column) ? "sort" : null,
|
|
@@ -837,12 +871,15 @@ var COLORS = {
|
|
|
837
871
|
grid: "#e3e6e8",
|
|
838
872
|
text: "#202124",
|
|
839
873
|
muted: "#5f6368",
|
|
874
|
+
icon: "#9aa0a6",
|
|
875
|
+
borderStrong: "#b8bec4",
|
|
840
876
|
selection: "#1677ff",
|
|
841
877
|
selectionFill: "#edf4ff",
|
|
842
878
|
axisSelectionFill: "#e8f2ff",
|
|
843
879
|
rowHoverFill: "#f6f9fc",
|
|
844
880
|
editedFill: "#fff1b8",
|
|
845
881
|
insertedFill: "#c8ead4",
|
|
882
|
+
columnDropTargetFill: "#eeeeee",
|
|
846
883
|
stripe: "#fafbfc"
|
|
847
884
|
};
|
|
848
885
|
function ellipsizeText(context, text, maxWidth) {
|
|
@@ -862,7 +899,7 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
862
899
|
return `${text.slice(0, start)}${ellipsis}`;
|
|
863
900
|
}
|
|
864
901
|
function paintGrid(options) {
|
|
865
|
-
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;
|
|
866
903
|
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
867
904
|
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
868
905
|
const colors = { ...COLORS, ...options.colors };
|
|
@@ -884,6 +921,7 @@ function paintGrid(options) {
|
|
|
884
921
|
const leftFixedWidth = columns.reduce((value, column, index) => column.fixed === "left" ? value + metrics[index].width : value, 0);
|
|
885
922
|
const rightFixedWidth = columns.reduce((value, column, index) => column.fixed === "right" ? value + metrics[index].width : value, 0);
|
|
886
923
|
const rightFixedLeft = width - rightFixedWidth;
|
|
924
|
+
const rightFixedBoundaryInset = rightFixedWidth > 0 && !verticalBorderless ? 1 : 0;
|
|
887
925
|
const leftOffsets = /* @__PURE__ */ new Map();
|
|
888
926
|
let leftOffset = 0;
|
|
889
927
|
for (let index = 0; index < columns.length; index += 1) {
|
|
@@ -907,11 +945,19 @@ function paintGrid(options) {
|
|
|
907
945
|
const getColumnX = (index) => {
|
|
908
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;
|
|
909
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;
|
|
910
956
|
const paintBodyColumns = (layer) => {
|
|
911
957
|
const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
|
|
912
958
|
for (let rowIndex = rowStart; rowIndex < range.rowEnd; rowIndex += 1) {
|
|
913
959
|
if (rowDragPreview?.sourceIndex === rowIndex) continue;
|
|
914
|
-
const shift =
|
|
960
|
+
const shift = getRowDragOffset(rowIndex);
|
|
915
961
|
const y = bodyTop + rowIndex * rowHeight - scrollTop + shift;
|
|
916
962
|
const row = rows[rowIndex];
|
|
917
963
|
const rowKey = getRowKey(row, rowIndex);
|
|
@@ -944,6 +990,10 @@ function paintGrid(options) {
|
|
|
944
990
|
ctx.fillStyle = colors.rowHoverFill;
|
|
945
991
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
946
992
|
}
|
|
993
|
+
if (columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex) {
|
|
994
|
+
ctx.fillStyle = colors.columnDropTargetFill;
|
|
995
|
+
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
996
|
+
}
|
|
947
997
|
if (highlightInsertedRows && insertedRowKeys.has(rowKey)) {
|
|
948
998
|
ctx.fillStyle = colors.insertedFill;
|
|
949
999
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
@@ -970,6 +1020,7 @@ function paintGrid(options) {
|
|
|
970
1020
|
}
|
|
971
1021
|
ctx.fillStyle = colors.grid;
|
|
972
1022
|
if (!verticalBorderless) ctx.fillRect(x + cellWidth - 1, y, 1, cellHeight);
|
|
1023
|
+
if (rowIndex === rowBelowDragGap) ctx.fillRect(x, y, cellWidth, 1);
|
|
973
1024
|
if (!options.suppressLastRowBottomBorder || rowIndex !== rows.length - 1) {
|
|
974
1025
|
ctx.fillRect(x, y + cellHeight - 1, cellWidth, 1);
|
|
975
1026
|
}
|
|
@@ -996,6 +1047,59 @@ function paintGrid(options) {
|
|
|
996
1047
|
if (columnIndex === rangeColumnStart) ctx.fillRect(x, y, 2, cellHeight);
|
|
997
1048
|
if (columnIndex === rangeColumnEnd) ctx.fillRect(x + cellWidth - 2, y, 2, cellHeight);
|
|
998
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
|
+
}
|
|
999
1103
|
if (!column.rowDragHandle && !column.rowSelection && !column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
1000
1104
|
let label = "";
|
|
1001
1105
|
try {
|
|
@@ -1051,6 +1155,10 @@ function paintGrid(options) {
|
|
|
1051
1155
|
ctx.fillStyle = colors.selectionFill;
|
|
1052
1156
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1053
1157
|
}
|
|
1158
|
+
if (columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex) {
|
|
1159
|
+
ctx.fillStyle = colors.columnDropTargetFill;
|
|
1160
|
+
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1161
|
+
}
|
|
1054
1162
|
ctx.fillStyle = colors.grid;
|
|
1055
1163
|
if (!verticalBorderless) ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1056
1164
|
ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
@@ -1059,7 +1167,7 @@ function paintGrid(options) {
|
|
|
1059
1167
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1060
1168
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1061
1169
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
1062
|
-
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;
|
|
1063
1171
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1064
1172
|
const padding = 10;
|
|
1065
1173
|
const clipWidth = contentWidth;
|
|
@@ -1107,28 +1215,28 @@ function paintGrid(options) {
|
|
|
1107
1215
|
const markerBottom = Math.min(bottom, height);
|
|
1108
1216
|
const startX = getColumnX(columnStart);
|
|
1109
1217
|
const endX = getColumnX(columnEnd) + metrics[columnEnd].width;
|
|
1110
|
-
const visibleLeft = columns[columnStart].fixed === "left" ? Math.max(0, startX) : Math.max(leftFixedWidth
|
|
1218
|
+
const visibleLeft = columns[columnStart].fixed === "left" ? Math.max(0, startX) : Math.max(leftFixedWidth, startX);
|
|
1111
1219
|
const visibleRight = columns[columnEnd].fixed === "right" ? Math.min(width, endX) : Math.min(rightFixedLeft, endX);
|
|
1112
1220
|
ctx.fillStyle = colors.selection;
|
|
1113
1221
|
if (markerBottom > markerTop) {
|
|
1114
1222
|
if (columns[columnStart].fixed === void 0 && startX < leftFixedWidth) {
|
|
1115
|
-
ctx.fillRect(Math.max(0, leftFixedWidth
|
|
1223
|
+
ctx.fillRect(Math.max(0, leftFixedWidth), markerTop, 2, markerBottom - markerTop);
|
|
1116
1224
|
}
|
|
1117
1225
|
if (columns[columnEnd].fixed === void 0 && endX > rightFixedLeft) {
|
|
1118
|
-
ctx.fillRect(Math.max(0, rightFixedLeft -
|
|
1226
|
+
ctx.fillRect(Math.max(0, rightFixedLeft - 2 - rightFixedBoundaryInset), markerTop, 2, markerBottom - markerTop);
|
|
1119
1227
|
}
|
|
1120
1228
|
}
|
|
1121
1229
|
if (visibleRight > visibleLeft) {
|
|
1122
1230
|
if (top < clipTop) ctx.fillRect(visibleLeft, clipTop, visibleRight - visibleLeft, 2);
|
|
1123
1231
|
if (bottom > height) ctx.fillRect(visibleLeft, height - 2, visibleRight - visibleLeft, 2);
|
|
1124
1232
|
} else if (top < clipTop || bottom > height) {
|
|
1125
|
-
const markerX = endX <= leftFixedWidth ? Math.max(0, leftFixedWidth
|
|
1233
|
+
const markerX = endX <= leftFixedWidth ? Math.max(0, leftFixedWidth) : Math.max(0, rightFixedLeft - 2 - rightFixedBoundaryInset);
|
|
1126
1234
|
ctx.fillRect(markerX, top < clipTop ? clipTop : height - 2, 2, 2);
|
|
1127
1235
|
}
|
|
1128
1236
|
}
|
|
1129
1237
|
const selectedRow = selection ? rows[selection.rowIndex] : void 0;
|
|
1130
1238
|
const hasValidSelection = Boolean(selection && selectedRow && getRowKey(selectedRow, selection.rowIndex) === selection.rowKey);
|
|
1131
|
-
if (selection && hasValidSelection && !selectionRange) {
|
|
1239
|
+
if (selection && hasValidSelection && !selectionRange && !rowDragPreview) {
|
|
1132
1240
|
const metric = metrics[selection.columnIndex];
|
|
1133
1241
|
if (metric) {
|
|
1134
1242
|
const fixedSide = columns[selection.columnIndex].fixed;
|
|
@@ -1137,22 +1245,22 @@ function paintGrid(options) {
|
|
|
1137
1245
|
const selectionWidth = getCellWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
1138
1246
|
const selectionHeight = rowHeight * (span?.rowSpan ?? 1);
|
|
1139
1247
|
const x = Math.round(getColumnX(selection.columnIndex));
|
|
1140
|
-
const y = Math.round(bodyTop + selection.rowIndex * rowHeight - scrollTop);
|
|
1248
|
+
const y = Math.round(bodyTop + selection.rowIndex * rowHeight - scrollTop + getRowDragOffset(selection.rowIndex));
|
|
1141
1249
|
const borderWidth = 2;
|
|
1142
1250
|
const visibleLeft = fixedSide === "left" ? 0 : leftFixedWidth;
|
|
1143
1251
|
const selectionAreaRight = fixedSide === "right" ? width : width - rightFixedWidth;
|
|
1144
1252
|
const visibleRight = x + selectionWidth;
|
|
1145
1253
|
const visibleBottom = y + selectionHeight;
|
|
1146
1254
|
const selectionTop = fixedHeader ? bodyTop : 0;
|
|
1147
|
-
const selectionClipTop =
|
|
1255
|
+
const selectionClipTop = selectionTop;
|
|
1148
1256
|
const hiddenAboveHeader = visibleBottom <= selectionTop;
|
|
1149
1257
|
const hiddenBelowViewport = y >= height;
|
|
1150
1258
|
const hiddenBehindLeft = !isFixed && visibleRight <= visibleLeft;
|
|
1151
1259
|
const hiddenBehindRight = !isFixed && x >= selectionAreaRight;
|
|
1152
|
-
const leftMarkerX = Math.max(0, leftFixedWidth
|
|
1260
|
+
const leftMarkerX = Math.max(0, leftFixedWidth);
|
|
1153
1261
|
if ((hiddenAboveHeader || hiddenBelowViewport) && (hiddenBehindLeft || hiddenBehindRight)) {
|
|
1154
1262
|
const markerSize = 2;
|
|
1155
|
-
const markerX = hiddenBehindLeft ? leftMarkerX : selectionAreaRight - borderWidth;
|
|
1263
|
+
const markerX = hiddenBehindLeft ? leftMarkerX : selectionAreaRight - borderWidth - rightFixedBoundaryInset;
|
|
1156
1264
|
const markerY = hiddenAboveHeader ? selectionClipTop : height - markerSize;
|
|
1157
1265
|
ctx.fillStyle = colors.selection;
|
|
1158
1266
|
ctx.fillRect(markerX, markerY, markerSize, markerSize);
|
|
@@ -1160,7 +1268,7 @@ function paintGrid(options) {
|
|
|
1160
1268
|
}
|
|
1161
1269
|
ctx.save();
|
|
1162
1270
|
ctx.beginPath();
|
|
1163
|
-
const clipLeft = fixedSide === "left" ? 0 : Math.max(0, leftFixedWidth
|
|
1271
|
+
const clipLeft = fixedSide === "left" ? 0 : Math.max(0, leftFixedWidth);
|
|
1164
1272
|
const clipRight = Math.min(width, selectionAreaRight + 1);
|
|
1165
1273
|
ctx.rect(clipLeft, selectionClipTop, clipRight - clipLeft, height - selectionClipTop);
|
|
1166
1274
|
ctx.clip();
|
|
@@ -1178,14 +1286,14 @@ function paintGrid(options) {
|
|
|
1178
1286
|
if (hiddenBehindLeft || hiddenBehindRight) {
|
|
1179
1287
|
const markerTop = Math.max(y - borderWidth, selectionTop);
|
|
1180
1288
|
const markerBottom = Math.min(y + selectionHeight + 1, height);
|
|
1181
|
-
const markerX = hiddenBehindLeft ? leftMarkerX : selectionAreaRight - borderWidth;
|
|
1289
|
+
const markerX = hiddenBehindLeft ? leftMarkerX : selectionAreaRight - borderWidth - rightFixedBoundaryInset;
|
|
1182
1290
|
ctx.fillRect(markerX, markerTop, borderWidth, Math.max(0, markerBottom - markerTop));
|
|
1183
1291
|
}
|
|
1184
1292
|
if (hiddenAboveHeader || hiddenBelowViewport || hiddenBehindLeft || hiddenBehindRight) {
|
|
1185
1293
|
ctx.restore();
|
|
1186
1294
|
return;
|
|
1187
1295
|
}
|
|
1188
|
-
const borderLeft = x <= 0 ? 0 : Math.max(x - borderWidth, visibleLeft
|
|
1296
|
+
const borderLeft = x <= 0 ? 0 : Math.max(x - borderWidth, visibleLeft);
|
|
1189
1297
|
const borderRight = Math.min(x + selectionWidth - 1, selectionAreaRight - borderWidth, width - borderWidth);
|
|
1190
1298
|
const borderTop = Math.max(y - borderWidth, selectionClipTop);
|
|
1191
1299
|
const borderBottom = Math.min(y + selectionHeight - 1, height - borderWidth);
|
|
@@ -1247,6 +1355,40 @@ function flattenDataColumns(columns, inheritedFixed, insideGroup = false) {
|
|
|
1247
1355
|
return flattenDataColumns(column.children, column.fixed ?? inheritedFixed, true);
|
|
1248
1356
|
});
|
|
1249
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
|
+
}
|
|
1250
1392
|
function buildHeaderCells(sourceColumns, utilityColumnCount, depth) {
|
|
1251
1393
|
const cells = [];
|
|
1252
1394
|
let leafIndex = utilityColumnCount;
|
|
@@ -1294,6 +1436,25 @@ var createEmptyCellSpanLookup = () => ({
|
|
|
1294
1436
|
covered: /* @__PURE__ */ new Map(),
|
|
1295
1437
|
maxRowSpan: 1
|
|
1296
1438
|
});
|
|
1439
|
+
var summaryFunctionIds = /* @__PURE__ */ new WeakMap();
|
|
1440
|
+
var nextSummaryFunctionId = 1;
|
|
1441
|
+
function getSummaryFunctionId(fn) {
|
|
1442
|
+
if (!fn) return "";
|
|
1443
|
+
const existing = summaryFunctionIds.get(fn);
|
|
1444
|
+
if (existing !== void 0) return existing;
|
|
1445
|
+
const next = nextSummaryFunctionId;
|
|
1446
|
+
nextSummaryFunctionId += 1;
|
|
1447
|
+
summaryFunctionIds.set(fn, next);
|
|
1448
|
+
return next;
|
|
1449
|
+
}
|
|
1450
|
+
function getSummarySignature(columns) {
|
|
1451
|
+
return columns.filter((column) => Boolean(column.summary)).map((column) => [
|
|
1452
|
+
column.key,
|
|
1453
|
+
String(column.dataIndex ?? ""),
|
|
1454
|
+
typeof column.summary === "function" ? getSummaryFunctionId(column.summary) : "sum",
|
|
1455
|
+
getSummaryFunctionId(column.formatter)
|
|
1456
|
+
].join("")).join("");
|
|
1457
|
+
}
|
|
1297
1458
|
async function calculateSummaryValues(columns, rows) {
|
|
1298
1459
|
const values = /* @__PURE__ */ new Map();
|
|
1299
1460
|
for (const column of columns) {
|
|
@@ -1332,7 +1493,7 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1332
1493
|
return defaults;
|
|
1333
1494
|
}
|
|
1334
1495
|
function Table({
|
|
1335
|
-
columns:
|
|
1496
|
+
columns: columnProps,
|
|
1336
1497
|
rows: sourceRows,
|
|
1337
1498
|
rowKey,
|
|
1338
1499
|
width = "100%",
|
|
@@ -1361,23 +1522,21 @@ function Table({
|
|
|
1361
1522
|
rowSelection,
|
|
1362
1523
|
selectedRowKeys,
|
|
1363
1524
|
defaultSelectedRowKeys,
|
|
1364
|
-
|
|
1525
|
+
onSelectedRowChange,
|
|
1365
1526
|
columnSelection,
|
|
1366
1527
|
selectedColumnKeys,
|
|
1367
1528
|
defaultSelectedColumnKeys,
|
|
1368
|
-
|
|
1529
|
+
onSelectedColumnChange,
|
|
1369
1530
|
columnDraggable = true,
|
|
1370
|
-
columnResizable =
|
|
1371
|
-
|
|
1531
|
+
columnResizable = true,
|
|
1532
|
+
onColumnsReorder,
|
|
1372
1533
|
onColumnResize,
|
|
1373
1534
|
rowDraggable = false,
|
|
1374
|
-
|
|
1535
|
+
onRowsReorder,
|
|
1375
1536
|
onInsertRows,
|
|
1376
1537
|
onDeleteRows,
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
filterValues = {},
|
|
1380
|
-
onFilterValuesChange,
|
|
1538
|
+
onSortChange,
|
|
1539
|
+
onFilterChange,
|
|
1381
1540
|
onCellChange,
|
|
1382
1541
|
onCellContextMenu,
|
|
1383
1542
|
contextMenu: contextMenuConfig = true,
|
|
@@ -1386,6 +1545,10 @@ function Table({
|
|
|
1386
1545
|
style,
|
|
1387
1546
|
ariaLabel = "Data grid"
|
|
1388
1547
|
}) {
|
|
1548
|
+
const [sourceColumns, setSourceColumns] = useState4(columnProps);
|
|
1549
|
+
useEffect2(() => {
|
|
1550
|
+
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1551
|
+
}, [columnProps]);
|
|
1389
1552
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1390
1553
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1391
1554
|
const headerDepth = useMemo(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
@@ -1466,7 +1629,6 @@ function Table({
|
|
|
1466
1629
|
const frameRef = useRef2(null);
|
|
1467
1630
|
const textFrameRef = useRef2(null);
|
|
1468
1631
|
const toastTimerRef = useRef2(null);
|
|
1469
|
-
const sortDebounceRef = useRef2(null);
|
|
1470
1632
|
const headerTooltipTimerRef = useRef2(null);
|
|
1471
1633
|
const cellTooltipTimerRef = useRef2(null);
|
|
1472
1634
|
const pendingHeaderTooltipKeyRef = useRef2("");
|
|
@@ -1478,6 +1640,7 @@ function Table({
|
|
|
1478
1640
|
const dragGuideRef = useRef2(null);
|
|
1479
1641
|
const rowDragGuideRef = useRef2(null);
|
|
1480
1642
|
const selectionFocusRef = useRef2(null);
|
|
1643
|
+
const selectionEdgeTargetRef = useRef2(null);
|
|
1481
1644
|
const verticalScrollbarRef = useRef2(null);
|
|
1482
1645
|
const verticalScrollbarThumbRef = useRef2(null);
|
|
1483
1646
|
const verticalScrollbarDragRef = useRef2(null);
|
|
@@ -1496,6 +1659,7 @@ function Table({
|
|
|
1496
1659
|
const suppressClickRef = useRef2(false);
|
|
1497
1660
|
const hasCompletedLoadRef = useRef2(!loading);
|
|
1498
1661
|
const columnDragPreviewRef = useRef2(null);
|
|
1662
|
+
const validColumnDropRef = useRef2(null);
|
|
1499
1663
|
const hoveredHeaderActionRef = useRef2(null);
|
|
1500
1664
|
const hoveredRowIndexRef = useRef2(null);
|
|
1501
1665
|
const [viewport, setViewport] = useState4({ width: 0, height: typeof height === "number" ? height : FALLBACK_HEIGHT });
|
|
@@ -1503,11 +1667,8 @@ function Table({
|
|
|
1503
1667
|
const resolvedHeight = typeof height === "number" ? height : viewport.height || FALLBACK_HEIGHT;
|
|
1504
1668
|
const [scrollPosition, setScrollPosition] = useState4({ left: 0, top: 0 });
|
|
1505
1669
|
const scrollRef = useRef2({ left: 0, top: 0 });
|
|
1506
|
-
const [selection, setSelection] = useControllableValue(selectedCell, defaultSelectedCell, onSelectedCellChange);
|
|
1507
|
-
const [selectionRange, setSelectionRange] = useState4(null);
|
|
1508
|
-
const rangeDragRef = useRef2(null);
|
|
1509
1670
|
const [rowKeys, setRowKeys] = useControllableKeys(selectedRowKeys, defaultSelectedRowKeys, (keys) => {
|
|
1510
|
-
if (!
|
|
1671
|
+
if (!onSelectedRowChange) return;
|
|
1511
1672
|
const missing = new Set(keys.filter((key) => !rowByKeyRef.current.has(key)));
|
|
1512
1673
|
if (missing.size > 0) {
|
|
1513
1674
|
for (let index = 0; index < rows.length && missing.size > 0; index += 1) {
|
|
@@ -1524,12 +1685,13 @@ function Table({
|
|
|
1524
1685
|
const index = rowIndexByKeyRef.current.get(key);
|
|
1525
1686
|
return row && index !== void 0 ? [{ row, index }] : [];
|
|
1526
1687
|
});
|
|
1527
|
-
|
|
1688
|
+
onSelectedRowChange(keys, entries.map(({ row }) => row), entries.map(({ index }) => index));
|
|
1528
1689
|
});
|
|
1529
|
-
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys,
|
|
1690
|
+
const [columnKeys, setColumnKeys] = useControllableKeys(selectedColumnKeys, defaultSelectedColumnKeys, onSelectedColumnChange);
|
|
1530
1691
|
const [editing, setEditing] = useState4(null);
|
|
1531
1692
|
const [draft, setDraft] = useState4("");
|
|
1532
1693
|
const [rowDragPreview, setRowDragPreview] = useState4(null);
|
|
1694
|
+
const [columnDropTarget, setColumnDropTarget] = useState4(null);
|
|
1533
1695
|
useEffect2(() => {
|
|
1534
1696
|
if (!loading) hasCompletedLoadRef.current = true;
|
|
1535
1697
|
}, [loading]);
|
|
@@ -1598,6 +1760,8 @@ function Table({
|
|
|
1598
1760
|
return () => observer.disconnect();
|
|
1599
1761
|
}, [activeCustomHeaderLevels, measureCustomHeaderHeight, viewport.width]);
|
|
1600
1762
|
const [filterEditor, setFilterEditor] = useState4(null);
|
|
1763
|
+
const [filterValues, setFilterValues] = useState4({});
|
|
1764
|
+
const [sortState, setSortState] = useState4(null);
|
|
1601
1765
|
const [contextMenu, setContextMenu] = useState4(null);
|
|
1602
1766
|
const [insertCounts, setInsertCounts] = useState4({ before: 1, after: 1 });
|
|
1603
1767
|
const [confirmAction, setConfirmAction] = useState4(null);
|
|
@@ -1610,7 +1774,20 @@ function Table({
|
|
|
1610
1774
|
const [hoveredHeaderAction, setHoveredHeaderAction] = useState4(null);
|
|
1611
1775
|
const [visibleHeaderTooltip, setVisibleHeaderTooltip] = useState4(null);
|
|
1612
1776
|
const [hoveredCellTooltip, setHoveredCellTooltip] = useState4(null);
|
|
1613
|
-
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
|
+
}, []);
|
|
1614
1791
|
const [editedCellKeys, setEditedCellKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1615
1792
|
const [cellAnnotations, setCellAnnotations] = useState4(() => /* @__PURE__ */ new Map());
|
|
1616
1793
|
const [annotationType, setAnnotationType] = useState4("corner");
|
|
@@ -1622,6 +1799,7 @@ function Table({
|
|
|
1622
1799
|
const [pendingDeletedRowKeys, setPendingDeletedRowKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1623
1800
|
const [pendingInserts, setPendingInserts] = useState4(() => []);
|
|
1624
1801
|
const [insertedRowKeys, setInsertedRowKeys] = useState4(() => /* @__PURE__ */ new Set());
|
|
1802
|
+
const [rowOrderKeys, setRowOrderKeys] = useState4(null);
|
|
1625
1803
|
const settledPendingInsertIdsRef = useRef2(/* @__PURE__ */ new Set());
|
|
1626
1804
|
const getDataRowKey = useCallback2((row, index) => {
|
|
1627
1805
|
return typeof rowKey === "function" ? rowKey(row, index) : rowKey ? row[rowKey] : getDefaultRowKey(row, index);
|
|
@@ -1636,7 +1814,7 @@ function Table({
|
|
|
1636
1814
|
}
|
|
1637
1815
|
return sourceRows.findIndex((sourceRow, index) => getDataRowKey(sourceRow, index) === key);
|
|
1638
1816
|
}, [getDataRowKey, sourceRows]);
|
|
1639
|
-
const
|
|
1817
|
+
const orderedRows = useMemo(() => {
|
|
1640
1818
|
let next = sourceRows;
|
|
1641
1819
|
if (pendingInserts.length > 0) {
|
|
1642
1820
|
const activeInserts = pendingInserts.filter((insert) => {
|
|
@@ -1655,9 +1833,91 @@ function Table({
|
|
|
1655
1833
|
insertedOffset += insert.rows.length;
|
|
1656
1834
|
});
|
|
1657
1835
|
}
|
|
1658
|
-
if (pendingDeletedRowKeys.size
|
|
1659
|
-
|
|
1660
|
-
|
|
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]);
|
|
1661
1921
|
useEffect2(() => {
|
|
1662
1922
|
if (insertBusy || settledPendingInsertIdsRef.current.size === 0) return;
|
|
1663
1923
|
setPendingInserts((current) => {
|
|
@@ -1725,7 +1985,8 @@ function Table({
|
|
|
1725
1985
|
const getScrollableColumnLeft = useCallback2((columnIndex) => scrollableColumnLefts[columnIndex] ?? fixedWidth, [fixedWidth, scrollableColumnLefts]);
|
|
1726
1986
|
const hasRowSelectionColumn = useMemo(() => columns.some((column) => column.rowSelection), [columns]);
|
|
1727
1987
|
const rowSelectionMode = typeof rowSelection === "object" ? rowSelection.mode ?? "multiple" : "multiple";
|
|
1728
|
-
const
|
|
1988
|
+
const summarySignature = useMemo(() => getSummarySignature(columns), [columns]);
|
|
1989
|
+
const hasSummaryRow = rows.length > 0 && summaryEnabled && summarySignature.length > 0;
|
|
1729
1990
|
const topSummaryHeight = hasSummaryRow && summaryPosition === "top" ? rowHeight : 0;
|
|
1730
1991
|
const bottomSummaryHeight = hasSummaryRow && summaryPosition === "bottom" ? rowHeight : 0;
|
|
1731
1992
|
const bodyTop = headerHeight + topSummaryHeight;
|
|
@@ -1734,21 +1995,21 @@ function Table({
|
|
|
1734
1995
|
const effectiveHeight = autoHeight ? Math.max(bodyTop + bottomSummaryHeight, Math.min(resolvedHeight, realContentHeight)) : resolvedHeight;
|
|
1735
1996
|
const renderHeight = Math.max(0, effectiveHeight - bottomSummaryHeight);
|
|
1736
1997
|
const bodyViewportHeight = Math.max(0, renderHeight - (fixedHeader ? headerHeight + topSummaryHeight : 0));
|
|
1737
|
-
const [summaryState, setSummaryState] = useState4(() => ({
|
|
1738
|
-
const summaryPending = hasSummaryRow && (loading || summaryState.pending || summaryState.
|
|
1739
|
-
const summaryValues = hasSummaryRow && summaryState.
|
|
1998
|
+
const [summaryState, setSummaryState] = useState4(() => ({ signature: "", rows: null, values: /* @__PURE__ */ new Map(), pending: false }));
|
|
1999
|
+
const summaryPending = hasSummaryRow && (loading || summaryState.pending || summaryState.signature !== summarySignature || summaryState.rows !== rows);
|
|
2000
|
+
const summaryValues = hasSummaryRow && summaryState.signature === summarySignature && summaryState.rows === rows ? summaryState.values : /* @__PURE__ */ new Map();
|
|
1740
2001
|
useEffect2(() => {
|
|
1741
2002
|
let cancelled = false;
|
|
1742
2003
|
if (!hasSummaryRow) {
|
|
1743
|
-
setSummaryState((current) => current.
|
|
2004
|
+
setSummaryState((current) => current.signature === "" && current.rows === null && current.values.size === 0 && !current.pending ? current : { signature: "", rows: null, values: /* @__PURE__ */ new Map(), pending: false });
|
|
1744
2005
|
return () => {
|
|
1745
2006
|
cancelled = true;
|
|
1746
2007
|
};
|
|
1747
2008
|
}
|
|
1748
2009
|
setSummaryState((current) => ({
|
|
1749
|
-
|
|
2010
|
+
signature: summarySignature,
|
|
1750
2011
|
rows,
|
|
1751
|
-
values: current.
|
|
2012
|
+
values: current.signature === summarySignature && current.rows === rows ? current.values : /* @__PURE__ */ new Map(),
|
|
1752
2013
|
pending: true
|
|
1753
2014
|
}));
|
|
1754
2015
|
if (loading) {
|
|
@@ -1761,13 +2022,13 @@ function Table({
|
|
|
1761
2022
|
if (cancelled) return;
|
|
1762
2023
|
const values = await calculateSummaryValues(columns, rows);
|
|
1763
2024
|
if (cancelled) return;
|
|
1764
|
-
setSummaryState({
|
|
2025
|
+
setSummaryState({ signature: summarySignature, rows, values, pending: false });
|
|
1765
2026
|
};
|
|
1766
2027
|
void run();
|
|
1767
2028
|
return () => {
|
|
1768
2029
|
cancelled = true;
|
|
1769
2030
|
};
|
|
1770
|
-
}, [
|
|
2031
|
+
}, [hasSummaryRow, loading, rows, summarySignature]);
|
|
1771
2032
|
const domRange = useMemo(() => {
|
|
1772
2033
|
if (!isVirtualized) return { rowStart: 0, rowEnd: rows.length, columnStart: 0, columnEnd: columns.length };
|
|
1773
2034
|
const currentScroll2 = scrollRef.current;
|
|
@@ -1898,22 +2159,177 @@ function Table({
|
|
|
1898
2159
|
grid: readThemeColor(themeStyles, "--rvg-color-grid", "#e3e6e8"),
|
|
1899
2160
|
text: readThemeColor(themeStyles, "--rvg-color-text", "#202124"),
|
|
1900
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"),
|
|
1901
2164
|
selection: readThemeColor(themeStyles, "--rvg-color-primary", "#1677ff"),
|
|
1902
2165
|
selectionFill: readThemeColor(themeStyles, "--rvg-color-selection-fill", "#edf4ff"),
|
|
1903
2166
|
axisSelectionFill: readThemeColor(themeStyles, "--rvg-color-axis-selection-fill", "#e8f2ff"),
|
|
1904
2167
|
rowHoverFill: readThemeColor(themeStyles, "--rvg-color-row-hover-fill", "#f6f9fc"),
|
|
1905
2168
|
editedFill: editedCellHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-edited-fill", "#fff1b8"),
|
|
1906
2169
|
insertedFill: insertedRowHighlightColor ?? readThemeColor(themeStyles, "--rvg-color-inserted-fill", "#c8ead4"),
|
|
2170
|
+
columnDropTargetFill: readThemeColor(themeStyles, "--rvg-color-column-drop-target-fill", "#eeeeee"),
|
|
1907
2171
|
stripe: stripedColor ?? readThemeColor(themeStyles, "--rvg-color-stripe", "#fafbfc")
|
|
1908
2172
|
};
|
|
1909
2173
|
const scroll = scrollRef.current;
|
|
1910
2174
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
1911
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 };
|
|
1912
|
-
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 });
|
|
1913
|
-
}, [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]);
|
|
1914
2178
|
const scheduleDraw = useCallback2(() => {
|
|
1915
2179
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
1916
2180
|
}, [draw]);
|
|
2181
|
+
const drawImmediately = useCallback2(() => {
|
|
2182
|
+
if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
|
|
2183
|
+
frameRef.current = null;
|
|
2184
|
+
draw();
|
|
2185
|
+
}, [draw]);
|
|
2186
|
+
const getSelectionHorizontalVisibility = useCallback2((scrollLeft) => {
|
|
2187
|
+
if (!selection || selectionRange) return "visible";
|
|
2188
|
+
const column = columns[selection.columnIndex];
|
|
2189
|
+
if (!column || column.fixed !== void 0) return "visible";
|
|
2190
|
+
const span = getCellSpan(selection.rowIndex, selection.columnIndex);
|
|
2191
|
+
const left = getScrollableColumnLeft(selection.columnIndex) - scrollLeft;
|
|
2192
|
+
const right = left + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
2193
|
+
if (right <= fixedWidth) return "hidden-left";
|
|
2194
|
+
if (left >= viewport.width - rightFixedWidth) return "hidden-right";
|
|
2195
|
+
return "visible";
|
|
2196
|
+
}, [columns, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, rightFixedWidth, selection, selectionRange, viewport.width]);
|
|
2197
|
+
const getSelectionEdgeIndicator = useCallback2((scrollLeft, scrollTop) => {
|
|
2198
|
+
if (!selection || selectionRange) return null;
|
|
2199
|
+
const row = rows[selection.rowIndex];
|
|
2200
|
+
const metric = metrics[selection.columnIndex];
|
|
2201
|
+
const column = columns[selection.columnIndex];
|
|
2202
|
+
if (!row || !metric || !column || getRowKey(row, selection.rowIndex) !== selection.rowKey) return null;
|
|
2203
|
+
const span = getCellSpan(selection.rowIndex, selection.columnIndex);
|
|
2204
|
+
const rawLeft = column.fixed === "left" ? leftFixedOffsets.get(selection.columnIndex) ?? 0 : column.fixed === "right" ? viewport.width - (rightFixedOffsets.get(selection.columnIndex) ?? 0) - metric.width : getScrollableColumnLeft(selection.columnIndex) - scrollLeft;
|
|
2205
|
+
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
2206
|
+
const rawTop = bodyTop + selection.rowIndex * rowHeight - scrollTop;
|
|
2207
|
+
const rawBottom = rawTop + rowHeight * (span?.rowSpan ?? 1);
|
|
2208
|
+
const horizontalStart = column.fixed === void 0 ? fixedWidth : 0;
|
|
2209
|
+
const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
2210
|
+
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
2211
|
+
const hiddenLeft = column.fixed === void 0 && rawRight <= horizontalStart;
|
|
2212
|
+
const hiddenRight = column.fixed === void 0 && rawLeft >= horizontalEnd;
|
|
2213
|
+
const hiddenTop = rawBottom <= verticalStart;
|
|
2214
|
+
const hiddenBottom = rawTop >= renderHeight;
|
|
2215
|
+
if (!hiddenLeft && !hiddenRight && !hiddenTop && !hiddenBottom) return null;
|
|
2216
|
+
const borderWidth = 2;
|
|
2217
|
+
const cornerLength = 10;
|
|
2218
|
+
const hitSlop = 6;
|
|
2219
|
+
const targetSize = borderWidth + hitSlop * 2;
|
|
2220
|
+
const rightBoundaryInset = rightFixedWidth > 0 && hasVerticalBorders ? 1 : 0;
|
|
2221
|
+
const markerX = hiddenLeft ? horizontalStart : horizontalEnd - borderWidth - rightBoundaryInset;
|
|
2222
|
+
const markerY = hiddenTop ? verticalStart : renderHeight - borderWidth;
|
|
2223
|
+
if (hiddenLeft || hiddenRight) {
|
|
2224
|
+
let markerTop = Math.max(rawTop - borderWidth, verticalStart);
|
|
2225
|
+
let markerBottom = Math.min(rawBottom + 1, renderHeight);
|
|
2226
|
+
const topClip = Math.max(0, verticalStart - (rawTop - borderWidth));
|
|
2227
|
+
const bottomClip = Math.max(0, rawBottom + 1 - renderHeight);
|
|
2228
|
+
if (topClip > 0 || bottomClip > 0) {
|
|
2229
|
+
const foldAtTop = topClip > 0;
|
|
2230
|
+
const fold = Math.min(cornerLength, foldAtTop ? topClip : bottomClip);
|
|
2231
|
+
if (fold > borderWidth) {
|
|
2232
|
+
const cornerWidth = fold;
|
|
2233
|
+
const cornerHeight = Math.max(cornerLength, markerBottom - markerTop);
|
|
2234
|
+
const cornerOnLeft = hiddenLeft;
|
|
2235
|
+
const shapeLeft = cornerOnLeft ? markerX : markerX + borderWidth - cornerWidth;
|
|
2236
|
+
const shapeTop = foldAtTop ? verticalStart : renderHeight - cornerHeight;
|
|
2237
|
+
return {
|
|
2238
|
+
side: `${foldAtTop ? "top" : "bottom"}-${cornerOnLeft ? "left" : "right"}`,
|
|
2239
|
+
orientation: "corner",
|
|
2240
|
+
style: {
|
|
2241
|
+
left: shapeLeft - hitSlop,
|
|
2242
|
+
top: shapeTop - hitSlop,
|
|
2243
|
+
width: cornerWidth + hitSlop * 2,
|
|
2244
|
+
height: cornerHeight + hitSlop * 2
|
|
2245
|
+
},
|
|
2246
|
+
corner: { width: cornerWidth, height: cornerHeight }
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
if (markerBottom <= markerTop) return null;
|
|
2251
|
+
return {
|
|
2252
|
+
side: hiddenLeft ? "left" : "right",
|
|
2253
|
+
orientation: "vertical",
|
|
2254
|
+
viewportEdge: hiddenLeft && horizontalStart === 0 ? "left" : hiddenRight && horizontalEnd === viewport.width ? "right" : void 0,
|
|
2255
|
+
style: {
|
|
2256
|
+
left: markerX - hitSlop,
|
|
2257
|
+
top: markerTop,
|
|
2258
|
+
width: targetSize,
|
|
2259
|
+
height: markerBottom - markerTop
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2263
|
+
const horizontalMarkerEnd = horizontalEnd - rightBoundaryInset;
|
|
2264
|
+
let markerLeft = Math.max(rawLeft - borderWidth, horizontalStart);
|
|
2265
|
+
let markerRight = Math.min(rawRight + 1, horizontalMarkerEnd);
|
|
2266
|
+
const leftClip = Math.max(0, horizontalStart - (rawLeft - borderWidth));
|
|
2267
|
+
const rightClip = Math.max(0, rawRight + 1 - horizontalMarkerEnd);
|
|
2268
|
+
if (leftClip > 0 || rightClip > 0) {
|
|
2269
|
+
const foldAtLeft = leftClip > 0;
|
|
2270
|
+
const fold = Math.min(cornerLength, foldAtLeft ? leftClip : rightClip);
|
|
2271
|
+
if (fold > borderWidth) {
|
|
2272
|
+
const cornerWidth = Math.max(cornerLength, markerRight - markerLeft);
|
|
2273
|
+
const cornerHeight = fold;
|
|
2274
|
+
const shapeLeft = foldAtLeft ? horizontalStart : horizontalMarkerEnd - cornerWidth;
|
|
2275
|
+
const shapeTop = hiddenTop ? verticalStart : renderHeight - cornerHeight;
|
|
2276
|
+
return {
|
|
2277
|
+
side: `${hiddenTop ? "top" : "bottom"}-${foldAtLeft ? "left" : "right"}`,
|
|
2278
|
+
orientation: "corner",
|
|
2279
|
+
style: {
|
|
2280
|
+
left: shapeLeft - hitSlop,
|
|
2281
|
+
top: shapeTop - hitSlop,
|
|
2282
|
+
width: cornerWidth + hitSlop * 2,
|
|
2283
|
+
height: cornerHeight + hitSlop * 2
|
|
2284
|
+
},
|
|
2285
|
+
corner: { width: cornerWidth, height: cornerHeight }
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
if (markerRight <= markerLeft) return null;
|
|
2290
|
+
return {
|
|
2291
|
+
side: hiddenTop ? "top" : "bottom",
|
|
2292
|
+
orientation: "horizontal",
|
|
2293
|
+
viewportEdge: hiddenTop && verticalStart === 0 ? "top" : hiddenBottom ? "bottom" : void 0,
|
|
2294
|
+
style: {
|
|
2295
|
+
left: markerLeft,
|
|
2296
|
+
top: markerY - hitSlop,
|
|
2297
|
+
width: markerRight - markerLeft,
|
|
2298
|
+
height: targetSize
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, hasVerticalBorders, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, rows, selection, selectionRange, viewport.width]);
|
|
2302
|
+
const syncSelectionEdgeTarget = useCallback2((scrollLeft, scrollTop) => {
|
|
2303
|
+
const target = selectionEdgeTargetRef.current;
|
|
2304
|
+
if (!target) return;
|
|
2305
|
+
const indicator = getSelectionEdgeIndicator(scrollLeft, scrollTop);
|
|
2306
|
+
if (!indicator) {
|
|
2307
|
+
target.style.visibility = "hidden";
|
|
2308
|
+
return;
|
|
2309
|
+
}
|
|
2310
|
+
const orientationChanged = !target.classList.contains(`is-${indicator.orientation}`);
|
|
2311
|
+
target.className = `rvg-selection-edge-target is-${indicator.orientation} is-${indicator.side}${indicator.viewportEdge ? ` is-viewport-${indicator.viewportEdge}` : ""}${orientationChanged ? " is-shape-syncing" : ""}`;
|
|
2312
|
+
target.style.left = `${Number(indicator.style.left)}px`;
|
|
2313
|
+
target.style.top = `${Number(indicator.style.top)}px`;
|
|
2314
|
+
target.style.width = `${Number(indicator.style.width)}px`;
|
|
2315
|
+
target.style.height = `${Number(indicator.style.height)}px`;
|
|
2316
|
+
if (indicator.corner) {
|
|
2317
|
+
target.style.setProperty("--rvg-corner-width", `${indicator.corner.width}px`);
|
|
2318
|
+
target.style.setProperty("--rvg-corner-height", `${indicator.corner.height}px`);
|
|
2319
|
+
target.style.setProperty("--rvg-corner-hover-width-extension", "4px");
|
|
2320
|
+
target.style.setProperty("--rvg-corner-hover-height-extension", "4px");
|
|
2321
|
+
} else {
|
|
2322
|
+
target.style.removeProperty("--rvg-corner-width");
|
|
2323
|
+
target.style.removeProperty("--rvg-corner-height");
|
|
2324
|
+
target.style.removeProperty("--rvg-corner-hover-width-extension");
|
|
2325
|
+
target.style.removeProperty("--rvg-corner-hover-height-extension");
|
|
2326
|
+
}
|
|
2327
|
+
target.style.visibility = "visible";
|
|
2328
|
+
if (orientationChanged) {
|
|
2329
|
+
void target.offsetWidth;
|
|
2330
|
+
target.classList.remove("is-shape-syncing");
|
|
2331
|
+
}
|
|
2332
|
+
}, [getSelectionEdgeIndicator]);
|
|
1917
2333
|
useLayoutEffect2(() => {
|
|
1918
2334
|
const element = scrollerRef.current;
|
|
1919
2335
|
if (!element) return;
|
|
@@ -1940,11 +2356,7 @@ function Table({
|
|
|
1940
2356
|
}
|
|
1941
2357
|
};
|
|
1942
2358
|
}, [scheduleDraw]);
|
|
1943
|
-
useEffect2(() => {
|
|
1944
|
-
setDisplaySortState(sortState);
|
|
1945
|
-
}, [sortState]);
|
|
1946
2359
|
useEffect2(() => () => {
|
|
1947
|
-
if (sortDebounceRef.current !== null) clearTimeout(sortDebounceRef.current);
|
|
1948
2360
|
if (textFrameRef.current !== null) cancelAnimationFrame(textFrameRef.current);
|
|
1949
2361
|
if (toastTimerRef.current !== null) clearTimeout(toastTimerRef.current);
|
|
1950
2362
|
if (verticalScrollbarVisibilityTimerRef.current !== null) clearTimeout(verticalScrollbarVisibilityTimerRef.current);
|
|
@@ -2164,7 +2576,13 @@ function Table({
|
|
|
2164
2576
|
}
|
|
2165
2577
|
const nextThumbLeft = Math.max(0, Math.min(trackWidth - thumbWidth, event.clientX - trackRect.left - thumbWidth / 2));
|
|
2166
2578
|
const maxThumbLeft = Math.max(1, trackWidth - thumbWidth);
|
|
2167
|
-
scroller.scrollLeft
|
|
2579
|
+
const previousScrollLeft = scroller.scrollLeft;
|
|
2580
|
+
const nextScrollLeft = nextThumbLeft / maxThumbLeft * maxScrollLeft;
|
|
2581
|
+
const visibilityChanged = getSelectionHorizontalVisibility(previousScrollLeft) !== getSelectionHorizontalVisibility(nextScrollLeft);
|
|
2582
|
+
scroller.scrollLeft = nextScrollLeft;
|
|
2583
|
+
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
2584
|
+
syncSelectionEdgeTarget(scroller.scrollLeft, scroller.scrollTop);
|
|
2585
|
+
if (visibilityChanged) drawImmediately();
|
|
2168
2586
|
updateCustomScrollbars();
|
|
2169
2587
|
horizontalScrollbarDragRef.current = {
|
|
2170
2588
|
pointerId: event.pointerId,
|
|
@@ -2174,7 +2592,7 @@ function Table({
|
|
|
2174
2592
|
thumbWidth,
|
|
2175
2593
|
maxScrollLeft
|
|
2176
2594
|
};
|
|
2177
|
-
}, [showCustomScrollbar, updateCustomScrollbars]);
|
|
2595
|
+
}, [drawImmediately, getSelectionHorizontalVisibility, showCustomScrollbar, syncSelectionEdgeTarget, updateCustomScrollbars]);
|
|
2178
2596
|
const handleHorizontalScrollbarPointerMove = useCallback2((event) => {
|
|
2179
2597
|
const drag = horizontalScrollbarDragRef.current;
|
|
2180
2598
|
const scroller = scrollerRef.current;
|
|
@@ -2182,9 +2600,15 @@ function Table({
|
|
|
2182
2600
|
event.preventDefault();
|
|
2183
2601
|
const maxThumbLeft = Math.max(1, drag.trackWidth - drag.thumbWidth);
|
|
2184
2602
|
const nextThumbLeft = Math.max(0, Math.min(maxThumbLeft, drag.startLeft + event.clientX - drag.startX));
|
|
2185
|
-
|
|
2603
|
+
const previousScrollLeft = scroller.scrollLeft;
|
|
2604
|
+
const nextScrollLeft = nextThumbLeft / maxThumbLeft * drag.maxScrollLeft;
|
|
2605
|
+
const visibilityChanged = getSelectionHorizontalVisibility(previousScrollLeft) !== getSelectionHorizontalVisibility(nextScrollLeft);
|
|
2606
|
+
scroller.scrollLeft = nextScrollLeft;
|
|
2607
|
+
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
2608
|
+
syncSelectionEdgeTarget(scroller.scrollLeft, scroller.scrollTop);
|
|
2609
|
+
if (visibilityChanged) drawImmediately();
|
|
2186
2610
|
updateCustomScrollbars();
|
|
2187
|
-
}, [updateCustomScrollbars]);
|
|
2611
|
+
}, [drawImmediately, getSelectionHorizontalVisibility, syncSelectionEdgeTarget, updateCustomScrollbars]);
|
|
2188
2612
|
const handleHorizontalScrollbarPointerUp = useCallback2((event) => {
|
|
2189
2613
|
const drag = horizontalScrollbarDragRef.current;
|
|
2190
2614
|
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
@@ -2199,6 +2623,7 @@ function Table({
|
|
|
2199
2623
|
const scrollDeltaX = element.scrollLeft - previousScroll.left;
|
|
2200
2624
|
const scrollDeltaY = element.scrollTop - previousScroll.top;
|
|
2201
2625
|
scrollRef.current = { left: element.scrollLeft, top: element.scrollTop };
|
|
2626
|
+
syncSelectionEdgeTarget(element.scrollLeft, element.scrollTop);
|
|
2202
2627
|
const focus = selectionFocusRef.current;
|
|
2203
2628
|
if (focus && selection && !selectionRange) {
|
|
2204
2629
|
const row = rows[selection.rowIndex];
|
|
@@ -2220,9 +2645,9 @@ function Table({
|
|
|
2220
2645
|
focus.style.display = "none";
|
|
2221
2646
|
} else {
|
|
2222
2647
|
const borderWidth = 2;
|
|
2223
|
-
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart
|
|
2648
|
+
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
|
|
2224
2649
|
const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
|
|
2225
|
-
const top = Math.round(Math.max(rawTop - borderWidth, verticalStart
|
|
2650
|
+
const top = Math.round(Math.max(rawTop - borderWidth, verticalStart));
|
|
2226
2651
|
const bottom = Math.round(Math.min(rawBottom + 1, renderHeight));
|
|
2227
2652
|
focus.style.display = "block";
|
|
2228
2653
|
focus.style.left = `${left}px`;
|
|
@@ -2252,7 +2677,7 @@ function Table({
|
|
|
2252
2677
|
setHoveredCellTooltip(null);
|
|
2253
2678
|
scheduleDraw();
|
|
2254
2679
|
setEditing(null);
|
|
2255
|
-
}, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, showCustomScrollbar, updateCustomScrollbars, viewport.width]);
|
|
2680
|
+
}, [bodyTop, columns, renderHeight, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getRowKey, getScrollableColumnLeft, metrics, rightFixedOffsets, rightFixedWidth, rowHeight, rows, scheduleDraw, selection, selectionRange, showCustomScrollbar, syncSelectionEdgeTarget, updateCustomScrollbars, viewport.width]);
|
|
2256
2681
|
const locateColumn = useCallback2((clientX) => {
|
|
2257
2682
|
const canvas = canvasRef.current;
|
|
2258
2683
|
if (!canvas) return -1;
|
|
@@ -2306,12 +2731,12 @@ function Table({
|
|
|
2306
2731
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2307
2732
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2308
2733
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2309
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2734
|
+
let right = columnRight - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
2310
2735
|
if (visibleActions.sort) {
|
|
2311
|
-
if (localX >= right -
|
|
2312
|
-
right -=
|
|
2736
|
+
if (localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "sort";
|
|
2737
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
2313
2738
|
}
|
|
2314
|
-
if (visibleActions.filter && localX >= right -
|
|
2739
|
+
if (visibleActions.filter && localX >= right - HEADER_ACTION_SLOT_WIDTH && localX < right) return "filter";
|
|
2315
2740
|
return null;
|
|
2316
2741
|
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2317
2742
|
const isHeaderTitleTruncated = useCallback2((columnIndex) => {
|
|
@@ -2321,7 +2746,7 @@ function Table({
|
|
|
2321
2746
|
const metric = metrics[columnIndex];
|
|
2322
2747
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2323
2748
|
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2324
|
-
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;
|
|
2325
2750
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2326
2751
|
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2327
2752
|
const locateHeaderDragHandle = useCallback2((clientX, columnIndex) => {
|
|
@@ -2340,6 +2765,30 @@ function Table({
|
|
|
2340
2765
|
return fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex) - scrollRef.current.left;
|
|
2341
2766
|
}, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
|
|
2342
2767
|
const getHeaderCellWidth = useCallback2((cell) => cell.leaf ? metrics[cell.startIndex]?.width ?? 0 : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1), [getCellDisplayWidth, metrics]);
|
|
2768
|
+
const getHeaderCellEdgeFromMetrics = useCallback2((startIndex, endIndex, edge, nextMetrics) => {
|
|
2769
|
+
const fixedSide = columns[startIndex]?.fixed;
|
|
2770
|
+
const width2 = nextMetrics.slice(startIndex, endIndex + 1).reduce((total, metric) => total + metric.width, 0);
|
|
2771
|
+
let left;
|
|
2772
|
+
if (fixedSide === "left") {
|
|
2773
|
+
left = 0;
|
|
2774
|
+
for (let index = 0; index < startIndex; index += 1) {
|
|
2775
|
+
if (columns[index].fixed === "left") left += nextMetrics[index]?.width ?? 0;
|
|
2776
|
+
}
|
|
2777
|
+
} else if (fixedSide === "right") {
|
|
2778
|
+
let rightOffset = 0;
|
|
2779
|
+
for (let index = columns.length - 1; index > startIndex; index -= 1) {
|
|
2780
|
+
if (columns[index].fixed === "right") rightOffset += nextMetrics[index]?.width ?? 0;
|
|
2781
|
+
}
|
|
2782
|
+
left = viewport.width - rightOffset - width2;
|
|
2783
|
+
} else {
|
|
2784
|
+
left = 0;
|
|
2785
|
+
for (let index = 0; index < startIndex; index += 1) {
|
|
2786
|
+
if (columns[index].fixed === void 0) left += nextMetrics[index]?.width ?? 0;
|
|
2787
|
+
}
|
|
2788
|
+
left += fixedWidth - scrollRef.current.left;
|
|
2789
|
+
}
|
|
2790
|
+
return left + (edge === "right" ? width2 : 0);
|
|
2791
|
+
}, [columns, fixedWidth, viewport.width]);
|
|
2343
2792
|
const locateHeaderResizeHit = useCallback2((clientX, clientY) => {
|
|
2344
2793
|
if (!columnResizable || !canvasRef.current) return null;
|
|
2345
2794
|
const rect = canvasRef.current.getBoundingClientRect();
|
|
@@ -2350,6 +2799,7 @@ function Table({
|
|
|
2350
2799
|
const level = getHeaderLevelAtY(localY, headerY);
|
|
2351
2800
|
let closest = null;
|
|
2352
2801
|
let distance = 6;
|
|
2802
|
+
let priority = -1;
|
|
2353
2803
|
for (const cell of headerCells) {
|
|
2354
2804
|
if (cell.level !== level) continue;
|
|
2355
2805
|
if (columns[cell.startIndex]?.rowSelection || columns[cell.startIndex]?.rowDragHandle || columns[cell.startIndex]?.rowNumber) continue;
|
|
@@ -2357,8 +2807,10 @@ function Table({
|
|
|
2357
2807
|
const edge = fixedSide === "right" && cell.leaf ? "left" : "right";
|
|
2358
2808
|
const edgeX = getHeaderCellLeft(cell) + (edge === "right" ? getHeaderCellWidth(cell) : 0);
|
|
2359
2809
|
const nextDistance = Math.abs(localX - edgeX);
|
|
2360
|
-
|
|
2810
|
+
const nextPriority = fixedSide === "right" ? 2 : fixedSide === "left" ? 1 : 0;
|
|
2811
|
+
if (nextDistance < distance || nextDistance === distance && nextPriority > priority) {
|
|
2361
2812
|
distance = nextDistance;
|
|
2813
|
+
priority = nextPriority;
|
|
2362
2814
|
closest = { cell, edge };
|
|
2363
2815
|
}
|
|
2364
2816
|
}
|
|
@@ -2450,6 +2902,7 @@ function Table({
|
|
|
2450
2902
|
}
|
|
2451
2903
|
const sourceIndex = headerDragCell.startIndex;
|
|
2452
2904
|
columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
|
|
2905
|
+
validColumnDropRef.current = null;
|
|
2453
2906
|
return {
|
|
2454
2907
|
type: "table-column",
|
|
2455
2908
|
sourceIndex,
|
|
@@ -2460,13 +2913,26 @@ function Table({
|
|
|
2460
2913
|
fixed: columns[headerDragCell.startIndex]?.fixed
|
|
2461
2914
|
};
|
|
2462
2915
|
},
|
|
2463
|
-
onGenerateDragPreview: ({ nativeSetDragImage, source }) => {
|
|
2916
|
+
onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
|
|
2464
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
|
+
};
|
|
2465
2927
|
setCustomNativeDragPreview({
|
|
2466
2928
|
nativeSetDragImage,
|
|
2929
|
+
getOffset: () => previewOffset,
|
|
2467
2930
|
render: ({ container }) => {
|
|
2468
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
2469
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`;
|
|
2470
2936
|
const preview2 = document.createElement("div");
|
|
2471
2937
|
preview2.className = "rvg-row-drag-preview";
|
|
2472
2938
|
preview2.style.width = `${canvasRect.width}px`;
|
|
@@ -2492,10 +2958,14 @@ function Table({
|
|
|
2492
2958
|
} else {
|
|
2493
2959
|
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
2494
2960
|
}
|
|
2961
|
+
if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
|
|
2962
|
+
cell.classList.add("is-selected");
|
|
2963
|
+
}
|
|
2495
2964
|
preview2.appendChild(cell);
|
|
2496
2965
|
});
|
|
2497
|
-
|
|
2498
|
-
|
|
2966
|
+
frame.appendChild(preview2);
|
|
2967
|
+
container.appendChild(frame);
|
|
2968
|
+
return () => frame.remove();
|
|
2499
2969
|
}
|
|
2500
2970
|
const preview = document.createElement("div");
|
|
2501
2971
|
preview.className = "rvg-column-drag-preview";
|
|
@@ -2509,6 +2979,29 @@ function Table({
|
|
|
2509
2979
|
header.style.height = `${headerHeight}px`;
|
|
2510
2980
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
2511
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
|
+
}
|
|
2512
3005
|
preview.appendChild(header);
|
|
2513
3006
|
for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
|
|
2514
3007
|
const row = rows[rowIndex];
|
|
@@ -2537,6 +3030,8 @@ function Table({
|
|
|
2537
3030
|
},
|
|
2538
3031
|
onDragStart: ({ source }) => {
|
|
2539
3032
|
suppressClickRef.current = true;
|
|
3033
|
+
hideDragTooltips();
|
|
3034
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
2540
3035
|
canvas.style.cursor = "move";
|
|
2541
3036
|
if (source.data.type === "table-row") {
|
|
2542
3037
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
@@ -2562,30 +3057,66 @@ function Table({
|
|
|
2562
3057
|
}
|
|
2563
3058
|
const targetIndex = Number(target?.targetIndex);
|
|
2564
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);
|
|
2565
3062
|
setDragGuide(null);
|
|
2566
3063
|
return;
|
|
2567
3064
|
}
|
|
2568
3065
|
const edge = target?.columnEdge;
|
|
2569
3066
|
const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
|
|
2570
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 });
|
|
2571
3095
|
const targetLeft = Number(target?.targetLeft);
|
|
2572
3096
|
const targetWidth = Number(target?.targetWidth);
|
|
3097
|
+
if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
|
|
3098
|
+
validColumnDropRef.current = null;
|
|
3099
|
+
setColumnDropTarget(null);
|
|
3100
|
+
setDragGuide(null);
|
|
3101
|
+
return;
|
|
3102
|
+
}
|
|
2573
3103
|
const guideTop = headerRowOffsets[Number(source.data.headerLevel)] ?? 0;
|
|
2574
3104
|
setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
|
|
2575
3105
|
},
|
|
2576
3106
|
onDrop: ({ source, location }) => {
|
|
3107
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2577
3108
|
const target = location.current.dropTargets[0]?.data;
|
|
2578
3109
|
const sourceIndex = Number(source.data.sourceIndex);
|
|
2579
3110
|
if (source.data.type === "table-row") {
|
|
2580
|
-
const
|
|
2581
|
-
let
|
|
2582
|
-
if (sourceIndex <
|
|
2583
|
-
|
|
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));
|
|
2584
3115
|
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
2585
3116
|
setRowDragPreview(null);
|
|
2586
3117
|
setRowDragGuide(null);
|
|
2587
3118
|
canvas.style.cursor = "default";
|
|
2588
|
-
if (Number.isInteger(
|
|
3119
|
+
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
2589
3120
|
requestAnimationFrame(() => {
|
|
2590
3121
|
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
2591
3122
|
});
|
|
@@ -2594,21 +3125,22 @@ function Table({
|
|
|
2594
3125
|
}, 0);
|
|
2595
3126
|
return;
|
|
2596
3127
|
}
|
|
2597
|
-
const
|
|
2598
|
-
const targetIndex = columnDragPreviewRef.current?.targetIndex ?? (Number.isInteger(rawTargetIndex) ? getColumnDropIndex(sourceIndex, rawTargetIndex, target?.columnEdge) : rawTargetIndex);
|
|
3128
|
+
const validDrop = validColumnDropRef.current;
|
|
2599
3129
|
canvas.style.cursor = "default";
|
|
2600
3130
|
setDragGuide(null);
|
|
3131
|
+
setColumnDropTarget(null);
|
|
2601
3132
|
columnDragPreviewRef.current = null;
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
3133
|
+
validColumnDropRef.current = null;
|
|
3134
|
+
if (validDrop) {
|
|
3135
|
+
applyColumnOrder(
|
|
3136
|
+
validDrop.sourceIndex - utilityColumnCount,
|
|
3137
|
+
validDrop.targetIndex - utilityColumnCount,
|
|
2606
3138
|
{
|
|
2607
|
-
type:
|
|
3139
|
+
type: validDrop.headerKind,
|
|
2608
3140
|
sourceKey: String(source.data.sourceKey),
|
|
2609
|
-
targetKey:
|
|
2610
|
-
parentKey:
|
|
2611
|
-
placement: getColumnDropPlacement(sourceIndex, rawTargetIndex,
|
|
3141
|
+
targetKey: validDrop.targetKey,
|
|
3142
|
+
parentKey: validDrop.parentKey,
|
|
3143
|
+
placement: getColumnDropPlacement(validDrop.sourceIndex, validDrop.rawTargetIndex, validDrop.columnEdge)
|
|
2612
3144
|
}
|
|
2613
3145
|
);
|
|
2614
3146
|
}
|
|
@@ -2620,6 +3152,7 @@ function Table({
|
|
|
2620
3152
|
const cleanupDrop = dropTargetForElements({
|
|
2621
3153
|
element: canvas,
|
|
2622
3154
|
canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
|
|
3155
|
+
getDropEffect: () => "move",
|
|
2623
3156
|
getData: ({ input, element, source }) => {
|
|
2624
3157
|
if (source.data.type === "table-row") {
|
|
2625
3158
|
const targetIndex2 = locateRow(input.clientY);
|
|
@@ -2628,7 +3161,8 @@ function Table({
|
|
|
2628
3161
|
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
2629
3162
|
return attachClosestEdge({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
2630
3163
|
}
|
|
2631
|
-
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);
|
|
2632
3166
|
if (!targetCell) return { targetIndex: -1 };
|
|
2633
3167
|
let targetIndex = targetCell.startIndex;
|
|
2634
3168
|
const targetFixed = columns[targetCell.startIndex]?.fixed;
|
|
@@ -2645,6 +3179,7 @@ function Table({
|
|
|
2645
3179
|
const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
|
|
2646
3180
|
return attachClosestEdge({
|
|
2647
3181
|
targetIndex,
|
|
3182
|
+
targetEndIndex: targetCell.endIndex,
|
|
2648
3183
|
targetKey: targetCell.key,
|
|
2649
3184
|
parentKey: targetCell.parentKey,
|
|
2650
3185
|
headerKind,
|
|
@@ -2656,10 +3191,11 @@ function Table({
|
|
|
2656
3191
|
}
|
|
2657
3192
|
});
|
|
2658
3193
|
return () => {
|
|
3194
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
2659
3195
|
cleanupDrag();
|
|
2660
3196
|
cleanupDrop();
|
|
2661
3197
|
};
|
|
2662
|
-
}, [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]);
|
|
2663
3199
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
2664
3200
|
const canvas = canvasRef.current;
|
|
2665
3201
|
if (!canvas) return null;
|
|
@@ -2967,18 +3503,28 @@ function Table({
|
|
|
2967
3503
|
const editorStyle = useMemo(() => {
|
|
2968
3504
|
if (!editing) return void 0;
|
|
2969
3505
|
const metric = metrics[editing.columnIndex];
|
|
2970
|
-
const
|
|
3506
|
+
const column = columns[editing.columnIndex];
|
|
3507
|
+
if (!metric || !column) return void 0;
|
|
3508
|
+
const fixedSide = column.fixed;
|
|
2971
3509
|
const span = getCellSpan(editing.rowIndex, editing.columnIndex);
|
|
2972
3510
|
const cellWidth = getCellDisplayWidth(editing.columnIndex, span?.colSpan ?? 1);
|
|
2973
3511
|
const cellHeight = rowHeight * (span?.rowSpan ?? 1);
|
|
2974
3512
|
const cellLeft = fixedSide === "left" ? leftFixedOffsets.get(editing.columnIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(editing.columnIndex) ?? 0) - metric.width : getScrollableColumnLeft(editing.columnIndex) - scrollRef.current.left;
|
|
3513
|
+
const cellTop = bodyTop + editing.rowIndex * rowHeight - scrollRef.current.top;
|
|
3514
|
+
const horizontalStart = fixedSide === void 0 ? fixedWidth : 0;
|
|
3515
|
+
const horizontalEnd = fixedSide === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
3516
|
+
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
3517
|
+
const visibleLeft = Math.max(cellLeft, horizontalStart);
|
|
3518
|
+
const visibleRight = Math.min(cellLeft + cellWidth, horizontalEnd, viewport.width);
|
|
3519
|
+
const visibleTop = Math.max(cellTop, verticalStart);
|
|
3520
|
+
const visibleBottom = Math.min(cellTop + cellHeight, renderHeight);
|
|
2975
3521
|
return {
|
|
2976
|
-
left:
|
|
2977
|
-
top:
|
|
2978
|
-
width:
|
|
2979
|
-
height:
|
|
3522
|
+
left: visibleLeft,
|
|
3523
|
+
top: visibleTop,
|
|
3524
|
+
width: Math.max(0, visibleRight - visibleLeft),
|
|
3525
|
+
height: Math.max(0, visibleBottom - visibleTop)
|
|
2980
3526
|
};
|
|
2981
|
-
}, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, rowHeight, viewport.width]);
|
|
3527
|
+
}, [bodyTop, columns, editing, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, leftFixedOffsets, metrics, renderHeight, rightFixedOffsets, rightFixedWidth, rowHeight, viewport.width]);
|
|
2982
3528
|
const handleColumnPointerDown = useCallback2((event) => {
|
|
2983
3529
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
2984
3530
|
const localY = event.clientY - rect.top;
|
|
@@ -2998,9 +3544,10 @@ function Table({
|
|
|
2998
3544
|
columnIndex: resizeIndex,
|
|
2999
3545
|
startX: event.clientX,
|
|
3000
3546
|
startWidth: startWidths.reduce((total, width2) => total + width2, 0),
|
|
3001
|
-
startGuideX,
|
|
3002
3547
|
guideTop: headerRowOffsets[resizeCell.level] ?? 0,
|
|
3003
3548
|
resizeEdge,
|
|
3549
|
+
resizeStartIndex: resizeCell.startIndex,
|
|
3550
|
+
resizeEndIndex: resizeCell.endIndex,
|
|
3004
3551
|
resizeIndices,
|
|
3005
3552
|
startWidths
|
|
3006
3553
|
};
|
|
@@ -3017,6 +3564,12 @@ function Table({
|
|
|
3017
3564
|
const minWidth = getMinimumColumnWidth(column, columnDraggable);
|
|
3018
3565
|
const pointerDelta = Math.round(event.clientX - drag.startX);
|
|
3019
3566
|
const delta = drag.resizeEdge === "left" ? -pointerDelta : pointerDelta;
|
|
3567
|
+
const setGuideFromWidths = (nextWidths) => {
|
|
3568
|
+
const widthByIndex = new Map(drag.resizeIndices.map((columnIndex, index) => [columnIndex, nextWidths[index]]));
|
|
3569
|
+
const nextColumns = columns.map((column2, index) => widthByIndex.has(index) ? { ...column2, width: widthByIndex.get(index) } : column2);
|
|
3570
|
+
const nextMetrics = buildColumnMetrics(nextColumns, { columnDraggable, viewportWidth: viewport.width });
|
|
3571
|
+
setResizeGuideX(getHeaderCellEdgeFromMetrics(drag.resizeStartIndex, drag.resizeEndIndex, drag.resizeEdge, nextMetrics));
|
|
3572
|
+
};
|
|
3020
3573
|
if (drag.resizeIndices.length > 1) {
|
|
3021
3574
|
const minWidths = drag.resizeIndices.map((index) => getMinimumColumnWidth(columns[index], columnDraggable));
|
|
3022
3575
|
const minTotalWidth = minWidths.reduce((total, width3) => total + width3, 0);
|
|
@@ -3033,13 +3586,13 @@ function Table({
|
|
|
3033
3586
|
drag.resizeIndices.forEach((columnIndex, index) => {
|
|
3034
3587
|
resizeColumn(columns[columnIndex].key, nextWidths[index]);
|
|
3035
3588
|
});
|
|
3036
|
-
|
|
3589
|
+
setGuideFromWidths(nextWidths);
|
|
3037
3590
|
return;
|
|
3038
3591
|
}
|
|
3039
3592
|
const width2 = Math.max(minWidth, Math.round(drag.startWidth + delta));
|
|
3040
3593
|
resizeColumn(column.key, width2);
|
|
3041
|
-
|
|
3042
|
-
}, [columnDraggable, columns, resizeColumn]);
|
|
3594
|
+
setGuideFromWidths([width2]);
|
|
3595
|
+
}, [columnDraggable, columns, getHeaderCellEdgeFromMetrics, resizeColumn, viewport.width]);
|
|
3043
3596
|
const handleColumnPointerUp = useCallback2((event) => {
|
|
3044
3597
|
const drag = columnDragRef.current;
|
|
3045
3598
|
if (!drag) return;
|
|
@@ -3049,19 +3602,14 @@ function Table({
|
|
|
3049
3602
|
setResizeGuideTop(0);
|
|
3050
3603
|
}, []);
|
|
3051
3604
|
const queueSortStateChange = useCallback2((next) => {
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
sortDebounceRef.current = setTimeout(() => {
|
|
3055
|
-
sortDebounceRef.current = null;
|
|
3056
|
-
onSortStateChange?.(next);
|
|
3057
|
-
}, 200);
|
|
3058
|
-
}, [onSortStateChange]);
|
|
3605
|
+
setSortState(next);
|
|
3606
|
+
}, []);
|
|
3059
3607
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3060
3608
|
const column = columns[columnIndex];
|
|
3061
3609
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3062
3610
|
const top = headerLeafTop + (headerLeafHeight - 14) / 2;
|
|
3063
3611
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3064
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3612
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? HEADER_ACTION_SLOT_WIDTH : 2);
|
|
3065
3613
|
const icons = [];
|
|
3066
3614
|
if (visibleActions.drag) {
|
|
3067
3615
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
@@ -3071,11 +3619,11 @@ function Table({
|
|
|
3071
3619
|
}
|
|
3072
3620
|
if (visibleActions.sort) {
|
|
3073
3621
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3074
|
-
const direction =
|
|
3622
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3075
3623
|
icons.push(
|
|
3076
3624
|
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - 16, top }, direction }, "sort")
|
|
3077
3625
|
);
|
|
3078
|
-
right -=
|
|
3626
|
+
right -= HEADER_ACTION_SLOT_WIDTH;
|
|
3079
3627
|
}
|
|
3080
3628
|
if (visibleActions.filter) {
|
|
3081
3629
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
@@ -3102,7 +3650,7 @@ function Table({
|
|
|
3102
3650
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3103
3651
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3104
3652
|
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3105
|
-
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;
|
|
3106
3654
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3107
3655
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3108
3656
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3121,7 +3669,7 @@ function Table({
|
|
|
3121
3669
|
anchorLeft = anchorX;
|
|
3122
3670
|
label = labels.dragColumn;
|
|
3123
3671
|
} else if (action === "sort") {
|
|
3124
|
-
const direction =
|
|
3672
|
+
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3125
3673
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3126
3674
|
anchorX = cellLeft + cellWidth - 22;
|
|
3127
3675
|
anchorLeft = anchorX;
|
|
@@ -3141,7 +3689,7 @@ function Table({
|
|
|
3141
3689
|
label,
|
|
3142
3690
|
placement
|
|
3143
3691
|
};
|
|
3144
|
-
}, [baseHeaderHeight, columnDraggable, columns,
|
|
3692
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3145
3693
|
const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
|
|
3146
3694
|
const canvas = canvasRef.current;
|
|
3147
3695
|
if (!canvas) return false;
|
|
@@ -3156,7 +3704,7 @@ function Table({
|
|
|
3156
3704
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3157
3705
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3158
3706
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3159
|
-
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;
|
|
3160
3708
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3161
3709
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3162
3710
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
@@ -3396,7 +3944,9 @@ function Table({
|
|
|
3396
3944
|
});
|
|
3397
3945
|
setPendingInserts((current) => [...current, pending]);
|
|
3398
3946
|
try {
|
|
3399
|
-
|
|
3947
|
+
const nextRows = sourceRows.slice();
|
|
3948
|
+
nextRows.splice(insertIndex, 0, ...insertedRows);
|
|
3949
|
+
await Promise.resolve(onInsertRows(nextRows, insertedRows));
|
|
3400
3950
|
await waitForPaint();
|
|
3401
3951
|
setInsertBusy(false);
|
|
3402
3952
|
} catch (error) {
|
|
@@ -3423,28 +3973,10 @@ function Table({
|
|
|
3423
3973
|
const currentScrollTop = scrollRef.current.top;
|
|
3424
3974
|
const top = (fixedHeader ? 0 : bodyTop) + rowIndex * rowHeight - currentScrollTop;
|
|
3425
3975
|
if (column.rowSelection) {
|
|
3426
|
-
|
|
3427
|
-
return /* @__PURE__ */ jsx7(
|
|
3428
|
-
"div",
|
|
3429
|
-
{
|
|
3430
|
-
className: "rvg-row-selection-icon",
|
|
3431
|
-
style: { left, top, width: cellWidth, height: cellHeight, opacity: isDraggedSource ? 0 : 1, transform: `translateY(${dragOffset}px)` },
|
|
3432
|
-
children: /* @__PURE__ */ jsx7(SelectionIcon, { checked: selectedRowKeySet.has(rowKey2), radio: rowSelectionMode === "single" })
|
|
3433
|
-
},
|
|
3434
|
-
`selection:${String(rowKey2)}`
|
|
3435
|
-
);
|
|
3976
|
+
return null;
|
|
3436
3977
|
}
|
|
3437
3978
|
if (column.rowDragHandle) {
|
|
3438
|
-
return
|
|
3439
|
-
"div",
|
|
3440
|
-
{
|
|
3441
|
-
className: "rvg-row-drag-icon",
|
|
3442
|
-
style: { left, top, width: cellWidth, height: cellHeight, opacity: isDraggedSource ? 0 : 1, transform: `translateY(${dragOffset}px)` },
|
|
3443
|
-
"aria-hidden": "true",
|
|
3444
|
-
children: /* @__PURE__ */ jsx7(RowDragHandleIcon, {})
|
|
3445
|
-
},
|
|
3446
|
-
`drag:${String(getRowKey(rows[rowIndex], rowIndex))}`
|
|
3447
|
-
);
|
|
3979
|
+
return null;
|
|
3448
3980
|
}
|
|
3449
3981
|
if (column.renderCell && !(editing?.rowIndex === rowIndex && editing.columnIndex === columnIndex)) {
|
|
3450
3982
|
const row = rows[rowIndex];
|
|
@@ -3471,6 +4003,7 @@ function Table({
|
|
|
3471
4003
|
};
|
|
3472
4004
|
const renderHeaderTitle = (columnIndex, left) => {
|
|
3473
4005
|
const column = columns[columnIndex];
|
|
4006
|
+
const isDropTarget = Boolean(columnDropTarget && columnIndex >= columnDropTarget.startIndex && columnIndex <= columnDropTarget.endIndex);
|
|
3474
4007
|
const currentScrollTop = scrollRef.current.top;
|
|
3475
4008
|
const headerTop = fixedHeader ? 0 : -currentScrollTop;
|
|
3476
4009
|
const leafTop = headerTop + headerLeafTop;
|
|
@@ -3478,7 +4011,7 @@ function Table({
|
|
|
3478
4011
|
return /* @__PURE__ */ jsx7(
|
|
3479
4012
|
"div",
|
|
3480
4013
|
{
|
|
3481
|
-
className:
|
|
4014
|
+
className: `rvg-header-title${isDropTarget ? " is-drop-target" : ""}`,
|
|
3482
4015
|
style: { left, top: headerTop, width: metrics[columnIndex].width, height: headerHeight, justifyContent: "center", padding: 0, textAlign: "center" },
|
|
3483
4016
|
children: /* @__PURE__ */ jsx7("span", { children: column.title })
|
|
3484
4017
|
},
|
|
@@ -3501,11 +4034,11 @@ function Table({
|
|
|
3501
4034
|
}
|
|
3502
4035
|
if (column.renderHeader) {
|
|
3503
4036
|
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3504
|
-
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;
|
|
3505
4038
|
return /* @__PURE__ */ jsx7(
|
|
3506
4039
|
"div",
|
|
3507
4040
|
{
|
|
3508
|
-
className:
|
|
4041
|
+
className: `rvg-header-title is-custom${isDropTarget ? " is-drop-target" : ""}`,
|
|
3509
4042
|
"data-level": headerDepth - 1,
|
|
3510
4043
|
"data-measure-key": column.key,
|
|
3511
4044
|
style: {
|
|
@@ -3546,11 +4079,12 @@ function Table({
|
|
|
3546
4079
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
3547
4080
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
3548
4081
|
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
3549
|
-
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);
|
|
3550
4084
|
return /* @__PURE__ */ jsxs7(
|
|
3551
4085
|
"div",
|
|
3552
4086
|
{
|
|
3553
|
-
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" : ""}`,
|
|
3554
4088
|
"data-level": cell.level,
|
|
3555
4089
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
3556
4090
|
style: {
|
|
@@ -3606,6 +4140,7 @@ function Table({
|
|
|
3606
4140
|
})();
|
|
3607
4141
|
const selectionOutlineStyle = (() => {
|
|
3608
4142
|
if (!selection || selectionRange) return null;
|
|
4143
|
+
if (rowDragPreview?.sourceIndex === selection.rowIndex) return null;
|
|
3609
4144
|
const row = rows[selection.rowIndex];
|
|
3610
4145
|
const metric = metrics[selection.columnIndex];
|
|
3611
4146
|
const column = columns[selection.columnIndex];
|
|
@@ -3615,22 +4150,37 @@ function Table({
|
|
|
3615
4150
|
const rawRight = rawLeft + getCellDisplayWidth(selection.columnIndex, span?.colSpan ?? 1);
|
|
3616
4151
|
const rawTop = bodyTop + selection.rowIndex * rowHeight - scrollPosition.top;
|
|
3617
4152
|
const rawBottom = rawTop + rowHeight * (span?.rowSpan ?? 1);
|
|
4153
|
+
const dragOffset = getRowDragOffset(selection.rowIndex);
|
|
3618
4154
|
const horizontalStart = column.fixed === void 0 ? fixedWidth : 0;
|
|
3619
4155
|
const horizontalEnd = column.fixed === void 0 ? viewport.width - rightFixedWidth : viewport.width;
|
|
3620
4156
|
const verticalStart = fixedHeader ? bodyTop : 0;
|
|
3621
|
-
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;
|
|
3622
4158
|
const borderWidth = 2;
|
|
3623
|
-
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart
|
|
4159
|
+
const left = Math.round(Math.max(rawLeft - borderWidth, horizontalStart));
|
|
3624
4160
|
const right = Math.round(Math.min(rawRight + 1, horizontalEnd, viewport.width));
|
|
3625
|
-
const top = Math.round(Math.max(rawTop - borderWidth, verticalStart
|
|
4161
|
+
const top = Math.round(Math.max(rawTop - borderWidth, verticalStart));
|
|
3626
4162
|
const bottom = Math.round(Math.min(rawBottom + 1, renderHeight));
|
|
3627
4163
|
return {
|
|
3628
4164
|
left,
|
|
3629
4165
|
top,
|
|
3630
4166
|
width: Math.max(0, right - left),
|
|
3631
|
-
height: Math.max(0, bottom - top)
|
|
4167
|
+
height: Math.max(0, bottom - top),
|
|
4168
|
+
transform: `translateY(${dragOffset}px)`
|
|
3632
4169
|
};
|
|
3633
4170
|
})();
|
|
4171
|
+
const selectionEdgeIndicator = getSelectionEdgeIndicator(scrollPosition.left, scrollPosition.top);
|
|
4172
|
+
const selectionEdgeStyle = selectionEdgeIndicator ? {
|
|
4173
|
+
...selectionEdgeIndicator.style,
|
|
4174
|
+
...selectionEdgeIndicator.corner ? {
|
|
4175
|
+
"--rvg-corner-width": `${selectionEdgeIndicator.corner.width}px`,
|
|
4176
|
+
"--rvg-corner-height": `${selectionEdgeIndicator.corner.height}px`,
|
|
4177
|
+
"--rvg-corner-hover-width-extension": "4px",
|
|
4178
|
+
"--rvg-corner-hover-height-extension": "4px"
|
|
4179
|
+
} : null
|
|
4180
|
+
} : void 0;
|
|
4181
|
+
useLayoutEffect2(() => {
|
|
4182
|
+
syncSelectionEdgeTarget(scrollPosition.left, scrollPosition.top);
|
|
4183
|
+
}, [scrollPosition.left, scrollPosition.top, syncSelectionEdgeTarget]);
|
|
3634
4184
|
const handleContextMenu = (event) => {
|
|
3635
4185
|
event.preventDefault();
|
|
3636
4186
|
event.stopPropagation();
|
|
@@ -3774,6 +4324,10 @@ function Table({
|
|
|
3774
4324
|
className: "rvg-canvas",
|
|
3775
4325
|
style: { width: viewport.width, height: renderHeight },
|
|
3776
4326
|
onMouseMove: (event) => {
|
|
4327
|
+
if (document.documentElement.classList.contains("rvg-is-dragging")) {
|
|
4328
|
+
hideDragTooltips();
|
|
4329
|
+
return;
|
|
4330
|
+
}
|
|
3777
4331
|
if (columnDragRef.current) return;
|
|
3778
4332
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
3779
4333
|
const localY = event.clientY - rect.top;
|
|
@@ -3876,6 +4430,14 @@ function Table({
|
|
|
3876
4430
|
}
|
|
3877
4431
|
},
|
|
3878
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
|
+
}
|
|
3879
4441
|
handleColumnPointerDown(event);
|
|
3880
4442
|
beginRangeDrag(event);
|
|
3881
4443
|
},
|
|
@@ -3884,10 +4446,12 @@ function Table({
|
|
|
3884
4446
|
updateRangeDrag(event);
|
|
3885
4447
|
},
|
|
3886
4448
|
onPointerUp: (event) => {
|
|
4449
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3887
4450
|
handleColumnPointerUp(event);
|
|
3888
4451
|
endRangeDrag(event);
|
|
3889
4452
|
},
|
|
3890
4453
|
onPointerCancel: (event) => {
|
|
4454
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3891
4455
|
handleColumnPointerUp(event);
|
|
3892
4456
|
endRangeDrag(event);
|
|
3893
4457
|
},
|
|
@@ -3906,7 +4470,7 @@ function Table({
|
|
|
3906
4470
|
const action = locateHeaderAction(event.clientX, columnIndex);
|
|
3907
4471
|
if (action === "sort") {
|
|
3908
4472
|
const columnKey = columns[columnIndex].key;
|
|
3909
|
-
const next =
|
|
4473
|
+
const next = sortState?.columnKey !== columnKey ? { columnKey, direction: "asc" } : sortState.direction === "asc" ? { columnKey, direction: "desc" } : null;
|
|
3910
4474
|
queueSortStateChange(next);
|
|
3911
4475
|
return;
|
|
3912
4476
|
}
|
|
@@ -4078,6 +4642,27 @@ function Table({
|
|
|
4078
4642
|
}
|
|
4079
4643
|
),
|
|
4080
4644
|
selectionOutlineStyle && /* @__PURE__ */ jsx7("div", { ref: selectionFocusRef, className: "rvg-selection-focus", style: selectionOutlineStyle, "aria-hidden": "true" }),
|
|
4645
|
+
selectionEdgeIndicator && selection && /* @__PURE__ */ jsx7(
|
|
4646
|
+
"button",
|
|
4647
|
+
{
|
|
4648
|
+
ref: selectionEdgeTargetRef,
|
|
4649
|
+
type: "button",
|
|
4650
|
+
className: `rvg-selection-edge-target is-${selectionEdgeIndicator.orientation} is-${selectionEdgeIndicator.side}${selectionEdgeIndicator.viewportEdge ? ` is-viewport-${selectionEdgeIndicator.viewportEdge}` : ""}`,
|
|
4651
|
+
style: selectionEdgeStyle,
|
|
4652
|
+
"aria-label": labels.revealSelectedCell,
|
|
4653
|
+
title: labels.revealSelectedCell,
|
|
4654
|
+
onPointerDown: (event) => {
|
|
4655
|
+
event.preventDefault();
|
|
4656
|
+
event.stopPropagation();
|
|
4657
|
+
},
|
|
4658
|
+
onClick: (event) => {
|
|
4659
|
+
event.stopPropagation();
|
|
4660
|
+
scrollerRef.current?.focus({ preventScroll: true });
|
|
4661
|
+
revealCell(selection);
|
|
4662
|
+
},
|
|
4663
|
+
children: /* @__PURE__ */ jsx7("span", { className: "rvg-selection-edge-halo", "aria-hidden": "true", children: /* @__PURE__ */ jsx7("svg", { viewBox: "0 0 100 100", preserveAspectRatio: "none", children: /* @__PURE__ */ jsx7("path", { d: "M 0 100 L 0 0 L 100 0" }) }) })
|
|
4664
|
+
}
|
|
4665
|
+
),
|
|
4081
4666
|
contextMenu && /* @__PURE__ */ jsx7("div", { ref: contextMenuRef, className: "rvg-context-menu", role: "menu", style: { left: contextMenu.left, top: contextMenu.top }, children: contextMenu.type === "header" ? (() => {
|
|
4082
4667
|
const column = columns[contextMenu.columnIndex];
|
|
4083
4668
|
const headerContext = { column, columnIndex: contextMenu.columnIndex };
|
|
@@ -4235,12 +4820,12 @@ function Table({
|
|
|
4235
4820
|
/* @__PURE__ */ jsx7("span", { children: labels.rowUnit })
|
|
4236
4821
|
] });
|
|
4237
4822
|
if (item === "move-up") {
|
|
4238
|
-
if (!rowDraggable
|
|
4239
|
-
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" }) });
|
|
4240
4825
|
}
|
|
4241
4826
|
if (item === "move-down") {
|
|
4242
|
-
if (!rowDraggable
|
|
4243
|
-
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" }) });
|
|
4244
4829
|
}
|
|
4245
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" }) });
|
|
4246
4831
|
return null;
|
|
@@ -4272,21 +4857,30 @@ function Table({
|
|
|
4272
4857
|
await Promise.resolve(onCellChange?.({ ...confirmAction.cell, row: confirmAction.row, previousValue: confirmAction.previousValue, value: "" }));
|
|
4273
4858
|
} else {
|
|
4274
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)));
|
|
4275
4863
|
setConfirmAction(null);
|
|
4276
4864
|
setConfirmLoading(false);
|
|
4865
|
+
setPendingDeletedRowKeys((current) => {
|
|
4866
|
+
const next = new Set(current);
|
|
4867
|
+
deletingKeys.forEach((key) => next.add(key));
|
|
4868
|
+
return next;
|
|
4869
|
+
});
|
|
4277
4870
|
if (onDeleteRows) {
|
|
4278
4871
|
setDeleteBusy(true);
|
|
4279
4872
|
try {
|
|
4280
|
-
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;
|
|
4281
4881
|
} finally {
|
|
4282
4882
|
setDeleteBusy(false);
|
|
4283
4883
|
}
|
|
4284
|
-
} else {
|
|
4285
|
-
setPendingDeletedRowKeys((current) => {
|
|
4286
|
-
const next = new Set(current);
|
|
4287
|
-
deletingKeys.forEach((key) => next.add(key));
|
|
4288
|
-
return next;
|
|
4289
|
-
});
|
|
4290
4884
|
}
|
|
4291
4885
|
return;
|
|
4292
4886
|
}
|
|
@@ -4359,7 +4953,7 @@ function Table({
|
|
|
4359
4953
|
const next = { ...filterValues };
|
|
4360
4954
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4361
4955
|
else delete next[key];
|
|
4362
|
-
|
|
4956
|
+
setFilterValues(next);
|
|
4363
4957
|
setFilterEditor(null);
|
|
4364
4958
|
}
|
|
4365
4959
|
}
|
|
@@ -4370,7 +4964,7 @@ function Table({
|
|
|
4370
4964
|
const key = columns[filterEditor.columnIndex].key;
|
|
4371
4965
|
const next = { ...filterValues };
|
|
4372
4966
|
delete next[key];
|
|
4373
|
-
|
|
4967
|
+
setFilterValues(next);
|
|
4374
4968
|
setFilterEditor(null);
|
|
4375
4969
|
}, children: labels.reset }),
|
|
4376
4970
|
/* @__PURE__ */ jsx7("button", { type: "button", className: "rvg-filter-confirm", onClick: () => {
|
|
@@ -4378,7 +4972,7 @@ function Table({
|
|
|
4378
4972
|
const next = { ...filterValues };
|
|
4379
4973
|
if (filterEditor.draft) next[key] = filterEditor.draft;
|
|
4380
4974
|
else delete next[key];
|
|
4381
|
-
|
|
4975
|
+
setFilterValues(next);
|
|
4382
4976
|
setFilterEditor(null);
|
|
4383
4977
|
}, children: labels.confirm })
|
|
4384
4978
|
] })
|
|
@@ -4402,8 +4996,8 @@ function Table({
|
|
|
4402
4996
|
column.key
|
|
4403
4997
|
);
|
|
4404
4998
|
}) }, rowIndex)),
|
|
4405
|
-
fixedWidth > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-loading-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
4406
|
-
rightFixedWidth > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-loading-fixed-shadow is-right", style: { right: rightFixedWidth } })
|
|
4999
|
+
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-loading-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
5000
|
+
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ jsx7("div", { className: "rvg-loading-fixed-shadow is-right", style: { right: rightFixedWidth } })
|
|
4407
5001
|
] }),
|
|
4408
5002
|
loading && !hasCustomLoading && hasCompletedLoadRef.current && /* @__PURE__ */ jsx7("div", { className: "rvg-refresh-loading", "aria-label": labels.refreshing, children: /* @__PURE__ */ jsx7(LoadingSpinnerIcon, {}) })
|
|
4409
5003
|
] });
|