@lensui/lens-table 0.1.22 → 0.1.24

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.js CHANGED
@@ -716,48 +716,6 @@ function createRowDragHandleSvg() {
716
716
  }
717
717
  return svg;
718
718
  }
719
- function createHeaderDragHandleSvg() {
720
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
721
- svg.setAttribute("viewBox", "0 0 14 14");
722
- svg.setAttribute("aria-hidden", "true");
723
- for (const cy of [2.5, 7, 11.5]) {
724
- const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
725
- circle.setAttribute("cx", "7");
726
- circle.setAttribute("cy", String(cy));
727
- circle.setAttribute("r", "1.25");
728
- svg.appendChild(circle);
729
- }
730
- return svg;
731
- }
732
- function createHeaderSortSvg(direction) {
733
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
734
- svg.setAttribute("viewBox", "0 0 14 14");
735
- svg.setAttribute("aria-hidden", "true");
736
- for (const [value, active] of [
737
- ["M3 5.5 7 1.5l4 4Z", direction === "asc"],
738
- ["M3 8.5 7 12.5l4-4Z", direction === "desc"]
739
- ]) {
740
- const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
741
- path.setAttribute("d", value);
742
- if (active) path.classList.add("is-active");
743
- svg.appendChild(path);
744
- }
745
- return svg;
746
- }
747
- function createHeaderSearchSvg(active) {
748
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
749
- svg.setAttribute("viewBox", "0 0 14 14");
750
- svg.setAttribute("aria-hidden", "true");
751
- if (active) svg.classList.add("is-active");
752
- const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
753
- circle.setAttribute("cx", "5.5");
754
- circle.setAttribute("cy", "5.5");
755
- circle.setAttribute("r", "4.25");
756
- const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
757
- path.setAttribute("d", "m8.75 8.75 2.25 2.25");
758
- svg.append(circle, path);
759
- return svg;
760
- }
761
719
 
762
720
  // src/Table.tsx
763
721
  import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
