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/compound.js CHANGED
@@ -21,6 +21,7 @@ var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
21
21
  var DATA_TABLE_COLUMN_SIZE = 150;
22
22
  var DATA_TABLE_COLUMN_MIN_SIZE = 40;
23
23
  var DATA_TABLE_COLUMN_MAX_SIZE = 800;
24
+ var DATA_TABLE_COLUMN_REORDER_THRESHOLD = 4;
24
25
 
25
26
  // src/components/ui/table/DataTableContext.tsx
26
27
  import { createContext, use } from "react";
@@ -861,23 +862,49 @@ var useConvertTreeData = ({
861
862
  function getRowFieldValue(row, key) {
862
863
  return row[key];
863
864
  }
864
- function computeRowSpans(data, rowSpanKey) {
865
+ function normalizeRowSpanParent(value) {
866
+ if (!value) return [];
867
+ return typeof value === "string" ? [value] : [...value];
868
+ }
869
+ function toParentSpanList(parentSpans) {
870
+ if (!parentSpans?.length) return [];
871
+ const first = parentSpans[0];
872
+ if (!Array.isArray(first)) {
873
+ return [parentSpans];
874
+ }
875
+ return parentSpans;
876
+ }
877
+ function buildStartRowLookup(spans) {
878
+ const startRows = new Array(spans.length);
879
+ let origin = 0;
880
+ for (let i = 0; i < spans.length; i++) {
881
+ if ((spans[i]?.rowSpan ?? 1) > 0) origin = i;
882
+ startRows[i] = origin;
883
+ }
884
+ return startRows;
885
+ }
886
+ function sharesParentGroup(parentStartRows, rowIndex) {
887
+ if (parentStartRows.length === 0 || rowIndex <= 0) return true;
888
+ return parentStartRows.every(
889
+ (startRows) => startRows[rowIndex - 1] === startRows[rowIndex]
890
+ );
891
+ }
892
+ function computeRowSpans(data, rowSpanKey, parentSpans) {
865
893
  if (data.length === 0) return [];
894
+ const parentStartRows = toParentSpanList(parentSpans).map(buildStartRowLookup);
866
895
  const result = [];
867
896
  for (let index = 0; index < data.length; index++) {
868
897
  const currentValue = getRowFieldValue(data[index], rowSpanKey);
869
898
  const previousValue = index > 0 ? getRowFieldValue(data[index - 1], rowSpanKey) : void 0;
870
- if (index > 0 && currentValue === previousValue) {
899
+ if (index > 0 && currentValue === previousValue && sharesParentGroup(parentStartRows, index)) {
871
900
  result.push({ rowSpan: 0, isFirstInGroup: false });
872
901
  continue;
873
902
  }
874
903
  let span = 1;
875
904
  for (let nextIndex = index + 1; nextIndex < data.length; nextIndex++) {
876
- if (getRowFieldValue(data[nextIndex], rowSpanKey) === currentValue) {
877
- span++;
878
- } else {
879
- break;
880
- }
905
+ if (getRowFieldValue(data[nextIndex], rowSpanKey) !== currentValue) break;
906
+ if (!sharesParentGroup(parentStartRows, nextIndex)) break;
907
+ span++;
881
908
  }
882
909
  result.push({ rowSpan: span, isFirstInGroup: true });
883
910
  }
@@ -899,10 +926,50 @@ function resolveRowSpanAt(rowSpans, rowIndex) {
899
926
  }
900
927
  return { startRow: rowIndex, rowSpan: 1 };
901
928
  }
929
+ function findRowSpanColumn(spec, ref) {
930
+ return spec.find((column) => column.columnId === ref) ?? spec.find((column) => column.rowSpanKey === ref);
931
+ }
902
932
  function buildColumnRowSpanMap(data, columnKeys) {
903
933
  const map = /* @__PURE__ */ new Map();
904
- for (const { columnId, rowSpanKey } of columnKeys) {
905
- map.set(columnId, computeRowSpans(data, rowSpanKey));
934
+ const visiting = /* @__PURE__ */ new Set();
935
+ const warnedCycles = /* @__PURE__ */ new Set();
936
+ const virtualParents = /* @__PURE__ */ new Map();
937
+ const spansForColumn = (columnId) => {
938
+ const cached = map.get(columnId);
939
+ if (cached !== void 0) return cached;
940
+ const column = columnKeys.find((item) => item.columnId === columnId);
941
+ if (!column) return void 0;
942
+ if (visiting.has(columnId)) {
943
+ if (!warnedCycles.has(columnId)) {
944
+ warnedCycles.add(columnId);
945
+ console.warn(
946
+ `[rowSpan] rowSpanParent cycle detected at column "${columnId}"; dropping the cyclic parent reference.`
947
+ );
948
+ }
949
+ return void 0;
950
+ }
951
+ visiting.add(columnId);
952
+ const parentSpans = (column.rowSpanParent ?? []).map((ref) => spansForParentRef(ref)).filter((spans2) => Boolean(spans2));
953
+ visiting.delete(columnId);
954
+ const spans = computeRowSpans(
955
+ data,
956
+ column.rowSpanKey,
957
+ parentSpans.length > 0 ? parentSpans : void 0
958
+ );
959
+ map.set(columnId, spans);
960
+ return spans;
961
+ };
962
+ const spansForParentRef = (ref) => {
963
+ const parentColumn = findRowSpanColumn(columnKeys, ref);
964
+ if (parentColumn) return spansForColumn(parentColumn.columnId);
965
+ const cached = virtualParents.get(ref);
966
+ if (cached !== void 0) return cached;
967
+ const spans = computeRowSpans(data, ref);
968
+ virtualParents.set(ref, spans);
969
+ return spans;
970
+ };
971
+ for (const column of columnKeys) {
972
+ spansForColumn(column.columnId);
906
973
  }
907
974
  return map;
908
975
  }
@@ -918,7 +985,8 @@ function collectRowSpanColumns(columns) {
918
985
  if (!columnId || !columnDef.meta?.rowSpan) continue;
919
986
  result.push({
920
987
  columnId,
921
- rowSpanKey: columnDef.meta.rowSpanKey ?? columnId
988
+ rowSpanKey: columnDef.meta.rowSpanKey ?? columnId,
989
+ rowSpanParent: normalizeRowSpanParent(columnDef.meta.rowSpanParent)
922
990
  });
923
991
  }
924
992
  };
@@ -1757,6 +1825,348 @@ function getMergedHeaderGroups(headerGroups) {
1757
1825
  }));
1758
1826
  }
1759
1827
 
1828
+ // src/components/ui/table/features/column-reorder/columnReorder.ts
1829
+ function getColumnDefId(column) {
1830
+ if (column.id != null && column.id !== "") return column.id;
1831
+ if ("accessorKey" in column && column.accessorKey != null) {
1832
+ return String(column.accessorKey);
1833
+ }
1834
+ return void 0;
1835
+ }
1836
+ function getColumnDefChildren(column) {
1837
+ if (!("columns" in column) || !Array.isArray(column.columns)) return void 0;
1838
+ if (column.columns.length === 0) return void 0;
1839
+ return column.columns;
1840
+ }
1841
+ function collectLeafColumnIds(columns) {
1842
+ const ids = [];
1843
+ for (const column of columns) {
1844
+ const children = getColumnDefChildren(column);
1845
+ if (children) {
1846
+ ids.push(...collectLeafColumnIds(children));
1847
+ continue;
1848
+ }
1849
+ const id = getColumnDefId(column);
1850
+ if (id) ids.push(id);
1851
+ }
1852
+ return ids;
1853
+ }
1854
+ function areColumnOrdersEqual(left, right) {
1855
+ if (left.length !== right.length) return false;
1856
+ return left.every((id, index) => id === right[index]);
1857
+ }
1858
+ function resolveLeafColumnOrder(columns, order) {
1859
+ const leafIds = collectLeafColumnIds(columns);
1860
+ if (!order?.length) return leafIds;
1861
+ const leafSet = new Set(leafIds);
1862
+ const seen = /* @__PURE__ */ new Set();
1863
+ const next = order.filter((id) => {
1864
+ if (!leafSet.has(id) || seen.has(id)) return false;
1865
+ seen.add(id);
1866
+ return true;
1867
+ });
1868
+ for (const id of leafIds) {
1869
+ if (!seen.has(id)) next.push(id);
1870
+ }
1871
+ return next;
1872
+ }
1873
+ function flattenColumnSlots(columns, group) {
1874
+ const slots = [];
1875
+ for (const column of columns) {
1876
+ const id = getColumnDefId(column);
1877
+ const children = getColumnDefChildren(column);
1878
+ if (children) {
1879
+ const nestedGroup = id ? { id, def: column } : group;
1880
+ slots.push(...flattenColumnSlots(children, nestedGroup));
1881
+ continue;
1882
+ }
1883
+ if (!id) continue;
1884
+ slots.push({ id, def: column, group });
1885
+ }
1886
+ return slots;
1887
+ }
1888
+ function rebuildColumnTree(slots) {
1889
+ const result = [];
1890
+ let index = 0;
1891
+ while (index < slots.length) {
1892
+ const slot = slots[index];
1893
+ if (!slot.group) {
1894
+ result.push(slot.def);
1895
+ index += 1;
1896
+ continue;
1897
+ }
1898
+ const groupId = slot.group.id;
1899
+ const children = [];
1900
+ while (index < slots.length && slots[index]?.group?.id === groupId) {
1901
+ children.push(slots[index].def);
1902
+ index += 1;
1903
+ }
1904
+ const firstChildId = children[0] ? getColumnDefId(children[0]) : groupId;
1905
+ result.push({
1906
+ ...slot.group.def,
1907
+ id: `${groupId}::${firstChildId}`,
1908
+ columns: children
1909
+ });
1910
+ }
1911
+ return result;
1912
+ }
1913
+ function applyLeafColumnOrder(columns, order) {
1914
+ const resolved = resolveLeafColumnOrder(columns, order);
1915
+ const defaultOrder = collectLeafColumnIds(columns);
1916
+ if (areColumnOrdersEqual(resolved, defaultOrder)) {
1917
+ return columns;
1918
+ }
1919
+ const byId = new Map(
1920
+ flattenColumnSlots(columns).map((slot) => [
1921
+ slot.id,
1922
+ slot
1923
+ ])
1924
+ );
1925
+ const ordered = [];
1926
+ for (const id of resolved) {
1927
+ const slot = byId.get(id);
1928
+ if (slot) ordered.push(slot);
1929
+ }
1930
+ return rebuildColumnTree(ordered);
1931
+ }
1932
+ function moveColumnIds(order, fromIds, targetIds, edge) {
1933
+ if (fromIds.length === 0 || targetIds.length === 0) return [...order];
1934
+ const fromSet = new Set(fromIds);
1935
+ if (targetIds.some((id) => fromSet.has(id))) return [...order];
1936
+ const rest = order.filter((id) => !fromSet.has(id));
1937
+ const anchorId = edge === "before" ? targetIds[0] : targetIds[targetIds.length - 1];
1938
+ const anchorIndex = rest.indexOf(anchorId);
1939
+ if (anchorIndex < 0) return [...order];
1940
+ const insertAt = edge === "before" ? anchorIndex : anchorIndex + 1;
1941
+ return [...rest.slice(0, insertAt), ...fromIds, ...rest.slice(insertAt)];
1942
+ }
1943
+ function resolveDropEdge(clientX, rect) {
1944
+ return clientX < rect.left + rect.width / 2 ? "before" : "after";
1945
+ }
1946
+ function parseReorderIds(value) {
1947
+ if (!value) return [];
1948
+ return value.split(",").filter(Boolean);
1949
+ }
1950
+ function serializeReorderIds(ids) {
1951
+ return ids.join(",");
1952
+ }
1953
+ function isColumnReorderable(meta) {
1954
+ return meta?.reorderable !== false;
1955
+ }
1956
+
1957
+ // src/components/ui/table/features/column-reorder/useColumnReorder.ts
1958
+ import {
1959
+ useCallback,
1960
+ useEffect as useEffect3,
1961
+ useRef as useRef3,
1962
+ useState
1963
+ } from "react";
1964
+ function hitTestReorderHeader(table, clientX, clientY) {
1965
+ const headers = Array.from(
1966
+ table.querySelectorAll(
1967
+ "thead th[data-column-id][data-reorder-ids]"
1968
+ )
1969
+ );
1970
+ const containing = headers.find((element) => {
1971
+ const rect = element.getBoundingClientRect();
1972
+ return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
1973
+ });
1974
+ if (containing) {
1975
+ return {
1976
+ columnId: containing.dataset.columnId ?? "",
1977
+ edge: resolveDropEdge(clientX, containing.getBoundingClientRect())
1978
+ };
1979
+ }
1980
+ const leaves = headers.filter(
1981
+ (element) => element.hasAttribute("data-reorder-leaf")
1982
+ );
1983
+ let match;
1984
+ for (const element of leaves) {
1985
+ const rect = element.getBoundingClientRect();
1986
+ if (clientX >= rect.left && clientX <= rect.right) {
1987
+ match = element;
1988
+ break;
1989
+ }
1990
+ }
1991
+ if (!match && leaves.length > 0) {
1992
+ const first = leaves[0].getBoundingClientRect();
1993
+ const last = leaves[leaves.length - 1].getBoundingClientRect();
1994
+ if (clientX < first.left) match = leaves[0];
1995
+ else if (clientX > last.right) match = leaves[leaves.length - 1];
1996
+ }
1997
+ if (!match) return null;
1998
+ return {
1999
+ columnId: match.dataset.columnId ?? "",
2000
+ edge: resolveDropEdge(clientX, match.getBoundingClientRect())
2001
+ };
2002
+ }
2003
+ function readTargetIds(table, columnId) {
2004
+ const element = table.querySelector(
2005
+ `thead th[data-column-id="${CSS.escape(columnId)}"]`
2006
+ );
2007
+ return parseReorderIds(element?.getAttribute("data-reorder-ids"));
2008
+ }
2009
+ function useColumnReorder(options) {
2010
+ const { enabled, columnOrder, onColumnOrderChange } = options;
2011
+ const sessionRef = useRef3(null);
2012
+ const columnOrderRef = useRef3(columnOrder);
2013
+ const onColumnOrderChangeRef = useRef3(onColumnOrderChange);
2014
+ const [draggingColumnId, setDraggingColumnId] = useState(null);
2015
+ const [dropTarget, setDropTarget] = useState(
2016
+ null
2017
+ );
2018
+ const dropTargetRef = useRef3(dropTarget);
2019
+ const previousUserSelectRef = useRef3(null);
2020
+ columnOrderRef.current = columnOrder;
2021
+ onColumnOrderChangeRef.current = onColumnOrderChange;
2022
+ dropTargetRef.current = dropTarget;
2023
+ const resetDrag = useCallback(() => {
2024
+ sessionRef.current = null;
2025
+ setDraggingColumnId(null);
2026
+ setDropTarget(null);
2027
+ const backup = previousUserSelectRef.current;
2028
+ previousUserSelectRef.current = null;
2029
+ if (backup) {
2030
+ if (backup.value) {
2031
+ document.body.style.setProperty("user-select", backup.value, backup.priority);
2032
+ } else {
2033
+ document.body.style.removeProperty("user-select");
2034
+ }
2035
+ return;
2036
+ }
2037
+ document.body.style.removeProperty("user-select");
2038
+ }, []);
2039
+ useEffect3(() => {
2040
+ if (!enabled) resetDrag();
2041
+ }, [enabled, resetDrag]);
2042
+ useEffect3(() => {
2043
+ return () => {
2044
+ resetDrag();
2045
+ };
2046
+ }, [resetDrag]);
2047
+ const onHeaderPointerDown = useCallback(
2048
+ (event, meta) => {
2049
+ if (!enabled || !meta.canDrag) return;
2050
+ if (event.button !== 0) return;
2051
+ if (event.pointerType === "mouse" && event.ctrlKey) return;
2052
+ const target = event.target;
2053
+ if (target instanceof Element && target.closest("[data-table-disable-cell-selection]")) {
2054
+ return;
2055
+ }
2056
+ const table = event.currentTarget.closest("table");
2057
+ if (!(table instanceof HTMLTableElement)) return;
2058
+ sessionRef.current = {
2059
+ pointerId: event.pointerId,
2060
+ startX: event.clientX,
2061
+ startY: event.clientY,
2062
+ columnId: meta.columnId,
2063
+ fromIds: meta.leafIds,
2064
+ table,
2065
+ active: false
2066
+ };
2067
+ },
2068
+ [enabled]
2069
+ );
2070
+ useEffect3(() => {
2071
+ if (!enabled) return;
2072
+ const onPointerMove = (event) => {
2073
+ const session = sessionRef.current;
2074
+ if (!session || event.pointerId !== session.pointerId) return;
2075
+ const deltaX = event.clientX - session.startX;
2076
+ const deltaY = event.clientY - session.startY;
2077
+ const distance = Math.hypot(deltaX, deltaY);
2078
+ if (!session.active) {
2079
+ if (distance < DATA_TABLE_COLUMN_REORDER_THRESHOLD) return;
2080
+ session.active = true;
2081
+ if (!previousUserSelectRef.current) {
2082
+ previousUserSelectRef.current = {
2083
+ value: document.body.style.getPropertyValue("user-select"),
2084
+ priority: document.body.style.getPropertyPriority("user-select")
2085
+ };
2086
+ }
2087
+ document.body.style.setProperty("user-select", "none");
2088
+ setDraggingColumnId(session.columnId);
2089
+ }
2090
+ event.preventDefault();
2091
+ const nextTarget = hitTestReorderHeader(
2092
+ session.table,
2093
+ event.clientX,
2094
+ event.clientY
2095
+ );
2096
+ if (!nextTarget || !nextTarget.columnId) {
2097
+ setDropTarget(null);
2098
+ return;
2099
+ }
2100
+ const targetIds = readTargetIds(session.table, nextTarget.columnId);
2101
+ const fromSet = new Set(session.fromIds);
2102
+ if (targetIds.some((id) => fromSet.has(id))) {
2103
+ setDropTarget(null);
2104
+ return;
2105
+ }
2106
+ setDropTarget((previous) => {
2107
+ if (previous?.columnId === nextTarget.columnId && previous.edge === nextTarget.edge) {
2108
+ return previous;
2109
+ }
2110
+ return nextTarget;
2111
+ });
2112
+ };
2113
+ const onPointerUp = (event) => {
2114
+ const session = sessionRef.current;
2115
+ if (!session || event.pointerId !== session.pointerId) {
2116
+ return;
2117
+ }
2118
+ if (session.active) {
2119
+ event.preventDefault();
2120
+ const target = dropTargetRef.current;
2121
+ if (target) {
2122
+ const targetIds = readTargetIds(session.table, target.columnId);
2123
+ const next = moveColumnIds(
2124
+ columnOrderRef.current,
2125
+ session.fromIds,
2126
+ targetIds,
2127
+ target.edge
2128
+ );
2129
+ onColumnOrderChangeRef.current(next);
2130
+ }
2131
+ const suppressClick = (clickEvent) => {
2132
+ clickEvent.preventDefault();
2133
+ clickEvent.stopPropagation();
2134
+ document.removeEventListener("click", suppressClick, true);
2135
+ };
2136
+ document.addEventListener("click", suppressClick, true);
2137
+ window.setTimeout(() => {
2138
+ document.removeEventListener("click", suppressClick, true);
2139
+ }, 0);
2140
+ }
2141
+ resetDrag();
2142
+ };
2143
+ const onPointerCancel = (event) => {
2144
+ const session = sessionRef.current;
2145
+ if (!session || event.pointerId !== session.pointerId) {
2146
+ return;
2147
+ }
2148
+ if (session.active) {
2149
+ event.preventDefault();
2150
+ }
2151
+ resetDrag();
2152
+ };
2153
+ document.addEventListener("pointermove", onPointerMove);
2154
+ document.addEventListener("pointerup", onPointerUp);
2155
+ document.addEventListener("pointercancel", onPointerCancel);
2156
+ return () => {
2157
+ document.removeEventListener("pointermove", onPointerMove);
2158
+ document.removeEventListener("pointerup", onPointerUp);
2159
+ document.removeEventListener("pointercancel", onPointerCancel);
2160
+ };
2161
+ }, [enabled, resetDrag]);
2162
+ return {
2163
+ isReordering: draggingColumnId != null,
2164
+ draggingColumnId,
2165
+ dropTarget,
2166
+ onHeaderPointerDown
2167
+ };
2168
+ }
2169
+
1760
2170
  // src/core/useGlideTable.ts
1761
2171
  import {
1762
2172
  getCoreRowModel,
@@ -1766,15 +2176,15 @@ import {
1766
2176
  useVirtualizer
1767
2177
  } from "@tanstack/react-virtual";
1768
2178
  import {
1769
- useCallback as useCallback4,
1770
- useEffect as useEffect6,
2179
+ useCallback as useCallback5,
2180
+ useEffect as useEffect7,
1771
2181
  useMemo as useMemo3,
1772
- useRef as useRef6,
1773
- useState as useState4
2182
+ useRef as useRef7,
2183
+ useState as useState5
1774
2184
  } from "react";
1775
2185
 
1776
2186
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
1777
- import { useCallback, useEffect as useEffect3, useRef as useRef3, useState } from "react";
2187
+ import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState2 } from "react";
1778
2188
 
1779
2189
  // src/components/ui/table/features/cell-render/commitCellValue.ts
1780
2190
  function commitCellValue({
@@ -1814,21 +2224,21 @@ function useCellEdit({
1814
2224
  onDataChange,
1815
2225
  onCellChange
1816
2226
  }) {
1817
- const [editingCell, setEditingCell] = useState(null);
1818
- const [draftValue, setDraftValue] = useState("");
1819
- const draftValueRef = useRef3(draftValue);
1820
- const editingCellRef = useRef3(editingCell);
1821
- useEffect3(() => {
2227
+ const [editingCell, setEditingCell] = useState2(null);
2228
+ const [draftValue, setDraftValue] = useState2("");
2229
+ const draftValueRef = useRef4(draftValue);
2230
+ const editingCellRef = useRef4(editingCell);
2231
+ useEffect4(() => {
1822
2232
  draftValueRef.current = draftValue;
1823
2233
  }, [draftValue]);
1824
- useEffect3(() => {
2234
+ useEffect4(() => {
1825
2235
  editingCellRef.current = editingCell;
1826
2236
  }, [editingCell]);
1827
- const cancelEdit = useCallback(() => {
2237
+ const cancelEdit = useCallback2(() => {
1828
2238
  setEditingCell(null);
1829
2239
  setDraftValue("");
1830
2240
  }, []);
1831
- const commitEdit = useCallback(
2241
+ const commitEdit = useCallback2(
1832
2242
  (raw) => {
1833
2243
  const current = editingCellRef.current;
1834
2244
  if (!current) return true;
@@ -1864,7 +2274,7 @@ function useCellEdit({
1864
2274
  },
1865
2275
  [cancelEdit, data, onCellChange, onDataChange, rows]
1866
2276
  );
1867
- const startEdit = useCallback(
2277
+ const startEdit = useCallback2(
1868
2278
  (rowIndex, colIndex) => {
1869
2279
  const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
1870
2280
  if (!cell || !isColumnEditable(cell.column.columnDef)) return;
@@ -2100,7 +2510,7 @@ function formatDefaultCellValue(value) {
2100
2510
  }
2101
2511
 
2102
2512
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
2103
- import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState2 } from "react";
2513
+ import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
2104
2514
 
2105
2515
  // src/components/ui/table/features/cell-selection/copyData.ts
2106
2516
  function formatPrimitive(value) {
@@ -2379,15 +2789,15 @@ function useCellSelection({
2379
2789
  onRowsPaste,
2380
2790
  onCellNavigate
2381
2791
  }) {
2382
- const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
2383
- const pendingPasteModeRef = useRef4(null);
2384
- const dragStateRef = useRef4(dragState);
2385
- const onCellNavigateRef = useRef4(onCellNavigate);
2792
+ const [dragState, setDragState] = useState3(INITIAL_DRAG_STATE);
2793
+ const pendingPasteModeRef = useRef5(null);
2794
+ const dragStateRef = useRef5(dragState);
2795
+ const onCellNavigateRef = useRef5(onCellNavigate);
2386
2796
  dragStateRef.current = dragState;
2387
2797
  onCellNavigateRef.current = onCellNavigate;
2388
2798
  const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
2389
2799
  const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
2390
- const handleCellMouseDown = useCallback2(
2800
+ const handleCellMouseDown = useCallback3(
2391
2801
  (rowIndex, colIndex, options) => {
2392
2802
  if (!enabled) return;
2393
2803
  setDragState((prev) => {
@@ -2413,7 +2823,7 @@ function useCellSelection({
2413
2823
  },
2414
2824
  [enabled]
2415
2825
  );
2416
- const handleCellMouseEnter = useCallback2(
2826
+ const handleCellMouseEnter = useCallback3(
2417
2827
  (rowIndex, colIndex) => {
2418
2828
  if (!enabled) return;
2419
2829
  setDragState((prev) => {
@@ -2428,7 +2838,7 @@ function useCellSelection({
2428
2838
  },
2429
2839
  [enabled]
2430
2840
  );
2431
- const handleFillHandleMouseDown = useCallback2(
2841
+ const handleFillHandleMouseDown = useCallback3(
2432
2842
  (rowIndex, colIndex) => {
2433
2843
  if (!enabled) return;
2434
2844
  setDragState((prev) => {
@@ -2445,12 +2855,12 @@ function useCellSelection({
2445
2855
  },
2446
2856
  [enabled]
2447
2857
  );
2448
- useEffect4(() => {
2858
+ useEffect5(() => {
2449
2859
  if (!enabled) {
2450
2860
  setDragState(INITIAL_DRAG_STATE);
2451
2861
  }
2452
2862
  }, [enabled]);
2453
- useEffect4(() => {
2863
+ useEffect5(() => {
2454
2864
  if (!enabled) return;
2455
2865
  const handleKeyDown = (e) => {
2456
2866
  if (e.ctrlKey || e.metaKey || e.altKey) return;
@@ -2497,7 +2907,7 @@ function useCellSelection({
2497
2907
  window.addEventListener("keydown", handleKeyDown);
2498
2908
  return () => window.removeEventListener("keydown", handleKeyDown);
2499
2909
  }, [columnCount, enabled, rows]);
2500
- const copySelection = useCallback2(
2910
+ const copySelection = useCallback3(
2501
2911
  async (options) => {
2502
2912
  if (!enabled || !activeSelectionBounds) return false;
2503
2913
  const mode = options?.includeDescendants && enableSubtreeCopy ? "subtree" : "visible";
@@ -2505,7 +2915,7 @@ function useCellSelection({
2505
2915
  },
2506
2916
  [activeSelectionBounds, enableSubtreeCopy, enabled, rows]
2507
2917
  );
2508
- useEffect4(() => {
2918
+ useEffect5(() => {
2509
2919
  if (!enabled) return;
2510
2920
  const handleKeyDown = (e) => {
2511
2921
  if (!activeSelectionBounds) return;
@@ -2519,7 +2929,7 @@ function useCellSelection({
2519
2929
  window.addEventListener("keydown", handleKeyDown);
2520
2930
  return () => window.removeEventListener("keydown", handleKeyDown);
2521
2931
  }, [activeSelectionBounds, copySelection, enableSubtreeCopy, enabled]);
2522
- const emitRowsPaste = useCallback2(
2932
+ const emitRowsPaste = useCallback3(
2523
2933
  (text, mode) => {
2524
2934
  if (!onRowsPaste || !activeSelectionBounds) return false;
2525
2935
  const payload = buildRowsPastePayload(
@@ -2536,7 +2946,7 @@ function useCellSelection({
2536
2946
  },
2537
2947
  [activeSelectionBounds, onRowsPaste, rows]
2538
2948
  );
2539
- useEffect4(() => {
2949
+ useEffect5(() => {
2540
2950
  if (!enabled || !onRowsPaste) return;
2541
2951
  const pasteHandledRef = { current: false };
2542
2952
  const ignoreNextPasteRef = { current: false };
@@ -2604,7 +3014,7 @@ function useCellSelection({
2604
3014
  enabled,
2605
3015
  onRowsPaste
2606
3016
  ]);
2607
- useEffect4(() => {
3017
+ useEffect5(() => {
2608
3018
  if (!enabled) return;
2609
3019
  const handleMouseUp = () => {
2610
3020
  setDragState((prev) => {
@@ -2656,12 +3066,12 @@ function useCellSelection({
2656
3066
 
2657
3067
  // src/components/ui/table/features/inline-search/useInlineSearch.ts
2658
3068
  import {
2659
- useCallback as useCallback3,
2660
- useEffect as useEffect5,
3069
+ useCallback as useCallback4,
3070
+ useEffect as useEffect6,
2661
3071
  useId,
2662
3072
  useMemo as useMemo2,
2663
- useRef as useRef5,
2664
- useState as useState3
3073
+ useRef as useRef6,
3074
+ useState as useState4
2665
3075
  } from "react";
2666
3076
  var EMPTY_MATCH_KEYS = /* @__PURE__ */ new Set();
2667
3077
  function useInlineSearch({
@@ -2680,45 +3090,45 @@ function useInlineSearch({
2680
3090
  rootRef
2681
3091
  }) {
2682
3092
  const searchInputId = useId();
2683
- const searchInputRef = useRef5(null);
2684
- const [internalShowSearch, setInternalShowSearch] = useState3(false);
2685
- const [internalSearchValue, setInternalSearchValue] = useState3("");
2686
- const [internalResults, setInternalResults] = useState3(
3093
+ const searchInputRef = useRef6(null);
3094
+ const [internalShowSearch, setInternalShowSearch] = useState4(false);
3095
+ const [internalSearchValue, setInternalSearchValue] = useState4("");
3096
+ const [internalResults, setInternalResults] = useState4(
2687
3097
  []
2688
3098
  );
2689
- const [searchStatus, setSearchStatus] = useState3();
2690
- const searchStatusRef = useRef5(searchStatus);
3099
+ const [searchStatus, setSearchStatus] = useState4();
3100
+ const searchStatusRef = useRef6(searchStatus);
2691
3101
  searchStatusRef.current = searchStatus;
2692
- const abortControllerRef = useRef5(null);
2693
- const searchHandleRef = useRef5(void 0);
2694
- const initialStartRowRef = useRef5(initialStartRow);
3102
+ const abortControllerRef = useRef6(null);
3103
+ const searchHandleRef = useRef6(void 0);
3104
+ const initialStartRowRef = useRef6(initialStartRow);
2695
3105
  initialStartRowRef.current = initialStartRow;
2696
- const getCellValueRef = useRef5(getCellValue);
3106
+ const getCellValueRef = useRef6(getCellValue);
2697
3107
  getCellValueRef.current = getCellValue;
2698
3108
  const showSearch = controlledShowSearch ?? internalShowSearch;
2699
3109
  const searchValue = controlledSearchValue ?? internalSearchValue;
2700
3110
  const searchResults = controlledSearchResults ?? internalResults;
2701
- const setSearchValue = useCallback3(
3111
+ const setSearchValue = useCallback4(
2702
3112
  (value) => {
2703
3113
  setInternalSearchValue(value);
2704
3114
  onSearchValueChange?.(value);
2705
3115
  },
2706
3116
  [onSearchValueChange]
2707
3117
  );
2708
- const cancelSearch = useCallback3(() => {
3118
+ const cancelSearch = useCallback4(() => {
2709
3119
  if (searchHandleRef.current !== void 0) {
2710
3120
  window.cancelAnimationFrame(searchHandleRef.current);
2711
3121
  searchHandleRef.current = void 0;
2712
3122
  }
2713
3123
  abortControllerRef.current?.abort();
2714
3124
  }, []);
2715
- const emitResultsChanged = useCallback3(
3125
+ const emitResultsChanged = useCallback4(
2716
3126
  (results, navIndex) => {
2717
3127
  onSearchResultsChanged?.(results, navIndex);
2718
3128
  },
2719
3129
  [onSearchResultsChanged]
2720
3130
  );
2721
- const navigateToIndex = useCallback3(
3131
+ const navigateToIndex = useCallback4(
2722
3132
  (results, navIndex) => {
2723
3133
  if (onSearchResultsChanged) return;
2724
3134
  if (navIndex < 0 || navIndex >= results.length) return;
@@ -2728,7 +3138,7 @@ function useInlineSearch({
2728
3138
  },
2729
3139
  [onNavigateToResult, onSearchResultsChanged]
2730
3140
  );
2731
- const beginSearch = useCallback3(
3141
+ const beginSearch = useCallback4(
2732
3142
  (query) => {
2733
3143
  if (controlledSearchResults !== void 0) return;
2734
3144
  const totalRows = rowCount;
@@ -2800,12 +3210,12 @@ function useInlineSearch({
2800
3210
  rowCount
2801
3211
  ]
2802
3212
  );
2803
- const openSearch = useCallback3(() => {
3213
+ const openSearch = useCallback4(() => {
2804
3214
  if (controlledShowSearch === void 0) {
2805
3215
  setInternalShowSearch(true);
2806
3216
  }
2807
3217
  }, [controlledShowSearch]);
2808
- const closeSearch = useCallback3(() => {
3218
+ const closeSearch = useCallback4(() => {
2809
3219
  if (controlledShowSearch === void 0) {
2810
3220
  setInternalShowSearch(false);
2811
3221
  }
@@ -2820,7 +3230,7 @@ function useInlineSearch({
2820
3230
  emitResultsChanged,
2821
3231
  onSearchClose
2822
3232
  ]);
2823
- const goToNext = useCallback3(() => {
3233
+ const goToNext = useCallback4(() => {
2824
3234
  if (!searchStatus || searchStatus.results === 0) return;
2825
3235
  const newIndex = nextSearchIndex(
2826
3236
  searchStatus.selectedIndex,
@@ -2830,7 +3240,7 @@ function useInlineSearch({
2830
3240
  emitResultsChanged(searchResults, newIndex);
2831
3241
  navigateToIndex(searchResults, newIndex);
2832
3242
  }, [emitResultsChanged, navigateToIndex, searchResults, searchStatus]);
2833
- const goToPrevious = useCallback3(() => {
3243
+ const goToPrevious = useCallback4(() => {
2834
3244
  if (!searchStatus || searchStatus.results === 0) return;
2835
3245
  const newIndex = previousSearchIndex(
2836
3246
  searchStatus.selectedIndex,
@@ -2840,7 +3250,7 @@ function useInlineSearch({
2840
3250
  emitResultsChanged(searchResults, newIndex);
2841
3251
  navigateToIndex(searchResults, newIndex);
2842
3252
  }, [emitResultsChanged, navigateToIndex, searchResults, searchStatus]);
2843
- useEffect5(() => {
3253
+ useEffect6(() => {
2844
3254
  if (controlledSearchResults === void 0) return;
2845
3255
  if (controlledSearchResults.length > 0) {
2846
3256
  setSearchStatus((current) => ({
@@ -2852,7 +3262,7 @@ function useInlineSearch({
2852
3262
  setSearchStatus(void 0);
2853
3263
  }
2854
3264
  }, [controlledSearchResults, rowCount]);
2855
- useEffect5(() => {
3265
+ useEffect6(() => {
2856
3266
  if (!enabled) return;
2857
3267
  setSearchStatus(void 0);
2858
3268
  setInternalResults([]);
@@ -2865,7 +3275,7 @@ function useInlineSearch({
2865
3275
  cancelSearch();
2866
3276
  }
2867
3277
  }, [enabled, showSearch]);
2868
- useEffect5(() => {
3278
+ useEffect6(() => {
2869
3279
  if (!enabled || !showSearch) return;
2870
3280
  if (controlledSearchResults !== void 0) return;
2871
3281
  if (searchValue.trim() === "") {
@@ -2885,7 +3295,7 @@ function useInlineSearch({
2885
3295
  searchValue,
2886
3296
  showSearch
2887
3297
  ]);
2888
- useEffect5(() => {
3298
+ useEffect6(() => {
2889
3299
  if (!enabled) return;
2890
3300
  const handleKeyDown = (event) => {
2891
3301
  if (!(event.ctrlKey || event.metaKey)) return;
@@ -2912,7 +3322,7 @@ function useInlineSearch({
2912
3322
  window.addEventListener("keydown", handleKeyDown, true);
2913
3323
  return () => window.removeEventListener("keydown", handleKeyDown, true);
2914
3324
  }, [controlledShowSearch, enabled, rootRef, showSearch]);
2915
- useEffect5(() => () => cancelSearch(), [cancelSearch]);
3325
+ useEffect6(() => () => cancelSearch(), [cancelSearch]);
2916
3326
  const searchMatchKeys = useMemo2(
2917
3327
  () => buildSearchMatchKeys(searchResults),
2918
3328
  [searchResults]
@@ -2982,6 +3392,7 @@ var DEFAULT_DATA_TABLE_LABELS = {
2982
3392
  expandRow: "Expand row",
2983
3393
  collapseRow: "Collapse row",
2984
3394
  resizeColumn: "Resize column",
3395
+ reorderColumn: "Reorder column",
2985
3396
  searchPlaceholder: "Search\u2026",
2986
3397
  searchResultHint: "Type to search",
2987
3398
  searchPrevious: "Previous result",
@@ -3039,6 +3450,9 @@ function useGlideTable(options) {
3039
3450
  columnSizing: controlledColumnSizing,
3040
3451
  onColumnSizingChange,
3041
3452
  columnResizeMode = "onChange",
3453
+ enableColumnReorder = false,
3454
+ columnOrder: controlledColumnOrder,
3455
+ onColumnOrderChange,
3042
3456
  enableColumnFreeze = false,
3043
3457
  enableInlineSearch = false,
3044
3458
  showSearch,
@@ -3059,16 +3473,17 @@ function useGlideTable(options) {
3059
3473
  }, [labelsProp, emptyText, loadingText, selectionLabel]);
3060
3474
  const enableExpand = Boolean(toggleField);
3061
3475
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
3062
- const [internalRowSelection, setInternalRowSelection] = useState4({});
3063
- const [internalColumnSizing, setInternalColumnSizing] = useState4({});
3064
- const [internalExpandedRows, setInternalExpandedRows] = useState4(
3476
+ const [internalRowSelection, setInternalRowSelection] = useState5({});
3477
+ const [internalColumnSizing, setInternalColumnSizing] = useState5({});
3478
+ const [internalColumnOrder, setInternalColumnOrder] = useState5([]);
3479
+ const [internalExpandedRows, setInternalExpandedRows] = useState5(
3065
3480
  () => /* @__PURE__ */ new Set()
3066
3481
  );
3067
- const [hoveredRowIndex, setHoveredRowIndex] = useState4(null);
3068
- const scrollRef = useRef6(null);
3069
- const rootRef = useRef6(null);
3482
+ const [hoveredRowIndex, setHoveredRowIndex] = useState5(null);
3483
+ const scrollRef = useRef7(null);
3484
+ const rootRef = useRef7(null);
3070
3485
  const shouldVirtualize = enableVirtualization && !enableRowSpan;
3071
- useEffect6(() => {
3486
+ useEffect7(() => {
3072
3487
  if (enableVirtualization && enableRowSpan) {
3073
3488
  console.warn(
3074
3489
  "[useGlideTable] enableRowSpan is on; virtualization is disabled to preserve cell merges."
@@ -3081,8 +3496,23 @@ function useGlideTable(options) {
3081
3496
  internalRowSelection
3082
3497
  );
3083
3498
  const columnSizing = controlledColumnSizing ?? internalColumnSizing;
3499
+ const columnOrder = controlledColumnOrder ?? internalColumnOrder;
3500
+ const tableColumns = useMemo3(() => {
3501
+ if (!enableColumnReorder) return columns;
3502
+ return applyLeafColumnOrder(columns, columnOrder);
3503
+ }, [columnOrder, columns, enableColumnReorder]);
3504
+ const setColumnOrder = useCallback5(
3505
+ (next) => {
3506
+ if (onColumnOrderChange) {
3507
+ onColumnOrderChange(next);
3508
+ return;
3509
+ }
3510
+ setInternalColumnOrder(next);
3511
+ },
3512
+ [onColumnOrderChange]
3513
+ );
3084
3514
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
3085
- const handleExpandedRowsChange = useCallback4(
3515
+ const handleExpandedRowsChange = useCallback5(
3086
3516
  (next) => {
3087
3517
  if (onExpandedRowsChange) {
3088
3518
  onExpandedRowsChange(next);
@@ -3105,7 +3535,7 @@ function useGlideTable(options) {
3105
3535
  });
3106
3536
  const table = useReactTable({
3107
3537
  data: tableData,
3108
- columns,
3538
+ columns: tableColumns,
3109
3539
  ...enableColumnResize ? {
3110
3540
  defaultColumn: {
3111
3541
  minSize: DATA_TABLE_COLUMN_MIN_SIZE,
@@ -3185,7 +3615,7 @@ function useGlideTable(options) {
3185
3615
  }
3186
3616
  return indices;
3187
3617
  }, [selectedRows]);
3188
- const scrollCellIntoView = useCallback4(
3618
+ const scrollCellIntoView = useCallback5(
3189
3619
  (rowIndex, colIndex, options2) => {
3190
3620
  const align = options2?.align ?? "nearest";
3191
3621
  const blockAlign = align === "center" ? "center" : "nearest";
@@ -3212,7 +3642,7 @@ function useGlideTable(options) {
3212
3642
  },
3213
3643
  [rowVirtualizer, shouldVirtualize]
3214
3644
  );
3215
- const handleCellNavigate = useCallback4(
3645
+ const handleCellNavigate = useCallback5(
3216
3646
  (position) => {
3217
3647
  scrollCellIntoView(position.row, position.col, { align: "nearest" });
3218
3648
  },
@@ -3249,7 +3679,7 @@ function useGlideTable(options) {
3249
3679
  () => createCellRendererRegistry(cellRenderers),
3250
3680
  [cellRenderers]
3251
3681
  );
3252
- const commitRenderedCellValue = useCallback4(
3682
+ const commitRenderedCellValue = useCallback5(
3253
3683
  (rowId, columnId, value) => commitCellValue({
3254
3684
  data: tableData,
3255
3685
  rows,
@@ -3261,11 +3691,11 @@ function useGlideTable(options) {
3261
3691
  }),
3262
3692
  [onCellChange, onDataChange, rows, tableData]
3263
3693
  );
3264
- const getCellContext = useCallback4(
3694
+ const getCellContext = useCallback5(
3265
3695
  (cell) => withCellUpdate(cell.getContext(), commitRenderedCellValue),
3266
3696
  [commitRenderedCellValue]
3267
3697
  );
3268
- const handleCellMouseDownWithCommit = useCallback4(
3698
+ const handleCellMouseDownWithCommit = useCallback5(
3269
3699
  (rowIndex, colIndex, options2) => {
3270
3700
  const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
3271
3701
  if (editingCell && !isSameEditingCell && !commitEdit()) {
@@ -3275,7 +3705,7 @@ function useGlideTable(options) {
3275
3705
  },
3276
3706
  [commitEdit, editingCell, handleCellMouseDown]
3277
3707
  );
3278
- const navigateToSearchResult = useCallback4(
3708
+ const navigateToSearchResult = useCallback5(
3279
3709
  (item) => {
3280
3710
  const [colIndex, rowIndex] = item;
3281
3711
  handleCellMouseDownWithCommit(rowIndex, colIndex);
@@ -3283,7 +3713,7 @@ function useGlideTable(options) {
3283
3713
  },
3284
3714
  [handleCellMouseDownWithCommit, scrollCellIntoView]
3285
3715
  );
3286
- const resolveSearchRowId = useCallback4(
3716
+ const resolveSearchRowId = useCallback5(
3287
3717
  (row, index) => {
3288
3718
  if (getRowId) return getRowId(row, index);
3289
3719
  if (enableExpand) {
@@ -3323,7 +3753,7 @@ function useGlideTable(options) {
3323
3753
  tableData,
3324
3754
  toggleField
3325
3755
  ]);
3326
- const searchCorpusRef = useRef6(searchCorpus);
3756
+ const searchCorpusRef = useRef7(searchCorpus);
3327
3757
  searchCorpusRef.current = searchCorpus;
3328
3758
  const visibleRowIndexById = useMemo3(() => {
3329
3759
  const map = /* @__PURE__ */ new Map();
@@ -3332,7 +3762,7 @@ function useGlideTable(options) {
3332
3762
  }
3333
3763
  return map;
3334
3764
  }, [resolveSearchRowId, rows]);
3335
- const getSearchCellValue = useCallback4(
3765
+ const getSearchCellValue = useCallback5(
3336
3766
  (rowIndex, colIndex) => {
3337
3767
  const corpusRow = searchCorpusRef.current[rowIndex];
3338
3768
  const column = visibleLeafColumns[colIndex];
@@ -3355,14 +3785,14 @@ function useGlideTable(options) {
3355
3785
  },
3356
3786
  [rows, visibleLeafColumns, visibleRowIndexById]
3357
3787
  );
3358
- const pendingSearchNavRef = useRef6(null);
3359
- const focusSearchResult = useCallback4(
3788
+ const pendingSearchNavRef = useRef7(null);
3789
+ const focusSearchResult = useCallback5(
3360
3790
  (colIndex, visibleRowIndex) => {
3361
3791
  navigateToSearchResult([colIndex, visibleRowIndex]);
3362
3792
  },
3363
3793
  [navigateToSearchResult]
3364
3794
  );
3365
- const navigateToCorpusSearchResult = useCallback4(
3795
+ const navigateToCorpusSearchResult = useCallback5(
3366
3796
  (item) => {
3367
3797
  const [colIndex, corpusRowIndex] = item;
3368
3798
  const corpusRow = searchCorpusRef.current[corpusRowIndex];
@@ -3395,7 +3825,7 @@ function useGlideTable(options) {
3395
3825
  visibleRowIndexById
3396
3826
  ]
3397
3827
  );
3398
- useEffect6(() => {
3828
+ useEffect7(() => {
3399
3829
  const pending = pendingSearchNavRef.current;
3400
3830
  if (!pending) return;
3401
3831
  const visibleRowIndex = visibleRowIndexById.get(pending.rowId);
@@ -3445,13 +3875,13 @@ function useGlideTable(options) {
3445
3875
  searchCorpus,
3446
3876
  visibleRowIndexById
3447
3877
  ]);
3448
- const clearHover = useCallback4(() => {
3878
+ const clearHover = useCallback5(() => {
3449
3879
  setHoveredRowIndex(null);
3450
3880
  }, []);
3451
- const handleRowHover = useCallback4((rowIndex, _rowData) => {
3881
+ const handleRowHover = useCallback5((rowIndex, _rowData) => {
3452
3882
  setHoveredRowIndex(rowIndex);
3453
3883
  }, []);
3454
- const handleToggleSelect = useCallback4(
3884
+ const handleToggleSelect = useCallback5(
3455
3885
  (row) => {
3456
3886
  if (!row.getCanSelect()) return;
3457
3887
  if (preserveRowSelection && row.getIsSelected()) {
@@ -3461,7 +3891,7 @@ function useGlideTable(options) {
3461
3891
  },
3462
3892
  [preserveRowSelection]
3463
3893
  );
3464
- const handleToggleExpand = useCallback4(
3894
+ const handleToggleExpand = useCallback5(
3465
3895
  (rowKey) => {
3466
3896
  if (preventExpand) return;
3467
3897
  handleExpandedRowsChange(toggleExpandedRowId(rowKey, expandedRows));
@@ -3567,12 +3997,12 @@ function useGlideTable(options) {
3567
3997
  visibleSearchMatchKeys,
3568
3998
  visibleActiveMatch
3569
3999
  ]);
3570
- const copySelectionRef = useRef6(copySelection);
3571
- useEffect6(() => {
4000
+ const copySelectionRef = useRef7(copySelection);
4001
+ useEffect7(() => {
3572
4002
  copySelectionRef.current = copySelection;
3573
4003
  }, [copySelection]);
3574
- const stableCopySelection = useCallback4((options2) => copySelectionRef.current(options2), []);
3575
- useEffect6(() => {
4004
+ const stableCopySelection = useCallback5((options2) => copySelectionRef.current(options2), []);
4005
+ useEffect7(() => {
3576
4006
  onCopyActionsReady?.({ copySelection: stableCopySelection });
3577
4007
  }, [onCopyActionsReady, stableCopySelection]);
3578
4008
  return {
@@ -3587,6 +4017,7 @@ function useGlideTable(options) {
3587
4017
  selectionLabel: labels.selection,
3588
4018
  enableCellSelection,
3589
4019
  enableColumnResize,
4020
+ enableColumnReorder,
3590
4021
  enableColumnFreeze,
3591
4022
  enableInlineSearch,
3592
4023
  shouldVirtualize,
@@ -3600,6 +4031,7 @@ function useGlideTable(options) {
3600
4031
  getCellContext,
3601
4032
  handleToggleSelect,
3602
4033
  clearHover,
4034
+ setColumnOrder,
3603
4035
  copySelection: stableCopySelection,
3604
4036
  inlineSearch: {
3605
4037
  showSearch: inlineSearch.showSearch,
@@ -3683,6 +4115,7 @@ function DataTable({
3683
4115
  selectionLabel,
3684
4116
  enableCellSelection,
3685
4117
  enableColumnResize,
4118
+ enableColumnReorder,
3686
4119
  enableColumnFreeze,
3687
4120
  enableInlineSearch,
3688
4121
  shouldVirtualize,
@@ -3695,6 +4128,7 @@ function DataTable({
3695
4128
  rowContextValue,
3696
4129
  handleToggleSelect,
3697
4130
  clearHover,
4131
+ setColumnOrder,
3698
4132
  inlineSearch
3699
4133
  } = useGlideTable(glideOptions);
3700
4134
  const ToolbarSlot = slots?.Toolbar ?? DataTableToolbar;
@@ -3704,6 +4138,12 @@ function DataTable({
3704
4138
  const EmptySlot = slots?.Empty ?? DefaultEmpty;
3705
4139
  const freezeOffsets = rowContextValue.columnFreeze.offsets;
3706
4140
  const headerGroups = getMergedHeaderGroups(table.getHeaderGroups());
4141
+ const leafColumnIds = table.getVisibleLeafColumns().map((column) => column.id);
4142
+ const { isReordering, draggingColumnId, dropTarget, onHeaderPointerDown } = useColumnReorder({
4143
+ enabled: enableColumnReorder,
4144
+ columnOrder: leafColumnIds,
4145
+ onColumnOrderChange: setColumnOrder
4146
+ });
3707
4147
  const contextValue = useMemo4(
3708
4148
  () => ({ ...rowContextValue, classNames }),
3709
4149
  [rowContextValue, classNames]
@@ -3726,6 +4166,8 @@ function DataTable({
3726
4166
  "DataTableJSX",
3727
4167
  !enableCellSelection && "DataTableJSX--no-cell-selection",
3728
4168
  enableColumnResize && "DataTableJSX--column-resize",
4169
+ enableColumnReorder && "DataTableJSX--column-reorder",
4170
+ isReordering && "DataTableJSX--column-reordering",
3729
4171
  enableColumnFreeze && "DataTableJSX--column-freeze",
3730
4172
  enableInlineSearch && "DataTableJSX--inline-search",
3731
4173
  classNames?.root,
@@ -3794,20 +4236,43 @@ function DataTable({
3794
4236
  ...sizeStyle,
3795
4237
  ...freezeStyle
3796
4238
  };
4239
+ const isPlaceholder = header.isPlaceholder;
4240
+ const leafColumns = header.column.getLeafColumns();
4241
+ const leafIds = leafColumns.map((leafColumn) => leafColumn.id);
4242
+ const isLeafHeader = !isPlaceholder && header.subHeaders.length === 0;
4243
+ const canDrag = enableColumnReorder && !isPlaceholder && leafIds.length > 0 && leafColumns.every(
4244
+ (leafColumn) => isColumnReorderable(leafColumn.columnDef.meta)
4245
+ );
4246
+ const isDragging = draggingColumnId === header.column.id;
4247
+ const dropEdge = !isPlaceholder && dropTarget?.columnId === header.column.id ? dropTarget.edge : void 0;
3797
4248
  return /* @__PURE__ */ jsxs6(
3798
4249
  "th",
3799
4250
  {
3800
4251
  colSpan: header.colSpan,
3801
4252
  rowSpan: header.mergedRowSpan,
4253
+ "data-column-id": enableColumnReorder && !isPlaceholder ? header.column.id : void 0,
4254
+ "data-reorder-ids": enableColumnReorder && !isPlaceholder ? serializeReorderIds(leafIds) : void 0,
4255
+ "data-reorder-leaf": enableColumnReorder && isLeafHeader ? "" : void 0,
4256
+ "data-reorderable": canDrag ? "" : void 0,
4257
+ "data-reordering": isDragging ? "" : void 0,
4258
+ "data-drop-edge": dropEdge,
3802
4259
  "data-resizing": header.column.getIsResizing() ? "" : void 0,
3803
4260
  "data-frozen": freezeOffset?.side,
3804
4261
  "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
4262
+ "aria-grabbed": isDragging ? true : void 0,
4263
+ title: canDrag ? labels.reorderColumn : void 0,
4264
+ onPointerDown: enableColumnReorder ? (event) => onHeaderPointerDown(event, {
4265
+ columnId: header.column.id,
4266
+ leafIds,
4267
+ canDrag
4268
+ }) : void 0,
3805
4269
  style: Object.keys(headerStyle).length > 0 ? headerStyle : void 0,
3806
4270
  className: cn(
3807
4271
  "data-table-head-cell",
3808
4272
  freezeOffset && `data-table-head-cell--frozen-${freezeOffset.side}`,
3809
4273
  CELL_ALIGN_CLASS[align],
3810
4274
  classNames?.headCell,
4275
+ dropEdge && classNames?.dropEdge,
3811
4276
  headerClassName
3812
4277
  ),
3813
4278
  children: [
@@ -3929,10 +4394,10 @@ function DataTable({
3929
4394
  }
3930
4395
 
3931
4396
  // src/components/ui/table/components/Table/Table.tsx
3932
- import { useCallback as useCallback6, useMemo as useMemo5, useState as useState5 } from "react";
4397
+ import { useCallback as useCallback7, useMemo as useMemo5, useState as useState6 } from "react";
3933
4398
 
3934
4399
  // src/components/ui/table/features/cell-render/ResolvedTableCell.tsx
3935
- import { useCallback as useCallback5 } from "react";
4400
+ import { useCallback as useCallback6 } from "react";
3936
4401
  function ResolvedTableCell({
3937
4402
  info
3938
4403
  }) {
@@ -3941,7 +4406,7 @@ function ResolvedTableCell({
3941
4406
  const meta = column.columnDef.meta;
3942
4407
  const value = getValue();
3943
4408
  const columnId = column.id;
3944
- const update = useCallback5(
4409
+ const update = useCallback6(
3945
4410
  (next) => {
3946
4411
  cellRender.commitValue(row.id, columnId, next);
3947
4412
  },
@@ -4001,10 +4466,12 @@ function buildColumnDef(props, sort, onSort) {
4001
4466
  minWidth,
4002
4467
  maxWidth,
4003
4468
  resizable,
4469
+ reorderable,
4004
4470
  frozen,
4005
4471
  align,
4006
4472
  rowSpan,
4007
4473
  rowSpanKey,
4474
+ rowSpanParent,
4008
4475
  editable,
4009
4476
  editType,
4010
4477
  editInputProps,
@@ -4039,6 +4506,7 @@ function buildColumnDef(props, sort, onSort) {
4039
4506
  align,
4040
4507
  rowSpan,
4041
4508
  rowSpanKey,
4509
+ rowSpanParent,
4042
4510
  editable,
4043
4511
  editType,
4044
4512
  editInputProps,
@@ -4046,6 +4514,7 @@ function buildColumnDef(props, sort, onSort) {
4046
4514
  cellProps,
4047
4515
  cellRender: render,
4048
4516
  frozen,
4517
+ reorderable,
4049
4518
  className,
4050
4519
  headerClassName
4051
4520
  }
@@ -4293,8 +4762,8 @@ function TableRoot({
4293
4762
  () => parseTableChildren(children),
4294
4763
  [children]
4295
4764
  );
4296
- const [sort, setSort] = useState5(null);
4297
- const handleSort = useCallback6((field) => {
4765
+ const [sort, setSort] = useState6(null);
4766
+ const handleSort = useCallback7((field) => {
4298
4767
  setSort((previous) => {
4299
4768
  if (previous?.field !== field) {
4300
4769
  return { field, direction: "asc" };