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/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,9 +93,11 @@ __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,
100
+ withCellUpdate: () => withCellUpdate,
94
101
  writeSelectionToClipboard: () => writeSelectionToClipboard
95
102
  });
96
103
  module.exports = __toCommonJS(core_exports);
@@ -103,6 +110,7 @@ var DEFAULT_DATA_TABLE_LABELS = {
103
110
  expandRow: "Expand row",
104
111
  collapseRow: "Collapse row",
105
112
  resizeColumn: "Resize column",
113
+ reorderColumn: "Reorder column",
106
114
  searchPlaceholder: "Search\u2026",
107
115
  searchResultHint: "Type to search",
108
116
  searchPrevious: "Previous result",
@@ -133,6 +141,7 @@ var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
133
141
  var DATA_TABLE_COLUMN_SIZE = 150;
134
142
  var DATA_TABLE_COLUMN_MIN_SIZE = 40;
135
143
  var DATA_TABLE_COLUMN_MAX_SIZE = 800;
144
+ var DATA_TABLE_COLUMN_REORDER_THRESHOLD = 4;
136
145
 
137
146
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
138
147
  var import_react = require("react");
@@ -506,6 +515,16 @@ function formatDefaultCellValue(value) {
506
515
  return String(value);
507
516
  }
508
517
 
518
+ // src/components/ui/table/features/cell-render/withCellUpdate.ts
519
+ function withCellUpdate(context, commitValue) {
520
+ return {
521
+ ...context,
522
+ update: (next) => {
523
+ commitValue(context.row.id, context.column.id, next);
524
+ }
525
+ };
526
+ }
527
+
509
528
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
510
529
  var import_react2 = require("react");
511
530
 
@@ -1388,6 +1407,129 @@ function useCellSelection({
1388
1407
  };
1389
1408
  }
1390
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
+
1391
1533
  // src/components/ui/table/features/column-freeze/columnFreeze.ts
1392
1534
  var HEADER_Z_BASE = 30;
1393
1535
  var BODY_Z_BASE = 5;
@@ -2263,6 +2405,9 @@ function useGlideTable(options) {
2263
2405
  columnSizing: controlledColumnSizing,
2264
2406
  onColumnSizingChange,
2265
2407
  columnResizeMode = "onChange",
2408
+ enableColumnReorder = false,
2409
+ columnOrder: controlledColumnOrder,
2410
+ onColumnOrderChange,
2266
2411
  enableColumnFreeze = false,
2267
2412
  enableInlineSearch = false,
2268
2413
  showSearch,
@@ -2285,6 +2430,7 @@ function useGlideTable(options) {
2285
2430
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
2286
2431
  const [internalRowSelection, setInternalRowSelection] = (0, import_react5.useState)({});
2287
2432
  const [internalColumnSizing, setInternalColumnSizing] = (0, import_react5.useState)({});
2433
+ const [internalColumnOrder, setInternalColumnOrder] = (0, import_react5.useState)([]);
2288
2434
  const [internalExpandedRows, setInternalExpandedRows] = (0, import_react5.useState)(
2289
2435
  () => /* @__PURE__ */ new Set()
2290
2436
  );
@@ -2305,6 +2451,21 @@ function useGlideTable(options) {
2305
2451
  internalRowSelection
2306
2452
  );
2307
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
+ );
2308
2469
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
2309
2470
  const handleExpandedRowsChange = (0, import_react5.useCallback)(
2310
2471
  (next) => {
@@ -2329,7 +2490,7 @@ function useGlideTable(options) {
2329
2490
  });
2330
2491
  const table = (0, import_react_table.useReactTable)({
2331
2492
  data: tableData,
2332
- columns,
2493
+ columns: tableColumns,
2333
2494
  ...enableColumnResize ? {
2334
2495
  defaultColumn: {
2335
2496
  minSize: DATA_TABLE_COLUMN_MIN_SIZE,
@@ -2485,6 +2646,10 @@ function useGlideTable(options) {
2485
2646
  }),
2486
2647
  [onCellChange, onDataChange, rows, tableData]
2487
2648
  );
2649
+ const getCellContext = (0, import_react5.useCallback)(
2650
+ (cell) => withCellUpdate(cell.getContext(), commitRenderedCellValue),
2651
+ [commitRenderedCellValue]
2652
+ );
2488
2653
  const handleCellMouseDownWithCommit = (0, import_react5.useCallback)(
2489
2654
  (rowIndex, colIndex, options2) => {
2490
2655
  const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
@@ -2807,6 +2972,7 @@ function useGlideTable(options) {
2807
2972
  selectionLabel: labels.selection,
2808
2973
  enableCellSelection,
2809
2974
  enableColumnResize,
2975
+ enableColumnReorder,
2810
2976
  enableColumnFreeze,
2811
2977
  enableInlineSearch,
2812
2978
  shouldVirtualize,
@@ -2817,8 +2983,10 @@ function useGlideTable(options) {
2817
2983
  paddingTop,
2818
2984
  paddingBottom,
2819
2985
  rowContextValue,
2986
+ getCellContext,
2820
2987
  handleToggleSelect,
2821
2988
  clearHover,
2989
+ setColumnOrder,
2822
2990
  copySelection: stableCopySelection,
2823
2991
  inlineSearch: {
2824
2992
  showSearch: inlineSearch.showSearch,
@@ -2897,6 +3065,214 @@ function getColumnSizeStyle(size, options) {
2897
3065
  ...lockMax ? { maxWidth: size } : {}
2898
3066
  };
2899
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
+ }
2900
3276
  // Annotate the CommonJS export names for ESM import in node:
2901
3277
  0 && (module.exports = {
2902
3278
  BUILTIN_CELL_RENDERERS,
@@ -2910,6 +3286,7 @@ function getColumnSizeStyle(size, options) {
2910
3286
  ResolvedTableCell,
2911
3287
  applyCellEdit,
2912
3288
  applyFillData,
3289
+ applyLeafColumnOrder,
2913
3290
  applySelectionUpdater,
2914
3291
  buildColumnFreezeOffsets,
2915
3292
  buildColumnRowSpanMap,
@@ -2924,6 +3301,7 @@ function getColumnSizeStyle(size, options) {
2924
3301
  collectCopyRowEntries,
2925
3302
  collectCopyRows,
2926
3303
  collectFillChanges,
3304
+ collectLeafColumnIds,
2927
3305
  collectRowSpanColumns,
2928
3306
  collectSearchMatchesInRange,
2929
3307
  commitCellValue,
@@ -2948,6 +3326,7 @@ function getColumnSizeStyle(size, options) {
2948
3326
  mapSearchResultToVisibleItem,
2949
3327
  mapSearchResultsToVisibleKeys,
2950
3328
  measureMergedSpanRowHeights,
3329
+ moveColumnIds,
2951
3330
  nextSearchIndex,
2952
3331
  nextSearchStride,
2953
3332
  parseCellEditValue,
@@ -2957,7 +3336,9 @@ function getColumnSizeStyle(size, options) {
2957
3336
  resolveCellRenderer,
2958
3337
  resolveColumnFreezeSide,
2959
3338
  resolveDataTableLabels,
3339
+ resolveDropEdge,
2960
3340
  resolveHeaderFreezeOffset,
3341
+ resolveLeafColumnOrder,
2961
3342
  resolvePasteColumnIds,
2962
3343
  resolveRowSelection,
2963
3344
  resolveRowSpanAt,
@@ -2967,8 +3348,10 @@ function getColumnSizeStyle(size, options) {
2967
3348
  toggleExpandedRowId,
2968
3349
  useCellEdit,
2969
3350
  useCellSelection,
3351
+ useColumnReorder,
2970
3352
  useConvertTreeData,
2971
3353
  useGlideTable,
2972
3354
  useInlineSearch,
3355
+ withCellUpdate,
2973
3356
  writeSelectionToClipboard
2974
3357
  });
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-DJOlsDL8.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-DJOlsDL8.cjs';
3
- import { Row, ColumnDef, Table, CellContext, 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";
@@ -197,6 +197,19 @@ type DataTableRowContextValue = {
197
197
  };
198
198
  };
199
199
 
200
+ /**
201
+ * TanStack `CellContext` with a guaranteed `update` commit helper.
202
+ * Prefer this over bare `cell.getContext()`, which does not include `update` at runtime.
203
+ */
204
+ type CellContextWithUpdate<TData, TValue> = CellContext<TData, TValue> & {
205
+ update: (next: TValue) => void;
206
+ };
207
+ /**
208
+ * Injects `update` into a TanStack `CellContext` so `ColumnDef.cell` can commit
209
+ * through `onCellChange` / `onDataChange` the same way compound `Column.render` does.
210
+ */
211
+ declare function withCellUpdate<TData extends Record<string, unknown>, TValue>(context: CellContext<TData, TValue>, commitValue: (rowId: string, columnId: string, value: unknown) => boolean): CellContextWithUpdate<TData, TValue>;
212
+
200
213
  type UseInlineSearchOptions = {
201
214
  enabled?: boolean;
202
215
  rowCount: number;
@@ -248,6 +261,7 @@ type UseGlideTableResult<T extends Record<string, unknown>> = {
248
261
  selectionLabel: DataTableLabels["selection"];
249
262
  enableCellSelection: boolean;
250
263
  enableColumnResize: boolean;
264
+ enableColumnReorder: boolean;
251
265
  enableColumnFreeze: boolean;
252
266
  enableInlineSearch: boolean;
253
267
  shouldVirtualize: boolean;
@@ -258,8 +272,14 @@ type UseGlideTableResult<T extends Record<string, unknown>> = {
258
272
  paddingTop: number;
259
273
  paddingBottom: number;
260
274
  rowContextValue: DataTableRowContextValue;
275
+ /**
276
+ * TanStack `CellContext` with `update` injected for custom `ColumnDef.cell` renders.
277
+ * Prefer this over `cell.getContext()` when calling `flexRender` yourself.
278
+ */
279
+ getCellContext: <TValue>(cell: Cell<T, TValue>) => CellContextWithUpdate<T, TValue>;
261
280
  handleToggleSelect: (row: Row<T>) => void;
262
281
  clearHover: () => void;
282
+ setColumnOrder: (next: ColumnOrderState) => void;
263
283
  copySelection: DataTableCopyActions["copySelection"];
264
284
  inlineSearch: {
265
285
  showSearch: boolean;
@@ -321,6 +341,38 @@ declare function getColumnSizeStyle(size: number, options?: {
321
341
  lockMax?: boolean;
322
342
  }): CSSProperties | undefined;
323
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
+
324
376
  type ParsedClipboardTSV = {
325
377
  values: string[][];
326
378
  /**
@@ -445,4 +497,4 @@ declare const useConvertTreeData: <T extends Record<string, unknown>>({ data, en
445
497
  declare function resolveRowSelection(mode: RowSelectionMode, controlledSelection: RowSelectionState | undefined, internalSelection: RowSelectionState): RowSelectionState;
446
498
  declare function applySelectionUpdater(mode: RowSelectionMode, updater: Updater<RowSelectionState>, previous: RowSelectionState): RowSelectionState;
447
499
 
448
- export { BUILTIN_CELL_RENDERERS, CELL_SELECTION_EDGES_CLASS, 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, 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 };