@@ -811,7 +769,6 @@ function getMinimumColumnWidth(column, columnDraggable = false) {
811
769
  function buildColumnMetrics(columns, columnDraggableOrOptions = false) {
812
770
  const options = typeof columnDraggableOrOptions === "boolean" ? { columnDraggable: columnDraggableOrOptions } : columnDraggableOrOptions;
813
771
  const columnDraggable = options.columnDraggable ?? false;
814
- const stretchExcludedIndices = options.stretchExcludedIndices ?? /* @__PURE__ */ new Set();
815
772
  let left = 0;
816
773
  const metrics = columns.map((column) => {
817
774
  const width = Math.max(getMinimumColumnWidth(column, columnDraggable), column.width ?? DEFAULT_COLUMN_WIDTH);
@@ -821,10 +778,9 @@ function buildColumnMetrics(columns, columnDraggableOrOptions = false) {
821
778
  });
822
779
  const viewportWidth = options.viewportWidth ?? 0;
823
780
  if (viewportWidth <= left || columns.length === 0) return metrics;
824
- const unsetWidthStretchable = columns.map((column, index) => ({ column, index })).filter(({ column, index }) => !stretchExcludedIndices.has(index) && column.width === void 0 && column.fixed === void 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
825
- const allDataStretchable = columns.map((column, index) => ({ column, index })).filter(({ column }) => column.fixed === void 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
826
- const dataStretchable = allDataStretchable.filter(({ index }) => !stretchExcludedIndices.has(index));
827
- const targets = unsetWidthStretchable.length > 0 ? unsetWidthStretchable : dataStretchable.length > 0 ? dataStretchable : allDataStretchable.slice(-1);
781
+ const unsetWidthStretchable = columns.map((column, index) => ({ column, index })).filter(({ column }) => column.width === void 0 && column.fixed === void 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
782
+ const dataStretchable = columns.map((column, index) => ({ column, index })).filter(({ column }) => column.fixed === void 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
783
+ const targets = unsetWidthStretchable.length > 0 ? unsetWidthStretchable : dataStretchable.length > 0 ? dataStretchable : [];
828
784
  if (targets.length === 0) return metrics;
829
785
  const extra = viewportWidth - left;
830
786
  const baseTotal = targets.reduce((sum, { index }) => sum + metrics[index].width, 0);
@@ -963,6 +919,8 @@ function paintGrid(options) {
963
919
  const getColumnX = (index) => {
964
920
  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;
965
921
  };
922
+ const displayedContentRight = columns.reduce((right, _column, index) => Math.max(right, getColumnX(index) + metrics[index].width), 0);
923
+ const trailingBlankStart = displayedContentRight > 0 && displayedContentRight < width ? displayedContentRight : null;
966
924
  const getRowDragOffset = (rowIndex) => {
967
925
  if (!rowDragPreview || rowIndex === rowDragPreview.sourceIndex) return 0;
968
926
  if (rowDragPreview.sourceIndex < rowDragPreview.targetIndex) {
@@ -971,6 +929,15 @@ function paintGrid(options) {
971
929
  return rowIndex >= rowDragPreview.targetIndex && rowIndex < rowDragPreview.sourceIndex ? rowHeight : 0;
972
930
  };
973
931
  const rowBelowDragGap = rowDragPreview ? rowDragPreview.sourceIndex <= rowDragPreview.targetIndex ? rowDragPreview.targetIndex + 1 : rowDragPreview.targetIndex : -1;
932
+ if (striped && trailingBlankStart !== null) {
933
+ const rowStart = Math.max(0, range.rowStart);
934
+ for (let rowIndex = rowStart; rowIndex < range.rowEnd; rowIndex += 1) {
935
+ if (rowIndex % 2 === 0 || rowDragPreview?.sourceIndex === rowIndex) continue;
936
+ const y = bodyTop + rowIndex * rowHeight - scrollTop + getRowDragOffset(rowIndex);
937
+ ctx.fillStyle = colors.stripe;
938
+ ctx.fillRect(trailingBlankStart, y, width - trailingBlankStart, rowHeight);
939
+ }
940
+ }
974
941
  const paintBodyColumns = (layer) => {
975
942
  const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
976
943
  for (let rowIndex = rowStart; rowIndex < range.rowEnd; rowIndex += 1) {
@@ -1286,6 +1253,10 @@ function paintGrid(options) {
1286
1253
  ctx.fillStyle = colors.grid;
1287
1254
  ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
1288
1255
  }
1256
+ if (!verticalBorderless && trailingBlankStart !== null) {
1257
+ ctx.fillStyle = colors.grid;
1258
+ ctx.fillRect(Math.round(trailingBlankStart) - 1, 0, 1, height);
1259
+ }
1289
1260
  ctx.fillStyle = colors.grid;
1290
1261
  if (!horizontalBorderless && !frameBorderless) ctx.fillRect(0, 0, width, 1);
1291
1262
  if (!verticalBorderless && !frameBorderless) {
@@ -1698,7 +1669,6 @@ function TableInner({
1698
1669
  const contextMenuEnabled = contextMenuConfig !== false;
1699
1670
  const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
1700
1671
  const [resizedColumnWidths, setResizedColumnWidths] = useState4({});
1701
- const [manuallyResizedColumnKeys, setManuallyResizedColumnKeys] = useState4(() => /* @__PURE__ */ new Set());
1702
1672
  const leafSourceColumns = useMemo(() => flattenDataColumns(sourceColumns), [sourceColumns]);
1703
1673
  const sourceColumnWidthsRef = useRef2(new Map(leafSourceColumns.map((column) => [column.key, column.width])));
1704
1674
  const showRowCheckbox = Boolean(rowSelection) && (typeof rowSelection !== "object" || rowSelection.showCheckbox !== false);
@@ -1752,6 +1722,7 @@ function TableInner({
1752
1722
  const rowAnchorRef = useRef2(null);
1753
1723
  const columnAnchorRef = useRef2(null);
1754
1724
  const columnDragRef = useRef2(null);
1725
+ const columnOrderDragRef = useRef2(null);
1755
1726
  const dragGuideRef = useRef2(null);
1756
1727
  const rowDragGuideRef = useRef2(null);
1757
1728
  const selectionFocusRef = useRef2(null);
@@ -1820,10 +1791,6 @@ function TableInner({
1820
1791
  const previousSourceWidths = sourceColumnWidthsRef.current;
1821
1792
  const nextSourceWidths = new Map(leafSourceColumns.map((column) => [column.key, column.width]));
1822
1793
  sourceColumnWidthsRef.current = nextSourceWidths;
1823
- setManuallyResizedColumnKeys((current) => {
1824
- const next = new Set([...current].filter((key) => nextSourceWidths.has(key) && previousSourceWidths.get(key) === nextSourceWidths.get(key)));
1825
- return next.size === current.size ? current : next;
1826
- });
1827
1794
  setResizedColumnWidths((current) => {
1828
1795
  const sourceColumnByKey = new Map(leafSourceColumns.map((column) => [column.key, column]));
1829
1796
  let changed = false;
@@ -2085,14 +2052,11 @@ function TableInner({
2085
2052
  if (selection?.rowKey === editing.rowKey && selection.columnKey === editing.columnKey) return;
2086
2053
  setEditing(null);
2087
2054
  }, [editing, selection]);
2088
- const stretchExcludedIndices = useMemo(() => new Set(
2089
- columns.flatMap((column, index) => manuallyResizedColumnKeys.has(column.key) ? [index] : [])
2090
- ), [columns, manuallyResizedColumnKeys]);
2055
+ const hasManualColumnWidths = Object.keys(resizedColumnWidths).length > 0;
2091
2056
  const metrics = useMemo(() => buildColumnMetrics(columns, {
2092
2057
  columnDraggable,
2093
- viewportWidth: viewport.width,
2094
- stretchExcludedIndices
2095
- }), [columnDraggable, columns, stretchExcludedIndices, viewport.width]);
2058
+ viewportWidth: hasManualColumnWidths ? 0 : viewport.width
2059
+ }), [columnDraggable, columns, hasManualColumnWidths, viewport.width]);
2096
2060
  const contentWidth = metrics.length > 0 ? metrics[metrics.length - 1].right : 0;
2097
2061
  const contentHeight = rows.length * rowHeight;
2098
2062
  const fixedWidth = useMemo(() => columns.reduce((width2, column, index) => column.fixed === "left" ? width2 + metrics[index].width : width2, 0), [columns, metrics]);
@@ -2868,6 +2832,10 @@ function TableInner({
2868
2832
  if (columns[columnIndex].fixed === "right") return viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metric.width;
2869
2833
  return getScrollableColumnLeft(columnIndex) - scrollRef.current.left;
2870
2834
  }, [columns, getScrollableColumnLeft, leftFixedOffsets, metrics, rightFixedOffsets, viewport.width]);
2835
+ const trailingColumnBorderLeft = useMemo(() => {
2836
+ const displayedContentRight = columns.reduce((right, _column, columnIndex) => Math.max(right, getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width), 0);
2837
+ return displayedContentRight > 0 && displayedContentRight < viewport.width ? Math.round(displayedContentRight) - 1 : null;
2838
+ }, [columns, getDisplayedColumnLeft, metrics, scrollPosition.left, viewport.width]);
2871
2839
  const getHeaderLevelAtY = useCallback2((localY, headerY) => {
2872
2840
  const y = localY - headerY;
2873
2841
  for (let level = 0; level < headerRowHeights.length; level += 1) {
@@ -2877,7 +2845,6 @@ function TableInner({
2877
2845
  return headerDepth - 1;
2878
2846
  }, [headerDepth, headerRowHeights, headerRowOffsets]);
2879
2847
  const resizeColumn = useCallback2((columnKey, width2) => {
2880
- setManuallyResizedColumnKeys((current) => current.has(columnKey) ? current : new Set(current).add(columnKey));
2881
2848
  setResizedColumnWidths((current) => current[columnKey] === width2 ? current : { ...current, [columnKey]: width2 });
2882
2849
  onColumnResize?.(columnKey, width2);
2883
2850
  }, [onColumnResize]);
@@ -3022,284 +2989,104 @@ function TableInner({
3022
2989
  }, [bodyTop, rowHeight, rows.length]);
3023
2990
  useEffect2(() => {
3024
2991
  const canvas = canvasRef.current;
3025
- if (!canvas || !columnDraggable && !rowDraggable) return;
3026
- const getColumnDropIndex = (sourceIndex, targetIndex, edge) => resolveColumnDropIndex(sourceIndex, targetIndex, edge, columns.length);
3027
- const getHeaderColumn = (clientX, clientY) => {
3028
- const rect = canvas.getBoundingClientRect();
3029
- const headerY = fixedHeader ? 0 : -scrollRef.current.top;
3030
- const localY = clientY - rect.top;
3031
- if (localY < headerY || localY >= headerY + headerHeight) return -1;
3032
- return locateColumn(clientX);
3033
- };
3034
- const getHeaderDragCell = (clientX, clientY) => {
3035
- const cell = locateHeaderCell(clientX, clientY);
3036
- if (!cell || locateHeaderResizeCell(clientX, clientY)) return null;
3037
- if (cell.leaf && locateHeaderAction(clientX, cell.startIndex)) return null;
3038
- return cell;
3039
- };
2992
+ if (!canvas || !rowDraggable) return;
3040
2993
  const cleanupDrag = draggable({
3041
2994
  element: canvas,
3042
2995
  canDrag: ({ input }) => {
3043
- const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
3044
- if (headerDragCell) return true;
3045
2996
  const columnIndex = locateColumn(input.clientX);
3046
- return rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
3047
- },
3048
- getInitialData: ({ input }) => {
3049
- const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
3050
- if (!headerDragCell) {
3051
- return { type: "table-row", sourceIndex: locateRow(input.clientY) };
3052
- }
3053
- const sourceIndex = headerDragCell.startIndex;
3054
- columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
3055
- validColumnDropRef.current = null;
3056
- return {
3057
- type: "table-column",
3058
- sourceIndex,
3059
- sourceKey: headerDragCell.key,
3060
- parentKey: headerDragCell.parentKey,
3061
- headerLevel: headerDragCell.level,
3062
- headerKind: headerDragCell.leaf ? "column" : "group",
3063
- fixed: columns[headerDragCell.startIndex]?.fixed
3064
- };
2997
+ return columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
3065
2998
  },
2999
+ getInitialData: ({ input }) => ({ type: "table-row", sourceIndex: locateRow(input.clientY) }),
3066
3000
  onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
3067
3001
  const sourceIndex = Number(source.data.sourceIndex);
3068
3002
  const canvasRect = canvas.getBoundingClientRect();
3069
3003
  const input = location.current.input;
3070
- const previewOffset = source.data.type === "table-row" ? {
3004
+ const previewOffset = {
3071
3005
  x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
3072
3006
  y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
3073
- } : {
3074
- x: Math.max(0, Math.min(metrics[sourceIndex].width, input.clientX - canvasRect.left - getDisplayedColumnLeft(sourceIndex))),
3075
- y: Math.max(0, Math.min(canvasRect.height, input.clientY - canvasRect.top))
3076
3007
  };
3077
3008
  setCustomNativeDragPreview({
3078
3009
  nativeSetDragImage,
3079
3010
  getOffset: () => previewOffset,
3080
3011
  render: ({ container }) => {
3081
- if (source.data.type === "table-row") {
3082
- const frame = document.createElement("div");
3083
- frame.className = "rvg-row-drag-preview-frame";
3084
- frame.style.width = `${canvasRect.width + 4}px`;
3085
- frame.style.height = `${rowHeight + 4}px`;
3086
- const preview2 = document.createElement("div");
3087
- preview2.className = "rvg-row-drag-preview";
3088
- preview2.style.width = `${canvasRect.width}px`;
3089
- preview2.style.height = `${rowHeight}px`;
3090
- const row = rows[sourceIndex];
3091
- const rowKey2 = getRowKey(row, sourceIndex);
3092
- columns.forEach((column2, columnIndex) => {
3093
- const left = getDisplayedColumnLeft(columnIndex);
3094
- const columnWidth2 = metrics[columnIndex].width;
3095
- if (left + columnWidth2 <= 0 || left >= canvasRect.width) return;
3096
- const cell = document.createElement("div");
3097
- cell.className = "rvg-row-drag-preview-cell";
3098
- cell.style.left = `${left}px`;
3099
- cell.style.width = `${columnWidth2}px`;
3100
- cell.style.justifyContent = column2.align === "right" ? "flex-end" : column2.align === "center" ? "center" : "flex-start";
3101
- if (column2.rowDragHandle) {
3102
- cell.appendChild(createRowDragHandleSvg());
3103
- } else if (column2.rowSelection) {
3104
- const checkbox = document.createElement("span");
3105
- checkbox.className = selectedRowKeySet.has(rowKey2) ? "rvg-preview-checkbox is-checked" : "rvg-preview-checkbox";
3106
- checkbox.textContent = selectedRowKeySet.has(rowKey2) ? "\u2713" : "";
3107
- cell.appendChild(checkbox);
3108
- } else {
3109
- cell.textContent = getCellLabel(sourceIndex, columnIndex);
3110
- }
3111
- if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
3112
- cell.classList.add("is-selected");
3113
- }
3114
- preview2.appendChild(cell);
3115
- });
3116
- frame.appendChild(preview2);
3117
- container.appendChild(frame);
3118
- return () => frame.remove();
3119
- }
3012
+ const frame = document.createElement("div");
3013
+ frame.className = "rvg-row-drag-preview-frame";
3014
+ frame.style.width = `${canvasRect.width + 4}px`;
3015
+ frame.style.height = `${rowHeight + 4}px`;
3120
3016
  const preview = document.createElement("div");
3121
- preview.className = "rvg-column-drag-preview";
3122
- const columnWidth = metrics[sourceIndex].width;
3123
- preview.style.width = `${columnWidth}px`;
3124
- preview.style.height = `${canvasRect.height}px`;
3125
- const column = columns[sourceIndex];
3126
- const header = document.createElement("div");
3127
- header.className = "rvg-column-drag-preview-header";
3128
- header.style.top = `${fixedHeader ? 0 : -scrollRef.current.top}px`;
3129
- header.style.height = `${headerHeight}px`;
3130
- header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
3131
- header.textContent = column.title;
3132
- const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex), headerActionSlotWidth);
3133
- let actionRight = 2;
3134
- if (visibleActions.drag) {
3135
- const icon = createHeaderDragHandleSvg();
3136
- icon.classList.add("rvg-preview-header-icon");
3137
- icon.style.width = `${headerActionSize}px`;
3138
- icon.style.height = `${headerActionSize}px`;
3139
- icon.style.right = `${actionRight}px`;
3140
- header.appendChild(icon);
3141
- actionRight += headerActionSlotWidth;
3142
- }
3143
- if (visibleActions.sort) {
3144
- const direction = sortState?.columnKey === column.key ? sortState.direction : null;
3145
- const icon = createHeaderSortSvg(direction);
3146
- icon.classList.add("rvg-preview-header-icon");
3147
- icon.style.width = `${headerActionSize}px`;
3148
- icon.style.height = `${headerActionSize}px`;
3149
- icon.style.right = `${actionRight}px`;
3150
- header.appendChild(icon);
3151
- actionRight += headerActionSlotWidth;
3152
- }
3153
- if (visibleActions.filter) {
3154
- const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
3155
- icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
3156
- icon.style.width = `${headerActionSize}px`;
3157
- icon.style.height = `${headerActionSize}px`;
3158
- icon.style.right = `${actionRight}px`;
3159
- header.appendChild(icon);
3160
- }
3161
- preview.appendChild(header);
3162
- for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
3163
- const row = rows[rowIndex];
3164
- const rowKey2 = getRowKey(row, rowIndex);
3017
+ preview.className = "rvg-row-drag-preview";
3018
+ preview.style.width = `${canvasRect.width}px`;
3019
+ preview.style.height = `${rowHeight}px`;
3020
+ const row = rows[sourceIndex];
3021
+ const rowKey2 = getRowKey(row, sourceIndex);
3022
+ columns.forEach((column, columnIndex) => {
3023
+ const left = getDisplayedColumnLeft(columnIndex);
3024
+ const columnWidth = metrics[columnIndex].width;
3025
+ if (left + columnWidth <= 0 || left >= canvasRect.width) return;
3165
3026
  const cell = document.createElement("div");
3166
- cell.className = "rvg-column-drag-preview-cell";
3167
- cell.style.top = `${bodyTop + rowIndex * rowHeight - scrollRef.current.top}px`;
3168
- cell.style.height = `${rowHeight}px`;
3027
+ cell.className = "rvg-row-drag-preview-cell";
3028
+ cell.style.left = `${left}px`;
3029
+ cell.style.width = `${columnWidth}px`;
3169
3030
  cell.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
3170
- const key = `${typeof rowKey2}:${String(rowKey2)}\0${column.key}`;
3171
- if (selectedRowKeySet.has(rowKey2) || selectedColumnKeySet.has(column.key)) {
3172
- cell.classList.add("is-axis-selected");
3173
- }
3174
- if (!insertedRowKeys.has(rowKey2) && editedCellKeys.has(key)) cell.classList.add("is-edited");
3175
- if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) {
3176
- cell.classList.remove("is-edited");
3177
- cell.classList.add("is-selected");
3031
+ if (column.rowDragHandle) {
3032
+ cell.appendChild(createRowDragHandleSvg());
3033
+ } else if (column.rowSelection) {
3034
+ const checkbox = document.createElement("span");
3035
+ checkbox.className = selectedRowKeySet.has(rowKey2) ? "rvg-preview-checkbox is-checked" : "rvg-preview-checkbox";
3036
+ checkbox.textContent = selectedRowKeySet.has(rowKey2) ? "\u2713" : "";
3037
+ cell.appendChild(checkbox);
3038
+ } else {
3039
+ cell.textContent = getCellLabel(sourceIndex, columnIndex);
3178
3040
  }
3179
- cell.textContent = getCellLabel(rowIndex, sourceIndex);
3041
+ if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) cell.classList.add("is-selected");
3180
3042
  preview.appendChild(cell);
3181
- }
3182
- container.appendChild(preview);
3183
- return () => preview.remove();
3043
+ });
3044
+ frame.appendChild(preview);
3045
+ container.appendChild(frame);
3046
+ return () => frame.remove();
3184
3047
  }
3185
3048
  });
3186
3049
  },
3187
3050
  onDragStart: ({ source }) => {
3051
+ const sourceIndex = Number(source.data.sourceIndex);
3188
3052
  suppressClickRef.current = true;
3189
3053
  hideDragTooltips();
3190
3054
  document.documentElement.classList.add("rvg-is-dragging");
3191
3055
  canvas.style.cursor = "move";
3192
- if (source.data.type === "table-row") {
3193
- const sourceIndex = Number(source.data.sourceIndex);
3194
- setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
3195
- }
3056
+ setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
3196
3057
  },
3197
3058
  onDrag: ({ source, location }) => {
3198
3059
  const target = location.current.dropTargets[0]?.data;
3199
3060
  const sourceIndex = Number(source.data.sourceIndex);
3200
- if (source.data.type === "table-row") {
3201
- const rawTargetIndex = Number(target?.targetIndex);
3202
- if (!Number.isInteger(rawTargetIndex)) {
3203
- setRowDragPreview(null);
3204
- return setRowDragGuide(null);
3205
- }
3206
- const edge2 = target?.rowEdge;
3207
- let targetIndex2 = rawTargetIndex + (edge2 === "bottom" ? 1 : 0);
3208
- if (sourceIndex < targetIndex2) targetIndex2 -= 1;
3209
- targetIndex2 = Math.max(0, Math.min(rows.length - 1, targetIndex2));
3210
- setRowDragPreview((current) => current?.sourceIndex === sourceIndex && current.targetIndex === targetIndex2 ? current : { sourceIndex, targetIndex: targetIndex2 });
3211
- setRowDragGuide(bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top + (edge2 === "bottom" ? rowHeight : 0));
3212
- return;
3213
- }
3214
- const targetIndex = Number(target?.targetIndex);
3215
- if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
3216
- validColumnDropRef.current = null;
3217
- setColumnDropTarget(null);
3218
- setDragGuide(null);
3219
- return;
3220
- }
3221
- const edge = target?.columnEdge;
3222
- const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
3223
- columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
3224
- if (destinationIndex === sourceIndex) {
3225
- validColumnDropRef.current = null;
3226
- setColumnDropTarget(null);
3227
- setDragGuide(null);
3228
- return;
3229
- }
3230
- validColumnDropRef.current = {
3231
- sourceIndex,
3232
- targetIndex: destinationIndex,
3233
- rawTargetIndex: targetIndex,
3234
- targetKey: String(target.targetKey),
3235
- headerKind: source.data.headerKind === "group" ? "group" : "column",
3236
- parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
3237
- fixed: source.data.fixed === "left" || source.data.fixed === "right" ? source.data.fixed : void 0,
3238
- columnEdge: edge === "right" ? "right" : "left"
3239
- };
3240
- 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);
3241
- const targetEndIndex = Number.isInteger(target?.targetEndIndex) ? Number(target.targetEndIndex) : targetIndex;
3242
- const hoveredTargetCell = siblingCells.find((cell) => cell.startIndex === targetIndex && cell.endIndex === targetEndIndex);
3243
- if (!hoveredTargetCell) {
3244
- validColumnDropRef.current = null;
3245
- setColumnDropTarget(null);
3246
- setDragGuide(null);
3247
- return;
3248
- }
3249
- const highlightedCell = edge === "right" ? hoveredTargetCell : siblingCells.filter((cell) => cell.endIndex < hoveredTargetCell.startIndex).sort((left, right) => right.endIndex - left.endIndex)[0] ?? hoveredTargetCell;
3250
- setColumnDropTarget({ startIndex: highlightedCell.startIndex, endIndex: highlightedCell.endIndex });
3251
- const targetLeft = Number(target?.targetLeft);
3252
- const targetWidth = Number(target?.targetWidth);
3253
- if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
3254
- validColumnDropRef.current = null;
3255
- setColumnDropTarget(null);
3256
- setDragGuide(null);
3061
+ const rawTargetIndex = Number(target?.targetIndex);
3062
+ if (!Number.isInteger(rawTargetIndex)) {
3063
+ setRowDragPreview(null);
3064
+ setRowDragGuide(null);
3257
3065
  return;
3258
3066
  }
3259
- const guideTop = headerRowOffsets[Number(source.data.headerLevel)] ?? 0;
3260
- setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
3067
+ const edge = target?.rowEdge;
3068
+ let targetIndex = rawTargetIndex + (edge === "bottom" ? 1 : 0);
3069
+ if (sourceIndex < targetIndex) targetIndex -= 1;
3070
+ targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
3071
+ setRowDragPreview((current) => current?.sourceIndex === sourceIndex && current.targetIndex === targetIndex ? current : { sourceIndex, targetIndex });
3072
+ setRowDragGuide(bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top + (edge === "bottom" ? rowHeight : 0));
3261
3073
  },
3262
3074
  onDrop: ({ source, location }) => {
3263
- document.documentElement.classList.remove("rvg-is-dragging");
3264
3075
  const target = location.current.dropTargets[0]?.data;
3265
3076
  const sourceIndex = Number(source.data.sourceIndex);
3266
- if (source.data.type === "table-row") {
3267
- const rawTargetIndex = Number(target?.targetIndex);
3268
- let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
3269
- if (sourceIndex < targetIndex) targetIndex -= 1;
3270
- targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
3271
- scrollerRef.current?.classList.add("rvg-row-drop-settling");
3272
- setRowDragPreview(null);
3273
- setRowDragGuide(null);
3274
- canvas.style.cursor = "default";
3275
- if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
3276
- requestAnimationFrame(() => {
3277
- requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
3278
- });
3279
- window.setTimeout(() => {
3280
- suppressClickRef.current = false;
3281
- }, 0);
3282
- return;
3283
- }
3284
- const validDrop = validColumnDropRef.current;
3077
+ const rawTargetIndex = Number(target?.targetIndex);
3078
+ let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
3079
+ if (sourceIndex < targetIndex) targetIndex -= 1;
3080
+ targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
3081
+ scrollerRef.current?.classList.add("rvg-row-drop-settling");
3082
+ setRowDragPreview(null);
3083
+ setRowDragGuide(null);
3084
+ document.documentElement.classList.remove("rvg-is-dragging");
3285
3085
  canvas.style.cursor = "default";
3286
- setDragGuide(null);
3287
- setColumnDropTarget(null);
3288
- columnDragPreviewRef.current = null;
3289
- validColumnDropRef.current = null;
3290
- if (validDrop) {
3291
- applyColumnOrder(
3292
- validDrop.sourceIndex - utilityColumnCount,
3293
- validDrop.targetIndex - utilityColumnCount,
3294
- {
3295
- type: validDrop.headerKind,
3296
- sourceKey: String(source.data.sourceKey),
3297
- targetKey: validDrop.targetKey,
3298
- parentKey: validDrop.parentKey,
3299
- placement: resolveColumnDropPlacement(validDrop.columnEdge)
3300
- }
3301
- );
3302
- }
3086
+ if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
3087
+ requestAnimationFrame(() => {
3088
+ requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
3089
+ });
3303
3090
  window.setTimeout(() => {
3304
3091
  suppressClickRef.current = false;
3305
3092
  }, 0);
@@ -3307,43 +3094,14 @@ function TableInner({
3307
3094
  });
3308
3095
  const cleanupDrop = dropTargetForElements({
3309
3096
  element: canvas,
3310
- canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
3097
+ canDrop: ({ source }) => source.data.type === "table-row",
3311
3098
  getDropEffect: () => "move",
3312
- getData: ({ input, element, source }) => {
3313
- if (source.data.type === "table-row") {
3314
- const targetIndex2 = locateRow(input.clientY);
3315
- if (targetIndex2 < 0) return { targetIndex: -1 };
3316
- const rowTop = bodyTop + targetIndex2 * rowHeight - scrollRef.current.top;
3317
- const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
3318
- return attachClosestEdge({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
3319
- }
3320
- const hoveredColumnIndex = locateColumn(input.clientX);
3321
- 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);
3322
- if (!targetCell) return { targetIndex: -1 };
3323
- let targetIndex = targetCell.startIndex;
3324
- const targetFixed = columns[targetCell.startIndex]?.fixed;
3325
- const headerKind = targetCell.leaf ? "column" : "group";
3326
- if (source.data.headerKind !== headerKind || source.data.parentKey !== targetCell.parentKey || source.data.fixed !== targetFixed) return { targetIndex: -1 };
3327
- if (columns[targetIndex].rowSelection || columns[targetIndex].rowDragHandle || columns[targetIndex].rowNumber) {
3328
- const fixedSide = columns[Number(source.data.sourceIndex)]?.fixed;
3329
- targetIndex = columns.findIndex((column, index) => index > targetIndex && column.fixed === fixedSide && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
3330
- if (targetIndex < 0) return { targetIndex: -1 };
3331
- return { targetIndex, columnEdge: "left" };
3332
- }
3333
- const left = getHeaderCellLeft(targetCell);
3334
- const targetWidth = targetCell.leaf ? metrics[targetIndex].width : getHeaderCellWidth(targetCell);
3335
- const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
3336
- return attachClosestEdge({
3337
- targetIndex,
3338
- targetEndIndex: targetCell.endIndex,
3339
- targetKey: targetCell.key,
3340
- parentKey: targetCell.parentKey,
3341
- headerKind,
3342
- fixed: targetFixed,
3343
- targetLeft: left,
3344
- targetWidth,
3345
- columnEdge
3346
- }, { element, input, allowedEdges: ["left", "right"] });
3099
+ getData: ({ input, element }) => {
3100
+ const targetIndex = locateRow(input.clientY);
3101
+ if (targetIndex < 0) return { targetIndex: -1 };
3102
+ const rowTop = bodyTop + targetIndex * rowHeight - scrollRef.current.top;
3103
+ const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
3104
+ return attachClosestEdge({ targetIndex, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
3347
3105
  }
3348
3106
  });
3349
3107
  return () => {
@@ -3351,7 +3109,7 @@ function TableInner({
3351
3109
  cleanupDrag();
3352
3110
  cleanupDrop();
3353
3111
  };
3354
- }, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerActionSize, headerActionSlotWidth, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderAction, locateHeaderCell, locateHeaderResizeCell, locateRow, measureHeaderTitleWidth, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setDragGuide, setRowDragGuide, sortState, utilityColumnCount]);
3112
+ }, [applyRowOrder, bodyTop, columns, getCellLabel, getDisplayedColumnLeft, getRowKey, hideDragTooltips, locateColumn, locateRow, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setRowDragGuide]);
3355
3113
  const locateCell = useCallback2((clientX, clientY) => {
3356
3114
  const canvas = canvasRef.current;
3357
3115
  if (!canvas) return null;
@@ -3798,6 +3556,113 @@ function TableInner({
3798
3556
  setResizeGuideX(null);
3799
3557
  setResizeGuideTop(0);
3800
3558
  }, []);
3559
+ const clearColumnOrderPointerDrag = useCallback2((canvas) => {
3560
+ columnOrderDragRef.current = null;
3561
+ columnDragPreviewRef.current = null;
3562
+ validColumnDropRef.current = null;
3563
+ setColumnDropTarget(null);
3564
+ setDragGuide(null);
3565
+ document.documentElement.classList.remove("rvg-is-dragging");
3566
+ canvas.style.cursor = "default";
3567
+ }, [setDragGuide]);
3568
+ const handleColumnOrderPointerDown = useCallback2((event) => {
3569
+ if (!columnDraggable || event.button !== 0 || columnDragRef.current) return;
3570
+ const sourceCell = locateHeaderCell(event.clientX, event.clientY);
3571
+ if (!sourceCell || locateHeaderResizeCell(event.clientX, event.clientY)) return;
3572
+ if (sourceCell.leaf && locateHeaderAction(event.clientX, sourceCell.startIndex)) return;
3573
+ const sourceColumn = columns[sourceCell.startIndex];
3574
+ if (!sourceColumn || sourceColumn.rowSelection || sourceColumn.rowDragHandle || sourceColumn.rowNumber) return;
3575
+ event.currentTarget.setPointerCapture(event.pointerId);
3576
+ columnOrderDragRef.current = {
3577
+ pointerId: event.pointerId,
3578
+ startX: event.clientX,
3579
+ startY: event.clientY,
3580
+ active: false,
3581
+ sourceCell
3582
+ };
3583
+ }, [columnDraggable, columns, locateHeaderAction, locateHeaderCell, locateHeaderResizeCell]);
3584
+ const handleColumnOrderPointerMove = useCallback2((event) => {
3585
+ const drag = columnOrderDragRef.current;
3586
+ if (!drag || drag.pointerId !== event.pointerId || columnDragRef.current) return;
3587
+ if (!drag.active) {
3588
+ if (Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) < 4) return;
3589
+ drag.active = true;
3590
+ suppressClickRef.current = true;
3591
+ hideDragTooltips();
3592
+ document.documentElement.classList.add("rvg-is-dragging");
3593
+ event.currentTarget.style.cursor = "move";
3594
+ }
3595
+ event.preventDefault();
3596
+ const sourceCell = drag.sourceCell;
3597
+ const hoveredColumnIndex = locateColumn(event.clientX);
3598
+ const targetCell = locateHeaderCell(event.clientX, event.clientY) ?? headerCells.find((cell) => hoveredColumnIndex >= cell.startIndex && hoveredColumnIndex <= cell.endIndex && cell.level === sourceCell.level && cell.leaf === sourceCell.leaf && cell.parentKey === sourceCell.parentKey && columns[cell.startIndex]?.fixed === columns[sourceCell.startIndex]?.fixed);
3599
+ if (!targetCell) {
3600
+ validColumnDropRef.current = null;
3601
+ setColumnDropTarget(null);
3602
+ setDragGuide(null);
3603
+ return;
3604
+ }
3605
+ const targetColumn = columns[targetCell.startIndex];
3606
+ if (!targetColumn || targetColumn.rowSelection || targetColumn.rowDragHandle || targetColumn.rowNumber || targetCell.leaf !== sourceCell.leaf || targetCell.parentKey !== sourceCell.parentKey || targetColumn.fixed !== columns[sourceCell.startIndex]?.fixed) {
3607
+ validColumnDropRef.current = null;
3608
+ setColumnDropTarget(null);
3609
+ setDragGuide(null);
3610
+ return;
3611
+ }
3612
+ const targetLeft = getHeaderCellLeft(targetCell);
3613
+ const targetWidth = getHeaderCellWidth(targetCell);
3614
+ const localX = event.clientX - event.currentTarget.getBoundingClientRect().left;
3615
+ const columnEdge = localX < targetLeft + targetWidth / 2 ? "left" : "right";
3616
+ const destinationIndex = resolveColumnDropIndex(
3617
+ sourceCell.startIndex,
3618
+ targetCell.startIndex,
3619
+ columnEdge,
3620
+ columns.length
3621
+ );
3622
+ columnDragPreviewRef.current = { sourceIndex: sourceCell.startIndex, targetIndex: destinationIndex };
3623
+ if (destinationIndex === sourceCell.startIndex) {
3624
+ validColumnDropRef.current = null;
3625
+ setColumnDropTarget(null);
3626
+ setDragGuide(null);
3627
+ return;
3628
+ }
3629
+ validColumnDropRef.current = {
3630
+ sourceIndex: sourceCell.startIndex,
3631
+ targetIndex: destinationIndex,
3632
+ rawTargetIndex: targetCell.startIndex,
3633
+ targetKey: targetCell.key,
3634
+ headerKind: sourceCell.leaf ? "column" : "group",
3635
+ parentKey: sourceCell.parentKey,
3636
+ fixed: targetColumn.fixed,
3637
+ columnEdge
3638
+ };
3639
+ setColumnDropTarget({ startIndex: targetCell.startIndex, endIndex: targetCell.endIndex });
3640
+ setDragGuide(columnEdge === "right" ? targetLeft + targetWidth : targetLeft, headerRowOffsets[sourceCell.level] ?? 0);
3641
+ }, [columns, getHeaderCellLeft, getHeaderCellWidth, headerCells, headerRowOffsets, hideDragTooltips, locateColumn, locateHeaderCell, setDragGuide]);
3642
+ const finishColumnOrderPointerDrag = useCallback2((event, apply) => {
3643
+ const drag = columnOrderDragRef.current;
3644
+ if (!drag || drag.pointerId !== event.pointerId) return;
3645
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
3646
+ const validDrop = validColumnDropRef.current;
3647
+ if (apply && drag.active && validDrop) {
3648
+ applyColumnOrder(
3649
+ validDrop.sourceIndex - utilityColumnCount,
3650
+ validDrop.targetIndex - utilityColumnCount,
3651
+ {
3652
+ type: validDrop.headerKind,
3653
+ sourceKey: drag.sourceCell.key,
3654
+ targetKey: validDrop.targetKey,
3655
+ parentKey: validDrop.parentKey,
3656
+ placement: resolveColumnDropPlacement(validDrop.columnEdge)
3657
+ }
3658
+ );
3659
+ }
3660
+ const wasActive = drag.active;
3661
+ clearColumnOrderPointerDrag(event.currentTarget);
3662
+ if (wasActive) window.setTimeout(() => {
3663
+ suppressClickRef.current = false;
3664
+ }, 0);
3665
+ }, [applyColumnOrder, clearColumnOrderPointerDrag, utilityColumnCount]);
3801
3666
  const queueSortStateChange = useCallback2((next) => {
3802
3667
  setSortState(next);
3803
3668
  }, []);
@@ -4611,7 +4476,7 @@ function TableInner({
4611
4476
  hideDragTooltips();
4612
4477
  return;
4613
4478
  }
4614
- if (columnDragRef.current) return;
4479
+ if (columnDragRef.current || columnOrderDragRef.current?.active) return;
4615
4480
  const rect = event.currentTarget.getBoundingClientRect();
4616
4481
  const localY = event.clientY - rect.top;
4617
4482
  const headerY = fixedHeader ? 0 : -scrollRef.current.top;
@@ -4728,20 +4593,22 @@ function TableInner({
4728
4593
  event.currentTarget.style.cursor = "move";
4729
4594
  }
4730
4595
  handleColumnPointerDown(event);
4596
+ if (!columnDragRef.current) handleColumnOrderPointerDown(event);
4731
4597
  beginRangeDrag(event);
4732
4598
  },
4733
4599
  onPointerMove: (event) => {
4734
4600
  handleColumnPointerMove(event);
4601
+ handleColumnOrderPointerMove(event);
4735
4602
  updateRangeDrag(event);
4736
4603
  },
4737
4604
  onPointerUp: (event) => {
4738
- document.documentElement.classList.remove("rvg-is-dragging");
4739
4605
  handleColumnPointerUp(event);
4606
+ finishColumnOrderPointerDrag(event, true);
4740
4607
  endRangeDrag(event);
4741
4608
  },
4742
4609
  onPointerCancel: (event) => {
4743
- document.documentElement.classList.remove("rvg-is-dragging");
4744
4610
  handleColumnPointerUp(event);
4611
+ finishColumnOrderPointerDrag(event, false);
4745
4612
  endRangeDrag(event);
4746
4613
  },
4747
4614
  onClick: (event) => {
@@ -4901,6 +4768,13 @@ function TableInner({
4901
4768
  columns.map((column, index) => column.fixed === "right" ? /* @__PURE__ */ jsx7("span", { children: renderHeaderIcons(index, viewport.width - (rightFixedOffsets.get(index) ?? 0) - metrics[index].width) }, column.key) : null)
4902
4769
  ] })
4903
4770
  ] }),
4771
+ hasVerticalBorders && trailingColumnBorderLeft !== null && /* @__PURE__ */ jsx7(
4772
+ "div",
4773
+ {
4774
+ className: "rvg-trailing-column-border",
4775
+ style: { left: trailingColumnBorderLeft, height: renderHeight }
4776
+ }
4777
+ ),
4904
4778
  headerTooltip && /* @__PURE__ */ jsx7("div", { className: `rvg-header-tooltip is-${headerTooltip.placement}`, role: "tooltip", style: { left: headerTooltip.left, top: headerTooltip.top }, children: headerTooltip.label }),
4905
4779
  hoveredCellTooltip && /* @__PURE__ */ jsx7(
4906
4780
  "div",