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/README.md +70 -6
- package/dist/compound.cjs +532 -117
- package/dist/compound.d.cts +3 -3
- package/dist/compound.d.ts +3 -3
- package/dist/compound.js +513 -93
- package/dist/core.cjs +384 -1
- package/dist/core.d.cts +58 -6
- package/dist/core.d.ts +58 -6
- package/dist/core.js +382 -1
- package/dist/index.cjs +454 -25
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +436 -9
- package/dist/{types-DJOlsDL8.d.cts → types-CMUGtH-c.d.cts} +33 -1
- package/dist/{types-DJOlsDL8.d.ts → types-CMUGtH-c.d.ts} +33 -1
- package/package.json +1 -1
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-
|
|
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-
|
|
3
|
-
import { Row, ColumnDef, 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";
|
|
@@ -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 };
|
package/dist/core.js
CHANGED
|
@@ -6,6 +6,7 @@ var DEFAULT_DATA_TABLE_LABELS = {
|
|
|
6
6
|
expandRow: "Expand row",
|
|
7
7
|
collapseRow: "Collapse row",
|
|
8
8
|
resizeColumn: "Resize column",
|
|
9
|
+
reorderColumn: "Reorder column",
|
|
9
10
|
searchPlaceholder: "Search\u2026",
|
|
10
11
|
searchResultHint: "Type to search",
|
|
11
12
|
searchPrevious: "Previous result",
|
|
@@ -47,6 +48,7 @@ var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
|
|
|
47
48
|
var DATA_TABLE_COLUMN_SIZE = 150;
|
|
48
49
|
var DATA_TABLE_COLUMN_MIN_SIZE = 40;
|
|
49
50
|
var DATA_TABLE_COLUMN_MAX_SIZE = 800;
|
|
51
|
+
var DATA_TABLE_COLUMN_REORDER_THRESHOLD = 4;
|
|
50
52
|
|
|
51
53
|
// src/components/ui/table/features/cell-edit/useCellEdit.ts
|
|
52
54
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
@@ -420,6 +422,16 @@ function formatDefaultCellValue(value) {
|
|
|
420
422
|
return String(value);
|
|
421
423
|
}
|
|
422
424
|
|
|
425
|
+
// src/components/ui/table/features/cell-render/withCellUpdate.ts
|
|
426
|
+
function withCellUpdate(context, commitValue) {
|
|
427
|
+
return {
|
|
428
|
+
...context,
|
|
429
|
+
update: (next) => {
|
|
430
|
+
commitValue(context.row.id, context.column.id, next);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
423
435
|
// src/components/ui/table/features/cell-selection/useCellSelection.ts
|
|
424
436
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
425
437
|
|
|
@@ -1302,6 +1314,129 @@ function useCellSelection({
|
|
|
1302
1314
|
};
|
|
1303
1315
|
}
|
|
1304
1316
|
|
|
1317
|
+
// src/components/ui/table/features/column-reorder/columnReorder.ts
|
|
1318
|
+
function getColumnDefId(column) {
|
|
1319
|
+
if (column.id != null && column.id !== "") return column.id;
|
|
1320
|
+
if ("accessorKey" in column && column.accessorKey != null) {
|
|
1321
|
+
return String(column.accessorKey);
|
|
1322
|
+
}
|
|
1323
|
+
return void 0;
|
|
1324
|
+
}
|
|
1325
|
+
function getColumnDefChildren(column) {
|
|
1326
|
+
if (!("columns" in column) || !Array.isArray(column.columns)) return void 0;
|
|
1327
|
+
if (column.columns.length === 0) return void 0;
|
|
1328
|
+
return column.columns;
|
|
1329
|
+
}
|
|
1330
|
+
function collectLeafColumnIds(columns) {
|
|
1331
|
+
const ids = [];
|
|
1332
|
+
for (const column of columns) {
|
|
1333
|
+
const children = getColumnDefChildren(column);
|
|
1334
|
+
if (children) {
|
|
1335
|
+
ids.push(...collectLeafColumnIds(children));
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
const id = getColumnDefId(column);
|
|
1339
|
+
if (id) ids.push(id);
|
|
1340
|
+
}
|
|
1341
|
+
return ids;
|
|
1342
|
+
}
|
|
1343
|
+
function areColumnOrdersEqual(left, right) {
|
|
1344
|
+
if (left.length !== right.length) return false;
|
|
1345
|
+
return left.every((id, index) => id === right[index]);
|
|
1346
|
+
}
|
|
1347
|
+
function resolveLeafColumnOrder(columns, order) {
|
|
1348
|
+
const leafIds = collectLeafColumnIds(columns);
|
|
1349
|
+
if (!order?.length) return leafIds;
|
|
1350
|
+
const leafSet = new Set(leafIds);
|
|
1351
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1352
|
+
const next = order.filter((id) => {
|
|
1353
|
+
if (!leafSet.has(id) || seen.has(id)) return false;
|
|
1354
|
+
seen.add(id);
|
|
1355
|
+
return true;
|
|
1356
|
+
});
|
|
1357
|
+
for (const id of leafIds) {
|
|
1358
|
+
if (!seen.has(id)) next.push(id);
|
|
1359
|
+
}
|
|
1360
|
+
return next;
|
|
1361
|
+
}
|
|
1362
|
+
function flattenColumnSlots(columns, group) {
|
|
1363
|
+
const slots = [];
|
|
1364
|
+
for (const column of columns) {
|
|
1365
|
+
const id = getColumnDefId(column);
|
|
1366
|
+
const children = getColumnDefChildren(column);
|
|
1367
|
+
if (children) {
|
|
1368
|
+
const nestedGroup = id ? { id, def: column } : group;
|
|
1369
|
+
slots.push(...flattenColumnSlots(children, nestedGroup));
|
|
1370
|
+
continue;
|
|
1371
|
+
}
|
|
1372
|
+
if (!id) continue;
|
|
1373
|
+
slots.push({ id, def: column, group });
|
|
1374
|
+
}
|
|
1375
|
+
return slots;
|
|
1376
|
+
}
|
|
1377
|
+
function rebuildColumnTree(slots) {
|
|
1378
|
+
const result = [];
|
|
1379
|
+
let index = 0;
|
|
1380
|
+
while (index < slots.length) {
|
|
1381
|
+
const slot = slots[index];
|
|
1382
|
+
if (!slot.group) {
|
|
1383
|
+
result.push(slot.def);
|
|
1384
|
+
index += 1;
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
const groupId = slot.group.id;
|
|
1388
|
+
const children = [];
|
|
1389
|
+
while (index < slots.length && slots[index]?.group?.id === groupId) {
|
|
1390
|
+
children.push(slots[index].def);
|
|
1391
|
+
index += 1;
|
|
1392
|
+
}
|
|
1393
|
+
const firstChildId = children[0] ? getColumnDefId(children[0]) : groupId;
|
|
1394
|
+
result.push({
|
|
1395
|
+
...slot.group.def,
|
|
1396
|
+
id: `${groupId}::${firstChildId}`,
|
|
1397
|
+
columns: children
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
return result;
|
|
1401
|
+
}
|
|
1402
|
+
function applyLeafColumnOrder(columns, order) {
|
|
1403
|
+
const resolved = resolveLeafColumnOrder(columns, order);
|
|
1404
|
+
const defaultOrder = collectLeafColumnIds(columns);
|
|
1405
|
+
if (areColumnOrdersEqual(resolved, defaultOrder)) {
|
|
1406
|
+
return columns;
|
|
1407
|
+
}
|
|
1408
|
+
const byId = new Map(
|
|
1409
|
+
flattenColumnSlots(columns).map((slot) => [
|
|
1410
|
+
slot.id,
|
|
1411
|
+
slot
|
|
1412
|
+
])
|
|
1413
|
+
);
|
|
1414
|
+
const ordered = [];
|
|
1415
|
+
for (const id of resolved) {
|
|
1416
|
+
const slot = byId.get(id);
|
|
1417
|
+
if (slot) ordered.push(slot);
|
|
1418
|
+
}
|
|
1419
|
+
return rebuildColumnTree(ordered);
|
|
1420
|
+
}
|
|
1421
|
+
function moveColumnIds(order, fromIds, targetIds, edge) {
|
|
1422
|
+
if (fromIds.length === 0 || targetIds.length === 0) return [...order];
|
|
1423
|
+
const fromSet = new Set(fromIds);
|
|
1424
|
+
if (targetIds.some((id) => fromSet.has(id))) return [...order];
|
|
1425
|
+
const rest = order.filter((id) => !fromSet.has(id));
|
|
1426
|
+
const anchorId = edge === "before" ? targetIds[0] : targetIds[targetIds.length - 1];
|
|
1427
|
+
const anchorIndex = rest.indexOf(anchorId);
|
|
1428
|
+
if (anchorIndex < 0) return [...order];
|
|
1429
|
+
const insertAt = edge === "before" ? anchorIndex : anchorIndex + 1;
|
|
1430
|
+
return [...rest.slice(0, insertAt), ...fromIds, ...rest.slice(insertAt)];
|
|
1431
|
+
}
|
|
1432
|
+
function resolveDropEdge(clientX, rect) {
|
|
1433
|
+
return clientX < rect.left + rect.width / 2 ? "before" : "after";
|
|
1434
|
+
}
|
|
1435
|
+
function parseReorderIds(value) {
|
|
1436
|
+
if (!value) return [];
|
|
1437
|
+
return value.split(",").filter(Boolean);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1305
1440
|
// src/components/ui/table/features/column-freeze/columnFreeze.ts
|
|
1306
1441
|
var HEADER_Z_BASE = 30;
|
|
1307
1442
|
var BODY_Z_BASE = 5;
|
|
@@ -2184,6 +2319,9 @@ function useGlideTable(options) {
|
|
|
2184
2319
|
columnSizing: controlledColumnSizing,
|
|
2185
2320
|
onColumnSizingChange,
|
|
2186
2321
|
columnResizeMode = "onChange",
|
|
2322
|
+
enableColumnReorder = false,
|
|
2323
|
+
columnOrder: controlledColumnOrder,
|
|
2324
|
+
onColumnOrderChange,
|
|
2187
2325
|
enableColumnFreeze = false,
|
|
2188
2326
|
enableInlineSearch = false,
|
|
2189
2327
|
showSearch,
|
|
@@ -2206,6 +2344,7 @@ function useGlideTable(options) {
|
|
|
2206
2344
|
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
2207
2345
|
const [internalRowSelection, setInternalRowSelection] = useState4({});
|
|
2208
2346
|
const [internalColumnSizing, setInternalColumnSizing] = useState4({});
|
|
2347
|
+
const [internalColumnOrder, setInternalColumnOrder] = useState4([]);
|
|
2209
2348
|
const [internalExpandedRows, setInternalExpandedRows] = useState4(
|
|
2210
2349
|
() => /* @__PURE__ */ new Set()
|
|
2211
2350
|
);
|
|
@@ -2226,6 +2365,21 @@ function useGlideTable(options) {
|
|
|
2226
2365
|
internalRowSelection
|
|
2227
2366
|
);
|
|
2228
2367
|
const columnSizing = controlledColumnSizing ?? internalColumnSizing;
|
|
2368
|
+
const columnOrder = controlledColumnOrder ?? internalColumnOrder;
|
|
2369
|
+
const tableColumns = useMemo3(() => {
|
|
2370
|
+
if (!enableColumnReorder) return columns;
|
|
2371
|
+
return applyLeafColumnOrder(columns, columnOrder);
|
|
2372
|
+
}, [columnOrder, columns, enableColumnReorder]);
|
|
2373
|
+
const setColumnOrder = useCallback4(
|
|
2374
|
+
(next) => {
|
|
2375
|
+
if (onColumnOrderChange) {
|
|
2376
|
+
onColumnOrderChange(next);
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
setInternalColumnOrder(next);
|
|
2380
|
+
},
|
|
2381
|
+
[onColumnOrderChange]
|
|
2382
|
+
);
|
|
2229
2383
|
const expandedRows = controlledExpandedRows ?? internalExpandedRows;
|
|
2230
2384
|
const handleExpandedRowsChange = useCallback4(
|
|
2231
2385
|
(next) => {
|
|
@@ -2250,7 +2404,7 @@ function useGlideTable(options) {
|
|
|
2250
2404
|
});
|
|
2251
2405
|
const table = useReactTable({
|
|
2252
2406
|
data: tableData,
|
|
2253
|
-
columns,
|
|
2407
|
+
columns: tableColumns,
|
|
2254
2408
|
...enableColumnResize ? {
|
|
2255
2409
|
defaultColumn: {
|
|
2256
2410
|
minSize: DATA_TABLE_COLUMN_MIN_SIZE,
|
|
@@ -2406,6 +2560,10 @@ function useGlideTable(options) {
|
|
|
2406
2560
|
}),
|
|
2407
2561
|
[onCellChange, onDataChange, rows, tableData]
|
|
2408
2562
|
);
|
|
2563
|
+
const getCellContext = useCallback4(
|
|
2564
|
+
(cell) => withCellUpdate(cell.getContext(), commitRenderedCellValue),
|
|
2565
|
+
[commitRenderedCellValue]
|
|
2566
|
+
);
|
|
2409
2567
|
const handleCellMouseDownWithCommit = useCallback4(
|
|
2410
2568
|
(rowIndex, colIndex, options2) => {
|
|
2411
2569
|
const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
|
|
@@ -2728,6 +2886,7 @@ function useGlideTable(options) {
|
|
|
2728
2886
|
selectionLabel: labels.selection,
|
|
2729
2887
|
enableCellSelection,
|
|
2730
2888
|
enableColumnResize,
|
|
2889
|
+
enableColumnReorder,
|
|
2731
2890
|
enableColumnFreeze,
|
|
2732
2891
|
enableInlineSearch,
|
|
2733
2892
|
shouldVirtualize,
|
|
@@ -2738,8 +2897,10 @@ function useGlideTable(options) {
|
|
|
2738
2897
|
paddingTop,
|
|
2739
2898
|
paddingBottom,
|
|
2740
2899
|
rowContextValue,
|
|
2900
|
+
getCellContext,
|
|
2741
2901
|
handleToggleSelect,
|
|
2742
2902
|
clearHover,
|
|
2903
|
+
setColumnOrder,
|
|
2743
2904
|
copySelection: stableCopySelection,
|
|
2744
2905
|
inlineSearch: {
|
|
2745
2906
|
showSearch: inlineSearch.showSearch,
|
|
@@ -2818,6 +2979,219 @@ function getColumnSizeStyle(size, options) {
|
|
|
2818
2979
|
...lockMax ? { maxWidth: size } : {}
|
|
2819
2980
|
};
|
|
2820
2981
|
}
|
|
2982
|
+
|
|
2983
|
+
// src/components/ui/table/features/column-reorder/useColumnReorder.ts
|
|
2984
|
+
import {
|
|
2985
|
+
useCallback as useCallback6,
|
|
2986
|
+
useEffect as useEffect6,
|
|
2987
|
+
useRef as useRef6,
|
|
2988
|
+
useState as useState5
|
|
2989
|
+
} from "react";
|
|
2990
|
+
function hitTestReorderHeader(table, clientX, clientY) {
|
|
2991
|
+
const headers = Array.from(
|
|
2992
|
+
table.querySelectorAll(
|
|
2993
|
+
"thead th[data-column-id][data-reorder-ids]"
|
|
2994
|
+
)
|
|
2995
|
+
);
|
|
2996
|
+
const containing = headers.find((element) => {
|
|
2997
|
+
const rect = element.getBoundingClientRect();
|
|
2998
|
+
return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
|
2999
|
+
});
|
|
3000
|
+
if (containing) {
|
|
3001
|
+
return {
|
|
3002
|
+
columnId: containing.dataset.columnId ?? "",
|
|
3003
|
+
edge: resolveDropEdge(clientX, containing.getBoundingClientRect())
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
const leaves = headers.filter(
|
|
3007
|
+
(element) => element.hasAttribute("data-reorder-leaf")
|
|
3008
|
+
);
|
|
3009
|
+
let match;
|
|
3010
|
+
for (const element of leaves) {
|
|
3011
|
+
const rect = element.getBoundingClientRect();
|
|
3012
|
+
if (clientX >= rect.left && clientX <= rect.right) {
|
|
3013
|
+
match = element;
|
|
3014
|
+
break;
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
if (!match && leaves.length > 0) {
|
|
3018
|
+
const first = leaves[0].getBoundingClientRect();
|
|
3019
|
+
const last = leaves[leaves.length - 1].getBoundingClientRect();
|
|
3020
|
+
if (clientX < first.left) match = leaves[0];
|
|
3021
|
+
else if (clientX > last.right) match = leaves[leaves.length - 1];
|
|
3022
|
+
}
|
|
3023
|
+
if (!match) return null;
|
|
3024
|
+
return {
|
|
3025
|
+
columnId: match.dataset.columnId ?? "",
|
|
3026
|
+
edge: resolveDropEdge(clientX, match.getBoundingClientRect())
|
|
3027
|
+
};
|
|
3028
|
+
}
|
|
3029
|
+
function readTargetIds(table, columnId) {
|
|
3030
|
+
const element = table.querySelector(
|
|
3031
|
+
`thead th[data-column-id="${CSS.escape(columnId)}"]`
|
|
3032
|
+
);
|
|
3033
|
+
return parseReorderIds(element?.getAttribute("data-reorder-ids"));
|
|
3034
|
+
}
|
|
3035
|
+
function useColumnReorder(options) {
|
|
3036
|
+
const { enabled, columnOrder, onColumnOrderChange } = options;
|
|
3037
|
+
const sessionRef = useRef6(null);
|
|
3038
|
+
const columnOrderRef = useRef6(columnOrder);
|
|
3039
|
+
const onColumnOrderChangeRef = useRef6(onColumnOrderChange);
|
|
3040
|
+
const [draggingColumnId, setDraggingColumnId] = useState5(null);
|
|
3041
|
+
const [dropTarget, setDropTarget] = useState5(
|
|
3042
|
+
null
|
|
3043
|
+
);
|
|
3044
|
+
const dropTargetRef = useRef6(dropTarget);
|
|
3045
|
+
const previousUserSelectRef = useRef6(null);
|
|
3046
|
+
columnOrderRef.current = columnOrder;
|
|
3047
|
+
onColumnOrderChangeRef.current = onColumnOrderChange;
|
|
3048
|
+
dropTargetRef.current = dropTarget;
|
|
3049
|
+
const resetDrag = useCallback6(() => {
|
|
3050
|
+
sessionRef.current = null;
|
|
3051
|
+
setDraggingColumnId(null);
|
|
3052
|
+
setDropTarget(null);
|
|
3053
|
+
const backup = previousUserSelectRef.current;
|
|
3054
|
+
previousUserSelectRef.current = null;
|
|
3055
|
+
if (backup) {
|
|
3056
|
+
if (backup.value) {
|
|
3057
|
+
document.body.style.setProperty("user-select", backup.value, backup.priority);
|
|
3058
|
+
} else {
|
|
3059
|
+
document.body.style.removeProperty("user-select");
|
|
3060
|
+
}
|
|
3061
|
+
return;
|
|
3062
|
+
}
|
|
3063
|
+
document.body.style.removeProperty("user-select");
|
|
3064
|
+
}, []);
|
|
3065
|
+
useEffect6(() => {
|
|
3066
|
+
if (!enabled) resetDrag();
|
|
3067
|
+
}, [enabled, resetDrag]);
|
|
3068
|
+
useEffect6(() => {
|
|
3069
|
+
return () => {
|
|
3070
|
+
resetDrag();
|
|
3071
|
+
};
|
|
3072
|
+
}, [resetDrag]);
|
|
3073
|
+
const onHeaderPointerDown = useCallback6(
|
|
3074
|
+
(event, meta) => {
|
|
3075
|
+
if (!enabled || !meta.canDrag) return;
|
|
3076
|
+
if (event.button !== 0) return;
|
|
3077
|
+
if (event.pointerType === "mouse" && event.ctrlKey) return;
|
|
3078
|
+
const target = event.target;
|
|
3079
|
+
if (target instanceof Element && target.closest("[data-table-disable-cell-selection]")) {
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
const table = event.currentTarget.closest("table");
|
|
3083
|
+
if (!(table instanceof HTMLTableElement)) return;
|
|
3084
|
+
sessionRef.current = {
|
|
3085
|
+
pointerId: event.pointerId,
|
|
3086
|
+
startX: event.clientX,
|
|
3087
|
+
startY: event.clientY,
|
|
3088
|
+
columnId: meta.columnId,
|
|
3089
|
+
fromIds: meta.leafIds,
|
|
3090
|
+
table,
|
|
3091
|
+
active: false
|
|
3092
|
+
};
|
|
3093
|
+
},
|
|
3094
|
+
[enabled]
|
|
3095
|
+
);
|
|
3096
|
+
useEffect6(() => {
|
|
3097
|
+
if (!enabled) return;
|
|
3098
|
+
const onPointerMove = (event) => {
|
|
3099
|
+
const session = sessionRef.current;
|
|
3100
|
+
if (!session || event.pointerId !== session.pointerId) return;
|
|
3101
|
+
const deltaX = event.clientX - session.startX;
|
|
3102
|
+
const deltaY = event.clientY - session.startY;
|
|
3103
|
+
const distance = Math.hypot(deltaX, deltaY);
|
|
3104
|
+
if (!session.active) {
|
|
3105
|
+
if (distance < DATA_TABLE_COLUMN_REORDER_THRESHOLD) return;
|
|
3106
|
+
session.active = true;
|
|
3107
|
+
if (!previousUserSelectRef.current) {
|
|
3108
|
+
previousUserSelectRef.current = {
|
|
3109
|
+
value: document.body.style.getPropertyValue("user-select"),
|
|
3110
|
+
priority: document.body.style.getPropertyPriority("user-select")
|
|
3111
|
+
};
|
|
3112
|
+
}
|
|
3113
|
+
document.body.style.setProperty("user-select", "none");
|
|
3114
|
+
setDraggingColumnId(session.columnId);
|
|
3115
|
+
}
|
|
3116
|
+
event.preventDefault();
|
|
3117
|
+
const nextTarget = hitTestReorderHeader(
|
|
3118
|
+
session.table,
|
|
3119
|
+
event.clientX,
|
|
3120
|
+
event.clientY
|
|
3121
|
+
);
|
|
3122
|
+
if (!nextTarget || !nextTarget.columnId) {
|
|
3123
|
+
setDropTarget(null);
|
|
3124
|
+
return;
|
|
3125
|
+
}
|
|
3126
|
+
const targetIds = readTargetIds(session.table, nextTarget.columnId);
|
|
3127
|
+
const fromSet = new Set(session.fromIds);
|
|
3128
|
+
if (targetIds.some((id) => fromSet.has(id))) {
|
|
3129
|
+
setDropTarget(null);
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
setDropTarget((previous) => {
|
|
3133
|
+
if (previous?.columnId === nextTarget.columnId && previous.edge === nextTarget.edge) {
|
|
3134
|
+
return previous;
|
|
3135
|
+
}
|
|
3136
|
+
return nextTarget;
|
|
3137
|
+
});
|
|
3138
|
+
};
|
|
3139
|
+
const onPointerUp = (event) => {
|
|
3140
|
+
const session = sessionRef.current;
|
|
3141
|
+
if (!session || event.pointerId !== session.pointerId) {
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
if (session.active) {
|
|
3145
|
+
event.preventDefault();
|
|
3146
|
+
const target = dropTargetRef.current;
|
|
3147
|
+
if (target) {
|
|
3148
|
+
const targetIds = readTargetIds(session.table, target.columnId);
|
|
3149
|
+
const next = moveColumnIds(
|
|
3150
|
+
columnOrderRef.current,
|
|
3151
|
+
session.fromIds,
|
|
3152
|
+
targetIds,
|
|
3153
|
+
target.edge
|
|
3154
|
+
);
|
|
3155
|
+
onColumnOrderChangeRef.current(next);
|
|
3156
|
+
}
|
|
3157
|
+
const suppressClick = (clickEvent) => {
|
|
3158
|
+
clickEvent.preventDefault();
|
|
3159
|
+
clickEvent.stopPropagation();
|
|
3160
|
+
document.removeEventListener("click", suppressClick, true);
|
|
3161
|
+
};
|
|
3162
|
+
document.addEventListener("click", suppressClick, true);
|
|
3163
|
+
window.setTimeout(() => {
|
|
3164
|
+
document.removeEventListener("click", suppressClick, true);
|
|
3165
|
+
}, 0);
|
|
3166
|
+
}
|
|
3167
|
+
resetDrag();
|
|
3168
|
+
};
|
|
3169
|
+
const onPointerCancel = (event) => {
|
|
3170
|
+
const session = sessionRef.current;
|
|
3171
|
+
if (!session || event.pointerId !== session.pointerId) {
|
|
3172
|
+
return;
|
|
3173
|
+
}
|
|
3174
|
+
if (session.active) {
|
|
3175
|
+
event.preventDefault();
|
|
3176
|
+
}
|
|
3177
|
+
resetDrag();
|
|
3178
|
+
};
|
|
3179
|
+
document.addEventListener("pointermove", onPointerMove);
|
|
3180
|
+
document.addEventListener("pointerup", onPointerUp);
|
|
3181
|
+
document.addEventListener("pointercancel", onPointerCancel);
|
|
3182
|
+
return () => {
|
|
3183
|
+
document.removeEventListener("pointermove", onPointerMove);
|
|
3184
|
+
document.removeEventListener("pointerup", onPointerUp);
|
|
3185
|
+
document.removeEventListener("pointercancel", onPointerCancel);
|
|
3186
|
+
};
|
|
3187
|
+
}, [enabled, resetDrag]);
|
|
3188
|
+
return {
|
|
3189
|
+
isReordering: draggingColumnId != null,
|
|
3190
|
+
draggingColumnId,
|
|
3191
|
+
dropTarget,
|
|
3192
|
+
onHeaderPointerDown
|
|
3193
|
+
};
|
|
3194
|
+
}
|
|
2821
3195
|
export {
|
|
2822
3196
|
BUILTIN_CELL_RENDERERS,
|
|
2823
3197
|
CELL_SELECTION_EDGES_CLASS,
|
|
@@ -2830,6 +3204,7 @@ export {
|
|
|
2830
3204
|
ResolvedTableCell,
|
|
2831
3205
|
applyCellEdit,
|
|
2832
3206
|
applyFillData,
|
|
3207
|
+
applyLeafColumnOrder,
|
|
2833
3208
|
applySelectionUpdater,
|
|
2834
3209
|
buildColumnFreezeOffsets,
|
|
2835
3210
|
buildColumnRowSpanMap,
|
|
@@ -2844,6 +3219,7 @@ export {
|
|
|
2844
3219
|
collectCopyRowEntries,
|
|
2845
3220
|
collectCopyRows,
|
|
2846
3221
|
collectFillChanges,
|
|
3222
|
+
collectLeafColumnIds,
|
|
2847
3223
|
collectRowSpanColumns,
|
|
2848
3224
|
collectSearchMatchesInRange,
|
|
2849
3225
|
commitCellValue,
|
|
@@ -2868,6 +3244,7 @@ export {
|
|
|
2868
3244
|
mapSearchResultToVisibleItem,
|
|
2869
3245
|
mapSearchResultsToVisibleKeys,
|
|
2870
3246
|
measureMergedSpanRowHeights,
|
|
3247
|
+
moveColumnIds,
|
|
2871
3248
|
nextSearchIndex,
|
|
2872
3249
|
nextSearchStride,
|
|
2873
3250
|
parseCellEditValue,
|
|
@@ -2877,7 +3254,9 @@ export {
|
|
|
2877
3254
|
resolveCellRenderer,
|
|
2878
3255
|
resolveColumnFreezeSide,
|
|
2879
3256
|
resolveDataTableLabels,
|
|
3257
|
+
resolveDropEdge,
|
|
2880
3258
|
resolveHeaderFreezeOffset,
|
|
3259
|
+
resolveLeafColumnOrder,
|
|
2881
3260
|
resolvePasteColumnIds,
|
|
2882
3261
|
resolveRowSelection,
|
|
2883
3262
|
resolveRowSpanAt,
|
|
@@ -2887,8 +3266,10 @@ export {
|
|
|
2887
3266
|
toggleExpandedRowId,
|
|
2888
3267
|
useCellEdit,
|
|
2889
3268
|
useCellSelection,
|
|
3269
|
+
useColumnReorder,
|
|
2890
3270
|
useConvertTreeData,
|
|
2891
3271
|
useGlideTable,
|
|
2892
3272
|
useInlineSearch,
|
|
3273
|
+
withCellUpdate,
|
|
2893
3274
|
writeSelectionToClipboard
|
|
2894
3275
|
};
|