react-glide-table 1.1.9 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/compound.cjs CHANGED
@@ -45,6 +45,9 @@ var ROW_HOVERED_BG_CLASS = "row-hovered";
45
45
  var CELL_SELECTION_FILL_CLASS = "cell-selection-fill";
46
46
  var DATA_TABLE_ROW_HEIGHT = 44;
47
47
  var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
48
+ var DATA_TABLE_COLUMN_SIZE = 150;
49
+ var DATA_TABLE_COLUMN_MIN_SIZE = 40;
50
+ var DATA_TABLE_COLUMN_MAX_SIZE = 800;
48
51
 
49
52
  // src/components/ui/table/DataTableContext.tsx
50
53
  var import_react = require("react");
@@ -385,6 +388,102 @@ function hasCellSelectionEdges(style) {
385
388
  );
386
389
  }
387
390
 
391
+ // src/components/ui/table/features/column-freeze/columnFreeze.ts
392
+ var HEADER_Z_BASE = 30;
393
+ var BODY_Z_BASE = 5;
394
+ function resolveColumnFreezeSide(frozen) {
395
+ if (frozen === true || frozen === "left") return "left";
396
+ if (frozen === "right") return "right";
397
+ return void 0;
398
+ }
399
+ function getColumnFreezeEdgeAttr(offset) {
400
+ if (!offset) return void 0;
401
+ if (offset.edgeLeft && offset.edgeRight) return "both";
402
+ if (offset.edgeLeft) return "left";
403
+ if (offset.edgeRight) return "right";
404
+ return void 0;
405
+ }
406
+ function buildColumnFreezeOffsets(columns) {
407
+ const result = /* @__PURE__ */ new Map();
408
+ let leftOffset = 0;
409
+ const leftIds = [];
410
+ for (const column of columns) {
411
+ if (column.side !== "left") continue;
412
+ leftIds.push(column.id);
413
+ result.set(column.id, {
414
+ side: "left",
415
+ offset: leftOffset,
416
+ isEdge: false,
417
+ edgeLeft: false,
418
+ edgeRight: false,
419
+ stack: 0
420
+ });
421
+ leftOffset += column.size;
422
+ }
423
+ leftIds.forEach((id, index) => {
424
+ const entry = result.get(id);
425
+ if (!entry) return;
426
+ entry.stack = leftIds.length - index;
427
+ });
428
+ let rightOffset = 0;
429
+ const rightIds = [];
430
+ for (let index = columns.length - 1; index >= 0; index -= 1) {
431
+ const column = columns[index];
432
+ if (!column || column.side !== "right") continue;
433
+ rightIds.push(column.id);
434
+ result.set(column.id, {
435
+ side: "right",
436
+ offset: rightOffset,
437
+ isEdge: false,
438
+ edgeLeft: false,
439
+ edgeRight: false,
440
+ stack: 0
441
+ });
442
+ rightOffset += column.size;
443
+ }
444
+ rightIds.forEach((id, index) => {
445
+ const entry = result.get(id);
446
+ if (!entry) return;
447
+ entry.stack = rightIds.length - index;
448
+ });
449
+ columns.forEach((column, index) => {
450
+ if (!column.side) return;
451
+ const entry = result.get(column.id);
452
+ if (!entry) return;
453
+ const prevSide = index > 0 ? columns[index - 1]?.side : void 0;
454
+ const nextSide = index < columns.length - 1 ? columns[index + 1]?.side : void 0;
455
+ entry.edgeLeft = prevSide !== column.side;
456
+ entry.edgeRight = nextSide !== column.side;
457
+ if (index === 0) entry.edgeLeft = false;
458
+ if (index === columns.length - 1) entry.edgeRight = false;
459
+ entry.isEdge = entry.edgeLeft || entry.edgeRight;
460
+ });
461
+ return result;
462
+ }
463
+ function getColumnFreezeStyle(offset, options) {
464
+ if (!offset) return void 0;
465
+ const zBase = options?.isHeader ? HEADER_Z_BASE : BODY_Z_BASE;
466
+ return {
467
+ position: "sticky",
468
+ ...offset.side === "left" ? { left: offset.offset } : { right: offset.offset },
469
+ zIndex: zBase + offset.stack,
470
+ ...options?.isHeader ? { top: 0 } : {}
471
+ };
472
+ }
473
+
474
+ // src/components/ui/table/features/column-resize/columnResize.ts
475
+ function getColumnSizeStyle(size, options) {
476
+ const { force = false, lockMax = false } = options ?? {};
477
+ if (!force && size === DATA_TABLE_COLUMN_SIZE) {
478
+ return void 0;
479
+ }
480
+ return {
481
+ width: size,
482
+ minWidth: size,
483
+ ...lockMax ? { maxWidth: size } : {}
484
+ };
485
+ }
486
+
388
487
  // src/components/ui/table/features/row-expand/row-expand.ts
