@lensui/lens-table 0.1.22 → 0.1.23

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]);
@@ -2877,7 +2841,6 @@ function TableInner({
2877
2841
  return headerDepth - 1;
2878
2842
  }, [headerDepth, headerRowHeights, headerRowOffsets]);
2879
2843
  const resizeColumn = useCallback2((columnKey, width2) => {
2880
- setManuallyResizedColumnKeys((current) => current.has(columnKey) ? current : new Set(current).add(columnKey));
2881
2844
  setResizedColumnWidths((current) => current[columnKey] === width2 ? current : { ...current, [columnKey]: width2 });
2882
2845
  onColumnResize?.(columnKey, width2);
2883
2846
  }, [onColumnResize]);
@@ -3022,284 +2985,104 @@ function TableInner({
3022
2985
  }, [bodyTop, rowHeight, rows.length]);
3023
2986
  useEffect2(() => {
3024
2987
  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
- };
2988
+ if (!canvas || !rowDraggable) return;
3040
2989
  const cleanupDrag = draggable({
3041
2990
  element: canvas,
3042
2991
  canDrag: ({ input }) => {
3043
- const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
3044
- if (headerDragCell) return true;
3045
2992
  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
- };
2993
+ return columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
3065
2994
  },
2995
+ getInitialData: ({ input }) => ({ type: "table-row", sourceIndex: locateRow(input.clientY) }),
3066
2996
  onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
3067
2997
  const sourceIndex = Number(source.data.sourceIndex);
3068
2998
  const canvasRect = canvas.getBoundingClientRect();
3069
2999
  const input = location.current.input;
3070
- const previewOffset = source.data.type === "table-row" ? {
3000
+ const previewOffset = {
3071
3001
  x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
3072
3002
  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
3003
  };
3077
3004
  setCustomNativeDragPreview({
3078
3005
  nativeSetDragImage,
3079
3006
  getOffset: () => previewOffset,
3080
3007
  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
- }
3008
+ const frame = document.createElement("div");
3009
+ frame.className = "rvg-row-drag-preview-frame";
3010
+ frame.style.width = `${canvasRect.width + 4}px`;
3011
+ frame.style.height = `${rowHeight + 4}px`;
3120
3012
  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);
3013
+ preview.className = "rvg-row-drag-preview";
3014
+ preview.style.width = `${canvasRect.width}px`;
3015
+ preview.style.height = `${rowHeight}px`;
3016
+ const row = rows[sourceIndex];
3017
+ const rowKey2 = getRowKey(row, sourceIndex);
3018
+ columns.forEach((column, columnIndex) => {
3019
+ const left = getDisplayedColumnLeft(columnIndex);
3020
+ const columnWidth = metrics[columnIndex].width;
3021
+ if (left + columnWidth <= 0 || left >= canvasRect.width) return;
3165
3022
  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`;
3023
+ cell.className = "rvg-row-drag-preview-cell";
3024
+ cell.style.left = `${left}px`;
3025
+ cell.style.width = `${columnWidth}px`;
3169
3026
  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");
3027
+ if (column.rowDragHandle) {
3028
+ cell.appendChild(createRowDragHandleSvg());
3029
+ } else if (column.rowSelection) {
3030
+ const checkbox = document.createElement("span");
3031
+ checkbox.className = selectedRowKeySet.has(rowKey2) ? "rvg-preview-checkbox is-checked" : "rvg-preview-checkbox";
3032
+ checkbox.textContent = selectedRowKeySet.has(rowKey2) ? "\u2713" : "";
3033
+ cell.appendChild(checkbox);
3034
+ } else {
3035
+ cell.textContent = getCellLabel(sourceIndex, columnIndex);
3178
3036
  }
3179
- cell.textContent = getCellLabel(rowIndex, sourceIndex);
3037
+ if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) cell.classList.add("is-selected");
3180
3038
  preview.appendChild(cell);
3181
- }
3182
- container.appendChild(preview);
3183
- return () => preview.remove();
3039
+ });
3040
+ frame.appendChild(preview);
3041
+ container.appendChild(frame);
3042
+ return () => frame.remove();
3184
3043
  }
3185
3044
  });
3186
3045
  },
3187
3046
  onDragStart: ({ source }) => {
3047
+ const sourceIndex = Number(source.data.sourceIndex);
3188
3048
  suppressClickRef.current = true;
3189
3049
  hideDragTooltips();
3190
3050
  document.documentElement.classList.add("rvg-is-dragging");
3191
3051
  canvas.style.cursor = "move";
3192
- if (source.data.type === "table-row") {
3193
- const sourceIndex = Number(source.data.sourceIndex);
3194
- setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
3195
- }
3052
+ setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
3196
3053
  },
3197
3054
  onDrag: ({ source, location }) => {
3198
3055
  const target = location.current.dropTargets[0]?.data;
3199
3056
  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);
3057
+ const rawTargetIndex = Number(target?.targetIndex);
3058
+ if (!Number.isInteger(rawTargetIndex)) {
3059
+ setRowDragPreview(null);
3060
+ setRowDragGuide(null);
3257
3061
  return;
3258
3062
  }
3259
- const guideTop = headerRowOffsets[Number(source.data.headerLevel)] ?? 0;
3260
- setDragGuide(edge === "right" ? targetLeft + targetWidth : targetLeft, guideTop);
3063
+ const edge = target?.rowEdge;
3064
+ let targetIndex = rawTargetIndex + (edge === "bottom" ? 1 : 0);
3065
+ if (sourceIndex < targetIndex) targetIndex -= 1;
3066
+ targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
3067
+ setRowDragPreview((current) => current?.sourceIndex === sourceIndex && current.targetIndex === targetIndex ? current : { sourceIndex, targetIndex });
3068
+ setRowDragGuide(bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top + (edge === "bottom" ? rowHeight : 0));
3261
3069
  },
3262
3070
  onDrop: ({ source, location }) => {
3263
- document.documentElement.classList.remove("rvg-is-dragging");
3264
3071
  const target = location.current.dropTargets[0]?.data;
3265
3072
  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;
3073
+ const rawTargetIndex = Number(target?.targetIndex);
3074
+ let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
3075
+ if (sourceIndex < targetIndex) targetIndex -= 1;
3076
+ targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
3077
+ scrollerRef.current?.classList.add("rvg-row-drop-settling");
3078
+ setRowDragPreview(null);
3079
+ setRowDragGuide(null);
3080
+ document.documentElement.classList.remove("rvg-is-dragging");
3285
3081
  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
- }
3082
+ if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
3083
+ requestAnimationFrame(() => {
3084
+ requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
3085
+ });
3303
3086
  window.setTimeout(() => {
3304
3087
  suppressClickRef.current = false;
3305
3088
  }, 0);
@@ -3307,43 +3090,14 @@ function TableInner({
3307
3090
  });
3308
3091
  const cleanupDrop = dropTargetForElements({
3309
3092
  element: canvas,
3310
- canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
3093
+ canDrop: ({ source }) => source.data.type === "table-row",
3311
3094
  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"] });
3095
+ getData: ({ input, element }) => {
3096
+ const targetIndex = locateRow(input.clientY);
3097
+ if (targetIndex < 0) return { targetIndex: -1 };
3098
+ const rowTop = bodyTop + targetIndex * rowHeight - scrollRef.current.top;
3099
+ const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
3100
+ return attachClosestEdge({ targetIndex, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
3347
3101
  }
3348
3102
  });
3349
3103
  return () => {
@@ -3351,7 +3105,7 @@ function TableInner({
3351
3105
  cleanupDrag();
3352
3106
  cleanupDrop();
3353
3107
  };
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]);
3108
+ }, [applyRowOrder, bodyTop, columns, getCellLabel, getDisplayedColumnLeft, getRowKey, hideDragTooltips, locateColumn, locateRow, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setRowDragGuide]);
3355
3109
  const locateCell = useCallback2((clientX, clientY) => {
3356
3110
  const canvas = canvasRef.current;
3357
3111
  if (!canvas) return null;
@@ -3798,6 +3552,113 @@ function TableInner({
3798
3552
  setResizeGuideX(null);
3799
3553
  setResizeGuideTop(0);
3800
3554
  }, []);
3555
+ const clearColumnOrderPointerDrag = useCallback2((canvas) => {
3556
+ columnOrderDragRef.current = null;
3557
+ columnDragPreviewRef.current = null;
3558
+ validColumnDropRef.current = null;
3559
+ setColumnDropTarget(null);
3560
+ setDragGuide(null);
3561
+ document.documentElement.classList.remove("rvg-is-dragging");
3562
+ canvas.style.cursor = "default";
3563
+ }, [setDragGuide]);
3564
+ const handleColumnOrderPointerDown = useCallback2((event) => {
3565
+ if (!columnDraggable || event.button !== 0 || columnDragRef.current) return;
3566
+ const sourceCell = locateHeaderCell(event.clientX, event.clientY);
3567
+ if (!sourceCell || locateHeaderResizeCell(event.clientX, event.clientY)) return;
3568
+ if (sourceCell.leaf && locateHeaderAction(event.clientX, sourceCell.startIndex)) return;
3569
+ const sourceColumn = columns[sourceCell.startIndex];
3570
+ if (!sourceColumn || sourceColumn.rowSelection || sourceColumn.rowDragHandle || sourceColumn.rowNumber) return;
3571
+ event.currentTarget.setPointerCapture(event.pointerId);
3572
+ columnOrderDragRef.current = {
3573
+ pointerId: event.pointerId,
3574
+ startX: event.clientX,
3575
+ startY: event.clientY,
3576
+ active: false,
3577
+ sourceCell
3578
+ };
3579
+ }, [columnDraggable, columns, locateHeaderAction, locateHeaderCell, locateHeaderResizeCell]);
3580
+ const handleColumnOrderPointerMove = useCallback2((event) => {
3581
+ const drag = columnOrderDragRef.current;
3582
+ if (!drag || drag.pointerId !== event.pointerId || columnDragRef.current) return;
3583
+ if (!drag.active) {
3584
+ if (Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) < 4) return;
3585
+ drag.active = true;
3586
+ suppressClickRef.current = true;
3587
+ hideDragTooltips();
3588
+ document.documentElement.classList.add("rvg-is-dragging");
3589
+ event.currentTarget.style.cursor = "move";
3590
+ }
3591
+ event.preventDefault();
3592
+ const sourceCell = drag.sourceCell;
3593
+ const hoveredColumnIndex = locateColumn(event.clientX);
3594
+ 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);
3595
+ if (!targetCell) {
3596
+ validColumnDropRef.current = null;
3597
+ setColumnDropTarget(null);
3598
+ setDragGuide(null);
3599
+ return;
3600
+ }
3601
+ const targetColumn = columns[targetCell.startIndex];
3602
+ if (!targetColumn || targetColumn.rowSelection || targetColumn.rowDragHandle || targetColumn.rowNumber || targetCell.leaf !== sourceCell.leaf || targetCell.parentKey !== sourceCell.parentKey || targetColumn.fixed !== columns[sourceCell.startIndex]?.fixed) {
3603
+ validColumnDropRef.current = null;
3604
+ setColumnDropTarget(null);
3605
+ setDragGuide(null);
3606
+ return;
3607
+ }
3608
+ const targetLeft = getHeaderCellLeft(targetCell);
3609
+ const targetWidth = getHeaderCellWidth(targetCell);
3610
+ const localX = event.clientX - event.currentTarget.getBoundingClientRect().left;
3611
+ const columnEdge = localX < targetLeft + targetWidth / 2 ? "left" : "right";
3612
+ const destinationIndex = resolveColumnDropIndex(
3613
+ sourceCell.startIndex,
3614
+ targetCell.startIndex,
3615
+ columnEdge,
3616
+ columns.length
3617
+ );
3618
+ columnDragPreviewRef.current = { sourceIndex: sourceCell.startIndex, targetIndex: destinationIndex };
3619
+ if (destinationIndex === sourceCell.startIndex) {
3620
+ validColumnDropRef.current = null;
3621
+ setColumnDropTarget(null);
3622
+ setDragGuide(null);
3623
+ return;
3624
+ }
3625
+ validColumnDropRef.current = {
3626
+ sourceIndex: sourceCell.startIndex,
3627
+ targetIndex: destinationIndex,
3628
+ rawTargetIndex: targetCell.startIndex,
3629
+ targetKey: targetCell.key,
3630
+ headerKind: sourceCell.leaf ? "column" : "group",
3631
+ parentKey: sourceCell.parentKey,
3632
+ fixed: targetColumn.fixed,
3633
+ columnEdge
3634
+ };
3635
+ setColumnDropTarget({ startIndex: targetCell.startIndex, endIndex: targetCell.endIndex });
3636
+ setDragGuide(columnEdge === "right" ? targetLeft + targetWidth : targetLeft, headerRowOffsets[sourceCell.level] ?? 0);
3637
+ }, [columns, getHeaderCellLeft, getHeaderCellWidth, headerCells, headerRowOffsets, hideDragTooltips, locateColumn, locateHeaderCell, setDragGuide]);
3638
+ const finishColumnOrderPointerDrag = useCallback2((event, apply) => {
3639
+ const drag = columnOrderDragRef.current;
3640
+ if (!drag || drag.pointerId !== event.pointerId) return;
3641
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
3642
+ const validDrop = validColumnDropRef.current;
3643
+ if (apply && drag.active && validDrop) {
3644
+ applyColumnOrder(
3645
+ validDrop.sourceIndex - utilityColumnCount,
3646
+ validDrop.targetIndex - utilityColumnCount,
3647
+ {
3648
+ type: validDrop.headerKind,
3649
+ sourceKey: drag.sourceCell.key,
3650
+ targetKey: validDrop.targetKey,
3651
+ parentKey: validDrop.parentKey,
3652
+ placement: resolveColumnDropPlacement(validDrop.columnEdge)
3653
+ }
3654
+ );
3655
+ }
3656
+ const wasActive = drag.active;
3657
+ clearColumnOrderPointerDrag(event.currentTarget);
3658
+ if (wasActive) window.setTimeout(() => {
3659
+ suppressClickRef.current = false;
3660
+ }, 0);
3661
+ }, [applyColumnOrder, clearColumnOrderPointerDrag, utilityColumnCount]);
3801
3662
  const queueSortStateChange = useCallback2((next) => {
3802
3663
  setSortState(next);
3803
3664
  }, []);
@@ -4611,7 +4472,7 @@ function TableInner({
4611
4472
  hideDragTooltips();
4612
4473
  return;
4613
4474
  }
4614
- if (columnDragRef.current) return;
4475
+ if (columnDragRef.current || columnOrderDragRef.current?.active) return;
4615
4476
  const rect = event.currentTarget.getBoundingClientRect();
4616
4477
  const localY = event.clientY - rect.top;
4617
4478
  const headerY = fixedHeader ? 0 : -scrollRef.current.top;
@@ -4728,20 +4589,22 @@ function TableInner({
4728
4589
  event.currentTarget.style.cursor = "move";
4729
4590
  }
4730
4591
  handleColumnPointerDown(event);
4592
+ if (!columnDragRef.current) handleColumnOrderPointerDown(event);
4731
4593
  beginRangeDrag(event);
4732
4594
  },
4733
4595
  onPointerMove: (event) => {
4734
4596
  handleColumnPointerMove(event);
4597
+ handleColumnOrderPointerMove(event);
4735
4598
  updateRangeDrag(event);
4736
4599
  },
4737
4600
  onPointerUp: (event) => {
4738
- document.documentElement.classList.remove("rvg-is-dragging");
4739
4601
  handleColumnPointerUp(event);
4602
+ finishColumnOrderPointerDrag(event, true);
4740
4603
  endRangeDrag(event);
4741
4604
  },
4742
4605
  onPointerCancel: (event) => {
4743
- document.documentElement.classList.remove("rvg-is-dragging");
4744
4606
  handleColumnPointerUp(event);
4607
+ finishColumnOrderPointerDrag(event, false);
4745
4608
  endRangeDrag(event);
4746
4609
  },
4747
4610
  onClick: (event) => {