react-glide-table 2.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -33,6 +33,7 @@ __export(src_exports, {
33
33
  Table: () => Table,
34
34
  applyCellEdit: () => applyCellEdit,
35
35
  applyFillData: () => applyFillData,
36
+ applyLeafColumnOrder: () => applyLeafColumnOrder,
36
37
  applySelectionUpdater: () => applySelectionUpdater,
37
38
  buildColumnFreezeOffsets: () => buildColumnFreezeOffsets,
38
39
  buildColumnRowSpanMap: () => buildColumnRowSpanMap,
@@ -47,6 +48,7 @@ __export(src_exports, {
47
48
  collectCopyRowEntries: () => collectCopyRowEntries,
48
49
  collectCopyRows: () => collectCopyRows,
49
50
  collectFillChanges: () => collectFillChanges,
51
+ collectLeafColumnIds: () => collectLeafColumnIds,
50
52
  collectRowSpanColumns: () => collectRowSpanColumns,
51
53
  collectSearchMatchesInRange: () => collectSearchMatchesInRange,
52
54
  commitCellValue: () => commitCellValue,
@@ -72,6 +74,7 @@ __export(src_exports, {
72
74
  mapSearchResultToVisibleItem: () => mapSearchResultToVisibleItem,
73
75
  mapSearchResultsToVisibleKeys: () => mapSearchResultsToVisibleKeys,
74
76
  measureMergedSpanRowHeights: () => measureMergedSpanRowHeights,
77
+ moveColumnIds: () => moveColumnIds,
75
78
  nextSearchIndex: () => nextSearchIndex,
76
79
  nextSearchStride: () => nextSearchStride,
77
80
  parseCellEditValue: () => parseCellEditValue,
@@ -81,7 +84,9 @@ __export(src_exports, {
81
84
  resolveCellRenderer: () => resolveCellRenderer,
82
85
  resolveColumnFreezeSide: () => resolveColumnFreezeSide,
83
86
  resolveDataTableLabels: () => resolveDataTableLabels,
87
+ resolveDropEdge: () => resolveDropEdge,
84
88
  resolveHeaderFreezeOffset: () => resolveHeaderFreezeOffset,
89
+ resolveLeafColumnOrder: () => resolveLeafColumnOrder,
85
90
  resolvePasteColumnIds: () => resolvePasteColumnIds,
86
91
  resolveRowSelection: () => resolveRowSelection,
87
92
  resolveRowSpanAt: () => resolveRowSpanAt,
@@ -91,6 +96,7 @@ __export(src_exports, {
91
96
  toggleExpandedRowId: () => toggleExpandedRowId,
92
97
  useCellEdit: () => useCellEdit,
93
98
  useCellSelection: () => useCellSelection,
99
+ useColumnReorder: () => useColumnReorder,
94
100
  useConvertTreeData: () => useConvertTreeData,
95
101
  useGlideTable: () => useGlideTable,
96
102
  useInlineSearch: () => useInlineSearch,
@@ -107,6 +113,7 @@ var DEFAULT_DATA_TABLE_LABELS = {
107
113
  expandRow: "Expand row",
108
114
  collapseRow: "Collapse row",
109
115
  resizeColumn: "Resize column",
116
+ reorderColumn: "Reorder column",
110
117
  searchPlaceholder: "Search\u2026",
111
118
  searchResultHint: "Type to search",
112
119
  searchPrevious: "Previous result",
@@ -146,6 +153,7 @@ var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
146
153
  var DATA_TABLE_COLUMN_SIZE = 150;
147
154
  var DATA_TABLE_COLUMN_MIN_SIZE = 40;
148
155
  var DATA_TABLE_COLUMN_MAX_SIZE = 800;
156
+ var DATA_TABLE_COLUMN_REORDER_THRESHOLD = 4;
149
157
 
150
158
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
151
159
  var import_react = require("react");
@@ -1411,6 +1419,135 @@ function useCellSelection({
1411
1419
  };
1412
1420
  }
1413
1421
 
1422
+ // src/components/ui/table/features/column-reorder/columnReorder.ts
1423
+ function getColumnDefId(column) {
1424
+ if (column.id != null && column.id !== "") return column.id;
1425
+ if ("accessorKey" in column && column.accessorKey != null) {
1426
+ return String(column.accessorKey);
1427
+ }
1428
+ return void 0;
1429
+ }
1430
+ function getColumnDefChildren(column) {
1431
+ if (!("columns" in column) || !Array.isArray(column.columns)) return void 0;
1432
+ if (column.columns.length === 0) return void 0;
1433
+ return column.columns;
1434
+ }
1435
+ function collectLeafColumnIds(columns) {
1436
+ const ids = [];
1437
+ for (const column of columns) {
1438
+ const children = getColumnDefChildren(column);
1439
+ if (children) {
1440
+ ids.push(...collectLeafColumnIds(children));
1441
+ continue;
1442
+ }
1443
+ const id = getColumnDefId(column);
1444
+ if (id) ids.push(id);
1445
+ }
1446
+ return ids;
1447
+ }
1448
+ function areColumnOrdersEqual(left, right) {
1449
+ if (left.length !== right.length) return false;
1450
+ return left.every((id, index) => id === right[index]);
1451
+ }
1452
+ function resolveLeafColumnOrder(columns, order) {
1453
+ const leafIds = collectLeafColumnIds(columns);
1454
+ if (!order?.length) return leafIds;
1455
+ const leafSet = new Set(leafIds);
1456
+ const seen = /* @__PURE__ */ new Set();
1457
+ const next = order.filter((id) => {
1458
+ if (!leafSet.has(id) || seen.has(id)) return false;
1459
+ seen.add(id);
1460
+ return true;
1461
+ });
1462
+ for (const id of leafIds) {
1463
+ if (!seen.has(id)) next.push(id);
1464
+ }
1465
+ return next;
1466
+ }
1467
+ function flattenColumnSlots(columns, group) {
1468
+ const slots = [];
1469
+ for (const column of columns) {
1470
+ const id = getColumnDefId(column);
1471
+ const children = getColumnDefChildren(column);
1472
+ if (children) {
1473
+ const nestedGroup = id ? { id, def: column } : group;
1474
+ slots.push(...flattenColumnSlots(children, nestedGroup));
1475
+ continue;
1476
+ }
1477
+ if (!id) continue;
1478
+ slots.push({ id, def: column, group });
1479
+ }
1480
+ return slots;
1481
+ }
1482
+ function rebuildColumnTree(slots) {
1483
+ const result = [];
1484
+ let index = 0;
1485
+ while (index < slots.length) {
1486
+ const slot = slots[index];
1487
+ if (!slot.group) {
1488
+ result.push(slot.def);
1489
+ index += 1;
1490
+ continue;
1491
+ }
1492
+ const groupId = slot.group.id;
1493
+ const children = [];
1494
+ while (index < slots.length && slots[index]?.group?.id === groupId) {
1495
+ children.push(slots[index].def);
1496
+ index += 1;
1497
+ }
1498
+ const firstChildId = children[0] ? getColumnDefId(children[0]) : groupId;
1499
+ result.push({
1500
+ ...slot.group.def,
1501
+ id: `${groupId}::${firstChildId}`,
1502
+ columns: children
1503
+ });
1504
+ }
1505
+ return result;
1506
+ }
1507
+ function applyLeafColumnOrder(columns, order) {
1508
+ const resolved = resolveLeafColumnOrder(columns, order);
1509
+ const defaultOrder = collectLeafColumnIds(columns);
1510
+ if (areColumnOrdersEqual(resolved, defaultOrder)) {
1511
+ return columns;
1512
+ }
1513
+ const byId = new Map(
1514
+ flattenColumnSlots(columns).map((slot) => [
1515
+ slot.id,
1516
+ slot
1517
+ ])
1518
+ );
1519
+ const ordered = [];
1520
+ for (const id of resolved) {
1521
+ const slot = byId.get(id);
1522
+ if (slot) ordered.push(slot);
1523
+ }
1524
+ return rebuildColumnTree(ordered);
1525
+ }
1526
+ function moveColumnIds(order, fromIds, targetIds, edge) {
1527
+ if (fromIds.length === 0 || targetIds.length === 0) return [...order];
1528
+ const fromSet = new Set(fromIds);
1529
+ if (targetIds.some((id) => fromSet.has(id))) return [...order];
1530
+ const rest = order.filter((id) => !fromSet.has(id));
1531
+ const anchorId = edge === "before" ? targetIds[0] : targetIds[targetIds.length - 1];
1532
+ const anchorIndex = rest.indexOf(anchorId);
1533
+ if (anchorIndex < 0) return [...order];
1534
+ const insertAt = edge === "before" ? anchorIndex : anchorIndex + 1;
1535
+ return [...rest.slice(0, insertAt), ...fromIds, ...rest.slice(insertAt)];
1536
+ }
1537
+ function resolveDropEdge(clientX, rect) {
1538
+ return clientX < rect.left + rect.width / 2 ? "before" : "after";
1539
+ }
1540
+ function parseReorderIds(value) {
1541
+ if (!value) return [];
1542
+ return value.split(",").filter(Boolean);
1543
+ }
1544
+ function serializeReorderIds(ids) {
1545
+ return ids.join(",");
1546
+ }
1547
+ function isColumnReorderable(meta) {
1548
+ return meta?.reorderable !== false;
1549
+ }
1550
+
1414
1551
  // src/components/ui/table/features/column-freeze/columnFreeze.ts
1415
1552
  var HEADER_Z_BASE = 30;
1416
1553
  var BODY_Z_BASE = 5;
@@ -2177,23 +2314,49 @@ function applySelectionUpdater(mode, updater, previous) {
2177
2314
  function getRowFieldValue(row, key) {
2178
2315
  return row[key];
2179
2316
  }
2180
- function computeRowSpans(data, rowSpanKey) {
2317
+ function normalizeRowSpanParent(value) {
2318
+ if (!value) return [];
2319
+ return typeof value === "string" ? [value] : [...value];
2320
+ }
2321
+ function toParentSpanList(parentSpans) {
2322
+ if (!parentSpans?.length) return [];
2323
+ const first = parentSpans[0];
2324
+ if (!Array.isArray(first)) {
2325
+ return [parentSpans];
2326
+ }
2327
+ return parentSpans;
2328
+ }
2329
+ function buildStartRowLookup(spans) {
2330
+ const startRows = new Array(spans.length);
2331
+ let origin = 0;
2332
+ for (let i = 0; i < spans.length; i++) {
2333
+ if ((spans[i]?.rowSpan ?? 1) > 0) origin = i;
2334
+ startRows[i] = origin;
2335
+ }
2336
+ return startRows;
2337
+ }
2338
+ function sharesParentGroup(parentStartRows, rowIndex) {
2339
+ if (parentStartRows.length === 0 || rowIndex <= 0) return true;
2340
+ return parentStartRows.every(
2341
+ (startRows) => startRows[rowIndex - 1] === startRows[rowIndex]
2342
+ );
2343
+ }
2344
+ function computeRowSpans(data, rowSpanKey, parentSpans) {
2181
2345
  if (data.length === 0) return [];
2346
+ const parentStartRows = toParentSpanList(parentSpans).map(buildStartRowLookup);
2182
2347
  const result = [];
2183
2348
  for (let index = 0; index < data.length; index++) {
2184
2349
  const currentValue = getRowFieldValue(data[index], rowSpanKey);
2185
2350
  const previousValue = index > 0 ? getRowFieldValue(data[index - 1], rowSpanKey) : void 0;
2186
- if (index > 0 && currentValue === previousValue) {
2351
+ if (index > 0 && currentValue === previousValue && sharesParentGroup(parentStartRows, index)) {
2187
2352
  result.push({ rowSpan: 0, isFirstInGroup: false });
2188
2353
  continue;
2189
2354
  }
2190
2355
  let span = 1;
2191
2356
  for (let nextIndex = index + 1; nextIndex < data.length; nextIndex++) {
2192
- if (getRowFieldValue(data[nextIndex], rowSpanKey) === currentValue) {
2193
- span++;
2194
- } else {
2195
- break;
2196
- }
2357
+ if (getRowFieldValue(data[nextIndex], rowSpanKey) !== currentValue) break;
2358
+ if (!sharesParentGroup(parentStartRows, nextIndex)) break;
2359
+ span++;
2197
2360
  }
2198
2361
  result.push({ rowSpan: span, isFirstInGroup: true });
2199
2362
  }
@@ -2215,10 +2378,50 @@ function resolveRowSpanAt(rowSpans, rowIndex) {
2215
2378
  }
2216
2379
  return { startRow: rowIndex, rowSpan: 1 };
2217
2380
  }
2381
+ function findRowSpanColumn(spec, ref) {
2382
+ return spec.find((column) => column.columnId === ref) ?? spec.find((column) => column.rowSpanKey === ref);
2383
+ }
2218
2384
  function buildColumnRowSpanMap(data, columnKeys) {
2219
2385
  const map = /* @__PURE__ */ new Map();
2220
- for (const { columnId, rowSpanKey } of columnKeys) {
2221
- map.set(columnId, computeRowSpans(data, rowSpanKey));
2386
+ const visiting = /* @__PURE__ */ new Set();
2387
+ const warnedCycles = /* @__PURE__ */ new Set();
2388
+ const virtualParents = /* @__PURE__ */ new Map();
2389
+ const spansForColumn = (columnId) => {
2390
+ const cached = map.get(columnId);
2391
+ if (cached !== void 0) return cached;
2392
+ const column = columnKeys.find((item) => item.columnId === columnId);
2393
+ if (!column) return void 0;
2394
+ if (visiting.has(columnId)) {
2395
+ if (!warnedCycles.has(columnId)) {
2396
+ warnedCycles.add(columnId);
2397
+ console.warn(
2398
+ `[rowSpan] rowSpanParent cycle detected at column "${columnId}"; dropping the cyclic parent reference.`
2399
+ );
2400
+ }
2401
+ return void 0;
2402
+ }
2403
+ visiting.add(columnId);
2404
+ const parentSpans = (column.rowSpanParent ?? []).map((ref) => spansForParentRef(ref)).filter((spans2) => Boolean(spans2));
2405
+ visiting.delete(columnId);
2406
+ const spans = computeRowSpans(
2407
+ data,
2408
+ column.rowSpanKey,
2409
+ parentSpans.length > 0 ? parentSpans : void 0
2410
+ );
2411
+ map.set(columnId, spans);
2412
+ return spans;
2413
+ };
2414
+ const spansForParentRef = (ref) => {
2415
+ const parentColumn = findRowSpanColumn(columnKeys, ref);
2416
+ if (parentColumn) return spansForColumn(parentColumn.columnId);
2417
+ const cached = virtualParents.get(ref);
2418
+ if (cached !== void 0) return cached;
2419
+ const spans = computeRowSpans(data, ref);
2420
+ virtualParents.set(ref, spans);
2421
+ return spans;
2422
+ };
2423
+ for (const column of columnKeys) {
2424
+ spansForColumn(column.columnId);
2222
2425
  }
2223
2426
  return map;
2224
2427
  }
@@ -2234,7 +2437,8 @@ function collectRowSpanColumns(columns) {
2234
2437
  if (!columnId || !columnDef.meta?.rowSpan) continue;
2235
2438
  result.push({
2236
2439
  columnId,
2237
- rowSpanKey: columnDef.meta.rowSpanKey ?? columnId
2440
+ rowSpanKey: columnDef.meta.rowSpanKey ?? columnId,
2441
+ rowSpanParent: normalizeRowSpanParent(columnDef.meta.rowSpanParent)
2238
2442
  });
2239
2443
  }
2240
2444
  };
@@ -2286,6 +2490,9 @@ function useGlideTable(options) {
2286
2490
  columnSizing: controlledColumnSizing,
2287
2491
  onColumnSizingChange,
2288
2492
  columnResizeMode = "onChange",
2493
+ enableColumnReorder = false,
2494
+ columnOrder: controlledColumnOrder,
2495
+ onColumnOrderChange,
2289
2496
  enableColumnFreeze = false,
2290
2497
  enableInlineSearch = false,
2291
2498
  showSearch,
@@ -2308,6 +2515,7 @@ function useGlideTable(options) {
2308
2515
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
2309
2516
  const [internalRowSelection, setInternalRowSelection] = (0, import_react5.useState)({});
2310
2517
  const [internalColumnSizing, setInternalColumnSizing] = (0, import_react5.useState)({});
2518
+ const [internalColumnOrder, setInternalColumnOrder] = (0, import_react5.useState)([]);
2311
2519
  const [internalExpandedRows, setInternalExpandedRows] = (0, import_react5.useState)(
2312
2520
  () => /* @__PURE__ */ new Set()
2313
2521
  );
@@ -2328,6 +2536,21 @@ function useGlideTable(options) {
2328
2536
  internalRowSelection
2329
2537
  );
2330
2538
  const columnSizing = controlledColumnSizing ?? internalColumnSizing;
2539
+ const columnOrder = controlledColumnOrder ?? internalColumnOrder;
2540
+ const tableColumns = (0, import_react5.useMemo)(() => {
2541
+ if (!enableColumnReorder) return columns;
2542
+ return applyLeafColumnOrder(columns, columnOrder);
2543
+ }, [columnOrder, columns, enableColumnReorder]);
2544
+ const setColumnOrder = (0, import_react5.useCallback)(
2545
+ (next) => {
2546
+ if (onColumnOrderChange) {
2547
+ onColumnOrderChange(next);
2548
+ return;
2549
+ }
2550
+ setInternalColumnOrder(next);
2551
+ },
2552
+ [onColumnOrderChange]
2553
+ );
2331
2554
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
2332
2555
  const handleExpandedRowsChange = (0, import_react5.useCallback)(
2333
2556
  (next) => {
@@ -2352,7 +2575,7 @@ function useGlideTable(options) {
2352
2575
  });
2353
2576
  const table = (0, import_react_table.useReactTable)({
2354
2577
  data: tableData,
2355
- columns,
2578
+ columns: tableColumns,
2356
2579
  ...enableColumnResize ? {
2357
2580
  defaultColumn: {
2358
2581
  minSize: DATA_TABLE_COLUMN_MIN_SIZE,
@@ -2834,6 +3057,7 @@ function useGlideTable(options) {
2834
3057
  selectionLabel: labels.selection,
2835
3058
  enableCellSelection,
2836
3059
  enableColumnResize,
3060
+ enableColumnReorder,
2837
3061
  enableColumnFreeze,
2838
3062
  enableInlineSearch,
2839
3063
  shouldVirtualize,
@@ -2847,6 +3071,7 @@ function useGlideTable(options) {
2847
3071
  getCellContext,
2848
3072
  handleToggleSelect,
2849
3073
  clearHover,
3074
+ setColumnOrder,
2850
3075
  copySelection: stableCopySelection,
2851
3076
  inlineSearch: {
2852
3077
  showSearch: inlineSearch.showSearch,
@@ -2932,13 +3157,221 @@ function getColumnSizeStyle(size, options) {
2932
3157
  };
2933
3158
  }
2934
3159
 
3160
+ // src/components/ui/table/features/column-reorder/useColumnReorder.ts
3161
+ var import_react8 = require("react");
3162
+ function hitTestReorderHeader(table, clientX, clientY) {
3163
+ const headers = Array.from(
3164
+ table.querySelectorAll(
3165
+ "thead th[data-column-id][data-reorder-ids]"
3166
+ )
3167
+ );
3168
+ const containing = headers.find((element) => {
3169
+ const rect = element.getBoundingClientRect();
3170
+ return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
3171
+ });
3172
+ if (containing) {
3173
+ return {
3174
+ columnId: containing.dataset.columnId ?? "",
3175
+ edge: resolveDropEdge(clientX, containing.getBoundingClientRect())
3176
+ };
3177
+ }
3178
+ const leaves = headers.filter(
3179
+ (element) => element.hasAttribute("data-reorder-leaf")
3180
+ );
3181
+ let match;
3182
+ for (const element of leaves) {
3183
+ const rect = element.getBoundingClientRect();
3184
+ if (clientX >= rect.left && clientX <= rect.right) {
3185
+ match = element;
3186
+ break;
3187
+ }
3188
+ }
3189
+ if (!match && leaves.length > 0) {
3190
+ const first = leaves[0].getBoundingClientRect();
3191
+ const last = leaves[leaves.length - 1].getBoundingClientRect();
3192
+ if (clientX < first.left) match = leaves[0];
3193
+ else if (clientX > last.right) match = leaves[leaves.length - 1];
3194
+ }
3195
+ if (!match) return null;
3196
+ return {
3197
+ columnId: match.dataset.columnId ?? "",
3198
+ edge: resolveDropEdge(clientX, match.getBoundingClientRect())
3199
+ };
3200
+ }
3201
+ function readTargetIds(table, columnId) {
3202
+ const element = table.querySelector(
3203
+ `thead th[data-column-id="${CSS.escape(columnId)}"]`
3204
+ );
3205
+ return parseReorderIds(element?.getAttribute("data-reorder-ids"));
3206
+ }
3207
+ function useColumnReorder(options) {
3208
+ const { enabled, columnOrder, onColumnOrderChange } = options;
3209
+ const sessionRef = (0, import_react8.useRef)(null);
3210
+ const columnOrderRef = (0, import_react8.useRef)(columnOrder);
3211
+ const onColumnOrderChangeRef = (0, import_react8.useRef)(onColumnOrderChange);
3212
+ const [draggingColumnId, setDraggingColumnId] = (0, import_react8.useState)(null);
3213
+ const [dropTarget, setDropTarget] = (0, import_react8.useState)(
3214
+ null
3215
+ );
3216
+ const dropTargetRef = (0, import_react8.useRef)(dropTarget);
3217
+ const previousUserSelectRef = (0, import_react8.useRef)(null);
3218
+ columnOrderRef.current = columnOrder;
3219
+ onColumnOrderChangeRef.current = onColumnOrderChange;
3220
+ dropTargetRef.current = dropTarget;
3221
+ const resetDrag = (0, import_react8.useCallback)(() => {
3222
+ sessionRef.current = null;
3223
+ setDraggingColumnId(null);
3224
+ setDropTarget(null);
3225
+ const backup = previousUserSelectRef.current;
3226
+ previousUserSelectRef.current = null;
3227
+ if (backup) {
3228
+ if (backup.value) {
3229
+ document.body.style.setProperty("user-select", backup.value, backup.priority);
3230
+ } else {
3231
+ document.body.style.removeProperty("user-select");
3232
+ }
3233
+ return;
3234
+ }
3235
+ document.body.style.removeProperty("user-select");
3236
+ }, []);
3237
+ (0, import_react8.useEffect)(() => {
3238
+ if (!enabled) resetDrag();
3239
+ }, [enabled, resetDrag]);
3240
+ (0, import_react8.useEffect)(() => {
3241
+ return () => {
3242
+ resetDrag();
3243
+ };
3244
+ }, [resetDrag]);
3245
+ const onHeaderPointerDown = (0, import_react8.useCallback)(
3246
+ (event, meta) => {
3247
+ if (!enabled || !meta.canDrag) return;
3248
+ if (event.button !== 0) return;
3249
+ if (event.pointerType === "mouse" && event.ctrlKey) return;
3250
+ const target = event.target;
3251
+ if (target instanceof Element && target.closest("[data-table-disable-cell-selection]")) {
3252
+ return;
3253
+ }
3254
+ const table = event.currentTarget.closest("table");
3255
+ if (!(table instanceof HTMLTableElement)) return;
3256
+ sessionRef.current = {
3257
+ pointerId: event.pointerId,
3258
+ startX: event.clientX,
3259
+ startY: event.clientY,
3260
+ columnId: meta.columnId,
3261
+ fromIds: meta.leafIds,
3262
+ table,
3263
+ active: false
3264
+ };
3265
+ },
3266
+ [enabled]
3267
+ );
3268
+ (0, import_react8.useEffect)(() => {
3269
+ if (!enabled) return;
3270
+ const onPointerMove = (event) => {
3271
+ const session = sessionRef.current;
3272
+ if (!session || event.pointerId !== session.pointerId) return;
3273
+ const deltaX = event.clientX - session.startX;
3274
+ const deltaY = event.clientY - session.startY;
3275
+ const distance = Math.hypot(deltaX, deltaY);
3276
+ if (!session.active) {
3277
+ if (distance < DATA_TABLE_COLUMN_REORDER_THRESHOLD) return;
3278
+ session.active = true;
3279
+ if (!previousUserSelectRef.current) {
3280
+ previousUserSelectRef.current = {
3281
+ value: document.body.style.getPropertyValue("user-select"),
3282
+ priority: document.body.style.getPropertyPriority("user-select")
3283
+ };
3284
+ }
3285
+ document.body.style.setProperty("user-select", "none");
3286
+ setDraggingColumnId(session.columnId);
3287
+ }
3288
+ event.preventDefault();
3289
+ const nextTarget = hitTestReorderHeader(
3290
+ session.table,
3291
+ event.clientX,
3292
+ event.clientY
3293
+ );
3294
+ if (!nextTarget || !nextTarget.columnId) {
3295
+ setDropTarget(null);
3296
+ return;
3297
+ }
3298
+ const targetIds = readTargetIds(session.table, nextTarget.columnId);
3299
+ const fromSet = new Set(session.fromIds);
3300
+ if (targetIds.some((id) => fromSet.has(id))) {
3301
+ setDropTarget(null);
3302
+ return;
3303
+ }
3304
+ setDropTarget((previous) => {
3305
+ if (previous?.columnId === nextTarget.columnId && previous.edge === nextTarget.edge) {
3306
+ return previous;
3307
+ }
3308
+ return nextTarget;
3309
+ });
3310
+ };
3311
+ const onPointerUp = (event) => {
3312
+ const session = sessionRef.current;
3313
+ if (!session || event.pointerId !== session.pointerId) {
3314
+ return;
3315
+ }
3316
+ if (session.active) {
3317
+ event.preventDefault();
3318
+ const target = dropTargetRef.current;
3319
+ if (target) {
3320
+ const targetIds = readTargetIds(session.table, target.columnId);
3321
+ const next = moveColumnIds(
3322
+ columnOrderRef.current,
3323
+ session.fromIds,
3324
+ targetIds,
3325
+ target.edge
3326
+ );
3327
+ onColumnOrderChangeRef.current(next);
3328
+ }
3329
+ const suppressClick = (clickEvent) => {
3330
+ clickEvent.preventDefault();
3331
+ clickEvent.stopPropagation();
3332
+ document.removeEventListener("click", suppressClick, true);
3333
+ };
3334
+ document.addEventListener("click", suppressClick, true);
3335
+ window.setTimeout(() => {
3336
+ document.removeEventListener("click", suppressClick, true);
3337
+ }, 0);
3338
+ }
3339
+ resetDrag();
3340
+ };
3341
+ const onPointerCancel = (event) => {
3342
+ const session = sessionRef.current;
3343
+ if (!session || event.pointerId !== session.pointerId) {
3344
+ return;
3345
+ }
3346
+ if (session.active) {
3347
+ event.preventDefault();
3348
+ }
3349
+ resetDrag();
3350
+ };
3351
+ document.addEventListener("pointermove", onPointerMove);
3352
+ document.addEventListener("pointerup", onPointerUp);
3353
+ document.addEventListener("pointercancel", onPointerCancel);
3354
+ return () => {
3355
+ document.removeEventListener("pointermove", onPointerMove);
3356
+ document.removeEventListener("pointerup", onPointerUp);
3357
+ document.removeEventListener("pointercancel", onPointerCancel);
3358
+ };
3359
+ }, [enabled, resetDrag]);
3360
+ return {
3361
+ isReordering: draggingColumnId != null,
3362
+ draggingColumnId,
3363
+ dropTarget,
3364
+ onHeaderPointerDown
3365
+ };
3366
+ }
3367
+
2935
3368
  // src/components/ui/table/components/DataTable/DataTable.tsx
2936
3369
  var import_react_table3 = require("@tanstack/react-table");
2937
- var import_react9 = require("react");
3370
+ var import_react10 = require("react");
2938
3371
 
2939
3372
  // src/components/ui/table/components/DataTable/DataTableRow.tsx
2940
3373
  var import_react_table2 = require("@tanstack/react-table");
2941
- var import_react8 = require("react");
3374
+ var import_react9 = require("react");
2942
3375
 
2943
3376
  // src/components/ui/table/components/icons.tsx
2944
3377
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -3236,9 +3669,9 @@ function DataTableRow({
3236
3669
  const expandKey = toggleField && rowData[toggleField] !== null && rowData[toggleField] !== void 0 ? String(rowData[toggleField]) : null;
3237
3670
  const isExpanded = expandKey !== null && Boolean(expandedRows?.has(expandKey));
3238
3671
  const rowLevel = typeof rowData.level === "number" ? rowData.level : 0;
3239
- const editInputRef = (0, import_react8.useRef)(null);
3672
+ const editInputRef = (0, import_react9.useRef)(null);
3240
3673
  const isRowEditing = editingCell?.rowIndex === rowIndex;
3241
- (0, import_react8.useEffect)(() => {
3674
+ (0, import_react9.useEffect)(() => {
3242
3675
  if (!isRowEditing) return;
3243
3676
  editInputRef.current?.focus();
3244
3677
  editInputRef.current?.select();
@@ -3836,6 +4269,7 @@ function DataTable({
3836
4269
  selectionLabel,
3837
4270
  enableCellSelection,
3838
4271
  enableColumnResize,
4272
+ enableColumnReorder,
3839
4273
  enableColumnFreeze,
3840
4274
  enableInlineSearch,
3841
4275
  shouldVirtualize,
@@ -3848,6 +4282,7 @@ function DataTable({
3848
4282
  rowContextValue,
3849
4283
  handleToggleSelect,
3850
4284
  clearHover,
4285
+ setColumnOrder,
3851
4286
  inlineSearch
3852
4287
  } = useGlideTable(glideOptions);
3853
4288
  const ToolbarSlot = slots?.Toolbar ?? DataTableToolbar;
@@ -3857,7 +4292,13 @@ function DataTable({
3857
4292
  const EmptySlot = slots?.Empty ?? DefaultEmpty;
3858
4293
  const freezeOffsets = rowContextValue.columnFreeze.offsets;
3859
4294
  const headerGroups = getMergedHeaderGroups(table.getHeaderGroups());
3860
- const contextValue = (0, import_react9.useMemo)(
4295
+ const leafColumnIds = table.getVisibleLeafColumns().map((column) => column.id);
4296
+ const { isReordering, draggingColumnId, dropTarget, onHeaderPointerDown } = useColumnReorder({
4297
+ enabled: enableColumnReorder,
4298
+ columnOrder: leafColumnIds,
4299
+ onColumnOrderChange: setColumnOrder
4300
+ });
4301
+ const contextValue = (0, import_react10.useMemo)(
3861
4302
  () => ({ ...rowContextValue, classNames }),
3862
4303
  [rowContextValue, classNames]
3863
4304
  );
@@ -3879,6 +4320,8 @@ function DataTable({
3879
4320
  "DataTableJSX",
3880
4321
  !enableCellSelection && "DataTableJSX--no-cell-selection",
3881
4322
  enableColumnResize && "DataTableJSX--column-resize",
4323
+ enableColumnReorder && "DataTableJSX--column-reorder",
4324
+ isReordering && "DataTableJSX--column-reordering",
3882
4325
  enableColumnFreeze && "DataTableJSX--column-freeze",
3883
4326
  enableInlineSearch && "DataTableJSX--inline-search",
3884
4327
  classNames?.root,
@@ -3947,20 +4390,43 @@ function DataTable({
3947
4390
  ...sizeStyle,
3948
4391
  ...freezeStyle
3949
4392
  };
4393
+ const isPlaceholder = header.isPlaceholder;
4394
+ const leafColumns = header.column.getLeafColumns();
4395
+ const leafIds = leafColumns.map((leafColumn) => leafColumn.id);
4396
+ const isLeafHeader = !isPlaceholder && header.subHeaders.length === 0;
4397
+ const canDrag = enableColumnReorder && !isPlaceholder && leafIds.length > 0 && leafColumns.every(
4398
+ (leafColumn) => isColumnReorderable(leafColumn.columnDef.meta)
4399
+ );
4400
+ const isDragging = draggingColumnId === header.column.id;
4401
+ const dropEdge = !isPlaceholder && dropTarget?.columnId === header.column.id ? dropTarget.edge : void 0;
3950
4402
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3951
4403
  "th",
3952
4404
  {
3953
4405
  colSpan: header.colSpan,
3954
4406
  rowSpan: header.mergedRowSpan,
4407
+ "data-column-id": enableColumnReorder && !isPlaceholder ? header.column.id : void 0,
4408
+ "data-reorder-ids": enableColumnReorder && !isPlaceholder ? serializeReorderIds(leafIds) : void 0,
4409
+ "data-reorder-leaf": enableColumnReorder && isLeafHeader ? "" : void 0,
4410
+ "data-reorderable": canDrag ? "" : void 0,
4411
+ "data-reordering": isDragging ? "" : void 0,
4412
+ "data-drop-edge": dropEdge,
3955
4413
  "data-resizing": header.column.getIsResizing() ? "" : void 0,
3956
4414
  "data-frozen": freezeOffset?.side,
3957
4415
  "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
4416
+ "aria-grabbed": isDragging ? true : void 0,
4417
+ title: canDrag ? labels.reorderColumn : void 0,
4418
+ onPointerDown: enableColumnReorder ? (event) => onHeaderPointerDown(event, {
4419
+ columnId: header.column.id,
4420
+ leafIds,
4421
+ canDrag
4422
+ }) : void 0,
3958
4423
  style: Object.keys(headerStyle).length > 0 ? headerStyle : void 0,
3959
4424
  className: cn(
3960
4425
  "data-table-head-cell",
3961
4426
  freezeOffset && `data-table-head-cell--frozen-${freezeOffset.side}`,
3962
4427
  CELL_ALIGN_CLASS[align],
3963
4428
  classNames?.headCell,
4429
+ dropEdge && classNames?.dropEdge,
3964
4430
  headerClassName
3965
4431
  ),
3966
4432
  children: [
@@ -4082,7 +4548,7 @@ function DataTable({
4082
4548
  }
4083
4549
 
4084
4550
  // src/components/ui/table/components/Table/Table.tsx
4085
- var import_react12 = require("react");
4551
+ var import_react13 = require("react");
4086
4552
 
4087
4553
  // src/components/ui/table/components/Table/buildColumnDef.tsx
4088
4554
  var import_jsx_runtime8 = require("react/jsx-runtime");
@@ -4120,10 +4586,12 @@ function buildColumnDef(props, sort, onSort) {
4120
4586
  minWidth,
4121
4587
  maxWidth,
4122
4588
  resizable,
4589
+ reorderable,
4123
4590
  frozen,
4124
4591
  align,
4125
4592
  rowSpan,
4126
4593
  rowSpanKey,
4594
+ rowSpanParent,
4127
4595
  editable,
4128
4596
  editType,
4129
4597
  editInputProps,
@@ -4158,6 +4626,7 @@ function buildColumnDef(props, sort, onSort) {
4158
4626
  align,
4159
4627
  rowSpan,
4160
4628
  rowSpanKey,
4629
+ rowSpanParent,
4161
4630
  editable,
4162
4631
  editType,
4163
4632
  editInputProps,
@@ -4165,6 +4634,7 @@ function buildColumnDef(props, sort, onSort) {
4165
4634
  cellProps,
4166
4635
  cellRender: render,
4167
4636
  frozen,
4637
+ reorderable,
4168
4638
  className,
4169
4639
  headerClassName
4170
4640
  }
@@ -4210,10 +4680,10 @@ function countLeafColumns(nodes) {
4210
4680
  }
4211
4681
 
4212
4682
  // src/components/ui/table/components/Table/parseTableChildren.ts
4213
- var import_react11 = require("react");
4683
+ var import_react12 = require("react");
4214
4684
 
4215
4685
  // src/components/ui/table/components/Table/tableChildTypes.ts
4216
- var import_react10 = require("react");
4686
+ var import_react11 = require("react");
4217
4687
  var TABLE_HEADER_DISPLAY_NAME = "Table.Header";
4218
4688
  var TABLE_BODY_DISPLAY_NAME = "Table.Body";
4219
4689
  var TABLE_COLUMN_DISPLAY_NAME = "Table.Column";
@@ -4226,19 +4696,19 @@ function getComponentDisplayName(type) {
4226
4696
  return void 0;
4227
4697
  }
4228
4698
  function isTableHeaderElement(child) {
4229
- return (0, import_react10.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_HEADER_DISPLAY_NAME;
4699
+ return (0, import_react11.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_HEADER_DISPLAY_NAME;
4230
4700
  }
4231
4701
  function isTableBodyElement(child) {
4232
- return (0, import_react10.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_BODY_DISPLAY_NAME;
4702
+ return (0, import_react11.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_BODY_DISPLAY_NAME;
4233
4703
  }
4234
4704
  function isTableColumnElement(child) {
4235
- return (0, import_react10.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_DISPLAY_NAME;
4705
+ return (0, import_react11.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_DISPLAY_NAME;
4236
4706
  }
4237
4707
  function isTableColumnGroupElement(child) {
4238
- return (0, import_react10.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_GROUP_DISPLAY_NAME;
4708
+ return (0, import_react11.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_GROUP_DISPLAY_NAME;
4239
4709
  }
4240
4710
  function isTablePaginationElement(child) {
4241
- return (0, import_react10.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_PAGINATION_DISPLAY_NAME;
4711
+ return (0, import_react11.isValidElement)(child) && getComponentDisplayName(child.type) === TABLE_PAGINATION_DISPLAY_NAME;
4242
4712
  }
4243
4713
 
4244
4714
  // src/components/ui/table/components/Table/parseTableChildren.ts
@@ -4248,7 +4718,7 @@ function parseTableChildren(children) {
4248
4718
  body: null,
4249
4719
  pagination: null
4250
4720
  };
4251
- for (const child of import_react11.Children.toArray(children)) {
4721
+ for (const child of import_react12.Children.toArray(children)) {
4252
4722
  if (isTableHeaderElement(child)) {
4253
4723
  slots.header = child;
4254
4724
  continue;
@@ -4265,7 +4735,7 @@ function parseTableChildren(children) {
4265
4735
  }
4266
4736
  function walkColumnTreeNodes(children) {
4267
4737
  const result = [];
4268
- for (const child of import_react11.Children.toArray(children)) {
4738
+ for (const child of import_react12.Children.toArray(children)) {
4269
4739
  if (isTableColumnElement(child)) {
4270
4740
  result.push({
4271
4741
  type: "leaf",
@@ -4282,7 +4752,7 @@ function walkColumnTreeNodes(children) {
4282
4752
  });
4283
4753
  continue;
4284
4754
  }
4285
- if ((0, import_react11.isValidElement)(child)) {
4755
+ if ((0, import_react12.isValidElement)(child)) {
4286
4756
  const nested = child.props.children;
4287
4757
  if (nested != null) {
4288
4758
  result.push(...walkColumnTreeNodes(nested));
@@ -4408,12 +4878,12 @@ function TableRoot({
4408
4878
  filteredCount,
4409
4879
  ...dataTableProps
4410
4880
  }) {
4411
- const { header, pagination: paginationElement } = (0, import_react12.useMemo)(
4881
+ const { header, pagination: paginationElement } = (0, import_react13.useMemo)(
4412
4882
  () => parseTableChildren(children),
4413
4883
  [children]
4414
4884
  );
4415
- const [sort, setSort] = (0, import_react12.useState)(null);
4416
- const handleSort = (0, import_react12.useCallback)((field) => {
4885
+ const [sort, setSort] = (0, import_react13.useState)(null);
4886
+ const handleSort = (0, import_react13.useCallback)((field) => {
4417
4887
  setSort((previous) => {
4418
4888
  if (previous?.field !== field) {
4419
4889
  return { field, direction: "asc" };
@@ -4424,8 +4894,8 @@ function TableRoot({
4424
4894
  return null;
4425
4895
  });
4426
4896
  }, []);
4427
- const columnTree = (0, import_react12.useMemo)(() => extractColumnTree(header), [header]);
4428
- const columns = (0, import_react12.useMemo)(
4897
+ const columnTree = (0, import_react13.useMemo)(() => extractColumnTree(header), [header]);
4898
+ const columns = (0, import_react13.useMemo)(
4429
4899
  () => buildColumnDefsFromTree(columnTree, sort, handleSort),
4430
4900
  [columnTree, sort, handleSort]
4431
4901
  );
@@ -4433,7 +4903,7 @@ function TableRoot({
4433
4903
  const pageSize = paginationProps?.pageSize ?? 10;
4434
4904
  const page = paginationProps?.page ?? 1;
4435
4905
  const resolvedTotalCount = paginationProps?.totalCount ?? totalCount ?? data.length;
4436
- const tableData = (0, import_react12.useMemo)(() => {
4906
+ const tableData = (0, import_react13.useMemo)(() => {
4437
4907
  const sortedData = sortTableData(data, sort);
4438
4908
  if (!paginationProps) return sortedData;
4439
4909
  return paginateTableData(sortedData, page, pageSize);
@@ -4511,6 +4981,7 @@ var Table = Object.assign(TableRoot, {
4511
4981
  Table,
4512
4982
  applyCellEdit,
4513
4983
  applyFillData,
4984
+ applyLeafColumnOrder,
4514
4985
  applySelectionUpdater,
4515
4986
  buildColumnFreezeOffsets,
4516
4987
  buildColumnRowSpanMap,
@@ -4525,6 +4996,7 @@ var Table = Object.assign(TableRoot, {
4525
4996
  collectCopyRowEntries,
4526
4997
  collectCopyRows,
4527
4998
  collectFillChanges,
4999
+ collectLeafColumnIds,
4528
5000
  collectRowSpanColumns,
4529
5001
  collectSearchMatchesInRange,
4530
5002
  commitCellValue,
@@ -4550,6 +5022,7 @@ var Table = Object.assign(TableRoot, {
4550
5022
  mapSearchResultToVisibleItem,
4551
5023
  mapSearchResultsToVisibleKeys,
4552
5024
  measureMergedSpanRowHeights,
5025
+ moveColumnIds,
4553
5026
  nextSearchIndex,
4554
5027
  nextSearchStride,
4555
5028
  parseCellEditValue,
@@ -4559,7 +5032,9 @@ var Table = Object.assign(TableRoot, {
4559
5032
  resolveCellRenderer,
4560
5033
  resolveColumnFreezeSide,
4561
5034
  resolveDataTableLabels,
5035
+ resolveDropEdge,
4562
5036
  resolveHeaderFreezeOffset,
5037
+ resolveLeafColumnOrder,
4563
5038
  resolvePasteColumnIds,
4564
5039
  resolveRowSelection,
4565
5040
  resolveRowSpanAt,
@@ -4569,6 +5044,7 @@ var Table = Object.assign(TableRoot, {
4569
5044
  toggleExpandedRowId,
4570
5045
  useCellEdit,
4571
5046
  useCellSelection,
5047
+ useColumnReorder,
4572
5048
  useConvertTreeData,
4573
5049
  useGlideTable,
4574
5050
  useInlineSearch,