@jielga/tmdatagrid 2.0.0-beta.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -212
- package/dist/index.d.ts +1323 -796
- package/dist/index.js +4719 -3193
- 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 +268 -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 +69 -78
- package/skills/columns/SKILL.md +90 -34
- package/skills/data/SKILL.md +86 -16
- package/skills/editing/SKILL.md +83 -50
- package/skills/editing/references/common-mistakes.md +77 -69
- package/skills/editing/references/editing-api.md +31 -23
- package/skills/editing/references/editors-and-validation.md +24 -17
- package/skills/filtering/SKILL.md +148 -40
- package/skills/getting-started/SKILL.md +17 -15
- package/skills/grouping/SKILL.md +31 -16
- package/skills/options/SKILL.md +8 -8
- package/skills/rows/SKILL.md +22 -18
- 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/TMDataGridContext.ts → TMDataGridContext.ts} +7 -19
- package/src/{tmdatagrid/components → components}/TMDataGrid.module.css +7 -1
- package/src/{tmdatagrid/components → components}/TMDataGrid.tsx +38 -21
- package/src/{tmdatagrid/components → components}/TMDataGridCellEditor.tsx +73 -7
- 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 +9 -55
- package/src/{tmdatagrid/components → components}/TMDataGridDraftActions.tsx +41 -24
- package/src/{tmdatagrid/components → components}/TMDataGridEditColumn.tsx +23 -63
- package/src/components/TMDataGridEntryRows.tsx +354 -0
- 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 +9 -72
- 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 +15 -53
- package/src/{tmdatagrid/components → components}/TMDataGridTable.module.css +88 -65
- package/src/{tmdatagrid/components → components}/TMDataGridTable.tsx +579 -165
- 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}/capabilities.ts +5 -5
- 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 +1172 -388
- package/src/{tmdatagrid/core → core}/editorFocus.ts +8 -4
- 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} +70 -36
- package/src/{tmdatagrid/useTMDataGrid.tsx → useTMDataGrid.tsx} +534 -123
- package/src/useTMDataGridExport.ts +78 -0
- package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +0 -298
- 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/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}/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}/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
package/skills/data/SKILL.md
CHANGED
|
@@ -10,17 +10,23 @@ description: >
|
|
|
10
10
|
onReachEnd is better for loading more, the header and pinned-lane depth
|
|
11
11
|
shadows, and the four empty states in precedence order with meta.loading,
|
|
12
12
|
renderEmptyState, hasActiveFilters, TMDataGrid.LoadingIndicator and
|
|
13
|
-
TMDataGrid.SummaryCount
|
|
14
|
-
|
|
13
|
+
TMDataGrid.SummaryCount, and export: TMDataGrid.Menu.Export and
|
|
14
|
+
Menu.ExportSelected, useTMDataGridExport, exportGrid, exportOptions, the
|
|
15
|
+
csvExcel / csv / tsv / json formats, meta.exportValue and meta.enableExport.
|
|
16
|
+
Load when adding a pager, tuning scrolling, scrolling to a row, deciding what
|
|
17
|
+
an empty grid should say, or exporting rows to Excel or CSV.
|
|
15
18
|
metadata:
|
|
16
19
|
type: core
|
|
17
20
|
library: '@jielga/tmdatagrid'
|
|
18
|
-
library_version: '2.0.0
|
|
21
|
+
library_version: '2.0.0'
|
|
19
22
|
sources:
|
|
20
|
-
- 'Jielga/TMDataGrid:
|
|
21
|
-
- 'Jielga/TMDataGrid:
|
|
22
|
-
- 'Jielga/TMDataGrid:
|
|
23
|
-
- 'Jielga/TMDataGrid:
|
|
23
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/pagination.md'
|
|
24
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/scrolling.md'
|
|
25
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/loading-and-empty.md'
|
|
26
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/export.md'
|
|
27
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/components/TMDataGridFooter.tsx'
|
|
28
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/pagination.ts'
|
|
29
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/export.ts'
|
|
24
30
|
---
|
|
25
31
|
|
|
26
32
|
# TMDataGrid - Pagination, scrolling and empty states
|
|
@@ -77,7 +83,10 @@ pieces, already wired.
|
|
|
77
83
|
`Controls.PageSize`, `Controls.Range` and `Controls.Pager` are what the default
|
|
78
84
|
footer renders, in that order, so a custom layout can keep the parts it wants
|
|
79
85
|
instead of rebuilding them. They behave exactly as before, including greying out
|
|
80
|
-
under a suspended pager.
|
|
86
|
+
under a suspended pager. `Controls.PageNumber` - the "Page 3 of 200" label a
|
|
87
|
+
server-paged grid usually shows in place of a row range - is a fourth control,
|
|
88
|
+
not in the default footer; put it in through the slot rather than writing it by
|
|
89
|
+
hand.
|
|
81
90
|
|
|
82
91
|
`state` carries `pageIndex`, `pageSize`, `pageCount`, `rowCount`,
|
|
83
92
|
`canPreviousPage`, `canNextPage`, `from`, `to` and `isPagingActive`. `actions`
|
|
@@ -178,6 +187,67 @@ server-driven grid refetching with rows still on screen keeps showing them.
|
|
|
178
187
|
total, where the total is `meta.totalRowCount` when provided and the pre-filtered
|
|
179
188
|
count otherwise.
|
|
180
189
|
|
|
190
|
+
## Export
|
|
191
|
+
|
|
192
|
+
Every filtered and sorted row across every page, or the selected rows, as a
|
|
193
|
+
file. The built-in entry points are menu items; a button of your own uses the
|
|
194
|
+
hook.
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
const grid = useTMDataGrid({
|
|
198
|
+
data,
|
|
199
|
+
columns,
|
|
200
|
+
exportOptions: { format: csvFormat(), fileName: "employees" },
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
<TMDataGrid.Menu>
|
|
204
|
+
<TMDataGrid.Menu.Export />
|
|
205
|
+
<TMDataGrid.Menu.ExportSelected />
|
|
206
|
+
</TMDataGrid.Menu>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
function ExportButton() {
|
|
211
|
+
const { exportAll, exportSelected, selectedCount, canExportSelected } =
|
|
212
|
+
useTMDataGridExport();
|
|
213
|
+
return <Button onClick={() => void exportAll()}>Export</Button>;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
What is written: the data columns in render order (never the generated lanes,
|
|
218
|
+
never a column with `meta.enableExport: false`), every row after filtering and
|
|
219
|
+
sorting (a grouped grid writes the records under every group, never the group
|
|
220
|
+
rows), and each cell's **value** rather than what it renders -
|
|
221
|
+
`meta.exportValue: ({ value, row, column }) => unknown` substitutes one.
|
|
222
|
+
`columns` on `exportOptions`, the items and the functions is `"visible"` (the
|
|
223
|
+
default), `"all"` (hidden columns too) or a list of ids; `columns="custom"` on
|
|
224
|
+
a menu item opens a picker instead - every exportable column, the visible ones
|
|
225
|
+
ticked, Export and Cancel - driven by `ui.state.exportPicker` and
|
|
226
|
+
`ui.actions.openExportPicker`. `TMDataGrid.Menu.ExportSelected` counts and
|
|
227
|
+
writes the ticked rows of the current view, in grid order; it renders nothing
|
|
228
|
+
when row selection is off.
|
|
229
|
+
|
|
230
|
+
Formats, each a `TMDataGridExportFormat` from a factory:
|
|
231
|
+
|
|
232
|
+
| Factory | Writes |
|
|
233
|
+
| --- | --- |
|
|
234
|
+
| `csvExcelFormat()` (default) | BOM, `sep=;` line, CRLF, `;` fields, `,` decimal - opens straight into columns in Excel. `separator`, `decimalComma` for another locale. |
|
|
235
|
+
| `csvFormat()` | RFC 4180: `,` fields, `.` decimal, BOM, no `sep=` line - for Google Sheets, Numbers and tooling. |
|
|
236
|
+
| `tsvFormat()` | Tab-separated, the clipboard shape as a file. |
|
|
237
|
+
| `jsonFormat()` | One object per row keyed by column label, numbers as numbers, dates as ISO strings. |
|
|
238
|
+
| `xlsxFormat()` | Excel workbook, from the separate `@jielga/tmdatagrid-xlsx` package. |
|
|
239
|
+
|
|
240
|
+
The text formats guard against formula injection by default: a value starting
|
|
241
|
+
with `=`, `+`, `-` or `@` that is not a number is prefixed with `'`.
|
|
242
|
+
`escapeFormulas: false` on the format turns that off.
|
|
243
|
+
|
|
244
|
+
`exportGrid({ table, rows: "all" | "selected" | rows, options })` is the same
|
|
245
|
+
export for code outside a component; `buildExportData` is the step before the
|
|
246
|
+
file. A format of your own is `{ id, extension, mimeType, write(data, { includeHeaders }) }`
|
|
247
|
+
returning a string, a `Blob`, or a promise of either.
|
|
248
|
+
|
|
249
|
+
Source: `packages/tmdatagrid/docs/export.md`.
|
|
250
|
+
|
|
181
251
|
## Common mistakes
|
|
182
252
|
|
|
183
253
|
### CRITICAL Turning pagination on to make a large grid fast
|
|
@@ -186,7 +256,7 @@ Virtualization is already unconditional, so paging a 200 000-row grid changes
|
|
|
186
256
|
nothing about rendering cost. It only changes how users navigate. Enable it when
|
|
187
257
|
they should move page by page, not for performance.
|
|
188
258
|
|
|
189
|
-
Source: `
|
|
259
|
+
Source: `packages/tmdatagrid/docs/pagination.md`, `packages/tmdatagrid/docs/scrolling.md`.
|
|
190
260
|
|
|
191
261
|
### CRITICAL A variable row height
|
|
192
262
|
|
|
@@ -207,7 +277,7 @@ Correct:
|
|
|
207
277
|
useTMDataGrid({ data, columns, meta: { rowHeight: 64 } });
|
|
208
278
|
```
|
|
209
279
|
|
|
210
|
-
Source: `
|
|
280
|
+
Source: `packages/tmdatagrid/docs/scrolling.md` (Row height).
|
|
211
281
|
|
|
212
282
|
### HIGH `scrollIntoView` on a row that is not mounted
|
|
213
283
|
|
|
@@ -223,7 +293,7 @@ grid.scrollToRow({ rowId: "4000", align: "center" });
|
|
|
223
293
|
`scrollToRow` returns `false` when the row is not in the current view (filtered
|
|
224
294
|
out, on another page, or an id matching no row) and nothing scrolled.
|
|
225
295
|
|
|
226
|
-
Source: `
|
|
296
|
+
Source: `packages/tmdatagrid/docs/scrolling.md` (Scrolling to a row).
|
|
227
297
|
|
|
228
298
|
### HIGH Loading more rows from `onScrollToBottom`
|
|
229
299
|
|
|
@@ -231,7 +301,7 @@ It fires at the very bottom, so the user waits at the end of the list for the
|
|
|
231
301
|
fetch. `onReachEnd` fires a number of rows earlier and latches per row count, so
|
|
232
302
|
a pending fetch is not requested twice.
|
|
233
303
|
|
|
234
|
-
Source: `
|
|
304
|
+
Source: `packages/tmdatagrid/docs/scrolling.md` (Edge callbacks).
|
|
235
305
|
|
|
236
306
|
### HIGH `SummaryCount` reporting the page under manual pagination
|
|
237
307
|
|
|
@@ -250,7 +320,7 @@ useTMDataGrid({
|
|
|
250
320
|
});
|
|
251
321
|
```
|
|
252
322
|
|
|
253
|
-
Source: `
|
|
323
|
+
Source: `packages/tmdatagrid/docs/loading-and-empty.md` (Counting what is there).
|
|
254
324
|
|
|
255
325
|
### MEDIUM Rendering an empty message while data is loading
|
|
256
326
|
|
|
@@ -264,7 +334,7 @@ Correct:
|
|
|
264
334
|
useTMDataGrid({ data, columns, meta: { loading: isFetching } });
|
|
265
335
|
```
|
|
266
336
|
|
|
267
|
-
Source: `
|
|
337
|
+
Source: `packages/tmdatagrid/docs/loading-and-empty.md` (What wins).
|
|
268
338
|
|
|
269
339
|
### MEDIUM Trusting the pager while grouped
|
|
270
340
|
|
|
@@ -272,7 +342,7 @@ Source: `src/docs/loading-and-empty.md` (What wins).
|
|
|
272
342
|
grid is rendering the whole tree. A custom pager must read
|
|
273
343
|
`isPagingActive(table, features)` rather than the page count.
|
|
274
344
|
|
|
275
|
-
Source: `
|
|
345
|
+
Source: `packages/tmdatagrid/docs/pagination.md` (Grouping suspends it).
|
|
276
346
|
|
|
277
347
|
## Reference
|
|
278
348
|
|
|
@@ -283,7 +353,7 @@ Source: `src/docs/pagination.md` (Grouping suspends it).
|
|
|
283
353
|
| `rowCount` | Table option | `number` | – | The true total, required under `manualPagination`. |
|
|
284
354
|
| `initialState.pagination` | Table option | `{ pageIndex, pageSize }` | `{ 0, 25 }` | Where paging starts. A `data` slice, so it persists. |
|
|
285
355
|
| `onPaginationChange` | Table option | `OnChangeFn` | – | Controls the pagination state. |
|
|
286
|
-
| `TMDataGrid.Footer` | Component | `pageSizeOptions`, `
|
|
356
|
+
| `TMDataGrid.Footer` | Component | `pageSizeOptions`, `renderPagination`, Mantine `BoxProps` | `[10, 25, 50, 100]` | The footer bar. Renders nothing when paging is off. Style props set on the bar. |
|
|
287
357
|
| `Footer` `renderPagination` | Slot | `({ state, actions, Controls }) => ReactNode` | Built-in pager | Replaces the pager, and hands over its pieces. |
|
|
288
358
|
| `getTMDataGridPaginationApi` | Export | `(table) => { state, actions }` | – | The pager API, outside the Footer. |
|
|
289
359
|
| `TMDataGridPaginationState` · `TMDataGridPaginationActions` · `TMDataGridPaginationControls` | Exports | types | – | The three parts of the slot argument. |
|
package/skills/editing/SKILL.md
CHANGED
|
@@ -18,13 +18,15 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.0.0
|
|
21
|
+
library_version: '2.0.0'
|
|
22
22
|
sources:
|
|
23
|
-
- 'Jielga/TMDataGrid:
|
|
24
|
-
- 'Jielga/TMDataGrid:
|
|
25
|
-
- 'Jielga/TMDataGrid:
|
|
26
|
-
- 'Jielga/TMDataGrid:
|
|
27
|
-
- 'Jielga/TMDataGrid:
|
|
23
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/editing.md'
|
|
24
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/draft-store.md'
|
|
25
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/adding-rows.md'
|
|
26
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/query-builder.md'
|
|
27
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/editors.md'
|
|
28
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/core/editEngine.ts'
|
|
29
|
+
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/useTMDataGrid.tsx'
|
|
28
30
|
---
|
|
29
31
|
|
|
30
32
|
# TMDataGrid - Editing
|
|
@@ -34,9 +36,10 @@ happen. Three facts decide every wiring question below:
|
|
|
34
36
|
|
|
35
37
|
- **The grid never mutates `data`.** `editing.onCommit` applies the change
|
|
36
38
|
wherever the data lives, and the updated rows arrive back through `data`.
|
|
37
|
-
- **One row, one form.** Each
|
|
38
|
-
row id and living outside the DOM, so a draft
|
|
39
|
-
filtering.
|
|
39
|
+
- **One row, one form, while it is open.** Each row being edited gets its own
|
|
40
|
+
TanStack Form, keyed by row id and living outside the DOM, so a draft
|
|
41
|
+
survives scrolling, sorting and filtering. A committed row holds values, not
|
|
42
|
+
a form.
|
|
40
43
|
- **`getRowId` is required** once `editing` is set, and it must be the record's
|
|
41
44
|
own identity. Drafts are keyed by it.
|
|
42
45
|
|
|
@@ -82,16 +85,18 @@ They are independent, and every pair is legal.
|
|
|
82
85
|
| Mode | Commits on | Cancels on | Controls |
|
|
83
86
|
| --- | --- | --- | --- |
|
|
84
87
|
| `"cell"` | Enter, Tab, leaving the cell | Escape | none |
|
|
85
|
-
| `"cellConfirm"` | ✓ or Enter; Tab and
|
|
88
|
+
| `"cellConfirm"` | ✓ or Enter; Tab walks input, ✓, ✕ and then leaves, keeping the draft | ✕ or Escape | ✓ / ✕ beside the input |
|
|
86
89
|
| `"row"` | Save in the edit lane, or Enter | Cancel, or Escape | generated edit lane |
|
|
87
90
|
|
|
91
|
+
Leaving a cell commits it only once the value passes: a refused commit keeps the editor open, invalid, with the message in its tooltip, until the value is fixed or Escape drops it.
|
|
92
|
+
|
|
88
93
|
| `editing.draft` | Where a commit goes |
|
|
89
94
|
| --- | --- |
|
|
90
95
|
| `false` (default) | Straight out: `onCommit`, `onRowAdd`, `onRowDelete` |
|
|
91
96
|
| `true` | Into the grid's draft store, until `edit.saveDrafts()` sends the lot |
|
|
92
97
|
|
|
93
98
|
Which to pick: `"cell"` for spreadsheet feel; `"cellConfirm"` when a stray click must not fire a request; `"row"` when the row is the unit of the save or a rule spans two columns.
|
|
94
|
-
Add `draft: true` for many edits sent as one transaction - `{ mode: "row", draft: true }`
|
|
99
|
+
Add `draft: true` for many edits sent as one transaction - `{ mode: "row", draft: true }` commits a whole row from the lane's ✓, `{ mode: "cell", draft: true }` commits a row as the caret leaves it.
|
|
95
100
|
|
|
96
101
|
An editor opens on double-click, or with the cell cursor on the cell: Enter, F2,
|
|
97
102
|
or typing, where the first character replaces the value. Delete or Backspace
|
|
@@ -108,9 +113,12 @@ commit. Rows accumulate: opening a second row leaves the first open, and each
|
|
|
108
113
|
row's ✓ and ✕ act on that row alone.
|
|
109
114
|
|
|
110
115
|
Under `draft: true` nothing reaches a callback until `saveDrafts`.
|
|
111
|
-
The mode's own commit gesture
|
|
112
|
-
`edit.commit(rowId)`
|
|
113
|
-
A
|
|
116
|
+
The mode's own commit gesture puts the row in the draft store instead of sending it, Escape drops that one draft, and committed rows accumulate.
|
|
117
|
+
`edit.commit(rowId)` goes to the draft store too, so there is no per-row escape hatch to the consumer.
|
|
118
|
+
A committed row is displayed: the cell renders the draft value through the column's own `cell` renderer, with the blue corner marking it dirty and `data-dirty` on the row.
|
|
119
|
+
It is a row like any other to the table: sorting, filtering, quick search, grouping, aggregates, export, selection, the row counts, `edit.getRows()` and `editing.tableValidators` all read its draft values, and the row callbacks receive it with the draft as `row.original`.
|
|
120
|
+
A committed row that stops matching a filter leaves the view, and the Save bar still counts it.
|
|
121
|
+
`data` itself is never modified, and only top-level rows are overlaid - `getSubRows` children keep their `data` values.
|
|
114
122
|
An entry row is row-shaped in every mode - every editable cell open at once, the browser's Tab, and the lane's ✓ to enter it.
|
|
115
123
|
|
|
116
124
|
The edit lane is the change indicator and the per-row undo: an edited row shows
|
|
@@ -128,15 +136,27 @@ a list of row ids. Rows failing validation stay open either way.
|
|
|
128
136
|
|
|
129
137
|
`onSaveDrafts` decides how much of the store is cleared: returning nothing
|
|
130
138
|
saves everything, throwing saves nothing, and returning
|
|
131
|
-
`{ updated, created, deleted }`
|
|
132
|
-
`false`. Each key takes `false` for the
|
|
133
|
-
an unnamed id saved. A kept row stays
|
|
134
|
-
|
|
139
|
+
`{ updated, created, deleted }` (a `TMDataGridSaveDraftsResponse`) saves
|
|
140
|
+
everything except the ids reported `false`. Each key takes `false` for the
|
|
141
|
+
whole bucket or a map of id to result; an unnamed id saved. A kept row stays
|
|
142
|
+
committed, so the next `saveDrafts()` retries it.
|
|
143
|
+
|
|
144
|
+
`saveDrafts()` resolves a `TMDataGridSaveDraftsResult`, `{ ok, saved, kept, reopened }`.
|
|
145
|
+
Every id the save took from the draft store is in exactly one list - row ids for edits and deletions, temp ids for new rows, all kinds mixed:
|
|
146
|
+
|
|
147
|
+
- `saved` - left the draft store; the consumer accepted it
|
|
148
|
+
- `kept` - still in the draft store, still committed, retried by the next save: an id `onSaveDrafts` returned as failed, every id it was sent when it threw, or, without `onSaveDrafts`, a deletion whose `onRowDelete` threw
|
|
149
|
+
- `reopened` - open again with an error: a table rule rejected it, or on the per-row path its `onCommit` / `onRowAdd` threw
|
|
150
|
+
- `ok` - `true` when `kept` and `reopened` are both empty
|
|
151
|
+
|
|
152
|
+
On the per-row path a deletion always leaves the store and is reported in `saved`.
|
|
153
|
+
An empty store resolves `{ ok: true, saved: [], kept: [], reopened: [] }`.
|
|
154
|
+
Rows still open are in no list.
|
|
135
155
|
|
|
136
156
|
Rows carry `data-dirty` (values typed in), `data-draft` (committed, waiting for
|
|
137
|
-
Save), `data-deleted` and
|
|
138
|
-
|
|
139
|
-
pending.
|
|
157
|
+
Save), `data-deleted` and `data-new` - a committed new row in the body, or an
|
|
158
|
+
entry row in the block. The grid paints none of them; use `rowStyle` /
|
|
159
|
+
`rowClassName` or the attributes to highlight what is pending.
|
|
140
160
|
|
|
141
161
|
## What a commit receives
|
|
142
162
|
|
|
@@ -213,16 +233,22 @@ rowValidators: {
|
|
|
213
233
|
```
|
|
214
234
|
|
|
215
235
|
Pathed issues land on the matching cells, pathless ones on the row, and cell
|
|
216
|
-
corners mark both: blue for a dirty draft, red for a validation error.
|
|
236
|
+
corners mark both: blue for a dirty draft, red for a validation error. A
|
|
237
|
+
field's message shows in a tooltip on the open editor, which the host renders
|
|
238
|
+
for a custom editor as much as a built-in one; the plain-function form of a
|
|
239
|
+
validator types `value` as `never`, so annotate the parameter -
|
|
240
|
+
`({ value }: { value: unknown })`.
|
|
217
241
|
|
|
218
242
|
`editing.tableValidators` carries the rules that need the other rows - no
|
|
219
243
|
duplicate keys, no overlapping ranges, shares summing to a total. Its
|
|
220
244
|
`onSubmit` / `onSubmitAsync` receive `{ value, rowId, isNew, rows }`, where
|
|
221
245
|
`rows` is the collection as it would stand if the commit landed: every draft
|
|
222
|
-
overlaid,
|
|
246
|
+
overlaid, committed new rows among them, the entry rows the table does not hold
|
|
247
|
+
appended, deletion-marked rows removed. Each row appears once. Same result
|
|
223
248
|
vocabulary as `rowValidators`; errors land on the committing row. The rules
|
|
224
|
-
re-run per
|
|
225
|
-
invalidated
|
|
249
|
+
re-run per committed row during `saveDrafts`, the only validation that runs
|
|
250
|
+
there: a committed row a later edit invalidated is reopened with its errors
|
|
251
|
+
and the save reports it in `reopened`.
|
|
226
252
|
|
|
227
253
|
```tsx
|
|
228
254
|
tableValidators: {
|
|
@@ -251,16 +277,18 @@ from `editing.newRowDefaults`. `edit.addRow(values)` overrides that seed key by
|
|
|
251
277
|
key, so `addRow()` opens the `newRowDefaults` row and `addRow(values)` opens it
|
|
252
278
|
with those fields filled in - pass a whole row to duplicate it. Enter, or the
|
|
253
279
|
lane's ✓, commits the add through `editing.onRowAdd`; under `draft: true` it
|
|
254
|
-
|
|
255
|
-
`saveDrafts` reports it in `
|
|
280
|
+
commits the row into the draft store, validated, and
|
|
281
|
+
`saveDrafts` reports it in `created`. Escape, or ✕, discards the entry. An entry
|
|
256
282
|
row never OK'd is not part of a save - it stays open.
|
|
257
283
|
|
|
258
|
-
Under `draft: true`
|
|
259
|
-
`data-new` and `data-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
the
|
|
263
|
-
|
|
284
|
+
Under `draft: true` a committed entry row leaves the entry block and becomes a
|
|
285
|
+
body row with no inputs, marked `data-new` and `data-draft`, tinted with
|
|
286
|
+
`--dg-row-new-bg`, and sorted, filtered and counted with the rest on the values
|
|
287
|
+
it was entered with. `editing.newRowsSticky: true` keeps committed rows in the
|
|
288
|
+
entry block until the save instead, out of the body's sort and out of the row
|
|
289
|
+
count. Double-click, or the lane's pencil, reopens it back into the entry block;
|
|
290
|
+
✕ removes it. To limit how many entry rows are open at once, gate the Add
|
|
291
|
+
button on
|
|
264
292
|
`useSelector(grid.edit.store, (s) => s.newRows.some((n) => !n.committed))`.
|
|
265
293
|
|
|
266
294
|
```tsx
|
|
@@ -291,13 +319,14 @@ const grid = useTMDataGrid({
|
|
|
291
319
|
`edit.addRows(rows, options?)` opens a batch in one write. `{ commit: true }`
|
|
292
320
|
submits each row as it lands - the import case: valid rows are committed,
|
|
293
321
|
invalid ones stay open in the entry block with their errors, and the result
|
|
294
|
-
(`{ committed, open }`) says which went which way
|
|
295
|
-
even though the rows never had an
|
|
296
|
-
`meta.edit.validate` itself at
|
|
322
|
+
(`{ ok, committed, open }`) says which went which way; `ok` is `true` when
|
|
323
|
+
`open` is empty. Column rules are enforced even though the rows never had an
|
|
324
|
+
editor on screen, because the engine runs `meta.edit.validate` itself at
|
|
325
|
+
commit.
|
|
297
326
|
|
|
298
327
|
```tsx
|
|
299
|
-
const {
|
|
300
|
-
if (
|
|
328
|
+
const { ok, open } = await grid.edit.addRows(parsed, { commit: true });
|
|
329
|
+
if (!ok) notify(`${open.length} rows need attention`);
|
|
301
330
|
await grid.edit.saveDrafts();
|
|
302
331
|
```
|
|
303
332
|
|
|
@@ -312,8 +341,8 @@ it toggles a mark instead: the row renders struck through and inert
|
|
|
312
341
|
|
|
313
342
|
The generated edit lane (`EDIT_COLUMN_ID`, pinned right) appears when `editing.mode` is `"row"`, when `editing.draft` is on, or when `editing.onRowDelete` is set.
|
|
314
343
|
Nothing else adds it.
|
|
315
|
-
It holds one thing per axis: the mode's own controls while a row is open - Save and Cancel under `"row"` - and, once a row is
|
|
316
|
-
A
|
|
344
|
+
It holds one thing per axis: the mode's own controls while a row is open - Save and Cancel under `"row"` - and, once a row is committed, the row-state marker with Revert or Restore.
|
|
345
|
+
A committed row never offers a save.
|
|
317
346
|
The trash shows when the deletion has somewhere to report to: `onRowDelete` is set, or under `draft: true`, `onSaveDrafts` is.
|
|
318
347
|
If validation blocks a row, its marker - or the open row's ✓ - turns red with the message in the tooltip, which is where a pathless `rowValidators` message shows.
|
|
319
348
|
Every control carries a tooltip from the labels.
|
|
@@ -347,10 +376,10 @@ while editing is off, and works under any mode, not only draft.
|
|
|
347
376
|
```
|
|
348
377
|
|
|
349
378
|
`state` is
|
|
350
|
-
`{ draftCount, openCount, openRowIds,
|
|
351
|
-
`pendingCount` deprecated, reading as `draftCount + openCount`. `actions` is
|
|
379
|
+
`{ draftCount, openCount, openRowIds, isSubmitting, isSaving }`. `actions` is
|
|
352
380
|
`{ save, commitAll, discard, scrollToRow, scrollToFirstOpenRow }`, and
|
|
353
381
|
`Controls` is `{ Save, Discard, OpenRowsNote }`.
|
|
382
|
+
`actions.save` and `actions.commitAll` resolve what `edit.saveDrafts()` and `edit.commitAll()` resolve.
|
|
354
383
|
|
|
355
384
|
The grid is always virtualized, so an open row far down the list has no element
|
|
356
385
|
to scroll to. `actions.scrollToFirstOpenRow(align?)` moves the virtualizer to
|
|
@@ -370,16 +399,20 @@ row it reaches.
|
|
|
370
399
|
`setCellValue` / `setRowValues` / `clearCell`, `addRow` / `addRows` /
|
|
371
400
|
`deleteRow`, `getForm`, and `store` for `useSelector` (an example is under
|
|
372
401
|
[Submitting an outer form](#high-submitting-an-outer-form-while-the-grid-holds-a-draft)).
|
|
373
|
-
`
|
|
374
|
-
`
|
|
375
|
-
|
|
402
|
+
`commitAll()` resolves a `TMDataGridCommitAllResult`, `{ ok, committed, open }`: every row open at the call is in exactly one list, and `ok` is `true` when `open` is empty.
|
|
403
|
+
`commit(rowId)` alone resolves a plain boolean.
|
|
404
|
+
`edit.store` publishes each open or committed row's drafted values as
|
|
405
|
+
`rows[rowId].values`, which is what a cross-row check reads. A `cell`
|
|
406
|
+
renderer needs no lookup: its `row.original` is already the row as shown, and
|
|
407
|
+
`getRowValues(rowId)` is the same row for a handler with no cell context.
|
|
376
408
|
Every member with its signature, the gates, `isColumnEditable`, `deactivate`,
|
|
377
409
|
and the `edit.store` shape are in
|
|
378
410
|
[references/editing-api.md](references/editing-api.md#the-edit-engine).
|
|
379
411
|
|
|
380
|
-
`getForm` exposes
|
|
381
|
-
dirty state and errors with the inline cells, because it is the same
|
|
382
|
-
`FormApi`.
|
|
412
|
+
`getForm` exposes an open row's form: render it in a drawer and it shares
|
|
413
|
+
values, dirty state and errors with the inline cells, because it is the same
|
|
414
|
+
`FormApi`. It is `undefined` for a committed row, which holds values and no
|
|
415
|
+
form; `begin` reopens the row with a form seeded from them.
|
|
383
416
|
|
|
384
417
|
`edit.setCellValue(rowId, columnId, value)` writes one cell and commits its row with no editor open, which is what a toolbar action or a bulk fill wants.
|
|
385
418
|
The row need not be mounted, so a selected row inside a collapsed group takes the write like any other.
|
|
@@ -391,7 +424,7 @@ for (const row of grid.table.getSelectedRowModel().rows) {
|
|
|
391
424
|
}
|
|
392
425
|
```
|
|
393
426
|
|
|
394
|
-
Under `draft: true` each row
|
|
427
|
+
Under `draft: true` each row is committed into the draft store like any hand-made edit, with the same change markers and the same per-row revert, and the basket leaves through `saveDrafts`.
|
|
395
428
|
`value` is the stored value: no editor runs, so `meta.edit.mapValue` does not run either, while `meta.edit.validate` does.
|
|
396
429
|
Both resolve `false` when the cell takes no edit - no such row or column, `editing.columns` excludes it, `meta.edit.enabled` is off, or the row is not editable - and when validation refuses the value, which leaves the row open carrying its errors.
|
|
397
430
|
|
|
@@ -422,7 +455,6 @@ are in [references/common-mistakes.md](references/common-mistakes.md).
|
|
|
422
455
|
| CRITICAL | Expecting the grid to write into `data` - without `editing.onCommit` the cell reverts |
|
|
423
456
|
| CRITICAL | `getRowId` built from the row index - drafts follow the index, not the record |
|
|
424
457
|
| HIGH | A cell editor defined inside the component - a new type per render unmounts the editor |
|
|
425
|
-
| HIGH | A custom editor that binds no error text - a refused commit shows no message; bind `field.state.meta.errors` |
|
|
426
458
|
| HIGH | A cross-field rule under `mode: "cell"` - `rowValidators` needs `"row"` |
|
|
427
459
|
| HIGH | An `accessorFn` column with no `meta.edit.field` - it maps to nothing and stays read-only |
|
|
428
460
|
| HIGH | Swallowing the error in `editing.onCommit` - a resolved catch drops the draft |
|
|
@@ -431,6 +463,7 @@ are in [references/common-mistakes.md](references/common-mistakes.md).
|
|
|
431
463
|
| MEDIUM | A computed column frozen while a row is edited - `accessorFn` reads `data`; read the draft from `edit.store`'s `rows[rowId].values` |
|
|
432
464
|
| MEDIUM | Reading a commit's result as the saved value - it is a `boolean` about the form |
|
|
433
465
|
| MEDIUM | Expecting `editing.onRowDelete` to fire under draft - the mark waits for `saveDrafts` |
|
|
466
|
+
| MEDIUM | A custom editor that binds no invalid state - the host shows the message in a tooltip, but the control keeps its normal border; bind a boolean to `error` |
|
|
434
467
|
|
|
435
468
|
## References
|
|
436
469
|
|