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/index.js CHANGED
@@ -4,7 +4,8 @@ var DEFAULT_DATA_TABLE_LABELS = {
4
4
  loading: "Loading...",
5
5
  selection: (selectedCount) => selectedCount > 0 ? `\u2713 ${selectedCount} selected` : null,
6
6
  expandRow: "Expand row",
7
- collapseRow: "Collapse row"
7
+ collapseRow: "Collapse row",
8
+ resizeColumn: "Resize column"
8
9
  };
9
10
  function resolveDataTableLabels(partial) {
10
11
  return {
@@ -46,6 +47,9 @@ var ROW_HOVERED_BG_CLASS = "row-hovered";
46
47
  var CELL_SELECTION_FILL_CLASS = "cell-selection-fill";
47
48
  var DATA_TABLE_ROW_HEIGHT = 44;
48
49
  var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
50
+ var DATA_TABLE_COLUMN_SIZE = 150;
51
+ var DATA_TABLE_COLUMN_MIN_SIZE = 40;
52
+ var DATA_TABLE_COLUMN_MAX_SIZE = 800;
49
53
 
50
54
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
51
55
  import { useCallback, useEffect, useRef, useState } from "react";
@@ -936,6 +940,89 @@ function useCellSelection({
936
940
  };
937
941
  }
938
942
 
943
+ // src/components/ui/table/features/column-freeze/columnFreeze.ts
944
+ var HEADER_Z_BASE = 30;
945
+ var BODY_Z_BASE = 5;
946
+ function resolveColumnFreezeSide(frozen) {
947
+ if (frozen === true || frozen === "left") return "left";
948
+ if (frozen === "right") return "right";
949
+ return void 0;
950
+ }
951
+ function getColumnFreezeEdgeAttr(offset) {
952
+ if (!offset) return void 0;
953
+ if (offset.edgeLeft && offset.edgeRight) return "both";
954
+ if (offset.edgeLeft) return "left";
955
+ if (offset.edgeRight) return "right";
956
+ return void 0;
957
+ }
958
+ function buildColumnFreezeOffsets(columns) {
959
+ const result = /* @__PURE__ */ new Map();
960
+ let leftOffset = 0;
961
+ const leftIds = [];
962
+ for (const column of columns) {
963
+ if (column.side !== "left") continue;
964
+ leftIds.push(column.id);
965
+ result.set(column.id, {
966
+ side: "left",
967
+ offset: leftOffset,
968
+ isEdge: false,
969
+ edgeLeft: false,
970
+ edgeRight: false,
971
+ stack: 0
972
+ });
973
+ leftOffset += column.size;
974
+ }
975
+ leftIds.forEach((id, index) => {
976
+ const entry = result.get(id);
977
+ if (!entry) return;
978
+ entry.stack = leftIds.length - index;
979
+ });
980
+ let rightOffset = 0;
981
+ const rightIds = [];
982
+ for (let index = columns.length - 1; index >= 0; index -= 1) {
983
+ const column = columns[index];
984
+ if (!column || column.side !== "right") continue;
985
+ rightIds.push(column.id);
986
+ result.set(column.id, {
987
+ side: "right",
988
+ offset: rightOffset,
989
+ isEdge: false,
990
+ edgeLeft: false,
991
+ edgeRight: false,
992
+ stack: 0
993
+ });
994
+ rightOffset += column.size;
995
+ }
996
+ rightIds.forEach((id, index) => {
997
+ const entry = result.get(id);
998
+ if (!entry) return;
999
+ entry.stack = rightIds.length - index;
1000
+ });
1001
+ columns.forEach((column, index) => {
1002
+ if (!column.side) return;
1003
+ const entry = result.get(column.id);
1004
+ if (!entry) return;
1005
+ const prevSide = index > 0 ? columns[index - 1]?.side : void 0;
1006
+ const nextSide = index < columns.length - 1 ? columns[index + 1]?.side : void 0;
1007
+ entry.edgeLeft = prevSide !== column.side;
1008
+ entry.edgeRight = nextSide !== column.side;
1009
+ if (index === 0) entry.edgeLeft = false;
1010
+ if (index === columns.length - 1) entry.edgeRight = false;
1011
+ entry.isEdge = entry.edgeLeft || entry.edgeRight;
1012
+ });
1013
+ return result;
1014
+ }
1015
+ function getColumnFreezeStyle(offset, options) {
1016
+ if (!offset) return void 0;
1017
+ const zBase = options?.isHeader ? HEADER_Z_BASE : BODY_Z_BASE;
1018
+ return {
1019
+ position: "sticky",
1020
+ ...offset.side === "left" ? { left: offset.offset } : { right: offset.offset },
1021
+ zIndex: zBase + offset.stack,
1022
+ ...options?.isHeader ? { top: 0 } : {}
1023
+ };
1024
+ }
1025
+
939
1026
  // src/components/ui/table/features/row-expand/row-expand.ts
940
1027
  import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "react";
941
1028
  function getFieldValue(row, key) {
@@ -1201,6 +1288,7 @@ function collectRowSpanColumns(columns) {
1201
1288
  }
1202
1289
 
1203
1290
  // src/core/useGlideTable.ts
1291
+ var EMPTY_COLUMN_FREEZE_OFFSETS = /* @__PURE__ */ new Map();
1204
1292
  function useGlideTable(options) {
1205
1293
  const {
1206
1294
  data,
@@ -1236,7 +1324,12 @@ function useGlideTable(options) {
1236
1324
  enableInsertPaste,
1237
1325
  enableVirtualization = true,
1238
1326
  estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
1239
- virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
1327
+ virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN,
1328
+ enableColumnResize = false,
1329
+ columnSizing: controlledColumnSizing,
1330
+ onColumnSizingChange,
1331
+ columnResizeMode = "onChange",
1332
+ enableColumnFreeze = false
1240
1333
  } = options;
1241
1334
  const labels = useMemo2(() => {
1242
1335
  const resolved = resolveDataTableLabels(labelsProp);
@@ -1250,6 +1343,7 @@ function useGlideTable(options) {
1250
1343
  const enableExpand = Boolean(toggleField);
1251
1344
  const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
1252
1345
  const [internalRowSelection, setInternalRowSelection] = useState3({});
1346
+ const [internalColumnSizing, setInternalColumnSizing] = useState3({});
1253
1347
  const [internalExpandedRows, setInternalExpandedRows] = useState3(
1254
1348
  () => /* @__PURE__ */ new Set()
1255
1349
  );
@@ -1268,6 +1362,7 @@ function useGlideTable(options) {
1268
1362
  controlledRowSelection,
1269
1363
  internalRowSelection
1270
1364
  );
1365
+ const columnSizing = controlledColumnSizing ?? internalColumnSizing;
1271
1366
  const expandedRows = controlledExpandedRows ?? internalExpandedRows;
1272
1367
  const handleExpandedRowsChange = useCallback3(
1273
1368
  (next) => {
@@ -1293,9 +1388,27 @@ function useGlideTable(options) {
1293
1388
  const table = useReactTable({
1294
1389
  data: tableData,
1295
1390
  columns,
1391
+ ...enableColumnResize ? {
1392
+ defaultColumn: {
1393
+ minSize: DATA_TABLE_COLUMN_MIN_SIZE,
1394
+ maxSize: DATA_TABLE_COLUMN_MAX_SIZE
1395
+ }
1396
+ } : {},
1397
+ enableColumnResizing: enableColumnResize,
1398
+ columnResizeMode,
1296
1399
  state: {
1297
- rowSelection: rowSelectionMode === "none" ? {} : rowSelection
1400
+ rowSelection: rowSelectionMode === "none" ? {} : rowSelection,
1401
+ ...enableColumnResize ? { columnSizing } : {}
1298
1402
  },
1403
+ onColumnSizingChange: enableColumnResize ? (updater) => {
1404
+ if (onColumnSizingChange) {
1405
+ onColumnSizingChange(updater);
1406
+ return;
1407
+ }
1408
+ setInternalColumnSizing(
1409
+ (previous) => typeof updater === "function" ? updater(previous) : updater
1410
+ );
1411
+ } : void 0,
1299
1412
  enableRowSelection: rowSelectionMode === "none" ? false : getRowCanSelect ? (row) => getRowCanSelect(row.original, row.index) : true,
1300
1413
  enableMultiRowSelection: rowSelectionMode === "multi",
1301
1414
  onRowSelectionChange: (updater) => {
@@ -1326,6 +1439,17 @@ function useGlideTable(options) {
1326
1439
  const selectedCount = selectedRows.length;
1327
1440
  const rows = table.getRowModel().rows;
1328
1441
  const columnCount = table.getAllLeafColumns().length || 1;
1442
+ const visibleLeafColumns = table.getVisibleLeafColumns();
1443
+ const columnFreezeOffsets = useMemo2(() => {
1444
+ if (!enableColumnFreeze) return EMPTY_COLUMN_FREEZE_OFFSETS;
1445
+ return buildColumnFreezeOffsets(
1446
+ visibleLeafColumns.map((column) => ({
1447
+ id: column.id,
1448
+ size: column.getSize(),
1449
+ side: resolveColumnFreezeSide(column.columnDef.meta?.frozen)
1450
+ }))
1451
+ );
1452
+ }, [enableColumnFreeze, visibleLeafColumns, columnSizing]);
1329
1453
  const rowVirtualizer = useVirtualizer({
1330
1454
  count: shouldVirtualize ? rows.length : 0,
1331
1455
  getScrollElement: () => scrollRef.current,
@@ -1442,6 +1566,13 @@ function useGlideTable(options) {
1442
1566
  onToggleExpand: handleToggleExpand,
1443
1567
  expandRowLabel: labels.expandRow,
1444
1568
  collapseRowLabel: labels.collapseRow
1569
+ },
1570
+ columnResize: {
1571
+ enableColumnResize
1572
+ },
1573
+ columnFreeze: {
1574
+ enableColumnFreeze,
1575
+ offsets: columnFreezeOffsets
1445
1576
  }
1446
1577
  };
1447
1578
  }, [
@@ -1474,7 +1605,10 @@ function useGlideTable(options) {
1474
1605
  preventExpand,
1475
1606
  handleToggleExpand,
1476
1607
  labels.expandRow,
1477
- labels.collapseRow
1608
+ labels.collapseRow,
1609
+ enableColumnResize,
1610
+ enableColumnFreeze,
1611
+ columnFreezeOffsets
1478
1612
  ]);
1479
1613
  const copySelectionRef = useRef4(copySelection);
1480
1614
  useEffect4(() => {
@@ -1495,6 +1629,8 @@ function useGlideTable(options) {
1495
1629
  loadingText: labels.loading,
1496
1630
  selectionLabel: labels.selection,
1497
1631
  enableCellSelection,
1632
+ enableColumnResize,
1633
+ enableColumnFreeze,
1498
1634
  shouldVirtualize,
1499
1635
  scrollRef,
1500
1636
  rowVirtualizer,
@@ -1508,6 +1644,19 @@ function useGlideTable(options) {
1508
1644
  };
1509
1645
  }
1510
1646
 
1647
+ // src/components/ui/table/features/column-resize/columnResize.ts
1648
+ function getColumnSizeStyle(size, options) {
1649
+ const { force = false, lockMax = false } = options ?? {};
1650
+ if (!force && size === DATA_TABLE_COLUMN_SIZE) {
1651
+ return void 0;
1652
+ }
1653
+ return {
1654
+ width: size,
1655
+ minWidth: size,
1656
+ ...lockMax ? { maxWidth: size } : {}
1657
+ };
1658
+ }
1659
+
1511
1660
  // src/components/ui/table/components/DataTable/DataTable.tsx
1512
1661
  import { flexRender as flexRender2 } from "@tanstack/react-table";
1513
1662
  import { useMemo as useMemo3 } from "react";
@@ -1714,7 +1863,18 @@ function DataTableRow({
1714
1863
  virtualIndex,
1715
1864
  measureElement
1716
1865
  }) {
1717
- const { classNames, rowSpan, selection, cellSelection, cellEdit, expand } = useDataTableRowContext();
1866
+ const {
1867
+ classNames,
1868
+ rowSpan,
1869
+ selection,
1870
+ cellSelection,
1871
+ cellEdit,
1872
+ expand,
1873
+ columnResize,
1874
+ columnFreeze
1875
+ } = useDataTableRowContext();
1876
+ const { enableColumnResize } = columnResize;
1877
+ const { enableColumnFreeze, offsets: freezeOffsets } = columnFreeze;
1718
1878
  const {
1719
1879
  enableRowSpan,
1720
1880
  primaryRowSpanColumnId,
@@ -1895,6 +2055,17 @@ function DataTableRow({
1895
2055
  );
1896
2056
  const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
1897
2057
  const hasSelectionEdges = hasCellSelectionEdges(selectionEdgeStyle);
2058
+ const sizeStyle = getColumnSizeStyle(cell.column.getSize(), {
2059
+ force: enableColumnResize,
2060
+ lockMax: enableColumnResize
2061
+ });
2062
+ const freezeOffset = enableColumnFreeze ? freezeOffsets.get(columnId) : void 0;
2063
+ const freezeStyle = getColumnFreezeStyle(freezeOffset);
2064
+ const cellStyle = {
2065
+ ...sizeStyle,
2066
+ ...freezeStyle,
2067
+ ...selectionEdgeStyle
2068
+ };
1898
2069
  return /* @__PURE__ */ jsxs2(
1899
2070
  "td",
1900
2071
  {
@@ -1908,6 +2079,8 @@ function DataTableRow({
1908
2079
  "data-selection-edges": hasSelectionEdges ? "" : void 0,
1909
2080
  "data-editable": editable ? "" : void 0,
1910
2081
  "data-editing": isEditing ? "" : void 0,
2082
+ "data-frozen": freezeOffset?.side,
2083
+ "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
1911
2084
  onMouseDown: (event) => {
1912
2085
  if (isEditing) {
1913
2086
  event.stopPropagation();
@@ -1942,9 +2115,10 @@ function DataTableRow({
1942
2115
  event.stopPropagation();
1943
2116
  onStartEdit(rowIndex, cellIndex);
1944
2117
  },
1945
- style: selectionEdgeStyle,
2118
+ style: Object.keys(cellStyle).length > 0 ? cellStyle : void 0,
1946
2119
  className: cn(
1947
2120
  "data-table-cell",
2121
+ freezeOffset && `data-table-cell--frozen-${freezeOffset.side}`,
1948
2122
  CELL_ALIGN_CLASS[align],
1949
2123
  cellClassName,
1950
2124
  isMerged && "is-merged",
@@ -2177,10 +2351,13 @@ function DataTable({
2177
2351
  rows,
2178
2352
  columnCount,
2179
2353
  selectedCount,
2354
+ labels,
2180
2355
  emptyText,
2181
2356
  loadingText,
2182
2357
  selectionLabel,
2183
2358
  enableCellSelection,
2359
+ enableColumnResize,
2360
+ enableColumnFreeze,
2184
2361
  shouldVirtualize,
2185
2362
  scrollRef,
2186
2363
  rowVirtualizer,
@@ -2195,6 +2372,7 @@ function DataTable({
2195
2372
  const RowSlot = slots?.Row ?? DataTableRow;
2196
2373
  const PendingSlot = slots?.Pending ?? DefaultPending;
2197
2374
  const EmptySlot = slots?.Empty ?? DefaultEmpty;
2375
+ const freezeOffsets = rowContextValue.columnFreeze.offsets;
2198
2376
  const contextValue = useMemo3(
2199
2377
  () => ({ ...rowContextValue, classNames }),
2200
2378
  [rowContextValue, classNames]
@@ -2215,6 +2393,8 @@ function DataTable({
2215
2393
  className: cn(
2216
2394
  "DataTableJSX",
2217
2395
  !enableCellSelection && "DataTableJSX--no-cell-selection",
2396
+ enableColumnResize && "DataTableJSX--column-resize",
2397
+ enableColumnFreeze && "DataTableJSX--column-freeze",
2218
2398
  classNames?.root,
2219
2399
  className
2220
2400
  ),
@@ -2235,6 +2415,7 @@ function DataTable({
2235
2415
  "table",
2236
2416
  {
2237
2417
  className: cn("data-table", classNames?.table),
2418
+ style: enableColumnResize ? { width: table.getTotalSize() } : void 0,
2238
2419
  onDragStart: enableCellSelection ? (event) => event.preventDefault() : void 0,
2239
2420
  children: [
2240
2421
  /* @__PURE__ */ jsx5("thead", { className: cn("data-table-head", classNames?.head), children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx5(
@@ -2244,22 +2425,54 @@ function DataTable({
2244
2425
  children: headerGroup.headers.map((header) => {
2245
2426
  const align = header.column.columnDef.meta?.align ?? "center";
2246
2427
  const headerClassName = header.column.columnDef.meta?.headerClassName;
2247
- return /* @__PURE__ */ jsx5(
2428
+ const canResize = enableColumnResize && header.column.getCanResize();
2429
+ const sizeStyle = getColumnSizeStyle(header.getSize(), {
2430
+ force: enableColumnResize,
2431
+ lockMax: enableColumnResize
2432
+ });
2433
+ const freezeOffset = enableColumnFreeze ? freezeOffsets.get(header.column.id) : void 0;
2434
+ const freezeStyle = getColumnFreezeStyle(freezeOffset, {
2435
+ isHeader: true
2436
+ });
2437
+ const headerStyle = {
2438
+ ...sizeStyle,
2439
+ ...freezeStyle
2440
+ };
2441
+ return /* @__PURE__ */ jsxs4(
2248
2442
  "th",
2249
2443
  {
2250
- style: {
2251
- width: header.getSize() !== 150 ? header.getSize() : void 0,
2252
- // Column sizing follows TanStack's `size`, but
2253
- // ensure the column keeps its min width when the container shrinks.
2254
- minWidth: header.getSize() !== 150 ? header.getSize() : void 0
2255
- },
2444
+ "data-resizing": header.column.getIsResizing() ? "" : void 0,
2445
+ "data-frozen": freezeOffset?.side,
2446
+ "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
2447
+ style: Object.keys(headerStyle).length > 0 ? headerStyle : void 0,
2256
2448
  className: cn(
2257
2449
  "data-table-head-cell",
2450
+ freezeOffset && `data-table-head-cell--frozen-${freezeOffset.side}`,
2258
2451
  CELL_ALIGN_CLASS[align],
2259
2452
  classNames?.headCell,
2260
2453
  headerClassName
2261
2454
  ),
2262
- children: header.isPlaceholder ? null : flexRender2(header.column.columnDef.header, header.getContext())
2455
+ children: [
2456
+ header.isPlaceholder ? null : flexRender2(header.column.columnDef.header, header.getContext()),
2457
+ canResize ? /* @__PURE__ */ jsx5(
2458
+ "div",
2459
+ {
2460
+ role: "separator",
2461
+ "aria-orientation": "vertical",
2462
+ "aria-label": labels.resizeColumn,
2463
+ "data-table-disable-cell-selection": "",
2464
+ className: cn(
2465
+ "data-table-resize-handle",
2466
+ classNames?.resizeHandle
2467
+ ),
2468
+ onMouseDown: header.getResizeHandler(),
2469
+ onTouchStart: header.getResizeHandler(),
2470
+ onDoubleClick: () => {
2471
+ header.column.resetSize();
2472
+ }
2473
+ }
2474
+ ) : null
2475
+ ]
2263
2476
  },
2264
2477
  header.id
2265
2478
  );
@@ -2387,6 +2600,10 @@ function buildColumnDef(props, sort, onSort) {
2387
2600
  children,
2388
2601
  sortable = false,
2389
2602
  width,
2603
+ minWidth,
2604
+ maxWidth,
2605
+ resizable,
2606
+ frozen,
2390
2607
  align,
2391
2608
  rowSpan,
2392
2609
  rowSpanKey,
@@ -2400,7 +2617,10 @@ function buildColumnDef(props, sort, onSort) {
2400
2617
  return {
2401
2618
  id: field,
2402
2619
  ...!virtual ? { accessorKey: field } : {},
2403
- size: width ?? 150,
2620
+ size: width ?? DATA_TABLE_COLUMN_SIZE,
2621
+ ...minWidth != null ? { minSize: minWidth } : {},
2622
+ ...maxWidth != null ? { maxSize: maxWidth } : {},
2623
+ ...resizable === false ? { enableResizing: false } : {},
2404
2624
  header: sortable ? () => /* @__PURE__ */ jsx6(SortableHeader, { label: children, field, sort, onSort }) : (
2405
2625
  // eslint-disable-next-line @typescript-eslint/promise-function-async
2406
2626
  () => children
@@ -2420,6 +2640,7 @@ function buildColumnDef(props, sort, onSort) {
2420
2640
  editable,
2421
2641
  editType,
2422
2642
  editInputProps,
2643
+ frozen,
2423
2644
  className,
2424
2645
  headerClassName
2425
2646
  }
@@ -2695,6 +2916,7 @@ export {
2695
2916
  applyCellEdit,
2696
2917
  applyFillData,
2697
2918
  applySelectionUpdater,
2919
+ buildColumnFreezeOffsets,
2698
2920
  buildColumnRowSpanMap,
2699
2921
  buildRowsPastePayload,
2700
2922
  canExpandRow,
@@ -2707,6 +2929,9 @@ export {
2707
2929
  getCellEditDraftValue,
2708
2930
  getCellSelectionEdgeStyle,
2709
2931
  getColumnEditType,
2932
+ getColumnFreezeEdgeAttr,
2933
+ getColumnFreezeStyle,
2934
+ getColumnSizeStyle,
2710
2935
  getRowIndexInMergedCell,
2711
2936
  hasCellSelectionEdges,
2712
2937
  isCellInSelection,
@@ -2716,6 +2941,7 @@ export {
2716
2941
  parseCellEditValue,
2717
2942
  parseClipboardTSV,
2718
2943
  parseClipboardTSVWithDepths,
2944
+ resolveColumnFreezeSide,
2719
2945
  resolveDataTableLabels,
2720
2946
  resolvePasteColumnIds,
2721
2947
  resolveRowSelection,
@@ -1,5 +1,52 @@
1
- import { ColumnDef, RowSelectionState, Updater, Row } from '@tanstack/react-table';
2
- import { ReactNode, InputHTMLAttributes, ComponentType } from 'react';
1
+ import { ColumnDef, RowSelectionState, Updater, ColumnSizingState, OnChangeFn, ColumnResizeMode, Row } from '@tanstack/react-table';
2
+ import { CSSProperties, ReactNode, InputHTMLAttributes, ComponentType } from 'react';
3
+
4
+ /** Sticky edge for a frozen column. Does not reorder columns. */
5
+ type ColumnFreezeSide = "left" | "right";
6
+ /**
7
+ * Per-column freeze flag.
8
+ * `true` is sugar for `"left"`.
9
+ */
10
+ type ColumnFreezeMeta = boolean | ColumnFreezeSide;
11
+ type ColumnFreezeColumnInput = {
12
+ id: string;
13
+ size: number;
14
+ side?: ColumnFreezeSide;
15
+ };
16
+ /** Which outer sides of a freeze island get a divider shadow. */
17
+ type ColumnFreezeEdgeSide = "left" | "right" | "both";
18
+ type ColumnFreezeOffset = {
19
+ side: ColumnFreezeSide;
20
+ /** Cumulative sticky inset (`left` or `right` in px). */
21
+ offset: number;
22
+ /** True when this cell is on an island boundary (any side). */
23
+ isEdge: boolean;
24
+ /** Shadow toward the previous column (scrollable / other island). */
25
+ edgeLeft: boolean;
26
+ /** Shadow toward the next column (scrollable / other island). */
27
+ edgeRight: boolean;
28
+ /** Relative stack order within the freeze side (higher = closer to the viewport edge). */
29
+ stack: number;
30
+ };
31
+ /** Normalize column `frozen` meta into a sticky side. */
32
+ declare function resolveColumnFreezeSide(frozen?: ColumnFreezeMeta): ColumnFreezeSide | undefined;
33
+ /** Serialize freeze-edge flags for `data-freeze-edge`. */
34
+ declare function getColumnFreezeEdgeAttr(offset: Pick<ColumnFreezeOffset, "edgeLeft" | "edgeRight"> | undefined): ColumnFreezeEdgeSide | undefined;
35
+ /**
36
+ * Build sticky insets for frozen columns without changing DOM/column order.
37
+ *
38
+ * - `left`: `left = Σ(widths of left-frozen columns before this one)`
39
+ * - `right`: `right = Σ(widths of right-frozen columns after this one)`
40
+ *
41
+ * Contiguous same-side freezes form one island — only the outer boundaries
42
+ * get edge shadows. Gaps between same-side freezes create separate islands,
43
+ * so both sides of the gap receive a shadow.
44
+ */
45
+ declare function buildColumnFreezeOffsets(columns: ColumnFreezeColumnInput[]): Map<string, ColumnFreezeOffset>;
46
+ /** Sticky position styles for a frozen header or body cell. */
47
+ declare function getColumnFreezeStyle(offset: ColumnFreezeOffset | undefined, options?: {
48
+ isHeader?: boolean;
49
+ }): CSSProperties | undefined;
3
50
 
4
51
  type DataTableLabels = {
5
52
  empty: string;
@@ -7,6 +54,8 @@ type DataTableLabels = {
7
54
  selection: (selectedCount: number) => ReactNode;
8
55
  expandRow: string;
9
56
  collapseRow: string;
57
+ /** Accessible label for the column resize handle */
58
+ resizeColumn: string;
10
59
  };
11
60
  /** Default copy. Override via the `labels` option. */
12
61
  declare const DEFAULT_DATA_TABLE_LABELS: DataTableLabels;
@@ -31,6 +80,12 @@ declare module "@tanstack/react-table" {
31
80
  editType?: CellEditType;
32
81
  /** Inline editor input attribute overrides */
33
82
  editInputProps?: DataTableEditInputProps;
83
+ /**
84
+ * Freeze (sticky) this column without reordering.
85
+ * `true` / `"left"` stick to the scrollport left; `"right"` to the right.
86
+ * Middle columns are allowed; multiple frozen columns stack via cumulative offsets.
87
+ */
88
+ frozen?: ColumnFreezeMeta;
34
89
  }
35
90
  interface Row<TData> {
36
91
  /**
@@ -180,6 +235,25 @@ type DataTableProps<T extends Record<string, unknown>> = {
180
235
  estimateRowHeight?: number;
181
236
  /** Virtualization overscan row count. Default 8 */
182
237
  virtualOverscan?: number;
238
+ /**
239
+ * Enable drag-to-resize on column headers. Defaults to false.
240
+ * Opt out per column with `Column.resizable={false}` / `enableResizing: false`.
241
+ */
242
+ enableColumnResize?: boolean;
243
+ /** Controlled column sizing map (`{ [columnId]: widthPx }`) */
244
+ columnSizing?: ColumnSizingState;
245
+ onColumnSizingChange?: OnChangeFn<ColumnSizingState>;
246
+ /**
247
+ * When to commit resize updates. Defaults to `"onChange"` (live while dragging).
248
+ * Use `"onEnd"` to update only after the pointer is released.
249
+ */
250
+ columnResizeMode?: ColumnResizeMode;
251
+ /**
252
+ * Enable sticky freeze columns. Defaults to false.
253
+ * Mark columns with `Column.frozen` / `meta.frozen` (`true` | `"left"` | `"right"`).
254
+ * Does not reorder columns; offsets stack so frozen cells do not overlap.
255
+ */
256
+ enableColumnFreeze?: boolean;
183
257
  /**
184
258
  * Optional UI part replacements for the unstyled DataTable renderer.
185
259
  * Use with `createTable` / `Table.Column`, or pass columns directly to `DataTable`.
@@ -205,6 +279,8 @@ type DataTableClassNames = {
205
279
  head?: string;
206
280
  headRow?: string;
207
281
  headCell?: string;
282
+ /** Column resize drag handle inside a header cell */
283
+ resizeHandle?: string;
208
284
  body?: string;
209
285
  emptyCell?: string;
210
286
  virtualSpacer?: string;
@@ -266,7 +342,23 @@ type TableColumnProps<T extends Record<string, unknown>, K extends string = keyo
266
342
  virtual?: boolean;
267
343
  children?: ReactNode;
268
344
  sortable?: boolean;
345
+ /** Initial / default column width in px (TanStack `size`) */
269
346
  width?: number;
347
+ /** Minimum resize width in px. Defaults to the table min when omitted */
348
+ minWidth?: number;
349
+ /** Maximum resize width in px. Defaults to the table max when omitted */
350
+ maxWidth?: number;
351
+ /**
352
+ * When false, this column cannot be resized even if `enableColumnResize` is on.
353
+ * Defaults to true.
354
+ */
355
+ resizable?: boolean;
356
+ /**
357
+ * Freeze (sticky) without changing column order.
358
+ * `true` / `"left"` → left edge; `"right"` → right edge.
359
+ * Requires `enableColumnFreeze`. Middle columns are allowed.
360
+ */
361
+ frozen?: ColumnFreezeMeta;
270
362
  align?: "left" | "center" | "right";
271
363
  rowSpan?: boolean;
272
364
  rowSpanKey?: string;
@@ -282,4 +374,4 @@ type TableProps<T extends Record<string, unknown>> = Omit<DataTableProps<T>, "co
282
374
  children: ReactNode;
283
375
  };
284
376
 
285
- export { type CellEditType as C, DEFAULT_DATA_TABLE_LABELS as D, type PasteMode as P, type RowSelectionMode as R, type TableColumnProps as T, type DataTableClassNames as a, type DataTableCopyActions as b, type DataTableLabels as c, type DataTableProps as d, type DataTableSlots as e, type RowsPastePayload as f, type TableProps as g, resolveDataTableLabels as r };
377
+ export { type ColumnFreezeColumnInput as C, DEFAULT_DATA_TABLE_LABELS as D, type PasteMode as P, type RowSelectionMode as R, type TableColumnProps as T, type ColumnFreezeEdgeSide as a, type ColumnFreezeMeta as b, type ColumnFreezeOffset as c, type ColumnFreezeSide as d, type DataTableClassNames as e, type DataTableCopyActions as f, type DataTableLabels as g, type DataTableProps as h, type DataTableSlots as i, type RowsPastePayload as j, type TableProps as k, buildColumnFreezeOffsets as l, getColumnFreezeEdgeAttr as m, getColumnFreezeStyle as n, resolveDataTableLabels as o, type CellEditType as p, resolveColumnFreezeSide as r };