react-glide-table 2.0.1 → 2.1.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.js CHANGED
@@ -6,6 +6,7 @@ var DEFAULT_DATA_TABLE_LABELS = {
6
6
  expandRow: "Expand row",
7
7
  collapseRow: "Collapse row",
8
8
  resizeColumn: "Resize column",
9
+ reorderColumn: "Reorder column",
9
10
  searchPlaceholder: "Search\u2026",
10
11
  searchResultHint: "Type to search",
11
12
  searchPrevious: "Previous result",
@@ -56,6 +57,7 @@ var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
56
57
  var DATA_TABLE_COLUMN_SIZE = 150;
57
58
  var DATA_TABLE_COLUMN_MIN_SIZE = 40;
58
59
  var DATA_TABLE_COLUMN_MAX_SIZE = 800;
60
+ var DATA_TABLE_COLUMN_REORDER_THRESHOLD = 4;
59
61
 
60
62
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
61
63
  import { useCallback, useEffect, useRef, useState } from "react";
@@ -429,6 +431,16 @@ function formatDefaultCellValue(value) {
429
431
  return String(value);
430
432
  }
431
433
 
434
+ // src/components/ui/table/features/cell-render/withCellUpdate.ts
435
+ function withCellUpdate(context, commitValue) {
436
+ return {
437
+ ...context,
438
+ update: (next) => {
439
+ commitValue(context.row.id, context.column.id, next);
440
+ }
441
+ };
442
+ }
443
+
432
444
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
433
445
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
434
446
 
@@ -1311,6 +1323,135 @@ function useCellSelection({
1311
1323
  };
1312
1324
  }
1313
1325
 
1326
+ // src/components/ui/table/features/column-reorder/columnReorder.ts
1327
+ function getColumnDefId(column) {
1328
+ if (column.id != null && column.id !== "") return column.id;
1329
+ if ("accessorKey" in column && column.accessorKey != null) {
1330
+ return String(column.accessorKey);
1331
+ }
1332
+ return void 0;
1333
+ }
1334
+ function getColumnDefChildren(column) {
1335
+ if (!("columns" in column) || !Array.isArray(column.columns)) return void 0;
1336
+ if (column.columns.length === 0) return void 0;
1337
+ return column.columns;
1338
+ }
1339
+ function collectLeafColumnIds(columns) {
1340
+ const ids = [];
1341
+ for (const column of columns) {
1342
+ const children = getColumnDefChildren(column);
1343
+ if (children) {
1344
+ ids.push(...collectLeafColumnIds(children));
1345
+ continue;
1346
+ }
1347
+ const id = getColumnDefId(column);
1348
+ if (id) ids.push(id);
1349
+ }
1350
+ return ids;
1351
+ }
1352
+ function areColumnOrdersEqual(left, right) {
1353
+ if (left.length !== right.length) return false;
1354
+ return left.every((id, index) => id === right[index]);
1355
+ }
1356
+ function resolveLeafColumnOrder(columns, order) {
1357
+ const leafIds = collectLeafColumnIds(columns);
1358
+ if (!order?.length) return leafIds;
1359
+ const leafSet = new Set(leafIds);
1360
+ const seen = /* @__PURE__ */ new Set();
1361
+ const next = order.filter((id) => {
1362
+ if (!leafSet.has(id) || seen.has(id)) return false;
1363
+ seen.add(id);
1364
+ return true;
1365
+ });
1366
+ for (const id of leafIds) {
1367
+ if (!seen.has(id)) next.push(id);
1368
+ }
1369
+ return next;
1370
+ }
1371
+ function flattenColumnSlots(columns, group) {
1372
+ const slots = [];
1373
+ for (const column of columns) {
1374
+ const id = getColumnDefId(column);
1375
+ const children = getColumnDefChildren(column);
1376
+ if (children) {
1377
+ const nestedGroup = id ? { id, def: column } : group;
1378
+ slots.push(...flattenColumnSlots(children, nestedGroup));
1379
+ continue;
1380
+ }
1381
+ if (!id) continue;
1382
+ slots.push({ id, def: column, group });
1383
+ }
1384
+ return slots;
1385
+ }
1386
+ function rebuildColumnTree(slots) {
1387
+ const result = [];
1388
+ let index = 0;
1389
+ while (index < slots.length) {
1390
+ const slot = slots[index];
1391
+ if (!slot.group) {
1392
+ result.push(slot.def);
1393
+ index += 1;
1394
+ continue;
1395
+ }
1396
+ const groupId = slot.group.id;
1397
+ const children = [];
1398
+ while (index < slots.length && slots[index]?.group?.id === groupId) {
1399
+ children.push(slots[index].def);
1400
+ index += 1;
1401
+ }
1402
+ const firstChildId = children[0] ? getColumnDefId(children[0]) : groupId;
1403
+ result.push({
1404
+ ...slot.group.def,
1405
+ id: `${groupId}::${firstChildId}`,
1406
+ columns: children
1407
+ });
1408
+ }
1409
+ return result;
1410
+ }
1411
+ function applyLeafColumnOrder(columns, order) {
1412
+ const resolved = resolveLeafColumnOrder(columns, order);
1413
+ const defaultOrder = collectLeafColumnIds(columns);
1414
+ if (areColumnOrdersEqual(resolved, defaultOrder)) {
1415
+ return columns;
1416
+ }
1417
+ const byId = new Map(
1418
+ flattenColumnSlots(columns).map((slot) => [
1419
+ slot.id,
1420
+ slot
1421
+ ])
1422
+ );
1423
+ const ordered = [];
1424
+ for (const id of resolved) {
1425
+ const slot = byId.get(id);
1426
+ if (slot) ordered.push(slot);
1427
+ }
1428
+ return rebuildColumnTree(ordered);
1429
+ }
1430
+ function moveColumnIds(order, fromIds, targetIds, edge) {
1431
+ if (fromIds.length === 0 || targetIds.length === 0) return [...order];
1432
+ const fromSet = new Set(fromIds);
1433
+ if (targetIds.some((id) => fromSet.has(id))) return [...order];
1434
+ const rest = order.filter((id) => !fromSet.has(id));
1435
+ const anchorId = edge === "before" ? targetIds[0] : targetIds[targetIds.length - 1];
1436
+ const anchorIndex = rest.indexOf(anchorId);
1437
+ if (anchorIndex < 0) return [...order];
1438
+ const insertAt = edge === "before" ? anchorIndex : anchorIndex + 1;
1439
+ return [...rest.slice(0, insertAt), ...fromIds, ...rest.slice(insertAt)];
1440
+ }
1441
+ function resolveDropEdge(clientX, rect) {
1442
+ return clientX < rect.left + rect.width / 2 ? "before" : "after";
1443
+ }
1444
+ function parseReorderIds(value) {
1445
+ if (!value) return [];
1446
+ return value.split(",").filter(Boolean);
1447
+ }
1448
+ function serializeReorderIds(ids) {
1449
+ return ids.join(",");
1450
+ }
1451
+ function isColumnReorderable(meta) {
1452
+ return meta?.reorderable !== false;
1453
+ }
1454
+
1314
1455
  // src/components/ui/table/features/column-freeze/columnFreeze.ts
1315
1456
  var HEADER_Z_BASE = 30;
1316
1457
  var BODY_Z_BASE = 5;
@@ -2193,6 +2334,9 @@ function useGlideTable(options) {
2193
2334
  columnSizing: controlledColumnSizing,
2194
2335
  onColumnSizingChange,
2195
2336
  columnResizeMode = "onChange",
2337
+ enableColumnReorder = false,
2338
+ columnOrder: controlledColumnOrder,
2339
+ onColumnOrderChange,
2196
2340
  enableColumnFreeze = false,
2197
2341
  enableInlineSearch = false,
2198
2342
  showSearch,
@@ -2215,6 +2359,7 @@ function useGlideTable(options) {
2215
2359
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
2216
2360
  const [internalRowSelection, setInternalRowSelection] = useState4({});
2217
2361
  const [internalColumnSizing, setInternalColumnSizing] = useState4({});
2362
+ const [internalColumnOrder, setInternalColumnOrder] = useState4([]);
2218
2363
  const [internalExpandedRows, setInternalExpandedRows] = useState4(
2219
2364
  () => /* @__PURE__ */ new Set()
2220
2365
  );
@@ -2235,6 +2380,21 @@ function useGlideTable(options) {
2235
2380
  internalRowSelection
2236
2381
  );
2237
2382
  const columnSizing = controlledColumnSizing ?? internalColumnSizing;
2383
+ const columnOrder = controlledColumnOrder ?? internalColumnOrder;
2384
+ const tableColumns = useMemo3(() => {
2385
+ if (!enableColumnReorder) return columns;
2386
+ return applyLeafColumnOrder(columns, columnOrder);
2387
+ }, [columnOrder, columns, enableColumnReorder]);
2388
+ const setColumnOrder = useCallback4(
2389
+ (next) => {
2390
+ if (onColumnOrderChange) {
2391
+ onColumnOrderChange(next);
2392
+ return;
2393
+ }
2394
+ setInternalColumnOrder(next);
2395
+ },
2396
+ [onColumnOrderChange]
2397
+ );
2238
2398
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
2239
2399
  const handleExpandedRowsChange = useCallback4(
2240
2400
  (next) => {
@@ -2259,7 +2419,7 @@ function useGlideTable(options) {
2259
2419
  });
2260
2420
  const table = useReactTable({
2261
2421
  data: tableData,
2262
- columns,
2422
+ columns: tableColumns,
2263
2423
  ...enableColumnResize ? {
2264
2424
  defaultColumn: {
2265
2425
  minSize: DATA_TABLE_COLUMN_MIN_SIZE,
@@ -2415,6 +2575,10 @@ function useGlideTable(options) {
2415
2575
  }),
2416
2576
  [onCellChange, onDataChange, rows, tableData]
2417
2577
  );
2578
+ const getCellContext = useCallback4(
2579
+ (cell) => withCellUpdate(cell.getContext(), commitRenderedCellValue),
2580
+ [commitRenderedCellValue]
2581
+ );
2418
2582
  const handleCellMouseDownWithCommit = useCallback4(
2419
2583
  (rowIndex, colIndex, options2) => {
2420
2584
  const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
@@ -2737,6 +2901,7 @@ function useGlideTable(options) {
2737
2901
  selectionLabel: labels.selection,
2738
2902
  enableCellSelection,
2739
2903
  enableColumnResize,
2904
+ enableColumnReorder,
2740
2905
  enableColumnFreeze,
2741
2906
  enableInlineSearch,
2742
2907
  shouldVirtualize,
@@ -2747,8 +2912,10 @@ function useGlideTable(options) {
2747
2912
  paddingTop,
2748
2913
  paddingBottom,
2749
2914
  rowContextValue,
2915
+ getCellContext,
2750
2916
  handleToggleSelect,
2751
2917
  clearHover,
2918
+ setColumnOrder,
2752
2919
  copySelection: stableCopySelection,
2753
2920
  inlineSearch: {
2754
2921
  showSearch: inlineSearch.showSearch,
@@ -2834,13 +3001,226 @@ function getColumnSizeStyle(size, options) {
2834
3001
  };
2835
3002
  }
2836
3003
 
3004
+ // src/components/ui/table/features/column-reorder/useColumnReorder.ts
3005
+ import {
3006
+ useCallback as useCallback6,
3007
+ useEffect as useEffect6,
3008
+ useRef as useRef6,
3009
+ useState as useState5
3010
+ } from "react";
3011
+ function hitTestReorderHeader(table, clientX, clientY) {
3012
+ const headers = Array.from(
3013
+ table.querySelectorAll(
3014
+ "thead th[data-column-id][data-reorder-ids]"
3015
+ )
3016
+ );
3017
+ const containing = headers.find((element) => {
3018
+ const rect = element.getBoundingClientRect();
3019
+ return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
3020
+ });
3021
+ if (containing) {
3022
+ return {
3023
+ columnId: containing.dataset.columnId ?? "",
3024
+ edge: resolveDropEdge(clientX, containing.getBoundingClientRect())
3025
+ };
3026
+ }
3027
+ const leaves = headers.filter(
3028
+ (element) => element.hasAttribute("data-reorder-leaf")
3029
+ );
3030
+ let match;
3031
+ for (const element of leaves) {
3032
+ const rect = element.getBoundingClientRect();
3033
+ if (clientX >= rect.left && clientX <= rect.right) {
3034
+ match = element;
3035
+ break;
3036
+ }
3037
+ }
3038
+ if (!match && leaves.length > 0) {
3039
+ const first = leaves[0].getBoundingClientRect();
3040
+ const last = leaves[leaves.length - 1].getBoundingClientRect();
3041
+ if (clientX < first.left) match = leaves[0];
3042
+ else if (clientX > last.right) match = leaves[leaves.length - 1];
3043
+ }
3044
+ if (!match) return null;
3045
+ return {
3046
+ columnId: match.dataset.columnId ?? "",
3047
+ edge: resolveDropEdge(clientX, match.getBoundingClientRect())
3048
+ };
3049
+ }
3050
+ function readTargetIds(table, columnId) {
3051
+ const element = table.querySelector(
3052
+ `thead th[data-column-id="${CSS.escape(columnId)}"]`
3053
+ );
3054
+ return parseReorderIds(element?.getAttribute("data-reorder-ids"));
3055
+ }
3056
+ function useColumnReorder(options) {
3057
+ const { enabled, columnOrder, onColumnOrderChange } = options;
3058
+ const sessionRef = useRef6(null);
3059
+ const columnOrderRef = useRef6(columnOrder);
3060
+ const onColumnOrderChangeRef = useRef6(onColumnOrderChange);
3061
+ const [draggingColumnId, setDraggingColumnId] = useState5(null);
3062
+ const [dropTarget, setDropTarget] = useState5(
3063
+ null
3064
+ );
3065
+ const dropTargetRef = useRef6(dropTarget);
3066
+ const previousUserSelectRef = useRef6(null);
3067
+ columnOrderRef.current = columnOrder;
3068
+ onColumnOrderChangeRef.current = onColumnOrderChange;
3069
+ dropTargetRef.current = dropTarget;
3070
+ const resetDrag = useCallback6(() => {
3071
+ sessionRef.current = null;
3072
+ setDraggingColumnId(null);
3073
+ setDropTarget(null);
3074
+ const backup = previousUserSelectRef.current;
3075
+ previousUserSelectRef.current = null;
3076
+ if (backup) {
3077
+ if (backup.value) {
3078
+ document.body.style.setProperty("user-select", backup.value, backup.priority);
3079
+ } else {
3080
+ document.body.style.removeProperty("user-select");
3081
+ }
3082
+ return;
3083
+ }
3084
+ document.body.style.removeProperty("user-select");
3085
+ }, []);
3086
+ useEffect6(() => {
3087
+ if (!enabled) resetDrag();
3088
+ }, [enabled, resetDrag]);
3089
+ useEffect6(() => {
3090
+ return () => {
3091
+ resetDrag();
3092
+ };
3093
+ }, [resetDrag]);
3094
+ const onHeaderPointerDown = useCallback6(
3095
+ (event, meta) => {
3096
+ if (!enabled || !meta.canDrag) return;
3097
+ if (event.button !== 0) return;
3098
+ if (event.pointerType === "mouse" && event.ctrlKey) return;
3099
+ const target = event.target;
3100
+ if (target instanceof Element && target.closest("[data-table-disable-cell-selection]")) {
3101
+ return;
3102
+ }
3103
+ const table = event.currentTarget.closest("table");
3104
+ if (!(table instanceof HTMLTableElement)) return;
3105
+ sessionRef.current = {
3106
+ pointerId: event.pointerId,
3107
+ startX: event.clientX,
3108
+ startY: event.clientY,
3109
+ columnId: meta.columnId,
3110
+ fromIds: meta.leafIds,
3111
+ table,
3112
+ active: false
3113
+ };
3114
+ },
3115
+ [enabled]
3116
+ );
3117
+ useEffect6(() => {
3118
+ if (!enabled) return;
3119
+ const onPointerMove = (event) => {
3120
+ const session = sessionRef.current;
3121
+ if (!session || event.pointerId !== session.pointerId) return;
3122
+ const deltaX = event.clientX - session.startX;
3123
+ const deltaY = event.clientY - session.startY;
3124
+ const distance = Math.hypot(deltaX, deltaY);
3125
+ if (!session.active) {
3126
+ if (distance < DATA_TABLE_COLUMN_REORDER_THRESHOLD) return;
3127
+ session.active = true;
3128
+ if (!previousUserSelectRef.current) {
3129
+ previousUserSelectRef.current = {
3130
+ value: document.body.style.getPropertyValue("user-select"),
3131
+ priority: document.body.style.getPropertyPriority("user-select")
3132
+ };
3133
+ }
3134
+ document.body.style.setProperty("user-select", "none");
3135
+ setDraggingColumnId(session.columnId);
3136
+ }
3137
+ event.preventDefault();
3138
+ const nextTarget = hitTestReorderHeader(
3139
+ session.table,
3140
+ event.clientX,
3141
+ event.clientY
3142
+ );
3143
+ if (!nextTarget || !nextTarget.columnId) {
3144
+ setDropTarget(null);
3145
+ return;
3146
+ }
3147
+ const targetIds = readTargetIds(session.table, nextTarget.columnId);
3148
+ const fromSet = new Set(session.fromIds);
3149
+ if (targetIds.some((id) => fromSet.has(id))) {
3150
+ setDropTarget(null);
3151
+ return;
3152
+ }
3153
+ setDropTarget((previous) => {
3154
+ if (previous?.columnId === nextTarget.columnId && previous.edge === nextTarget.edge) {
3155
+ return previous;
3156
+ }
3157
+ return nextTarget;
3158
+ });
3159
+ };
3160
+ const onPointerUp = (event) => {
3161
+ const session = sessionRef.current;
3162
+ if (!session || event.pointerId !== session.pointerId) {
3163
+ return;
3164
+ }
3165
+ if (session.active) {
3166
+ event.preventDefault();
3167
+ const target = dropTargetRef.current;
3168
+ if (target) {
3169
+ const targetIds = readTargetIds(session.table, target.columnId);
3170
+ const next = moveColumnIds(
3171
+ columnOrderRef.current,
3172
+ session.fromIds,
3173
+ targetIds,
3174
+ target.edge
3175
+ );
3176
+ onColumnOrderChangeRef.current(next);
3177
+ }
3178
+ const suppressClick = (clickEvent) => {
3179
+ clickEvent.preventDefault();
3180
+ clickEvent.stopPropagation();
3181
+ document.removeEventListener("click", suppressClick, true);
3182
+ };
3183
+ document.addEventListener("click", suppressClick, true);
3184
+ window.setTimeout(() => {
3185
+ document.removeEventListener("click", suppressClick, true);
3186
+ }, 0);
3187
+ }
3188
+ resetDrag();
3189
+ };
3190
+ const onPointerCancel = (event) => {
3191
+ const session = sessionRef.current;
3192
+ if (!session || event.pointerId !== session.pointerId) {
3193
+ return;
3194
+ }
3195
+ if (session.active) {
3196
+ event.preventDefault();
3197
+ }
3198
+ resetDrag();
3199
+ };
3200
+ document.addEventListener("pointermove", onPointerMove);
3201
+ document.addEventListener("pointerup", onPointerUp);
3202
+ document.addEventListener("pointercancel", onPointerCancel);
3203
+ return () => {
3204
+ document.removeEventListener("pointermove", onPointerMove);
3205
+ document.removeEventListener("pointerup", onPointerUp);
3206
+ document.removeEventListener("pointercancel", onPointerCancel);
3207
+ };
3208
+ }, [enabled, resetDrag]);
3209
+ return {
3210
+ isReordering: draggingColumnId != null,
3211
+ draggingColumnId,
3212
+ dropTarget,
3213
+ onHeaderPointerDown
3214
+ };
3215
+ }
3216
+
2837
3217
  // src/components/ui/table/components/DataTable/DataTable.tsx
2838
3218
  import { flexRender as flexRender2 } from "@tanstack/react-table";
2839
3219
  import { useMemo as useMemo4 } from "react";
2840
3220
 
2841
3221
  // src/components/ui/table/components/DataTable/DataTableRow.tsx
2842
3222
  import { flexRender } from "@tanstack/react-table";
2843
- import { useEffect as useEffect6, useRef as useRef6 } from "react";
3223
+ import { useEffect as useEffect7, useRef as useRef7 } from "react";
2844
3224
 
2845
3225
  // src/components/ui/table/components/icons.tsx
2846
3226
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -3028,6 +3408,7 @@ function DataTableRow({
3028
3408
  selection,
3029
3409
  cellSelection,
3030
3410
  cellEdit,
3411
+ cellRender,
3031
3412
  expand,
3032
3413
  columnResize,
3033
3414
  columnFreeze,
@@ -3065,6 +3446,10 @@ function DataTableRow({
3065
3446
  onCommitEdit,
3066
3447
  onCancelEdit
3067
3448
  } = cellEdit;
3449
+ const renderCell = (tableCell) => flexRender(
3450
+ tableCell.column.columnDef.cell,
3451
+ withCellUpdate(tableCell.getContext(), cellRender.commitValue)
3452
+ );
3068
3453
  const {
3069
3454
  enableExpand,
3070
3455
  toggleField,
@@ -3133,9 +3518,9 @@ function DataTableRow({
3133
3518
  const expandKey = toggleField && rowData[toggleField] !== null && rowData[toggleField] !== void 0 ? String(rowData[toggleField]) : null;
3134
3519
  const isExpanded = expandKey !== null && Boolean(expandedRows?.has(expandKey));
3135
3520
  const rowLevel = typeof rowData.level === "number" ? rowData.level : 0;
3136
- const editInputRef = useRef6(null);
3521
+ const editInputRef = useRef7(null);
3137
3522
  const isRowEditing = editingCell?.rowIndex === rowIndex;
3138
- useEffect6(() => {
3523
+ useEffect7(() => {
3139
3524
  if (!isRowEditing) return;
3140
3525
  editInputRef.current?.focus();
3141
3526
  editInputRef.current?.select();
@@ -3377,7 +3762,7 @@ function DataTableRow({
3377
3762
  "expand-cell-value",
3378
3763
  classNames?.expandCellValue
3379
3764
  ),
3380
- children: flexRender(cell.column.columnDef.cell, cell.getContext())
3765
+ children: renderCell(cell)
3381
3766
  }
3382
3767
  )
3383
3768
  ]
@@ -3416,7 +3801,7 @@ function DataTableRow({
3416
3801
  )
3417
3802
  }
3418
3803
  )
3419
- ] }) : flexRender(cell.column.columnDef.cell, cell.getContext()),
3804
+ ] }) : renderCell(cell),
3420
3805
  isBottomRightCell && /* @__PURE__ */ jsx4(
3421
3806
  "div",
3422
3807
  {
@@ -3733,6 +4118,7 @@ function DataTable({
3733
4118
  selectionLabel,
3734
4119
  enableCellSelection,
3735
4120
  enableColumnResize,
4121
+ enableColumnReorder,
3736
4122
  enableColumnFreeze,
3737
4123
  enableInlineSearch,
3738
4124
  shouldVirtualize,
@@ -3745,6 +4131,7 @@ function DataTable({
3745
4131
  rowContextValue,
3746
4132
  handleToggleSelect,
3747
4133
  clearHover,
4134
+ setColumnOrder,
3748
4135
  inlineSearch
3749
4136
  } = useGlideTable(glideOptions);
3750
4137
  const ToolbarSlot = slots?.Toolbar ?? DataTableToolbar;
@@ -3754,6 +4141,12 @@ function DataTable({
3754
4141
  const EmptySlot = slots?.Empty ?? DefaultEmpty;
3755
4142
  const freezeOffsets = rowContextValue.columnFreeze.offsets;
3756
4143
  const headerGroups = getMergedHeaderGroups(table.getHeaderGroups());
4144
+ const leafColumnIds = table.getVisibleLeafColumns().map((column) => column.id);
4145
+ const { isReordering, draggingColumnId, dropTarget, onHeaderPointerDown } = useColumnReorder({
4146
+ enabled: enableColumnReorder,
4147
+ columnOrder: leafColumnIds,
4148
+ onColumnOrderChange: setColumnOrder
4149
+ });
3757
4150
  const contextValue = useMemo4(
3758
4151
  () => ({ ...rowContextValue, classNames }),
3759
4152
  [rowContextValue, classNames]
@@ -3776,6 +4169,8 @@ function DataTable({
3776
4169
  "DataTableJSX",
3777
4170
  !enableCellSelection && "DataTableJSX--no-cell-selection",
3778
4171
  enableColumnResize && "DataTableJSX--column-resize",
4172
+ enableColumnReorder && "DataTableJSX--column-reorder",
4173
+ isReordering && "DataTableJSX--column-reordering",
3779
4174
  enableColumnFreeze && "DataTableJSX--column-freeze",
3780
4175
  enableInlineSearch && "DataTableJSX--inline-search",
3781
4176
  classNames?.root,
@@ -3844,20 +4239,43 @@ function DataTable({
3844
4239
  ...sizeStyle,
3845
4240
  ...freezeStyle
3846
4241
  };
4242
+ const isPlaceholder = header.isPlaceholder;
4243
+ const leafColumns = header.column.getLeafColumns();
4244
+ const leafIds = leafColumns.map((leafColumn) => leafColumn.id);
4245
+ const isLeafHeader = !isPlaceholder && header.subHeaders.length === 0;
4246
+ const canDrag = enableColumnReorder && !isPlaceholder && leafIds.length > 0 && leafColumns.every(
4247
+ (leafColumn) => isColumnReorderable(leafColumn.columnDef.meta)
4248
+ );
4249
+ const isDragging = draggingColumnId === header.column.id;
4250
+ const dropEdge = !isPlaceholder && dropTarget?.columnId === header.column.id ? dropTarget.edge : void 0;
3847
4251
  return /* @__PURE__ */ jsxs6(
3848
4252
  "th",
3849
4253
  {
3850
4254
  colSpan: header.colSpan,
3851
4255
  rowSpan: header.mergedRowSpan,
4256
+ "data-column-id": enableColumnReorder && !isPlaceholder ? header.column.id : void 0,
4257
+ "data-reorder-ids": enableColumnReorder && !isPlaceholder ? serializeReorderIds(leafIds) : void 0,
4258
+ "data-reorder-leaf": enableColumnReorder && isLeafHeader ? "" : void 0,
4259
+ "data-reorderable": canDrag ? "" : void 0,
4260
+ "data-reordering": isDragging ? "" : void 0,
4261
+ "data-drop-edge": dropEdge,
3852
4262
  "data-resizing": header.column.getIsResizing() ? "" : void 0,
3853
4263
  "data-frozen": freezeOffset?.side,
3854
4264
  "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
4265
+ "aria-grabbed": isDragging ? true : void 0,
4266
+ title: canDrag ? labels.reorderColumn : void 0,
4267
+ onPointerDown: enableColumnReorder ? (event) => onHeaderPointerDown(event, {
4268
+ columnId: header.column.id,
4269
+ leafIds,
4270
+ canDrag
4271
+ }) : void 0,
3855
4272
  style: Object.keys(headerStyle).length > 0 ? headerStyle : void 0,
3856
4273
  className: cn(
3857
4274
  "data-table-head-cell",
3858
4275
  freezeOffset && `data-table-head-cell--frozen-${freezeOffset.side}`,
3859
4276
  CELL_ALIGN_CLASS[align],
3860
4277
  classNames?.headCell,
4278
+ dropEdge && classNames?.dropEdge,
3861
4279
  headerClassName
3862
4280
  ),
3863
4281
  children: [
@@ -3979,7 +4397,7 @@ function DataTable({
3979
4397
  }
3980
4398
 
3981
4399
  // src/components/ui/table/components/Table/Table.tsx
3982
- import { useCallback as useCallback6, useMemo as useMemo5, useState as useState5 } from "react";
4400
+ import { useCallback as useCallback7, useMemo as useMemo5, useState as useState6 } from "react";
3983
4401
 
3984
4402
  // src/components/ui/table/components/Table/buildColumnDef.tsx
3985
4403
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -4017,6 +4435,7 @@ function buildColumnDef(props, sort, onSort) {
4017
4435
  minWidth,
4018
4436
  maxWidth,
4019
4437
  resizable,
4438
+ reorderable,
4020
4439
  frozen,
4021
4440
  align,
4022
4441
  rowSpan,
@@ -4062,6 +4481,7 @@ function buildColumnDef(props, sort, onSort) {
4062
4481
  cellProps,
4063
4482
  cellRender: render,
4064
4483
  frozen,
4484
+ reorderable,
4065
4485
  className,
4066
4486
  headerClassName
4067
4487
  }
@@ -4309,8 +4729,8 @@ function TableRoot({
4309
4729
  () => parseTableChildren(children),
4310
4730
  [children]
4311
4731
  );
4312
- const [sort, setSort] = useState5(null);
4313
- const handleSort = useCallback6((field) => {
4732
+ const [sort, setSort] = useState6(null);
4733
+ const handleSort = useCallback7((field) => {
4314
4734
  setSort((previous) => {
4315
4735
  if (previous?.field !== field) {
4316
4736
  return { field, direction: "asc" };
@@ -4407,6 +4827,7 @@ export {
4407
4827
  Table,
4408
4828
  applyCellEdit,
4409
4829
  applyFillData,
4830
+ applyLeafColumnOrder,
4410
4831
  applySelectionUpdater,
4411
4832
  buildColumnFreezeOffsets,
4412
4833
  buildColumnRowSpanMap,
@@ -4421,6 +4842,7 @@ export {
4421
4842
  collectCopyRowEntries,
4422
4843
  collectCopyRows,
4423
4844
  collectFillChanges,
4845
+ collectLeafColumnIds,
4424
4846
  collectRowSpanColumns,
4425
4847
  collectSearchMatchesInRange,
4426
4848
  commitCellValue,
@@ -4446,6 +4868,7 @@ export {
4446
4868
  mapSearchResultToVisibleItem,
4447
4869
  mapSearchResultsToVisibleKeys,
4448
4870
  measureMergedSpanRowHeights,
4871
+ moveColumnIds,
4449
4872
  nextSearchIndex,
4450
4873
  nextSearchStride,
4451
4874
  parseCellEditValue,
@@ -4455,7 +4878,9 @@ export {
4455
4878
  resolveCellRenderer,
4456
4879
  resolveColumnFreezeSide,
4457
4880
  resolveDataTableLabels,
4881
+ resolveDropEdge,
4458
4882
  resolveHeaderFreezeOffset,
4883
+ resolveLeafColumnOrder,
4459
4884
  resolvePasteColumnIds,
4460
4885
  resolveRowSelection,
4461
4886
  resolveRowSpanAt,
@@ -4465,8 +4890,10 @@ export {
4465
4890
  toggleExpandedRowId,
4466
4891
  useCellEdit,
4467
4892
  useCellSelection,
4893
+ useColumnReorder,
4468
4894
  useConvertTreeData,
4469
4895
  useGlideTable,
4470
4896
  useInlineSearch,
4897
+ withCellUpdate,
4471
4898
  writeSelectionToClipboard
4472
4899
  };