389
488
  var import_react2 = require("react");
390
489
 
@@ -822,7 +921,18 @@ function DataTableRow({
822
921
  virtualIndex,
823
922
  measureElement
824
923
  }) {
825
- const { classNames, rowSpan, selection, cellSelection, cellEdit, expand } = useDataTableRowContext();
924
+ const {
925
+ classNames,
926
+ rowSpan,
927
+ selection,
928
+ cellSelection,
929
+ cellEdit,
930
+ expand,
931
+ columnResize,
932
+ columnFreeze
933
+ } = useDataTableRowContext();
934
+ const { enableColumnResize } = columnResize;
935
+ const { enableColumnFreeze, offsets: freezeOffsets } = columnFreeze;
826
936
  const {
827
937
  enableRowSpan,
828
938
  primaryRowSpanColumnId,
@@ -1003,6 +1113,17 @@ function DataTableRow({
1003
1113
  );
1004
1114
  const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
1005
1115
  const hasSelectionEdges = hasCellSelectionEdges(selectionEdgeStyle);
1116
+ const sizeStyle = getColumnSizeStyle(cell.column.getSize(), {
1117
+ force: enableColumnResize,
1118
+ lockMax: enableColumnResize
1119
+ });
1120
+ const freezeOffset = enableColumnFreeze ? freezeOffsets.get(columnId) : void 0;
1121
+ const freezeStyle = getColumnFreezeStyle(freezeOffset);
1122
+ const cellStyle = {
1123
+ ...sizeStyle,
1124
+ ...freezeStyle,
1125
+ ...selectionEdgeStyle
1126
+ };
1006
1127
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1007
1128
  "td",
1008
1129
  {
@@ -1016,6 +1137,8 @@ function DataTableRow({
1016
1137
  "data-selection-edges": hasSelectionEdges ? "" : void 0,
1017
1138
  "data-editable": editable ? "" : void 0,
1018
1139
  "data-editing": isEditing ? "" : void 0,
1140
+ "data-frozen": freezeOffset?.side,
1141
+ "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
1019
1142
  onMouseDown: (event) => {
1020
1143
  if (isEditing) {
1021
1144
  event.stopPropagation();
@@ -1050,9 +1173,10 @@ function DataTableRow({
1050
1173
  event.stopPropagation();
1051
1174
  onStartEdit(rowIndex, cellIndex);
1052
1175
  },
1053
- style: selectionEdgeStyle,
1176
+ style: Object.keys(cellStyle).length > 0 ? cellStyle : void 0,
1054
1177
  className: cn(
1055
1178
  "data-table-cell",
1179
+ freezeOffset && `data-table-cell--frozen-${freezeOffset.side}`,
1056
1180
  CELL_ALIGN_CLASS[align],
1057
1181
  cellClassName,
1058
1182
  isMerged && "is-merged",
@@ -1803,7 +1927,8 @@ var DEFAULT_DATA_TABLE_LABELS = {
1803
1927
  loading: "Loading...",
1804
1928
  selection: (selectedCount) => selectedCount > 0 ? `\u2713 ${selectedCount} selected` : null,
1805
1929
  expandRow: "Expand row",
1806
- collapseRow: "Collapse row"
1930
+ collapseRow: "Collapse row",
1931
+ resizeColumn: "Resize column"
1807
1932
  };
1808
1933
  function resolveDataTableLabels(partial) {
1809
1934
  return {
@@ -1813,6 +1938,7 @@ function resolveDataTableLabels(partial) {
1813
1938
  }
1814
1939
 
1815
1940
  // src/core/useGlideTable.ts
1941
+ var EMPTY_COLUMN_FREEZE_OFFSETS = /* @__PURE__ */ new Map();
1816
1942
  function useGlideTable(options) {
1817
1943
  const {
1818
1944
  data,
@@ -1848,7 +1974,12 @@ function useGlideTable(options) {
1848
1974
  enableInsertPaste,
1849
1975
  enableVirtualization = true,
1850
1976
  estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
1851
- virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
1977
+ virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN,
1978
+ enableColumnResize = false,
1979
+ columnSizing: controlledColumnSizing,
1980
+ onColumnSizingChange,
1981
+ columnResizeMode = "onChange",
1982
+ enableColumnFreeze = false
1852
1983
  } = options;
1853
1984
  const labels = (0, import_react6.useMemo)(() => {
1854
1985
  const resolved = resolveDataTableLabels(labelsProp);
@@ -1862,6 +1993,7 @@ function useGlideTable(options) {
1862
1993
  const enableExpand = Boolean(toggleField);
1863
1994
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
1864
1995
  const [internalRowSelection, setInternalRowSelection] = (0, import_react6.useState)({});
1996
+ const [internalColumnSizing, setInternalColumnSizing] = (0, import_react6.useState)({});
1865
1997
  const [internalExpandedRows, setInternalExpandedRows] = (0, import_react6.useState)(
1866
1998
  () => /* @__PURE__ */ new Set()
1867
1999
  );
@@ -1880,6 +2012,7 @@ function useGlideTable(options) {
1880
2012
  controlledRowSelection,
1881
2013
  internalRowSelection
1882
2014
  );
2015
+ const columnSizing = controlledColumnSizing ?? internalColumnSizing;
1883
2016
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
1884
2017
  const handleExpandedRowsChange = (0, import_react6.useCallback)(
1885
2018
  (next) => {
@@ -1905,9 +2038,27 @@ function useGlideTable(options) {
1905
2038
  const table = (0, import_react_table2.useReactTable)({
1906
2039
  data: tableData,
1907
2040
  columns,
2041
+ ...enableColumnResize ? {
2042
+ defaultColumn: {
2043
+ minSize: DATA_TABLE_COLUMN_MIN_SIZE,
2044
+ maxSize: DATA_TABLE_COLUMN_MAX_SIZE
2045
+ }
2046
+ } : {},
2047
+ enableColumnResizing: enableColumnResize,
2048
+ columnResizeMode,
1908
2049
  state: {
1909
- rowSelection: rowSelectionMode === "none" ? {} : rowSelection
2050
+ rowSelection: rowSelectionMode === "none" ? {} : rowSelection,
2051
+ ...enableColumnResize ? { columnSizing } : {}
1910
2052
  },
2053
+ onColumnSizingChange: enableColumnResize ? (updater) => {
2054
+ if (onColumnSizingChange) {
2055
+ onColumnSizingChange(updater);
2056
+ return;
2057
+ }
2058
+ setInternalColumnSizing(
2059
+ (previous) => typeof updater === "function" ? updater(previous) : updater
2060
+ );
2061
+ } : void 0,
1911
2062
  enableRowSelection: rowSelectionMode === "none" ? false : getRowCanSelect ? (row) => getRowCanSelect(row.original, row.index) : true,
1912
2063
  enableMultiRowSelection: rowSelectionMode === "multi",
1913
2064
  onRowSelectionChange: (updater) => {
@@ -1938,6 +2089,17 @@ function useGlideTable(options) {
1938
2089
  const selectedCount = selectedRows.length;
1939
2090
  const rows = table.getRowModel().rows;
1940
2091
  const columnCount = table.getAllLeafColumns().length || 1;
2092
+ const visibleLeafColumns = table.getVisibleLeafColumns();
2093
+ const columnFreezeOffsets = (0, import_react6.useMemo)(() => {
2094
+ if (!enableColumnFreeze) return EMPTY_COLUMN_FREEZE_OFFSETS;
2095
+ return buildColumnFreezeOffsets(
2096
+ visibleLeafColumns.map((column) => ({
2097
+ id: column.id,
2098
+ size: column.getSize(),
2099
+ side: resolveColumnFreezeSide(column.columnDef.meta?.frozen)
2100
+ }))
2101
+ );
2102
+ }, [enableColumnFreeze, visibleLeafColumns, columnSizing]);
1941
2103
  const rowVirtualizer = (0, import_react_virtual.useVirtualizer)({
1942
2104
  count: shouldVirtualize ? rows.length : 0,
1943
2105
  getScrollElement: () => scrollRef.current,
@@ -2054,6 +2216,13 @@ function useGlideTable(options) {
2054
2216
  onToggleExpand: handleToggleExpand,
2055
2217
  expandRowLabel: labels.expandRow,
2056
2218
  collapseRowLabel: labels.collapseRow
2219
+ },
2220
+ columnResize: {
2221
+ enableColumnResize
2222
+ },
2223
+ columnFreeze: {
2224
+ enableColumnFreeze,
2225
+ offsets: columnFreezeOffsets
2057
2226
  }
2058
2227
  };
2059
2228
  }, [
@@ -2086,7 +2255,10 @@ function useGlideTable(options) {
2086
2255
  preventExpand,
2087
2256
  handleToggleExpand,
2088
2257
  labels.expandRow,
2089
- labels.collapseRow
2258
+ labels.collapseRow,
2259
+ enableColumnResize,
2260
+ enableColumnFreeze,
2261
+ columnFreezeOffsets
2090
2262
  ]);
2091
2263
  const copySelectionRef = (0, import_react6.useRef)(copySelection);
2092
2264
  (0, import_react6.useEffect)(() => {
@@ -2107,6 +2279,8 @@ function useGlideTable(options) {
2107
2279
  loadingText: labels.loading,
2108
2280
  selectionLabel: labels.selection,
2109
2281
  enableCellSelection,
2282
+ enableColumnResize,
2283
+ enableColumnFreeze,
2110
2284
  shouldVirtualize,
2111
2285
  scrollRef,
2112
2286
  rowVirtualizer,
@@ -2172,10 +2346,13 @@ function DataTable({
2172
2346
  rows,
2173
2347
  columnCount,
2174
2348
  selectedCount,
2349
+ labels,
2175
2350
  emptyText,
2176
2351
  loadingText,
2177
2352
  selectionLabel,
2178
2353
  enableCellSelection,
2354
+ enableColumnResize,
2355
+ enableColumnFreeze,
2179
2356
  shouldVirtualize,
2180
2357
  scrollRef,
2181
2358
  rowVirtualizer,
@@ -2190,6 +2367,7 @@ function DataTable({
2190
2367
  const RowSlot = slots?.Row ?? DataTableRow;
2191
2368
  const PendingSlot = slots?.Pending ?? DefaultPending;
2192
2369
  const EmptySlot = slots?.Empty ?? DefaultEmpty;
2370
+ const freezeOffsets = rowContextValue.columnFreeze.offsets;
2193
2371
  const contextValue = (0, import_react7.useMemo)(
2194
2372
  () => ({ ...rowContextValue, classNames }),
2195
2373
  [rowContextValue, classNames]
@@ -2210,6 +2388,8 @@ function DataTable({
2210
2388
  className: cn(
2211
2389
  "DataTableJSX",
2212
2390
  !enableCellSelection && "DataTableJSX--no-cell-selection",
2391
+ enableColumnResize && "DataTableJSX--column-resize",
2392
+ enableColumnFreeze && "DataTableJSX--column-freeze",
2213
2393
  classNames?.root,
2214
2394
  className
2215
2395
  ),
@@ -2230,6 +2410,7 @@ function DataTable({
2230
2410
  "table",
2231
2411
  {
2232
2412
  className: cn("data-table", classNames?.table),
2413
+ style: enableColumnResize ? { width: table.getTotalSize() } : void 0,
2233
2414
  onDragStart: enableCellSelection ? (event) => event.preventDefault() : void 0,
2234
2415
  children: [
2235
2416
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: cn("data-table-head", classNames?.head), children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -2239,22 +2420,54 @@ function DataTable({
2239
2420
  children: headerGroup.headers.map((header) => {
2240
2421
  const align = header.column.columnDef.meta?.align ?? "center";
2241
2422
  const headerClassName = header.column.columnDef.meta?.headerClassName;
2242
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2423
+ const canResize = enableColumnResize && header.column.getCanResize();
2424
+ const sizeStyle = getColumnSizeStyle(header.getSize(), {
2425
+ force: enableColumnResize,
2426
+ lockMax: enableColumnResize
2427
+ });
2428
+ const freezeOffset = enableColumnFreeze ? freezeOffsets.get(header.column.id) : void 0;
2429
+ const freezeStyle = getColumnFreezeStyle(freezeOffset, {
2430
+ isHeader: true
2431
+ });
2432
+ const headerStyle = {
2433
+ ...sizeStyle,
2434
+ ...freezeStyle
2435
+ };
2436
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2243
2437
  "th",
2244
2438
  {
2245
- style: {
2246
- width: header.getSize() !== 150 ? header.getSize() : void 0,
2247
- // Column sizing follows TanStack's `size`, but
2248
- // ensure the column keeps its min width when the container shrinks.
2249
- minWidth: header.getSize() !== 150 ? header.getSize() : void 0
2250
- },
2439
+ "data-resizing": header.column.getIsResizing() ? "" : void 0,
2440
+ "data-frozen": freezeOffset?.side,
2441
+ "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
2442
+ style: Object.keys(headerStyle).length > 0 ? headerStyle : void 0,
2251
2443
  className: cn(
2252
2444
  "data-table-head-cell",
2445
+ freezeOffset && `data-table-head-cell--frozen-${freezeOffset.side}`,
2253
2446
  CELL_ALIGN_CLASS[align],
2254
2447
  classNames?.headCell,
2255
2448
  headerClassName
2256
2449
  ),
2257
- children: header.isPlaceholder ? null : (0, import_react_table3.flexRender)(header.column.columnDef.header, header.getContext())
2450
+ children: [
2451
+ header.isPlaceholder ? null : (0, import_react_table3.flexRender)(header.column.columnDef.header, header.getContext()),
2452
+ canResize ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2453
+ "div",
2454
+ {
2455
+ role: "separator",
2456
+ "aria-orientation": "vertical",
2457
+ "aria-label": labels.resizeColumn,
2458
+ "data-table-disable-cell-selection": "",
2459
+ className: cn(
2460
+ "data-table-resize-handle",
2461
+ classNames?.resizeHandle
2462
+ ),
2463
+ onMouseDown: header.getResizeHandler(),
2464
+ onTouchStart: header.getResizeHandler(),
2465
+ onDoubleClick: () => {
2466
+ header.column.resetSize();
2467
+ }
2468
+ }
2469
+ ) : null
2470
+ ]
2258
2471
  },
2259
2472
  header.id
2260
2473
  );
@@ -2382,6 +2595,10 @@ function buildColumnDef(props, sort, onSort) {
2382
2595
  children,
2383
2596
  sortable = false,
2384
2597
  width,
2598
+ minWidth,
2599
+ maxWidth,
2600
+ resizable,
2601
+ frozen,
2385
2602
  align,
2386
2603
  rowSpan,
2387
2604
  rowSpanKey,
@@ -2395,7 +2612,10 @@ function buildColumnDef(props, sort, onSort) {
2395
2612
  return {
2396
2613
  id: field,
2397
2614
  ...!virtual ? { accessorKey: field } : {},
2398
- size: width ?? 150,
2615
+ size: width ?? DATA_TABLE_COLUMN_SIZE,
2616
+ ...minWidth != null ? { minSize: minWidth } : {},
2617
+ ...maxWidth != null ? { maxSize: maxWidth } : {},
2618
+ ...resizable === false ? { enableResizing: false } : {},
2399
2619
  header: sortable ? () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SortableHeader, { label: children, field, sort, onSort }) : (
2400
2620
  // eslint-disable-next-line @typescript-eslint/promise-function-async
2401
2621
  () => children
@@ -2415,6 +2635,7 @@ function buildColumnDef(props, sort, onSort) {
2415
2635
  editable,
2416
2636
  editType,
2417
2637
  editInputProps,
2638
+ frozen,
2418
2639
  className,
2419
2640
  headerClassName
2420
2641
  }
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ReactElement } from 'react';
3
- import { d as DataTableProps, T as TableColumnProps, g as TableProps } from './types-xxzMLUwM.cjs';
4
- export { a as DataTableClassNames, c as DataTableLabels, e as DataTableSlots, P as PasteMode, R as RowSelectionMode, f as RowsPastePayload } from './types-xxzMLUwM.cjs';
5
- export { ColumnDef, RowSelectionState } from '@tanstack/react-table';
3
+ import { h as DataTableProps, T as TableColumnProps, k as TableProps } from './types-B4uHdkrY.cjs';
4
+ export { b as ColumnFreezeMeta, d as ColumnFreezeSide, e as DataTableClassNames, g as DataTableLabels, i as DataTableSlots, P as PasteMode, R as RowSelectionMode, j as RowsPastePayload } from './types-B4uHdkrY.cjs';
5
+ export { ColumnDef, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
6
6
 
7
7
  /**
8
8
  * Unstyled DataTable shell: semantic HTML + interaction behavior.
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ReactElement } from 'react';
3
- import { d as DataTableProps, T as TableColumnProps, g as TableProps } from './types-xxzMLUwM.js';
4
- export { a as DataTableClassNames, c as DataTableLabels, e as DataTableSlots, P as PasteMode, R as RowSelectionMode, f as RowsPastePayload } from './types-xxzMLUwM.js';
5
- export { ColumnDef, RowSelectionState } from '@tanstack/react-table';
3
+ import { h as DataTableProps, T as TableColumnProps, k as TableProps } from './types-B4uHdkrY.js';
4
+ export { b as ColumnFreezeMeta, d as ColumnFreezeSide, e as DataTableClassNames, g as DataTableLabels, i as DataTableSlots, P as PasteMode, R as RowSelectionMode, j as RowsPastePayload } from './types-B4uHdkrY.js';
5
+ export { ColumnDef, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
6
6
 
7
7
  /**
8
8
  * Unstyled DataTable shell: semantic HTML + interaction behavior.