@lensui/lens-table 0.1.21 → 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.
Files changed (3) hide show
  1. package/dist/index.cjs +202 -328
  2. package/dist/index.js +202 -328
  3. package/package.json +1 -1
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";
@@ -961,6 +919,8 @@ function paintGrid(options) {
961
919
  const getColumnX = (index) => {
962
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;
963
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;
964
924
  const getRowDragOffset = (rowIndex) => {
965
925
  if (!rowDragPreview || rowIndex === rowDragPreview.sourceIndex) return 0;
966
926
  if (rowDragPreview.sourceIndex < rowDragPreview.targetIndex) {
@@ -969,6 +929,15 @@ function paintGrid(options) {
969
929
  return rowIndex >= rowDragPreview.targetIndex && rowIndex < rowDragPreview.sourceIndex ? rowHeight : 0;
970
930
  };
971
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
+ }
972
941
  const paintBodyColumns = (layer) => {
973
942
  const rowStart = Math.max(0, range.rowStart - Math.max(0, options.maxRowSpan - 1));
974
943
  for (let rowIndex = rowStart; rowIndex < range.rowEnd; rowIndex += 1) {
@@ -1284,6 +1253,10 @@ function paintGrid(options) {
1284
1253
  ctx.fillStyle = colors.grid;
1285
1254
  ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
1286
1255
  }
1256
+ if (!verticalBorderless && trailingBlankStart !== null) {
1257
+ ctx.fillStyle = colors.grid;
1258
+ ctx.fillRect(Math.round(trailingBlankStart) - 1, 0, 1, height);
1259
+ }
1287
1260
  ctx.fillStyle = colors.grid;
1288
1261
  if (!horizontalBorderless && !frameBorderless) ctx.fillRect(0, 0, width, 1);
1289
1262
  if (!verticalBorderless && !frameBorderless) {
@@ -1418,6 +1391,13 @@ function useControllableValue(value, defaultValue, onChange) {
1418
1391
 
1419
1392
  // src/Table.tsx
1420
1393
  import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1394
+ function resolveColumnDropIndex(sourceIndex, targetIndex, edge, columnCount) {
1395
+ const insertionIndex = targetIndex + (edge === "right" ? 1 : 0) - (sourceIndex < targetIndex ? 1 : 0);
1396
+ return Math.max(0, Math.min(columnCount - 1, insertionIndex));
1397
+ }
1398
+ function resolveColumnDropPlacement(edge) {
1399
+ return edge === "right" ? "after" : "before";
1400
+ }
1421
1401
  var ANNOTATION_COLORS = ["#f44336", "#ff7a45", "#f5a623", "#f2c94c", "#52c41a", "#13a8a8", "#1677ff", "#597ef7", "#9254de", "#eb2f96"];
1422
1402
  var FALLBACK_HEIGHT = 480;
1423
1403
  var EMPTY_BODY_HEIGHT = 240;
@@ -1742,6 +1722,7 @@ function TableInner({
1742
1722
  const rowAnchorRef = useRef2(null);
1743
1723
  const columnAnchorRef = useRef2(null);
1744
1724
  const columnDragRef = useRef2(null);
1725
+ const columnOrderDragRef = useRef2(null);
1745
1726
  const dragGuideRef = useRef2(null);
1746
1727
  const rowDragGuideRef = useRef2(null);
1747
1728
  const selectionFocusRef = useRef2(null);
@@ -3004,291 +2985,104 @@ function TableInner({
3004
2985
  }, [bodyTop, rowHeight, rows.length]);
3005
2986
  useEffect2(() => {
3006
2987
  const canvas = canvasRef.current;
3007
- if (!canvas || !columnDraggable && !rowDraggable) return;
3008
- const getColumnDropIndex = (sourceIndex, targetIndex, edge) => {
3009
- if (edge === "right") return targetIndex;
3010
- const destinationIndex = targetIndex - (sourceIndex < targetIndex ? 1 : 0);
3011
- return Math.max(0, Math.min(columns.length - 1, destinationIndex));
3012
- };
3013
- const getColumnDropPlacement = (sourceIndex, targetIndex, edge) => {
3014
- if (edge !== "right") return "before";
3015
- return targetIndex < sourceIndex ? "before" : "after";
3016
- };
3017
- const getHeaderColumn = (clientX, clientY) => {
3018
- const rect = canvas.getBoundingClientRect();
3019
- const headerY = fixedHeader ? 0 : -scrollRef.current.top;
3020
- const localY = clientY - rect.top;
3021
- if (localY < headerY || localY >= headerY + headerHeight) return -1;
3022
- return locateColumn(clientX);
3023
- };
3024
- const getHeaderDragCell = (clientX, clientY) => {
3025
- const cell = locateHeaderCell(clientX, clientY);
3026
- if (!cell) return null;
3027
- return locateHeaderCellDragHandle(clientX, cell) && !locateHeaderResizeCell(clientX, clientY) ? cell : null;
3028
- };
2988
+ if (!canvas || !rowDraggable) return;
3029
2989
  const cleanupDrag = draggable({
3030
2990
  element: canvas,
3031
2991
  canDrag: ({ input }) => {
3032
- const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
3033
- if (headerDragCell) return true;
3034
2992
  const columnIndex = locateColumn(input.clientX);
3035
- return rowDraggable && columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
3036
- },
3037
- getInitialData: ({ input }) => {
3038
- const headerDragCell = columnDraggable ? getHeaderDragCell(input.clientX, input.clientY) : null;
3039
- if (!headerDragCell) {
3040
- return { type: "table-row", sourceIndex: locateRow(input.clientY) };
3041
- }
3042
- const sourceIndex = headerDragCell.startIndex;
3043
- columnDragPreviewRef.current = { sourceIndex, targetIndex: sourceIndex };
3044
- validColumnDropRef.current = null;
3045
- return {
3046
- type: "table-column",
3047
- sourceIndex,
3048
- sourceKey: headerDragCell.key,
3049
- parentKey: headerDragCell.parentKey,
3050
- headerLevel: headerDragCell.level,
3051
- headerKind: headerDragCell.leaf ? "column" : "group",
3052
- fixed: columns[headerDragCell.startIndex]?.fixed
3053
- };
2993
+ return columnIndex >= 0 && Boolean(columns[columnIndex].rowDragHandle) && locateRow(input.clientY) >= 0;
3054
2994
  },
2995
+ getInitialData: ({ input }) => ({ type: "table-row", sourceIndex: locateRow(input.clientY) }),
3055
2996
  onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {
3056
2997
  const sourceIndex = Number(source.data.sourceIndex);
3057
2998
  const canvasRect = canvas.getBoundingClientRect();
3058
2999
  const input = location.current.input;
3059
- const previewOffset = source.data.type === "table-row" ? {
3000
+ const previewOffset = {
3060
3001
  x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
3061
3002
  y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
3062
- } : {
3063
- x: Math.max(0, Math.min(metrics[sourceIndex].width, input.clientX - canvasRect.left - getDisplayedColumnLeft(sourceIndex))),
3064
- y: Math.max(0, Math.min(canvasRect.height, input.clientY - canvasRect.top))
3065
3003
  };
3066
3004
  setCustomNativeDragPreview({
3067
3005
  nativeSetDragImage,
3068
3006
  getOffset: () => previewOffset,
3069
3007
  render: ({ container }) => {
3070
- if (source.data.type === "table-row") {
3071
- const frame = document.createElement("div");
3072
- frame.className = "rvg-row-drag-preview-frame";
3073
- frame.style.width = `${canvasRect.width + 4}px`;
3074
- frame.style.height = `${rowHeight + 4}px`;
3075
- const preview2 = document.createElement("div");
3076
- preview2.className = "rvg-row-drag-preview";
3077
- preview2.style.width = `${canvasRect.width}px`;
3078
- preview2.style.height = `${rowHeight}px`;
3079
- const row = rows[sourceIndex];
3080
- const rowKey2 = getRowKey(row, sourceIndex);
3081
- columns.forEach((column2, columnIndex) => {
3082
- const left = getDisplayedColumnLeft(columnIndex);
3083
- const columnWidth2 = metrics[columnIndex].width;
3084
- if (left + columnWidth2 <= 0 || left >= canvasRect.width) return;
3085
- const cell = document.createElement("div");
3086
- cell.className = "rvg-row-drag-preview-cell";
3087
- cell.style.left = `${left}px`;
3088
- cell.style.width = `${columnWidth2}px`;
3089
- cell.style.justifyContent = column2.align === "right" ? "flex-end" : column2.align === "center" ? "center" : "flex-start";
3090
- if (column2.rowDragHandle) {
3091
- cell.appendChild(createRowDragHandleSvg());
3092
- } else if (column2.rowSelection) {
3093
- const checkbox = document.createElement("span");
3094
- checkbox.className = selectedRowKeySet.has(rowKey2) ? "rvg-preview-checkbox is-checked" : "rvg-preview-checkbox";
3095
- checkbox.textContent = selectedRowKeySet.has(rowKey2) ? "\u2713" : "";
3096
- cell.appendChild(checkbox);
3097
- } else {
3098
- cell.textContent = getCellLabel(sourceIndex, columnIndex);
3099
- }
3100
- if (selection?.rowKey === rowKey2 && selection.columnKey === column2.key) {
3101
- cell.classList.add("is-selected");
3102
- }
3103
- preview2.appendChild(cell);
3104
- });
3105
- frame.appendChild(preview2);
3106
- container.appendChild(frame);
3107
- return () => frame.remove();
3108
- }
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`;
3109
3012
  const preview = document.createElement("div");
3110
- preview.className = "rvg-column-drag-preview";
3111
- const columnWidth = metrics[sourceIndex].width;
3112
- preview.style.width = `${columnWidth}px`;
3113
- preview.style.height = `${canvasRect.height}px`;
3114
- const column = columns[sourceIndex];
3115
- const header = document.createElement("div");
3116
- header.className = "rvg-column-drag-preview-header";
3117
- header.style.top = `${fixedHeader ? 0 : -scrollRef.current.top}px`;
3118
- header.style.height = `${headerHeight}px`;
3119
- header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
3120
- header.textContent = column.title;
3121
- const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex), headerActionSlotWidth);
3122
- let actionRight = 2;
3123
- if (visibleActions.drag) {
3124
- const icon = createHeaderDragHandleSvg();
3125
- icon.classList.add("rvg-preview-header-icon");
3126
- icon.style.width = `${headerActionSize}px`;
3127
- icon.style.height = `${headerActionSize}px`;
3128
- icon.style.right = `${actionRight}px`;
3129
- header.appendChild(icon);
3130
- actionRight += headerActionSlotWidth;
3131
- }
3132
- if (visibleActions.sort) {
3133
- const direction = sortState?.columnKey === column.key ? sortState.direction : null;
3134
- const icon = createHeaderSortSvg(direction);
3135
- icon.classList.add("rvg-preview-header-icon");
3136
- icon.style.width = `${headerActionSize}px`;
3137
- icon.style.height = `${headerActionSize}px`;
3138
- icon.style.right = `${actionRight}px`;
3139
- header.appendChild(icon);
3140
- actionRight += headerActionSlotWidth;
3141
- }
3142
- if (visibleActions.filter) {
3143
- const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
3144
- icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
3145
- icon.style.width = `${headerActionSize}px`;
3146
- icon.style.height = `${headerActionSize}px`;
3147
- icon.style.right = `${actionRight}px`;
3148
- header.appendChild(icon);
3149
- }
3150
- preview.appendChild(header);
3151
- for (let rowIndex = domRange.rowStart; rowIndex < domRange.rowEnd; rowIndex += 1) {
3152
- const row = rows[rowIndex];
3153
- 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;
3154
3022
  const cell = document.createElement("div");
3155
- cell.className = "rvg-column-drag-preview-cell";
3156
- cell.style.top = `${bodyTop + rowIndex * rowHeight - scrollRef.current.top}px`;
3157
- 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`;
3158
3026
  cell.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
3159
- const key = `${typeof rowKey2}:${String(rowKey2)}\0${column.key}`;
3160
- if (selectedRowKeySet.has(rowKey2) || selectedColumnKeySet.has(column.key)) {
3161
- cell.classList.add("is-axis-selected");
3162
- }
3163
- if (!insertedRowKeys.has(rowKey2) && editedCellKeys.has(key)) cell.classList.add("is-edited");
3164
- if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) {
3165
- cell.classList.remove("is-edited");
3166
- 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);
3167
3036
  }
3168
- cell.textContent = getCellLabel(rowIndex, sourceIndex);
3037
+ if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) cell.classList.add("is-selected");
3169
3038
  preview.appendChild(cell);
3170
- }
3171
- container.appendChild(preview);
3172
- return () => preview.remove();
3039
+ });
3040
+ frame.appendChild(preview);
3041
+ container.appendChild(frame);
3042
+ return () => frame.remove();
3173
3043
  }
3174
3044
  });
3175
3045
  },
3176
3046
  onDragStart: ({ source }) => {
3047
+ const sourceIndex = Number(source.data.sourceIndex);
3177
3048
  suppressClickRef.current = true;
3178
3049
  hideDragTooltips();
3179
3050
  document.documentElement.classList.add("rvg-is-dragging");
3180
3051
  canvas.style.cursor = "move";
3181
- if (source.data.type === "table-row") {
3182
- const sourceIndex = Number(source.data.sourceIndex);
3183
- setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
3184
- }
3052
+ setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
3185
3053
  },
3186
3054
  onDrag: ({ source, location }) => {
3187
3055
  const target = location.current.dropTargets[0]?.data;
3188
3056
  const sourceIndex = Number(source.data.sourceIndex);
3189
- if (source.data.type === "table-row") {
3190
- const rawTargetIndex = Number(target?.targetIndex);
3191
- if (!Number.isInteger(rawTargetIndex)) {
3192
- setRowDragPreview(null);
3193
- return setRowDragGuide(null);
3194
- }
3195
- const edge2 = target?.rowEdge;
3196
- let targetIndex2 = rawTargetIndex + (edge2 === "bottom" ? 1 : 0);
3197
- if (sourceIndex < targetIndex2) targetIndex2 -= 1;
3198
- targetIndex2 = Math.max(0, Math.min(rows.length - 1, targetIndex2));
3199
- setRowDragPreview((current) => current?.sourceIndex === sourceIndex && current.targetIndex === targetIndex2 ? current : { sourceIndex, targetIndex: targetIndex2 });
3200
- setRowDragGuide(bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top + (edge2 === "bottom" ? rowHeight : 0));
3201
- return;
3202
- }
3203
- const targetIndex = Number(target?.targetIndex);
3204
- if (!Number.isInteger(targetIndex) || target?.headerKind !== source.data.headerKind || target?.parentKey !== source.data.parentKey || target?.fixed !== source.data.fixed) {
3205
- validColumnDropRef.current = null;
3206
- setColumnDropTarget(null);
3207
- setDragGuide(null);
3208
- return;
3209
- }
3210
- const edge = target?.columnEdge;
3211
- const destinationIndex = getColumnDropIndex(sourceIndex, targetIndex, edge);
3212
- columnDragPreviewRef.current = { sourceIndex, targetIndex: destinationIndex };
3213
- if (destinationIndex === sourceIndex) {
3214
- validColumnDropRef.current = null;
3215
- setColumnDropTarget(null);
3216
- setDragGuide(null);
3217
- return;
3218
- }
3219
- validColumnDropRef.current = {
3220
- sourceIndex,
3221
- targetIndex: destinationIndex,
3222
- rawTargetIndex: targetIndex,
3223
- targetKey: String(target.targetKey),
3224
- headerKind: source.data.headerKind === "group" ? "group" : "column",
3225
- parentKey: typeof source.data.parentKey === "string" ? source.data.parentKey : void 0,
3226
- fixed: source.data.fixed === "left" || source.data.fixed === "right" ? source.data.fixed : void 0,
3227
- columnEdge: edge === "right" ? "right" : "left"
3228
- };
3229
- 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);
3230
- const targetEndIndex = Number.isInteger(target?.targetEndIndex) ? Number(target.targetEndIndex) : targetIndex;
3231
- const hoveredTargetCell = siblingCells.find((cell) => cell.startIndex === targetIndex && cell.endIndex === targetEndIndex);
3232
- if (!hoveredTargetCell) {
3233
- validColumnDropRef.current = null;
3234
- setColumnDropTarget(null);
3235
- setDragGuide(null);
3236
- return;
3237
- }
3238
- const highlightedCell = edge === "right" ? hoveredTargetCell : siblingCells.filter((cell) => cell.endIndex < hoveredTargetCell.startIndex).sort((left, right) => right.endIndex - left.endIndex)[0] ?? hoveredTargetCell;
3239
- setColumnDropTarget({ startIndex: highlightedCell.startIndex, endIndex: highlightedCell.endIndex });
3240
- const targetLeft = Number(target?.targetLeft);
3241
- const targetWidth = Number(target?.targetWidth);
3242
- if (!Number.isFinite(targetLeft) || !Number.isFinite(targetWidth)) {
3243
- validColumnDropRef.current = null;
3244
- setColumnDropTarget(null);
3245
- setDragGuide(null);
3057
+ const rawTargetIndex = Number(target?.targetIndex);
3058
+ if (!Number.isInteger(rawTargetIndex)) {
3059
+ setRowDragPreview(null);
3060
+ setRowDragGuide(null);
3246
3061
  return;
3247
3062
  }
3248
- const guideTop = headerRowOffsets[Number(source.data.headerLevel)] ?? 0;
3249
- 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));
3250
3069
  },
3251
3070
  onDrop: ({ source, location }) => {
3252
- document.documentElement.classList.remove("rvg-is-dragging");
3253
3071
  const target = location.current.dropTargets[0]?.data;
3254
3072
  const sourceIndex = Number(source.data.sourceIndex);
3255
- if (source.data.type === "table-row") {
3256
- const rawTargetIndex = Number(target?.targetIndex);
3257
- let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
3258
- if (sourceIndex < targetIndex) targetIndex -= 1;
3259
- targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
3260
- scrollerRef.current?.classList.add("rvg-row-drop-settling");
3261
- setRowDragPreview(null);
3262
- setRowDragGuide(null);
3263
- canvas.style.cursor = "default";
3264
- if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
3265
- requestAnimationFrame(() => {
3266
- requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
3267
- });
3268
- window.setTimeout(() => {
3269
- suppressClickRef.current = false;
3270
- }, 0);
3271
- return;
3272
- }
3273
- 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");
3274
3081
  canvas.style.cursor = "default";
3275
- setDragGuide(null);
3276
- setColumnDropTarget(null);
3277
- columnDragPreviewRef.current = null;
3278
- validColumnDropRef.current = null;
3279
- if (validDrop) {
3280
- applyColumnOrder(
3281
- validDrop.sourceIndex - utilityColumnCount,
3282
- validDrop.targetIndex - utilityColumnCount,
3283
- {
3284
- type: validDrop.headerKind,
3285
- sourceKey: String(source.data.sourceKey),
3286
- targetKey: validDrop.targetKey,
3287
- parentKey: validDrop.parentKey,
3288
- placement: getColumnDropPlacement(validDrop.sourceIndex, validDrop.rawTargetIndex, validDrop.columnEdge)
3289
- }
3290
- );
3291
- }
3082
+ if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
3083
+ requestAnimationFrame(() => {
3084
+ requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
3085
+ });
3292
3086
  window.setTimeout(() => {
3293
3087
  suppressClickRef.current = false;
3294
3088
  }, 0);
@@ -3296,43 +3090,14 @@ function TableInner({
3296
3090
  });
3297
3091
  const cleanupDrop = dropTargetForElements({
3298
3092
  element: canvas,
3299
- canDrop: ({ source }) => source.data.type === "table-column" || source.data.type === "table-row",
3093
+ canDrop: ({ source }) => source.data.type === "table-row",
3300
3094
  getDropEffect: () => "move",
3301
- getData: ({ input, element, source }) => {
3302
- if (source.data.type === "table-row") {
3303
- const targetIndex2 = locateRow(input.clientY);
3304
- if (targetIndex2 < 0) return { targetIndex: -1 };
3305
- const rowTop = bodyTop + targetIndex2 * rowHeight - scrollRef.current.top;
3306
- const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
3307
- return attachClosestEdge({ targetIndex: targetIndex2, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
3308
- }
3309
- const hoveredColumnIndex = locateColumn(input.clientX);
3310
- 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);
3311
- if (!targetCell) return { targetIndex: -1 };
3312
- let targetIndex = targetCell.startIndex;
3313
- const targetFixed = columns[targetCell.startIndex]?.fixed;
3314
- const headerKind = targetCell.leaf ? "column" : "group";
3315
- if (source.data.headerKind !== headerKind || source.data.parentKey !== targetCell.parentKey || source.data.fixed !== targetFixed) return { targetIndex: -1 };
3316
- if (columns[targetIndex].rowSelection || columns[targetIndex].rowDragHandle || columns[targetIndex].rowNumber) {
3317
- const fixedSide = columns[Number(source.data.sourceIndex)]?.fixed;
3318
- targetIndex = columns.findIndex((column, index) => index > targetIndex && column.fixed === fixedSide && !column.rowSelection && !column.rowDragHandle && !column.rowNumber);
3319
- if (targetIndex < 0) return { targetIndex: -1 };
3320
- return { targetIndex, columnEdge: "left" };
3321
- }
3322
- const left = getHeaderCellLeft(targetCell);
3323
- const targetWidth = targetCell.leaf ? metrics[targetIndex].width : getHeaderCellWidth(targetCell);
3324
- const columnEdge = input.clientX - canvas.getBoundingClientRect().left < left + targetWidth / 2 ? "left" : "right";
3325
- return attachClosestEdge({
3326
- targetIndex,
3327
- targetEndIndex: targetCell.endIndex,
3328
- targetKey: targetCell.key,
3329
- parentKey: targetCell.parentKey,
3330
- headerKind,
3331
- fixed: targetFixed,
3332
- targetLeft: left,
3333
- targetWidth,
3334
- columnEdge
3335
- }, { 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"] });
3336
3101
  }
3337
3102
  });
3338
3103
  return () => {
@@ -3340,7 +3105,7 @@ function TableInner({
3340
3105
  cleanupDrag();
3341
3106
  cleanupDrop();
3342
3107
  };
3343
- }, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerActionSize, headerActionSlotWidth, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, 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]);
3344
3109
  const locateCell = useCallback2((clientX, clientY) => {
3345
3110
  const canvas = canvasRef.current;
3346
3111
  if (!canvas) return null;
@@ -3787,6 +3552,113 @@ function TableInner({
3787
3552
  setResizeGuideX(null);
3788
3553
  setResizeGuideTop(0);
3789
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]);
3790
3662
  const queueSortStateChange = useCallback2((next) => {
3791
3663
  setSortState(next);
3792
3664
  }, []);
@@ -3796,7 +3668,7 @@ function TableInner({
3796
3668
  const isAxisSelected = selectedColumnKeySet.has(column.key);
3797
3669
  const selectedClassName = isAxisSelected ? " is-axis-selected" : "";
3798
3670
  const hoveredColumnClassName = hoveredHeaderColumnIndex === columnIndex ? " is-header-hovered" : "";
3799
- const top = headerLeafTop + (headerLeafHeight - headerActionSize) / 2;
3671
+ const top = column.renderHeader ? headerLeafTop + 8 + Math.max(0, (16 - headerActionSize) / 2) : headerLeafTop + (headerLeafHeight - headerActionSize) / 2;
3800
3672
  const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
3801
3673
  let right = left + metrics[columnIndex].width - (visibleActions.drag ? headerActionSlotWidth : 2);
3802
3674
  const icons = [];
@@ -4600,7 +4472,7 @@ function TableInner({
4600
4472
  hideDragTooltips();
4601
4473
  return;
4602
4474
  }
4603
- if (columnDragRef.current) return;
4475
+ if (columnDragRef.current || columnOrderDragRef.current?.active) return;
4604
4476
  const rect = event.currentTarget.getBoundingClientRect();
4605
4477
  const localY = event.clientY - rect.top;
4606
4478
  const headerY = fixedHeader ? 0 : -scrollRef.current.top;
@@ -4717,20 +4589,22 @@ function TableInner({
4717
4589
  event.currentTarget.style.cursor = "move";
4718
4590
  }
4719
4591
  handleColumnPointerDown(event);
4592
+ if (!columnDragRef.current) handleColumnOrderPointerDown(event);
4720
4593
  beginRangeDrag(event);
4721
4594
  },
4722
4595
  onPointerMove: (event) => {
4723
4596
  handleColumnPointerMove(event);
4597
+ handleColumnOrderPointerMove(event);
4724
4598
  updateRangeDrag(event);
4725
4599
  },
4726
4600
  onPointerUp: (event) => {
4727
- document.documentElement.classList.remove("rvg-is-dragging");
4728
4601
  handleColumnPointerUp(event);
4602
+ finishColumnOrderPointerDrag(event, true);
4729
4603
  endRangeDrag(event);
4730
4604
  },
4731
4605
  onPointerCancel: (event) => {
4732
- document.documentElement.classList.remove("rvg-is-dragging");
4733
4606
  handleColumnPointerUp(event);
4607
+ finishColumnOrderPointerDrag(event, false);
4734
4608
  endRangeDrag(event);
4735
4609
  },
4736
4610
  onClick: (event) => {