@jielga/tmdatagrid 2.0.0-beta.2 → 2.0.0-beta.4
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 +185 -48
- package/dist/index.js +1558 -1341
- package/dist/index.js.map +1 -1
- 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 +1 -1
- package/skills/data/SKILL.md +1 -1
- package/skills/editing/SKILL.md +59 -25
- package/skills/editing/references/common-mistakes.md +10 -8
- package/skills/editing/references/editing-api.md +20 -13
- package/skills/filtering/SKILL.md +1 -1
- package/skills/getting-started/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +1 -1
- package/skills/options/SKILL.md +33 -3
- package/skills/rows/SKILL.md +1 -1
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +1 -1
- package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +10 -7
- package/src/tmdatagrid/components/TMDataGridEditActions.tsx +96 -25
- package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +1 -1
- package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +21 -18
- package/src/tmdatagrid/components/TMDataGridTable.tsx +13 -0
- package/src/tmdatagrid/core/controlledState.ts +179 -0
- package/src/tmdatagrid/core/editEngine.ts +480 -77
- package/src/tmdatagrid/core/labels.ts +8 -1
- package/src/tmdatagrid/core/labelsSv.ts +2 -0
- package/src/tmdatagrid/index.ts +5 -0
- package/src/tmdatagrid/useTMDataGrid.tsx +154 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jielga/tmdatagrid",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.4",
|
|
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.0.0-beta.
|
|
17
|
+
library_version: '2.0.0-beta.4'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/TMDataGrid:src/docs/cell-selection.md'
|
|
20
20
|
- 'Jielga/TMDataGrid:src/tmdatagrid/core/cellNavigation.ts'
|
package/skills/columns/SKILL.md
CHANGED
package/skills/data/SKILL.md
CHANGED
package/skills/editing/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: editing
|
|
|
3
3
|
description: >
|
|
4
4
|
Edit cells and rows in TMDataGrid. Covers the editing option with its four
|
|
5
5
|
mode policies (cell, cellConfirm, row, draft), the required getRowId,
|
|
6
|
-
editing.onCommit and editing.
|
|
6
|
+
editing.onCommit and editing.onSaveDrafts, why the grid never mutates data,
|
|
7
7
|
per-column gating with meta.edit.enabled and meta.edit.field, the six built-in
|
|
8
8
|
editors picked by meta.type, custom editors through meta.edit.editor,
|
|
9
9
|
per-keystroke value mapping with meta.edit.mapValue, field validation with
|
|
@@ -11,13 +11,14 @@ description: >
|
|
|
11
11
|
Schema and Zod), adding and deleting rows with edit.addRow,
|
|
12
12
|
editing.newRowDefaults, editing.onRowAdd and editing.onRowDelete, the
|
|
13
13
|
generated edit lane, TMDataGrid.EditActions with its renderActions slot, and
|
|
14
|
-
the public edit engine (begin, commit,
|
|
15
|
-
Load when making a grid editable, choosing an edit mode,
|
|
16
|
-
writing a cell editor, validating an edit, or when cells will
|
|
14
|
+
the public edit engine (begin, commit, commitAll, saveDrafts, addRows,
|
|
15
|
+
getForm, store). Load when making a grid editable, choosing an edit mode,
|
|
16
|
+
wiring a save, writing a cell editor, validating an edit, or when cells will
|
|
17
|
+
not open.
|
|
17
18
|
metadata:
|
|
18
19
|
type: core
|
|
19
20
|
library: '@jielga/tmdatagrid'
|
|
20
|
-
library_version: '2.0.0-beta.
|
|
21
|
+
library_version: '2.0.0-beta.4'
|
|
21
22
|
sources:
|
|
22
23
|
- 'Jielga/TMDataGrid:src/docs/editing.md'
|
|
23
24
|
- 'Jielga/TMDataGrid:src/docs/query-builder.md'
|
|
@@ -69,8 +70,8 @@ const grid = useTMDataGrid({
|
|
|
69
70
|
```
|
|
70
71
|
|
|
71
72
|
Two rules are compile errors, not options that silently do nothing: `editing`
|
|
72
|
-
requires `getRowId`, and `editing.
|
|
73
|
-
`editing.mode: "draft"`. Draft _without_ `
|
|
73
|
+
requires `getRowId`, and `editing.onSaveDrafts` exists only under
|
|
74
|
+
`editing.mode: "draft"`. Draft _without_ `onSaveDrafts` is fine: `saveDrafts`
|
|
74
75
|
falls back to the per-row `editing.onCommit` loop.
|
|
75
76
|
|
|
76
77
|
## The four modes
|
|
@@ -83,7 +84,7 @@ as a commit, and which controls trigger it.
|
|
|
83
84
|
| `"cell"` | Enter, Tab, blur | Escape | none |
|
|
84
85
|
| `"cellConfirm"` | ✓ or Enter; blur keeps the draft | ✕ or Escape | ✓ / ✕ beside the input |
|
|
85
86
|
| `"row"` | Save in the edit lane, or Ctrl+Enter | Cancel, or Escape | generated edit lane |
|
|
86
|
-
| `"draft"` |
|
|
87
|
+
| `"draft"` | Enter or the lane's ✓, into the draft store | `edit.cancelAll()`, or per row in the lane | `TMDataGrid.EditActions` + the edit lane |
|
|
87
88
|
|
|
88
89
|
Which to pick: `"cell"` for saved-as-you-go spreadsheet feel; `"cellConfirm"`
|
|
89
90
|
when a stray click must not fire a request; `"row"` when the row is the unit of
|
|
@@ -104,7 +105,8 @@ the cell clicked, opens every editable cell of the row, and ✓ saves them as on
|
|
|
104
105
|
commit. Rows accumulate: opening a second row leaves the first open, and each
|
|
105
106
|
row's ✓ and ✕ act on that row alone.
|
|
106
107
|
|
|
107
|
-
Under `"draft"` nothing reaches a callback until `
|
|
108
|
+
Under `"draft"` nothing reaches a callback until `saveDrafts`. Enter commits the
|
|
109
|
+
row into the draft store; Tab holds
|
|
108
110
|
the draft, Tab moving on to the next editable cell, Escape drops that one draft,
|
|
109
111
|
and drafts accumulate across rows, surviving filters, sorts and scrolling.
|
|
110
112
|
`edit.commit(rowId)` validates and holds the draft too, so there is no per-row
|
|
@@ -119,11 +121,23 @@ Restore. A row holding a dirty draft hides the trash - revert first, then
|
|
|
119
121
|
delete. A row blocked by validation turns its icon red with the message in the
|
|
120
122
|
tooltip.
|
|
121
123
|
|
|
122
|
-
`
|
|
124
|
+
`saveDrafts` then sends the draft store: through the per-row
|
|
123
125
|
`editing.onCommit` / `editing.onRowAdd` / `editing.onRowDelete` loop by default,
|
|
124
|
-
or through one `editing.
|
|
125
|
-
is set.
|
|
126
|
-
|
|
126
|
+
or through one `editing.onSaveDrafts({ updated, created, deleted })` call when
|
|
127
|
+
that is set. `updated` entries carry a `rowId`, `created` entries a `tempId`, `deleted` is
|
|
128
|
+
a list of row ids. Rows failing validation stay open either way.
|
|
129
|
+
|
|
130
|
+
`onSaveDrafts` decides how much of the store is cleared: returning nothing
|
|
131
|
+
saves everything, throwing saves nothing, and returning
|
|
132
|
+
`{ updated, created, deleted }` saves everything except the ids reported
|
|
133
|
+
`false`. Each key takes `false` for the whole bucket or a map of id to result;
|
|
134
|
+
an unnamed id saved. A kept row stays committed, so the next `saveDrafts()`
|
|
135
|
+
retries it, and `saveDrafts()` resolves `false` when anything was kept.
|
|
136
|
+
|
|
137
|
+
Rows carry `data-dirty` (values typed in), `data-draft` (committed, waiting for
|
|
138
|
+
Save), `data-deleted` and, on entry rows, `data-new`. The grid paints none of
|
|
139
|
+
them; use `rowStyle` / `rowClassName` or the attributes to highlight what is
|
|
140
|
+
pending.
|
|
127
141
|
|
|
128
142
|
## What a commit receives
|
|
129
143
|
|
|
@@ -210,18 +224,21 @@ Detail for all three: [references/editors-and-validation.md](references/editors-
|
|
|
210
224
|
## Adding and deleting rows
|
|
211
225
|
|
|
212
226
|
`edit.addRow()` opens an entry row in a sticky block under the header, seeded
|
|
213
|
-
from `editing.newRowDefaults`.
|
|
214
|
-
`
|
|
215
|
-
|
|
216
|
-
|
|
227
|
+
from `editing.newRowDefaults`. `edit.addRow(values)` overrides that seed key by
|
|
228
|
+
key, so `addRow()` opens the `newRowDefaults` row and `addRow(values)` opens it
|
|
229
|
+
with those fields filled in - pass a whole row to duplicate it. Enter, or the
|
|
230
|
+
lane's ✓, commits the add through `editing.onRowAdd` under the immediate modes;
|
|
231
|
+
under draft mode it puts the row in the draft store, validated, and
|
|
232
|
+
`saveDrafts` reports it in `added`. Escape, or ✕, discards the entry. An entry
|
|
233
|
+
row never OK'd is not part of a save - it stays open.
|
|
217
234
|
|
|
218
235
|
Under `"draft"` an entered row renders as a value row with no inputs, marked
|
|
219
|
-
`data-new` and `data-
|
|
236
|
+
`data-new` and `data-committed` and tinted with `--dg-row-new-bg`. By default it
|
|
220
237
|
joins the scrolling flow above the body rows; `editing.newRowsSticky: true`
|
|
221
|
-
keeps
|
|
238
|
+
keeps committed rows pinned in the entry block until the save. Double-click, or
|
|
222
239
|
the lane's pencil, reopens it; ✕ removes it. To limit how many entry rows are
|
|
223
240
|
open at once, gate the Add button on
|
|
224
|
-
`useSelector(grid.edit.store, (s) => s.newRows.some((n) => !n.
|
|
241
|
+
`useSelector(grid.edit.store, (s) => s.newRows.some((n) => !n.committed))`.
|
|
225
242
|
|
|
226
243
|
```tsx
|
|
227
244
|
const grid = useTMDataGrid({
|
|
@@ -231,23 +248,39 @@ const grid = useTMDataGrid({
|
|
|
231
248
|
editing: {
|
|
232
249
|
mode: "draft",
|
|
233
250
|
newRowDefaults: () => ({ id: 0, firstName: "", salary: 30_000 }),
|
|
234
|
-
|
|
235
|
-
await api.saveBatch({
|
|
251
|
+
onSaveDrafts: async ({ updated, created, deleted }) => {
|
|
252
|
+
await api.saveBatch({ updated, created, deleted });
|
|
236
253
|
},
|
|
237
254
|
},
|
|
238
255
|
});
|
|
239
256
|
|
|
240
257
|
<TMDataGrid.Toolbar>
|
|
241
258
|
<Button onClick={() => grid.edit.addRow()}>Add row</Button>
|
|
259
|
+
<Button onClick={() => grid.edit.addRow({ salary: 50_000 })}>
|
|
260
|
+
Add senior
|
|
261
|
+
</Button>
|
|
242
262
|
<TMDataGrid.Spacer />
|
|
243
263
|
<TMDataGrid.EditActions />
|
|
244
264
|
</TMDataGrid.Toolbar>;
|
|
245
265
|
```
|
|
246
266
|
|
|
267
|
+
`edit.addRows(rows, options?)` opens a batch in one write. `{ commit: true }`
|
|
268
|
+
submits each row as it lands - the import case: valid rows are committed,
|
|
269
|
+
invalid ones stay open in the entry block with their errors, and the result
|
|
270
|
+
(`{ committed, open }`) says which went which way. Column rules are enforced
|
|
271
|
+
even though the rows never had an editor on screen, because the engine runs
|
|
272
|
+
`meta.edit.validate` itself at commit.
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
const { committed, open } = await grid.edit.addRows(parsed, { commit: true });
|
|
276
|
+
if (open.length > 0) notify(`${open.length} rows need attention`);
|
|
277
|
+
await grid.edit.saveDrafts();
|
|
278
|
+
```
|
|
279
|
+
|
|
247
280
|
`edit.deleteRow(rowId)` calls `editing.onRowDelete({ rowId, row })` immediately
|
|
248
281
|
under the immediate modes, so put any confirmation inside that callback. Under
|
|
249
282
|
draft mode it toggles a mark instead: the row renders struck through and inert
|
|
250
|
-
(`data-deleted`), the lane shows Restore, and `
|
|
283
|
+
(`data-deleted`), the lane shows Restore, and `saveDrafts` reports the ids in
|
|
251
284
|
`deleted`. You apply adds and deletes, the same as edits. The engine's `tempId`
|
|
252
285
|
(`__new__1`, …) does not need to become a real id.
|
|
253
286
|
|
|
@@ -283,7 +316,8 @@ while editing is off, and works under any mode, not only draft.
|
|
|
283
316
|
## The engine: `edit`
|
|
284
317
|
|
|
285
318
|
`grid.edit` is public, and everything the built-in controls do goes through it:
|
|
286
|
-
`begin` and `commit`, `cancel` / `cancelAll`, `
|
|
319
|
+
`begin` and `commit`, `cancel` / `cancelAll`, `commitAll` / `saveDrafts`,
|
|
320
|
+
`addRow` / `addRows` /
|
|
287
321
|
`deleteRow`, `getForm`, and `store` for `useSelector` (an example is under
|
|
288
322
|
[Submitting an outer form](#high-submitting-an-outer-form-while-the-grid-holds-a-draft)).
|
|
289
323
|
Every member with its signature, the gates, `clearCell`, `deactivate`, and the
|
|
@@ -324,7 +358,7 @@ are in [references/common-mistakes.md](references/common-mistakes.md).
|
|
|
324
358
|
| HIGH | Swallowing the error in `editing.onCommit` - a resolved catch drops the draft |
|
|
325
359
|
| HIGH | Submitting an outer form while the grid holds a draft - it saves stale rows |
|
|
326
360
|
| MEDIUM | Reading a commit's result as the saved value - it is a `boolean` about the form |
|
|
327
|
-
| MEDIUM | Expecting `editing.onRowDelete` to fire under draft - the mark waits for `
|
|
361
|
+
| MEDIUM | Expecting `editing.onRowDelete` to fire under draft - the mark waits for `saveDrafts` |
|
|
328
362
|
|
|
329
363
|
## References
|
|
330
364
|
|
|
@@ -137,7 +137,7 @@ Source: `src/tmdatagrid/useTMDataGrid.tsx` (`TMDataGridEditingCallbacks`).
|
|
|
137
137
|
## HIGH Submitting an outer form while the grid holds a draft
|
|
138
138
|
|
|
139
139
|
The outer form's array contains only committed rows. Under any mode a mid-edit
|
|
140
|
-
row is invisible to it, and under `"draft"` every edit is until `
|
|
140
|
+
row is invisible to it, and under `"draft"` every edit is until `saveDrafts()`,
|
|
141
141
|
so a form submit saves stale rows and collection rules skip pending values.
|
|
142
142
|
|
|
143
143
|
Correct:
|
|
@@ -146,8 +146,9 @@ Correct:
|
|
|
146
146
|
const hasOpenDraft = useSelector(grid.edit.store, (s) => s.openRowIds.length > 0);
|
|
147
147
|
|
|
148
148
|
<Button type="submit" disabled={!canSubmit || hasOpenDraft}>Save</Button>
|
|
149
|
-
// or flush instead of blocking:
|
|
150
|
-
|
|
149
|
+
// or commit and flush instead of blocking:
|
|
150
|
+
await grid.edit.commitAll();
|
|
151
|
+
const flushed = await grid.edit.saveDrafts();
|
|
151
152
|
if (flushed) await form.handleSubmit();
|
|
152
153
|
```
|
|
153
154
|
|
|
@@ -155,12 +156,13 @@ Source: `src/docs/query-builder.md` (Which mode, Submitting).
|
|
|
155
156
|
|
|
156
157
|
## MEDIUM Reading a commit's result as the saved value
|
|
157
158
|
|
|
158
|
-
`edit.commit(rowId)` and `edit.
|
|
159
|
-
whether
|
|
160
|
-
kept
|
|
159
|
+
`edit.commit(rowId)`, `edit.commitAll()` and `edit.saveDrafts()` resolve to a
|
|
160
|
+
`boolean` saying whether everything landed, and resolve `false` when validation
|
|
161
|
+
or a rejected save kept a row open. Ignoring the result reports a save that did
|
|
162
|
+
not happen.
|
|
161
163
|
|
|
162
164
|
```tsx
|
|
163
|
-
const saved = await grid.edit.
|
|
165
|
+
const saved = await grid.edit.saveDrafts();
|
|
164
166
|
notifications.show({ message: saved ? "Saved" : "Some rows need attention" });
|
|
165
167
|
```
|
|
166
168
|
|
|
@@ -170,7 +172,7 @@ Source: `src/tmdatagrid/core/editEngine.ts` (`TMDataGridEditApi`).
|
|
|
170
172
|
|
|
171
173
|
Under the immediate modes `edit.deleteRow` calls `editing.onRowDelete` at once.
|
|
172
174
|
Under `"draft"` it only toggles a deletion mark, so nothing is removed until
|
|
173
|
-
`
|
|
175
|
+
`saveDrafts`: the ids arrive as `deleted` in `editing.onSaveDrafts`, or, with
|
|
174
176
|
no such callback, in the per-row `editing.onRowDelete` loop. A confirmation
|
|
175
177
|
placed inside `editing.onRowDelete` therefore guards the save, not the trash.
|
|
176
178
|
|
|
@@ -17,7 +17,7 @@ kind.
|
|
|
17
17
|
| `cellSelection` | `"none" \| "single" \| "range"` | `"single"` while `editing` is set | Editing turns the cell cursor on; set it explicitly to override. |
|
|
18
18
|
|
|
19
19
|
Passing any other member of `editing` without `mode` is a compile error, and
|
|
20
|
-
`
|
|
20
|
+
`onSaveDrafts` and `newRowsSticky` exist only in the `"draft"` branch of the
|
|
21
21
|
type.
|
|
22
22
|
|
|
23
23
|
## Callbacks
|
|
@@ -25,7 +25,8 @@ type.
|
|
|
25
25
|
| Name | Argument | What it does |
|
|
26
26
|
| --- | --- | --- |
|
|
27
27
|
| `editing.onCommit` | `{ rowId, value, original, changes, source }` | Applies one row's change. Reject to keep the draft and show the error. |
|
|
28
|
-
| `editing.
|
|
28
|
+
| `editing.onSaveDrafts` | `{ rows, added, deleted }` | Draft mode only. One call for the whole draft store. Without it, `saveDrafts` loops `editing.onCommit`, `editing.onRowAdd` and `editing.onRowDelete`. |
|
|
29
|
+
| `editing.onCommitDrafts` | `{ rows, added, deleted }` | **Deprecated** - renamed to `onSaveDrafts`. Still honoured; the new name wins if both are set. |
|
|
29
30
|
| `editing.onRowAdd` | `{ tempId, value }` | Commits an entry row. Mint the real id here. |
|
|
30
31
|
| `editing.onRowDelete` | `{ rowId, row }` | Deletes a row under the immediate modes, and puts the trash can in the edit lane. |
|
|
31
32
|
|
|
@@ -49,14 +50,17 @@ path, which may be dotted.
|
|
|
49
50
|
|
|
50
51
|
| Member | Signature | Notes |
|
|
51
52
|
| --- | --- | --- |
|
|
52
|
-
| `begin` | `({ rowId, columnId }) => void` | Row mode opens the entire row either way. `columnId` selects which cell takes the caret; `null` (the pencil) uses its first editable one. On
|
|
53
|
-
| `commit` | `(rowId) => Promise<boolean>` | `false` keeps
|
|
53
|
+
| `begin` | `({ rowId, columnId }) => void` | Row mode opens the entire row either way. `columnId` selects which cell takes the caret; `null` (the pencil) uses its first editable one. On a committed row it reopens it, taking it back out of the draft store. |
|
|
54
|
+
| `commit` | `(rowId) => Promise<boolean>` | The OK gesture: submits the row's form. `false` keeps it open with its errors. Under `"draft"` a pass puts the row in the draft store - no consumer callback runs until `saveDrafts`. Column rules run whether or not an editor is mounted. |
|
|
55
|
+
| `commitAll` | `() => Promise<boolean>` | Submits every open row. Rows that fail stay open. `false` when one did. |
|
|
56
|
+
| `saveDrafts` | `() => Promise<boolean>` | Sends the draft store. Open rows are left alone and stay open. |
|
|
54
57
|
| `cancel` | `(rowId) => void` | Drops one draft. |
|
|
55
58
|
| `cancelAll` | `() => void` | Drops every draft. |
|
|
56
59
|
| `deactivate` | `() => void` | Closes the editor without touching the draft, as blur does under `"cellConfirm"`. |
|
|
57
|
-
| `submitAll` | `() => Promise<boolean>` |
|
|
60
|
+
| `submitAll` | `() => Promise<boolean>` | **Deprecated** - `commitAll()` then `saveDrafts()`. |
|
|
58
61
|
| `clearCell` | `(rowId, columnId) => Promise<boolean>` | What Delete does: writes the type's empty value and commits. |
|
|
59
|
-
| `addRow` | `() => string` | Opens an entry row, returns its `tempId`. |
|
|
62
|
+
| `addRow` | `(values?) => string` | Opens an entry row, returns its `tempId`. `values` overrides `editing.newRowDefaults` key by key for that row; with no argument the row is `newRowDefaults` alone. |
|
|
63
|
+
| `addRows` | `(rows, options?) => Promise<{ committed, open }>` | Opens a batch in one write, each row seeded as `addRow` seeds. `{ commit: true }` submits each as it lands - valid rows commit, invalid ones stay open with their errors. |
|
|
60
64
|
| `deleteRow` | `(rowId) => void` | `editing.onRowDelete` under the immediate modes, a deletion mark under draft mode. Toggles: a second call restores the row. |
|
|
61
65
|
| `canEditCell` | `(row, column) => boolean` | The check the built-in controls use. |
|
|
62
66
|
| `canEditRow` | `(row) => boolean` | The pencil's gate. |
|
|
@@ -71,8 +75,8 @@ path, which may be dotted.
|
|
|
71
75
|
type TMDataGridEditState = {
|
|
72
76
|
// The cell the last open gesture named - where the caret goes.
|
|
73
77
|
active: { rowId: string; columnId: string | null } | null;
|
|
74
|
-
// Rows with a live form.
|
|
75
|
-
//
|
|
78
|
+
// Rows with a live form, committed or not. A row is *open* when it is in
|
|
79
|
+
// here and not in `committedRowIds`.
|
|
76
80
|
openRowIds: ReadonlyArray<string>;
|
|
77
81
|
// One `TMDataGridEditRowProjection` per open row.
|
|
78
82
|
rows: Record<
|
|
@@ -86,9 +90,12 @@ type TMDataGridEditState = {
|
|
|
86
90
|
values: TMDataGridRowData;
|
|
87
91
|
}
|
|
88
92
|
>;
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
|
|
93
|
+
// The draft store's edit slice: existing rows whose form passed its submit,
|
|
94
|
+
// parked for `saveDrafts`. Empty outside `"draft"`.
|
|
95
|
+
committedRowIds: ReadonlyArray<string>;
|
|
96
|
+
// `committed` is draft mode's "in the store, awaiting the save". Under the
|
|
97
|
+
// immediate modes a commit adds through `onRowAdd`, so it stays `false`.
|
|
98
|
+
newRows: ReadonlyArray<{ tempId: string; committed: boolean }>;
|
|
92
99
|
deletedRowIds: ReadonlyArray<string>;
|
|
93
100
|
};
|
|
94
101
|
```
|
|
@@ -119,7 +126,7 @@ holds:
|
|
|
119
126
|
|
|
120
127
|
- `editing.mode: "row"` - the lane is Save and Cancel's home
|
|
121
128
|
- `editing.mode: "draft"` - the lane is the change indicator and the per-row
|
|
122
|
-
revert, and `editing.
|
|
129
|
+
revert, and `editing.onSaveDrafts` is not required for it
|
|
123
130
|
- `editing.onRowDelete` is set - the trash can has somewhere to report to
|
|
124
131
|
|
|
125
132
|
`"cell"` and `"cellConfirm"` have no lane unless `editing.onRowDelete` asks for
|
|
@@ -142,7 +149,7 @@ control carries a tooltip from the labels, `revertRow`, `rowStateNew`,
|
|
|
142
149
|
| `--dg-row-new-bg` | CSS variable | Background of an entered new row. A green tint. |
|
|
143
150
|
| `data-deleted` | Row attribute | On a row marked for deletion under draft mode. |
|
|
144
151
|
| `data-dirty` | Row attribute | On a body row holding a dirty draft. Also on the cell whose field is dirty. |
|
|
145
|
-
| `data-new` / `data-
|
|
152
|
+
| `data-new` / `data-committed` | Entry row attributes | On an entry row; `data-committed` once it is committed, awaiting the save. |
|
|
146
153
|
| `data-dg-entry-flow-block` | Attribute | The in-flow block above the body rows holding entered new rows, unless `editing.newRowsSticky` keeps them in the sticky entry block. |
|
|
147
154
|
| `data-dg-part="editor-input"` | Part | The control inside an editing cell. |
|
|
148
155
|
| `data-dg-part="save-row"` / `"cancel-row"` | Parts | The edit lane's buttons on an open row, with `data-row-id`. Row mode only. |
|
package/skills/grouping/SKILL.md
CHANGED
package/skills/options/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ description: >
|
|
|
14
14
|
metadata:
|
|
15
15
|
type: core
|
|
16
16
|
library: '@jielga/tmdatagrid'
|
|
17
|
-
library_version: '2.0.0-beta.
|
|
17
|
+
library_version: '2.0.0-beta.4'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/TMDataGrid:src/docs/use-tm-data-grid.md'
|
|
20
20
|
- 'Jielga/TMDataGrid:src/tmdatagrid/useTMDataGrid.tsx'
|
|
@@ -62,10 +62,11 @@ rather than forwarded to TanStack.
|
|
|
62
62
|
| `onFocusedCellChange` | `(cell \| null) => void` | – | Fires whenever the focused cell moves. |
|
|
63
63
|
| `overscan` | `number` | `6` | Rows the virtualizer keeps mounted above and below the viewport. Defined by the grid. |
|
|
64
64
|
| `columnResizeMode` | `"onChange" \| "onEnd"` | `"onChange"` | Resize update strategy. |
|
|
65
|
-
| `initialState` | `Partial<TableState>` | See below | Merged over the grid defaults. |
|
|
65
|
+
| `initialState` | `Partial<TableState>` | See below | The state the grid starts from, read once on mount. Merged over the grid defaults. |
|
|
66
|
+
| `state` | `Partial<TableState>` | – | Controlled state. Each slice requires its `onXChange` - see below. |
|
|
66
67
|
| `meta` | `TMDataGridTableMeta` | `{}` | Grid configuration, see below. |
|
|
67
68
|
| `persist` | `TMDataGridPersistence` | – | State persistence, see below. |
|
|
68
|
-
| `editing` | `TMDataGridEditingOptions` | off | Turns editing on. `mode` (`"cell" \| "cellConfirm" \| "row" \| "draft"`) picks the commit policy; the object also holds `onCommit`, `
|
|
69
|
+
| `editing` | `TMDataGridEditingOptions` | off | Turns editing on. `mode` (`"cell" \| "cellConfirm" \| "row" \| "draft"`) picks the commit policy; the object also holds `onCommit`, `onSaveDrafts`, `rowValidators`, `isRowEditable`, `newRowDefaults`, `newRowsSticky`, `onRowAdd` and `onRowDelete` - see the `editing` skill. |
|
|
69
70
|
| `labels` | `TMDataGridLabelsOverride` | English | Overrides for the grid's strings and `aria-label`s. |
|
|
70
71
|
|
|
71
72
|
### Default initial state
|
|
@@ -76,6 +77,35 @@ rather than forwarded to TanStack.
|
|
|
76
77
|
| `columnPinning.left` | The checkbox column, followed by any columns you provide |
|
|
77
78
|
| `globalFilterFn` | `"includesString"` |
|
|
78
79
|
|
|
80
|
+
### Controlled state
|
|
81
|
+
|
|
82
|
+
`state` makes a slice controlled: the parent owns the value, the grid reads it
|
|
83
|
+
every render, and all writes go through the matching `onXChange`. Without the
|
|
84
|
+
callback the slice cannot change; the grid logs a console warning in
|
|
85
|
+
development. For a starting value only, use `initialState`.
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const [columnVisibility, setColumnVisibility] = useState({ play: false });
|
|
89
|
+
|
|
90
|
+
const grid = useTMDataGrid({
|
|
91
|
+
data,
|
|
92
|
+
columns,
|
|
93
|
+
state: { columnVisibility },
|
|
94
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- A key set to `undefined` is ignored; the slice is uncontrolled.
|
|
99
|
+
- Slices compare structurally between renders, so the `state` object can be
|
|
100
|
+
built inline. `Date`s compare by time; `Map`s and class instances compare by
|
|
101
|
+
identity and belong in `useState` or `useMemo`.
|
|
102
|
+
- `atoms` also controls a slice, with no callback. Takes precedence over
|
|
103
|
+
`state` for the same slice.
|
|
104
|
+
- `columnVisibility` toggles user-defined columns only. Entries for the
|
|
105
|
+
generated columns are ignored; enable or disable those through their feature
|
|
106
|
+
options. The tree column's entry follows `grouping`.
|
|
107
|
+
- `persist` cannot restore a controlled slice; it still writes it to storage.
|
|
108
|
+
|
|
79
109
|
## meta
|
|
80
110
|
|
|
81
111
|
| Field | Type | Default | Description |
|
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.0.0-beta.
|
|
20
|
+
library_version: '2.0.0-beta.4'
|
|
21
21
|
sources:
|
|
22
22
|
- 'Jielga/TMDataGrid:src/docs/row-selection.md'
|
|
23
23
|
- 'Jielga/TMDataGrid:src/docs/row-interaction.md'
|
|
@@ -10,7 +10,7 @@ description: >
|
|
|
10
10
|
metadata:
|
|
11
11
|
type: core
|
|
12
12
|
library: '@jielga/tmdatagrid'
|
|
13
|
-
library_version: '2.0.0-beta.
|
|
13
|
+
library_version: '2.0.0-beta.4'
|
|
14
14
|
sources:
|
|
15
15
|
- 'Jielga/TMDataGrid:src/docs/server-side.md'
|
|
16
16
|
- 'Jielga/TMDataGrid:src/tmdatagrid/useTMDataGrid.tsx'
|
package/skills/testing/SKILL.md
CHANGED
|
@@ -11,7 +11,7 @@ description: >
|
|
|
11
11
|
metadata:
|
|
12
12
|
type: core
|
|
13
13
|
library: '@jielga/tmdatagrid'
|
|
14
|
-
library_version: '2.0.0-beta.
|
|
14
|
+
library_version: '2.0.0-beta.4'
|
|
15
15
|
sources:
|
|
16
16
|
- 'Jielga/TMDataGrid:src/docs/testing.md'
|
|
17
17
|
- 'Jielga/TMDataGrid:src/tmdatagrid/components/TMDataGrid.tsx'
|
|
@@ -172,7 +172,11 @@ export function TMDataGridCellEditor({
|
|
|
172
172
|
onClose({ committed: false, via: "escape" });
|
|
173
173
|
};
|
|
174
174
|
|
|
175
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* Draft: the key closes the editor and leaves the row open - undecided
|
|
177
|
+
* form state, which `saveDrafts` does not send. Tab moving along the row
|
|
178
|
+
* is not a decision about it; Enter is, and commits instead.
|
|
179
|
+
*/
|
|
176
180
|
const deferAndClose = (via: "defer" | "defer-tab" | "defer-shift-tab") => {
|
|
177
181
|
if (closingRef.current) return;
|
|
178
182
|
closingRef.current = true;
|
|
@@ -185,12 +189,11 @@ export function TMDataGridCellEditor({
|
|
|
185
189
|
if (event.key === "Enter") {
|
|
186
190
|
event.preventDefault();
|
|
187
191
|
event.stopPropagation();
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
else void commitAndClose("enter");
|
|
192
|
+
// Enter is OK, in every mode: the row's form submits and has to pass
|
|
193
|
+
// validation. What a commit *does* is the mode's business - the
|
|
194
|
+
// immediate modes call the consumer, draft mode parks the row in the
|
|
195
|
+
// draft store for `saveDrafts` - so this key does not branch.
|
|
196
|
+
void commitAndClose("enter");
|
|
194
197
|
} else if (event.key === "Escape") {
|
|
195
198
|
event.preventDefault();
|
|
196
199
|
event.stopPropagation();
|