@lensui/lens-table 0.1.5 → 0.1.7

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