@jielga/tmdatagrid 2.1.4 → 2.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/dist/index.d.ts +38 -2
- package/dist/index.js +1329 -1246
- package/dist/index.js.map +1 -1
- package/docs/cell-selection.md +1 -1
- package/docs/column-layout.md +13 -8
- package/docs/columns.md +57 -2
- package/docs/export.md +2 -2
- package/docs/filtering.md +105 -15
- package/docs/getting-started.md +40 -0
- package/docs/grouping.md +9 -6
- package/docs/loading-and-empty.md +29 -9
- package/docs/localization.md +130 -3
- package/docs/menu.md +1 -1
- package/docs/pagination.md +26 -7
- package/docs/row-details.md +36 -4
- package/docs/row-interaction.md +1 -1
- package/docs/row-selection.md +6 -7
- package/docs/scrolling.md +1 -1
- package/docs/server-side.md +3 -1
- package/docs/testing.md +18 -0
- package/docs/use-tm-data-grid.md +69 -34
- package/package.json +1 -1
- package/skills/appearance/SKILL.md +6 -4
- package/skills/appearance/references/labels.md +126 -0
- package/skills/cell-selection/SKILL.md +2 -2
- package/skills/columns/SKILL.md +42 -41
- package/skills/columns/references/columns-api.md +15 -1
- package/skills/data/SKILL.md +77 -50
- package/skills/editing/SKILL.md +1 -1
- package/skills/filtering/SKILL.md +71 -49
- package/skills/filtering/references/custom-filters.md +118 -0
- package/skills/getting-started/SKILL.md +37 -2
- package/skills/grouping/SKILL.md +16 -9
- package/skills/migrating-to-2/SKILL.md +1 -1
- package/skills/options/SKILL.md +131 -51
- package/skills/rows/SKILL.md +53 -31
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +12 -1
- package/skills/testing-components/SKILL.md +1 -1
- package/skills/testing-editing/SKILL.md +1 -1
- package/src/components/TMDataGridTable.tsx +241 -41
- package/src/core/autosize.ts +19 -7
- package/src/core/cellRange.ts +11 -2
- package/src/core/colSpan.ts +78 -0
- package/src/core/columnUtils.ts +7 -0
- package/src/core/filterOperators.ts +16 -1
- package/src/index.ts +4 -0
- package/src/useTMDataGrid.tsx +38 -0
package/skills/grouping/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ description: >
|
|
|
14
14
|
metadata:
|
|
15
15
|
type: core
|
|
16
16
|
library: '@jielga/tmdatagrid'
|
|
17
|
-
library_version: '2.
|
|
17
|
+
library_version: '2.2.0'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/react:packages/tmdatagrid/docs/grouping.md'
|
|
20
20
|
- 'Jielga/react:packages/tmdatagrid/docs/summary-row.md'
|
|
@@ -96,8 +96,8 @@ would pass a row that looks real but is the wrong one. Group rows therefore:
|
|
|
96
96
|
A group row's checkbox selects every record under it at any depth, including
|
|
97
97
|
records inside collapsed sub-groups, showing a tick once all are selected and a
|
|
98
98
|
dash while only some are. Only the records reach `rowSelection`; a group row is
|
|
99
|
-
never in it, so `getSelectedRowModel()` and
|
|
100
|
-
how the tree is arranged. Under `enableMultiRowSelection: false` group rows carry
|
|
99
|
+
never in it, so `getSelectedRowModel()` and `onRowSelectionChange` do not depend
|
|
100
|
+
on how the tree is arranged. Under `enableMultiRowSelection: false` group rows carry
|
|
101
101
|
no checkbox.
|
|
102
102
|
|
|
103
103
|
`getGroupDataRows(row)` returns every record under a group row, at any depth.
|
|
@@ -116,8 +116,11 @@ page. Rendering the whole tree is the grid's default mode in any case, so only
|
|
|
116
116
|
the pager is lost.
|
|
117
117
|
|
|
118
118
|
`isPagingActive(table, features)` is exported so a custom pager can grey itself
|
|
119
|
-
out the same way.
|
|
120
|
-
|
|
119
|
+
out the same way. There is no option to keep the built-in pager active while
|
|
120
|
+
grouped, and `manualGrouping` does not change that: the pager greys out whenever
|
|
121
|
+
`grouping` is non-empty. To have both, page on the server with
|
|
122
|
+
`manualPagination` and `manualGrouping`, and render the pager through the
|
|
123
|
+
Footer's `renderPagination` slot, ignoring `isPagingActive`.
|
|
121
124
|
|
|
122
125
|
## The summary row
|
|
123
126
|
|
|
@@ -197,7 +200,7 @@ out instead of paging the tree, so a footer count wired to `getPageCount()`
|
|
|
197
200
|
reports a number nobody can navigate to. Read
|
|
198
201
|
`isPagingActive(table, features)` before trusting the pager state.
|
|
199
202
|
|
|
200
|
-
Source: `packages/tmdatagrid/docs/grouping.md` (Grouping
|
|
203
|
+
Source: `packages/tmdatagrid/docs/grouping.md` (Grouping and pagination).
|
|
201
204
|
|
|
202
205
|
### HIGH Handing a group row to a row callback
|
|
203
206
|
|
|
@@ -224,7 +227,7 @@ const records = getGroupDataRows(groupRow).map((row) => row.original);
|
|
|
224
227
|
/>;
|
|
225
228
|
```
|
|
226
229
|
|
|
227
|
-
Source: `packages/tmdatagrid/docs/grouping.md` (Group rows
|
|
230
|
+
Source: `packages/tmdatagrid/docs/grouping.md` (Group rows).
|
|
228
231
|
|
|
229
232
|
### MEDIUM Totalling the page instead of the data
|
|
230
233
|
|
|
@@ -252,18 +255,22 @@ useTMDataGrid({
|
|
|
252
255
|
});
|
|
253
256
|
```
|
|
254
257
|
|
|
258
|
+
The built-in pager still greys out while `grouping` is set, so such a grid
|
|
259
|
+
renders its pager through `TMDataGrid.Footer`'s `renderPagination` slot and
|
|
260
|
+
ignores `state.isPagingActive`.
|
|
261
|
+
|
|
255
262
|
Source: `packages/tmdatagrid/docs/grouping.md` (Server-side grids).
|
|
256
263
|
|
|
257
264
|
## Reference
|
|
258
265
|
|
|
259
266
|
| Name | Kind | Type | Default | What it does |
|
|
260
267
|
| --- | --- | --- | --- | --- |
|
|
261
|
-
| `enableGrouping` | Table option | `boolean` | `true` | Group by and Ungroup menu items. Also a column option. |
|
|
268
|
+
| `enableGrouping` | Table option | `boolean` | `true`; `false` under `manualPagination` | Group by and Ungroup menu items, and the tree lane. Also a column option. |
|
|
262
269
|
| `groupedColumnMode` | Table option | `"reorder" \| "remove" \| false` | `"remove"` | Whether a grouped column leaves the grid or moves to the front. |
|
|
263
270
|
| `manualGrouping` | Table option | `boolean` | `false` | The rows arrive grouped. Required to group a server-paged grid. |
|
|
264
271
|
| `initialState.grouping` | Table option | `string[]` | `[]` | Column ids grouped at mount. A settings slice, so it persists. |
|
|
265
272
|
| `aggregationFn` | Column option | `TMDataGridAggregationName \| fn` | – | How a column fills in its group cells. Unset leaves them blank. |
|
|
266
|
-
| `aggregatedCell` | Column option | `(ctx) => ReactNode` |
|
|
273
|
+
| `aggregatedCell` | Column option | `(ctx) => ReactNode` | `cell` over the aggregate when `aggregationFn` is set, else blank | Renders a group row's value differently from a data row's. |
|
|
267
274
|
| `footer` | Column option | `(ctx) => ReactNode` | – | Renders this column's summary cell. Defining one adds the row. |
|
|
268
275
|
| `aggregateColumn` | Export | `({ table, columnId, fn }) => unknown` | `fn: "sum"` | Aggregates over every filtered row, all pages. |
|
|
269
276
|
| `TMDataGridAggregationName` | Export | type | – | The registered function names. |
|
|
@@ -15,7 +15,7 @@ description: >
|
|
|
15
15
|
metadata:
|
|
16
16
|
type: lifecycle
|
|
17
17
|
library: '@jielga/tmdatagrid'
|
|
18
|
-
library_version: '2.
|
|
18
|
+
library_version: '2.2.0'
|
|
19
19
|
sources:
|
|
20
20
|
- 'Jielga/react:packages/tmdatagrid/docs/migrating-to-2.md'
|
|
21
21
|
- 'Jielga/react:packages/tmdatagrid/src/index.ts'
|
package/skills/options/SKILL.md
CHANGED
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
name: options
|
|
3
3
|
description: >
|
|
4
4
|
useTMDataGrid options, return value and state persistence. Covers passthrough
|
|
5
|
-
of TanStack TableOptions,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
of TanStack TableOptions, every default the grid changes (globalFilterFn,
|
|
6
|
+
groupedColumnMode, autoResetExpanded, autoResetPageIndex,
|
|
7
|
+
defaultColumn.minSize), the default initialState, the meta object (loading,
|
|
8
|
+
noResultsLabel, rowHeight, totalRowCount), the grid's own options (persist,
|
|
9
|
+
labels, editing, filters, exportOptions, enableColumnOrdering,
|
|
10
|
+
enablePagination, resetPageOnQueryChange, enableRowNumbers, selectionMode,
|
|
11
|
+
showSelectedBackground, cellSelection, renderDetails, overscan,
|
|
12
|
+
quickSearchMode), persist with dataKey/settingsKey slices and storageMode, the
|
|
10
13
|
returned api (table, ui, edit, features, labels, resetSettings, scrollToRow),
|
|
11
|
-
ui
|
|
12
|
-
Load when configuring the hook,
|
|
13
|
-
|
|
14
|
+
ui actions, and reading grid state with useSelector over table.store, since
|
|
15
|
+
table.getState() does not exist in v9. Load when configuring the hook, looking
|
|
16
|
+
up an option's default, persisting layout or filters, or reacting to grid
|
|
17
|
+
state from a parent.
|
|
14
18
|
metadata:
|
|
15
19
|
type: core
|
|
16
20
|
library: '@jielga/tmdatagrid'
|
|
17
|
-
library_version: '2.
|
|
21
|
+
library_version: '2.2.0'
|
|
18
22
|
sources:
|
|
19
23
|
- 'Jielga/react:packages/tmdatagrid/docs/use-tm-data-grid.md'
|
|
20
24
|
- 'Jielga/react:packages/tmdatagrid/docs/persistence.md'
|
|
@@ -28,7 +32,8 @@ Creates the table instance and the state used by the grid interface.
|
|
|
28
32
|
|
|
29
33
|
```tsx
|
|
30
34
|
const grid = useTMDataGrid<TData>(options);
|
|
31
|
-
// { table, ui, edit, features, labels,
|
|
35
|
+
// { table, ui, edit, features, labels, filters, exportOptions, renderDetails,
|
|
36
|
+
// renderDetailsEstHeight, overscan, resetSettings, scrollToRow }
|
|
32
37
|
```
|
|
33
38
|
|
|
34
39
|
The signature is
|
|
@@ -42,43 +47,77 @@ All TanStack `TableOptions` are supported and passed through unchanged, includin
|
|
|
42
47
|
flags and `rowCount`. The `features` option is supplied internally and cannot be
|
|
43
48
|
overridden.
|
|
44
49
|
|
|
45
|
-
`persist`, `
|
|
46
|
-
`
|
|
47
|
-
|
|
50
|
+
The grid defines these options itself: `persist`, `labels`, `editing`,
|
|
51
|
+
`filters`, `exportOptions`, `enableColumnOrdering`, `enablePagination`,
|
|
52
|
+
`resetPageOnQueryChange`, `enableRowNumbers`, `selectionMode`,
|
|
53
|
+
`showSelectedBackground`, `defaultHighlightedRowId`, `onHighlightedRowChange`,
|
|
54
|
+
`cellSelection`, `onFocusedCellChange`, `renderDetails`,
|
|
55
|
+
`renderDetailsEstHeight`, `detailsColumnPosition`, `overscan`,
|
|
56
|
+
`quickSearchMode` and `enableMatchHighlighting`. The table below marks them
|
|
57
|
+
"Defined by the grid"; every other row is a TanStack option, listed where the
|
|
58
|
+
grid changes its default or where it decides something visible. A TanStack
|
|
59
|
+
default the grid changes reads, for example, `"remove"` (grid default;
|
|
60
|
+
TanStack: `"reorder"`). A TanStack option that is not listed passes through
|
|
61
|
+
with TanStack's own default.
|
|
48
62
|
|
|
49
63
|
| Option | Type | Default | Description |
|
|
50
64
|
| --- | --- | --- | --- |
|
|
51
|
-
| `data` | `TData[]` | – | Row data.
|
|
52
|
-
| `columns` | `ColumnDef[]` | – | Created with `createTMDataGridColumnHelper`. |
|
|
53
|
-
| `getRowId` | `(row, index) => string` | Row index |
|
|
65
|
+
| `data` | `TData[]` | – | Row data. When the reference changes the table reprocesses the row models, so keep it stable with `useMemo`; a fresh `[]` for the empty case belongs in a module-scope constant. |
|
|
66
|
+
| `columns` | `ColumnDef[]` | – | Created with `createTMDataGridColumnHelper`. Define them outside the component. |
|
|
67
|
+
| `getRowId` | `(row, index, parent?) => string` | Row index | The id that row selection, expansion, row pinning and editing are keyed by. The index points at another record after a sort or a refetch, so return the entity id. Required once `editing` is set. |
|
|
68
|
+
| `defaultColumn` | `Partial<ColumnDef>` | `{ minSize: 80 }` (grid default; TanStack: `{}`) | Defaults merged under every column. The grid sets `filterFn: "tmDataGrid"` and clears `aggregationFn` and `aggregatedCell` on every column, so those three keys have no effect here; a value on the column wins. |
|
|
54
69
|
| `enableRowSelection` | `boolean \| (row) => boolean` | `true` | `false` removes row selection and its checkbox column. |
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
70
|
+
| `enableMultiRowSelection` | `boolean \| (row) => boolean` | `true` | `false` removes the select-all checkbox and limits the selection to one row. |
|
|
71
|
+
| `selectionMode` | `"checkbox" \| "row" \| "checkboxAndHighlight" \| "highlight"` | `"checkbox"` | What selecting looks like and what a bare row click does. Defined by the grid, see the `rows` skill. |
|
|
72
|
+
| `showSelectedBackground` | `boolean` | On for `"row"`, off for `"checkbox"` | Determines whether selected rows take a background tint, coloured by `--dg-row-selected-bg`. Defined by the grid, see the `rows` skill. |
|
|
73
|
+
| `defaultHighlightedRowId` | `string \| null` | – | Row highlighted on mount, under a mode with a highlight. Read once, like `initialState`. Defined by the grid. |
|
|
74
|
+
| `onHighlightedRowChange` | `(rowId: string \| null) => void` | – | Follows the highlighted row, from clicks and from `ui.actions.setHighlightedRow`. Defined by the grid. |
|
|
75
|
+
| `enableSorting` | `boolean` | `true` | `false` removes the sort indicator, the sort menu items and click-to-sort. Also a column option. See the `columns` skill. |
|
|
76
|
+
| `enableMultiSort` | `boolean` | `true` for accessor columns | Shift+click on a header adds a sort instead of replacing it. Also a column option. See the `columns` skill. |
|
|
77
|
+
| `maxMultiSortColCount` | `number` | `Number.MAX_SAFE_INTEGER` | How many sorts are kept; past it the oldest is dropped. |
|
|
78
|
+
| `enableColumnFilters` | `boolean` | `true` | `false` removes the filter menu item, the `FilterButton`, the header filter row and the panel's column list, and disables the panel's "Add filter" button. Filters already in state still apply. See the `filtering` skill. |
|
|
79
|
+
| `enableGlobalFilter` | `boolean` | `true` | `false` removes `Search`. Also a column option, removing one column from the search. See the `filtering` skill. |
|
|
80
|
+
| `globalFilterFn` | filter fn \| name | `"tmDataGridFuzzy"`; `"includesString"` under `quickSearchMode: "contains"` (grid default; TanStack: `"auto"`) | How the quick search matches. An explicit value also switches the fuzzy rank ordering off. |
|
|
81
|
+
| `enableHiding` | `boolean` | `true` | `false` removes the Hide column item, the Manage columns submenu and the column chooser. Also a column option. |
|
|
60
82
|
| `enableColumnPinning` | `boolean` | `true` | Enables pinning for the table. `false` removes the pin menu items; the generated lanes stay pinned. |
|
|
61
|
-
| `enableColumnResizing` | `boolean` | `true` |
|
|
62
|
-
| `enableColumnOrdering` | `boolean` | `true` | Enables header dragging and the move menu items. Defined by the grid. |
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
83
|
+
| `enableColumnResizing` | `boolean` | `true` | With `false` the divider is displayed but cannot be dragged, and double-click autosize and the Autosize menu item are removed. Also a column option, as `enableResizing`. |
|
|
84
|
+
| `enableColumnOrdering` | `boolean` | `true` | Enables header dragging and the move menu items. Defined by the grid, see the `columns` skill. |
|
|
85
|
+
| `enableGrouping` | `boolean` | `true`; `false` under `manualPagination` (grid default; TanStack: `true`) | `false` removes the Group by and Ungroup menu items and the tree lane. Also a column option. See the `grouping` skill. |
|
|
86
|
+
| `groupedColumnMode` | `"remove" \| "reorder" \| false` | `"remove"` (grid default; TanStack: `"reorder"`) | What happens to a column the rows are grouped by: `"remove"` takes it out of the grid, `"reorder"` moves it to the front, `false` leaves it in place. See the `grouping` skill. |
|
|
87
|
+
| `enablePagination` | `boolean` | `false` | Enables client-side paging and the `Footer` pager. Implied by `manualPagination`. Defined by the grid, see the `data` skill. |
|
|
88
|
+
| `resetPageOnQueryChange` | `boolean` | `true` | Returns to the first page when a column filter, the quick search, the sorting or the grouping changes through the table. A `data` change does not count. Defined by the grid, see the `data` skill. |
|
|
89
|
+
| `autoResetPageIndex` | `boolean` | `false` (grid default; TanStack: `!manualPagination`) | TanStack's return to the first page on every `data` change. Off, since `resetPageOnQueryChange` covers the query. |
|
|
90
|
+
| `autoResetExpanded` | `boolean` | `false` (grid default; TanStack: `!manualExpanding`) | TanStack's collapse of every expanded row on a `data` change. Off, so open details panels survive a refetch. |
|
|
91
|
+
| `manualFiltering`, `manualSorting`, `manualGrouping`, `manualPagination` | `boolean` | `false` | The server does that step and the grid shows `data` as given. `manualPagination` also implies `enablePagination`. See the `server-side` skill. |
|
|
92
|
+
| `rowCount` | `number` | – | The total row count under `manualPagination`, read by the pager. |
|
|
93
|
+
| `enableRowNumbers` | `boolean` | `false` | The row-number gutter, outermost left. Defined by the grid, see the `rows` skill. |
|
|
94
|
+
| `enableRowPinning` | `boolean \| (row) => boolean` | `false` (grid default; TanStack: `true`) | Rows can be pinned to sticky edge blocks with `row.pin()`. See the `rows` skill. |
|
|
95
|
+
| `quickSearchMode` | `"fuzzy" \| "contains"` | `"fuzzy"` | How `Search` matches. Fuzzy forgives typos and orders unsorted results by match quality; `"contains"` is plain substring matching. Defined by the grid, see the `filtering` skill. |
|
|
96
|
+
| `enableMatchHighlighting` | `boolean` | `false` | Cells mark the matched text while a contains-family filter or the quick search is active. Defined by the grid, see the `filtering` skill. |
|
|
97
|
+
| `renderDetails` | `({ row, table }) => ReactNode` | – | Panel rendered under an expanded row, spanning every column. Setting it turns row details on and adds the pinned chevron lane. Defined by the grid, see the `rows` skill. |
|
|
98
|
+
| `renderDetailsEstHeight` | `number` | `160` | What the virtualizer assumes for a panel it has not measured yet. Panels are measured once mounted, so an approximation is enough. Defined by the grid. |
|
|
99
|
+
| `detailsColumnPosition` | `"left" \| "right"` | `"left"` | Which edge the details lane is pinned to. `"right"` places it after every column, inside the edit lane. Defined by the grid, see the `rows` skill. |
|
|
100
|
+
| `cellSelection` | `"none" \| "single" \| "range"` | `"none"` | Cell cursor and, under `"range"`, a selectable rectangle with Ctrl+C and CSV export. Defined by the grid, see the `cell-selection` skill. |
|
|
101
|
+
| `onFocusedCellChange` | `(cell: TMDataGridCellPosition \| null) => void` | – | Called whenever the focused cell moves, by key, click or `setFocusedCell`. Defined by the grid. |
|
|
102
|
+
| `overscan` | `number` | `6` | Rows the virtualizer keeps mounted above and below the viewport. Raise it if fast scrolling flashes blank rows, lower it when rows are expensive to render. Defined by the grid. |
|
|
103
|
+
| `columnResizeMode` | `"onChange" \| "onEnd"` | `"onEnd"` | When a resize drag writes `columnSizing`. The grid paints a running drag itself either way; `"onChange"` also publishes a width on every pointer move, which re-renders the grid with each of them. |
|
|
104
|
+
| `initialState` | `Partial<TableState>` | – | Starting state, read once on mount. Merged over the grid defaults below. |
|
|
105
|
+
| `state` | `Partial<TableState>` | – | Controlled state. Each slice requires its `onXChange`. See below. |
|
|
106
|
+
| `atoms` | `Partial<Record<slice, Atom>>` | – | External atoms owning state slices. No callback required. Takes precedence over `state`. |
|
|
107
|
+
| `meta` | `TMDataGridTableMeta` | `{}` | Grid configuration. See below. |
|
|
108
|
+
| `filters` | `TMDataGridFiltersOptions` | `{ surface: "popup" }` | Where the filter controls go - a popup, a sidebar, the column headers, or nowhere. Defined by the grid, see the `filtering` skill. |
|
|
109
|
+
| `exportOptions` | `TMDataGridExportOptions` | `csvExcelFormat()`, `"export"`, headers on, `"visible"` columns | The export's `format`, `fileName`, `includeHeaders` and `columns`. Defined by the grid, see the `data` skill. |
|
|
110
|
+
| `editing` | `TMDataGridEditingOptions` | off | Turns editing on. `mode` picks what counts as a commit and `draft` whether edits collect in the draft store. Requires `getRowId`. Defined by the grid, see the `editing` skill. |
|
|
111
|
+
| `persist` | `TMDataGridPersistence` | – | State persistence. Defined by the grid, see below. |
|
|
112
|
+
| `labels` | `TMDataGridLabelsOverride` | English | Overrides for the grid's strings and `aria-label`s. Defined by the grid, see the `appearance` skill. |
|
|
74
113
|
|
|
75
114
|
### Default initial state
|
|
76
115
|
|
|
77
116
|
| Slice | Default |
|
|
78
117
|
| --- | --- |
|
|
79
|
-
| `pagination` | `{ pageIndex: 0, pageSize: 25 }
|
|
80
|
-
| `columnPinning.start` | The checkbox
|
|
81
|
-
| `
|
|
118
|
+
| `pagination` | `{ pageIndex: 0, pageSize: 25 }`. Inert until pagination is enabled |
|
|
119
|
+
| `columnPinning.start` | The row number, checkbox, tree and details columns, followed by any columns you provide. The details column moves to `end` under `detailsColumnPosition: "right"` |
|
|
120
|
+
| `columnPinning.end` | Any columns you provide, then the details column under `detailsColumnPosition: "right"`, then the edit column |
|
|
82
121
|
|
|
83
122
|
### Controlled state
|
|
84
123
|
|
|
@@ -113,10 +152,10 @@ const grid = useTMDataGrid({
|
|
|
113
152
|
|
|
114
153
|
| Field | Type | Default | Description |
|
|
115
154
|
| --- | --- | --- | --- |
|
|
116
|
-
| `loading` | `boolean` |
|
|
117
|
-
| `noResultsLabel` | `string` | `
|
|
155
|
+
| `loading` | `boolean` | `false` | While `true` and the view is empty, a loader replaces the empty state; `renderEmptyState` is not called. Rows on screen stay. See the `data` skill. |
|
|
156
|
+
| `noResultsLabel` | `string` | `labels.noResults` | The text shown when a filter or the search leaves no rows. |
|
|
118
157
|
| `rowHeight` | `number` | From `size` | Row height in px. Overrides the size scale. |
|
|
119
|
-
| `totalRowCount` | `number` | – | Unfiltered total used by `SummaryCount`.
|
|
158
|
+
| `totalRowCount` | `number` | – | Unfiltered total used by `SummaryCount`. Without it a `manualFiltering` or `manualPagination` grid shows the shown count alone. |
|
|
120
159
|
|
|
121
160
|
## persist
|
|
122
161
|
|
|
@@ -194,32 +233,58 @@ Source: `packages/tmdatagrid/docs/persistence.md` (Behaviour).
|
|
|
194
233
|
| --- | --- | --- |
|
|
195
234
|
| `table` | `Table<TMDataGridFeatures, TData>` | The TanStack table instance. |
|
|
196
235
|
| `ui` | `TMDataGridUiStore`: `Store<TMDataGridUiState, TMDataGridUiActions>` | State of the filter and column panels. |
|
|
236
|
+
| `filters` | `TMDataGridFiltersSettings` | The `filters` option with its defaults filled in. |
|
|
237
|
+
| `exportOptions` | `TMDataGridExportSettings` | The `exportOptions` option with its defaults filled in. |
|
|
197
238
|
| `edit` | `TMDataGridEditApi` | The edit engine, inert until `editing` is set. See the `editing` skill. |
|
|
198
239
|
| `features` | `TMDataGridFeatureFlags` | Table-level feature switches, re-read on each render. |
|
|
199
240
|
| `labels` | `TMDataGridLabels` | The resolved label set, overrides merged over English. |
|
|
241
|
+
| `renderDetails` | `TMDataGridDetailsRenderer<TData> \| undefined` | The detail renderer, passed through for `TMDataGrid.Table` to call. |
|
|
242
|
+
| `renderDetailsEstHeight` | `number` | The estimate, resolved to its default when the option was not set. |
|
|
243
|
+
| `overscan` | `number` | The overscan, resolved to its default when the option was not set. |
|
|
200
244
|
| `resetSettings` | `() => void` | Puts the settings state back to a clean first visit. |
|
|
201
245
|
| `scrollToRow` | `({ rowId, align? }) => boolean` | Scrolls a row into view through the virtualizer. `false` when the row is not in the current view. |
|
|
202
246
|
|
|
203
|
-
|
|
204
|
-
|
|
247
|
+
`table` is `TMDataGridTable<TData>`, TanStack's core `Table` type. It has no
|
|
248
|
+
`getState()` (that method does not exist in TanStack Table v9) and `table.state`
|
|
249
|
+
is not part of the type; state lives in `table.store`.
|
|
250
|
+
|
|
251
|
+
### Reading state
|
|
252
|
+
|
|
253
|
+
`table.store` and `ui` are TanStack stores. Read a slice with `useSelector`
|
|
254
|
+
from `@tanstack/react-store`, which subscribes the component to what the
|
|
255
|
+
selector returns:
|
|
205
256
|
|
|
206
257
|
```tsx
|
|
207
258
|
import { useSelector } from "@tanstack/react-store";
|
|
208
259
|
|
|
209
260
|
const selectedCount = useSelector(
|
|
210
261
|
grid.table.store,
|
|
211
|
-
(
|
|
262
|
+
() => grid.table.getSelectedRowModel().rows.length,
|
|
212
263
|
);
|
|
213
|
-
|
|
264
|
+
const isGrouped = useSelector(grid.table.store, (state) =>
|
|
265
|
+
state.grouping.includes("department"),
|
|
266
|
+
);
|
|
267
|
+
const pageIndex = useSelector(grid.table.store, (state) => state.pagination.pageIndex);
|
|
214
268
|
const filterPanelOpen = useSelector(grid.ui, (state) => state.filterPanelOpen);
|
|
215
269
|
```
|
|
216
270
|
|
|
271
|
+
`grid.table.store.state` is a plain read and does not subscribe the component.
|
|
272
|
+
A bare read is stale in any component that does not call `useTMDataGrid`
|
|
273
|
+
itself, and under the React Compiler also in the one that does; `useSelector`
|
|
274
|
+
subscribes either way. A table or column getter such as
|
|
275
|
+
`table.getSelectedRowModel()` or `column.getIsGrouped()` is a plain read as
|
|
276
|
+
well; call it inside a selector, as above. `getTMDataGridPaginationApi(table)`
|
|
277
|
+
is a snapshot too; wrap it in `useSelector` or use the `state` the Footer's
|
|
278
|
+
`renderPagination` slot receives.
|
|
279
|
+
|
|
217
280
|
### ui actions
|
|
218
281
|
|
|
219
282
|
| Action | Signature |
|
|
220
283
|
| --- | --- |
|
|
221
284
|
| `openFilterPanel` | `(columnId?: string \| null) => void` |
|
|
222
285
|
| `closeFilterPanel` | `() => void` |
|
|
286
|
+
| `openExportPicker` | `(request: TMDataGridExportPickerRequest) => void` |
|
|
287
|
+
| `closeExportPicker` | `() => void` |
|
|
223
288
|
| `focusPanelFilter` | `(columnId: string \| null) => void` |
|
|
224
289
|
| `focusHeaderFilter` | `(columnId: string \| null) => void` |
|
|
225
290
|
| `startColumnDrag` | `(columnId: string) => void` |
|
|
@@ -232,29 +297,41 @@ const filterPanelOpen = useSelector(grid.ui, (state) => state.filterPanelOpen);
|
|
|
232
297
|
The last two move the cell cursor and the selected rectangle under
|
|
233
298
|
`cellSelection`; DOM focus follows `focusedCell` and scrolls its row into view.
|
|
234
299
|
|
|
235
|
-
`startColumnDrag` / `endColumnDrag` are called by the header cells while a
|
|
236
|
-
`ui.draggedColumnId` holds the column being
|
|
237
|
-
unreadable until the drop.
|
|
300
|
+
`startColumnDrag` / `endColumnDrag` are called by the header cells while a
|
|
301
|
+
column is being dragged, and `ui.state.draggedColumnId` holds the column being
|
|
302
|
+
moved - browsers keep `dataTransfer` unreadable until the drop.
|
|
238
303
|
|
|
239
304
|
`openColumnFilter(grid, columnId)` combines the two steps the column menu uses:
|
|
240
|
-
add an empty filter row for the column if none exists, then open the panel
|
|
305
|
+
add an empty filter row for the column if none exists, then open the panel on
|
|
306
|
+
it, or focus the column's header control under `filters.inHeader`.
|
|
241
307
|
|
|
242
308
|
## Common mistakes
|
|
243
309
|
|
|
244
310
|
### Reading store state during render
|
|
245
311
|
|
|
246
|
-
`grid.table.store.state` is a plain read - it does not subscribe the component
|
|
247
|
-
|
|
312
|
+
`grid.table.store.state` is a plain read - it does not subscribe the component.
|
|
313
|
+
A bare read is stale in any component that does not call `useTMDataGrid`
|
|
314
|
+
itself, and under the React Compiler also in the one that does; `useSelector`
|
|
315
|
+
subscribes either way. The same holds for every table and column getter called
|
|
316
|
+
outside a selector.
|
|
248
317
|
|
|
249
318
|
```tsx
|
|
250
319
|
// Wrong - never re-renders when the selection changes.
|
|
251
320
|
const count = Object.keys(grid.table.store.state.rowSelection).length;
|
|
321
|
+
// Wrong - a getter outside a selector is a snapshot.
|
|
322
|
+
const grouped = grid.table.getColumn("department")!.getIsGrouped();
|
|
323
|
+
// Wrong - `getState()` does not exist in TanStack Table v9.
|
|
324
|
+
const sorting = grid.table.getState().sorting;
|
|
252
325
|
|
|
253
326
|
// Right.
|
|
254
327
|
const count = useSelector(
|
|
255
328
|
grid.table.store,
|
|
256
329
|
(state) => Object.keys(state.rowSelection).length,
|
|
257
330
|
);
|
|
331
|
+
const grouped = useSelector(grid.table.store, (state) =>
|
|
332
|
+
state.grouping.includes("department"),
|
|
333
|
+
);
|
|
334
|
+
const sorting = useSelector(grid.table.store, (state) => state.sorting);
|
|
258
335
|
```
|
|
259
336
|
|
|
260
337
|
### persist object built during render
|
|
@@ -273,4 +350,7 @@ Include a tenant or user identifier in the key.
|
|
|
273
350
|
|
|
274
351
|
A new array identity on each render re-runs the row model. `data={rows ?? []}`
|
|
275
352
|
allocates a fresh `[]` every render when `rows` is undefined - hoist the empty
|
|
276
|
-
array to a module-scope constant or `useMemo` the expression.
|
|
353
|
+
array to a module-scope constant or `useMemo` the expression. Under `editing`
|
|
354
|
+
the cost is higher: every new `data` identity drops the open drafts of the rows
|
|
355
|
+
it no longer contains, so a transient `[]` while refetching discards every
|
|
356
|
+
draft.
|
package/skills/rows/SKILL.md
CHANGED
|
@@ -17,7 +17,7 @@ description: >
|
|
|
17
17
|
metadata:
|
|
18
18
|
type: core
|
|
19
19
|
library: '@jielga/tmdatagrid'
|
|
20
|
-
library_version: '2.
|
|
20
|
+
library_version: '2.2.0'
|
|
21
21
|
sources:
|
|
22
22
|
- 'Jielga/react:packages/tmdatagrid/docs/row-selection.md'
|
|
23
23
|
- 'Jielga/react:packages/tmdatagrid/docs/row-interaction.md'
|
|
@@ -37,8 +37,8 @@ cell cursors and ranges are `cell-selection`.
|
|
|
37
37
|
## Selection
|
|
38
38
|
|
|
39
39
|
`selectionMode` sets what selecting looks like **and** what a bare row click
|
|
40
|
-
does.
|
|
41
|
-
|
|
40
|
+
does. A bare click either toggles the selection or moves the highlight, never
|
|
41
|
+
both.
|
|
42
42
|
|
|
43
43
|
| Mode | Checkbox column | Row click |
|
|
44
44
|
| --- | --- | --- |
|
|
@@ -51,8 +51,8 @@ multi-selection or move a highlight, but not both.
|
|
|
51
51
|
const grid = useTMDataGrid({ data, columns, selectionMode: "row" });
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
The first two write to TanStack's `rowSelection`, so
|
|
55
|
-
`
|
|
54
|
+
The first two write to TanStack's `rowSelection`, so `getSelectedRowModel()`
|
|
55
|
+
and `onRowSelectionChange` behave the same either way. Under
|
|
56
56
|
`"row"` the click follows desktop-list conventions: a plain click
|
|
57
57
|
makes the selection this row, Ctrl/Cmd toggles it and leaves the rest, Shift
|
|
58
58
|
selects the range from the anchor, Ctrl+Shift adds that range. Rows are
|
|
@@ -61,7 +61,7 @@ focusable in this mode, and Space or Enter toggles the focused row.
|
|
|
61
61
|
`enableRowSelection: false` removes the checkbox column and row-click selection
|
|
62
62
|
in any mode.
|
|
63
63
|
|
|
64
|
-
### The
|
|
64
|
+
### The highlighted row
|
|
65
65
|
|
|
66
66
|
The highlight is state of its own, not a slice of `rowSelection`. That is what
|
|
67
67
|
lets `"checkboxAndHighlight"` run both at once: tick rows for a bulk action,
|
|
@@ -81,8 +81,9 @@ const grid = useTMDataGrid({
|
|
|
81
81
|
### Reading a selection
|
|
82
82
|
|
|
83
83
|
Read it through the table store rather than by calling the method directly.
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
A bare read is stale in any component that does not call `useTMDataGrid`
|
|
85
|
+
itself, and under the React Compiler also in the one that does; `useSelector`
|
|
86
|
+
subscribes either way.
|
|
86
87
|
|
|
87
88
|
```tsx
|
|
88
89
|
import { useSelector } from "@tanstack/react-store";
|
|
@@ -160,9 +161,10 @@ the row with `data-context-menu` while its menu is open, so an action meant for
|
|
|
160
161
|
a multi-selection reads `table` and falls back to the clicked row.
|
|
161
162
|
|
|
162
163
|
Under `cellSelection: "range"` the grid has its own items for this menu: copy,
|
|
163
|
-
export and include headers. `internalItems`
|
|
164
|
-
over the composition
|
|
165
|
-
it and the grid
|
|
164
|
+
export and include headers. `internalItems` holds those items, and **using it
|
|
165
|
+
takes over the composition**. Place it, and the menu is exactly what you
|
|
166
|
+
returned. Omit it, and the grid renders its items above a divider and yours
|
|
167
|
+
below.
|
|
166
168
|
|
|
167
169
|
```tsx
|
|
168
170
|
renderRowContextMenu={({ row, internalItems }) => (
|
|
@@ -232,12 +234,14 @@ const grid = useTMDataGrid({
|
|
|
232
234
|
});
|
|
233
235
|
```
|
|
234
236
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
The panel opens below the row's cells, which stay where they are; there is no
|
|
238
|
+
mode in which a panel replaces the row. Each panel is measured, so heights need
|
|
239
|
+
not be uniform. `renderDetailsEstHeight` (default `160`) is what the virtualizer
|
|
240
|
+
assumes for one it has not measured yet; set it to the typical panel height.
|
|
241
|
+
`DETAILS_COLUMN_ID` is a generated chevron lane. It is pinned left, after the
|
|
242
|
+
checkbox and tree lanes; under `detailsColumnPosition: "right"` it is pinned
|
|
243
|
+
right, inside the edit lane. It cannot be hidden, moved, resized or unpinned.
|
|
244
|
+
Its header opens and closes every panel.
|
|
241
245
|
|
|
242
246
|
Which rows are open is TanStack's own `expanded` state, so anything can open
|
|
243
247
|
one - `row.toggleExpanded()` from a menu item, `initialState.expanded`,
|
|
@@ -246,6 +250,13 @@ is a cell spanning the row, not a row: `aria-rowcount` still counts records, and
|
|
|
246
250
|
a click inside it does not select the row underneath. Group rows have no panel;
|
|
247
251
|
expanding one opens its children.
|
|
248
252
|
|
|
253
|
+
Rows are virtualized. A row that leaves the viewport and the `overscan`
|
|
254
|
+
unmounts, and its panel unmounts with it, so state held inside the panel is
|
|
255
|
+
lost; keep such state outside the grid, keyed by `row.id`. `renderDetails` runs
|
|
256
|
+
on every render of the body, so give a heavy panel a `memo` component and pass
|
|
257
|
+
it `row.original`, not the row. Key a stateful child by `row.id`; that is stable
|
|
258
|
+
only when `getRowId` returns the entity id.
|
|
259
|
+
|
|
249
260
|
## Pinning and numbering
|
|
250
261
|
|
|
251
262
|
Two independent lanes at the edges.
|
|
@@ -264,7 +275,7 @@ There is no built-in pin gesture and no pin icon. Build one from TanStack's own
|
|
|
264
275
|
either as a display column whose cell is a pin button or in the row context
|
|
265
276
|
menu. Read the pinned state through a subscription
|
|
266
277
|
(`useSelector(row.table.store, () => row.getIsPinned())`) rather than calling it
|
|
267
|
-
in a component body
|
|
278
|
+
in a component body. The `row` identity survives a pin, so the React Compiler
|
|
268
279
|
would cache the call and the icon would never change. Whichever control you
|
|
269
280
|
build, include unpin in it. Pinned rows leave the scrolling order and render in
|
|
270
281
|
sticky blocks: top under the header, bottom above the summary row.
|
|
@@ -300,13 +311,13 @@ Correct:
|
|
|
300
311
|
rowStyle={() => ({ "--row-bg": "pink" })}
|
|
301
312
|
```
|
|
302
313
|
|
|
303
|
-
Source: `packages/tmdatagrid/docs/row-styling.md` (Set
|
|
314
|
+
Source: `packages/tmdatagrid/docs/row-styling.md` (Set the row background).
|
|
304
315
|
|
|
305
316
|
### CRITICAL Reading the selection without subscribing
|
|
306
317
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
then never changes.
|
|
318
|
+
A bare read is stale in any component that does not call `useTMDataGrid`
|
|
319
|
+
itself, and under the React Compiler also in the one that does; `useSelector`
|
|
320
|
+
subscribes either way. A stale count renders once and then never changes.
|
|
310
321
|
|
|
311
322
|
Wrong:
|
|
312
323
|
|
|
@@ -327,8 +338,8 @@ Source: `packages/tmdatagrid/docs/row-selection.md` (Acting on a selection).
|
|
|
327
338
|
### HIGH Looking for the highlight in `rowSelection`
|
|
328
339
|
|
|
329
340
|
The highlight is separate state, which is what lets `"checkboxAndHighlight"`
|
|
330
|
-
run both at once. It never appears in `rowSelection
|
|
331
|
-
|
|
341
|
+
run both at once. It never appears in `rowSelection` or
|
|
342
|
+
`getSelectedRowModel()`.
|
|
332
343
|
|
|
333
344
|
Wrong:
|
|
334
345
|
|
|
@@ -343,7 +354,7 @@ Correct:
|
|
|
343
354
|
const current = useSelector(grid.ui, (state) => state.highlightedRowId);
|
|
344
355
|
```
|
|
345
356
|
|
|
346
|
-
Source: `packages/tmdatagrid/docs/row-selection.md` (The
|
|
357
|
+
Source: `packages/tmdatagrid/docs/row-selection.md` (The highlighted row).
|
|
347
358
|
|
|
348
359
|
### HIGH Expecting a click handler to replace the built-in behaviour
|
|
349
360
|
|
|
@@ -382,18 +393,29 @@ written as though every row reaches it silently skips them.
|
|
|
382
393
|
|
|
383
394
|
Source: `packages/tmdatagrid/docs/row-interaction.md`, `packages/tmdatagrid/docs/row-pinning.md`.
|
|
384
395
|
|
|
385
|
-
### MEDIUM
|
|
396
|
+
### MEDIUM Keeping state inside a details panel
|
|
386
397
|
|
|
387
|
-
|
|
388
|
-
|
|
398
|
+
A panel unmounts with its row when the row leaves the virtual window, so a form
|
|
399
|
+
or an accordion inside `renderDetails` loses its state on a long scroll and
|
|
400
|
+
comes back reset.
|
|
389
401
|
|
|
390
|
-
Correct:
|
|
402
|
+
Correct: hold the state outside the grid, keyed by `row.id`, and pass it in.
|
|
391
403
|
|
|
392
404
|
```tsx
|
|
393
|
-
|
|
405
|
+
const [drafts, setDrafts] = useState<Record<string, Draft>>({});
|
|
406
|
+
useTMDataGrid({
|
|
407
|
+
data,
|
|
408
|
+
columns,
|
|
409
|
+
renderDetails: ({ row }) => (
|
|
410
|
+
<DetailsForm draft={drafts[row.id]} onChange={(d) => setDrafts((all) => ({ ...all, [row.id]: d }))} />
|
|
411
|
+
),
|
|
412
|
+
});
|
|
394
413
|
```
|
|
395
414
|
|
|
396
|
-
|
|
415
|
+
`autoResetExpanded` is already `false` by default, so a refetch does not close
|
|
416
|
+
the panels; pass `autoResetExpanded: true` to get TanStack's collapse back.
|
|
417
|
+
|
|
418
|
+
Source: `packages/tmdatagrid/docs/row-details.md` (Panel behaviour).
|
|
397
419
|
|
|
398
420
|
### MEDIUM Expecting pinned rows to persist
|
|
399
421
|
|
|
@@ -15,7 +15,7 @@ description: >
|
|
|
15
15
|
metadata:
|
|
16
16
|
type: core
|
|
17
17
|
library: '@jielga/tmdatagrid'
|
|
18
|
-
library_version: '2.
|
|
18
|
+
library_version: '2.2.0'
|
|
19
19
|
sources:
|
|
20
20
|
- 'Jielga/react:packages/tmdatagrid/docs/server-side.md'
|
|
21
21
|
- 'Jielga/react:packages/tmdatagrid/docs/server-query.md'
|
package/skills/testing/SKILL.md
CHANGED
|
@@ -13,7 +13,7 @@ description: >
|
|
|
13
13
|
metadata:
|
|
14
14
|
type: core
|
|
15
15
|
library: '@jielga/tmdatagrid'
|
|
16
|
-
library_version: '2.
|
|
16
|
+
library_version: '2.2.0'
|
|
17
17
|
sources:
|
|
18
18
|
- 'Jielga/react:packages/tmdatagrid/docs/testing.md'
|
|
19
19
|
- 'Jielga/react:playwright/support/DataGrid.ts'
|
|
@@ -104,6 +104,17 @@ match the same rows, and the negative is `:not([data-new])` in CSS and
|
|
|
104
104
|
|
|
105
105
|
**Keyed by both**: `editor`.
|
|
106
106
|
|
|
107
|
+
**The generated lanes** are columns with exported ids: `ROW_NUMBER_COLUMN_ID`
|
|
108
|
+
(`__rowNumber__`), `SELECT_COLUMN_ID` (`__select__`), `GROUP_COLUMN_ID`
|
|
109
|
+
(`__group__`), `DETAILS_COLUMN_ID` (`__details__`) and `EDIT_COLUMN_ID`
|
|
110
|
+
(`__edit__`). A lane's header is
|
|
111
|
+
`[data-dg-part="header"][data-column-id="__select__"]`, a lane cell
|
|
112
|
+
`[data-row-id="42"][data-column-id="__select__"]:not([data-dg-part])`, and the
|
|
113
|
+
control inside it has a row-keyed part: `select-row`, `details-toggle`,
|
|
114
|
+
`group-toggle`, the edit lane's buttons. `select-all` and `details-toggle-all`
|
|
115
|
+
sit in the lane headers. The checkbox parts are on the `<input>` itself, so
|
|
116
|
+
`check()` works on them directly. There is no `data-testid`.
|
|
117
|
+
|
|
107
118
|
Inside a `filter-row` the controls are `filter-column`, `filter-operator` and
|
|
108
119
|
`filter-value` - or `filter-value-from` / `filter-value-to` for `between` - and
|
|
109
120
|
`filter-remove` is its ✕. None of them carries `data-column-id`; scope through
|
|
@@ -12,7 +12,7 @@ description: >
|
|
|
12
12
|
metadata:
|
|
13
13
|
type: core
|
|
14
14
|
library: '@jielga/tmdatagrid'
|
|
15
|
-
library_version: '2.
|
|
15
|
+
library_version: '2.2.0'
|
|
16
16
|
sources:
|
|
17
17
|
- 'Jielga/react:packages/tmdatagrid/docs/testing.md'
|
|
18
18
|
- 'Jielga/react:packages/tmdatagrid/test/gallery/main.tsx'
|