react-glide-table 2.0.2 → 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/core.cjs CHANGED
@@ -31,6 +31,7 @@ __export(core_exports, {
31
31
  ResolvedTableCell: () => ResolvedTableCell,
32
32
  applyCellEdit: () => applyCellEdit,
33
33
  applyFillData: () => applyFillData,
34
+ applyLeafColumnOrder: () => applyLeafColumnOrder,
34
35
  applySelectionUpdater: () => applySelectionUpdater,
35
36
  buildColumnFreezeOffsets: () => buildColumnFreezeOffsets,
36
37
  buildColumnRowSpanMap: () => buildColumnRowSpanMap,
@@ -45,6 +46,7 @@ __export(core_exports, {
45
46
  collectCopyRowEntries: () => collectCopyRowEntries,
46
47
  collectCopyRows: () => collectCopyRows,
47
48
  collectFillChanges: () => collectFillChanges,
49
+ collectLeafColumnIds: () => collectLeafColumnIds,
48
50
  collectRowSpanColumns: () => collectRowSpanColumns,
49
51
  collectSearchMatchesInRange: () => collectSearchMatchesInRange,
50
52
  commitCellValue: () => commitCellValue,
@@ -69,6 +71,7 @@ __export(core_exports, {
69
71
  mapSearchResultToVisibleItem: () => mapSearchResultToVisibleItem,
70
72
  mapSearchResultsToVisibleKeys: () => mapSearchResultsToVisibleKeys,
71
73
  measureMergedSpanRowHeights: () => measureMergedSpanRowHeights,
74
+ moveColumnIds: () => moveColumnIds,
72
75
  nextSearchIndex: () => nextSearchIndex,
73
76
  nextSearchStride: () => nextSearchStride,
74
77
  parseCellEditValue: () => parseCellEditValue,
@@ -78,7 +81,9 @@ __export(core_exports, {
78
81
  resolveCellRenderer: () => resolveCellRenderer,
79
82
  resolveColumnFreezeSide: () => resolveColumnFreezeSide,
80
83
  resolveDataTableLabels: () => resolveDataTableLabels,
84
+ resolveDropEdge: () => resolveDropEdge,
81
85
  resolveHeaderFreezeOffset: () => resolveHeaderFreezeOffset,
86
+ resolveLeafColumnOrder: () => resolveLeafColumnOrder,
82
87
  resolvePasteColumnIds: () => resolvePasteColumnIds,
83
88
  resolveRowSelection: () => resolveRowSelection,
84
89
  resolveRowSpanAt: () => resolveRowSpanAt,
@@ -88,6 +93,7 @@ __export(core_exports, {
88
93
  toggleExpandedRowId: () => toggleExpandedRowId,
89
94
  useCellEdit: () => useCellEdit,
90
95
  useCellSelection: () => useCellSelection,
96
+ useColumnReorder: () => useColumnReorder,
91
97
  useConvertTreeData: () => useConvertTreeData,
92
98
  useGlideTable: () => useGlideTable,
93
99
  useInlineSearch: () => useInlineSearch,
@@ -104,6 +110,7 @@ var DEFAULT_DATA_TABLE_LABELS = {
104
110
  expandRow: "Expand row",
105
111
  collapseRow: "Collapse row",
106
112
  resizeColumn: "Resize column",
113
+ reorderColumn: "Reorder column",
107
114
  searchPlaceholder: "Search\u2026",
108
115
  searchResultHint: "Type to search",
109
116
  searchPrevious: "Previous result",
@@ -134,6 +141,7 @@ var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
134
141
  var DATA_TABLE_COLUMN_SIZE = 150;
135
142
  var DATA_TABLE_COLUMN_MIN_SIZE = 40;
136
143
  var DATA_TABLE_COLUMN_MAX_SIZE = 800;
144
+ var DATA_TABLE_COLUMN_REORDER_THRESHOLD = 4;
137
145
 
138
146
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
139
147
  var import_react = require("react");
@@ -1399,6 +1407,129 @@ function useCellSelection({
1399
1407
  };
1400
1408
  }
1401
1409
 
1410
+ // src/components/ui/table/features/column-reorder/columnReorder.ts
1411
+ function getColumnDefId(column) {
1412
+ if (column.id != null && column.id !== "") return column.id;
1413
+ if ("accessorKey" in column && column.accessorKey != null) {
1414
+ return String(column.accessorKey);
1415
+ }
1416
+ return void 0;
1417
+ }
1418
+ function getColumnDefChildren(column) {
1419
+ if (!("columns" in column) || !Array.isArray(column.columns)) return void 0;
1420
+ if (column.columns.length === 0) return void 0;
1421
+ return column.columns;
1422
+ }
1423
+ function collectLeafColumnIds(columns) {
1424
+ const ids = [];
1425
+ for (const column of columns) {
1426
+ const children = getColumnDefChildren(column);
1427
+ if (children) {
1428
+ ids.push(...collectLeafColumnIds(children));
1429
+ continue;
1430
+ }
1431
+ const id = getColumnDefId(column);
1432
+ if (id) ids.push(id);
1433
+ }
1434
+ return ids;
1435
+ }
1436
+ function areColumnOrdersEqual(left, right) {
1437
+ if (left.length !== right.length) return false;
1438
+ return left.every((id, index) => id === right[index]);
1439
+ }
1440
+ function resolveLeafColumnOrder(columns, order) {
1441
+ const leafIds = collectLeafColumnIds(columns);
1442
+ if (!order?.length) return leafIds;
1443
+ const leafSet = new Set(leafIds);
1444
+ const seen = /* @__PURE__ */ new Set();
1445
+ const next = order.filter((id) => {
1446
+ if (!leafSet.has(id) || seen.has(id)) return false;
1447
+ seen.add(id);
1448
+ return true;
1449
+ });
1450
+ for (const id of leafIds) {
1451
+ if (!seen.has(id)) next.push(id);
1452
+ }
1453
+ return next;
1454
+ }
1455
+ function flattenColumnSlots(columns, group) {
1456
+ const slots = [];
1457
+ for (const column of columns) {
1458
+ const id = getColumnDefId(column);
1459
+ const children = getColumnDefChildren(column);
1460
+ if (children) {
1461
+ const nestedGroup = id ? { id, def: column } : group;
1462
+ slots.push(...flattenColumnSlots(children, nestedGroup));
1463
+ continue;
1464
+ }
1465
+ if (!id) continue;
1466
+ slots.push({ id, def: column, group });
1467
+ }
1468
+ return slots;
1469
+ }
1470
+ function rebuildColumnTree(slots) {
1471
+ const result = [];
1472
+ let index = 0;
1473
+ while (index < slots.length) {
1474
+ const slot = slots[index];
1475
+ if (!slot.group) {
1476
+ result.push(slot.def);
1477
+ index += 1;
1478
+ continue;
1479
+ }
1480
+ const groupId = slot.group.id;
1481
+ const children = [];
1482
+ while (index < slots.length && slots[index]?.group?.id === groupId) {
1483
+ children.push(slots[index].def);
1484
+ index += 1;
1485
+ }
1486
+ const firstChildId = children[0] ? getColumnDefId(children[0]) : groupId;
1487
+ result.push({
1488
+ ...slot.group.def,
1489
+ id: `${groupId}::${firstChildId}`,
1490
+ columns: children
1491
+ });
1492
+ }
1493
+ return result;
1494
+ }
1495
+ function applyLeafColumnOrder(columns, order) {
1496
+ const resolved = resolveLeafColumnOrder(columns, order);
1497
+ const defaultOrder = collectLeafColumnIds(columns);
1498
+ if (areColumnOrdersEqual(resolved, defaultOrder)) {
1499
+ return columns;
1500
+ }
1501
+ const byId = new Map(
1502
+ flattenColumnSlots(columns).map((slot) => [
1503
+ slot.id,
1504
+ slot
1505
+ ])
1506
+ );
1507
+ const ordered = [];
1508
+ for (const id of resolved) {
1509
+ const slot = byId.get(id);
1510
+ if (slot) ordered.push(slot);
1511
+ }
1512
+ return rebuildColumnTree(ordered);
1513
+ }
1514
+ function moveColumnIds(order, fromIds, targetIds, edge) {
1515
+ if (fromIds.length === 0 || targetIds.length === 0) return [...order];
1516
+ const fromSet = new Set(fromIds);
1517
+ if (targetIds.some((id) => fromSet.has(id))) return [...order];
1518
+ const rest = order.filter((id) => !fromSet.has(id));
1519
+ const anchorId = edge === "before" ? targetIds[0] : targetIds[targetIds.length - 1];
1520
+ const anchorIndex = rest.indexOf(anchorId);
1521
+ if (anchorIndex < 0) return [...order];
1522
+ const insertAt = edge === "before" ? anchorIndex : anchorIndex + 1;
1523
+ return [...rest.slice(0, insertAt), ...fromIds, ...rest.slice(insertAt)];
1524
+ }
1525
+ function resolveDropEdge(clientX, rect) {
1526
+ return clientX < rect.left + rect.width / 2 ? "before" : "after";
1527
+ }
1528
+ function parseReorderIds(value) {
1529
+ if (!value) return [];
1530
+ return value.split(",").filter(Boolean);
1531
+ }
1532
+
1402
1533
  // src/components/ui/table/features/column-freeze/columnFreeze.ts
1403
1534
  var HEADER_Z_BASE = 30;
1404
1535
  var BODY_Z_BASE = 5;
@@ -2274,6 +2405,9 @@ function useGlideTable(options) {
2274
2405
  columnSizing: controlledColumnSizing,
2275
2406
  onColumnSizingChange,
2276
2407
  columnResizeMode = "onChange",
2408
+ enableColumnReorder = false,
2409
+ columnOrder: controlledColumnOrder,
2410
+ onColumnOrderChange,
2277
2411
  enableColumnFreeze = false,
2278
2412
  enableInlineSearch = false,
2279
2413
  showSearch,
@@ -2296,6 +2430,7 @@ function useGlideTable(options) {
2296
2430
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
2297
2431
  const [internalRowSelection, setInternalRowSelection] = (0, import_react5.useState)({});
2298
2432
  const [internalColumnSizing, setInternalColumnSizing] = (0, import_react5.useState)({});
2433
+ const [internalColumnOrder, setInternalColumnOrder] = (0, import_react5.useState)([]);
2299
2434
  const [internalExpandedRows, setInternalExpandedRows] = (0, import_react5.useState)(
2300
2435
  () => /* @__PURE__ */ new Set()
2301
2436
  );
@@ -2316,6 +2451,21 @@ function useGlideTable(options) {
2316
2451
  internalRowSelection
2317
2452
  );
2318
2453
  const columnSizing = controlledColumnSizing ?? internalColumnSizing;
2454
+ const columnOrder = controlledColumnOrder ?? internalColumnOrder;
2455
+ const tableColumns = (0, import_react5.useMemo)(() => {
2456
+ if (!enableColumnReorder) return columns;
2457
+ return applyLeafColumnOrder(columns, columnOrder);
2458
+ }, [columnOrder, columns, enableColumnReorder]);
2459
+ const setColumnOrder = (0, import_react5.useCallback)(
2460
+ (next) => {
2461
+ if (onColumnOrderChange) {
2462
+ onColumnOrderChange(next);
2463
+ return;
2464
+ }
2465
+ setInternalColumnOrder(next);
2466
+ },
2467
+ [onColumnOrderChange]
2468
+ );
2319
2469
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
2320
2470
  const handleExpandedRowsChange = (0, import_react5.useCallback)(
2321
2471
  (next) => {
@@ -2340,7 +2490,7 @@ function useGlideTable(options) {
2340
2490
  });
2341
2491
  const table = (0, import_react_table.useReactTable)({
2342
2492
  data: tableData,
2343
- columns,
2493
+ columns: tableColumns,
2344
2494
  ...enableColumnResize ? {
2345
2495
  defaultColumn: {
2346
2496
  minSize: DATA_TABLE_COLUMN_MIN_SIZE,
@@ -2822,6 +2972,7 @@ function useGlideTable(options) {
2822
2972
  selectionLabel: labels.selection,
2823
2973
  enableCellSelection,
2824
2974
  enableColumnResize,
2975
+ enableColumnReorder,
2825
2976
  enableColumnFreeze,
2826
2977
  enableInlineSearch,
2827
2978
  shouldVirtualize,
@@ -2835,6 +2986,7 @@ function useGlideTable(options) {
2835
2986
  getCellContext,
2836
2987
  handleToggleSelect,
2837
2988
  clearHover,
2989
+ setColumnOrder,
2838
2990
  copySelection: stableCopySelection,
2839
2991
  inlineSearch: {
2840
2992
  showSearch: inlineSearch.showSearch,
@@ -2913,6 +3065,214 @@ function getColumnSizeStyle(size, options) {
2913
3065
  ...lockMax ? { maxWidth: size } : {}
2914
3066
  };
2915
3067
  }
3068
+
3069
+ // src/components/ui/table/features/column-reorder/useColumnReorder.ts
3070
+ var import_react8 = require("react");
3071
+ function hitTestReorderHeader(table, clientX, clientY) {
3072
+ const headers = Array.from(
3073
+ table.querySelectorAll(
3074
+ "thead th[data-column-id][data-reorder-ids]"
3075
+ )
3076
+ );
3077
+ const containing = headers.find((element) => {
3078
+ const rect = element.getBoundingClientRect();
3079
+ return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
3080
+ });
3081
+ if (containing) {
3082
+ return {
3083
+ columnId: containing.dataset.columnId ?? "",
3084
+ edge: resolveDropEdge(clientX, containing.getBoundingClientRect())
3085
+ };
3086
+ }
3087
+ const leaves = headers.filter(
3088
+ (element) => element.hasAttribute("data-reorder-leaf")
3089
+ );
3090
+ let match;
3091
+ for (const element of leaves) {
3092
+ const rect = element.getBoundingClientRect();
3093
+ if (clientX >= rect.left && clientX <= rect.right) {
3094
+ match = element;
3095
+ break;
3096
+ }
3097
+ }
3098
+ if (!match && leaves.length > 0) {
3099
+ const first = leaves[0].getBoundingClientRect();
3100
+ const last = leaves[leaves.length - 1].getBoundingClientRect();
3101
+ if (clientX < first.left) match = leaves[0];
3102
+ else if (clientX > last.right) match = leaves[leaves.length - 1];
3103
+ }
3104
+ if (!match) return null;
3105
+ return {
3106
+ columnId: match.dataset.columnId ?? "",
3107
+ edge: resolveDropEdge(clientX, match.getBoundingClientRect())
3108
+ };
3109
+ }
3110
+ function readTargetIds(table, columnId) {
3111
+ const element = table.querySelector(
3112
+ `thead th[data-column-id="${CSS.escape(columnId)}"]`
3113
+ );
3114
+ return parseReorderIds(element?.getAttribute("data-reorder-ids"));
3115
+ }
3116
+ function useColumnReorder(options) {
3117
+ const { enabled, columnOrder, onColumnOrderChange } = options;
3118
+ const sessionRef = (0, import_react8.useRef)(null);
3119
+ const columnOrderRef = (0, import_react8.useRef)(columnOrder);
3120
+ const onColumnOrderChangeRef = (0, import_react8.useRef)(onColumnOrderChange);
3121
+ const [draggingColumnId, setDraggingColumnId] = (0, import_react8.useState)(null);
3122
+ const [dropTarget, setDropTarget] = (0, import_react8.useState)(
3123
+ null
3124
+ );
3125
+ const dropTargetRef = (0, import_react8.useRef)(dropTarget);
3126
+ const previousUserSelectRef = (0, import_react8.useRef)(null);
3127
+ columnOrderRef.current = columnOrder;
3128
+ onColumnOrderChangeRef.current = onColumnOrderChange;
3129
+ dropTargetRef.current = dropTarget;
3130
+ const resetDrag = (0, import_react8.useCallback)(() => {
3131
+ sessionRef.current = null;
3132
+ setDraggingColumnId(null);
3133
+ setDropTarget(null);
3134
+ const backup = previousUserSelectRef.current;
3135
+ previousUserSelectRef.current = null;
3136
+ if (backup) {
3137
+ if (backup.value) {
3138
+ document.body.style.setProperty("user-select", backup.value, backup.priority);
3139
+ } else {
3140
+ document.body.style.removeProperty("user-select");
3141
+ }
3142
+ return;
3143
+ }
3144
+ document.body.style.removeProperty("user-select");
3145
+ }, []);
3146
+ (0, import_react8.useEffect)(() => {
3147
+ if (!enabled) resetDrag();
3148
+ }, [enabled, resetDrag]);
3149
+ (0, import_react8.useEffect)(() => {
3150
+ return () => {
3151
+ resetDrag();
3152
+ };
3153
+ }, [resetDrag]);
3154
+ const onHeaderPointerDown = (0, import_react8.useCallback)(
3155
+ (event, meta) => {
3156
+ if (!enabled || !meta.canDrag) return;
3157
+ if (event.button !== 0) return;
3158
+ if (event.pointerType === "mouse" && event.ctrlKey) return;
3159
+ const target = event.target;
3160
+ if (target instanceof Element && target.closest("[data-table-disable-cell-selection]")) {
3161
+ return;
3162
+ }
3163
+ const table = event.currentTarget.closest("table");
3164
+ if (!(table instanceof HTMLTableElement)) return;
3165
+ sessionRef.current = {
3166
+ pointerId: event.pointerId,
3167
+ startX: event.clientX,
3168
+ startY: event.clientY,
3169
+ columnId: meta.columnId,
3170
+ fromIds: meta.leafIds,
3171
+ table,
3172
+ active: false
3173
+ };
3174
+ },
3175
+ [enabled]
3176
+ );
3177
+ (0, import_react8.useEffect)(() => {
3178
+ if (!enabled) return;
3179
+ const onPointerMove = (event) => {
3180
+ const session = sessionRef.current;
3181
+ if (!session || event.pointerId !== session.pointerId) return;
3182
+ const deltaX = event.clientX - session.startX;
3183
+ const deltaY = event.clientY - session.startY;
3184
+ const distance = Math.hypot(deltaX, deltaY);
3185
+ if (!session.active) {
3186
+ if (distance < DATA_TABLE_COLUMN_REORDER_THRESHOLD) return;
3187
+ session.active = true;
3188
+ if (!previousUserSelectRef.current) {
3189
+ previousUserSelectRef.current = {
3190
+ value: document.body.style.getPropertyValue("user-select"),
3191
+ priority: document.body.style.getPropertyPriority("user-select")
3192
+ };
3193
+ }
3194
+ document.body.style.setProperty("user-select", "none");
3195
+ setDraggingColumnId(session.columnId);
3196
+ }
3197
+ event.preventDefault();
3198
+ const nextTarget = hitTestReorderHeader(
3199
+ session.table,
3200
+ event.clientX,
3201
+ event.clientY
3202
+ );
3203
+ if (!nextTarget || !nextTarget.columnId) {
3204
+ setDropTarget(null);
3205
+ return;
3206
+ }
3207
+ const targetIds = readTargetIds(session.table, nextTarget.columnId);
3208
+ const fromSet = new Set(session.fromIds);
3209
+ if (targetIds.some((id) => fromSet.has(id))) {
3210
+ setDropTarget(null);
3211
+ return;
3212
+ }
3213
+ setDropTarget((previous) => {
3214
+ if (previous?.columnId === nextTarget.columnId && previous.edge === nextTarget.edge) {
3215
+ return previous;
3216
+ }
3217
+ return nextTarget;
3218
+ });
3219
+ };
3220
+ const onPointerUp = (event) => {
3221
+ const session = sessionRef.current;
3222
+ if (!session || event.pointerId !== session.pointerId) {
3223
+ return;
3224
+ }
3225
+ if (session.active) {
3226
+ event.preventDefault();
3227
+ const target = dropTargetRef.current;
3228
+ if (target) {
3229
+ const targetIds = readTargetIds(session.table, target.columnId);
3230
+ const next = moveColumnIds(
3231
+ columnOrderRef.current,
3232
+ session.fromIds,
3233
+ targetIds,
3234
+ target.edge
3235
+ );
3236
+ onColumnOrderChangeRef.current(next);
3237
+ }
3238
+ const suppressClick = (clickEvent) => {
3239
+ clickEvent.preventDefault();
3240
+ clickEvent.stopPropagation();
3241
+ document.removeEventListener("click", suppressClick, true);
3242
+ };
3243
+ document.addEventListener("click", suppressClick, true);
3244
+ window.setTimeout(() => {
3245
+ document.removeEventListener("click", suppressClick, true);
3246
+ }, 0);
3247
+ }
3248
+ resetDrag();
3249
+ };
3250
+ const onPointerCancel = (event) => {
3251
+ const session = sessionRef.current;
3252
+ if (!session || event.pointerId !== session.pointerId) {
3253
+ return;
3254
+ }
3255
+ if (session.active) {
3256
+ event.preventDefault();
3257
+ }
3258
+ resetDrag();
3259
+ };
3260
+ document.addEventListener("pointermove", onPointerMove);
3261
+ document.addEventListener("pointerup", onPointerUp);
3262
+ document.addEventListener("pointercancel", onPointerCancel);
3263
+ return () => {
3264
+ document.removeEventListener("pointermove", onPointerMove);
3265
+ document.removeEventListener("pointerup", onPointerUp);
3266
+ document.removeEventListener("pointercancel", onPointerCancel);
3267
+ };
3268
+ }, [enabled, resetDrag]);
3269
+ return {
3270
+ isReordering: draggingColumnId != null,
3271
+ draggingColumnId,
3272
+ dropTarget,
3273
+ onHeaderPointerDown
3274
+ };
3275
+ }
2916
3276
  // Annotate the CommonJS export names for ESM import in node:
2917
3277
  0 && (module.exports = {
2918
3278
  BUILTIN_CELL_RENDERERS,
@@ -2926,6 +3286,7 @@ function getColumnSizeStyle(size, options) {
2926
3286
  ResolvedTableCell,
2927
3287
  applyCellEdit,
2928
3288
  applyFillData,
3289
+ applyLeafColumnOrder,
2929
3290
  applySelectionUpdater,
2930
3291
  buildColumnFreezeOffsets,
2931
3292
  buildColumnRowSpanMap,
@@ -2940,6 +3301,7 @@ function getColumnSizeStyle(size, options) {
2940
3301
  collectCopyRowEntries,
2941
3302
  collectCopyRows,
2942
3303
  collectFillChanges,
3304
+ collectLeafColumnIds,
2943
3305
  collectRowSpanColumns,
2944
3306
  collectSearchMatchesInRange,
2945
3307
  commitCellValue,
@@ -2964,6 +3326,7 @@ function getColumnSizeStyle(size, options) {
2964
3326
  mapSearchResultToVisibleItem,
2965
3327
  mapSearchResultsToVisibleKeys,
2966
3328
  measureMergedSpanRowHeights,
3329
+ moveColumnIds,
2967
3330
  nextSearchIndex,
2968
3331
  nextSearchStride,
2969
3332
  parseCellEditValue,
@@ -2973,7 +3336,9 @@ function getColumnSizeStyle(size, options) {
2973
3336
  resolveCellRenderer,
2974
3337
  resolveColumnFreezeSide,
2975
3338
  resolveDataTableLabels,
3339
+ resolveDropEdge,
2976
3340
  resolveHeaderFreezeOffset,
3341
+ resolveLeafColumnOrder,
2977
3342
  resolvePasteColumnIds,
2978
3343
  resolveRowSelection,
2979
3344
  resolveRowSpanAt,
@@ -2983,6 +3348,7 @@ function getColumnSizeStyle(size, options) {
2983
3348
  toggleExpandedRowId,
2984
3349
  useCellEdit,
2985
3350
  useCellSelection,
3351
+ useColumnReorder,
2986
3352
  useConvertTreeData,
2987
3353
  useGlideTable,
2988
3354
  useInlineSearch,
package/dist/core.d.cts CHANGED
@@ -1,10 +1,10 @@
1
- import { W as CellEditType, c as CellRenderer, C as CellKind, a as CellRenderContext, i as DataTableClassNames, R as RowSelectionMode, g as ColumnFreezeOffset, p as SearchResultItem, q as SearchStatus, l as DataTableProps, k as DataTableLabels, j as DataTableCopyActions, P as PasteMode, o as RowsPastePayload } from './types-bgEceyRV.cjs';
2
- export { B as BuiltinCellKind, b as CellRenderFn, d as ColumnFreezeColumnInput, e as ColumnFreezeEdgeSide, f as ColumnFreezeMeta, h as ColumnFreezeSide, D as DEFAULT_DATA_TABLE_LABELS, I as INLINE_SEARCH_MAX_RESULTS, S as SearchCorpusRow, t as buildColumnFreezeOffsets, u as buildFlatSearchCorpus, v as buildSearchMatchKey, w as buildSearchMatchKeys, x as buildTreeSearchCorpus, y as cellValueToSearchText, z as collectAncestorKeysToExpand, A as collectSearchMatchesInRange, E as createSearchRegex, F as escapeSearchRegex, G as formatSearchResultLabel, H as getColumnFreezeEdgeAttr, J as getColumnFreezeStyle, K as mapSearchResultToVisibleItem, L as mapSearchResultsToVisibleKeys, M as nextSearchIndex, N as nextSearchStride, O as previousSearchIndex, Q as resolveColumnFreezeSide, U as resolveDataTableLabels, V as resolveHeaderFreezeOffset } from './types-bgEceyRV.cjs';
3
- import { Row, ColumnDef, CellContext, Table, Cell, Updater, RowSelectionState } from '@tanstack/react-table';
4
- export { ColumnDef, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
1
+ import { W as CellEditType, c as CellRenderer, C as CellKind, a as CellRenderContext, i as DataTableClassNames, R as RowSelectionMode, g as ColumnFreezeOffset, p as SearchResultItem, q as SearchStatus, l as DataTableProps, k as DataTableLabels, j as DataTableCopyActions, P as PasteMode, o as RowsPastePayload } from './types-CMUGtH-c.cjs';
2
+ export { B as BuiltinCellKind, b as CellRenderFn, d as ColumnFreezeColumnInput, e as ColumnFreezeEdgeSide, f as ColumnFreezeMeta, h as ColumnFreezeSide, D as DEFAULT_DATA_TABLE_LABELS, I as INLINE_SEARCH_MAX_RESULTS, S as SearchCorpusRow, t as buildColumnFreezeOffsets, u as buildFlatSearchCorpus, v as buildSearchMatchKey, w as buildSearchMatchKeys, x as buildTreeSearchCorpus, y as cellValueToSearchText, z as collectAncestorKeysToExpand, A as collectSearchMatchesInRange, E as createSearchRegex, F as escapeSearchRegex, G as formatSearchResultLabel, H as getColumnFreezeEdgeAttr, J as getColumnFreezeStyle, K as mapSearchResultToVisibleItem, L as mapSearchResultsToVisibleKeys, M as nextSearchIndex, N as nextSearchStride, O as previousSearchIndex, Q as resolveColumnFreezeSide, U as resolveDataTableLabels, V as resolveHeaderFreezeOffset } from './types-CMUGtH-c.cjs';
3
+ import { Row, ColumnDef, CellContext, Table, Cell, ColumnOrderState, Updater, RowSelectionState } from '@tanstack/react-table';
4
+ export { ColumnDef, ColumnOrderState, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
5
5
  import { Virtualizer, VirtualItem } from '@tanstack/react-virtual';
6
6
  import * as react from 'react';
7
- import { RefObject, CSSProperties } from 'react';
7
+ import { RefObject, CSSProperties, PointerEvent } from 'react';
8
8
 
9
9
  /** Neutral default field names for tree conversion */
10
10
  declare const DEFAULT_TREE_ID_FIELD = "id";
@@ -261,6 +261,7 @@ type UseGlideTableResult<T extends Record<string, unknown>> = {
261
261
  selectionLabel: DataTableLabels["selection"];
262
262
  enableCellSelection: boolean;
263
263
  enableColumnResize: boolean;
264
+ enableColumnReorder: boolean;
264
265
  enableColumnFreeze: boolean;
265
266
  enableInlineSearch: boolean;
266
267
  shouldVirtualize: boolean;
@@ -278,6 +279,7 @@ type UseGlideTableResult<T extends Record<string, unknown>> = {
278
279
  getCellContext: <TValue>(cell: Cell<T, TValue>) => CellContextWithUpdate<T, TValue>;
279
280
  handleToggleSelect: (row: Row<T>) => void;
280
281
  clearHover: () => void;
282
+ setColumnOrder: (next: ColumnOrderState) => void;
281
283
  copySelection: DataTableCopyActions["copySelection"];
282
284
  inlineSearch: {
283
285
  showSearch: boolean;
@@ -339,6 +341,38 @@ declare function getColumnSizeStyle(size: number, options?: {
339
341
  lockMax?: boolean;
340
342
  }): CSSProperties | undefined;
341
343
 
344
+ type ColumnDropEdge = "before" | "after";
345
+ declare function collectLeafColumnIds<T>(columns: readonly ColumnDef<T, unknown>[]): string[];
346
+ /** Keep known ids in the given order and append any new leaves at the end. */
347
+ declare function resolveLeafColumnOrder<T>(columns: readonly ColumnDef<T, unknown>[], order: readonly string[] | undefined): string[];
348
+ /**
349
+ * Reorder nested `ColumnDef`s by leaf id list.
350
+ * Consecutive leaves that still share a parent group stay wrapped together;
351
+ * interleaved groups split (Glide-style).
352
+ */
353
+ declare function applyLeafColumnOrder<T>(columns: readonly ColumnDef<T, unknown>[], order: readonly string[] | undefined): ColumnDef<T, unknown>[];
354
+ declare function moveColumnIds(order: readonly string[], fromIds: readonly string[], targetIds: readonly string[], edge: ColumnDropEdge): string[];
355
+ declare function resolveDropEdge(clientX: number, rect: Pick<DOMRect, "left" | "width">): ColumnDropEdge;
356
+
357
+ type ColumnReorderDropTarget = {
358
+ columnId: string;
359
+ edge: ColumnDropEdge;
360
+ };
361
+ declare function useColumnReorder(options: {
362
+ enabled: boolean;
363
+ columnOrder: readonly string[];
364
+ onColumnOrderChange: (next: string[]) => void;
365
+ }): {
366
+ isReordering: boolean;
367
+ draggingColumnId: string | null;
368
+ dropTarget: ColumnReorderDropTarget | null;
369
+ onHeaderPointerDown: (event: PointerEvent<HTMLTableCellElement>, meta: {
370
+ columnId: string;
371
+ leafIds: string[];
372
+ canDrag: boolean;
373
+ }) => void;
374
+ };
375
+
342
376
  type ParsedClipboardTSV = {
343
377
  values: string[][];
344
378
  /**
@@ -463,4 +497,4 @@ declare const useConvertTreeData: <T extends Record<string, unknown>>({ data, en
463
497
  declare function resolveRowSelection(mode: RowSelectionMode, controlledSelection: RowSelectionState | undefined, internalSelection: RowSelectionState): RowSelectionState;
464
498
  declare function applySelectionUpdater(mode: RowSelectionMode, updater: Updater<RowSelectionState>, previous: RowSelectionState): RowSelectionState;
465
499
 
466
- export { BUILTIN_CELL_RENDERERS, CELL_SELECTION_EDGES_CLASS, type CellContextWithUpdate, CellKind, CellRenderContext, CellRenderer, type CellRendererRegistry, type CellSelectionBounds, ColumnFreezeOffset, type ColumnRowSpanMap, type CopyRowEntry, type CopySelectionMode, DEFAULT_TREE_CHILDREN_FIELD, DEFAULT_TREE_ID_FIELD, DEFAULT_TREE_PARENT_ID_FIELD, DEFAULT_TREE_QTY_FIELD, DataTableCopyActions, DataTableLabels, DataTableProps, type DragState, type EditingCell, PasteMode, ResolvedTableCell, RowSelectionMode, type RowSpanInfo, RowsPastePayload, SearchResultItem, SearchStatus, type TreeRow, type UseConvertTreeDataParams, type UseGlideTableOptions, type UseGlideTableResult, type UseInlineSearchOptions, type UseInlineSearchResult, applyCellEdit, applyFillData, applySelectionUpdater, buildColumnRowSpanMap, buildRowsPastePayload, canExpandRow, collectCopyRowEntries, collectCopyRows, collectFillChanges, collectRowSpanColumns, commitCellValue, createCellRendererRegistry, flattenSubtreeRows, formatCellValue, formatDefaultCellValue, getCellEditDraftValue, getCellSelectionEdgeStyle, getColumnEditType, getColumnSizeStyle, getRowIndexInMergedCell, hasCellSelectionEdges, isCellInSelection, isColumnEditable, isEditablePasteTarget, measureMergedSpanRowHeights, parseCellEditValue, parseClipboardTSV, parseClipboardTSVWithDepths, resolveCellRenderer, resolvePasteColumnIds, resolveRowSelection, resolveRowSpanAt, rowRangeToHeightRatios, serializeCopyRowsToTSV, serializeSelectionToTSV, toggleExpandedRowId, useCellEdit, useCellSelection, useConvertTreeData, useGlideTable, useInlineSearch, withCellUpdate, writeSelectionToClipboard };
500
+ export { BUILTIN_CELL_RENDERERS, CELL_SELECTION_EDGES_CLASS, type CellContextWithUpdate, CellKind, CellRenderContext, CellRenderer, type CellRendererRegistry, type CellSelectionBounds, type ColumnDropEdge, ColumnFreezeOffset, type ColumnRowSpanMap, type CopyRowEntry, type CopySelectionMode, DEFAULT_TREE_CHILDREN_FIELD, DEFAULT_TREE_ID_FIELD, DEFAULT_TREE_PARENT_ID_FIELD, DEFAULT_TREE_QTY_FIELD, DataTableCopyActions, DataTableLabels, DataTableProps, type DragState, type EditingCell, PasteMode, ResolvedTableCell, RowSelectionMode, type RowSpanInfo, RowsPastePayload, SearchResultItem, SearchStatus, type TreeRow, type UseConvertTreeDataParams, type UseGlideTableOptions, type UseGlideTableResult, type UseInlineSearchOptions, type UseInlineSearchResult, applyCellEdit, applyFillData, applyLeafColumnOrder, applySelectionUpdater, buildColumnRowSpanMap, buildRowsPastePayload, canExpandRow, collectCopyRowEntries, collectCopyRows, collectFillChanges, collectLeafColumnIds, collectRowSpanColumns, commitCellValue, createCellRendererRegistry, flattenSubtreeRows, formatCellValue, formatDefaultCellValue, getCellEditDraftValue, getCellSelectionEdgeStyle, getColumnEditType, getColumnSizeStyle, getRowIndexInMergedCell, hasCellSelectionEdges, isCellInSelection, isColumnEditable, isEditablePasteTarget, measureMergedSpanRowHeights, moveColumnIds, parseCellEditValue, parseClipboardTSV, parseClipboardTSVWithDepths, resolveCellRenderer, resolveDropEdge, resolveLeafColumnOrder, resolvePasteColumnIds, resolveRowSelection, resolveRowSpanAt, rowRangeToHeightRatios, serializeCopyRowsToTSV, serializeSelectionToTSV, toggleExpandedRowId, useCellEdit, useCellSelection, useColumnReorder, useConvertTreeData, useGlideTable, useInlineSearch, withCellUpdate, writeSelectionToClipboard };
package/dist/core.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { W as CellEditType, c as CellRenderer, C as CellKind, a as CellRenderContext, i as DataTableClassNames, R as RowSelectionMode, g as ColumnFreezeOffset, p as SearchResultItem, q as SearchStatus, l as DataTableProps, k as DataTableLabels, j as DataTableCopyActions, P as PasteMode, o as RowsPastePayload } from './types-bgEceyRV.js';
2
- export { B as BuiltinCellKind, b as CellRenderFn, d as ColumnFreezeColumnInput, e as ColumnFreezeEdgeSide, f as ColumnFreezeMeta, h as ColumnFreezeSide, D as DEFAULT_DATA_TABLE_LABELS, I as INLINE_SEARCH_MAX_RESULTS, S as SearchCorpusRow, t as buildColumnFreezeOffsets, u as buildFlatSearchCorpus, v as buildSearchMatchKey, w as buildSearchMatchKeys, x as buildTreeSearchCorpus, y as cellValueToSearchText, z as collectAncestorKeysToExpand, A as collectSearchMatchesInRange, E as createSearchRegex, F as escapeSearchRegex, G as formatSearchResultLabel, H as getColumnFreezeEdgeAttr, J as getColumnFreezeStyle, K as mapSearchResultToVisibleItem, L as mapSearchResultsToVisibleKeys, M as nextSearchIndex, N as nextSearchStride, O as previousSearchIndex, Q as resolveColumnFreezeSide, U as resolveDataTableLabels, V as resolveHeaderFreezeOffset } from './types-bgEceyRV.js';
3
- import { Row, ColumnDef, CellContext, Table, Cell, Updater, RowSelectionState } from '@tanstack/react-table';
4
- export { ColumnDef, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
1
+ import { W as CellEditType, c as CellRenderer, C as CellKind, a as CellRenderContext, i as DataTableClassNames, R as RowSelectionMode, g as ColumnFreezeOffset, p as SearchResultItem, q as SearchStatus, l as DataTableProps, k as DataTableLabels, j as DataTableCopyActions, P as PasteMode, o as RowsPastePayload } from './types-CMUGtH-c.js';
2
+ export { B as BuiltinCellKind, b as CellRenderFn, d as ColumnFreezeColumnInput, e as ColumnFreezeEdgeSide, f as ColumnFreezeMeta, h as ColumnFreezeSide, D as DEFAULT_DATA_TABLE_LABELS, I as INLINE_SEARCH_MAX_RESULTS, S as SearchCorpusRow, t as buildColumnFreezeOffsets, u as buildFlatSearchCorpus, v as buildSearchMatchKey, w as buildSearchMatchKeys, x as buildTreeSearchCorpus, y as cellValueToSearchText, z as collectAncestorKeysToExpand, A as collectSearchMatchesInRange, E as createSearchRegex, F as escapeSearchRegex, G as formatSearchResultLabel, H as getColumnFreezeEdgeAttr, J as getColumnFreezeStyle, K as mapSearchResultToVisibleItem, L as mapSearchResultsToVisibleKeys, M as nextSearchIndex, N as nextSearchStride, O as previousSearchIndex, Q as resolveColumnFreezeSide, U as resolveDataTableLabels, V as resolveHeaderFreezeOffset } from './types-CMUGtH-c.js';
3
+ import { Row, ColumnDef, CellContext, Table, Cell, ColumnOrderState, Updater, RowSelectionState } from '@tanstack/react-table';
4
+ export { ColumnDef, ColumnOrderState, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
5
5
  import { Virtualizer, VirtualItem } from '@tanstack/react-virtual';
6
6
  import * as react from 'react';
7
- import { RefObject, CSSProperties } from 'react';
7
+ import { RefObject, CSSProperties, PointerEvent } from 'react';
8
8
 
9
9
  /** Neutral default field names for tree conversion */
10
10
  declare const DEFAULT_TREE_ID_FIELD = "id";
@@ -261,6 +261,7 @@ type UseGlideTableResult<T extends Record<string, unknown>> = {
261
261
  selectionLabel: DataTableLabels["selection"];
262
262
  enableCellSelection: boolean;
263
263
  enableColumnResize: boolean;
264
+ enableColumnReorder: boolean;
264
265
  enableColumnFreeze: boolean;
265
266
  enableInlineSearch: boolean;
266
267
  shouldVirtualize: boolean;
@@ -278,6 +279,7 @@ type UseGlideTableResult<T extends Record<string, unknown>> = {
278
279
  getCellContext: <TValue>(cell: Cell<T, TValue>) => CellContextWithUpdate<T, TValue>;
279
280
  handleToggleSelect: (row: Row<T>) => void;
280
281
  clearHover: () => void;
282
+ setColumnOrder: (next: ColumnOrderState) => void;
281
283
  copySelection: DataTableCopyActions["copySelection"];
282
284
  inlineSearch: {
283
285
  showSearch: boolean;
@@ -339,6 +341,38 @@ declare function getColumnSizeStyle(size: number, options?: {
339
341
  lockMax?: boolean;
340
342
  }): CSSProperties | undefined;
341
343
 
344
+ type ColumnDropEdge = "before" | "after";
345
+ declare function collectLeafColumnIds<T>(columns: readonly ColumnDef<T, unknown>[]): string[];
346
+ /** Keep known ids in the given order and append any new leaves at the end. */
347
+ declare function resolveLeafColumnOrder<T>(columns: readonly ColumnDef<T, unknown>[], order: readonly string[] | undefined): string[];
348
+ /**
349
+ * Reorder nested `ColumnDef`s by leaf id list.
350
+ * Consecutive leaves that still share a parent group stay wrapped together;
351
+ * interleaved groups split (Glide-style).
352
+ */
353
+ declare function applyLeafColumnOrder<T>(columns: readonly ColumnDef<T, unknown>[], order: readonly string[] | undefined): ColumnDef<T, unknown>[];
354
+ declare function moveColumnIds(order: readonly string[], fromIds: readonly string[], targetIds: readonly string[], edge: ColumnDropEdge): string[];
355
+ declare function resolveDropEdge(clientX: number, rect: Pick<DOMRect, "left" | "width">): ColumnDropEdge;
356
+
357
+ type ColumnReorderDropTarget = {
358
+ columnId: string;
359
+ edge: ColumnDropEdge;
360
+ };
361
+ declare function useColumnReorder(options: {
362
+ enabled: boolean;
363
+ columnOrder: readonly string[];
364
+ onColumnOrderChange: (next: string[]) => void;
365
+ }): {
366
+ isReordering: boolean;
367
+ draggingColumnId: string | null;
368
+ dropTarget: ColumnReorderDropTarget | null;
369
+ onHeaderPointerDown: (event: PointerEvent<HTMLTableCellElement>, meta: {
370
+ columnId: string;
371
+ leafIds: string[];
372
+ canDrag: boolean;
373
+ }) => void;
374
+ };
375
+
342
376
  type ParsedClipboardTSV = {
343
377
  values: string[][];
344
378
  /**
@@ -463,4 +497,4 @@ declare const useConvertTreeData: <T extends Record<string, unknown>>({ data, en
463
497
  declare function resolveRowSelection(mode: RowSelectionMode, controlledSelection: RowSelectionState | undefined, internalSelection: RowSelectionState): RowSelectionState;
464
498
  declare function applySelectionUpdater(mode: RowSelectionMode, updater: Updater<RowSelectionState>, previous: RowSelectionState): RowSelectionState;
465
499
 
466
- export { BUILTIN_CELL_RENDERERS, CELL_SELECTION_EDGES_CLASS, type CellContextWithUpdate, CellKind, CellRenderContext, CellRenderer, type CellRendererRegistry, type CellSelectionBounds, ColumnFreezeOffset, type ColumnRowSpanMap, type CopyRowEntry, type CopySelectionMode, DEFAULT_TREE_CHILDREN_FIELD, DEFAULT_TREE_ID_FIELD, DEFAULT_TREE_PARENT_ID_FIELD, DEFAULT_TREE_QTY_FIELD, DataTableCopyActions, DataTableLabels, DataTableProps, type DragState, type EditingCell, PasteMode, ResolvedTableCell, RowSelectionMode, type RowSpanInfo, RowsPastePayload, SearchResultItem, SearchStatus, type TreeRow, type UseConvertTreeDataParams, type UseGlideTableOptions, type UseGlideTableResult, type UseInlineSearchOptions, type UseInlineSearchResult, applyCellEdit, applyFillData, applySelectionUpdater, buildColumnRowSpanMap, buildRowsPastePayload, canExpandRow, collectCopyRowEntries, collectCopyRows, collectFillChanges, collectRowSpanColumns, commitCellValue, createCellRendererRegistry, flattenSubtreeRows, formatCellValue, formatDefaultCellValue, getCellEditDraftValue, getCellSelectionEdgeStyle, getColumnEditType, getColumnSizeStyle, getRowIndexInMergedCell, hasCellSelectionEdges, isCellInSelection, isColumnEditable, isEditablePasteTarget, measureMergedSpanRowHeights, parseCellEditValue, parseClipboardTSV, parseClipboardTSVWithDepths, resolveCellRenderer, resolvePasteColumnIds, resolveRowSelection, resolveRowSpanAt, rowRangeToHeightRatios, serializeCopyRowsToTSV, serializeSelectionToTSV, toggleExpandedRowId, useCellEdit, useCellSelection, useConvertTreeData, useGlideTable, useInlineSearch, withCellUpdate, writeSelectionToClipboard };
500
+ export { BUILTIN_CELL_RENDERERS, CELL_SELECTION_EDGES_CLASS, type CellContextWithUpdate, CellKind, CellRenderContext, CellRenderer, type CellRendererRegistry, type CellSelectionBounds, type ColumnDropEdge, ColumnFreezeOffset, type ColumnRowSpanMap, type CopyRowEntry, type CopySelectionMode, DEFAULT_TREE_CHILDREN_FIELD, DEFAULT_TREE_ID_FIELD, DEFAULT_TREE_PARENT_ID_FIELD, DEFAULT_TREE_QTY_FIELD, DataTableCopyActions, DataTableLabels, DataTableProps, type DragState, type EditingCell, PasteMode, ResolvedTableCell, RowSelectionMode, type RowSpanInfo, RowsPastePayload, SearchResultItem, SearchStatus, type TreeRow, type UseConvertTreeDataParams, type UseGlideTableOptions, type UseGlideTableResult, type UseInlineSearchOptions, type UseInlineSearchResult, applyCellEdit, applyFillData, applyLeafColumnOrder, applySelectionUpdater, buildColumnRowSpanMap, buildRowsPastePayload, canExpandRow, collectCopyRowEntries, collectCopyRows, collectFillChanges, collectLeafColumnIds, collectRowSpanColumns, commitCellValue, createCellRendererRegistry, flattenSubtreeRows, formatCellValue, formatDefaultCellValue, getCellEditDraftValue, getCellSelectionEdgeStyle, getColumnEditType, getColumnSizeStyle, getRowIndexInMergedCell, hasCellSelectionEdges, isCellInSelection, isColumnEditable, isEditablePasteTarget, measureMergedSpanRowHeights, moveColumnIds, parseCellEditValue, parseClipboardTSV, parseClipboardTSVWithDepths, resolveCellRenderer, resolveDropEdge, resolveLeafColumnOrder, resolvePasteColumnIds, resolveRowSelection, resolveRowSpanAt, rowRangeToHeightRatios, serializeCopyRowsToTSV, serializeSelectionToTSV, toggleExpandedRowId, useCellEdit, useCellSelection, useColumnReorder, useConvertTreeData, useGlideTable, useInlineSearch, withCellUpdate, writeSelectionToClipboard };