@jielga/tmdatagrid 2.0.0-beta.1 → 2.0.0-beta.10

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.
Files changed (61) hide show
  1. package/dist/index.d.ts +592 -168
  2. package/dist/index.js +3289 -2224
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +1 -1
  5. package/package.json +2 -1
  6. package/skills/appearance/SKILL.md +41 -4
  7. package/skills/cell-selection/SKILL.md +25 -33
  8. package/skills/columns/SKILL.md +104 -6
  9. package/skills/data/SKILL.md +14 -10
  10. package/skills/editing/SKILL.md +229 -256
  11. package/skills/editing/references/common-mistakes.md +264 -0
  12. package/skills/editing/references/editing-api.md +70 -22
  13. package/skills/editing/references/editors-and-validation.md +78 -18
  14. package/skills/filtering/SKILL.md +1 -1
  15. package/skills/getting-started/SKILL.md +11 -9
  16. package/skills/grouping/SKILL.md +22 -5
  17. package/skills/options/SKILL.md +33 -5
  18. package/skills/rows/SKILL.md +8 -4
  19. package/skills/rows/references/rows-api.md +1 -1
  20. package/skills/server-side/SKILL.md +1 -1
  21. package/skills/testing/SKILL.md +4 -3
  22. package/src/tmdatagrid/TMDataGridContext.ts +7 -19
  23. package/src/tmdatagrid/components/TMDataGrid.module.css +14 -1
  24. package/src/tmdatagrid/components/TMDataGrid.tsx +11 -6
  25. package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +108 -29
  26. package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +7 -40
  27. package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +4 -4
  28. package/src/tmdatagrid/components/TMDataGridDraftActions.tsx +296 -0
  29. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +263 -93
  30. package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +169 -82
  31. package/src/tmdatagrid/components/TMDataGridFooter.tsx +5 -5
  32. package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +4 -3
  33. package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +73 -21
  34. package/src/tmdatagrid/components/TMDataGridMenu.tsx +222 -0
  35. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +4 -5
  36. package/src/tmdatagrid/components/TMDataGridTable.module.css +106 -11
  37. package/src/tmdatagrid/components/TMDataGridTable.tsx +550 -86
  38. package/src/tmdatagrid/components/TMDataGridToolbar.module.css +4 -0
  39. package/src/tmdatagrid/components/TMDataGridToolbar.tsx +12 -55
  40. package/src/tmdatagrid/components/editors/TMDataGridBooleanEditor.tsx +3 -3
  41. package/src/tmdatagrid/components/editors/TMDataGridDateEditor.tsx +3 -3
  42. package/src/tmdatagrid/components/editors/TMDataGridMultiSelectEditor.tsx +3 -3
  43. package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +37 -7
  44. package/src/tmdatagrid/components/editors/TMDataGridSelectEditor.tsx +3 -3
  45. package/src/tmdatagrid/components/editors/TMDataGridStringEditor.tsx +3 -3
  46. package/src/tmdatagrid/components/editors/editorShared.ts +15 -30
  47. package/src/tmdatagrid/components/icons.ts +2 -0
  48. package/src/tmdatagrid/components/useHideableColumns.ts +52 -0
  49. package/src/tmdatagrid/core/capabilities.ts +19 -1
  50. package/src/tmdatagrid/core/controlledState.ts +179 -0
  51. package/src/tmdatagrid/core/draftCellContext.ts +68 -0
  52. package/src/tmdatagrid/core/editEngine.ts +1106 -116
  53. package/src/tmdatagrid/core/editorFocus.ts +8 -4
  54. package/src/tmdatagrid/core/labels.ts +32 -7
  55. package/src/tmdatagrid/core/labelsSv.ts +10 -2
  56. package/src/tmdatagrid/core/resizePreview.ts +141 -0
  57. package/src/tmdatagrid/core/summary.ts +10 -2
  58. package/src/tmdatagrid/core/useSettledTableState.ts +36 -0
  59. package/src/tmdatagrid/index.ts +20 -9
  60. package/src/tmdatagrid/useTMDataGrid.tsx +401 -69
  61. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +0 -162
package/dist/index.d.ts CHANGED
@@ -1,88 +1,61 @@
1
- import { Cell, Column, ColumnPinningState, ExpandedState, Header, Row, RowData, RowSelectionState, Table, TableFeatures, TableOptions, TableState, aggregationFns } from "@tanstack/react-table";
2
- import { CSSProperties, ComponentType, MouseEvent, MutableRefObject, ReactNode } from "react";
3
1
  import { MantineSize, MenuProps } from "@mantine/core";
2
+ import { CSSProperties, ComponentType, MouseEvent, MutableRefObject, ReactNode } from "react";
3
+ import { Cell, Column, ColumnPinningState, ExpandedState, Header, Row, RowData, RowSelectionState, Table, TableFeatures, TableOptions, TableState, aggregationFns } from "@tanstack/react-table";
4
4
  import { Store } from "@tanstack/store";
5
5
  import { AnyFieldApi, AnyFormApi, StandardSchemaV1 } from "@tanstack/react-form";
6
6
  import { RankingInfo } from "@tanstack/match-sorter-utils";
