@jielga/tmdatagrid 2.0.0-beta.9 → 2.0.1
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 +5 -212
- package/dist/index.d.ts +1281 -768
- package/dist/index.js +4607 -3250
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/docs/adding-rows.md +132 -0
- package/docs/anatomy.md +119 -0
- package/docs/card-view.md +108 -0
- package/docs/cell-selection.md +194 -0
- package/docs/column-layout.md +182 -0
- package/docs/column-menu.md +66 -0
- package/docs/columns.md +269 -0
- package/docs/components.md +311 -0
- package/docs/draft-store.md +242 -0
- package/docs/editing.md +303 -0
- package/docs/editors.md +250 -0
- package/docs/export.md +319 -0
- package/docs/filtering.md +362 -0
- package/docs/getting-started.md +123 -0
- package/docs/grouping.md +165 -0
- package/docs/loading-and-empty.md +92 -0
- package/docs/localization.md +79 -0
- package/docs/menu.md +143 -0
- package/docs/migrating-to-2.md +163 -0
- package/docs/pagination.md +144 -0
- package/docs/persistence.md +114 -0
- package/docs/portfolio-rebalancer.md +94 -0
- package/docs/query-builder.md +179 -0
- package/docs/quick-search.md +84 -0
- package/docs/row-details.md +115 -0
- package/docs/row-interaction.md +149 -0
- package/docs/row-pinning.md +132 -0
- package/docs/row-selection.md +136 -0
- package/docs/row-styling.md +133 -0
- package/docs/scrolling.md +112 -0
- package/docs/server-query.md +246 -0
- package/docs/server-side.md +206 -0
- package/docs/sorting.md +101 -0
- package/docs/styling.md +126 -0
- package/docs/summary-row.md +76 -0
- package/docs/testing.md +744 -0
- package/docs/toolbar.md +161 -0
- package/docs/use-tm-data-grid.md +361 -0
- package/package.json +22 -46
- package/skills/appearance/SKILL.md +72 -19
- package/skills/cell-selection/SKILL.md +49 -48
- package/skills/columns/SKILL.md +125 -70
- package/skills/columns/references/columns-api.md +59 -0
- package/skills/data/SKILL.md +112 -18
- package/skills/editing/SKILL.md +76 -42
- package/skills/editing/references/common-mistakes.md +77 -69
- package/skills/editing/references/editing-api.md +25 -20
- package/skills/editing/references/editors-and-validation.md +80 -18
- package/skills/filtering/SKILL.md +155 -41
- package/skills/getting-started/SKILL.md +116 -16
- package/skills/grouping/SKILL.md +31 -16
- package/skills/migrating-to-2/SKILL.md +244 -0
- package/skills/options/SKILL.md +24 -12
- package/skills/rows/SKILL.md +22 -18
- package/skills/rows/references/rows-api.md +10 -6
- package/skills/server-side/SKILL.md +170 -17
- package/skills/testing/SKILL.md +150 -32
- package/skills/testing-components/SKILL.md +230 -0
- package/skills/testing-editing/SKILL.md +240 -0
- package/src/{tmdatagrid/components → components}/TMDataGrid.tsx +38 -21
- package/src/{tmdatagrid/components → components}/TMDataGridCellEditor.tsx +54 -8
- package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.module.css +5 -1
- package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.tsx +47 -55
- package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.tsx +5 -51
- package/src/{tmdatagrid/components → components}/TMDataGridDraftActions.tsx +41 -24
- package/src/{tmdatagrid/components → components}/TMDataGridEditColumn.tsx +12 -59
- package/src/{tmdatagrid/components → components}/TMDataGridEntryRows.tsx +164 -92
- package/src/components/TMDataGridExportPicker.module.css +77 -0
- package/src/components/TMDataGridExportPicker.tsx +234 -0
- package/src/components/TMDataGridFilterPanel.module.css +54 -0
- package/src/components/TMDataGridFilterPanel.tsx +348 -0
- package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.tsx +15 -8
- package/src/components/TMDataGridFilterSurface.module.css +54 -0
- package/src/components/TMDataGridFilterSurface.tsx +167 -0
- package/src/{tmdatagrid/components → components}/TMDataGridFooter.tsx +53 -90
- package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.tsx +5 -69
- package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.module.css +12 -2
- package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.tsx +58 -21
- package/src/components/TMDataGridHeaderFilterRow.module.css +51 -0
- package/src/components/TMDataGridHeaderFilterRow.tsx +301 -0
- package/src/components/TMDataGridMenu.tsx +357 -0
- package/src/{tmdatagrid/components → components}/TMDataGridSelectColumn.tsx +11 -48
- package/src/{tmdatagrid/components → components}/TMDataGridTable.module.css +69 -56
- package/src/{tmdatagrid/components → components}/TMDataGridTable.tsx +240 -138
- package/src/{tmdatagrid/components → components}/TMDataGridToolbar.module.css +5 -0
- package/src/components/TMDataGridToolbar.tsx +181 -0
- package/src/{tmdatagrid/components → components}/editors/TMDataGridBooleanEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridDateEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridMultiSelectEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridNumberEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridSelectEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridStringEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/editorShared.ts +16 -2
- package/src/{tmdatagrid/components → components}/filters/DgAutocompleteFilter.tsx +5 -4
- package/src/{tmdatagrid/components → components}/filters/DgDateRangeFilter.tsx +22 -5
- package/src/{tmdatagrid/components → components}/filters/DgRangeSliderFilter.tsx +5 -1
- package/src/{tmdatagrid/components → components}/filters/DgTriStateFilter.tsx +5 -1
- package/src/{tmdatagrid/components → components}/filters/TMDataGridFilterValueInput.tsx +44 -28
- package/src/components/filters/controlLayout.ts +32 -0
- package/src/components/filters/filterControlFor.ts +65 -0
- package/src/components/generatedColumns.tsx +187 -0
- package/src/{tmdatagrid/components → components}/icons.ts +1 -0
- package/src/{tmdatagrid/components → components}/sticky.module.css +44 -0
- package/src/components/useHideableColumns.ts +52 -0
- package/src/{tmdatagrid/core → core}/autosize.ts +5 -2
- package/src/{tmdatagrid/core → core}/columnOptions.ts +60 -8
- package/src/{tmdatagrid/core → core}/columnOrdering.ts +33 -14
- package/src/{tmdatagrid/core → core}/columnUtils.ts +44 -5
- package/src/core/controlledStateSync.ts +108 -0
- package/src/core/deletedRows.ts +34 -0
- package/src/core/dom.ts +74 -0
- package/src/{tmdatagrid/core → core}/editEngine.ts +1107 -460
- package/src/core/export.ts +704 -0
- package/src/{tmdatagrid/core → core}/filterControls.ts +38 -1
- package/src/{tmdatagrid/core → core}/filterOperators.ts +64 -1
- package/src/core/filterSurface.ts +99 -0
- package/src/{tmdatagrid/core → core}/grouping.ts +21 -0
- package/src/{tmdatagrid/core → core}/labels.ts +51 -6
- package/src/{tmdatagrid/core → core}/labelsSv.ts +27 -6
- package/src/core/pageReset.ts +120 -0
- package/src/core/pagination.ts +81 -0
- package/src/{tmdatagrid/core → core}/persistence.ts +22 -5
- package/src/{tmdatagrid/core → core}/summary.ts +20 -4
- package/src/{tmdatagrid/index.ts → index.ts} +69 -35
- package/src/{tmdatagrid/useTMDataGrid.tsx → useTMDataGrid.tsx} +428 -109
- package/src/useTMDataGridExport.ts +78 -0
- package/src/tmdatagrid/components/TMDataGridFilterPanel.module.css +0 -35
- package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +0 -354
- package/src/tmdatagrid/components/TMDataGridToolbar.tsx +0 -161
- package/src/tmdatagrid/core/cellExport.ts +0 -320
- /package/src/{tmdatagrid/TMDataGridContext.ts → TMDataGridContext.ts} +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGrid.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFooter.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridRowNumberColumn.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridSearch.tsx +0 -0
- /package/src/{tmdatagrid/core → core}/capabilities.ts +0 -0
- /package/src/{tmdatagrid/core → core}/cellNavigation.ts +0 -0
- /package/src/{tmdatagrid/core → core}/cellRange.ts +0 -0
- /package/src/{tmdatagrid/core → core}/controlledState.ts +0 -0
- /package/src/{tmdatagrid/core → core}/draftCellContext.ts +0 -0
- /package/src/{tmdatagrid/core → core}/editorFocus.ts +0 -0
- /package/src/{tmdatagrid/core → core}/expanding.ts +0 -0
- /package/src/{tmdatagrid/core → core}/matchHighlight.ts +0 -0
- /package/src/{tmdatagrid/core → core}/quickSearch.ts +0 -0
- /package/src/{tmdatagrid/core → core}/resizePreview.ts +0 -0
- /package/src/{tmdatagrid/core → core}/rowPinning.ts +0 -0
- /package/src/{tmdatagrid/core → core}/rowSelection.ts +0 -0
- /package/src/{tmdatagrid/core → core}/sizes.ts +0 -0
- /package/src/{tmdatagrid/core → core}/useSettledTableState.ts +0 -0
|
@@ -63,11 +63,11 @@ Bind any control to `field` exactly as inside any TanStack Form:
|
|
|
63
63
|
`field.state.value`, `field.state.meta.errors`, `field.handleChange`,
|
|
64
64
|
`field.handleBlur`.
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
binds
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
The message itself is the host's: it shows in a tooltip on the editor, opened
|
|
67
|
+
by focus and by hover, for a custom editor as much as a built-in one. What an
|
|
68
|
+
editor binds is the invalid state - the built-ins pass a boolean to the input's
|
|
69
|
+
`error` prop for the border alone, and an editor that binds nothing looks
|
|
70
|
+
unchanged while the commit is refused.
|
|
71
71
|
|
|
72
72
|
```tsx
|
|
73
73
|
import { Slider } from "@mantine/core";
|
|
@@ -157,6 +157,10 @@ meta: {
|
|
|
157
157
|
}
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
+
The map receives `TMDataGridEditValueMapArgs`: `{ value, previous, row, column, table }`.
|
|
161
|
+
Unlike `meta.edit.enabled`, its `row` is `Row<TMDataGridFeatures, TMDataGridRowData>`
|
|
162
|
+
with or without the column helper.
|
|
163
|
+
|
|
160
164
|
The grid applies it in the editor host, around the field every editor writes
|
|
161
165
|
through, so it covers the six built-ins, a custom `meta.edit.editor`, and the
|
|
162
166
|
type-to-edit seed character.
|
|
@@ -193,8 +197,13 @@ meta: { edit: { validate: z.string().min(2, "At least two characters") } }
|
|
|
193
197
|
// Object form: pick the trigger.
|
|
194
198
|
meta: { edit: { validate: { onBlur: z.string().email("Not an email address") } } }
|
|
195
199
|
|
|
196
|
-
// A plain function works too.
|
|
197
|
-
meta: {
|
|
200
|
+
// A plain function works too. `value` is typed `never`, so annotate the parameter.
|
|
201
|
+
meta: {
|
|
202
|
+
edit: {
|
|
203
|
+
validate: ({ value }: { value: unknown }) =>
|
|
204
|
+
typeof value === "number" && value > 0 ? undefined : "Must be positive",
|
|
205
|
+
},
|
|
206
|
+
}
|
|
198
207
|
```
|
|
199
208
|
|
|
200
209
|
`normalizeFieldValidate(validate)` is exported for consumers building their own
|
|
@@ -224,8 +233,8 @@ const grid = useTMDataGrid({
|
|
|
224
233
|
```
|
|
225
234
|
|
|
226
235
|
Issues with a path land on the matching column's cell; pathless issues land on
|
|
227
|
-
the row, where the message shows in the edit lane's tooltip
|
|
228
|
-
row's
|
|
236
|
+
the row, where the message shows in the edit lane's tooltip on the open
|
|
237
|
+
row's ✓. A nested schema's issues follow the
|
|
229
238
|
same rule, so a `address.city` issue lands on the column whose `editField` is
|
|
230
239
|
`"address.city"`.
|
|
231
240
|
|
|
@@ -236,7 +245,8 @@ unedited value and cannot pass. Use `"row"`.
|
|
|
236
245
|
## Cross-row rules
|
|
237
246
|
|
|
238
247
|
`editing.tableValidators` holds the rules that need the other rows. Its
|
|
239
|
-
`onSubmit` / `onSubmitAsync` receive `
|
|
248
|
+
`onSubmit` / `onSubmitAsync` receive `TMDataGridTableValidateArgs`,
|
|
249
|
+
`{ value, rowId, isNew, rows }`:
|
|
240
250
|
`value` is the committing row as drafted, and `rows` is
|
|
241
251
|
`Array<{ rowId, value }>` - the collection as it would stand if the commit
|
|
242
252
|
landed, with every draft overlaid, entry rows appended and deletion-marked
|
|
@@ -261,9 +271,59 @@ row's cells. `onSubmit` runs first, and its failure stands without
|
|
|
261
271
|
`onSubmitAsync` running. Errors land on the committing row only.
|
|
262
272
|
|
|
263
273
|
The rules run at every commit - typed, ✓, `edit.setCellValue`, an entry
|
|
264
|
-
row's - after the row's own validators, and again for every
|
|
265
|
-
`saveDrafts
|
|
266
|
-
|
|
274
|
+
row's - after the row's own validators, and again for every committed row during
|
|
275
|
+
`saveDrafts`, the only rules that run there: a committed row that a later edit
|
|
276
|
+
invalidated is reopened with its errors, and the save reports it in `reopened`.
|
|
277
|
+
|
|
278
|
+
## Derived columns and a table-wide rule
|
|
279
|
+
|
|
280
|
+
A column whose value depends on the other rows - a weight as a share of the
|
|
281
|
+
total - cannot be an `accessorFn`, which is handed one row. Derive the whole
|
|
282
|
+
collection with `useMemo` and pass the finished rows as `data`;
|
|
283
|
+
`editing.onCommit` writes back to the source array, and the derived rows arrive
|
|
284
|
+
on the next render. Under `mode: "cell"` with no draft store, every dependent
|
|
285
|
+
column follows the commit.
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
const positions = useMemo(() => {
|
|
289
|
+
const valued = holdings.map((h) => ({ ...h, marketValue: h.price * h.shares }));
|
|
290
|
+
const total = valued.reduce((sum, h) => sum + h.marketValue, 0);
|
|
291
|
+
return valued.map((h) => ({
|
|
292
|
+
...h,
|
|
293
|
+
currentPct: (h.marketValue / total) * 100,
|
|
294
|
+
drift: h.targetPct - (h.marketValue / total) * 100,
|
|
295
|
+
}));
|
|
296
|
+
}, [holdings]);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
A rule over the whole collection, such as targets that may not total more than
|
|
300
|
+
100%, is a `tableValidators` rule, while a bound on one cell (between 0 and 100)
|
|
301
|
+
stays on `meta.edit.validate`. `editing.columns` keeps every other column
|
|
302
|
+
read-only:
|
|
303
|
+
|
|
304
|
+
```tsx
|
|
305
|
+
editing: {
|
|
306
|
+
mode: "cell",
|
|
307
|
+
// Only the target weight takes edits; everything else is market data.
|
|
308
|
+
columns: ["targetPct"],
|
|
309
|
+
onCommit: ({ rowId, value }) =>
|
|
310
|
+
setHoldings((previous) =>
|
|
311
|
+
previous.map((h) => (h.id === rowId ? { ...h, targetPct: value.targetPct } : h)),
|
|
312
|
+
),
|
|
313
|
+
tableValidators: {
|
|
314
|
+
// `rows` already holds the committing row's drafted value.
|
|
315
|
+
onSubmit: ({ rows }) => {
|
|
316
|
+
const total = rows.reduce((sum, r) => sum + Number(r.value.targetPct ?? 0), 0);
|
|
317
|
+
return total > 100.005
|
|
318
|
+
? { fields: { targetPct: `Targets would total ${pct(total)}` } }
|
|
319
|
+
: undefined;
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Source: `packages/tmdatagrid/docs/portfolio-rebalancer.md`, and the demo
|
|
326
|
+
`apps/docs/src/examples/demos/recipes/PortfolioRebalancer.tsx`.
|
|
267
327
|
|
|
268
328
|
## Server-side errors
|
|
269
329
|
|
|
@@ -283,9 +343,9 @@ rowValidators: {
|
|
|
283
343
|
},
|
|
284
344
|
```
|
|
285
345
|
|
|
286
|
-
A commit blocked by validation keeps the editor open with the message
|
|
287
|
-
|
|
288
|
-
row.
|
|
346
|
+
A commit blocked by validation keeps the editor open, invalid, with the message
|
|
347
|
+
in its tooltip. A rejected `editing.onCommit` keeps the draft too, with the
|
|
348
|
+
error on the row.
|
|
289
349
|
|
|
290
350
|
## Where the state shows
|
|
291
351
|
|
|
@@ -294,11 +354,13 @@ row.
|
|
|
294
354
|
| The cell's own value | A held draft is displayed: the cell renders the draft value through the column's `cell` renderer, in every mode |
|
|
295
355
|
| Blue cell corner | The field is dirty against its original value |
|
|
296
356
|
| Red cell corner | The field carries a validation error |
|
|
297
|
-
|
|
|
357
|
+
| Field error message | In a tooltip on the open editor, shown while the input has focus and on hover |
|
|
358
|
+
| Row error text | A pathless rule failed, or a commit was rejected. In the lane's tooltip, on the open row's ✓ |
|
|
298
359
|
| `data-dirty` on the row | The row holds a dirty draft |
|
|
299
360
|
|
|
300
361
|
The same information is readable from `edit.store`: `rows[rowId].dirtyFields`,
|
|
301
362
|
`rows[rowId].errorFields`, `rows[rowId].errorMessages` (`{ field, message }`
|
|
302
363
|
pairs), `rows[rowId].hasRowError`, `rows[rowId].isSubmitting`, and
|
|
303
364
|
`rows[rowId].values` for the draft itself. The pathless message's text is not
|
|
304
|
-
in the store; read it from `edit.getForm(rowId)?.state.errors
|
|
365
|
+
in the store; read it from `edit.getForm(rowId)?.state.errors` on the open
|
|
366
|
+
row that carries it.
|
|
@@ -3,24 +3,27 @@ name: filtering
|
|
|
3
3
|
description: >
|
|
4
4
|
Narrow the rows a TMDataGrid shows. Covers the shared tmDataGrid filter
|
|
5
5
|
function and its {operator, value} model, the eighteen operators and which
|
|
6
|
-
meta.type offers each, meta.filter.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
meta.type offers each, meta.filter.operators to offer a column only a subset
|
|
7
|
+
of them, meta.filter.defaultOperator, isFilterActive and the half-typed
|
|
8
|
+
filter, the filters option and its surfaces (popup, sidebar, none, plus
|
|
9
|
+
inHeader for header filters), TMDataGrid.FilterPanel and its layout prop,
|
|
10
|
+
TMDataGrid.FilterButton, TMDataGrid.FilterPills with its api prop,
|
|
11
|
+
openColumnFilter, replacing a value control with DgRangeSliderFilter /
|
|
12
|
+
DgDateRangeFilter / DgAutocompleteFilter / DgTriStateFilter or a
|
|
13
|
+
meta.filter.control component, per-column filterFn, and the quick search:
|
|
14
|
+
TMDataGrid.Search, quickSearchMode fuzzy or contains, fuzzyGlobalFilterFn,
|
|
15
|
+
enableMatchHighlighting and enableGlobalFilter. Load when adding filters,
|
|
16
|
+
choosing operators, building a filter control, showing active filters outside
|
|
17
|
+
the grid, or wiring a search box.
|
|
15
18
|
metadata:
|
|
16
19
|
type: core
|
|
17
20
|
library: '@jielga/tmdatagrid'
|
|
18
|
-
library_version: '2.0.
|
|
21
|
+
library_version: '2.0.1'
|
|
19
22
|
sources:
|
|
20
|
-
- 'Jielga/TMDataGrid:
|
|
21
|
-
- 'Jielga/TMDataGrid:
|
|
22
|
-
- 'Jielga/TMDataGrid:
|
|
23
|
-
- 'Jielga/TMDataGrid:
|
|
23
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/filtering.md'
|
|
24
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/quick-search.md'
|
|
25
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/filterOperators.ts'
|
|
26
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/quickSearch.ts'
|
|
24
27
|
---
|
|
25
28
|
|
|
26
29
|
# TMDataGrid - Filtering
|
|
@@ -48,7 +51,9 @@ leaving that end open).
|
|
|
48
51
|
|
|
49
52
|
A filter with an empty value **stays in state** so the panel keeps its row while
|
|
50
53
|
the user types. It matches every row, does not set the header indicator and
|
|
51
|
-
produces no pill. `isFilterActive(value)` tests for that state
|
|
54
|
+
produces no pill. `isFilterActive(value)` tests for that state, and
|
|
55
|
+
`activeColumnFilters(columnFilters | table)` applies it across the slice and
|
|
56
|
+
types what it hands back (entries in any other value shape are dropped); presence in
|
|
52
57
|
`columnFilters` does not.
|
|
53
58
|
|
|
54
59
|
## Operators
|
|
@@ -80,16 +85,105 @@ columnHelper.accessor("salary", {
|
|
|
80
85
|
});
|
|
81
86
|
```
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
`meta.filter.operators` narrows the list a column offers to a subset of its
|
|
89
|
+
type's - for a column whose backend answers only some operators, so the user is
|
|
90
|
+
never offered one the query cannot express. The panel dropdown and the header
|
|
91
|
+
funnel show only those, in the type's order. An operator the type does not
|
|
92
|
+
offer is ignored; a list that leaves nothing falls back to the type's full set.
|
|
93
|
+
Without `defaultOperator`, a fresh filter opens on the type's default when it is
|
|
94
|
+
offered, else on the first offered operator.
|
|
84
95
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
```tsx
|
|
97
|
+
columnHelper.accessor("customer", {
|
|
98
|
+
header: "Customer",
|
|
99
|
+
meta: { filter: { operators: ["contains", "equals", "isEmpty", "isNotEmpty"] } },
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`getColumnOperators(column)` returns the resolved list and
|
|
104
|
+
`getColumnDefaultOperator(column)` the operator a fresh filter opens on. The
|
|
105
|
+
`server-side` skill shows the list typed together with the API mapping table.
|
|
106
|
+
|
|
107
|
+
## The filters option
|
|
108
|
+
|
|
109
|
+
`filters` on `useTMDataGrid` picks the surface. It is read field by field, so a
|
|
110
|
+
literal is fine.
|
|
111
|
+
|
|
112
|
+
| Option | Type | Default | What it does |
|
|
113
|
+
| --- | --- | --- | --- |
|
|
114
|
+
| `surface` | `"popup" \| "sidebar" \| "none"` | `"popup"` | What `TMDataGrid.Table` renders and `FilterButton` toggles. |
|
|
115
|
+
| `sidebarSide` | `"left" \| "right"` | `"right"` | Which side the sidebar sits on. Ignored by the other surfaces. |
|
|
116
|
+
| `sidebarWidth` | `string` | `"280px"` | Sidebar width, any CSS length. Ignored by the other surfaces. |
|
|
117
|
+
| `defaultOpen` | `boolean` | `true` under `"sidebar"`, else `false` | Whether the surface starts open. Read once, at mount. Under `"none"`, the starting value of `ui.state.filterPanelOpen`. |
|
|
118
|
+
| `inHeader` | `boolean` | `false` | A second header row of per-column controls. Independent of `surface`. |
|
|
119
|
+
|
|
120
|
+
`surface` and `inHeader` are separate choices: `{ surface: "none", inHeader: true }`
|
|
121
|
+
is header filters alone, `{ inHeader: true }` keeps the popup as well.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
useTMDataGrid({ data, columns, filters: { surface: "sidebar", inHeader: true } });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Popup** - the default. Floats over the first body rows. A pointerdown
|
|
128
|
+
outside, Escape, and emptying it (the last row removed, or **Clear all**) all
|
|
129
|
+
close it; `FilterButton` is exempt from the click-away so it stays a toggle.
|
|
130
|
+
|
|
131
|
+
**Sidebar** - the same panel beside the rows, inside the grid frame and under
|
|
132
|
+
the toolbar. The rows give up the width rather than being covered, a click in
|
|
133
|
+
the table does not dismiss it, and clearing the filters leaves it standing.
|
|
134
|
+
Escape closes it. It starts open, being a layout choice; its rows are
|
|
135
|
+
`layout="stacked"`, since 280px has no room for the triple.
|
|
136
|
+
|
|
137
|
+
**Header filters** - `inHeader: true` adds a header row of value controls, one
|
|
138
|
+
per filterable column, on the same column tracks as everything else. The
|
|
139
|
+
column and operator dropdowns are not there: the column is the one the cell
|
|
140
|
+
sits over, and the operator is a funnel button beside the input, tinted off its
|
|
141
|
+
default. The column menu's Filter item and the funnel indicator both come off,
|
|
142
|
+
having nothing left to reveal; the filtered column's tinted title stays. A
|
|
143
|
+
narrow column clips its control - give it a `minSize`.
|
|
90
144
|
|
|
91
|
-
|
|
92
|
-
|
|
145
|
+
Clearing a header control removes the column's `columnFilters` entry rather
|
|
146
|
+
than leaving an empty one, unless the user also picked a non-default operator,
|
|
147
|
+
which is kept. Panel rows still keep their empty filters.
|
|
148
|
+
|
|
149
|
+
`FilterButton` still toggles whatever `surface` names. `openColumnFilter` does
|
|
150
|
+
not: under `inHeader` it always focuses the header control and leaves the
|
|
151
|
+
surface closed.
|
|
152
|
+
|
|
153
|
+
**None** - `surface: "none"` renders no panel and no `FilterButton`, so a
|
|
154
|
+
hand-placed `TMDataGrid.FilterPanel` is the only one. Read
|
|
155
|
+
`ui.state.filterPanelOpen` if it belongs behind a control of your own.
|
|
156
|
+
|
|
157
|
+
## TMDataGrid.FilterPanel
|
|
158
|
+
|
|
159
|
+
The panel of filter rows - one column / operator / value triple per filter, over "Add filter" and "Clear all".
|
|
160
|
+
A plain block with no title, no close button and no open state: it renders wherever it is mounted, and the popup and sidebar surfaces are wrappers around it.
|
|
161
|
+
It must be inside `<TMDataGrid>` (it reads the grid from context) and it only reads and writes `columnFilters`, so a `manualFiltering` grid gets it for free.
|
|
162
|
+
Closing a surface only hides it; the filters stay.
|
|
163
|
+
**Clear all** drops every filter, half-typed ones included.
|
|
164
|
+
|
|
165
|
+
| Prop | Type | Default | Description |
|
|
166
|
+
| --- | --- | --- | --- |
|
|
167
|
+
| `layout` | `"row" \| "stacked"` | `"row"` | `"row"` is side by side and wants about 550px; `"stacked"` fills a narrow host. Passed to every value control as its `layout`. |
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<Drawer opened={open} onClose={close}>
|
|
171
|
+
<TMDataGrid.FilterPanel layout="stacked" />
|
|
172
|
+
</Drawer>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## TMDataGrid.FilterButton
|
|
176
|
+
|
|
177
|
+
The toolbar button that toggles the filter surface, tinted with the count of active filters.
|
|
178
|
+
Opening an empty panel seeds a filter row on the first filterable column; with filters already in state it opens on those.
|
|
179
|
+
Renders nothing when no column can be filtered, and nothing under `surface: "none"`.
|
|
180
|
+
No props.
|
|
181
|
+
|
|
182
|
+
## TMDataGrid.FilterPills
|
|
183
|
+
|
|
184
|
+
One pill per **active** filter, `First name: Sofia ✕`, where the ✕ clears it and a click on the label calls `openColumnFilter`.
|
|
185
|
+
The label spells the operator out unless it is the type's default: `Age is greater than 30`, but `First name: Sofia`.
|
|
186
|
+
It takes the grid as an `api` prop instead of reading context, so it renders anywhere on the page.
|
|
93
187
|
|
|
94
188
|
```tsx
|
|
95
189
|
import { TMDataGridFilterPills } from "@jielga/tmdatagrid";
|
|
@@ -97,11 +191,18 @@ import { TMDataGridFilterPills } from "@jielga/tmdatagrid";
|
|
|
97
191
|
<TMDataGridFilterPills api={grid} onPillClick={(columnId) => focus(columnId)} />;
|
|
98
192
|
```
|
|
99
193
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`
|
|
104
|
-
|
|
194
|
+
| Prop | Type | Default | Description |
|
|
195
|
+
| --- | --- | --- | --- |
|
|
196
|
+
| `api` | `TMDataGridApi<TData>` | - | The object returned by `useTMDataGrid`. |
|
|
197
|
+
| `size` | `MantineSize` | `"sm"` | Pill size. |
|
|
198
|
+
| `showClearAll` | `boolean` | `true` | "Clear all", shown once two filters are active. |
|
|
199
|
+
| `onPillClick` | `(columnId: string) => void` | - | Replaces the default click behaviour. |
|
|
200
|
+
| `className` | `string` | - | Added to the wrapper class. |
|
|
201
|
+
|
|
202
|
+
## openColumnFilter
|
|
203
|
+
|
|
204
|
+
`openColumnFilter(api, columnId)` seeds an empty filter if the column has none, then opens the surface on that column's panel row - or, under `inHeader`, scrolls the column's header control into view and focuses it, leaving the surface closed.
|
|
205
|
+
It is what a pill's label and the column menu's Filter item both call.
|
|
105
206
|
|
|
106
207
|
## Replacing the value control
|
|
107
208
|
|
|
@@ -220,12 +321,13 @@ const activeCount = columnFilters.length;
|
|
|
220
321
|
Correct:
|
|
221
322
|
|
|
222
323
|
```tsx
|
|
223
|
-
import {
|
|
324
|
+
import { activeColumnFilters } from "@jielga/tmdatagrid";
|
|
224
325
|
|
|
225
|
-
|
|
326
|
+
// The entries that narrow anything, with `value` typed rather than `unknown`.
|
|
327
|
+
const active = activeColumnFilters(columnFilters);
|
|
226
328
|
```
|
|
227
329
|
|
|
228
|
-
Source: `
|
|
330
|
+
Source: `packages/tmdatagrid/docs/filtering.md` (How a filter is stored).
|
|
229
331
|
|
|
230
332
|
### HIGH Assuming `value` is always a string
|
|
231
333
|
|
|
@@ -246,7 +348,7 @@ if (operatorTakesRangeValue(operator)) {
|
|
|
246
348
|
}
|
|
247
349
|
```
|
|
248
350
|
|
|
249
|
-
Source: `
|
|
351
|
+
Source: `packages/tmdatagrid/src/core/filterOperators.ts`.
|
|
250
352
|
|
|
251
353
|
### HIGH A numeric column with no `meta.type`
|
|
252
354
|
|
|
@@ -255,7 +357,7 @@ Source: `src/tmdatagrid/core/filterOperators.ts`.
|
|
|
255
357
|
`between` never appear in the panel, and comparisons run as text, where `"9"`
|
|
256
358
|
sorts above `"10"`.
|
|
257
359
|
|
|
258
|
-
Source: `
|
|
360
|
+
Source: `packages/tmdatagrid/docs/filtering.md` (Operators).
|
|
259
361
|
|
|
260
362
|
### HIGH A filter control defined inside the component
|
|
261
363
|
|
|
@@ -272,7 +374,7 @@ const StatusFilter: TMDataGridFilterControlComponent = (args) => { /* … */ };
|
|
|
272
374
|
meta: { filter: { control: StatusFilter } }
|
|
273
375
|
```
|
|
274
376
|
|
|
275
|
-
Source: `
|
|
377
|
+
Source: `packages/tmdatagrid/docs/filtering.md` (Writing your own).
|
|
276
378
|
|
|
277
379
|
### MEDIUM Writing the whole filter from a custom control
|
|
278
380
|
|
|
@@ -292,7 +394,7 @@ Correct:
|
|
|
292
394
|
onChange(picked);
|
|
293
395
|
```
|
|
294
396
|
|
|
295
|
-
Source: `
|
|
397
|
+
Source: `packages/tmdatagrid/docs/filtering.md` (Writing your own).
|
|
296
398
|
|
|
297
399
|
### MEDIUM Expecting match highlighting in a custom cell
|
|
298
400
|
|
|
@@ -301,7 +403,7 @@ does not modify a custom renderer's output. A column with a `cell` renderer
|
|
|
301
403
|
shows no marks whatever `enableMatchHighlighting` is set to. Equality operators
|
|
302
404
|
highlight nothing either.
|
|
303
405
|
|
|
304
|
-
Source: `
|
|
406
|
+
Source: `packages/tmdatagrid/docs/quick-search.md` (Match highlighting).
|
|
305
407
|
|
|
306
408
|
### MEDIUM Expecting fuzzy ranking to survive a sort
|
|
307
409
|
|
|
@@ -309,7 +411,7 @@ The rank ordering applies only while the search is the sole narrowing. Any sort
|
|
|
309
411
|
or grouping replaces it. The ordering is derived and never written into
|
|
310
412
|
`sorting`, so there is nothing to clear afterwards.
|
|
311
413
|
|
|
312
|
-
Source: `
|
|
414
|
+
Source: `packages/tmdatagrid/docs/quick-search.md` (Fuzzy by default).
|
|
313
415
|
|
|
314
416
|
## Reference
|
|
315
417
|
|
|
@@ -318,20 +420,32 @@ Source: `src/docs/quick-search.md` (Fuzzy by default).
|
|
|
318
420
|
| `enableColumnFilters` | Table option | `boolean` | `true` | `false` removes the panel, the button and the menu item. |
|
|
319
421
|
| `enableColumnFilter` | Column option | `boolean` | `true` | `false` takes one column out of filtering. |
|
|
320
422
|
| `meta.type` | Column meta | `TMDataGridColumnType` | `"string"` | Selects the operators and the value control. |
|
|
321
|
-
| `meta.filter.
|
|
423
|
+
| `meta.filter.operators` | Column meta | `readonly TMDataGridFilterOperator[]` | The type's list | The operators this column offers, a subset of its type's. |
|
|
424
|
+
| `meta.filter.defaultOperator` | Column meta | `TMDataGridFilterOperator` | The type's default, else the first offered | The operator a fresh filter opens on. |
|
|
322
425
|
| `meta.filter.control` | Column meta | `TMDataGridFilterControlComponent` | By type and operator | Replaces the value control. Module scope. |
|
|
323
426
|
| `filterFn` | Column option | name or fn | `"tmDataGrid"` | Custom matching for one column. |
|
|
324
|
-
| `quickSearchMode` | Option | `"fuzzy" \| "contains"` | `"fuzzy"` | How the quick search matches. |
|
|
427
|
+
| `quickSearchMode` | Option | `TMDataGridQuickSearchMode`: `"fuzzy" \| "contains"` | `"fuzzy"` | How the quick search matches. |
|
|
325
428
|
| `enableMatchHighlighting` | Option | `boolean` | `false` | Mark matched text in default-rendered cells. |
|
|
326
429
|
| `enableGlobalFilter` | Table option | `boolean` | `true` | Also a column option. Removes the input, or one column's participation. |
|
|
327
430
|
| `globalFilterFn` | Table option | filter fn | fuzzy | Overrides the matching, and the ranking with it. |
|
|
328
|
-
| `TMDataGrid.FilterPanel` | Component |
|
|
431
|
+
| `TMDataGrid.FilterPanel` | Component | `layout: "row" \| "stacked"`, Mantine `BoxProps` | `"row"` | The panel of filter rows, as a plain block. Style props set on it. |
|
|
432
|
+
| `TMDataGridFilterPanelProps` · `TMDataGridFilterPanelLayout` | Types | – · `"row" \| "stacked"` | – | The props of `TMDataGrid.FilterPanel`, and the type of its `layout`. For wrapping the panel in a component of your own. |
|
|
433
|
+
| `filters` | Table option | `TMDataGridFiltersOptions` | `{ surface: "popup" }` | Which surface holds the filter controls. |
|
|
434
|
+
| `TMDataGridFiltersSettings` | Type | `Required<TMDataGridFiltersOptions>` | – | The `filters` option with its defaults filled in, as `api.filters`. |
|
|
435
|
+
| `TMDataGridFilterSurface` · `TMDataGridFilterSidebarSide` | Types | `"popup" \| "sidebar" \| "none"` · `"left" \| "right"` | – | The types of `filters.surface` and `filters.sidebarSide`. |
|
|
436
|
+
| `TMDataGridFilterControlArgs.layout` | Type | `TMDataGridFilterControlLayout` | – | How much room a value control has, and whether it names itself. |
|
|
437
|
+
| `TMDataGridFilterControlLayout` | Type | `"row" \| "stacked" \| "header"` | – | The type of `layout` on `TMDataGridFilterControlArgs`. `"header"` is the cell of the `inHeader` row. |
|
|
438
|
+
| `filterValueShape` | Export | `(operator) => TMDataGridFilterValueShape` | – | Which shape an operator's value takes. |
|
|
439
|
+
| `TMDataGridFilterValueShape` | Type | `"scalar" \| "set" \| "range"` | – | What `filterValueShape` returns. |
|
|
329
440
|
| `TMDataGrid.FilterButton` | Component | – | – | Toolbar button opening the panel, with an active count. |
|
|
330
|
-
| `TMDataGrid.FilterPills` | Component | `api`, `size`, `showClearAll`, `onPillClick`, `
|
|
441
|
+
| `TMDataGrid.FilterPills` | Component | `api`, `size`, `showClearAll`, `onPillClick`, Mantine `BoxProps` | – | Active filters as removable pills, renderable anywhere. Style props set on the wrapper. |
|
|
331
442
|
| `TMDataGrid.Search` | Component | `placeholder`, `debounce` (`250`), `w` (`220`) | – | The debounced quick-search input. |
|
|
332
443
|
| `openColumnFilter` | Export | `(api, columnId) => void` | – | Opens the panel on a column. |
|
|
333
444
|
| `isFilterActive` | Export | `(value) => boolean` | – | Whether a filter value narrows anything. |
|
|
445
|
+
| `activeColumnFilters` | Export | `(columnFilters \| table) => Array<TMDataGridColumnFilter>` | – | The filters in the grid's own value shape that narrow anything, typed. |
|
|
446
|
+
| `TMDataGridColumnFilter` | Type | `{ id, value }` | – | One entry of `columnFilters`, with `value` typed as `TMDataGridFilterValue`. |
|
|
334
447
|
| `getOperatorsForType` | Export | `(type) => operators` | – | The operator list a type offers. |
|
|
448
|
+
| `getColumnOperators` · `getColumnDefaultOperator` | Exports | `(column) => operators` · `(column) => operator` | – | One column's list after `meta.filter.operators`, and the operator a fresh filter on it opens on. |
|
|
335
449
|
| `FILTER_OPERATOR_LABELS` | Export | record | – | The label shown for each operator. |
|
|
336
450
|
| `formatFilterLabel` | Export | `({ label, type, filter }) => string` | – | The one-line description used on the pills. |
|
|
337
451
|
| `emptyValueForOperator` · `operatorNeedsValue` · `operatorTakesArrayValue` · `operatorTakesRangeValue` | Exports | – | – | What shape of value an operator expects. |
|
|
@@ -4,19 +4,23 @@ description: >
|
|
|
4
4
|
Set up TMDataGrid, a compound React data grid built on TanStack Table v9 and
|
|
5
5
|
Mantine. Covers useTMDataGrid, the TMDataGrid root, context, the component
|
|
6
6
|
catalog (Table, Footer, Toolbar, Spacer, SummaryCount, Search,
|
|
7
|
-
LoadingIndicator, DraftActions, FilterButton,
|
|
8
|
-
|
|
9
|
-
requirement
|
|
10
|
-
|
|
7
|
+
LoadingIndicator, DraftActions, FilterButton, Menu, FilterPanel, FilterPills,
|
|
8
|
+
ColumnsPanel) with their props types, the size scale, the bounded-height
|
|
9
|
+
layout requirement, and rendering rows without TMDataGrid.Table through
|
|
10
|
+
getDisplayedRows (a card view). Load when adding a grid, choosing which parts
|
|
11
|
+
to render, replacing the Table with a renderer of your own, or when rows do
|
|
12
|
+
not appear.
|
|
11
13
|
metadata:
|
|
12
14
|
type: core
|
|
13
15
|
library: '@jielga/tmdatagrid'
|
|
14
|
-
library_version: '2.0.
|
|
16
|
+
library_version: '2.0.1'
|
|
15
17
|
sources:
|
|
16
|
-
- 'Jielga/TMDataGrid:
|
|
17
|
-
- 'Jielga/TMDataGrid:
|
|
18
|
-
- 'Jielga/TMDataGrid:
|
|
19
|
-
- 'Jielga/TMDataGrid:
|
|
18
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/getting-started.md'
|
|
19
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/anatomy.md'
|
|
20
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/components.md'
|
|
21
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/card-view.md'
|
|
22
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/components/TMDataGrid.tsx'
|
|
23
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/sizes.ts'
|
|
20
24
|
---
|
|
21
25
|
|
|
22
26
|
# TMDataGrid - Getting started
|
|
@@ -80,7 +84,9 @@ export function Employees({ data }: { data: Employee[] }) {
|
|
|
80
84
|
<TMDataGrid.SummaryCount />
|
|
81
85
|
<TMDataGrid.Spacer />
|
|
82
86
|
<TMDataGrid.FilterButton />
|
|
83
|
-
<TMDataGrid.
|
|
87
|
+
<TMDataGrid.Menu>
|
|
88
|
+
<TMDataGrid.Menu.Columns />
|
|
89
|
+
</TMDataGrid.Menu>
|
|
84
90
|
</TMDataGrid.Toolbar>
|
|
85
91
|
|
|
86
92
|
<TMDataGrid.Table<Employee> />
|
|
@@ -129,6 +135,7 @@ TanStack ships state and APIs for both but no `enable` option.
|
|
|
129
135
|
| Configure the hook, or persist state | `options` |
|
|
130
136
|
| Theme, size, compose the toolbar, translate | `appearance` |
|
|
131
137
|
| Write tests against a grid | `testing` |
|
|
138
|
+
| Upgrade code written against a 2.0 beta | `migrating-to-2` |
|
|
132
139
|
|
|
133
140
|
## Layout
|
|
134
141
|
|
|
@@ -149,20 +156,43 @@ flex column.
|
|
|
149
156
|
| Component | Props | Notes |
|
|
150
157
|
| --- | --- | --- |
|
|
151
158
|
| `TMDataGrid` | `table`, `ui`, `features`, `size`, `className`, `style` | Root. Provides context. `style` also takes CSS variables: `--dg-row-selected-bg`, `--dg-row-height`, `--dg-header-height`, `--dg-font-size`, `--dg-padding`. |
|
|
152
|
-
| `TMDataGrid.Table` | `onRowClick(row)`, `renderRowContextMenu`, `renderColumnMenuItems`, `rowContextMenuProps` | Header, virtualized body, filter
|
|
159
|
+
| `TMDataGrid.Table` | `onRowClick(row)`, `renderRowContextMenu`, `renderColumnMenuItems`, `rowContextMenuProps` | Header, virtualized body, and whichever filter surface the `filters` option asks for. `onRowClick` runs in addition to selection under `selectionMode: "row"`. |
|
|
153
160
|
| `TMDataGrid.Footer` | `pageSizeOptions` (default `[10, 25, 50, 100]`), `pagination` render prop | Pagination controls. Renders nothing unless pagination is enabled. |
|
|
154
161
|
| `TMDataGrid.Toolbar` | `children` | Flex row above the grid. |
|
|
155
162
|
| `TMDataGrid.Spacer` | - | Pushes later toolbar items right. |
|
|
156
163
|
| `TMDataGrid.SummaryCount` | `children` | Visible rows out of total. |
|
|
157
|
-
| `TMDataGrid.Search` | `placeholder`, `debounce` (default `250`), `w` (default `220`) | Quick search over every column, debounced into `globalFilter`. Renders nothing under `enableGlobalFilter: false`. |
|
|
164
|
+
| `TMDataGrid.Search` | `placeholder`, `debounce` (default `250`), `w` (default `220`) | Quick search over every column, debounced into `globalFilter`. Renders nothing under `enableGlobalFilter: false`. Also exported as `TMDataGridSearch`. |
|
|
158
165
|
| `TMDataGrid.LoadingIndicator` | - | Small spinner while `meta.loading` is `true` and rows stay on screen. |
|
|
159
166
|
| `TMDataGrid.DraftActions` | `renderActions` | Save with the pending count, and Discard. Renders nothing while editing is off - see the `editing` skill. |
|
|
160
|
-
| `TMDataGrid.FilterButton` | - | Toggles filter
|
|
161
|
-
| `TMDataGrid.
|
|
162
|
-
| `TMDataGrid.FilterPanel` |
|
|
163
|
-
| `TMDataGrid.ColumnsPanel` | - |
|
|
167
|
+
| `TMDataGrid.FilterButton` | - | Toggles the filter surface, seeding a filter row on the first filterable column. Renders nothing if no column is filterable, or under `filters.surface: "none"`. |
|
|
168
|
+
| `TMDataGrid.Menu` | `children`, `icon`, `label`, Mantine `MenuProps` | The burger and its dropdown: your own `Menu.Item`s, and `TMDataGrid.Menu.Columns`, the column chooser as menu items (renders nothing if no column is hideable). See the `appearance` skill. |
|
|
169
|
+
| `TMDataGrid.FilterPanel` | `layout` (`"row"` \| `"stacked"`, default `"row"`) | Filter rows over "Add filter" / "Clear all", as a plain block. Rendered by `.Table` inside the popup and the sidebar; place it yourself under `filters.surface: "none"`. See the `filtering` skill. |
|
|
170
|
+
| `TMDataGrid.ColumnsPanel` | - | The column chooser as plain controls, for a Popover or a Drawer. |
|
|
164
171
|
| `TMDataGrid.FilterPills` | `api`, `size` (default `"sm"`), `showClearAll` (default `true`), `onPillClick(columnId)`, `className` | One pill per active filter, ✕ to clear it. Takes the api as a prop, so it can be rendered outside the grid. Also exported as `TMDataGridFilterPills`. |
|
|
165
172
|
|
|
173
|
+
Each component's props type is exported, for wrapping a part in a component of
|
|
174
|
+
your own:
|
|
175
|
+
|
|
176
|
+
| Component | Props type |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| `TMDataGrid` | `TMDataGridProps<TData>`: the fields of `TMDataGridApi<TData>`, plus `children`, `size`, `className`, `style`, `id` and `data-testid` |
|
|
179
|
+
| `TMDataGrid.Table` | `TMDataGridTableProps<TData>` |
|
|
180
|
+
| `TMDataGrid.Toolbar` | `TMDataGridToolbarProps`: `children`, `withBottomBorder` (default `false`), Mantine `BoxProps` |
|
|
181
|
+
| `TMDataGrid.Search` · `TMDataGridSearch` | `TMDataGridSearchProps` |
|
|
182
|
+
| `TMDataGrid.Footer` | `TMDataGridFooterProps` |
|
|
183
|
+
| `TMDataGrid.Menu` | `TMDataGridMenuProps`: `children`, `icon`, `label`, Mantine `MenuProps` |
|
|
184
|
+
| `TMDataGrid.Menu.Columns` | `TMDataGridMenuColumnsProps`: `searchable` |
|
|
185
|
+
| `TMDataGrid.Menu.Export` · `.ExportSelected` | `TMDataGridMenuExportProps`: per-item `exportOptions` overrides, `columns` (which also takes `"custom"`), `label` |
|
|
186
|
+
| `TMDataGrid.ColumnsPanel` | `TMDataGridColumnsPanelProps`: `searchable`, Mantine `BoxProps` |
|
|
187
|
+
| `TMDataGrid.FilterPanel` | `TMDataGridFilterPanelProps`: `layout`, Mantine `BoxProps` |
|
|
188
|
+
| `TMDataGrid.FilterPills` · `TMDataGridFilterPills` | `TMDataGridFilterPillsProps<TData>` |
|
|
189
|
+
| `TMDataGrid.DraftActions` · `TMDataGridDraftActions` | `TMDataGridDraftActionsProps`: `renderActions` |
|
|
190
|
+
|
|
191
|
+
`renderActions` on `TMDataGrid.DraftActions` receives
|
|
192
|
+
`TMDataGridDraftActionsSlotArgs`, `{ state, actions, Controls }`, typed
|
|
193
|
+
`TMDataGridDraftActionsState`, `TMDataGridDraftActionsActions` and
|
|
194
|
+
`TMDataGridDraftActionsControls`. The fields are in the `editing` skill.
|
|
195
|
+
|
|
166
196
|
Pass the row type so `onRowClick` stays typed:
|
|
167
197
|
|
|
168
198
|
```tsx
|
|
@@ -247,6 +277,76 @@ The virtualizer needs row height as a number, so it cannot come from CSS alone.
|
|
|
247
277
|
`SIZE_ROW_HEIGHT` is the exported source of these values and the stylesheet
|
|
248
278
|
mirrors them. Set `meta.rowHeight` for a height outside the scale.
|
|
249
279
|
|
|
280
|
+
## Render rows without TMDataGrid.Table
|
|
281
|
+
|
|
282
|
+
To show the rows as something other than a table - cards, a list - keep
|
|
283
|
+
`useTMDataGrid` and `<TMDataGrid>`, and replace `TMDataGrid.Table` with a
|
|
284
|
+
renderer of your own. `TMDataGrid` renders no rows itself, and every other part
|
|
285
|
+
works without the Table, so the toolbar stays. Search, filters, sorting, column
|
|
286
|
+
visibility and row selection write the same table state the grid would.
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
const grid = useTMDataGrid({
|
|
290
|
+
data,
|
|
291
|
+
columns,
|
|
292
|
+
getRowId: (row) => String(row.id),
|
|
293
|
+
// The popup and the sidebar belong to TMDataGrid.Table.
|
|
294
|
+
filters: { surface: "none" },
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
<TMDataGrid {...grid} style={{ flex: 1, minHeight: 0 }}>
|
|
298
|
+
<TMDataGrid.Toolbar>
|
|
299
|
+
<TMDataGrid.Search />
|
|
300
|
+
<TMDataGrid.SummaryCount />
|
|
301
|
+
<TMDataGrid.Menu>
|
|
302
|
+
<TMDataGrid.Menu.Columns />
|
|
303
|
+
</TMDataGrid.Menu>
|
|
304
|
+
</TMDataGrid.Toolbar>
|
|
305
|
+
<TMDataGrid.FilterPanel layout="stacked" />
|
|
306
|
+
<CardList table={grid.table} features={grid.features} />
|
|
307
|
+
</TMDataGrid>;
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Read the rows with `getDisplayedRows(table, features)`: the rows the Table
|
|
311
|
+
would render, in render order - filtered, sorted, the current page when paging
|
|
312
|
+
is active, pinned rows left out. Call it inside a selector with a shallow
|
|
313
|
+
compare:
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { useSelector } from "@tanstack/react-store";
|
|
317
|
+
import { shallow } from "@tanstack/store";
|
|
318
|
+
import { getDisplayedRows } from "@jielga/tmdatagrid";
|
|
319
|
+
|
|
320
|
+
const rows = useSelector(table.store, () => getDisplayedRows(table, features), {
|
|
321
|
+
compare: shallow,
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The table identity never changes, so the React Compiler caches a bare
|
|
326
|
+
`getDisplayedRows(table, features)` call and the list stops following filters
|
|
327
|
+
and sorting. The shallow compare re-renders the list only when the rows change.
|
|
328
|
+
Read `row.getVisibleCells()` the same way, inside
|
|
329
|
+
`useSelector(table.store, () => row.getVisibleCells())`, and skip the generated
|
|
330
|
+
columns with `isGeneratedColumn(cell.column.id)` - the checkbox column is among
|
|
331
|
+
the visible cells while row selection is on. Render each value through the
|
|
332
|
+
column's own renderer: `flexRender(cell.column.columnDef.cell, cell.getContext())`.
|
|
333
|
+
|
|
334
|
+
The following belong to `TMDataGrid.Table` and are not available without it:
|
|
335
|
+
|
|
336
|
+
- the header, with click-to-sort, resizing, dragging and the column menus -
|
|
337
|
+
sort from a control of your own with `table.setSorting`
|
|
338
|
+
- the filter popup and sidebar - set `filters: { surface: "none" }` and place
|
|
339
|
+
`TMDataGrid.FilterPanel` yourself
|
|
340
|
+
- row details, row pinning, cell selection and editing in cells
|
|
341
|
+
- `scrollToRow`, which returns `false` while no Table is mounted
|
|
342
|
+
|
|
343
|
+
Virtualize the list yourself, for example with `useVirtualizer` from
|
|
344
|
+
`@tanstack/react-virtual`.
|
|
345
|
+
|
|
346
|
+
Source: `packages/tmdatagrid/docs/card-view.md`,
|
|
347
|
+
`packages/tmdatagrid/docs/anatomy.md` (Which rows it renders), and the demo
|
|
348
|
+
`apps/docs/src/examples/demos/recipes/CardView.tsx`.
|
|
349
|
+
|
|
250
350
|
## Helpers
|
|
251
351
|
|
|
252
352
|
| Export | Description |
|