@jielga/tmdatagrid 2.0.0-beta.21 → 2.0.0-beta.23
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.js +1101 -1099
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/docs/cell-selection.md +1 -1
- package/docs/editing.md +321 -336
- package/docs/grouping.md +6 -6
- package/docs/row-styling.md +3 -3
- package/docs/styling.md +1 -1
- package/docs/testing.md +181 -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 +1 -1
- package/skills/data/SKILL.md +1 -1
- package/skills/editing/SKILL.md +4 -3
- package/skills/editing/references/common-mistakes.md +11 -12
- package/skills/editing/references/editing-api.md +2 -0
- package/skills/filtering/SKILL.md +1 -1
- package/skills/getting-started/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +4 -4
- package/skills/options/SKILL.md +1 -1
- package/skills/rows/SKILL.md +4 -3
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +10 -1
- package/skills/testing-editing/SKILL.md +225 -0
- package/src/components/TMDataGridDetailsColumn.tsx +2 -2
- package/src/components/TMDataGridEntryRows.tsx +49 -24
- package/src/components/TMDataGridFooter.tsx +1 -1
- package/src/components/TMDataGridGroupColumn.tsx +1 -1
- package/src/components/TMDataGridHeaderCell.module.css +2 -2
- package/src/components/TMDataGridHeaderCell.tsx +5 -5
- package/src/components/TMDataGridHeaderFilterRow.tsx +1 -1
- package/src/components/TMDataGridTable.tsx +34 -22
package/docs/grouping.md
CHANGED
|
@@ -56,7 +56,7 @@ grouped columns to the front. Note that the kept column's data cells render as
|
|
|
56
56
|
TanStack's grouped-cell placeholder - blank - with the value only on group
|
|
57
57
|
rows, so it repeats what the tree lane already shows and cannot be typed into.
|
|
58
58
|
To set the grouped field on a new row, seed it through `edit.addRow(values)` -
|
|
59
|
-
see [Editing](/docs/editing#adding-
|
|
59
|
+
see [Editing](/docs/editing#adding-rows).
|
|
60
60
|
|
|
61
61
|
## Aggregation
|
|
62
62
|
|
|
@@ -114,10 +114,10 @@ so it does not fire `onRowClick`, cannot be highlighted, cannot be
|
|
|
114
114
|
`rowStyle` and `rowClassName` are the exception: they are called for group rows too, with that same child's record as `original`.
|
|
115
115
|
Guard a callback that reads `original` with `row.getIsGrouped()`, and set `--dg-row-group-bg` to colour the group rows themselves.
|
|
116
116
|
|
|
117
|
-
`data-grouped` is
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
`data-grouped` is present, with the value `"true"`, only on group rows, so
|
|
118
|
+
`[data-grouped]` and `[data-grouped="true"]` are equivalent. `data-depth`
|
|
119
|
+
carries the nesting level, and `--dg-row-group-bg` sets a group row's
|
|
120
|
+
background.
|
|
121
121
|
|
|
122
122
|
## Grouping and pagination
|
|
123
123
|
|
|
@@ -161,5 +161,5 @@ server-side can set `enableGrouping: true` alongside `manualGrouping: true`. See
|
|
|
161
161
|
| `getGroupDataRows` | Export | `(row) => Row[]` | – | Every record under a group row, at any depth. |
|
|
162
162
|
| `isPagingActive` | Export | `(table, features) => boolean` | – | Whether the pager is slicing anything. `false` while grouped. |
|
|
163
163
|
| `--dg-row-group-bg` | CSS variable | colour | Themed | Group row background. |
|
|
164
|
-
| `data-grouped` | Data attribute | `"true"
|
|
164
|
+
| `data-grouped` | Data attribute | `"true"` | – | `"true"` on group rows. Absent on the rest. |
|
|
165
165
|
| `data-depth` | Data attribute | `number` | – | Nesting level, on every row. |
|
package/docs/row-styling.md
CHANGED
|
@@ -105,13 +105,13 @@ it without a callback:
|
|
|
105
105
|
| `data-selected` | Selected rows |
|
|
106
106
|
| `data-selected-bg` | Selected rows that also take the background |
|
|
107
107
|
| `data-highlighted` | The highlighted row |
|
|
108
|
-
| `data-grouped` |
|
|
108
|
+
| `data-grouped` | Group rows |
|
|
109
109
|
| `data-depth` | Every row. The nesting level |
|
|
110
110
|
| `data-context-menu` | The row whose context menu is open |
|
|
111
111
|
| `data-row-id` | Every row. Its id, which [tests](/docs/testing) key off |
|
|
112
112
|
|
|
113
|
-
The state attributes are
|
|
114
|
-
|
|
113
|
+
The state attributes are present, with the value `"true"`, only on the rows
|
|
114
|
+
they apply to, so the bare attribute and the value match the same rows:
|
|
115
115
|
|
|
116
116
|
```css
|
|
117
117
|
[data-dg-part="row"][data-grouped="true"] {
|
package/docs/styling.md
CHANGED
|
@@ -50,7 +50,7 @@ The wrapper components - `Toolbar`, `Spacer`, `Footer`, `FilterPanel`, `FilterPi
|
|
|
50
50
|
| `--dg-row-height` | From `size` | Row height. Prefer `meta.rowHeight` - the virtualizer needs the number. |
|
|
51
51
|
| `--dg-header-height` | From `size` | Header row height |
|
|
52
52
|
| `--dg-summary-height` | From `size` | [Summary row](/docs/summary-row) height |
|
|
53
|
-
| `--dg-entry-height` | From `size` | The sticky [entry block](/docs/editing#adding-
|
|
53
|
+
| `--dg-entry-height` | From `size` | The sticky [entry block](/docs/editing#adding-rows) |
|
|
54
54
|
| `--dg-font-size` | From `size` | Cell and header font size |
|
|
55
55
|
| `--dg-padding` | From `size` | Horizontal cell padding. The generated lanes are excluded: they are fixed 36px tracks that centre their control. |
|
|
56
56
|
| `--dg-radius` | `--mantine-radius-md` | The frame's corner radius. `0` squares the grid off. The root clips its overflow, so the header and the last row follow it. |
|
package/docs/testing.md
CHANGED
|
@@ -62,6 +62,17 @@ const cell = orders.locator('[data-row-id="42"][data-column-id="total"]');
|
|
|
62
62
|
|
|
63
63
|
Body cells carry no `data-dg-part`; the coordinate pair identifies them.
|
|
64
64
|
|
|
65
|
+
**State attributes are present only while they apply.** A boolean attribute
|
|
66
|
+
such as `data-selected`, `data-new` or `data-invalid` is rendered with the
|
|
67
|
+
value `"true"` while its state holds and omitted otherwise, so the bare
|
|
68
|
+
attribute and the value match the same elements, and the negative is the
|
|
69
|
+
absence:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const drafts = orders.locator('[data-dg-part="row"][data-draft]');
|
|
73
|
+
await expect(row).not.toHaveAttribute("data-deleted");
|
|
74
|
+
```
|
|
75
|
+
|
|
65
76
|
## Parts
|
|
66
77
|
|
|
67
78
|
Row and column ids come from your data (`getRowId` and the column definitions),
|
|
@@ -264,6 +275,49 @@ export class DataGrid {
|
|
|
264
275
|
await this.part("columns-toggle", { columnId }).click();
|
|
265
276
|
}
|
|
266
277
|
|
|
278
|
+
/** The entry row opened by `edit.addRow()`; `data-row-id` is its temp id. */
|
|
279
|
+
entryRow(): Locator {
|
|
280
|
+
return this.part("entry-row");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Types into the built-in editors of an open row: an entry row, or a row
|
|
284
|
+
* opened in row mode. */
|
|
285
|
+
async fillRow(rowId: string, values: Record<string, string>): Promise<void> {
|
|
286
|
+
for (const [columnId, value] of Object.entries(values)) {
|
|
287
|
+
await this.part("editor", { rowId, columnId })
|
|
288
|
+
.locator('[data-dg-part="editor-input"]')
|
|
289
|
+
.fill(value);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async commitEntryRow(rowId: string): Promise<void> {
|
|
294
|
+
await this.part("confirm-new-row", { rowId }).click();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Presses Save in `TMDataGrid.DraftActions` and waits for the store to empty. */
|
|
298
|
+
async saveDrafts(): Promise<void> {
|
|
299
|
+
await this.part("save-all").click();
|
|
300
|
+
await expect(this.part("save-all")).toHaveAttribute("data-draft-count", "0");
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Finds a row the test added by a value unique to it, since the grid does
|
|
304
|
+
* not know the id the app gave the row. Retries until the app has put the
|
|
305
|
+
* row in `data`. */
|
|
306
|
+
async expectRowAdded(
|
|
307
|
+
uniqueValue: string,
|
|
308
|
+
cells: Record<string, string>,
|
|
309
|
+
): Promise<void> {
|
|
310
|
+
await this.search(uniqueValue);
|
|
311
|
+
await this.expectRowCount(1);
|
|
312
|
+
const row = this.part("row");
|
|
313
|
+
for (const [columnId, text] of Object.entries(cells)) {
|
|
314
|
+
await expect(row.locator(`[data-column-id="${columnId}"]`)).toHaveText(
|
|
315
|
+
text,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
await this.search("");
|
|
319
|
+
}
|
|
320
|
+
|
|
267
321
|
async expectRowCount(count: number): Promise<void> {
|
|
268
322
|
await expect(this.grid).toHaveAttribute(
|
|
269
323
|
"data-dg-row-count",
|
|
@@ -291,6 +345,133 @@ test("filters to one employee", async ({ page }) => {
|
|
|
291
345
|
});
|
|
292
346
|
```
|
|
293
347
|
|
|
348
|
+
## Editing
|
|
349
|
+
|
|
350
|
+
### Adding a row
|
|
351
|
+
|
|
352
|
+
[`edit.addRow()`](/docs/editing) opens an entry row, `data-dg-part="entry-row"`,
|
|
353
|
+
keyed by a temporary id (`__new__1`, `__new__2`, …). Its editors are `editor`
|
|
354
|
+
parts keyed by that id and the column. What ✓ does with the row depends on
|
|
355
|
+
`editing.draft`:
|
|
356
|
+
|
|
357
|
+
| Step | Without `draft` | With `draft: true` |
|
|
358
|
+
| --- | --- | --- |
|
|
359
|
+
| `addRow()` | `entry-row[data-row-id="__new__1"]` | Same |
|
|
360
|
+
| ✓ fails validation | The entry row stays; the failing cells carry `data-invalid` | Same |
|
|
361
|
+
| ✓ (`confirm-new-row`) | The entry row is removed and the temp id is gone. `onRowAdd` receives the values, and the row exists again only once your app puts it in `data`, under the id your `getRowId` returns | The row becomes a body row, still keyed by the temp id: `row[data-row-id="__new__1"][data-new="true"][data-draft="true"]`, with `row-state[data-state="new"]` in its lane and `save-all[data-draft-count]` counting it |
|
|
362
|
+
| Save (`save-all`) | - | As ✓ without `draft`: the temp id is gone, and the row comes back through `data` under your id |
|
|
363
|
+
|
|
364
|
+
The grid never learns which id your app gave the row, so once `onRowAdd` or
|
|
365
|
+
`saveDrafts` has run, the row cannot be addressed by id. Find it by its content
|
|
366
|
+
instead: narrow the grid to a value unique to the row, assert that one row is
|
|
367
|
+
left, and read that row's cells. The row-count assertion is also the wait,
|
|
368
|
+
since it retries until the app has put the row in `data`:
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
test("adds an employee", async ({ page }) => {
|
|
372
|
+
const grid = new DataGrid(page, "employees");
|
|
373
|
+
await page.goto("/employees");
|
|
374
|
+
await grid.expectSettled();
|
|
375
|
+
|
|
376
|
+
// The app's own button, calling edit.addRow()
|
|
377
|
+
await page.getByRole("button", { name: "Add row" }).click();
|
|
378
|
+
const tempId = (await grid.entryRow().getAttribute("data-row-id"))!;
|
|
379
|
+
await grid.fillRow(tempId, { name: "Nordkvist-4711", city: "Stockholm" });
|
|
380
|
+
await grid.commitEntryRow(tempId);
|
|
381
|
+
|
|
382
|
+
await expect(grid.entryRow()).toHaveCount(0);
|
|
383
|
+
await grid.expectRowAdded("Nordkvist-4711", {
|
|
384
|
+
name: "Nordkvist-4711",
|
|
385
|
+
city: "Stockholm",
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
Use a value no other row has, such as a name with a run id in it, so that the
|
|
391
|
+
search leaves one row. If the grid has no quick search, narrow with `filterBy`
|
|
392
|
+
on a column instead.
|
|
393
|
+
|
|
394
|
+
Under `draft: true` the temp id stays valid until Save, so the committed row is
|
|
395
|
+
asserted directly, and the content-based check applies after the save:
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
await grid.commitEntryRow(tempId);
|
|
399
|
+
const row = grid.part("row", { rowId: tempId });
|
|
400
|
+
await expect(row).toHaveAttribute("data-new", "true");
|
|
401
|
+
await expect(grid.part("row-state", { rowId: tempId })).toHaveAttribute(
|
|
402
|
+
"data-state",
|
|
403
|
+
"new",
|
|
404
|
+
);
|
|
405
|
+
await expect(grid.part("save-all")).toHaveAttribute("data-draft-count", "1");
|
|
406
|
+
|
|
407
|
+
await grid.saveDrafts();
|
|
408
|
+
await expect(row).toHaveCount(0);
|
|
409
|
+
await grid.expectRowAdded("Nordkvist-4711", { city: "Stockholm" });
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Under `newRowsSticky: true` the committed row stays in the entry block instead,
|
|
413
|
+
as `entry-row[data-row-id="__new__1"][data-committed="true"]`, outside
|
|
414
|
+
`data-dg-row-count`, until the save.
|
|
415
|
+
|
|
416
|
+
A ✓ that fails validation keeps the entry row open, with `data-invalid` on the
|
|
417
|
+
failing cells:
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
await grid.commitEntryRow(tempId);
|
|
421
|
+
await expect(grid.entryRow()).toHaveCount(1);
|
|
422
|
+
await expect(
|
|
423
|
+
grid.entryRow().locator('[data-column-id="email"]'),
|
|
424
|
+
).toHaveAttribute("data-invalid", "true");
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Changing a row
|
|
428
|
+
|
|
429
|
+
Without `draft`, a commit goes to `onCommit` and the grid keeps nothing of it, so
|
|
430
|
+
the assertion is the cell's text once your app has applied the change. Under
|
|
431
|
+
`draft: true` the change stays in the grid until Save, marked on the cell, the
|
|
432
|
+
row and the lane:
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
const cell = grid.cell({ rowId: "42", columnId: "salary" });
|
|
436
|
+
await cell.dblclick();
|
|
437
|
+
await grid.fillRow("42", { salary: "52000" });
|
|
438
|
+
await page.keyboard.press("Enter");
|
|
439
|
+
|
|
440
|
+
// Without draft: the app applied it
|
|
441
|
+
await expect(cell).toHaveText("52 000");
|
|
442
|
+
|
|
443
|
+
// Under draft: the grid holds it
|
|
444
|
+
await expect(cell).toHaveAttribute("data-dirty", "true");
|
|
445
|
+
await expect(grid.part("row", { rowId: "42" })).toHaveAttribute("data-dirty", "true");
|
|
446
|
+
await expect(grid.part("row-state", { rowId: "42" })).toHaveAttribute(
|
|
447
|
+
"data-state",
|
|
448
|
+
"edited",
|
|
449
|
+
);
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
In row mode, `edit-row` opens the row, `save-row` commits it and `cancel-row`
|
|
453
|
+
discards it; `fillRow` reaches the open row's editors the same way.
|
|
454
|
+
|
|
455
|
+
### Deleting a row
|
|
456
|
+
|
|
457
|
+
`delete-row` calls `onRowDelete` at once, or marks the row under `draft: true`:
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
const before = Number(await grid.grid.getAttribute("data-dg-row-count"));
|
|
461
|
+
await grid.part("delete-row", { rowId: "42" }).click();
|
|
462
|
+
|
|
463
|
+
// Without draft: the app removed it from data
|
|
464
|
+
await grid.expectRowCount(before - 1);
|
|
465
|
+
|
|
466
|
+
// Under draft: marked until Save, and Restore undoes the mark
|
|
467
|
+
await expect(grid.part("row", { rowId: "42" })).toHaveAttribute("data-deleted", "true");
|
|
468
|
+
await grid.part("restore-row", { rowId: "42" }).click();
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Assert a deletion on `data-dg-row-count`, not on the row's element: a row
|
|
472
|
+
outside the viewport has no element either, so `toHaveCount(0)` passes for it
|
|
473
|
+
whether or not it was deleted.
|
|
474
|
+
|
|
294
475
|
## React Testing Library
|
|
295
476
|
|
|
296
477
|
Under jsdom there is no layout, so the virtualizer mounts a handful of rows
|
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.23",
|
|
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",
|
|
@@ -18,7 +18,7 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.0.0-beta.
|
|
21
|
+
library_version: '2.0.0-beta.23'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/styling.md'
|
|
24
24
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/toolbar.md'
|
|
@@ -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.23'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/cell-selection.md'
|
|
20
20
|
- 'Jielga/TMDataGrid: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.0.0-beta.
|
|
19
|
+
library_version: '2.0.0-beta.23'
|
|
20
20
|
sources:
|
|
21
21
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/columns.md'
|
|
22
22
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/column-layout.md'
|
package/skills/data/SKILL.md
CHANGED
|
@@ -18,7 +18,7 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.0.0-beta.
|
|
21
|
+
library_version: '2.0.0-beta.23'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/pagination.md'
|
|
24
24
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/scrolling.md'
|
package/skills/editing/SKILL.md
CHANGED
|
@@ -18,7 +18,7 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.0.0-beta.
|
|
21
|
+
library_version: '2.0.0-beta.23'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/editing.md'
|
|
24
24
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/query-builder.md'
|
|
@@ -385,8 +385,9 @@ row it reaches.
|
|
|
385
385
|
`deleteRow`, `getForm`, and `store` for `useSelector` (an example is under
|
|
386
386
|
[Submitting an outer form](#high-submitting-an-outer-form-while-the-grid-holds-a-draft)).
|
|
387
387
|
`edit.store` publishes each open or committed row's drafted values as
|
|
388
|
-
`rows[rowId].values`, which is what a
|
|
389
|
-
|
|
388
|
+
`rows[rowId].values`, which is what a cross-row check reads. A `cell`
|
|
389
|
+
renderer needs no lookup: its `row.original` is already the row as shown, and
|
|
390
|
+
`getRowValues(rowId)` is the same row for a handler with no cell context.
|
|
390
391
|
Every member with its signature, the gates, `isColumnEditable`, `deactivate`,
|
|
391
392
|
and the `edit.store` shape are in
|
|
392
393
|
[references/editing-api.md](references/editing-api.md#the-edit-engine).
|
|
@@ -187,24 +187,23 @@ A refused value leaves the row open carrying its errors and the call resolves `f
|
|
|
187
187
|
|
|
188
188
|
Source: `packages/tmdatagrid/src/core/editEngine.ts` (`begin`, `writeFields`).
|
|
189
189
|
|
|
190
|
-
## MEDIUM
|
|
190
|
+
## MEDIUM Reading an open row's values off `row.original` outside a cell
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
`data
|
|
195
|
-
|
|
192
|
+
Inside a `cell` renderer, `row.original` and `getValue()` are the row as
|
|
193
|
+
shown: the open form's values while the row is edited, the committed draft
|
|
194
|
+
after ✓, and `data` otherwise - a computed column follows the draft as it is
|
|
195
|
+
typed, and a button in a cell sends the draft the user sees. Outside it, the
|
|
196
|
+
row callbacks (`onRowClick`, `renderRowContextMenu`, `rowClassName`) and any
|
|
197
|
+
code holding a row id see `data`, or the committed draft, and never an open
|
|
198
|
+
form's values.
|
|
196
199
|
|
|
197
|
-
Correct:
|
|
200
|
+
Correct: reach the row as shown by id:
|
|
198
201
|
|
|
199
202
|
```tsx
|
|
200
|
-
|
|
201
|
-
const { edit } = useTMDataGridContext();
|
|
202
|
-
const values = useSelector(edit.store, (state) => state.rows[rowId]?.values);
|
|
203
|
-
return (values as Product | undefined) ?? original;
|
|
204
|
-
}
|
|
203
|
+
const shown = grid.edit.getRowValues(row.id) ?? row.original;
|
|
205
204
|
```
|
|
206
205
|
|
|
207
|
-
Source: `packages/tmdatagrid/docs/editing.md` (
|
|
206
|
+
Source: `packages/tmdatagrid/docs/editing.md` (How a draft renders).
|
|
208
207
|
|
|
209
208
|
## MEDIUM Reading a commit's result as the saved value
|
|
210
209
|
|
|
@@ -72,6 +72,8 @@ path, which may be dotted.
|
|
|
72
72
|
| `isColumnEditable` | `(column) => boolean` | The column's half alone, with no row in hand: it maps to a field, `editing.columns` lists it when that is set, and `meta.edit.enabled` is not `false`. |
|
|
73
73
|
| `canDeleteRows` | `() => boolean` | Whether the delete control should be shown. |
|
|
74
74
|
| `getForm` | `(rowId) => TMDataGridRowEditForm \| undefined` | The open row's live `FormApi`; `undefined` for a committed row. |
|
|
75
|
+
| `getRowValues` | `(rowId) => TData \| undefined` | The row as shown: the open form's values, else the committed draft, else the `data` value. `undefined` for an unknown row. |
|
|
76
|
+
| `getRows` | `() => ReadonlyArray<TMDataGridEditRowSnapshot>` | Every row as shown, from the core row model: drafts overlaid, entry rows appended, deletion-marked rows included and flagged `deleted`. |
|
|
75
77
|
| `state` | `TMDataGridEditState` | Snapshot, for reads outside React. |
|
|
76
78
|
| `store` | `Store<TMDataGridEditState>` | For `useSelector`. |
|
|
77
79
|
|
|
@@ -18,7 +18,7 @@ description: >
|
|
|
18
18
|
metadata:
|
|
19
19
|
type: core
|
|
20
20
|
library: '@jielga/tmdatagrid'
|
|
21
|
-
library_version: '2.0.0-beta.
|
|
21
|
+
library_version: '2.0.0-beta.23'
|
|
22
22
|
sources:
|
|
23
23
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/filtering.md'
|
|
24
24
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/quick-search.md'
|
|
@@ -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.23'
|
|
15
15
|
sources:
|
|
16
16
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/getting-started.md'
|
|
17
17
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/anatomy.md'
|
package/skills/grouping/SKILL.md
CHANGED
|
@@ -14,7 +14,7 @@ description: >
|
|
|
14
14
|
metadata:
|
|
15
15
|
type: core
|
|
16
16
|
library: '@jielga/tmdatagrid'
|
|
17
|
-
library_version: '2.0.0-beta.
|
|
17
|
+
library_version: '2.0.0-beta.23'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/grouping.md'
|
|
20
20
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/summary-row.md'
|
|
@@ -90,8 +90,8 @@ would pass a row that looks real but is the wrong one. Group rows therefore:
|
|
|
90
90
|
as `original`, so guard a callback reading `original` with
|
|
91
91
|
`row.getIsGrouped()` and colour the group rows with `--dg-row-group-bg`
|
|
92
92
|
- carry `data-grouped="true"` and `data-depth`, with `--dg-row-group-bg`
|
|
93
|
-
behind them. `data-grouped` is on
|
|
94
|
-
|
|
93
|
+
behind them. `data-grouped` is present only on group rows, so
|
|
94
|
+
`[data-grouped]` and `[data-grouped="true"]` are equivalent
|
|
95
95
|
|
|
96
96
|
A group row's checkbox selects every record under it at any depth, including
|
|
97
97
|
records inside collapsed sub-groups, showing a tick once all are selected and a
|
|
@@ -273,7 +273,7 @@ Source: `packages/tmdatagrid/docs/grouping.md` (Server-side grids).
|
|
|
273
273
|
| `isPagingActive` | Export | `(table, features) => boolean` | – | Whether the pager is slicing anything. `false` while grouped. |
|
|
274
274
|
| `--dg-row-group-bg` | CSS variable | colour | Themed | Group row background. |
|
|
275
275
|
| `--dg-summary-height` | CSS variable | length | From `size` | Height of the summary row. |
|
|
276
|
-
| `data-grouped` · `data-depth` | Data attributes | – | – | `"true"` on group rows (
|
|
276
|
+
| `data-grouped` · `data-depth` | Data attributes | – | – | `"true"` on group rows (absent on the rest), and the nesting level on every row. |
|
|
277
277
|
|
|
278
278
|
See also: the `rows` skill for selection and the details lane, and the `data`
|
|
279
279
|
skill for the pager grouping suspends.
|
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.23'
|
|
18
18
|
sources:
|
|
19
19
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/use-tm-data-grid.md'
|
|
20
20
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/useTMDataGrid.tsx'
|
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.23'
|
|
21
21
|
sources:
|
|
22
22
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/row-selection.md'
|
|
23
23
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/row-interaction.md'
|
|
@@ -211,8 +211,9 @@ are not striped.
|
|
|
211
211
|
Rows carry `data-selected`, `data-selected-bg`, `data-highlighted`,
|
|
212
212
|
`data-grouped`, `data-depth`, `data-context-menu` and `data-row-id`, so a
|
|
213
213
|
stylesheet can target any of it without a callback. The boolean attributes are
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
present, with the value `"true"`, only while they apply - `data-grouped` only
|
|
215
|
+
on group rows - so `[data-grouped]` and `[data-grouped="true"]` are
|
|
216
|
+
equivalent. Pick a `--row-bg` that
|
|
216
217
|
reads under both colour schemes - a `-0` Mantine shade is near-white and
|
|
217
218
|
unreadable in dark mode; mix a mid shade into transparency instead.
|
|
218
219
|
|
|
@@ -15,7 +15,7 @@ description: >
|
|
|
15
15
|
metadata:
|
|
16
16
|
type: core
|
|
17
17
|
library: '@jielga/tmdatagrid'
|
|
18
|
-
library_version: '2.0.0-beta.
|
|
18
|
+
library_version: '2.0.0-beta.23'
|
|
19
19
|
sources:
|
|
20
20
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/server-side.md'
|
|
21
21
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/server-query.md'
|
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.23'
|
|
15
15
|
sources:
|
|
16
16
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/docs/testing.md'
|
|
17
17
|
- 'Jielga/TMDataGrid:packages/tmdatagrid/src/components/TMDataGrid.tsx'
|
|
@@ -33,6 +33,9 @@ The grid mints no `data-testid` of its own - that attribute belongs to the app,
|
|
|
33
33
|
and Playwright's `testIdAttribute` is configurable. `@mantine/core` and
|
|
34
34
|
`@tanstack/*` ship none either.
|
|
35
35
|
|
|
36
|
+
Adding, changing and deleting rows, the draft store, and where a new row's
|
|
37
|
+
temporary id goes at commit are in the `testing-editing` skill.
|
|
38
|
+
|
|
36
39
|
## Naming a grid
|
|
37
40
|
|
|
38
41
|
Parts repeat across grids on a page. Name the grid, scope through it:
|
|
@@ -58,6 +61,12 @@ accessible name belongs to the element carrying the `grid` role.
|
|
|
58
61
|
|
|
59
62
|
Body cells carry no `data-dg-part` - the coordinate pair already names them.
|
|
60
63
|
|
|
64
|
+
State attributes are present only while they apply: `data-selected`,
|
|
65
|
+
`data-new`, `data-invalid` and the rest are rendered as `"true"` while the
|
|
66
|
+
state holds and omitted otherwise, so `[data-new]` and `[data-new="true"]`
|
|
67
|
+
match the same rows, and the negative is `:not([data-new])` in CSS and
|
|
68
|
+
`not.toHaveAttribute("data-new")` in a test.
|
|
69
|
+
|
|
61
70
|
## Parts
|
|
62
71
|
|
|
63
72
|
**Whole-grid** (unique, no coordinate needed): `toolbar`, `summary-count`,
|