7
- //#region .types-tmp/components/TMDataGridColumnsPanel.d.ts
8
- /**
9
- * The "Manage columns" surface. Reachable from every column header menu and
10
- * from the grid's burger menu, so it lives on its own and is rendered by
11
- * `TMDataGrid.ColumnsButton`.
12
- */
13
- declare function TMDataGridColumnsPanel(): import("react").JSX.Element;
14
- //#endregion
15
- //#region .types-tmp/components/TMDataGridEditActions.d.ts
16
- /** What the edit chrome is showing. */
17
- type TMDataGridEditActionsState = {
18
- /** Rows with unsaved work: dirty edits, entry rows, and deletion marks. */
19
- pendingCount: number;
20
- /** Whether a submit is in flight. */
21
- isSubmitting: boolean;
22
- };
23
- /** What the edit chrome can do. */
24
- type TMDataGridEditActionsActions = {
25
- /** Commits every open row. Resolves `false` when a row stayed open. */
26
- save: () => Promise<boolean>;
27
- /** Drops every draft. */
28
- discard: () => void;
29
- };
30
- /** The pre-bound pieces of the built-in edit chrome. */
31
- type TMDataGridEditActionsControls = {
32
- /** Save, with the pending count, disabled while nothing is pending. */
33
- Save: () => ReactNode;
34
- /** Discard, disabled while nothing is pending. */
35
- Discard: () => ReactNode;
36
- };
37
- /** What {@link TMDataGridEditActionsProps.renderActions} is handed. */
38
- type TMDataGridEditActionsSlotArgs = {
39
- state: TMDataGridEditActionsState;
40
- actions: TMDataGridEditActionsActions;
41
- Controls: TMDataGridEditActionsControls;
7
+ //#region .types-tmp/components/TMDataGridMenu.d.ts
8
+ type TMDataGridMenuProps = Omit<MenuProps, "children"> & {
9
+ /** The dropdown's content: Mantine `Menu.Item`s and the `TMDataGrid.Menu.*` items. */
10
+ children: ReactNode;
11
+ /** Replaces the burger icon on the trigger. */
12
+ icon?: ReactNode;
13
+ /** Tooltip and `aria-label` of the trigger. Default `labels.menuButton`. */
14
+ label?: string;
42
15
  };
43
- type TMDataGridEditActionsProps = {
44
- /**
45
- * Replaces the built-in Save/Discard pair, and is handed the pieces of it.
46
- *
47
- * ```tsx
48
- * <TMDataGrid.EditActions
49
- * renderActions={({ state, Controls }) => (
50
- * <Group>
51
- * {state.pendingCount > 0 && <Badge>{state.pendingCount}</Badge>}
52
- * <Controls.Save />
53
- * <Controls.Discard />
54
- * </Group>
55
- * )}
56
- * />
57
- * ```
58
- */
59
- renderActions?: (args: TMDataGridEditActionsSlotArgs) => ReactNode;
16
+ type TMDataGridMenuColumnsProps = {
17
+ /** Renders a `Menu.Search` above the toggles. Default `true`. Use `false` inside a `Menu.Sub`. */
18
+ searchable?: boolean;
60
19
  };
61
20
  /**
62
- * Batch mode's toolbar chrome: Save with the dirty-row count, and Discard.
63
- * Both read the edit store, so they grey out while nothing is dirty and the
64
- * Save spins while a submit is in flight. Works under any `editing.mode` - a
65
- * cellConfirm grid accumulating drafts can offer the same pair - and renders
66
- * nothing while editing is off.
21
+ * The whole column chooser as menu items: a search box, one checkbox item per
22
+ * hideable column, show/hide all, and Reset layout. Renders nothing when no
23
+ * column can be hidden.
67
24
  *
68
- * ```tsx
69
- * <TMDataGrid.Toolbar>
70
- * <TMDataGrid.SummaryCount />
71
- * <TMDataGrid.Spacer />
72
- * <TMDataGrid.EditActions />
73
- * </TMDataGrid.Toolbar>
74
- * ```
25
+ * `searchable` is only for a block at the top level of a dropdown.
26
+ * `Menu.Search` registers on the root menu context (`hasSearch`), which
27
+ * switches off type-ahead and the arrow-key handling of every dropdown of that
28
+ * menu, so a search inside a `Menu.Sub` breaks the parent menu's keyboard
29
+ * behaviour.
75
30
  */
76
- declare function TMDataGridEditActions({ renderActions }?: TMDataGridEditActionsProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
31
+ declare function TMDataGridMenuColumns({ searchable }: TMDataGridMenuColumnsProps): import("react").JSX.Element | null;
32
+ /**
33
+ * One checkbox item per hideable column, narrowed to `search` when one is
34
+ * given. Renders nothing when no column can be hidden.
35
+ */
36
+ declare function TMDataGridMenuColumnToggles({ search }: {
37
+ search?: string;
38
+ }): import("react").JSX.Element | null;
39
+ /**
40
+ * Shows or hides every listed column at once. Renders nothing when no column
41
+ * can be hidden.
42
+ */
43
+ declare function TMDataGridMenuShowHideAll(): import("react").JSX.Element | null;
44
+ /**
45
+ * Resets the whole layout, not only visibility: order, widths, pinning and
46
+ * grouping go back too. Not `table.resetColumnVisibility()`, which resets to
47
+ * `initialState` - and under persistence the mount built that *from* the
48
+ * persisted payload.
49
+ */
50
+ declare function TMDataGridMenuResetLayout(): import("react").JSX.Element;
77
51
  //#endregion
78
- //#region .types-tmp/components/TMDataGridFilterPanel.d.ts
52
+ //#region .types-tmp/components/TMDataGridColumnsPanel.d.ts
79
53
  /**
80
- * The MUI-style filter surface: one row per active column filter, each row a
81
- * column / operator / value triple. It only ever reads and writes the table's
82
- * `columnFilters` state, so a `manualFiltering` grid gets the same panel for
83
- * free - the state is forwarded to the server instead of a row model.
54
+ * The "Manage columns" surface as plain controls, for a host that is not a
55
+ * menu - a Popover, a Drawer, an inline layout. `TMDataGrid.Menu.Columns` is
56
+ * the same chooser as menu items.
84
57
  */
85
- declare function TMDataGridFilterPanel(): import("react").JSX.Element | null;
58
+ declare function TMDataGridColumnsPanel(): import("react").JSX.Element;
86
59
  //#endregion
87
60
  //#region .types-tmp/core/sizes.d.ts
88
61
  type TMDataGridSize = MantineSize;
@@ -113,28 +86,6 @@ type TMDataGridContextValue = TMDataGridApi<TMDataGridRowData> & {
113
86
  controlSize: TMDataGridSize;
114
87
  };
115
88
  declare function useTMDataGridContext(): TMDataGridContextValue;
116
- /**
117
- * What a control inside a *body* cell should put in its `tabIndex`.
118
- *
119
- * `-1` once cell selection is on, and this is what makes the promise of one tab
120
- * stop true. Without it the browser walks Tab into the checkbox of every
121
- * mounted row - a grid showing twenty rows would be twenty tab stops, and
122
- * scrolling would change how many. Enter or F2 steps into the cell instead,
123
- * which reaches a `-1` control perfectly well.
124
- *
125
- * Header controls are not covered: the header row is not part of cell
126
- * navigation, so its sort buttons and menus stay in the tab order, where they
127
- * are the only way to reach them.
128
- *
129
- * A custom cell renderer with a control in it wants the same:
130
- *
131
- * ```tsx
132
- * cell: ({ row }) => (
133
- * <Button tabIndex={useCellControlTabIndex()} onClick={...}>Open</Button>
134
- * )
135
- * ```
136
- */
137
- declare function useCellControlTabIndex(): 0 | -1;
138
89
  //#endregion
139
90
  //#region .types-tmp/core/columnOptions.d.ts
140
91
  /**
@@ -259,10 +210,21 @@ declare function tmDataGridFilterFn<TFeatures extends TableFeatures, TData exten
259
210
  //#endregion
260
211
  //#region .types-tmp/core/editEngine.d.ts
261
212
  /**
262
- * How commits happen - one axis, each mode a thin policy over the same
263
- * engine. See `editMode` on `UseTMDataGridOptions`.
213
+ * What counts as a commit - one axis, each mode a thin policy over the same
214
+ * engine. Where a commit *goes* is the other axis, `editing.draft`: out to
215
+ * the consumer, or into the draft store. See `editing` on
216
+ * `UseTMDataGridOptions`.
217
+ *
218
+ * | Mode | Enter | Tab | Focus leaves | Escape |
219
+ * | ---- | ----- | --- | ------------ | ------ |
220
+ * | `"cell"` | commits | commits, caret moves on | commits | cancels |
221
+ * | `"cellConfirm"` | commits | keeps the draft, caret moves on | keeps the draft | cancels |
222
+ * | `"row"` | commits the row | the browser's, along the row | nothing | cancels the row |
223
+ *
224
+ * An entry row is row-shaped in every mode - every editable cell open at
225
+ * once, the browser's Tab between them, and an explicit ✓.
264
226
  */
265
- type TMDataGridEditMode = "cell" | "cellConfirm" | "row" | "batch";
227
+ type TMDataGridEditMode = "cell" | "cellConfirm" | "row";
266
228
  /**
267
229
  * One editing row's live form. TanStack Form's `FormApi`, not a wrapper: the
268
230
  * engine is a form library, and everything mid-edit - values, dirty state,
@@ -315,6 +277,40 @@ type TMDataGridRowValidators = {
315
277
  onSubmitAsync?: TMDataGridValidator;
316
278
  onSubmitAsyncDebounceMs?: number;
317
279
  };
280
+ /** What `editing.tableValidators` is handed for one commit. */
281
+ type TMDataGridTableValidateArgs<TData extends RowData = TMDataGridRowData> = {
282
+ /** The committing row, as drafted. */
283
+ value: TData;
284
+ /** Its id - `addRow`'s temp id for an entry row. */
285
+ rowId: string;
286
+ /** Whether the row is an entry row, not yet in `data`. */
287
+ isNew: boolean;
288
+ /**
289
+ * The collection as it would stand if this commit landed: every data row
290
+ * overlaid with its draft where one is held (this row's `value` included),
291
+ * entry rows appended, deletion-marked rows removed. Unfiltered - a rule
292
+ * sees the whole collection whatever the view shows.
293
+ */
294
+ rows: ReadonlyArray<{
295
+ rowId: string;
296
+ value: TData;
297
+ }>;
298
+ };
299
+ /**
300
+ * `editing.tableValidators` - rules that need the other rows: no duplicate
301
+ * keys, no overlapping ranges, allocations summing to a total. Run at every
302
+ * commit, after the row's own validators, and again per parked row during
303
+ * `saveDrafts` - so a draft invalidated by a later edit blocks the save.
304
+ *
305
+ * Return nothing to pass, a message, or Form's `{ form, fields }` shape;
306
+ * pathed issues land on the committing row's cells, pathless ones on the row.
307
+ * `onSubmit` runs first, and its failure stands without `onSubmitAsync`
308
+ * running.
309
+ */
310
+ type TMDataGridTableValidators<TData extends RowData = TMDataGridRowData> = {
311
+ onSubmit?: (args: TMDataGridTableValidateArgs<TData>) => unknown;
312
+ onSubmitAsync?: (args: TMDataGridTableValidateArgs<TData>) => unknown | Promise<unknown>;
313
+ };
318
314
  /** One field's before/after across a commit. */
319
315
  type TMDataGridEditChange = {
320
316
  /** Column the field maps back to, for consumers thinking in columns. */
@@ -339,11 +335,29 @@ type TMDataGridEditCommitArgs<TData extends RowData> = {
339
335
  type TMDataGridEditRowProjection = {
340
336
  /** Field names whose value differs from the original. */
341
337
  dirtyFields: ReadonlyArray<string>;
342
- /** Field names carrying a validation error. */
338
+ /** Field names carrying a validation error, live or from a failed commit. */
343
339
  errorFields: ReadonlyArray<string>;
340
+ /**
341
+ * Those errors as text: what each cell editor is showing, plus what the
342
+ * row's last failed commit found. The second half is the reason this
343
+ * exists - Form clears a field's errors when its editor unmounts, so a row
344
+ * left invalid would go back to looking like an ordinary edited row. Such
345
+ * a message is dropped as soon as its field's value moves: the fix is what
346
+ * clears the mark.
347
+ */
348
+ errorMessages: ReadonlyArray<{
349
+ field: string;
350
+ message: string;
351
+ }>;
344
352
  /** A row-level error - a pathless `.refine()`, or a rejected commit. */
345
353
  hasRowError: boolean;
346
354
  isSubmitting: boolean;
355
+ /**
356
+ * The row as drafted - the form's `state.values`. Reference-stable while no
357
+ * value changes, so a cell may subscribe to it and repaint only when its
358
+ * row's draft actually moves.
359
+ */
360
+ values: TMDataGridRowData;
347
361
  };
348
362
  /**
349
363
  * The grid-facing index of everything mid-edit. A projection synced from the
@@ -362,16 +376,43 @@ type TMDataGridEditState = {
362
376
  columnId: string | null;
363
377
  } | null;
364
378
  /**
365
- * Rows with a live form. In cell mode at most one; in row, cellConfirm and
366
- * batch, as many as the user opened - which rows are editing.
379
+ * Rows with a live form, committed or not - every row the grid is holding
380
+ * work for. A row is *open* (undecided form state) when it is in here and
381
+ * not in {@link committedRowIds}.
367
382
  */
368
383
  openRowIds: ReadonlyArray<string>;
369
384
  rows: Record<string, TMDataGridEditRowProjection>;
370
- /** Phase 4 - rows being created, not yet in `data`. */
385
+ /**
386
+ * The draft store's edit slice: existing rows whose form passed its submit
387
+ * and is parked, waiting for `saveDrafts`. A subset of `openRowIds` - the
388
+ * values stay in the row's form, this records which side of the line the
389
+ * row is on. `begin` on one of these takes it back out, into form state.
390
+ *
391
+ * Only `editing.draft` parks. Without it a commit goes straight to the
392
+ * consumer and the form is dropped, so this stays empty.
393
+ */
394
+ committedRowIds: ReadonlyArray<string>;
395
+ /**
396
+ * The draft store's values, per row - what a committed row *is* to the
397
+ * table. Snapshotted when a row commits (existing and entry rows alike)
398
+ * and kept across a reopen until the row commits again or is dropped, so
399
+ * a row keeps its place in the sort while a second cell is being typed
400
+ * into. The hook feeds these into the table's `data` in place of the
401
+ * consumer's records, which is how sorting, filtering, grouping and
402
+ * aggregates see a draft.
403
+ */
404
+ committedValues: Readonly<Record<string, TMDataGridRowData>>;
405
+ /**
406
+ * Rows being created, not yet in `data`. `committed` is the draft store's
407
+ * add slice: the entry row passed its submit and renders as a value row
408
+ * until `begin` re-opens it. Without `editing.draft` a commit adds through
409
+ * `onRowAdd` and the entry is dropped, so it never turns `true`.
410
+ */
371
411
  newRows: ReadonlyArray<{
372
412
  tempId: string;
413
+ committed: boolean;
373
414
  }>;
374
- /** Phase 4 - rows marked deleted under batch mode. */
415
+ /** The draft store's delete slice: rows marked deleted, awaiting the save. */
375
416
  deletedRowIds: ReadonlyArray<string>;
376
417
  };
377
418
  type ErasedRow = Row<TMDataGridFeatures, TMDataGridRowData>;
@@ -481,7 +522,7 @@ type TMDataGridColumnEditOptions = {
481
522
  */
482
523
  mapValue?: TMDataGridEditValueMap;
483
524
  };
484
- /** A new row being committed - `onRowAdd`, and `submitAll`'s `added`. */
525
+ /** A new row being committed - `onRowAdd`, and `saveDrafts`'s `created`. */
485
526
  type TMDataGridRowAddArgs<TData extends RowData> = {
486
527
  /** The engine's placeholder id; the real id is the consumer's to mint. */
487
528
  tempId: string;
@@ -492,15 +533,51 @@ type TMDataGridRowDeleteArgs<TData extends RowData> = {
492
533
  rowId: string;
493
534
  row: Row<TMDataGridFeatures, TData>;
494
535
  };
495
- /** What `submitAll` hands `onEditCommitBatch` - everything pending at once. */
496
- type TMDataGridEditCommitBatchArgs<TData extends RowData> = {
497
- /** Every valid dirty existing row. */
536
+ /**
537
+ * The draft store, flushed - what `saveDrafts` hands `onSaveDrafts`. Every
538
+ * committed change at once, so a server can apply it as one transaction.
539
+ * Rows still open (undecided form state) are not in here and stay open.
540
+ */
541
+ type TMDataGridSaveDraftsArgs<TData extends RowData> = {
542
+ /** Committed edits to existing rows; each entry carries its `rowId`. */
543
+ updated: Array<TMDataGridEditCommitArgs<TData>>;
544
+ /** Committed new rows from the entry block; each entry carries its `tempId`. */
545
+ created: Array<TMDataGridRowAddArgs<TData>>;
546
+ /** Ids marked deleted while the drafts accumulated. */
547
+ deleted: Array<string>;
548
+ /** @deprecated Renamed to {@link updated}. Removed in a later beta. */
498
549
  rows: Array<TMDataGridEditCommitArgs<TData>>;
499
- /** Every valid new row from the entry block. */
550
+ /** @deprecated Renamed to {@link created}. Removed in a later beta. */
500
551
  added: Array<TMDataGridRowAddArgs<TData>>;
501
- /** Ids marked deleted while the batch accumulated. */
502
- deleted: Array<string>;
503
552
  };
553
+ /**
554
+ * Which entries of one bucket saved. `true`, or an id the map does not name,
555
+ * saved and is dropped from the draft store; `false` failed and keeps its
556
+ * draft. A bare boolean answers for the whole bucket.
557
+ */
558
+ type TMDataGridSaveOutcomes = boolean | Record<string, boolean>;
559
+ /**
560
+ * What `onSaveDrafts` may return to save part of the store.
561
+ *
562
+ * Returning nothing saves everything, and throwing saves nothing. Between
563
+ * those, name the ids that failed: they keep their drafts, committed and
564
+ * ready for the next save, while the rest are dropped. The grid marks them
565
+ * with nothing beyond the state itself - a failed edit keeps `data-draft`,
566
+ * a failed deletion keeps `data-deleted` - so the display is the consumer's.
567
+ */
568
+ type TMDataGridSaveDraftsResult = {
569
+ /** Keyed by `rowId`. */
570
+ updated?: TMDataGridSaveOutcomes;
571
+ /** Keyed by `tempId`. */
572
+ created?: TMDataGridSaveOutcomes;
573
+ /** Keyed by `rowId`. */
574
+ deleted?: TMDataGridSaveOutcomes;
575
+ };
576
+ /**
577
+ * @deprecated Renamed to {@link TMDataGridSaveDraftsArgs} - the payload is
578
+ * the draft store being saved, not a commit. Removed in a later beta.
579
+ */
580
+ type TMDataGridEditCommitDraftsArgs<TData extends RowData> = TMDataGridSaveDraftsArgs<TData>;
504
581
  /**
505
582
  * The data path a column edits, or `null` for a column that has none.
506
583
  *
@@ -522,6 +599,35 @@ declare function getEditFieldName(column: {
522
599
  }): string | null;
523
600
  /** What Delete writes into a cell - the type's honest empty value. */
524
601
  declare function clearedValueForType(type: TMDataGridColumnType): unknown;
602
+ /** `edit.addRows` options. */
603
+ type TMDataGridAddRowsOptions = {
604
+ /**
605
+ * Submit each row as it is added instead of leaving it open. Defaults to
606
+ * `false` - the rows open as editable entry rows, as `addRow` does.
607
+ */
608
+ commit?: boolean;
609
+ };
610
+ /** What `edit.addRows` reports back. Every added row is in exactly one list. */
611
+ type TMDataGridAddRowsResult = {
612
+ /** Temp ids that committed - parked as drafts, or added outright. */
613
+ committed: Array<string>;
614
+ /**
615
+ * Temp ids still open in the entry block: everything, when `commit` was
616
+ * not asked for; the rows that failed validation, when it was.
617
+ */
618
+ open: Array<string>;
619
+ };
620
+ /** One row of {@link TMDataGridEditApi.getRows}. */
621
+ type TMDataGridEditRowSnapshot<TData extends RowData = TMDataGridRowData> = {
622
+ /** The row's id - `addRow`'s temp id for an entry row. */
623
+ rowId: string;
624
+ /** The row as shown: its draft where a form holds one, else `data`'s value. */
625
+ value: TData;
626
+ /** An entry row, not yet in `data`. */
627
+ isNew: boolean;
628
+ /** Marked deleted, awaiting `saveDrafts`. */
629
+ deleted: boolean;
630
+ };
525
631
  /**
526
632
  * The engine plus its store - `api.edit`.
527
633
  *
@@ -529,13 +635,27 @@ declare function clearedValueForType(type: TMDataGridColumnType): unknown;
529
635
  * editors write through, so a consumer can render it in a drawer or a detail
530
636
  * panel and share values, dirty state and errors with the cells.
531
637
  */
532
- type TMDataGridEditApi = {
638
+ type TMDataGridEditApi<TData extends RowData = TMDataGridRowData> = {
533
639
  /** The projection store - subscribe with `useSelector(edit.store, …)`. */
534
640
  store: Store<TMDataGridEditState>;
535
641
  /** Current snapshot, for reads outside React. */
536
642
  readonly state: TMDataGridEditState;
537
643
  /** rowId → live form. The source of truth for everything mid-edit. */
538
644
  getForm: (rowId: string) => TMDataGridRowEditForm | undefined;
645
+ /**
646
+ * The row as shown: its draft values where a form holds one - open or
647
+ * parked in the draft store - else what `data` says. `undefined` when no
648
+ * such row exists. A deletion mark does not change the answer; check
649
+ * `state.deletedRowIds` for that.
650
+ */
651
+ getRowValues: (rowId: string) => TData | undefined;
652
+ /**
653
+ * Every row as shown, nothing filtered out: data rows overlaid with their
654
+ * drafts, entry rows appended, deletion-marked rows included and flagged.
655
+ * Built from the core row model, so it is unfiltered, unsorted and never
656
+ * contains group rows. Filter on `deleted` / `isNew` for the set you want.
657
+ */
658
+ getRows: () => ReadonlyArray<TMDataGridEditRowSnapshot<TData>>;
539
659
  /**
540
660
  * Whether this cell may open an editor: the column maps to a field, nothing
541
661
  * switched it off, and the row takes edits at all.
@@ -543,6 +663,13 @@ type TMDataGridEditApi = {
543
663
  canEditCell: (row: ErasedRow, column: ErasedColumn) => boolean;
544
664
  /** Whether the row takes edits at all - the edit lane's pencil gate. */
545
665
  canEditRow: (row: ErasedRow) => boolean;
666
+ /**
667
+ * Whether the column takes edits at all, with no row in hand: it maps to a
668
+ * field, `editing.columns` lists it if that option is set, and
669
+ * `meta.edit.enabled` is not `false`. A per-row `enabled` predicate is the
670
+ * row's half of the question - `canEditCell` asks both.
671
+ */
672
+ isColumnEditable: (column: ErasedColumn) => boolean;
546
673
  /**
547
674
  * Opens an editor. In row mode the whole row opens either way and `columnId`
548
675
  * only says which cell takes the caret; `null` (the lane's pencil) leaves it
@@ -565,24 +692,83 @@ type TMDataGridEditApi = {
565
692
  * `"cellConfirm"`, where the dirty cell keeps waiting for its ✓.
566
693
  */
567
694
  deactivate: () => void;
568
- /** Drops every draft. */
695
+ /** Drops every draft - open form state and the draft store alike. */
569
696
  cancelAll: () => void;
570
- /** Commits every open row - batch mode's save. `true` when all landed. */
697
+ /**
698
+ * Submits every open row, as if each had been OK'd: a row that validates
699
+ * commits (into the draft store with `editing.draft` on, straight to the
700
+ * consumer without it), a row that fails stays open with its errors.
701
+ * `true` when every row committed. Under `editing.draft` it sends nothing
702
+ * to the consumer by itself - that is `saveDrafts`.
703
+ */
704
+ commitAll: () => Promise<boolean>;
705
+ /**
706
+ * Flushes the draft store: every committed edit, added row and deletion
707
+ * mark reaches the consumer, through `onSaveDrafts` in one call when it is
708
+ * set, or row by row through `onCommit` / `onRowAdd` / `onRowDelete`.
709
+ *
710
+ * Rows still open are left alone - they keep their form state and stay
711
+ * open. `true` when everything landed; a rejected save keeps every draft.
712
+ */
713
+ saveDrafts: () => Promise<boolean>;
714
+ /**
715
+ * @deprecated Split into {@link commitAll} and {@link saveDrafts}, which is
716
+ * exactly what this now does. Removed in a later beta.
717
+ */
571
718
  submitAll: () => Promise<boolean>;
572
719
  /** Writes the type's empty value into a cell and commits it - Delete. */
573
720
  clearCell: (rowId: string, columnId: string) => Promise<boolean>;
721
+ /**
722
+ * Writes one cell and commits the row - a typed edit without the typing,
723
+ * for toolbar actions and bulk fills. Under `editing.draft` the row parks
724
+ * in the draft store exactly as a hand-made edit does, so it carries the
725
+ * same change markers and the same per-row revert.
726
+ *
727
+ * The row need not be mounted; a row inside a collapsed group takes the
728
+ * write. Resolves `false` when the cell takes no edit - no such row or
729
+ * column, `editing.columns` excludes it, `meta.edit.enabled` is off, or the
730
+ * row is not editable - and when validation refuses the value, which leaves
731
+ * the row open carrying its errors.
732
+ *
733
+ * `value` is the stored value: no editor runs, so `meta.edit.mapValue`
734
+ * does not either. `meta.edit.validate` does.
735
+ */
736
+ setCellValue: (rowId: string, columnId: string, value: unknown) => Promise<boolean>;
737
+ /**
738
+ * {@link setCellValue} for several cells of one row, in a single commit -
739
+ * one consumer call and one draft entry rather than one per column. Keys
740
+ * are column ids.
741
+ *
742
+ * All or nothing: if any named cell takes no edit, nothing is written and
743
+ * this resolves `false`.
744
+ */
745
+ setRowValues: (rowId: string, values: Record<string, unknown>) => Promise<boolean>;
574
746
  /**
575
747
  * Opens a new entry row (the sticky block under the header) seeded from
576
- * `newRowDefaults`. Returns its temporary id - a form with no backing row
577
- * yet. Committing it calls `onRowAdd` (immediate modes) or joins
578
- * `submitAll`'s `added` (batch).
748
+ * `newRowDefaults`. `values` overrides that seed key by key, so
749
+ * `addRow()` opens a blank row and `addRow({ status: "draft" })` opens one
750
+ * that starts filled in. Returns its temporary id - a form with no backing
751
+ * row yet. Committing it calls `onRowAdd`, or parks it for `saveDrafts`
752
+ * under `editing.draft`.
579
753
  */
580
- addRow: () => string;
754
+ addRow: (values?: Partial<TData>) => string;
581
755
  /**
582
- * Deletes a row: `onRowDelete` straight away under the immediate modes;
583
- * under batch it toggles the id in `deletedRowIds` - the row renders
584
- * struck through until `submitAll` reports it. On an uncommitted entry
585
- * row it just discards the entry.
756
+ * Opens entry rows for a list of records at once - one state write for the
757
+ * batch, where a loop over `addRow` is one per row. Each row is seeded over
758
+ * `newRowDefaults` exactly as `addRow` does.
759
+ *
760
+ * `commit: true` submits each row as it lands, which is what an import
761
+ * wants: rows that validate commit (parked in the draft store under
762
+ * `editing.draft`, added through `onRowAdd` without it - once per row),
763
+ * and rows that fail stay open in the entry block carrying their errors,
764
+ * for the user to fix. The result says which went which way.
765
+ */
766
+ addRows: (rows: ReadonlyArray<Partial<TData>>, options?: TMDataGridAddRowsOptions) => Promise<TMDataGridAddRowsResult>;
767
+ /**
768
+ * Deletes a row: `onRowDelete` straight away, or under `editing.draft` a
769
+ * toggle of the id in `deletedRowIds` - the row renders struck through
770
+ * until `saveDrafts` reports it. On an uncommitted entry row it just
771
+ * discards the entry.
586
772
  */
587
773
  deleteRow: (rowId: string) => void;
588
774
  /** Whether delete chrome makes sense - the lane's trash gate. */
@@ -607,13 +793,15 @@ declare function normalizeFieldValidate(validate: TMDataGridFieldValidate | unde
607
793
  type TMDataGridLabels = {
608
794
  /** Filter operator names, as shown in the operator dropdown and on pills. */
609
795
  operators: Record<TMDataGridFilterOperator, string>;
610
- /** "Manage columns" - the burger button and the header menu item. */
611
- manageColumns: string;
612
796
  /** "Filters" - the funnel button and the filter panel's title. */
613
797
  filters: string;
614
798
  searchPlaceholder: string;
615
799
  searchLabel: string;
616
800
  clearSearch: string;
801
+ /** Tooltip and `aria-label` of `TMDataGrid.Menu`'s burger trigger. */
802
+ menuButton: string;
803
+ /** "Manage columns" - the header menu's submenu. */
804
+ manageColumns: string;
617
805
  columnsSearchPlaceholder: string;
618
806
  columnsNoMatch: (search: string) => string;
619
807
  columnsShowHideAll: string;
@@ -691,18 +879,31 @@ type TMDataGridLabels = {
691
879
  cancelRowEdit: string;
692
880
  /** Save tooltip when field errors block the row, with no row message. */
693
881
  editRowErrors: string;
694
- /** `EditActions`' Save, with the dirty-row count. */
882
+ /** `DraftActions`' Save, with the count of rows in the draft store. */
695
883
  saveAllEdits: (rows: number) => string;
696
- /** `EditActions`' Discard. */
884
+ /** `DraftActions`' Discard. */
697
885
  discardAllEdits: string;
886
+ /**
887
+ * `DraftActions`' note about rows still open - edited but not committed, so
888
+ * not part of the save. Shown only while there are any.
889
+ */
890
+ editRowsStillOpen: (rows: number) => string;
698
891
  /** The entry row's ✓ - commit the add. */
699
892
  confirmNewRow: string;
700
893
  /** The entry row's ✕ - drop the entry. */
701
894
  discardNewRow: string;
702
895
  /** The lane's trash can. */
703
896
  deleteRow: string;
704
- /** The lane's undo on a row marked deleted (batch). */
897
+ /** The lane's undo on a row marked deleted (draft). */
705
898
  restoreRow: string;
899
+ /** The lane's undo on a row with a dirty draft (draft) - drops it. */
900
+ revertRow: string;
901
+ /** The lane's state icon on a confirmed entry row (draft). */
902
+ rowStateNew: string;
903
+ /** The lane's state icon on a row with a dirty draft (draft). */
904
+ rowStateEdited: string;
905
+ /** The lane's state icon on a row marked deleted (draft). */
906
+ rowStateDeleted: string;
706
907
  cellCount: (count: number) => string;
707
908
  copy: string;
708
909
  exportCsv: string;
@@ -985,8 +1186,22 @@ type TMDataGridFeatureFlags = {
985
1186
  grouping: boolean;
986
1187
  /** Whether cells can be edited at all - the `editing` option was set. */
987
1188
  editing: boolean;
988
- /** The commit policy, or `null` while editing is off. */
1189
+ /** What counts as a commit, or `null` while editing is off. */
989
1190
  editMode: TMDataGridEditMode | null;
1191
+ /**
1192
+ * Where a commit goes - `editing.draft`. On, commits park in the grid's
1193
+ * draft store and leave through `edit.saveDrafts()`; off, each one reaches
1194
+ * the consumer as it happens.
1195
+ */
1196
+ editDraft: boolean;
1197
+ /**
1198
+ * Whether a committed entry row stays pinned in the sticky entry block
1199
+ * until the draft store is saved - `editing.newRowsSticky`, which needs
1200
+ * `editing.draft`. Off by default: a committed row joins the body rows
1201
+ * instead, sorted and filtered with them, so entering many rows cannot
1202
+ * fill the viewport with sticky chrome.
1203
+ */
1204
+ editNewRowsSticky: boolean;
990
1205
  /** The generated row-number gutter - `enableRowNumbers`. Off by default. */
991
1206
  rowNumbers: boolean;
992
1207
  /**
@@ -1427,7 +1642,6 @@ type TMDataGridDetailsRenderer<TData extends RowData> = (args: TMDataGridDetails
1427
1642
  */
1428
1643
  type TMDataGridUiState = {
1429
1644
  filterPanelOpen: boolean;
1430
- columnsPanelOpen: boolean;
1431
1645
  /** Column whose filter row should be focused when the panel opens. */
1432
1646
  filterPanelColumnId: string | null;
1433
1647
  /**
@@ -1472,8 +1686,6 @@ type TMDataGridUiState = {
1472
1686
  type TMDataGridUiActions = {
1473
1687
  openFilterPanel: (columnId?: string | null) => void;
1474
1688
  closeFilterPanel: () => void;
1475
- setColumnsPanelOpen: (open: boolean) => void;
1476
- toggleColumnsPanel: () => void;
1477
1689
  startColumnDrag: (columnId: string) => void;
1478
1690
  endColumnDrag: () => void;
1479
1691
  /**
@@ -1517,7 +1729,7 @@ type TMDataGridApi<TData extends RowData> = {
1517
1729
  * out the same TanStack Form the inline editors write through, so a drawer
1518
1730
  * or detail panel can share a row's draft. Inert until `editing` is set.
1519
1731
  */
1520
- edit: TMDataGridEditApi;
1732
+ edit: TMDataGridEditApi<TData>;
1521
1733
  /** Table-level feature switches, re-read from options on every render. */
1522
1734
  features: TMDataGridFeatureFlags;
1523
1735
  /** Every string the chrome renders, `labels` merged over the English defaults. */
@@ -1581,6 +1793,27 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
1581
1793
  * Pathed issues land on the matching columns; pathless ones on the row.
1582
1794
  */
1583
1795
  rowValidators?: TMDataGridRowValidators;
1796
+ /**
1797
+ * Rules that need the other rows - no duplicate keys, no overlapping
1798
+ * ranges, allocations summing to a total. Handed the committing row and
1799
+ * `rows`, the collection as it would stand if the commit landed: every
1800
+ * draft overlaid, entry rows appended, deletion-marked rows removed.
1801
+ *
1802
+ * ```tsx
1803
+ * tableValidators: {
1804
+ * onSubmit: ({ value, rowId, rows }) =>
1805
+ * rows.some((r) => r.rowId !== rowId && r.value.code === value.code)
1806
+ * ? { fields: { code: "Duplicate code" } }
1807
+ * : undefined,
1808
+ * }
1809
+ * ```
1810
+ *
1811
+ * Runs at every commit, after the row's own validators, and again per
1812
+ * parked row during `saveDrafts` - a draft another edit has invalidated
1813
+ * blocks the save. Pathed issues land on the committing row's cells,
1814
+ * pathless ones on the row.
1815
+ */
1816
+ tableValidators?: TMDataGridTableValidators<TData>;
1584
1817
  /** Rows the pencil skips - `false` keeps a row read-only in every mode. */
1585
1818
  isRowEditable?: (row: Row<TMDataGridFeatures, TData>) => boolean;
1586
1819
  /**
@@ -1597,38 +1830,47 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
1597
1830
  /**
1598
1831
  * Seed values for `edit.addRow()` - the entry row's starting point. A
1599
1832
  * function is called per added row (fresh timestamps, empty arrays).
1833
+ * `edit.addRow(values)` overrides this key by key for that one row.
1600
1834
  */
1601
1835
  newRowDefaults?: TData | (() => TData);
1602
1836
  /**
1603
- * Called when an entry row commits: `Enter` or the lane's ✓ under the
1604
- * immediate modes, `submitAll` under batch. Create the record and let it
1605
- * arrive back through `data`; the engine's `tempId` never leaves the grid.
1837
+ * Called when an entry row commits: `Enter` or the lane's ✓, or
1838
+ * `saveDrafts` under `editing.draft`. Create the record and let it arrive
1839
+ * back through `data`; the engine's `tempId` never leaves the grid.
1606
1840
  */
1607
1841
  onRowAdd?: (args: TMDataGridRowAddArgs<TData>) => void | Promise<void>;
1608
1842
  /**
1609
- * Called by `edit.deleteRow` under the immediate modes - confirmation, if
1610
- * any, belongs in here. Under batch, deletions accumulate in
1611
- * `edit.state.deletedRowIds` instead and are reported by `submitAll`.
1612
- * Setting this also puts the trash can in the edit lane.
1843
+ * Called by `edit.deleteRow` - confirmation, if any, belongs in here. Under
1844
+ * `editing.draft` deletions accumulate in `edit.state.deletedRowIds`
1845
+ * instead and are reported by `saveDrafts`. Setting this also puts the
1846
+ * trash can in the edit lane.
1613
1847
  */
1614
1848
  onRowDelete?: (args: TMDataGridRowDeleteArgs<TData>) => void | Promise<void>;
1615
1849
  };
1616
1850
  /**
1617
1851
  * The `editing` option: one object that turns editing on and holds
1618
- * everything about it. `mode` picks what counts as a commit and which
1619
- * controls trigger it; the other members act within that mode.
1852
+ * everything about it. Two axes, and they are independent: `mode` picks what
1853
+ * counts as a commit, `draft` picks where that commit goes.
1854
+ *
1855
+ * | Mode | Commit | Cancel | Controls |
1856
+ * | ---- | ------ | ------ | -------- |
1857
+ * | `"cell"` | Enter, Tab, blur - Sheets | Escape | none |
1858
+ * | `"cellConfirm"` | ✓ or Enter; Tab and blur keep the draft | ✕ or Escape | ✓ / ✕ beside the input |
1859
+ * | `"row"` | Save in the edit lane, or Enter | Cancel, or Escape | generated edit lane |
1860
+ *
1861
+ * | `draft` | Where a commit goes |
1862
+ * | ------- | ------------------- |
1863
+ * | `false` (default) | Out as it happens - `onCommit`, `onRowAdd`, `onRowDelete` |
1864
+ * | `true` | Into the grid's draft store; `edit.saveDrafts()` sends the lot |
1620
1865
  *
1621
- * | Mode | Commit | Cancel |
1622
- * | ---- | ------ | ------ |
1623
- * | `"cell"` | Enter, Tab, blur - Sheets | Escape |
1624
- * | `"cellConfirm"` | ✓ or Enter only; blur keeps the draft | ✕ or Escape |
1625
- * | `"row"` | Save in the edit lane, or Ctrl+Enter | Cancel, or Escape |
1626
- * | `"batch"` | `edit.submitAll()` | `edit.cancelAll()` |
1866
+ * So `{ mode: "row", draft: true }` is "edit a row, the lane's ✓ parks it,
1867
+ * the toolbar's Save sends every parked row at once", and
1868
+ * `{ mode: "cell", draft: true }` is the same store filled cell by cell.
1627
1869
  *
1628
1870
  * Setting `editing` makes `getRowId` required - drafts are keyed by row id,
1629
1871
  * and the index fallback would name a different record after any sort - and
1630
- * `onCommitBatch` exists only under `mode: "batch"`, the one mode whose
1631
- * `submitAll` calls it.
1872
+ * `onSaveDrafts` exists only under `draft: true`, the one configuration with
1873
+ * a draft store to save.
1632
1874
  *
1633
1875
  * The object may be written inline: the callbacks are read through a ref
1634
1876
  * every render, so its identity does not matter.
@@ -1639,19 +1881,68 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
1639
1881
  * built-in editor, and `enabled`, `field`, `editor`, `validate` and `mapValue`
1640
1882
  * override the rest.
1641
1883
  */
1642
- type TMDataGridEditingOptions<TData extends RowData> = TMDataGridEditingCallbacks<TData> & ({
1643
- mode: "batch";
1884
+ type TMDataGridEditingOptions<TData extends RowData> = TMDataGridEditingCallbacks<TData> & {
1885
+ /** What counts as a commit. See the table above. */
1886
+ mode: TMDataGridEditMode;
1887
+ /**
1888
+ * The column ids that take edits, by id. Unset - the default - every
1889
+ * column mapping to a data path is editable, which is what a grid whose
1890
+ * columns are mostly the record itself wants.
1891
+ *
1892
+ * Set it for the other shape: a grid of reference data with one or two
1893
+ * columns the user maintains, where naming those is shorter and harder to
1894
+ * get wrong than switching every other column off one by one.
1895
+ *
1896
+ * This gates before `meta.edit`, never past it: a column left out takes no
1897
+ * edits whatever its own meta says, and a column listed here still answers
1898
+ * to its `meta.edit.enabled`.
1899
+ */
1900
+ columns?: ReadonlyArray<string>;
1901
+ } & ({
1902
+ /**
1903
+ * Commits park in the grid's draft store instead of reaching the
1904
+ * consumer, and leave together through `edit.saveDrafts()`. The
1905
+ * edit lane gains the change markers and the per-row revert, the
1906
+ * trash marks a row for deletion rather than deleting it, and
1907
+ * `TMDataGrid.DraftActions` gets something to save.
1908
+ */
1909
+ draft: true;
1910
+ /**
1911
+ * The bulk save: called once by `edit.saveDrafts()` with the
1912
+ * whole draft store - committed edits, added rows and deletion
1913
+ * marks - so a server can apply it as one transaction. Without it,
1914
+ * `saveDrafts` falls back to the per-row
1915
+ * {@link TMDataGridEditingCallbacks.onCommit} loop.
1916
+ *
1917
+ * Rows still open are not in the payload and stay open. Returning
1918
+ * nothing saves the whole store and throwing saves none of it;
1919
+ * return a {@link TMDataGridSaveDraftsResult} to save part of it.
1920
+ */
1921
+ onSaveDrafts?: (args: TMDataGridSaveDraftsArgs<TData>) => void | TMDataGridSaveDraftsResult | Promise<void | TMDataGridSaveDraftsResult>;
1922
+ /**
1923
+ * @deprecated Renamed to {@link onSaveDrafts} - it fires when the
1924
+ * draft store is saved, not when a row commits into it. Still
1925
+ * honoured; removed in a later beta.
1926
+ */
1927
+ onCommitDrafts?: (args: TMDataGridSaveDraftsArgs<TData>) => void | TMDataGridSaveDraftsResult | Promise<void | TMDataGridSaveDraftsResult>;
1644
1928
  /**
1645
- * Batch mode's save, called once by `edit.submitAll()` with every
1646
- * valid dirty row. Without it, `submitAll` falls back to the per-row
1647
- * {@link TMDataGridEditingCallbacks.onCommit} loop. Rows failing
1648
- * validation stay open either way; a rejection keeps every draft.
1929
+ * Keep committed entry rows pinned in the sticky entry block until
1930
+ * the draft store is saved, out of the body's sort. Off by default:
1931
+ * a committed row joins the body rows instead, sorted and filtered
1932
+ * with them - the block a row is *typed* into is always sticky, but
1933
+ * committed rows scroll, so entering many cannot fill the viewport
1934
+ * with sticky chrome.
1649
1935
  */
1650
- onCommitBatch?: (args: TMDataGridEditCommitBatchArgs<TData>) => void | Promise<void>;
1936
+ newRowsSticky?: boolean;
1651
1937
  } | {
1652
- mode: Exclude<TMDataGridEditMode, "batch">;
1653
- /** Only `"batch"`'s `submitAll` ever calls it - see the other branch. */
1654
- onCommitBatch?: never;
1938
+ /** Every commit reaches the consumer as it happens. The default. */
1939
+ draft?: false;
1940
+ /** Only `draft: true` has a store to save - see the other branch. */
1941
+ onSaveDrafts?: never;
1942
+ /** @deprecated See {@link onSaveDrafts}. */
1943
+ onCommitDrafts?: never;
1944
+ /** Parked entry rows exist only under `draft: true` - see there. */
1945
+ newRowsSticky?: never;
1655
1946
  });
1656
1947
  type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridFeatures, TData>, "features"> & ({
1657
1948
  editing?: undefined;
@@ -1917,6 +2208,130 @@ declare function useTMDataGrid<TData extends RowData>({ persist, labels: labelsO
1917
2208
  */
1918
2209
  declare function openColumnFilter<TData extends RowData>(api: TMDataGridApi<TData>, columnId: string): void;
1919
2210
  //#endregion
2211
+ //#region .types-tmp/components/TMDataGridDraftActions.d.ts
2212
+ /** What the edit chrome is showing. */
2213
+ type TMDataGridDraftActionsState = {
2214
+ /**
2215
+ * Rows in the draft store, which is what Save sends: committed edits,
2216
+ * committed entry rows and deletion marks.
2217
+ */
2218
+ draftCount: number;
2219
+ /**
2220
+ * Rows still open - edited or entered but not committed, so not part of
2221
+ * the save. They stay open across a save.
2222
+ */
2223
+ openCount: number;
2224
+ /**
2225
+ * The ids behind {@link openCount}, in the order the grid opened them - a
2226
+ * sort, a filter or a page never moves this list. An entered row appears as
2227
+ * its `tempId`.
2228
+ *
2229
+ * Narrower than `edit.state.openRowIds`, which is every row holding a form,
2230
+ * the parked ones included. And note the ordering:
2231
+ * {@link TMDataGridDraftActionsActions.scrollToFirstOpenRow} takes "first"
2232
+ * in display order, so it need not be `openRowIds[0]`.
2233
+ */
2234
+ openRowIds: ReadonlyArray<string>;
2235
+ /**
2236
+ * @deprecated Was "everything uncommitted", which Save no longer sends.
2237
+ * Reads as `draftCount + openCount`; use whichever you meant.
2238
+ */
2239
+ pendingCount: number;
2240
+ /** Whether a submit is in flight. */
2241
+ isSubmitting: boolean;
2242
+ };
2243
+ /** What the edit chrome can do. */
2244
+ type TMDataGridDraftActionsActions = {
2245
+ /** Saves the draft store. Open rows are left alone. */
2246
+ save: () => Promise<boolean>;
2247
+ /** Submits every open row, committing the ones that validate. */
2248
+ commitAll: () => Promise<boolean>;
2249
+ /** Drops everything - open form state and the draft store alike. */
2250
+ discard: () => void;
2251
+ /**
2252
+ * `grid.scrollToRow`, so a control in here can take the user to a row
2253
+ * without the grid being threaded down to it.
2254
+ */
2255
+ scrollToRow: (args: TMDataGridScrollToRowArgs) => boolean;
2256
+ /**
2257
+ * Scrolls to the first row still open, taking "first" in display order: the
2258
+ * topmost open row under the current sort, filter and page. That need not
2259
+ * be {@link TMDataGridDraftActionsState.openRowIds}`[0]`, which is the
2260
+ * order the grid opened them in.
2261
+ *
2262
+ * Answers whether an open row could be reached. `false` when nothing is
2263
+ * open, and when every open row is filtered out, on another page or
2264
+ * collapsed inside a group. An open entry row answers `true` without
2265
+ * scrolling - it is sticky under the header, so it is on screen already -
2266
+ * and so does an open row pinned to an edge. The scroll goes through
2267
+ * `scrollToRow`, so before `TMDataGrid.Table` has mounted there is nothing
2268
+ * to scroll and the answer is `false`.
2269
+ */
2270
+ scrollToFirstOpenRow: (align?: TMDataGridScrollAlign) => boolean;
2271
+ };
2272
+ /** The pre-bound pieces of the built-in edit chrome. */
2273
+ type TMDataGridDraftActionsControls = {
2274
+ /** Save, with the draft count, disabled while the draft store is empty. */
2275
+ Save: () => ReactNode;
2276
+ /** Discard, disabled while nothing is pending. */
2277
+ Discard: () => ReactNode;
2278
+ /** The "N rows still being edited" note, or nothing while there are none. */
2279
+ OpenRowsNote: () => ReactNode;
2280
+ };
2281
+ /** What {@link TMDataGridDraftActionsProps.renderActions} is handed. */
2282
+ type TMDataGridDraftActionsSlotArgs = {
2283
+ state: TMDataGridDraftActionsState;
2284
+ actions: TMDataGridDraftActionsActions;
2285
+ Controls: TMDataGridDraftActionsControls;
2286
+ };
2287
+ type TMDataGridDraftActionsProps = {
2288
+ /**
2289
+ * Replaces the built-in Save/Discard pair, and is handed the pieces of it.
2290
+ *
2291
+ * ```tsx
2292
+ * <TMDataGrid.DraftActions
2293
+ * renderActions={({ state, Controls }) => (
2294
+ * <Group>
2295
+ * {state.draftCount > 0 && <Badge>{state.draftCount}</Badge>}
2296
+ * <Controls.OpenRowsNote />
2297
+ * <Controls.Save />
2298
+ * <Controls.Discard />
2299
+ * </Group>
2300
+ * )}
2301
+ * />
2302
+ * ```
2303
+ */
2304
+ renderActions?: (args: TMDataGridDraftActionsSlotArgs) => ReactNode;
2305
+ };
2306
+ /**
2307
+ * The draft store's toolbar chrome: Save with the store's count, Discard, and
2308
+ * a note counting the rows still open. Save sends the store and leaves open
2309
+ * rows alone, so it greys out while nothing is parked however much is being
2310
+ * typed - the note is what makes those rows visible.
2311
+ *
2312
+ * Works under any `editing.mode`. The toolbar is declarative: the grid does
2313
+ * not decide for you, so include this only when the grid runs a draft store -
2314
+ * without `editing.draft` there is nothing to save and Save stays disabled.
2315
+ *
2316
+ * ```tsx
2317
+ * <TMDataGrid.Toolbar>
2318
+ * <TMDataGrid.SummaryCount />
2319
+ * <TMDataGrid.Spacer />
2320
+ * <TMDataGrid.DraftActions />
2321
+ * </TMDataGrid.Toolbar>
2322
+ * ```
2323
+ */
2324
+ declare function TMDataGridDraftActions({ renderActions }?: TMDataGridDraftActionsProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
2325
+ //#endregion
2326
+ //#region .types-tmp/components/TMDataGridFilterPanel.d.ts
2327
+ /**
2328
+ * The MUI-style filter surface: one row per active column filter, each row a
2329
+ * column / operator / value triple. It only ever reads and writes the table's
2330
+ * `columnFilters` state, so a `manualFiltering` grid gets the same panel for
2331
+ * free - the state is forwarded to the server instead of a row model.
2332
+ */
2333
+ declare function TMDataGridFilterPanel(): import("react").JSX.Element | null;
2334
+ //#endregion
1920
2335
  //#region .types-tmp/components/TMDataGridFilterPills.d.ts
1921
2336
  type TMDataGridFilterPillsProps<TData extends RowData> = {
1922
2337
  /** The object returned by `useTMDataGrid`. */
@@ -2520,11 +2935,6 @@ declare function TMDataGridLoadingIndicator(): import("react").JSX.Element | nul
2520
2935
  declare function TMDataGridSummaryCount({ children }: {
2521
2936
  children?: ReactNode;
2522
2937
  }): import("react").JSX.Element;
2523
- /**
2524
- * Burger menu in the grid's top-right corner - opens "Manage columns".
2525
- * Renders nothing when no column can be hidden (`enableHiding: false`).
2526
- */
2527
- declare function TMDataGridColumnsButton(): import("react").JSX.Element | null;
2528
2938
  /**
2529
2939
  * Toggles the filter panel, seeding a filter row on the first filterable column.
2530
2940
  * Renders nothing when no column can be filtered (`enableColumnFilters: false`).
@@ -2572,7 +2982,9 @@ type TMDataGridProps<TData extends RowData> = TMDataGridApi<TData> & {
2572
2982
  * <TMDataGrid.Toolbar>
2573
2983
  * <TMDataGrid.SummaryCount />
2574
2984
  * <TMDataGrid.Spacer />
2575
- * <TMDataGrid.ColumnsButton />
2985
+ * <TMDataGrid.Menu>
2986
+ * <TMDataGrid.Menu.Columns />
2987
+ * </TMDataGrid.Menu>
2576
2988
  * </TMDataGrid.Toolbar>
2577
2989
  * <TMDataGrid.Table />
2578
2990
  * <TMDataGrid.Footer />
@@ -2586,8 +2998,13 @@ declare const TMDataGrid: typeof TMDataGridRoot & {
2586
2998
  SummaryCount: typeof TMDataGridSummaryCount;
2587
2999
  LoadingIndicator: typeof TMDataGridLoadingIndicator;
2588
3000
  Search: typeof TMDataGridSearch;
2589
- EditActions: typeof TMDataGridEditActions;
2590
- ColumnsButton: typeof TMDataGridColumnsButton;
3001
+ DraftActions: typeof TMDataGridDraftActions;
3002
+ Menu: (({ children, icon, label, ...menuProps }: TMDataGridMenuProps) => import("react").JSX.Element) & {
3003
+ Columns: typeof TMDataGridMenuColumns;
3004
+ ColumnToggles: typeof TMDataGridMenuColumnToggles;
3005
+ ShowHideAll: typeof TMDataGridMenuShowHideAll;
3006
+ ResetLayout: typeof TMDataGridMenuResetLayout;
3007
+ };
2591
3008
  FilterButton: typeof TMDataGridFilterButton;
2592
3009
  Table: typeof TMDataGridTable$1;
2593
3010
  Footer: typeof TMDataGridFooter;
@@ -2598,7 +3015,10 @@ declare const TMDataGrid: typeof TMDataGridRoot & {
2598
3015
  * rendered outside `<TMDataGrid>` - a page header, for instance.
2599
3016
  */
2600
3017
  FilterPills: typeof TMDataGridFilterPills;
2601
- /** Rendered by `TMDataGrid.ColumnsButton`; exported for custom layouts. */
3018
+ /**
3019
+ * The column chooser as plain controls, for a Popover, a Drawer or an
3020
+ * inline layout; `TMDataGrid.Menu.Columns` is the same thing as menu items.
3021
+ */
2602
3022
  ColumnsPanel: typeof TMDataGridColumnsPanel;
2603
3023
  };
2604
3024
  //#endregion
@@ -2825,6 +3245,10 @@ type TMDataGridAggregationName = keyof typeof aggregationFns;
2825
3245
  * Filtered rather than paginated rows, so the total covers everything the
2826
3246
  * filters left (all pages), and follows the filters as they change. Reuses
2827
3247
  * TanStack's registered aggregation functions; `fn` defaults to `"sum"`.
3248
+ *
3249
+ * Every data row counts once. Grouping builds its group rows from this model
3250
+ * rather than into it, so a grouped grid totals its records, not its records
3251
+ * plus their subtotals; a tree counts parents and children alike.
2828
3252
  */
2829
3253
  declare function aggregateColumn<TData extends RowData>({ table, columnId, fn }: {
2830
3254
  table: TMDataGridTable<TData>;
@@ -3069,4 +3493,4 @@ declare function getSelectableRowIds<TData extends RowData>(row: Row<TMDataGridF
3069
3493
  */
3070
3494
  declare function resolveRowSelectionClick<TData extends RowData>({ rows, rowId, anchorRowId, modifiers, selection, canReplaceSelection }: ResolveRowSelectionClickArgs<TData>): ResolvedRowSelection;
3071
3495
  //#endregion
3072
- export { type BuildCellMatrixArgs, type ColumnStepArgs, DATA_STATE_SLICES, DEFAULT_CELL_EXPORT_OPTIONS, DEFAULT_TMDATAGRID_SIZE, DETAILS_COLUMN_ID, DgAutocompleteFilter, DgDateRangeFilter, DgRangeSliderFilter, DgTriStateFilter, EDIT_COLUMN_ID, FILTER_OPERATOR_LABELS, GROUP_COLUMN_ID, type MoveColumnArgs, PERSIST_PAYLOAD_VERSION, ROW_NUMBER_COLUMN_ID, type ResolveCellMoveArgs, type ResolveRangeBoundsArgs, type ResolveRowSelectionClickArgs, type ResolvedRowSelection, SELECT_COLUMN_ID, SETTINGS_STATE_SLICES, SIZE_CONTROL_SIZE, SIZE_ROW_HEIGHT, TMDATAGRID_LABELS_EN, TMDATAGRID_LABELS_SV, TMDataGrid, type TMDataGridAggregationName, type TMDataGridApi, TMDataGridBooleanEditor, type TMDataGridCapabilities, type TMDataGridCellCoords, type TMDataGridCellEventArgs, type TMDataGridCellExportOptions, type TMDataGridCellMatrix, type TMDataGridCellNav, type TMDataGridCellPosition, type TMDataGridCellRange, type TMDataGridCellSelectionMode, type TMDataGridColumnCapabilities, type TMDataGridColumnEditOptions, type TMDataGridColumnFilterOptions, type TMDataGridColumnLayout, type TMDataGridColumnMenuItemsArgs, type TMDataGridColumnMenuItemsRenderer, type TMDataGridColumnMeta, type TMDataGridColumnRegion, type TMDataGridColumnType, type TMDataGridContextValue, type TMDataGridDataSlice, TMDataGridDateEditor, type TMDataGridDetailsArgs, type TMDataGridDetailsRenderer, type TMDataGridDropSide, TMDataGridEditActions, type TMDataGridEditActionsActions, type TMDataGridEditActionsControls, type TMDataGridEditActionsProps, type TMDataGridEditActionsSlotArgs, type TMDataGridEditActionsState, type TMDataGridEditApi, type TMDataGridEditChange, type TMDataGridEditCommitArgs, type TMDataGridEditCommitBatchArgs, type TMDataGridEditField, type TMDataGridEditMode, type TMDataGridEditRowProjection, type TMDataGridEditState, type TMDataGridEditValueMap, type TMDataGridEditValueMapArgs, type TMDataGridEditingOptions, type TMDataGridEditorArgs, type TMDataGridEditorComponent, type TMDataGridExpandAllArgs, type TMDataGridExpandTarget, type TMDataGridFeatureFlags, type TMDataGridFeatures, type TMDataGridFieldValidate, type TMDataGridFilterControlArgs, type TMDataGridFilterControlComponent, type TMDataGridFilterOperator, TMDataGridFilterPills, type TMDataGridFilterPillsProps, type TMDataGridFilterValue, TMDataGridFilterValueInput, type TMDataGridFooterProps, type TMDataGridLabels, type TMDataGridLabelsOverride, TMDataGridMultiSelectEditor, TMDataGridNumberEditor, type TMDataGridOption, type TMDataGridOptionsArgs, type TMDataGridOptionsSource, type TMDataGridPaginationActions, type TMDataGridPaginationApi, type TMDataGridPaginationControls, type TMDataGridPaginationSlotArgs, type TMDataGridPaginationState, type TMDataGridPersistKey, type TMDataGridPersistence, type TMDataGridProps, type TMDataGridQuickSearchMode, type TMDataGridRangeBounds, type TMDataGridRowAddArgs, type TMDataGridRowClickModifiers, type TMDataGridRowContextMenuArgs, type TMDataGridRowContextMenuRenderer, type TMDataGridRowData, type TMDataGridRowDeleteArgs, type TMDataGridRowEditForm, type TMDataGridRowStyle, type TMDataGridRowValidators, type TMDataGridScrollAlign, type TMDataGridScrollToRowArgs, TMDataGridSearch, type TMDataGridSearchProps, TMDataGridSelectEditor, type TMDataGridSelectionMode, type TMDataGridSettingsSlice, type TMDataGridSize, type TMDataGridStorageMode, TMDataGridStringEditor, type TMDataGridTable, type TMDataGridTableMeta, type TMDataGridTableProps, type TMDataGridUiActions, type TMDataGridUiState, type TMDataGridUiStore, type UseTMDataGridOptions, aggregateColumn, areAllRowsExpanded, autosizeColumn, boundsCellCount, boundsEdges, buildCellMatrix, buildGridCellMatrix, clearedValueForType, createTMDataGridColumnHelper, downloadTextFile, emptyValueForOperator, exportGridToCsv, formatExportValue, formatFilterLabel, formatGroupValue, fuzzyGlobalFilterFn, getColumnCapabilities, getColumnDefaultOperator, getColumnFilterControl, getColumnLabel, getColumnRegion, getColumnType, getDefaultOperator, getDisplayedRows, getEditFieldName, getGridCapabilities, getGroupDataRows, getOperatorsForType, getSelectableRowIds, getStepTargetColumn, getTMDataGridPaginationApi, isColumnEditableForRow, isColumnReorderable, isControlColumn, isFilterActive, isGeneratedColumn, isPagingActive, isSameCell, isWithinBounds, keepGeneratedColumnsOutermost, measureColumnContentWidth, mergeLabels, moveColumn, moveColumnByStep, normalizeFieldValidate, openColumnFilter, operatorNeedsValue, operatorTakesArrayValue, operatorTakesRangeValue, optionsToComboboxData, readFeatureFlags, resolveCellMove, resolveColumnOptions, resolveExpandAll, resolveRangeBounds, resolveRowSelectionClick, tmDataGridFeatures, toClipboardText, toExcelCsv, useCellControlTabIndex, useTMDataGrid, useTMDataGridContext, writeClipboardText };
3496
+ export { type BuildCellMatrixArgs, type ColumnStepArgs, DATA_STATE_SLICES, DEFAULT_CELL_EXPORT_OPTIONS, DEFAULT_TMDATAGRID_SIZE, DETAILS_COLUMN_ID, DgAutocompleteFilter, DgDateRangeFilter, DgRangeSliderFilter, DgTriStateFilter, EDIT_COLUMN_ID, FILTER_OPERATOR_LABELS, GROUP_COLUMN_ID, type MoveColumnArgs, PERSIST_PAYLOAD_VERSION, ROW_NUMBER_COLUMN_ID, type ResolveCellMoveArgs, type ResolveRangeBoundsArgs, type ResolveRowSelectionClickArgs, type ResolvedRowSelection, SELECT_COLUMN_ID, SETTINGS_STATE_SLICES, SIZE_CONTROL_SIZE, SIZE_ROW_HEIGHT, TMDATAGRID_LABELS_EN, TMDATAGRID_LABELS_SV, TMDataGrid, type TMDataGridAddRowsOptions, type TMDataGridAddRowsResult, type TMDataGridAggregationName, type TMDataGridApi, TMDataGridBooleanEditor, type TMDataGridCapabilities, type TMDataGridCellCoords, type TMDataGridCellEventArgs, type TMDataGridCellExportOptions, type TMDataGridCellMatrix, type TMDataGridCellNav, type TMDataGridCellPosition, type TMDataGridCellRange, type TMDataGridCellSelectionMode, type TMDataGridColumnCapabilities, type TMDataGridColumnEditOptions, type TMDataGridColumnFilterOptions, type TMDataGridColumnLayout, type TMDataGridColumnMenuItemsArgs, type TMDataGridColumnMenuItemsRenderer, type TMDataGridColumnMeta, type TMDataGridColumnRegion, type TMDataGridColumnType, type TMDataGridContextValue, type TMDataGridDataSlice, TMDataGridDateEditor, type TMDataGridDetailsArgs, type TMDataGridDetailsRenderer, TMDataGridDraftActions, type TMDataGridDraftActionsActions, type TMDataGridDraftActionsControls, type TMDataGridDraftActionsProps, type TMDataGridDraftActionsSlotArgs, type TMDataGridDraftActionsState, type TMDataGridDropSide, type TMDataGridEditApi, type TMDataGridEditChange, type TMDataGridEditCommitArgs, type TMDataGridEditCommitDraftsArgs, type TMDataGridEditField, type TMDataGridEditMode, type TMDataGridEditRowProjection, type TMDataGridEditRowSnapshot, type TMDataGridEditState, type TMDataGridEditValueMap, type TMDataGridEditValueMapArgs, type TMDataGridEditingOptions, type TMDataGridEditorArgs, type TMDataGridEditorComponent, type TMDataGridExpandAllArgs, type TMDataGridExpandTarget, type TMDataGridFeatureFlags, type TMDataGridFeatures, type TMDataGridFieldValidate, type TMDataGridFilterControlArgs, type TMDataGridFilterControlComponent, type TMDataGridFilterOperator, TMDataGridFilterPills, type TMDataGridFilterPillsProps, type TMDataGridFilterValue, TMDataGridFilterValueInput, type TMDataGridFooterProps, type TMDataGridLabels, type TMDataGridLabelsOverride, type TMDataGridMenuColumnsProps, type TMDataGridMenuProps, TMDataGridMultiSelectEditor, TMDataGridNumberEditor, type TMDataGridOption, type TMDataGridOptionsArgs, type TMDataGridOptionsSource, type TMDataGridPaginationActions, type TMDataGridPaginationApi, type TMDataGridPaginationControls, type TMDataGridPaginationSlotArgs, type TMDataGridPaginationState, type TMDataGridPersistKey, type TMDataGridPersistence, type TMDataGridProps, type TMDataGridQuickSearchMode, type TMDataGridRangeBounds, type TMDataGridRowAddArgs, type TMDataGridRowClickModifiers, type TMDataGridRowContextMenuArgs, type TMDataGridRowContextMenuRenderer, type TMDataGridRowData, type TMDataGridRowDeleteArgs, type TMDataGridRowEditForm, type TMDataGridRowStyle, type TMDataGridRowValidators, type TMDataGridSaveDraftsArgs, type TMDataGridSaveDraftsResult, type TMDataGridSaveOutcomes, type TMDataGridScrollAlign, type TMDataGridScrollToRowArgs, TMDataGridSearch, type TMDataGridSearchProps, TMDataGridSelectEditor, type TMDataGridSelectionMode, type TMDataGridSettingsSlice, type TMDataGridSize, type TMDataGridStorageMode, TMDataGridStringEditor, type TMDataGridTable, type TMDataGridTableMeta, type TMDataGridTableProps, type TMDataGridTableValidateArgs, type TMDataGridTableValidators, type TMDataGridUiActions, type TMDataGridUiState, type TMDataGridUiStore, type UseTMDataGridOptions, aggregateColumn, areAllRowsExpanded, autosizeColumn, boundsCellCount, boundsEdges, buildCellMatrix, buildGridCellMatrix, clearedValueForType, createTMDataGridColumnHelper, downloadTextFile, emptyValueForOperator, exportGridToCsv, formatExportValue, formatFilterLabel, formatGroupValue, fuzzyGlobalFilterFn, getColumnCapabilities, getColumnDefaultOperator, getColumnFilterControl, getColumnLabel, getColumnRegion, getColumnType, getDefaultOperator, getDisplayedRows, getEditFieldName, getGridCapabilities, getGroupDataRows, getOperatorsForType, getSelectableRowIds, getStepTargetColumn, getTMDataGridPaginationApi, isColumnEditableForRow, isColumnReorderable, isControlColumn, isFilterActive, isGeneratedColumn, isPagingActive, isSameCell, isWithinBounds, keepGeneratedColumnsOutermost, measureColumnContentWidth, mergeLabels, moveColumn, moveColumnByStep, normalizeFieldValidate, openColumnFilter, operatorNeedsValue, operatorTakesArrayValue, operatorTakesRangeValue, optionsToComboboxData, readFeatureFlags, resolveCellMove, resolveColumnOptions, resolveExpandAll, resolveRangeBounds, resolveRowSelectionClick, tmDataGridFeatures, toClipboardText, toExcelCsv, useTMDataGrid, useTMDataGridContext, writeClipboardText };