@jielga/tmdatagrid 2.4.0 → 2.6.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 +96 -9
- package/dist/index.js +417 -348
- package/dist/index.js.map +1 -1
- package/docs/columns.md +1 -0
- package/docs/components.md +3 -1
- package/docs/editors.md +127 -6
- package/docs/testing.md +1 -0
- package/package.json +1 -1
- package/skills/appearance/SKILL.md +1 -1
- package/skills/cell-selection/SKILL.md +1 -1
- package/skills/columns/SKILL.md +2 -2
- package/skills/columns/references/columns-api.md +1 -0
- package/skills/data/SKILL.md +1 -1
- package/skills/editing/SKILL.md +28 -17
- package/skills/editing/references/editing-api.md +4 -2
- package/skills/editing/references/editors-and-validation.md +103 -4
- package/skills/filtering/SKILL.md +1 -1
- package/skills/getting-started/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +1 -1
- package/skills/migrating-to-2/SKILL.md +1 -1
- package/skills/options/SKILL.md +1 -1
- package/skills/rows/SKILL.md +1 -1
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +1 -1
- package/skills/testing-components/SKILL.md +1 -1
- package/skills/testing-editing/SKILL.md +4 -2
- package/src/components/editors/TMDataGridBooleanEditor.tsx +26 -4
- package/src/components/editors/TMDataGridDateEditor.tsx +33 -5
- package/src/components/editors/TMDataGridMultiSelectEditor.tsx +39 -6
- package/src/components/editors/TMDataGridNumberEditor.tsx +33 -6
- package/src/components/editors/TMDataGridSelectEditor.tsx +39 -6
- package/src/components/editors/TMDataGridStringEditor.tsx +33 -6
- package/src/components/editors/editorShared.ts +27 -1
- package/src/core/editEngine.ts +101 -5
- package/src/index.ts +26 -6
- package/src/useTMDataGrid.tsx +1 -1
package/docs/columns.md
CHANGED
|
@@ -125,6 +125,7 @@ meta: {
|
|
|
125
125
|
| `editor` | `TMDataGridEditorComponent` | By `type` | Replaces the cell editor. See [Editors](/docs/editors#writing-your-own). |
|
|
126
126
|
| `validate` | `TMDataGridFieldValidate` | - | Per-cell validation. See [Validation](/docs/editors#validation). |
|
|
127
127
|
| `mapValue` | `TMDataGridEditValueMap` | - | Maps each value an editor writes. See [Mapping the value](/docs/editors#mapping-the-value-as-it-is-typed). |
|
|
128
|
+
| `mapCommitValue` | `TMDataGridEditCommitMap` | - | Maps each changed field once, as its row commits. See [Mapping the value at commit](/docs/editors#mapping-the-value-at-commit). |
|
|
128
129
|
|
|
129
130
|
```tsx
|
|
130
131
|
meta: {
|
package/docs/components.md
CHANGED
|
@@ -245,7 +245,9 @@ The grid picks one from the column's `meta.type`, and `meta.edit.editor` replace
|
|
|
245
245
|
| `TMDataGridSelectEditor` | `Select`, committing on pick in `"cell"` mode | `"select"` |
|
|
246
246
|
| `TMDataGridMultiSelectEditor` | `MultiSelect`, committing on Enter or blur | `"multiSelect"` |
|
|
247
247
|
|
|
248
|
-
|
|
248
|
+
Each built-in editor also takes `inputProps`, passed to its Mantine control. See [Extending a built-in editor](/docs/editors#extending-a-built-in-editor).
|
|
249
|
+
|
|
250
|
+
Every editor takes the same argument object, `TMDataGridEditorArgs`:
|
|
249
251
|
|
|
250
252
|
| Field | Type | What it is |
|
|
251
253
|
| --- | --- | --- |
|
package/docs/editors.md
CHANGED
|
@@ -29,10 +29,98 @@ source the filter panel reads. Neither lives under `meta.edit`.
|
|
|
29
29
|
The number editor writes `null` rather than `NaN` while the text does not parse, so a half-typed number leaves the field empty instead of committing a number no rule can describe.
|
|
30
30
|
The date editor picks between its two types once, when it opens, from what the cell held: a `Date` cell keeps receiving `Date`s and a string cell keeps receiving `"YYYY-MM-DD"` strings, so clearing and retyping cannot flip the type.
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
## Extending a built-in editor
|
|
33
|
+
|
|
34
|
+
Each built-in editor is a named export that takes `TMDataGridEditorArgs` and `inputProps`.
|
|
35
|
+
To change the Mantine control a built-in renders, pass `args` through whole and add props with `inputProps`:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { IconBarcode } from "@tabler/icons-react";
|
|
39
|
+
import {
|
|
40
|
+
TMDataGridStringEditor,
|
|
41
|
+
type TMDataGridEditorComponent,
|
|
42
|
+
} from "@jielga/tmdatagrid";
|
|
43
|
+
|
|
44
|
+
const SkuEditor: TMDataGridEditorComponent = (args) => (
|
|
45
|
+
<TMDataGridStringEditor
|
|
46
|
+
{...args}
|
|
47
|
+
inputProps={{ leftSection: <IconBarcode size={14} /> }}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
columnHelper.accessor("sku", {
|
|
52
|
+
header: "SKU",
|
|
53
|
+
meta: { edit: { editor: SkuEditor } },
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```demo
|
|
58
|
+
file: editing/ExtendedEditors.tsx
|
|
59
|
+
hint: Double-click a cell. SKU has an icon, Price a unit and no negative numbers, Category a dropdown shadow and its own "nothing found" text.
|
|
60
|
+
height: 300
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Define the editor at module scope, as for [your own editor](#writing-your-own).
|
|
64
|
+
Spread `args` into the built-in with `{...args}`: its props type requires every field of `TMDataGridEditorArgs`.
|
|
65
|
+
Do not spread or rebuild `field` itself, because it is a live TanStack Form `FieldApi` and a copy loses the binding its methods rely on.
|
|
66
|
+
|
|
67
|
+
`inputProps` takes the props of the editor's Mantine control and `data-*` attributes, except the props the grid sets itself:
|
|
68
|
+
|
|
69
|
+
| Editor | Mantine control | `inputProps` type | Set by the grid |
|
|
70
|
+
| --- | --- | --- | --- |
|
|
71
|
+
| `TMDataGridStringEditor` | `TextInput` | `TMDataGridStringEditorProps["inputProps"]` | `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label` |
|
|
72
|
+
| `TMDataGridNumberEditor` | `NumberInput` | `TMDataGridNumberEditorProps["inputProps"]` | `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label` |
|
|
73
|
+
| `TMDataGridBooleanEditor` | `Checkbox` | `TMDataGridBooleanEditorProps["inputProps"]` | `checked`, `defaultChecked`, `onChange`, `error`, `size`, `aria-label` |
|
|
74
|
+
| `TMDataGridDateEditor` | `TextInput` | `TMDataGridDateEditorProps["inputProps"]` | `type`, `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label` |
|
|
75
|
+
| `TMDataGridSelectEditor` | `Select` | `TMDataGridSelectEditorProps["inputProps"]` | `data`, `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label`, `comboboxProps.withinPortal` |
|
|
76
|
+
| `TMDataGridMultiSelectEditor` | `MultiSelect` | `TMDataGridMultiSelectEditorProps["inputProps"]` | `data`, `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label`, `comboboxProps.withinPortal` |
|
|
77
|
+
|
|
78
|
+
The props the grid sets are left out of each type, so passing one is a type error.
|
|
79
|
+
`data-dg-part` is set after `inputProps`, so the input keeps `data-dg-part="editor-input"`.
|
|
80
|
+
|
|
81
|
+
- `onFocus` and `onBlur` run after the grid's own handlers.
|
|
82
|
+
The string and number editors select the value on focus, and every editor calls `field.handleBlur()` on blur, which marks the field as touched and runs its `onBlur` validators.
|
|
83
|
+
- `onBlur` runs when focus leaves the editor, for example on a click outside it.
|
|
84
|
+
It does not run when Enter, Tab or Escape closes the editor, or when a pick in the select editor commits under `"cell"`, because the editor closes before the focus moves.
|
|
85
|
+
To run code when an edit ends, use `editing.onCommit`, or `meta.edit.mapCommitValue` to change the committed value.
|
|
86
|
+
- `ref` receives the control's input element; the grid keeps its own ref on it too.
|
|
87
|
+
- `comboboxProps` on the select editors is merged with the grid's, and `withinPortal` is always `false`, because an option picked from a portal is a click outside the cell.
|
|
88
|
+
- The defaults the grid sets on the control can be overridden: `w="100%"` on every editor except the checkbox, `hideControls` on the number editor, and `searchable` on the select editors.
|
|
89
|
+
- The select editors read their options from `meta.options` only, so `data` is not accepted.
|
|
90
|
+
- To change the value as it is typed, use [`meta.edit.mapValue`](#mapping-the-value-as-it-is-typed); `onChange` is the grid's.
|
|
91
|
+
|
|
92
|
+
Important: do not stop the propagation of Enter, Tab or Escape in an `onKeyDown`, as the grid handles these keys on an ancestor to commit, move and cancel.
|
|
93
|
+
Props that add text around the control, such as `label` and `description`, make the editor taller than the cell, and `aria-labelledby` replaces the grid's translated accessible name.
|
|
94
|
+
|
|
95
|
+
To place content beside the control instead of inside it, render the built-in inside your own layout:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { Group, Text } from "@mantine/core";
|
|
99
|
+
import {
|
|
100
|
+
TMDataGridNumberEditor,
|
|
101
|
+
TMDataGridSelectEditor,
|
|
102
|
+
TMDataGridStringEditor,
|
|
103
|
+
type TMDataGridEditorComponent,
|
|
104
|
+
} from "@jielga/tmdatagrid";
|
|
105
|
+
|
|
106
|
+
// Content beside the input.
|
|
107
|
+
const SalaryEditor: TMDataGridEditorComponent = (args) => (
|
|
108
|
+
<Group gap={4} wrap="nowrap" w="100%">
|
|
109
|
+
<TMDataGridNumberEditor {...args} />
|
|
110
|
+
<Text size="xs" c="dimmed">
|
|
111
|
+
per month
|
|
112
|
+
</Text>
|
|
113
|
+
</Group>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// A different built-in per row.
|
|
117
|
+
const DepartmentEditor: TMDataGridEditorComponent = (args) =>
|
|
118
|
+
args.row.original.status === "Terminated" ? (
|
|
119
|
+
<TMDataGridStringEditor {...args} />
|
|
120
|
+
) : (
|
|
121
|
+
<TMDataGridSelectEditor {...args} />
|
|
122
|
+
);
|
|
123
|
+
```
|
|
36
124
|
|
|
37
125
|
## Writing your own
|
|
38
126
|
|
|
@@ -134,6 +222,35 @@ A custom editor rendering its own input has the same problem, and solves it the
|
|
|
134
222
|
same way: record `selectionStart` as the value is handed over, and restore it in
|
|
135
223
|
a layout effect once the mapped value has rendered.
|
|
136
224
|
|
|
225
|
+
## Mapping the value at commit
|
|
226
|
+
|
|
227
|
+
`meta.edit.mapCommitValue` maps a field once, as its row commits, instead of on every write.
|
|
228
|
+
Use it for a rule the user must be free to break while typing, such as trimming a string: with `mapValue`, a trailing space could never be typed.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
meta: {
|
|
232
|
+
edit: {
|
|
233
|
+
mapCommitValue: ({ value }) =>
|
|
234
|
+
typeof value === "string" ? value.trim() : value,
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
It runs before the validators of the submit, so a field that trims to `""` fails a required rule.
|
|
240
|
+
The result is written back into the form, so the draft, `changes` and `onCommit` all hold the mapped value.
|
|
241
|
+
An editor still open after the commit shows it too: in row mode, or after a commit the validators refused.
|
|
242
|
+
When a draft is held for `saveDrafts`, the mapped value is what the pending change shows.
|
|
243
|
+
|
|
244
|
+
It runs for the fields the user changed.
|
|
245
|
+
A stored value nobody edited is left as it is.
|
|
246
|
+
A row being added has no stored value, so every editable field of it is mapped, a field `meta.edit.enabled` keeps the user out of included.
|
|
247
|
+
A field written by `edit.setCellValue()`, `edit.setRowValues()`, `edit.clearCell()` or the Delete key is not mapped, because the caller passes the stored value itself; the other fields the user changed in the same row still are.
|
|
248
|
+
The rows of `edit.addRows({ commit: true })` are not mapped at all.
|
|
249
|
+
|
|
250
|
+
The map receives `TMDataGridEditCommitMapArgs`: `{ value, previous, row, column, table }`.
|
|
251
|
+
`previous` is the value the field held when editing began, and `row` is `undefined` for a row being added.
|
|
252
|
+
`mapValue` runs first, and its result is what `value` holds here.
|
|
253
|
+
|
|
137
254
|
## Validation
|
|
138
255
|
|
|
139
256
|
The validators are TanStack Form's own: a Standard Schema (Zod, Valibot,
|
|
@@ -240,11 +357,15 @@ validator instead. See [A query builder form](/docs/query-builder).
|
|
|
240
357
|
| `meta.edit.editor` | Column meta | `TMDataGridEditorComponent` | By `meta.type` | Replaces the cell editor. |
|
|
241
358
|
| `meta.edit.validate` | Column meta | `TMDataGridFieldValidate` | – | Field-level validation. A bare schema or function means `onChange`. |
|
|
242
359
|
| `meta.edit.mapValue` | Column meta | `TMDataGridEditValueMap` | – | Maps each value an editor writes, before it reaches the draft. |
|
|
360
|
+
| `meta.edit.mapCommitValue` | Column meta | `TMDataGridEditCommitMap` | – | Maps each changed field once, as its row commits. See [Mapping the value at commit](#mapping-the-value-at-commit). |
|
|
243
361
|
| `editing.rowValidators` | Option | `TMDataGridRowValidators` | – | Form-level validation, for cross-field rules. |
|
|
244
362
|
| `editing.tableValidators` | Option | `TMDataGridTableValidators` | – | Cross-row rules, handed the collection with every draft overlaid. See [Cross-row rules](#cross-row-rules). |
|
|
245
363
|
| `TMDataGridTableValidateArgs` | Export | type | – | What a table validator receives: `value`, `rowId`, `isNew`, `rows`. |
|
|
246
|
-
| `TMDataGridEditorArgs` | Export | type | – | What an editor component receives: `field`, `commit`, `cancel`, `
|
|
364
|
+
| `TMDataGridEditorArgs` | Export | type | – | What an editor component receives: `field`, `form`, `cell`, `row`, `column`, `table`, `commit`, `cancel`, `size`, `seedText`. See [Editors](/docs/components#editors). |
|
|
247
365
|
| `TMDataGridEditValueMapArgs` | Export | type | – | What `mapValue` receives: `value`, `previous`, `row`, `column`, `table`. |
|
|
248
|
-
| `
|
|
366
|
+
| `TMDataGridEditCommitMapArgs` | Export | type | – | What `mapCommitValue` receives: `value`, `previous`, `row`, `column`, `table`. |
|
|
367
|
+
| `TMDataGridStringEditor` · `NumberEditor` · `BooleanEditor` · `DateEditor` · `SelectEditor` · `MultiSelectEditor` | Exports | components | – | The six built-in editors. See [Extending a built-in editor](#extending-a-built-in-editor). |
|
|
368
|
+
| `inputProps` | Built-in editor prop | The Mantine control's props and `data-*` attributes, without the props the grid sets | – | Props passed to the Mantine control of a built-in editor. |
|
|
369
|
+
| `TMDataGridStringEditorProps` · `NumberEditorProps` · `BooleanEditorProps` · `DateEditorProps` · `SelectEditorProps` · `MultiSelectEditorProps` | Exports | types | – | The props of each built-in editor: `TMDataGridEditorArgs` and `inputProps`. |
|
|
249
370
|
| `normalizeFieldValidate` | Export | `(validate) => validators` | – | Turns a bare schema into TanStack Form's validator shape. |
|
|
250
371
|
| `getEditFieldName` | Export | `(column) => string` | – | The data path a column's edits write to. |
|
package/docs/testing.md
CHANGED
|
@@ -185,6 +185,7 @@ None of them carries `data-column-id`; scope through the row.
|
|
|
185
185
|
A column declaring `meta.filter.control` or `meta.edit.editor` renders your component
|
|
186
186
|
in that slot, so `filter-value` and `editor-input` cover the built-ins only.
|
|
187
187
|
`filter-row` and `editor` still apply; scope your own queries through them.
|
|
188
|
+
A built-in editor extended through `inputProps` keeps `editor-input`.
|
|
188
189
|
|
|
189
190
|
`editor-input` is also where the grid puts the caret when an editor opens. An
|
|
190
191
|
editor that does not publish it is focused on the first focusable element inside
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jielga/tmdatagrid",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "A React data grid built on TanStack Table v9 and Mantine - always virtualized, with resizable, reorderable, sortable, filterable, hideable and pinnable columns.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -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.6.0'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/react:packages/tmdatagrid/docs/cell-selection.md'
|
|
20
20
|
- 'Jielga/react:packages/tmdatagrid/src/core/cellNavigation.ts'
|
package/skills/columns/SKILL.md
CHANGED
|
@@ -16,7 +16,7 @@ description: >
|
|
|
16
16
|
metadata:
|
|
17
17
|
type: core
|
|
18
18
|
library: '@jielga/tmdatagrid'
|
|
19
|
-
library_version: '2.
|
|
19
|
+
library_version: '2.6.0'
|
|
20
20
|
sources:
|
|
21
21
|
- 'Jielga/react:packages/tmdatagrid/docs/columns.md'
|
|
22
22
|
- 'Jielga/react:packages/tmdatagrid/docs/column-layout.md'
|
|
@@ -98,7 +98,7 @@ with it sits in their namespaces. `type` and `options` are read by both stages,
|
|
|
98
98
|
which is why they are in neither.
|
|
99
99
|
|
|
100
100
|
`meta.filter` holds `operators`, `defaultOperator`, `control` and `url`; `meta.edit`
|
|
101
|
-
holds `enabled`, `field`, `editor`, `validate` and `
|
|
101
|
+
holds `enabled`, `field`, `editor`, `validate`, `mapValue` and `mapCommitValue`. Their fields are
|
|
102
102
|
in [references/columns-api.md](references/columns-api.md).
|
|
103
103
|
|
|
104
104
|
```tsx
|
|
@@ -22,6 +22,7 @@ Reference for the `columns` skill.
|
|
|
22
22
|
| `editor` | `TMDataGridEditorComponent` | By `meta.type` | Replaces the cell editor. Module scope. |
|
|
23
23
|
| `validate` | `TMDataGridFieldValidate` | – | Field-level validation. A bare schema means `onChange`. |
|
|
24
24
|
| `mapValue` | `TMDataGridEditValueMap` | – | Maps each value an editor writes, on every keystroke. |
|
|
25
|
+
| `mapCommitValue` | `TMDataGridEditCommitMap` | – | Maps each changed field once, as its row commits. |
|
|
25
26
|
|
|
26
27
|
## Column-level feature options
|
|
27
28
|
|
package/skills/data/SKILL.md
CHANGED
package/skills/editing/SKILL.md
CHANGED
|
@@ -5,20 +5,20 @@ description: >
|
|
|
5
5
|
(mode: cell, cellConfirm, row; draft), the required getRowId, editing.onCommit
|
|
6
6
|
and editing.onSaveDrafts, why the grid never mutates data, gating with
|
|
7
7
|
editing.columns, meta.edit.enabled and meta.edit.field, the built-in editors
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
cross-field editing.rowValidators, cross-row
|
|
11
|
-
draft-overlaid collection - adding and
|
|
12
|
-
newRowDefaults, onRowAdd, onRowDelete), the edit
|
|
13
|
-
and renderActions, and the edit engine (begin,
|
|
14
|
-
addRows, setCellValue, setRowValues, getForm,
|
|
15
|
-
editable, choosing an edit mode, wiring a
|
|
16
|
-
validating an edit, writing cells from a toolbar
|
|
17
|
-
cells will not open.
|
|
8
|
+
(meta.type, inputProps), custom editors via meta.edit.editor, value mapping
|
|
9
|
+
with mapValue and mapCommitValue, validation at every level -
|
|
10
|
+
meta.edit.validate, cross-field editing.rowValidators, cross-row
|
|
11
|
+
editing.tableValidators over the draft-overlaid collection - adding and
|
|
12
|
+
deleting rows (edit.addRow, newRowDefaults, onRowAdd, onRowDelete), the edit
|
|
13
|
+
lane, TMDataGrid.DraftActions and renderActions, and the edit engine (begin,
|
|
14
|
+
commit, commitAll, saveDrafts, addRows, setCellValue, setRowValues, getForm,
|
|
15
|
+
store). Load when making a grid editable, choosing an edit mode, wiring a
|
|
16
|
+
save, writing a cell editor, validating an edit, writing cells from a toolbar
|
|
17
|
+
action or bulk fill, or when cells will not open.
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.
|
|
21
|
+
library_version: '2.6.0'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/react:packages/tmdatagrid/docs/editing.md'
|
|
24
24
|
- 'Jielga/react:packages/tmdatagrid/docs/draft-store.md'
|
|
@@ -207,11 +207,9 @@ columnHelper.accessor("salary", {
|
|
|
207
207
|
|
|
208
208
|
## Editors and validation
|
|
209
209
|
|
|
210
|
-
`meta.type` picks the editor - `"string"` (the default), `"number"`,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
one, with the value it writes into the draft and the export that wraps it, is in
|
|
214
|
-
[references/editors-and-validation.md](references/editors-and-validation.md#the-built-in-editors).
|
|
210
|
+
`meta.type` picks the editor - `"string"` (the default), `"number"`, `"boolean"`, `"date"`, `"select"` and `"multiSelect"` - and `meta.options` feeds the two select editors from the same declaration the filter panel reads.
|
|
211
|
+
Each one, with the value it writes into the draft and its export, is in [references/editors-and-validation.md](references/editors-and-validation.md#the-built-in-editors).
|
|
212
|
+
To add a `leftSection`, a unit or a wider dropdown, do not copy a built-in: render it from `meta.edit.editor` with `inputProps` ([Extending a built-in](references/editors-and-validation.md#extending-a-built-in)).
|
|
215
213
|
|
|
216
214
|
`meta.edit.editor` replaces one, `meta.edit.validate` guards the field, and
|
|
217
215
|
`editing.rowValidators` carries cross-field rules. The validators are TanStack
|
|
@@ -274,6 +272,19 @@ validators check and what is committed.
|
|
|
274
272
|
meta: { edit: { mapValue: ({ value }) => String(value).toUpperCase() } }
|
|
275
273
|
```
|
|
276
274
|
|
|
275
|
+
`meta.edit.mapCommitValue` maps once, as the row commits, for a rule the user must be free to break while typing: trimming a string.
|
|
276
|
+
It runs before the submit validators on the fields the user changed, and writes the result back into the form, so the draft store, `changes` and `onCommit` all hold the mapped value.
|
|
277
|
+
Trimming only in `onCommit` or on the server leaves the grid's own state untrimmed.
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
meta: {
|
|
281
|
+
edit: {
|
|
282
|
+
mapCommitValue: ({ value }) =>
|
|
283
|
+
typeof value === "string" ? value.trim() : value,
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
277
288
|
Detail for all three: [references/editors-and-validation.md](references/editors-and-validation.md).
|
|
278
289
|
|
|
279
290
|
## Adding and deleting rows
|
|
@@ -474,7 +485,7 @@ are in [references/common-mistakes.md](references/common-mistakes.md).
|
|
|
474
485
|
## References
|
|
475
486
|
|
|
476
487
|
- [Editors and validation](references/editors-and-validation.md) - the editor
|
|
477
|
-
API,
|
|
488
|
+
API, extending a built-in with `inputProps`, what `mapValue` leaves alone, field, row and
|
|
478
489
|
cross-row validators, derived columns with a table-wide rule, server-side
|
|
479
490
|
errors.
|
|
480
491
|
- [Editing API](references/editing-api.md) - every option, callback, column meta
|
|
@@ -124,7 +124,8 @@ type TMDataGridEditState = {
|
|
|
124
124
|
| `hasPendingEdits` | Export | `(state) => boolean` - unsaved work: an open row with a changed value, any entry row, the draft store, or a save in flight. `useSelector(grid.edit.store, hasPendingEdits)` for a navigation blocker; do not use `openRowIds.length`, which also counts committed rows and rows that are only open. |
|
|
125
125
|
| `getEditFieldName` | Export | `(column) => string` - the data path a column's edits write to. |
|
|
126
126
|
| `normalizeFieldValidate` | Export | `(validate) => validators` - a bare schema into Form's shape. |
|
|
127
|
-
| `TMDataGridStringEditor` … `TMDataGridMultiSelectEditor` | Exports | The six built-in editors, for wrapping. |
|
|
127
|
+
| `TMDataGridStringEditor` … `TMDataGridMultiSelectEditor` | Exports | The six built-in editors, for extending with `inputProps` or wrapping. |
|
|
128
|
+
| `TMDataGridStringEditorProps` · `TMDataGridNumberEditorProps` · `TMDataGridBooleanEditorProps` · `TMDataGridDateEditorProps` · `TMDataGridSelectEditorProps` · `TMDataGridMultiSelectEditorProps` | Exports | The props of each built-in editor: `TMDataGridEditorArgs` and `inputProps`. |
|
|
128
129
|
|
|
129
130
|
Types: `TMDataGridEditMode`, `TMDataGridEditApi`, `TMDataGridEditState`,
|
|
130
131
|
`TMDataGridEditCommitArgs`, `TMDataGridSaveDraftsArgs`,
|
|
@@ -133,7 +134,8 @@ Types: `TMDataGridEditMode`, `TMDataGridEditApi`, `TMDataGridEditState`,
|
|
|
133
134
|
`TMDataGridRowValidators`, `TMDataGridRowEditForm`, `TMDataGridRowAddArgs`,
|
|
134
135
|
`TMDataGridRowDeleteArgs`, `TMDataGridEditingOptions`,
|
|
135
136
|
`TMDataGridSaveOutcomes`, `TMDataGridAddRowsOptions`,
|
|
136
|
-
`TMDataGridEditValueMapArgs`, `
|
|
137
|
+
`TMDataGridEditValueMapArgs`, `TMDataGridEditCommitMapArgs`,
|
|
138
|
+
`TMDataGridTableValidateArgs`.
|
|
137
139
|
|
|
138
140
|
## The edit lane
|
|
139
141
|
|
|
@@ -94,11 +94,86 @@ columnHelper.accessor("salary", {
|
|
|
94
94
|
});
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
##
|
|
97
|
+
## Extending a built-in
|
|
98
98
|
|
|
99
|
-
The built-ins take `TMDataGridEditorArgs` as their props
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
The built-ins take `TMDataGridEditorArgs` and `inputProps` as their props. To
|
|
100
|
+
change the Mantine control a built-in renders, render it from a
|
|
101
|
+
`meta.edit.editor`, pass `args` through whole, and add props with `inputProps`.
|
|
102
|
+
Extend a built-in rather than copying its source: keeping the caret in place
|
|
103
|
+
while `mapValue` rewrites the value, select-all on focus, the invalid border,
|
|
104
|
+
the translated accessible name and `data-dg-part="editor-input"` all come with
|
|
105
|
+
it. The props type requires every field of `TMDataGridEditorArgs`, so spread
|
|
106
|
+
`{...args}`; never spread or rebuild `field` itself.
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { Text } from "@mantine/core";
|
|
110
|
+
import { IconBarcode } from "@tabler/icons-react";
|
|
111
|
+
import {
|
|
112
|
+
TMDataGridNumberEditor,
|
|
113
|
+
TMDataGridSelectEditor,
|
|
114
|
+
TMDataGridStringEditor,
|
|
115
|
+
type TMDataGridEditorComponent,
|
|
116
|
+
} from "@jielga/tmdatagrid";
|
|
117
|
+
|
|
118
|
+
// Module scope. A new identity per render remounts the editor mid-edit.
|
|
119
|
+
const SkuEditor: TMDataGridEditorComponent = (args) => (
|
|
120
|
+
<TMDataGridStringEditor
|
|
121
|
+
{...args}
|
|
122
|
+
inputProps={{ leftSection: <IconBarcode size={14} /> }}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const PriceEditor: TMDataGridEditorComponent = (args) => (
|
|
127
|
+
<TMDataGridNumberEditor
|
|
128
|
+
{...args}
|
|
129
|
+
inputProps={{ allowNegative: false, rightSection: <Text size="xs">kr</Text> }}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// comboboxProps is merged with the grid's; withinPortal is not accepted.
|
|
134
|
+
const CategoryEditor: TMDataGridEditorComponent = (args) => (
|
|
135
|
+
<TMDataGridSelectEditor {...args} inputProps={{ comboboxProps: { shadow: "md" } }} />
|
|
136
|
+
);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
| Editor | Mantine control | Set by the grid, left out of `inputProps` |
|
|
140
|
+
| --- | --- | --- |
|
|
141
|
+
| `TMDataGridStringEditor` | `TextInput` | `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label` |
|
|
142
|
+
| `TMDataGridNumberEditor` | `NumberInput` | `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label` |
|
|
143
|
+
| `TMDataGridBooleanEditor` | `Checkbox` | `checked`, `defaultChecked`, `onChange`, `error`, `size`, `aria-label` |
|
|
144
|
+
| `TMDataGridDateEditor` | `TextInput` | `type`, `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label` |
|
|
145
|
+
| `TMDataGridSelectEditor` | `Select` | `data`, `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label`, `comboboxProps.withinPortal` |
|
|
146
|
+
| `TMDataGridMultiSelectEditor` | `MultiSelect` | `data`, `value`, `defaultValue`, `onChange`, `error`, `size`, `aria-label`, `comboboxProps.withinPortal` |
|
|
147
|
+
|
|
148
|
+
- `inputProps` also takes `data-*` attributes; `data-dg-part` stays
|
|
149
|
+
`"editor-input"`, because the grid sets it after the spread.
|
|
150
|
+
- `onFocus` and `onBlur` run after the grid's own: select-all on focus in the
|
|
151
|
+
string and number editors, `field.handleBlur()` (touched, `onBlur`
|
|
152
|
+
validators) in every editor.
|
|
153
|
+
- `onBlur` runs only when focus leaves the editor, such as a click outside it.
|
|
154
|
+
Enter, Tab, Escape and a committing select pick close the editor before the
|
|
155
|
+
focus moves, so it does not run. Code for "the edit ended" belongs in
|
|
156
|
+
`editing.onCommit` or `meta.edit.mapCommitValue`.
|
|
157
|
+
- `ref` receives the input element; the grid's own ref stays attached.
|
|
158
|
+
- `comboboxProps` is merged with the grid's and `withinPortal` is always
|
|
159
|
+
`false`, because an option picked from a portal is a click outside the cell.
|
|
160
|
+
- A consumer `onKeyDown` must not stop the propagation of Enter, Tab or Escape:
|
|
161
|
+
the grid handles them on an ancestor.
|
|
162
|
+
- `label` and `description` make the editor taller than the cell;
|
|
163
|
+
`aria-labelledby` replaces the grid's translated accessible name.
|
|
164
|
+
- `onChange` is the grid's; to rewrite the value as it is typed, use
|
|
165
|
+
`meta.edit.mapValue`.
|
|
166
|
+
- The grid's defaults can be overridden: `w="100%"` (not on the checkbox),
|
|
167
|
+
`hideControls` on the number editor, `searchable` on the select editors.
|
|
168
|
+
- The select editors read options from `meta.options` only; `data` is not
|
|
169
|
+
accepted.
|
|
170
|
+
- The props types are exported: `TMDataGridStringEditorProps`,
|
|
171
|
+
`TMDataGridNumberEditorProps`, `TMDataGridBooleanEditorProps`,
|
|
172
|
+
`TMDataGridDateEditorProps`, `TMDataGridSelectEditorProps`,
|
|
173
|
+
`TMDataGridMultiSelectEditorProps`.
|
|
174
|
+
|
|
175
|
+
To place content beside the control instead of inside it, render the built-in
|
|
176
|
+
inside your own layout:
|
|
102
177
|
|
|
103
178
|
```tsx
|
|
104
179
|
import { Group, Text } from "@mantine/core";
|
|
@@ -182,6 +257,30 @@ otherwise drops the caret at the end of the field. A custom editor rendering its
|
|
|
182
257
|
own input has to do the same: record `selectionStart` on change, restore it in a
|
|
183
258
|
layout effect.
|
|
184
259
|
|
|
260
|
+
## Mapping the value at commit
|
|
261
|
+
|
|
262
|
+
`meta.edit.mapCommitValue` maps a field once, as its row commits, where `mapValue` runs on every write.
|
|
263
|
+
Use it for a rule the user must be free to break while typing: trimming a string, because with `mapValue` a trailing space could never be typed.
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
meta: {
|
|
267
|
+
edit: {
|
|
268
|
+
mapCommitValue: ({ value }) =>
|
|
269
|
+
typeof value === "string" ? value.trim() : value,
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
- It runs before the submit validators, so `" "` trimmed to `""` fails a required rule.
|
|
275
|
+
- The result is written back into the form: the draft store, `changes` and `onCommit` hold the mapped value, and so does an editor still open after the commit (row mode, or a refused commit).
|
|
276
|
+
Trimming in `onCommit` or on the server instead leaves the grid's own state untrimmed.
|
|
277
|
+
- It maps only the fields the user changed.
|
|
278
|
+
A row being added maps every editable field.
|
|
279
|
+
- A field written by `edit.setCellValue()`, `edit.setRowValues()`, `edit.clearCell()` or the Delete key is not mapped; the other fields the user changed in that row still are.
|
|
280
|
+
The rows of `edit.addRows({ commit: true })` are not mapped at all.
|
|
281
|
+
- The map receives `TMDataGridEditCommitMapArgs`: `{ value, previous, row, column, table }`.
|
|
282
|
+
`previous` is the value when editing began; `row` is `undefined` for a row being added.
|
|
283
|
+
|
|
185
284
|
## Field validation
|
|
186
285
|
|
|
187
286
|
`meta.edit.validate` takes TanStack Form's field-validator vocabulary. A bare schema
|
|
@@ -18,7 +18,7 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.
|
|
21
|
+
library_version: '2.6.0'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/react:packages/tmdatagrid/docs/filtering.md'
|
|
24
24
|
- 'Jielga/react:packages/tmdatagrid/docs/quick-search.md'
|
|
@@ -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.6.0'
|
|
17
17
|
sources:
|
|
18
18
|
- 'Jielga/react:packages/tmdatagrid/docs/getting-started.md'
|
|
19
19
|
- 'Jielga/react:packages/tmdatagrid/docs/anatomy.md'
|
package/skills/grouping/SKILL.md
CHANGED
|
@@ -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.6.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
|
@@ -18,7 +18,7 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.
|
|
21
|
+
library_version: '2.6.0'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/react:packages/tmdatagrid/docs/use-tm-data-grid.md'
|
|
24
24
|
- 'Jielga/react:packages/tmdatagrid/docs/persistence.md'
|
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.6.0'
|
|
21
21
|
sources:
|
|
22
22
|
- 'Jielga/react:packages/tmdatagrid/docs/row-selection.md'
|
|
23
23
|
- 'Jielga/react:packages/tmdatagrid/docs/row-interaction.md'
|
|
@@ -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.6.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
|
@@ -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.6.0'
|
|
16
16
|
sources:
|
|
17
17
|
- 'Jielga/react:packages/tmdatagrid/docs/testing.md'
|
|
18
18
|
- 'Jielga/react:packages/tmdatagrid/test/gallery/main.tsx'
|
|
@@ -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.6.0'
|
|
16
16
|
sources:
|
|
17
17
|
- 'Jielga/react:packages/tmdatagrid/docs/testing.md'
|
|
18
18
|
- 'Jielga/react:packages/tmdatagrid/docs/editing.md'
|
|
@@ -102,7 +102,9 @@ async saveDrafts(): Promise<void> {
|
|
|
102
102
|
|
|
103
103
|
`fillRow` covers the built-in editors. A column with `meta.edit.editor` renders
|
|
104
104
|
the app's own component inside the `editor` part; scope through
|
|
105
|
-
`part("editor", { rowId, columnId })` and fill whatever is inside.
|
|
105
|
+
`part("editor", { rowId, columnId })` and fill whatever is inside. A built-in
|
|
106
|
+
editor rendered through `meta.edit.editor` with `inputProps` keeps
|
|
107
|
+
`editor-input`, so `fillRow` covers it.
|
|
106
108
|
|
|
107
109
|
## Recipes
|
|
108
110
|
|
|
@@ -1,26 +1,48 @@
|
|
|
1
|
-
import { Checkbox } from "@mantine/core";
|
|
1
|
+
import { Checkbox, type CheckboxProps } from "@mantine/core";
|
|
2
2
|
import type { TMDataGridEditorArgs } from "../../core/editEngine";
|
|
3
3
|
import { getColumnLabel } from "../../core/columnUtils";
|
|
4
4
|
import { useTMDataGridContext } from "../../TMDataGridContext";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
useFieldInvalid,
|
|
7
|
+
useFieldValue,
|
|
8
|
+
type EditorDataAttributes,
|
|
9
|
+
} from "./editorShared";
|
|
10
|
+
|
|
11
|
+
export type TMDataGridBooleanEditorProps = TMDataGridEditorArgs & {
|
|
12
|
+
/**
|
|
13
|
+
* Props for the Mantine `Checkbox`. The grid keeps `checked`, `onChange`,
|
|
14
|
+
* `error`, `size` and the accessible name; `onBlur` runs after the grid's
|
|
15
|
+
* own.
|
|
16
|
+
*/
|
|
17
|
+
inputProps?: Omit<
|
|
18
|
+
CheckboxProps,
|
|
19
|
+
"checked" | "defaultChecked" | "onChange" | "error" | "size" | "aria-label"
|
|
20
|
+
> &
|
|
21
|
+
EditorDataAttributes;
|
|
22
|
+
};
|
|
6
23
|
|
|
7
24
|
/** The built-in editor for `meta.type: "boolean"` - a focused checkbox. */
|
|
8
25
|
export function TMDataGridBooleanEditor({
|
|
9
26
|
field,
|
|
10
27
|
column,
|
|
11
28
|
size,
|
|
12
|
-
|
|
29
|
+
inputProps,
|
|
30
|
+
}: TMDataGridBooleanEditorProps) {
|
|
13
31
|
const { labels } = useTMDataGridContext();
|
|
14
32
|
const value = useFieldValue(field);
|
|
15
33
|
const invalid = useFieldInvalid(field);
|
|
16
34
|
return (
|
|
17
35
|
<Checkbox
|
|
36
|
+
{...inputProps}
|
|
18
37
|
size={size}
|
|
19
38
|
aria-label={labels.editCell(getColumnLabel(column))}
|
|
20
39
|
data-dg-part="editor-input"
|
|
21
40
|
checked={value === true}
|
|
22
41
|
onChange={(event) => field.handleChange(event.currentTarget.checked)}
|
|
23
|
-
onBlur={
|
|
42
|
+
onBlur={(event) => {
|
|
43
|
+
field.handleBlur();
|
|
44
|
+
inputProps?.onBlur?.(event);
|
|
45
|
+
}}
|
|
24
46
|
error={invalid}
|
|
25
47
|
/>
|
|
26
48
|
);
|