react-glide-table 1.1.8 → 1.2.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 +111 -47
- package/dist/compound.cjs +256 -15
- package/dist/compound.d.cts +3 -3
- package/dist/compound.d.ts +3 -3
- package/dist/compound.js +256 -15
- package/dist/core.cjs +140 -4
- package/dist/core.d.cts +20 -5
- package/dist/core.d.ts +20 -5
- package/dist/core.js +136 -4
- package/dist/index.cjs +264 -15
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +260 -15
- package/dist/{types-Ce4qepIU.d.cts → types-D031_07N.d.cts} +94 -3
- package/dist/{types-Ce4qepIU.d.ts → types-D031_07N.d.ts} +94 -3
- package/package.json +23 -1
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,68 @@ 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 buildColumnFreezeOffsets(columns) {
|
|
952
|
+
const result = /* @__PURE__ */ new Map();
|
|
953
|
+
let leftOffset = 0;
|
|
954
|
+
const leftIds = [];
|
|
955
|
+
for (const column of columns) {
|
|
956
|
+
if (column.side !== "left") continue;
|
|
957
|
+
leftIds.push(column.id);
|
|
958
|
+
result.set(column.id, {
|
|
959
|
+
side: "left",
|
|
960
|
+
offset: leftOffset,
|
|
961
|
+
isEdge: false,
|
|
962
|
+
stack: 0
|
|
963
|
+
});
|
|
964
|
+
leftOffset += column.size;
|
|
965
|
+
}
|
|
966
|
+
leftIds.forEach((id, index) => {
|
|
967
|
+
const entry = result.get(id);
|
|
968
|
+
if (!entry) return;
|
|
969
|
+
entry.isEdge = index === leftIds.length - 1;
|
|
970
|
+
entry.stack = leftIds.length - index;
|
|
971
|
+
});
|
|
972
|
+
let rightOffset = 0;
|
|
973
|
+
const rightIds = [];
|
|
974
|
+
for (let index = columns.length - 1; index >= 0; index -= 1) {
|
|
975
|
+
const column = columns[index];
|
|
976
|
+
if (!column || column.side !== "right") continue;
|
|
977
|
+
rightIds.push(column.id);
|
|
978
|
+
result.set(column.id, {
|
|
979
|
+
side: "right",
|
|
980
|
+
offset: rightOffset,
|
|
981
|
+
isEdge: false,
|
|
982
|
+
stack: 0
|
|
983
|
+
});
|
|
984
|
+
rightOffset += column.size;
|
|
985
|
+
}
|
|
986
|
+
rightIds.forEach((id, index) => {
|
|
987
|
+
const entry = result.get(id);
|
|
988
|
+
if (!entry) return;
|
|
989
|
+
entry.isEdge = index === rightIds.length - 1;
|
|
990
|
+
entry.stack = rightIds.length - index;
|
|
991
|
+
});
|
|
992
|
+
return result;
|
|
993
|
+
}
|
|
994
|
+
function getColumnFreezeStyle(offset, options) {
|
|
995
|
+
if (!offset) return void 0;
|
|
996
|
+
const zBase = options?.isHeader ? HEADER_Z_BASE : BODY_Z_BASE;
|
|
997
|
+
return {
|
|
998
|
+
position: "sticky",
|
|
999
|
+
...offset.side === "left" ? { left: offset.offset } : { right: offset.offset },
|
|
1000
|
+
zIndex: zBase + offset.stack,
|
|
1001
|
+
...options?.isHeader ? { top: 0 } : {}
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
939
1005
|
// src/components/ui/table/features/row-expand/row-expand.ts
|
|
940
1006
|
import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "react";
|
|
941
1007
|
function getFieldValue(row, key) {
|
|
@@ -1201,6 +1267,7 @@ function collectRowSpanColumns(columns) {
|
|
|
1201
1267
|
}
|
|
1202
1268
|
|
|
1203
1269
|
// src/core/useGlideTable.ts
|
|
1270
|
+
var EMPTY_COLUMN_FREEZE_OFFSETS = /* @__PURE__ */ new Map();
|
|
1204
1271
|
function useGlideTable(options) {
|
|
1205
1272
|
const {
|
|
1206
1273
|
data,
|
|
@@ -1236,7 +1303,12 @@ function useGlideTable(options) {
|
|
|
1236
1303
|
enableInsertPaste,
|
|
1237
1304
|
enableVirtualization = true,
|
|
1238
1305
|
estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
|
|
1239
|
-
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
|
|
1306
|
+
virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN,
|
|
1307
|
+
enableColumnResize = false,
|
|
1308
|
+
columnSizing: controlledColumnSizing,
|
|
1309
|
+
onColumnSizingChange,
|
|
1310
|
+
columnResizeMode = "onChange",
|
|
1311
|
+
enableColumnFreeze = false
|
|
1240
1312
|
} = options;
|
|
1241
1313
|
const labels = useMemo2(() => {
|
|
1242
1314
|
const resolved = resolveDataTableLabels(labelsProp);
|
|
@@ -1250,6 +1322,7 @@ function useGlideTable(options) {
|
|
|
1250
1322
|
const enableExpand = Boolean(toggleField);
|
|
1251
1323
|
const resolvedEnableSubtreeCopy = enableSubtreeCopy ?? enableExpand;
|
|
1252
1324
|
const [internalRowSelection, setInternalRowSelection] = useState3({});
|
|
1325
|
+
const [internalColumnSizing, setInternalColumnSizing] = useState3({});
|
|
1253
1326
|
const [internalExpandedRows, setInternalExpandedRows] = useState3(
|
|
1254
1327
|
() => /* @__PURE__ */ new Set()
|
|
1255
1328
|
);
|
|
@@ -1268,6 +1341,7 @@ function useGlideTable(options) {
|
|
|
1268
1341
|
controlledRowSelection,
|
|
1269
1342
|
internalRowSelection
|
|
1270
1343
|
);
|
|
1344
|
+
const columnSizing = controlledColumnSizing ?? internalColumnSizing;
|
|
1271
1345
|
const expandedRows = controlledExpandedRows ?? internalExpandedRows;
|
|
1272
1346
|
const handleExpandedRowsChange = useCallback3(
|
|
1273
1347
|
(next) => {
|
|
@@ -1293,9 +1367,27 @@ function useGlideTable(options) {
|
|
|
1293
1367
|
const table = useReactTable({
|
|
1294
1368
|
data: tableData,
|
|
1295
1369
|
columns,
|
|
1370
|
+
...enableColumnResize ? {
|
|
1371
|
+
defaultColumn: {
|
|
1372
|
+
minSize: DATA_TABLE_COLUMN_MIN_SIZE,
|
|
1373
|
+
maxSize: DATA_TABLE_COLUMN_MAX_SIZE
|
|
1374
|
+
}
|
|
1375
|
+
} : {},
|
|
1376
|
+
enableColumnResizing: enableColumnResize,
|
|
1377
|
+
columnResizeMode,
|
|
1296
1378
|
state: {
|
|
1297
|
-
rowSelection: rowSelectionMode === "none" ? {} : rowSelection
|
|
1379
|
+
rowSelection: rowSelectionMode === "none" ? {} : rowSelection,
|
|
1380
|
+
...enableColumnResize ? { columnSizing } : {}
|
|
1298
1381
|
},
|
|
1382
|
+
onColumnSizingChange: enableColumnResize ? (updater) => {
|
|
1383
|
+
if (onColumnSizingChange) {
|
|
1384
|
+
onColumnSizingChange(updater);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
setInternalColumnSizing(
|
|
1388
|
+
(previous) => typeof updater === "function" ? updater(previous) : updater
|
|
1389
|
+
);
|
|
1390
|
+
} : void 0,
|
|
1299
1391
|
enableRowSelection: rowSelectionMode === "none" ? false : getRowCanSelect ? (row) => getRowCanSelect(row.original, row.index) : true,
|
|
1300
1392
|
enableMultiRowSelection: rowSelectionMode === "multi",
|
|
1301
1393
|
onRowSelectionChange: (updater) => {
|
|
@@ -1326,6 +1418,17 @@ function useGlideTable(options) {
|
|
|
1326
1418
|
const selectedCount = selectedRows.length;
|
|
1327
1419
|
const rows = table.getRowModel().rows;
|
|
1328
1420
|
const columnCount = table.getAllLeafColumns().length || 1;
|
|
1421
|
+
const visibleLeafColumns = table.getVisibleLeafColumns();
|
|
1422
|
+
const columnFreezeOffsets = useMemo2(() => {
|
|
1423
|
+
if (!enableColumnFreeze) return EMPTY_COLUMN_FREEZE_OFFSETS;
|
|
1424
|
+
return buildColumnFreezeOffsets(
|
|
1425
|
+
visibleLeafColumns.map((column) => ({
|
|
1426
|
+
id: column.id,
|
|
1427
|
+
size: column.getSize(),
|
|
1428
|
+
side: resolveColumnFreezeSide(column.columnDef.meta?.frozen)
|
|
1429
|
+
}))
|
|
1430
|
+
);
|
|
1431
|
+
}, [enableColumnFreeze, visibleLeafColumns, columnSizing]);
|
|
1329
1432
|
const rowVirtualizer = useVirtualizer({
|
|
1330
1433
|
count: shouldVirtualize ? rows.length : 0,
|
|
1331
1434
|
getScrollElement: () => scrollRef.current,
|
|
@@ -1442,6 +1545,13 @@ function useGlideTable(options) {
|
|
|
1442
1545
|
onToggleExpand: handleToggleExpand,
|
|
1443
1546
|
expandRowLabel: labels.expandRow,
|
|
1444
1547
|
collapseRowLabel: labels.collapseRow
|
|
1548
|
+
},
|
|
1549
|
+
columnResize: {
|
|
1550
|
+
enableColumnResize
|
|
1551
|
+
},
|
|
1552
|
+
columnFreeze: {
|
|
1553
|
+
enableColumnFreeze,
|
|
1554
|
+
offsets: columnFreezeOffsets
|
|
1445
1555
|
}
|
|
1446
1556
|
};
|
|
1447
1557
|
}, [
|
|
@@ -1474,7 +1584,10 @@ function useGlideTable(options) {
|
|
|
1474
1584
|
preventExpand,
|
|
1475
1585
|
handleToggleExpand,
|
|
1476
1586
|
labels.expandRow,
|
|
1477
|
-
labels.collapseRow
|
|
1587
|
+
labels.collapseRow,
|
|
1588
|
+
enableColumnResize,
|
|
1589
|
+
enableColumnFreeze,
|
|
1590
|
+
columnFreezeOffsets
|
|
1478
1591
|
]);
|
|
1479
1592
|
const copySelectionRef = useRef4(copySelection);
|
|
1480
1593
|
useEffect4(() => {
|
|
@@ -1495,6 +1608,8 @@ function useGlideTable(options) {
|
|
|
1495
1608
|
loadingText: labels.loading,
|
|
1496
1609
|
selectionLabel: labels.selection,
|
|
1497
1610
|
enableCellSelection,
|
|
1611
|
+
enableColumnResize,
|
|
1612
|
+
enableColumnFreeze,
|
|
1498
1613
|
shouldVirtualize,
|
|
1499
1614
|
scrollRef,
|
|
1500
1615
|
rowVirtualizer,
|
|
@@ -1508,6 +1623,19 @@ function useGlideTable(options) {
|
|
|
1508
1623
|
};
|
|
1509
1624
|
}
|
|
1510
1625
|
|
|
1626
|
+
// src/components/ui/table/features/column-resize/columnResize.ts
|
|
1627
|
+
function getColumnSizeStyle(size, options) {
|
|
1628
|
+
const { force = false, lockMax = false } = options ?? {};
|
|
1629
|
+
if (!force && size === DATA_TABLE_COLUMN_SIZE) {
|
|
1630
|
+
return void 0;
|
|
1631
|
+
}
|
|
1632
|
+
return {
|
|
1633
|
+
width: size,
|
|
1634
|
+
minWidth: size,
|
|
1635
|
+
...lockMax ? { maxWidth: size } : {}
|
|
1636
|
+
};
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1511
1639
|
// src/components/ui/table/components/DataTable/DataTable.tsx
|
|
1512
1640
|
import { flexRender as flexRender2 } from "@tanstack/react-table";
|
|
1513
1641
|
import { useMemo as useMemo3 } from "react";
|
|
@@ -1681,6 +1809,19 @@ function cn(...inputs) {
|
|
|
1681
1809
|
|
|
1682
1810
|
// src/components/ui/table/components/DataTable/DataTableRow.tsx
|
|
1683
1811
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1812
|
+
function isInteractiveMouseTarget(target) {
|
|
1813
|
+
if (!(target instanceof Element)) return false;
|
|
1814
|
+
const interactiveSelector = [
|
|
1815
|
+
"input",
|
|
1816
|
+
"textarea",
|
|
1817
|
+
"select",
|
|
1818
|
+
"button",
|
|
1819
|
+
"a[href]",
|
|
1820
|
+
"[contenteditable]:not([contenteditable='false'])",
|
|
1821
|
+
"[data-table-disable-cell-selection]"
|
|
1822
|
+
].join(",");
|
|
1823
|
+
return target.closest(interactiveSelector) !== null;
|
|
1824
|
+
}
|
|
1684
1825
|
function resolveExpandCellIndex(cells, toggleField) {
|
|
1685
1826
|
if (!toggleField) return 0;
|
|
1686
1827
|
const matchedIndex = cells.findIndex(
|
|
@@ -1701,7 +1842,18 @@ function DataTableRow({
|
|
|
1701
1842
|
virtualIndex,
|
|
1702
1843
|
measureElement
|
|
1703
1844
|
}) {
|
|
1704
|
-
const {
|
|
1845
|
+
const {
|
|
1846
|
+
classNames,
|
|
1847
|
+
rowSpan,
|
|
1848
|
+
selection,
|
|
1849
|
+
cellSelection,
|
|
1850
|
+
cellEdit,
|
|
1851
|
+
expand,
|
|
1852
|
+
columnResize,
|
|
1853
|
+
columnFreeze
|
|
1854
|
+
} = useDataTableRowContext();
|
|
1855
|
+
const { enableColumnResize } = columnResize;
|
|
1856
|
+
const { enableColumnFreeze, offsets: freezeOffsets } = columnFreeze;
|
|
1705
1857
|
const {
|
|
1706
1858
|
enableRowSpan,
|
|
1707
1859
|
primaryRowSpanColumnId,
|
|
@@ -1747,6 +1899,33 @@ function DataTableRow({
|
|
|
1747
1899
|
const isGroupHovered = enableRowSpan && hoveredRowIndex !== null && hoveredRowIndex >= primaryGroupStart && hoveredRowIndex <= primaryGroupStart + primaryGroupSpan - 1;
|
|
1748
1900
|
const visibleCells = row.getVisibleCells();
|
|
1749
1901
|
const columnIdsByIndex = visibleCells.map((cell) => cell.column.id);
|
|
1902
|
+
row.getIsCellDragSelected = (columnId) => {
|
|
1903
|
+
if (!activeSelectionBounds) return false;
|
|
1904
|
+
if (columnId) {
|
|
1905
|
+
const colIndex = columnIdsByIndex.indexOf(columnId);
|
|
1906
|
+
if (colIndex < 0) return false;
|
|
1907
|
+
const { startRow, rowSpan: rowSpan2 } = resolveRowSpanAt(
|
|
1908
|
+
columnRowSpanMap.get(columnIdsByIndex[colIndex]),
|
|
1909
|
+
rowIndex
|
|
1910
|
+
);
|
|
1911
|
+
return isCellInSelection(
|
|
1912
|
+
startRow,
|
|
1913
|
+
colIndex,
|
|
1914
|
+
activeSelectionBounds,
|
|
1915
|
+
rowSpan2
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
for (let colIndex = 0; colIndex < columnIdsByIndex.length; colIndex += 1) {
|
|
1919
|
+
const { startRow, rowSpan: rowSpan2 } = resolveRowSpanAt(
|
|
1920
|
+
columnRowSpanMap.get(columnIdsByIndex[colIndex]),
|
|
1921
|
+
rowIndex
|
|
1922
|
+
);
|
|
1923
|
+
if (isCellInSelection(startRow, colIndex, activeSelectionBounds, rowSpan2)) {
|
|
1924
|
+
return true;
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
return false;
|
|
1928
|
+
};
|
|
1750
1929
|
const isVisuallySelectedAt = activeSelectionBounds ? (targetRow, targetCol) => {
|
|
1751
1930
|
if (targetCol < activeSelectionBounds.startCol || targetCol > activeSelectionBounds.endCol) {
|
|
1752
1931
|
return false;
|
|
@@ -1855,6 +2034,17 @@ function DataTableRow({
|
|
|
1855
2034
|
);
|
|
1856
2035
|
const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
|
|
1857
2036
|
const hasSelectionEdges = hasCellSelectionEdges(selectionEdgeStyle);
|
|
2037
|
+
const sizeStyle = getColumnSizeStyle(cell.column.getSize(), {
|
|
2038
|
+
force: enableColumnResize,
|
|
2039
|
+
lockMax: enableColumnResize
|
|
2040
|
+
});
|
|
2041
|
+
const freezeOffset = enableColumnFreeze ? freezeOffsets.get(columnId) : void 0;
|
|
2042
|
+
const freezeStyle = getColumnFreezeStyle(freezeOffset);
|
|
2043
|
+
const cellStyle = {
|
|
2044
|
+
...sizeStyle,
|
|
2045
|
+
...freezeStyle,
|
|
2046
|
+
...selectionEdgeStyle
|
|
2047
|
+
};
|
|
1858
2048
|
return /* @__PURE__ */ jsxs2(
|
|
1859
2049
|
"td",
|
|
1860
2050
|
{
|
|
@@ -1868,12 +2058,15 @@ function DataTableRow({
|
|
|
1868
2058
|
"data-selection-edges": hasSelectionEdges ? "" : void 0,
|
|
1869
2059
|
"data-editable": editable ? "" : void 0,
|
|
1870
2060
|
"data-editing": isEditing ? "" : void 0,
|
|
2061
|
+
"data-frozen": freezeOffset?.side,
|
|
2062
|
+
"data-freeze-edge": freezeOffset?.isEdge ? "" : void 0,
|
|
1871
2063
|
onMouseDown: (event) => {
|
|
1872
2064
|
if (isEditing) {
|
|
1873
2065
|
event.stopPropagation();
|
|
1874
2066
|
return;
|
|
1875
2067
|
}
|
|
1876
2068
|
if (!enableCellSelection) return;
|
|
2069
|
+
if (isInteractiveMouseTarget(event.target)) return;
|
|
1877
2070
|
event.preventDefault();
|
|
1878
2071
|
onCellMouseDown(
|
|
1879
2072
|
resolveCellRowIndex(event.clientY, event.currentTarget),
|
|
@@ -1901,9 +2094,10 @@ function DataTableRow({
|
|
|
1901
2094
|
event.stopPropagation();
|
|
1902
2095
|
onStartEdit(rowIndex, cellIndex);
|
|
1903
2096
|
},
|
|
1904
|
-
style:
|
|
2097
|
+
style: Object.keys(cellStyle).length > 0 ? cellStyle : void 0,
|
|
1905
2098
|
className: cn(
|
|
1906
2099
|
"data-table-cell",
|
|
2100
|
+
freezeOffset && `data-table-cell--frozen-${freezeOffset.side}`,
|
|
1907
2101
|
CELL_ALIGN_CLASS[align],
|
|
1908
2102
|
cellClassName,
|
|
1909
2103
|
isMerged && "is-merged",
|
|
@@ -2136,10 +2330,13 @@ function DataTable({
|
|
|
2136
2330
|
rows,
|
|
2137
2331
|
columnCount,
|
|
2138
2332
|
selectedCount,
|
|
2333
|
+
labels,
|
|
2139
2334
|
emptyText,
|
|
2140
2335
|
loadingText,
|
|
2141
2336
|
selectionLabel,
|
|
2142
2337
|
enableCellSelection,
|
|
2338
|
+
enableColumnResize,
|
|
2339
|
+
enableColumnFreeze,
|
|
2143
2340
|
shouldVirtualize,
|
|
2144
2341
|
scrollRef,
|
|
2145
2342
|
rowVirtualizer,
|
|
@@ -2154,6 +2351,7 @@ function DataTable({
|
|
|
2154
2351
|
const RowSlot = slots?.Row ?? DataTableRow;
|
|
2155
2352
|
const PendingSlot = slots?.Pending ?? DefaultPending;
|
|
2156
2353
|
const EmptySlot = slots?.Empty ?? DefaultEmpty;
|
|
2354
|
+
const freezeOffsets = rowContextValue.columnFreeze.offsets;
|
|
2157
2355
|
const contextValue = useMemo3(
|
|
2158
2356
|
() => ({ ...rowContextValue, classNames }),
|
|
2159
2357
|
[rowContextValue, classNames]
|
|
@@ -2174,6 +2372,8 @@ function DataTable({
|
|
|
2174
2372
|
className: cn(
|
|
2175
2373
|
"DataTableJSX",
|
|
2176
2374
|
!enableCellSelection && "DataTableJSX--no-cell-selection",
|
|
2375
|
+
enableColumnResize && "DataTableJSX--column-resize",
|
|
2376
|
+
enableColumnFreeze && "DataTableJSX--column-freeze",
|
|
2177
2377
|
classNames?.root,
|
|
2178
2378
|
className
|
|
2179
2379
|
),
|
|
@@ -2194,6 +2394,7 @@ function DataTable({
|
|
|
2194
2394
|
"table",
|
|
2195
2395
|
{
|
|
2196
2396
|
className: cn("data-table", classNames?.table),
|
|
2397
|
+
style: enableColumnResize ? { width: table.getTotalSize() } : void 0,
|
|
2197
2398
|
onDragStart: enableCellSelection ? (event) => event.preventDefault() : void 0,
|
|
2198
2399
|
children: [
|
|
2199
2400
|
/* @__PURE__ */ jsx5("thead", { className: cn("data-table-head", classNames?.head), children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx5(
|
|
@@ -2203,22 +2404,54 @@ function DataTable({
|
|
|
2203
2404
|
children: headerGroup.headers.map((header) => {
|
|
2204
2405
|
const align = header.column.columnDef.meta?.align ?? "center";
|
|
2205
2406
|
const headerClassName = header.column.columnDef.meta?.headerClassName;
|
|
2206
|
-
|
|
2407
|
+
const canResize = enableColumnResize && header.column.getCanResize();
|
|
2408
|
+
const sizeStyle = getColumnSizeStyle(header.getSize(), {
|
|
2409
|
+
force: enableColumnResize,
|
|
2410
|
+
lockMax: enableColumnResize
|
|
2411
|
+
});
|
|
2412
|
+
const freezeOffset = enableColumnFreeze ? freezeOffsets.get(header.column.id) : void 0;
|
|
2413
|
+
const freezeStyle = getColumnFreezeStyle(freezeOffset, {
|
|
2414
|
+
isHeader: true
|
|
2415
|
+
});
|
|
2416
|
+
const headerStyle = {
|
|
2417
|
+
...sizeStyle,
|
|
2418
|
+
...freezeStyle
|
|
2419
|
+
};
|
|
2420
|
+
return /* @__PURE__ */ jsxs4(
|
|
2207
2421
|
"th",
|
|
2208
2422
|
{
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
minWidth: header.getSize() !== 150 ? header.getSize() : void 0
|
|
2214
|
-
},
|
|
2423
|
+
"data-resizing": header.column.getIsResizing() ? "" : void 0,
|
|
2424
|
+
"data-frozen": freezeOffset?.side,
|
|
2425
|
+
"data-freeze-edge": freezeOffset?.isEdge ? "" : void 0,
|
|
2426
|
+
style: Object.keys(headerStyle).length > 0 ? headerStyle : void 0,
|
|
2215
2427
|
className: cn(
|
|
2216
2428
|
"data-table-head-cell",
|
|
2429
|
+
freezeOffset && `data-table-head-cell--frozen-${freezeOffset.side}`,
|
|
2217
2430
|
CELL_ALIGN_CLASS[align],
|
|
2218
2431
|
classNames?.headCell,
|
|
2219
2432
|
headerClassName
|
|
2220
2433
|
),
|
|
2221
|
-
children:
|
|
2434
|
+
children: [
|
|
2435
|
+
header.isPlaceholder ? null : flexRender2(header.column.columnDef.header, header.getContext()),
|
|
2436
|
+
canResize ? /* @__PURE__ */ jsx5(
|
|
2437
|
+
"div",
|
|
2438
|
+
{
|
|
2439
|
+
role: "separator",
|
|
2440
|
+
"aria-orientation": "vertical",
|
|
2441
|
+
"aria-label": labels.resizeColumn,
|
|
2442
|
+
"data-table-disable-cell-selection": "",
|
|
2443
|
+
className: cn(
|
|
2444
|
+
"data-table-resize-handle",
|
|
2445
|
+
classNames?.resizeHandle
|
|
2446
|
+
),
|
|
2447
|
+
onMouseDown: header.getResizeHandler(),
|
|
2448
|
+
onTouchStart: header.getResizeHandler(),
|
|
2449
|
+
onDoubleClick: () => {
|
|
2450
|
+
header.column.resetSize();
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
) : null
|
|
2454
|
+
]
|
|
2222
2455
|
},
|
|
2223
2456
|
header.id
|
|
2224
2457
|
);
|
|
@@ -2346,6 +2579,10 @@ function buildColumnDef(props, sort, onSort) {
|
|
|
2346
2579
|
children,
|
|
2347
2580
|
sortable = false,
|
|
2348
2581
|
width,
|
|
2582
|
+
minWidth,
|
|
2583
|
+
maxWidth,
|
|
2584
|
+
resizable,
|
|
2585
|
+
frozen,
|
|
2349
2586
|
align,
|
|
2350
2587
|
rowSpan,
|
|
2351
2588
|
rowSpanKey,
|
|
@@ -2359,7 +2596,10 @@ function buildColumnDef(props, sort, onSort) {
|
|
|
2359
2596
|
return {
|
|
2360
2597
|
id: field,
|
|
2361
2598
|
...!virtual ? { accessorKey: field } : {},
|
|
2362
|
-
size: width ??
|
|
2599
|
+
size: width ?? DATA_TABLE_COLUMN_SIZE,
|
|
2600
|
+
...minWidth != null ? { minSize: minWidth } : {},
|
|
2601
|
+
...maxWidth != null ? { maxSize: maxWidth } : {},
|
|
2602
|
+
...resizable === false ? { enableResizing: false } : {},
|
|
2363
2603
|
header: sortable ? () => /* @__PURE__ */ jsx6(SortableHeader, { label: children, field, sort, onSort }) : (
|
|
2364
2604
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
2365
2605
|
() => children
|
|
@@ -2379,6 +2619,7 @@ function buildColumnDef(props, sort, onSort) {
|
|
|
2379
2619
|
editable,
|
|
2380
2620
|
editType,
|
|
2381
2621
|
editInputProps,
|
|
2622
|
+
frozen,
|
|
2382
2623
|
className,
|
|
2383
2624
|
headerClassName
|
|
2384
2625
|
}
|
|
@@ -2654,6 +2895,7 @@ export {
|
|
|
2654
2895
|
applyCellEdit,
|
|
2655
2896
|
applyFillData,
|
|
2656
2897
|
applySelectionUpdater,
|
|
2898
|
+
buildColumnFreezeOffsets,
|
|
2657
2899
|
buildColumnRowSpanMap,
|
|
2658
2900
|
buildRowsPastePayload,
|
|
2659
2901
|
canExpandRow,
|
|
@@ -2666,6 +2908,8 @@ export {
|
|
|
2666
2908
|
getCellEditDraftValue,
|
|
2667
2909
|
getCellSelectionEdgeStyle,
|
|
2668
2910
|
getColumnEditType,
|
|
2911
|
+
getColumnFreezeStyle,
|
|
2912
|
+
getColumnSizeStyle,
|
|
2669
2913
|
getRowIndexInMergedCell,
|
|
2670
2914
|
hasCellSelectionEdges,
|
|
2671
2915
|
isCellInSelection,
|
|
@@ -2675,6 +2919,7 @@ export {
|
|
|
2675
2919
|
parseCellEditValue,
|
|
2676
2920
|
parseClipboardTSV,
|
|
2677
2921
|
parseClipboardTSVWithDepths,
|
|
2922
|
+
resolveColumnFreezeSide,
|
|
2678
2923
|
resolveDataTableLabels,
|
|
2679
2924
|
resolvePasteColumnIds,
|
|
2680
2925
|
resolveRowSelection,
|
|
@@ -1,5 +1,42 @@
|
|
|
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
|
+
type ColumnFreezeOffset = {
|
|
17
|
+
side: ColumnFreezeSide;
|
|
18
|
+
/** Cumulative sticky inset (`left` or `right` in px). */
|
|
19
|
+
offset: number;
|
|
20
|
+
/** Inner edge of the sticky group (shadow / divider). */
|
|
21
|
+
isEdge: boolean;
|
|
22
|
+
/** Relative stack order within the freeze side (higher = closer to the viewport edge). */
|
|
23
|
+
stack: number;
|
|
24
|
+
};
|
|
25
|
+
/** Normalize column `frozen` meta into a sticky side. */
|
|
26
|
+
declare function resolveColumnFreezeSide(frozen?: ColumnFreezeMeta): ColumnFreezeSide | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Build sticky insets for frozen columns without changing DOM/column order.
|
|
29
|
+
*
|
|
30
|
+
* - `left`: `left = Σ(widths of left-frozen columns before this one)`
|
|
31
|
+
* - `right`: `right = Σ(widths of right-frozen columns after this one)`
|
|
32
|
+
*
|
|
33
|
+
* Middle columns may be frozen; non-frozen neighbors scroll underneath.
|
|
34
|
+
*/
|
|
35
|
+
declare function buildColumnFreezeOffsets(columns: ColumnFreezeColumnInput[]): Map<string, ColumnFreezeOffset>;
|
|
36
|
+
/** Sticky position styles for a frozen header or body cell. */
|
|
37
|
+
declare function getColumnFreezeStyle(offset: ColumnFreezeOffset | undefined, options?: {
|
|
38
|
+
isHeader?: boolean;
|
|
39
|
+
}): CSSProperties | undefined;
|
|
3
40
|
|
|
4
41
|
type DataTableLabels = {
|
|
5
42
|
empty: string;
|
|
@@ -7,6 +44,8 @@ type DataTableLabels = {
|
|
|
7
44
|
selection: (selectedCount: number) => ReactNode;
|
|
8
45
|
expandRow: string;
|
|
9
46
|
collapseRow: string;
|
|
47
|
+
/** Accessible label for the column resize handle */
|
|
48
|
+
resizeColumn: string;
|
|
10
49
|
};
|
|
11
50
|
/** Default copy. Override via the `labels` option. */
|
|
12
51
|
declare const DEFAULT_DATA_TABLE_LABELS: DataTableLabels;
|
|
@@ -31,6 +70,21 @@ declare module "@tanstack/react-table" {
|
|
|
31
70
|
editType?: CellEditType;
|
|
32
71
|
/** Inline editor input attribute overrides */
|
|
33
72
|
editInputProps?: DataTableEditInputProps;
|
|
73
|
+
/**
|
|
74
|
+
* Freeze (sticky) this column without reordering.
|
|
75
|
+
* `true` / `"left"` stick to the scrollport left; `"right"` to the right.
|
|
76
|
+
* Middle columns are allowed; multiple frozen columns stack via cumulative offsets.
|
|
77
|
+
*/
|
|
78
|
+
frozen?: ColumnFreezeMeta;
|
|
79
|
+
}
|
|
80
|
+
interface Row<TData> {
|
|
81
|
+
/**
|
|
82
|
+
* Returns whether this row's cell is inside the active drag selection.
|
|
83
|
+
* Attached at render time by DataTableRow (optional outside that renderer).
|
|
84
|
+
* - `columnId` omitted: true when any visible cell in the row is selected.
|
|
85
|
+
* - `columnId` provided: checks only that column (row-span aware via merge origin).
|
|
86
|
+
*/
|
|
87
|
+
getIsCellDragSelected?: (columnId?: string) => boolean;
|
|
34
88
|
}
|
|
35
89
|
}
|
|
36
90
|
type DataTableCopyActions = {
|
|
@@ -171,6 +225,25 @@ type DataTableProps<T extends Record<string, unknown>> = {
|
|
|
171
225
|
estimateRowHeight?: number;
|
|
172
226
|
/** Virtualization overscan row count. Default 8 */
|
|
173
227
|
virtualOverscan?: number;
|
|
228
|
+
/**
|
|
229
|
+
* Enable drag-to-resize on column headers. Defaults to false.
|
|
230
|
+
* Opt out per column with `Column.resizable={false}` / `enableResizing: false`.
|
|
231
|
+
*/
|
|
232
|
+
enableColumnResize?: boolean;
|
|
233
|
+
/** Controlled column sizing map (`{ [columnId]: widthPx }`) */
|
|
234
|
+
columnSizing?: ColumnSizingState;
|
|
235
|
+
onColumnSizingChange?: OnChangeFn<ColumnSizingState>;
|
|
236
|
+
/**
|
|
237
|
+
* When to commit resize updates. Defaults to `"onChange"` (live while dragging).
|
|
238
|
+
* Use `"onEnd"` to update only after the pointer is released.
|
|
239
|
+
*/
|
|
240
|
+
columnResizeMode?: ColumnResizeMode;
|
|
241
|
+
/**
|
|
242
|
+
* Enable sticky freeze columns. Defaults to false.
|
|
243
|
+
* Mark columns with `Column.frozen` / `meta.frozen` (`true` | `"left"` | `"right"`).
|
|
244
|
+
* Does not reorder columns; offsets stack so frozen cells do not overlap.
|
|
245
|
+
*/
|
|
246
|
+
enableColumnFreeze?: boolean;
|
|
174
247
|
/**
|
|
175
248
|
* Optional UI part replacements for the unstyled DataTable renderer.
|
|
176
249
|
* Use with `createTable` / `Table.Column`, or pass columns directly to `DataTable`.
|
|
@@ -196,6 +269,8 @@ type DataTableClassNames = {
|
|
|
196
269
|
head?: string;
|
|
197
270
|
headRow?: string;
|
|
198
271
|
headCell?: string;
|
|
272
|
+
/** Column resize drag handle inside a header cell */
|
|
273
|
+
resizeHandle?: string;
|
|
199
274
|
body?: string;
|
|
200
275
|
emptyCell?: string;
|
|
201
276
|
virtualSpacer?: string;
|
|
@@ -257,7 +332,23 @@ type TableColumnProps<T extends Record<string, unknown>, K extends string = keyo
|
|
|
257
332
|
virtual?: boolean;
|
|
258
333
|
children?: ReactNode;
|
|
259
334
|
sortable?: boolean;
|
|
335
|
+
/** Initial / default column width in px (TanStack `size`) */
|
|
260
336
|
width?: number;
|
|
337
|
+
/** Minimum resize width in px. Defaults to the table min when omitted */
|
|
338
|
+
minWidth?: number;
|
|
339
|
+
/** Maximum resize width in px. Defaults to the table max when omitted */
|
|
340
|
+
maxWidth?: number;
|
|
341
|
+
/**
|
|
342
|
+
* When false, this column cannot be resized even if `enableColumnResize` is on.
|
|
343
|
+
* Defaults to true.
|
|
344
|
+
*/
|
|
345
|
+
resizable?: boolean;
|
|
346
|
+
/**
|
|
347
|
+
* Freeze (sticky) without changing column order.
|
|
348
|
+
* `true` / `"left"` → left edge; `"right"` → right edge.
|
|
349
|
+
* Requires `enableColumnFreeze`. Middle columns are allowed.
|
|
350
|
+
*/
|
|
351
|
+
frozen?: ColumnFreezeMeta;
|
|
261
352
|
align?: "left" | "center" | "right";
|
|
262
353
|
rowSpan?: boolean;
|
|
263
354
|
rowSpanKey?: string;
|
|
@@ -273,4 +364,4 @@ type TableProps<T extends Record<string, unknown>> = Omit<DataTableProps<T>, "co
|
|
|
273
364
|
children: ReactNode;
|
|
274
365
|
};
|
|
275
366
|
|
|
276
|
-
export { type
|
|
367
|
+
export { type ColumnFreezeColumnInput as C, DEFAULT_DATA_TABLE_LABELS as D, type PasteMode as P, type RowSelectionMode as R, type TableColumnProps as T, type ColumnFreezeMeta as a, type ColumnFreezeOffset as b, type ColumnFreezeSide as c, type DataTableClassNames as d, type DataTableCopyActions as e, type DataTableLabels as f, type DataTableProps as g, type DataTableSlots as h, type RowsPastePayload as i, type TableProps as j, buildColumnFreezeOffsets as k, getColumnFreezeStyle as l, resolveDataTableLabels as m, type CellEditType as n, resolveColumnFreezeSide as r };
|