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

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 (44) hide show
  1. package/README.md +32 -34
  2. package/dist/index.d.ts +110 -85
  3. package/dist/index.js +1539 -1500
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/package.json +1 -1
  7. package/skills/appearance/SKILL.md +37 -34
  8. package/skills/cell-selection/SKILL.md +19 -19
  9. package/skills/columns/SKILL.md +9 -9
  10. package/skills/data/SKILL.md +53 -53
  11. package/skills/editing/SKILL.md +140 -154
  12. package/skills/editing/references/editing-api.md +22 -20
  13. package/skills/editing/references/editors-and-validation.md +22 -18
  14. package/skills/filtering/SKILL.md +51 -50
  15. package/skills/getting-started/SKILL.md +10 -10
  16. package/skills/grouping/SKILL.md +41 -43
  17. package/skills/options/SKILL.md +4 -4
  18. package/skills/rows/SKILL.md +59 -59
  19. package/skills/rows/references/rows-api.md +6 -6
  20. package/skills/server-side/SKILL.md +1 -1
  21. package/skills/testing/SKILL.md +9 -9
  22. package/src/tmdatagrid/components/TMDataGrid.module.css +6 -1
  23. package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +29 -18
  24. package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +5 -8
  25. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +1 -1
  26. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +5 -1
  27. package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +11 -6
  28. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +9 -5
  29. package/src/tmdatagrid/components/TMDataGridTable.tsx +57 -36
  30. package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +1 -1
  31. package/src/tmdatagrid/core/autosize.ts +30 -6
  32. package/src/tmdatagrid/core/capabilities.ts +5 -5
  33. package/src/tmdatagrid/core/cellExport.ts +6 -7
  34. package/src/tmdatagrid/core/cellNavigation.ts +2 -2
  35. package/src/tmdatagrid/core/cellRange.ts +6 -6
  36. package/src/tmdatagrid/core/columnOrdering.ts +30 -1
  37. package/src/tmdatagrid/core/columnUtils.ts +14 -0
  38. package/src/tmdatagrid/core/editEngine.ts +5 -5
  39. package/src/tmdatagrid/core/filterOperators.ts +6 -6
  40. package/src/tmdatagrid/core/matchHighlight.ts +3 -3
  41. package/src/tmdatagrid/core/persistence.ts +3 -3
  42. package/src/tmdatagrid/core/rowSelection.ts +3 -3
  43. package/src/tmdatagrid/index.ts +2 -0
  44. package/src/tmdatagrid/useTMDataGrid.tsx +113 -90
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # TMDataGrid
2
2
 
3
- A data grid for React built on [TanStack Table v9](https://tanstack.com/table) and
4
- [Mantine](https://mantine.dev). Rows are always virtualized, columns are resizable,
5
- reorderable, sortable, filterable, hideable and pinnable, and every piece of grid
6
- chrome is a component you opt into.
3
+ A data grid for React built on [TanStack Table v9](https://tanstack.com/table)
4
+ and [Mantine](https://mantine.dev). Rows are always virtualized, columns are
5
+ resizable, reorderable, sortable, filterable, hideable and pinnable, and every
6
+ part of the grid interface is a component you render yourself.
7
7
 
8
8
  ## Installation
9
9
 
@@ -79,18 +79,16 @@ export function Employees({ data }: { data: Employee[] }) {
79
79
  ```
80
80
 
81
81
  Only the parts you render exist, and only the features you enable have state.
82
- Pagination is opt-in via `enablePagination` (implied by `manualPagination`) -
83
- by default every row renders, virtualized. A column that defines no filter
84
- shows no filter control.
82
+ Pagination is opt in through `enablePagination` (implied by `manualPagination`);
83
+ by default every row renders, virtualized. A column that defines no filter shows
84
+ no filter control.
85
85
 
86
86
  ## Documentation
87
87
 
88
- The documentation is written as markdown under [`src/docs/`](src/docs) and served by the
89
- demo site:
90
-
91
- One page per touchpoint: the prose, the demos that show it, and the reference
92
- table for everything that page owns. [`docsPages.ts`](src/docs/docsPages.ts) is
93
- the registry and the sidebar order.
88
+ The documentation is markdown under [`src/docs/`](src/docs), served by the demo
89
+ site. There is one page per topic, each holding the prose, its demos and a
90
+ reference table. [`docsPages.ts`](src/docs/docsPages.ts) is the registry and the
91
+ sidebar order.
94
92
 
95
93
  | Section | Pages |
96
94
  | -------------------- | ---------------------------------------------------------------- |
@@ -109,10 +107,10 @@ is the demo site that documents it.
109
107
 
110
108
  | Path | Contents |
111
109
  | ------------------- | ------------------------------------------------------------ |
112
- | `index.ts` | The public API - the only entry point the package exposes |
110
+ | `index.ts` | The public API, and the only entry point the package exposes |
113
111
  | `useTMDataGrid.tsx` | The hook that builds the table, and the types it is built on |
114
112
  | `core/` | Headless logic: filtering, ordering, persistence, capabilities |
115
- | `components/` | The React chrome and its co-located CSS modules |
113
+ | `components/` | The React components and their co-located CSS modules |
116
114
 
117
115
  ### Examples
118
116
 
@@ -122,14 +120,14 @@ The demo site's examples live in [`src/examples/`](src/examples):
122
120
  | ----------------- | -------------------------------------------------------------- |
123
121
  | `demoRegistry.ts` | Pairs each demo module with its own source through `import.meta.glob` |
124
122
  | `demos/` | One file per demo: one idea, no headings, no explanation |
125
- | `data/` | Shared datasets, and the column set for demos about other things |
126
- | `playground/` | The kitchen sink, every feature at once behind switches |
123
+ | `data/` | Shared datasets, and the column set used by unrelated demos |
124
+ | `playground/` | Every feature at once, behind switches |
127
125
 
128
- Adding a demo is adding a file under `demos/` and naming it from a ` ```demo `
129
- fence on the docs page that explains it. The registry pairs each module with
130
- its own source, so the code on screen cannot drift from the code running.
131
- [`demos.test.tsx`](src/examples/demos.test.tsx) mounts every registered demo,
132
- so a demo that stops working fails the suite whether or not it still compiles.
126
+ To add a demo, add a file under `demos/` and name it from a ` ```demo ` fence on
127
+ the docs page that explains it. The registry pairs each module with its own
128
+ source, so the code on screen cannot drift from the code running.
129
+ [`demos.test.tsx`](src/examples/demos.test.tsx) mounts every registered demo, so
130
+ a demo that stops working fails the suite whether or not it still compiles.
133
131
 
134
132
  ```sh
135
133
  npm install
@@ -141,8 +139,8 @@ npm run test:watch
141
139
 
142
140
  ## Testing
143
141
 
144
- For testing an application that *uses* the grid - the test ids, roles and ARIA
145
- attributes it publishes, and how to drive it from Playwright - see
142
+ For testing an application that *uses* the grid, including the test ids, roles
143
+ and ARIA attributes it publishes and how to drive it from Playwright, see
146
144
  [Testing](src/docs/testing.md). What follows is about this repo's own suite.
147
145
 
148
146
  Vitest with React Testing Library, in jsdom. Tests sit next to the code they
@@ -150,11 +148,11 @@ cover as `*.test.ts(x)` and are excluded from both the package and the
150
148
  declaration build; shared fixtures live in [`src/test/`](src/test) so they stay
151
149
  out of `src/tmdatagrid/` entirely.
152
150
 
153
- Two things worth knowing before adding to them:
151
+ Two things to know before adding to them:
154
152
 
155
- - `vitest.setup.ts` installs what jsdom does not provide - an in-memory
156
- `Storage`, `matchMedia`, `ResizeObserver`, and element sizes. The last one
157
- matters: without a measurable box, the virtualizer renders no rows at all.
153
+ - `vitest.setup.ts` installs what jsdom does not provide: an in-memory
154
+ `Storage`, `matchMedia`, `ResizeObserver`, and element sizes. Element sizes
155
+ matter, because without a measurable box the virtualizer renders no rows.
158
156
  - The Mantine provider in the harness runs with `env="test"`, which disables
159
157
  transitions. Without it a popover never finishes mounting and its panel is
160
158
  never found.
@@ -183,8 +181,8 @@ works everywhere without putting `.js` extensions in the sources.
183
181
  ## Publishing
184
182
 
185
183
  Releases are managed by [Changesets](https://github.com/changesets/changesets).
186
- Nothing publishes from an ordinary push - a release happens only when the
187
- version PR is merged.
184
+ Nothing publishes from an ordinary push. A release happens only when the version
185
+ PR is merged.
188
186
 
189
187
  Describe your change in the same PR that makes it:
190
188
 
@@ -196,9 +194,9 @@ That writes a markdown file under `.changeset/`. Commit it alongside the code.
196
194
 
197
195
  Once on `main`, [`release.yml`](.github/workflows/release.yml) opens a
198
196
  **chore: version packages** PR that collects every pending changeset, bumps
199
- `package.json`, writes `CHANGELOG.md` and syncs the skills. The PR is the
200
- release proposal: review the version it picked and the changelog it wrote, then
201
- merge it to publish to npm with provenance.
197
+ `package.json`, writes `CHANGELOG.md` and syncs the skills. Review the version it
198
+ picked and the changelog it wrote, then merge it to publish to npm with
199
+ provenance.
202
200
 
203
201
  The package build runs from `prepublishOnly` rather than as a workflow step, so
204
202
  `npm publish` cannot ship a stale `dist` whether it runs in CI or by hand.
@@ -212,7 +210,7 @@ The package build runs from `prepublishOnly` rather than as a workflow step, so
212
210
  Intent reports a skill as stale when its `library_version` trails the package
213
211
  version, so without that step every release would leave every skill stale.
214
212
  Because it runs inside the version command, the bump and the skill sync land in
215
- the same PR and are reviewed together.
213
+ the same PR.
216
214
 
217
215
  To check what a release would contain without publishing anything:
218
216
 
package/dist/index.d.ts CHANGED
@@ -61,7 +61,7 @@ type TMDataGridEditActionsProps = {
61
61
  /**
62
62
  * Batch mode's toolbar chrome: Save with the dirty-row count, and Discard.
63
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 `editMode` - a
64
+ * Save spins while a submit is in flight. Works under any `editing.mode` - a
65
65
  * cellConfirm grid accumulating drafts can offer the same pair - and renders
66
66
  * nothing while editing is off.
67
67
  *
@@ -204,9 +204,9 @@ declare function optionsToComboboxData(options: ReadonlyArray<TMDataGridOption>)
204
204
  * The value shape stored in `columnFilters` for every TMDataGrid column.
205
205
  *
206
206
  * TanStack resolves `filterFn` statically per column, so the operator travels
207
- * inside the filter *value* instead. That keeps the whole filter model plain,
208
- * serialisable JSON - which is what makes it portable to a server-side
209
- * `manualFiltering` table (just forward `columnFilters` to the API).
207
+ * inside the filter *value* instead. That keeps the filter model plain,
208
+ * serialisable JSON, so a server-side `manualFiltering` table can forward
209
+ * `columnFilters` to the API unchanged.
210
210
  *
211
211
  * `value` is a string array under `isAnyOf` / `isNoneOf` (the set the cell is
212
212
  * tested against), a `[min, max]` pair under `between` (an empty string means
@@ -505,11 +505,11 @@ type TMDataGridEditCommitBatchArgs<TData extends RowData> = {
505
505
  * The data path a column edits, or `null` for a column that has none.
506
506
  *
507
507
  * `accessorKey` is the true path and Form addresses fields by dot-path, so
508
- * nested rows work for free: `accessorKey: "address.city"` edits
509
- * `values.address.city`. A column built on `accessorFn` has no path and is
510
- * not editable unless `meta.edit.field` names one. TanStack's default column
511
- * id turns dots into underscores - which is why this starts from
512
- * `accessorKey`, never from `id`.
508
+ * nested rows need no extra handling: `accessorKey: "address.city"` edits
509
+ * `values.address.city`. A column built on `accessorFn` has no path and is not
510
+ * editable unless `meta.edit.field` names one. TanStack's default column id
511
+ * turns dots into underscores, which is why this starts from `accessorKey` and
512
+ * never from `id`.
513
513
  */
514
514
  declare function getEditFieldName(column: {
515
515
  columnDef: {
@@ -819,11 +819,11 @@ type GridState = TableState<TMDataGridFeatures>;
819
819
  /**
820
820
  * Persistence deliberately does not use Mantine's `useLocalStorage`.
821
821
  *
822
- * That hook owns a piece of state and returns `[value, setValue]`. Here the
823
- * table already owns the state and storage only mirrors it, so routing writes
822
+ * That hook holds a piece of state and returns `[value, setValue]`. Here the
823
+ * table already holds the state and storage only mirrors it, so routing writes
824
824
  * through the hook would keep a second copy and trigger a React state update on
825
825
  * every change, including every pointer move during a column resize. Its
826
- * defaults also work against this use: `getInitialValueInEffect: true` delivers
826
+ * defaults also conflict with this use: `getInitialValueInEffect: true` delivers
827
827
  * the stored value after mount, while `initialState` is only read on the first
828
828
  * render, and `sync: true` would let two open tabs overwrite each other's
829
829
  * column layout.
@@ -983,7 +983,7 @@ type TMDataGridFeatureFlags = {
983
983
  * its own grouping can still say `enableGrouping: true` to override.
984
984
  */
985
985
  grouping: boolean;
986
- /** Whether cells can be edited at all - `editMode` was set. */
986
+ /** Whether cells can be edited at all - the `editing` option was set. */
987
987
  editing: boolean;
988
988
  /** The commit policy, or `null` while editing is off. */
989
989
  editMode: TMDataGridEditMode | null;
@@ -1003,7 +1003,7 @@ type TMDataGridFeatureFlags = {
1003
1003
  */
1004
1004
  matchHighlighting: boolean;
1005
1005
  };
1006
- declare function readFeatureFlags<TData extends RowData>(options: Pick<UseTMDataGridOptions<TData>, "enableSorting" | "enableColumnFilters" | "enableGlobalFilter" | "enableHiding" | "enableColumnPinning" | "enableColumnResizing" | "enableColumnOrdering" | "enableRowSelection" | "enableMultiRowSelection" | "selectionMode" | "showSelectedBackground" | "cellSelection" | "enablePagination" | "manualPagination" | "enableGrouping" | "editMode" | "enableRowNumbers" | "enableRowPinning" | "enableMatchHighlighting">): TMDataGridFeatureFlags;
1006
+ declare function readFeatureFlags<TData extends RowData>(options: Pick<UseTMDataGridOptions<TData>, "enableSorting" | "enableColumnFilters" | "enableGlobalFilter" | "enableHiding" | "enableColumnPinning" | "enableColumnResizing" | "enableColumnOrdering" | "enableRowSelection" | "enableMultiRowSelection" | "selectionMode" | "showSelectedBackground" | "cellSelection" | "enablePagination" | "manualPagination" | "enableGrouping" | "editing" | "enableRowNumbers" | "enableRowPinning" | "enableMatchHighlighting">): TMDataGridFeatureFlags;
1007
1007
  /**
1008
1008
  * What one column's header may offer.
1009
1009
  *
@@ -1049,8 +1049,8 @@ declare function getGridCapabilities(table: TMDataGridTable<TMDataGridRowData>,
1049
1049
  * Ids, because every other thing the grid does moves cells around: sorting
1050
1050
  * reorders rows, filtering removes them, dragging a header reorders columns. A
1051
1051
  * coordinate pair would silently come to mean a different cell after any of
1052
- * them, while a pair of ids either still resolves or does not resolve at all -
1053
- * and "does not resolve" is a state the grid can handle honestly.
1052
+ * them, while a pair of ids either still resolves or does not resolve at all,
1053
+ * and the grid handles "does not resolve" explicitly.
1054
1054
  *
1055
1055
  * Indices are what navigation is actually computed in, so they are resolved
1056
1056
  * from the ids on each keystroke and turned straight back. See resolveCellMove.
@@ -1129,11 +1129,11 @@ type ResolveRangeBoundsArgs = {
1129
1129
  * Turns a range into the rectangle to paint and copy, or `null` when either
1130
1130
  * corner no longer exists.
1131
1131
  *
1132
- * A corner goes missing whenever a filter drops its row or a column is hidden,
1133
- * and the honest answer then is that there is no rectangle - better than
1134
- * guessing at a replacement corner and quietly copying cells the user never
1135
- * selected. The range itself is left alone: clearing it here would throw away
1136
- * a selection that comes straight back when the filter is lifted.
1132
+ * A corner goes missing whenever a filter drops its row or a column is hidden.
1133
+ * There is then no rectangle, rather than a guessed replacement corner that
1134
+ * would copy cells the user never selected. The range itself is left alone:
1135
+ * clearing it here would discard a selection that returns as soon as the filter
1136
+ * is cleared.
1137
1137
  */
1138
1138
  declare function resolveRangeBounds({ range, rowIndexOf, columnIndexOf }: ResolveRangeBoundsArgs): TMDataGridRangeBounds | null;
1139
1139
  /** Whether a cell is inside the rectangle. */
@@ -1141,7 +1141,7 @@ declare function isWithinBounds(bounds: TMDataGridRangeBounds | null, rowIndex:
1141
1141
  /** How many cells the rectangle covers. `0` for no range at all. */
1142
1142
  declare function boundsCellCount(bounds: TMDataGridRangeBounds | null): number;
1143
1143
  /**
1144
- * Which edges of the rectangle a cell sits on, for the outline.
1144
+ * Which edges of the rectangle a cell lies on, for the outline.
1145
1145
  *
1146
1146
  * The border is drawn per cell rather than as one box over the top, because the
1147
1147
  * body is a scrolling CSS grid with sticky columns in it: an overlay would have
@@ -1157,14 +1157,14 @@ declare function boundsEdges(bounds: TMDataGridRangeBounds | null, rowIndex: num
1157
1157
  //#endregion
1158
1158
  //#region .types-tmp/useTMDataGrid.d.ts
1159
1159
  /**
1160
- * Per-column configuration the TMDataGrid chrome reads.
1160
+ * Per-column configuration the grid's own components read.
1161
1161
  *
1162
- * A stage that owns behaviour gets a namespace - `filter` and `edit`, each
1162
+ * The filter and edit stages each get a namespace, `filter` and `edit`,
1163
1163
  * mirroring the feature's runtime API. What the column *is* stays flat:
1164
1164
  * `label`, `type`, `options`, `align`, `flex`, `autoSize`, `enableOrdering`.
1165
- * `type` and `options` in particular are shared ground - one declaration of
1166
- * each feeds the filter panel and the cell editor alike, which is why they sit
1167
- * outside both namespaces.
1165
+ * `type` and `options` are read by both stages, so one declaration of each
1166
+ * feeds the filter panel and the cell editor, which is why they sit outside
1167
+ * both namespaces.
1168
1168
  */
1169
1169
  type TMDataGridColumnMeta = {
1170
1170
  /** Name shown in menus and the column manager. Falls back to a string header. */
@@ -1515,7 +1515,7 @@ type TMDataGridApi<TData extends RowData> = {
1515
1515
  * The edit engine - open forms, dirty/error projections, and the verbs
1516
1516
  * (`begin`, `commit`, `cancel`, `submitAll`). `edit.getForm(rowId)` hands
1517
1517
  * out the same TanStack Form the inline editors write through, so a drawer
1518
- * or detail panel can share a row's draft. Inert until `editMode` is set.
1518
+ * or detail panel can share a row's draft. Inert until `editing` is set.
1519
1519
  */
1520
1520
  edit: TMDataGridEditApi;
1521
1521
  /** Table-level feature switches, re-read from options on every render. */
@@ -1558,19 +1558,13 @@ type TMDataGridApi<TData extends RowData> = {
1558
1558
  */
1559
1559
  scrollToRow: (args: TMDataGridScrollToRowArgs) => boolean;
1560
1560
  /**
1561
- * @internal Wiring for `TMDataGrid.Table`, which owns the virtualizer and
1562
- * fills this in. Not part of the supported surface.
1561
+ * @internal Wiring for `TMDataGrid.Table`, which holds the virtualizer and
1562
+ * fills this in. Not part of the public API.
1563
1563
  */
1564
1564
  scrollerRef: MutableRefObject<TMDataGridScroller>;
1565
1565
  };
1566
- /** The editing callbacks every mode shares. See {@link TMDataGridEditingOptions}. */
1566
+ /** The editing members every mode shares. See {@link TMDataGridEditingOptions}. */
1567
1567
  type TMDataGridEditingCallbacks<TData extends RowData> = {
1568
- /**
1569
- * `getRowId` stops being optional once editing is on: the forms are keyed
1570
- * by row id and live outside the DOM, and the index fallback points at a
1571
- * different record after any sort.
1572
- */
1573
- getRowId: NonNullable<TableOptions<TMDataGridFeatures, TData>["getRowId"]>;
1574
1568
  /**
1575
1569
  * Form-level validators for the whole editing row - where cross-field
1576
1570
  * rules live. TanStack Form's own vocabulary, Standard Schema included:
@@ -1596,10 +1590,10 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
1596
1590
  * draft visible with a busy marker - and a rejection keeps the form open
1597
1591
  * with the error on the row.
1598
1592
  *
1599
- * `changes` is the per-field diff (one entry in cell mode) for consumers
1600
- * who PATCH; `value` is the whole edited row for those who save records.
1593
+ * `changes` is the per-field diff (one entry in cell mode), for a PATCH.
1594
+ * `value` is the entire edited row, for saving a record.
1601
1595
  */
1602
- onEditCommit?: (args: TMDataGridEditCommitArgs<TData>) => void | Promise<void>;
1596
+ onCommit?: (args: TMDataGridEditCommitArgs<TData>) => void | Promise<void>;
1603
1597
  /**
1604
1598
  * Seed values for `edit.addRow()` - the entry row's starting point. A
1605
1599
  * function is called per added row (fresh timestamps, empty arrays).
@@ -1620,14 +1614,9 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
1620
1614
  onRowDelete?: (args: TMDataGridRowDeleteArgs<TData>) => void | Promise<void>;
1621
1615
  };
1622
1616
  /**
1623
- * The editing options travel together, and the type states it: without
1624
- * `editMode` none of them has anything to act on, so passing one is a
1625
- * compile error rather than a dead option; with it, `getRowId` becomes
1626
- * required; and `onEditCommitBatch` exists only under `"batch"` - the one
1627
- * mode whose `submitAll` calls it.
1628
- *
1629
- * `editMode` itself turns cell editing on and picks how commits happen. Off
1630
- * by default.
1617
+ * 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.
1631
1620
  *
1632
1621
  * | Mode | Commit | Cancel |
1633
1622
  * | ---- | ------ | ------ |
@@ -1636,36 +1625,46 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
1636
1625
  * | `"row"` | Save in the edit lane, or Ctrl+Enter | Cancel, or Escape |
1637
1626
  * | `"batch"` | `edit.submitAll()` | `edit.cancelAll()` |
1638
1627
  *
1628
+ * Setting `editing` makes `getRowId` required - drafts are keyed by row id,
1629
+ * 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.
1632
+ *
1633
+ * The object may be written inline: the callbacks are read through a ref
1634
+ * every render, so its identity does not matter.
1635
+ *
1639
1636
  * One TanStack Form per editing row; drafts survive scrolling because the
1640
1637
  * forms live outside the DOM, keyed by row id. Which columns edit, and with
1641
1638
  * what, is declared per column under `meta.edit`: `meta.type` picks the
1642
1639
  * built-in editor, and `enabled`, `field`, `editor`, `validate` and `mapValue`
1643
1640
  * override the rest.
1644
1641
  */
1645
- type TMDataGridEditingOptions<TData extends RowData> = (TMDataGridEditingCallbacks<TData> & {
1646
- editMode: "batch";
1642
+ type TMDataGridEditingOptions<TData extends RowData> = TMDataGridEditingCallbacks<TData> & ({
1643
+ mode: "batch";
1647
1644
  /**
1648
1645
  * Batch mode's save, called once by `edit.submitAll()` with every
1649
1646
  * valid dirty row. Without it, `submitAll` falls back to the per-row
1650
- * {@link TMDataGridEditingCallbacks.onEditCommit} loop. Rows failing
1647
+ * {@link TMDataGridEditingCallbacks.onCommit} loop. Rows failing
1651
1648
  * validation stay open either way; a rejection keeps every draft.
1652
1649
  */
1653
- onEditCommitBatch?: (args: TMDataGridEditCommitBatchArgs<TData>) => void | Promise<void>;
1654
- }) | (TMDataGridEditingCallbacks<TData> & {
1655
- editMode: Exclude<TMDataGridEditMode, "batch">;
1650
+ onCommitBatch?: (args: TMDataGridEditCommitBatchArgs<TData>) => void | Promise<void>;
1651
+ } | {
1652
+ mode: Exclude<TMDataGridEditMode, "batch">;
1656
1653
  /** Only `"batch"`'s `submitAll` ever calls it - see the other branch. */
1657
- onEditCommitBatch?: never;
1658
- }) | {
1659
- editMode?: never;
1660
- rowValidators?: never;
1661
- isRowEditable?: never;
1662
- onEditCommit?: never;
1663
- onEditCommitBatch?: never;
1664
- newRowDefaults?: never;
1665
- onRowAdd?: never;
1666
- onRowDelete?: never;
1667
- };
1668
- type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridFeatures, TData>, "features"> & TMDataGridEditingOptions<TData> & {
1654
+ onCommitBatch?: never;
1655
+ });
1656
+ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridFeatures, TData>, "features"> & ({
1657
+ editing?: undefined;
1658
+ } | {
1659
+ /** Turns editing on. See {@link TMDataGridEditingOptions}. */
1660
+ editing: TMDataGridEditingOptions<TData>;
1661
+ /**
1662
+ * Required once `editing` is set: the forms are keyed by row id and
1663
+ * live outside the DOM, and the index fallback points at a different
1664
+ * record after any sort.
1665
+ */
1666
+ getRowId: NonNullable<TableOptions<TMDataGridFeatures, TData>["getRowId"]>;
1667
+ }) & {
1669
1668
  /**
1670
1669
  * Restore and persist table state across mounts. Two keys, because the two
1671
1670
  * kinds of state have different lifetimes - see {@link TMDataGridPersistence}.
@@ -1885,9 +1884,9 @@ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridF
1885
1884
  * Defaults to 160.
1886
1885
  *
1887
1886
  * An estimate, not a height: every mounted row is measured, so the real one
1888
- * takes over as soon as the panel is on screen. It keeps the scrollbar honest
1889
- * for panels that open off screen (restored `expanded` state, say), and being
1890
- * roughly right is enough.
1887
+ * takes over as soon as the panel is on screen. It keeps the scrollbar
1888
+ * accurate for panels that open off screen, such as restored `expanded`
1889
+ * state. An approximate value is enough.
1891
1890
  */
1892
1891
  renderDetailsEstHeight?: number;
1893
1892
  /**
@@ -1911,7 +1910,7 @@ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridF
1911
1910
  * flag on, so `<TMDataGrid.Footer />` renders its pager without further
1912
1911
  * options.
1913
1912
  */
1914
- declare function useTMDataGrid<TData extends RowData>({ persist, labels: labelsOverride, enableColumnOrdering, enablePagination, enableRowNumbers, selectionMode, showSelectedBackground, defaultHighlightedRowId, onHighlightedRowChange, cellSelection, onFocusedCellChange, editMode, rowValidators, isRowEditable, onEditCommit, onEditCommitBatch, newRowDefaults, onRowAdd, onRowDelete, renderDetails, renderDetailsEstHeight, overscan, ...options }: UseTMDataGridOptions<TData>): TMDataGridApi<TData>;
1913
+ declare function useTMDataGrid<TData extends RowData>({ persist, labels: labelsOverride, enableColumnOrdering, enablePagination, enableRowNumbers, selectionMode, showSelectedBackground, defaultHighlightedRowId, onHighlightedRowChange, cellSelection, onFocusedCellChange, editing, renderDetails, renderDetailsEstHeight, overscan, ...options }: UseTMDataGridOptions<TData>): TMDataGridApi<TData>;
1915
1914
  /**
1916
1915
  * Opens the filter panel for a column, seeding an empty filter row when the
1917
1916
  * column has none yet - mirrors "Filter" in the column header menu.
@@ -2213,9 +2212,9 @@ declare function toClipboardText(matrix: TMDataGridCellMatrix): string;
2213
2212
  * | UTF-8 BOM | without it Excel reads the file as ANSI, and å ä ö arrive broken |
2214
2213
  * | CRLF line endings | what Excel writes, and what its importer is happiest with |
2215
2214
  *
2216
- * The `sep=` line is Excel's alone; other readers show it as a first row. That
2217
- * is the trade this makes - the file is for Excel, and "it just opens" is worth
2218
- * more than being a well-behaved CSV nobody was going to feed to a parser.
2215
+ * The `sep=` line is Excel's alone; other readers show it as a first row. This
2216
+ * export targets Excel, so opening correctly there takes priority over strict
2217
+ * CSV.
2219
2218
  */
2220
2219
  declare function toExcelCsv(matrix: TMDataGridCellMatrix, { separator }: {
2221
2220
  separator: string;
@@ -2226,7 +2225,7 @@ declare function toExcelCsv(matrix: TMDataGridCellMatrix, { separator }: {
2226
2225
  * The async clipboard API only resolves for a document that has the focus and a
2227
2226
  * user gesture behind it - both true when this runs off Ctrl+C or a menu item.
2228
2227
  * It is still allowed to reject (a permissions policy, a page that lost focus
2229
- * mid-copy), so the result is a boolean rather than a promise nobody checks.
2228
+ * mid-copy), so the result is a boolean the caller can act on.
2230
2229
  */
2231
2230
  declare function writeClipboardText(text: string): Promise<boolean>;
2232
2231
  /**
@@ -2473,9 +2472,9 @@ type TMDataGridTableProps<TData extends RowData> = {
2473
2472
  */
2474
2473
  reachEndThreshold?: number;
2475
2474
  /**
2476
- * Accessible name for the grid - what a screen reader announces on entry,
2477
- * and what `getByRole("grid", { name })` matches. Worth setting on any page
2478
- * holding more than one grid; without it they are all just "grid".
2475
+ * Accessible name for the grid: what a screen reader announces on entry, and
2476
+ * what `getByRole("grid", { name })` matches. Set it on any page holding more
2477
+ * than one grid; without it they are all announced as "grid".
2479
2478
  */
2480
2479
  "aria-label"?: string;
2481
2480
  /** As {@link "aria-label"}, pointing at an element that already names it. */
@@ -2483,9 +2482,9 @@ type TMDataGridTableProps<TData extends RowData> = {
2483
2482
  };
2484
2483
  /**
2485
2484
  * The scrollable grid surface. Always virtualized: only the rows inside the
2486
- * viewport (plus overscan) are mounted - which is what makes the default
2487
- * no-pagination mode viable at any row count. Pagination is opt-in via
2488
- * `enablePagination` (or implied by `manualPagination`).
2485
+ * viewport (plus overscan) are mounted, which is what makes the default
2486
+ * no-pagination mode work at any row count. Pagination is opt in through
2487
+ * `enablePagination`, or implied by `manualPagination`.
2489
2488
  */
2490
2489
  declare function TMDataGridTable$1<TData extends RowData = TMDataGridRowData>({ onRowClick, onCellClick, onCellDoubleClick, onCellContextMenu, rowClassName, rowStyle, striped, onScrollToTop, onScrollToBottom, onScrollToLeft, onScrollToRight, renderEmptyState, renderRowContextMenu, renderColumnMenuItems, rowContextMenuProps, cellExport, onReachEnd, reachEndThreshold, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }: TMDataGridTableProps<TData>): import("react").JSX.Element;
2491
2490
  //#endregion
@@ -2775,6 +2774,16 @@ declare function isColumnEditableForRow(column: ColumnLike, row: Row<TMDataGridF
2775
2774
  * chevron, and wants the padding.
2776
2775
  */
2777
2776
  declare function isControlColumn(columnId: string): boolean;
2777
+ /**
2778
+ * Whether the grid generated this column rather than the consumer declaring it
2779
+ * - the four control lanes plus the tree column.
2780
+ *
2781
+ * These hold the grid's own chrome, and they keep the edges of the row: the
2782
+ * generated left lanes before every consumer column, the edit lane after all of
2783
+ * them. `isControlColumn` answers a narrower question about layout, and leaves
2784
+ * the tree column out because it is padded like a data column.
2785
+ */
2786
+ declare function isGeneratedColumn(columnId: string): boolean;
2778
2787
  /**
2779
2788
  * Whether a column may be moved. Ordering is the one column feature TanStack
2780
2789
  * has no column option for, so the switch lives in `meta.enableOrdering`.
@@ -2829,7 +2838,9 @@ declare function aggregateColumn<TData extends RowData>({ table, columnId, fn }:
2829
2838
  *
2830
2839
  * Mounted cells only: under virtualization the unmounted rows do not exist to
2831
2840
  * be measured, so this reads the visible window plus overscan - the same
2832
- * trade AG Grid's autosize makes by default.
2841
+ * trade AG Grid's autosize makes by default. With no rows mounted at all the
2842
+ * header is the only thing left to measure, which is a width that fits the
2843
+ * title and nothing else - see `hasMountedCells`.
2833
2844
  */
2834
2845
  declare function measureColumnContentWidth({ container, columnId }: {
2835
2846
  /** The grid's scroll container - anything enclosing the column's cells. */
@@ -2928,6 +2939,20 @@ type MoveColumnArgs = {
2928
2939
  * updates that array as well.
2929
2940
  */
2930
2941
  declare function moveColumn({ table, columnId, targetId, side }: MoveColumnArgs): void;
2942
+ /**
2943
+ * Puts the generated lanes back on the outside of both pinned lanes: the ones
2944
+ * on the left before every consumer column, the edit lane after all of them.
2945
+ *
2946
+ * `column.pin("right")` appends, so pinning a column right would otherwise drop
2947
+ * it outside the edit lane, so the row's Save and Delete would no longer be
2948
+ * last in the row. Pinning left appends too, which is already correct there,
2949
+ * but the same pass keeps both lanes in place whatever a consumer writes into
2950
+ * `columnPinning` directly.
2951
+ *
2952
+ * Relative order is preserved inside each part, so a user's own arrangement of
2953
+ * the pinned columns survives.
2954
+ */
2955
+ declare function keepGeneratedColumnsOutermost(pinning: ColumnPinningState): ColumnPinningState;
2931
2956
  type ColumnStepArgs = {
2932
2957
  table: GridTable;
2933
2958
  columnId: string;
@@ -2998,9 +3023,9 @@ type ResolveRowSelectionClickArgs<TData extends RowData> = {
2998
3023
  /**
2999
3024
  * Whether this gesture is allowed to clear rows it did not touch.
3000
3025
  *
3001
- * `true` for a bare row click, where replacing is the whole point. `false` for
3002
- * a checkbox, which is only ever additive - ticking one box has never cleared
3003
- * the others, and shift-clicking one adds the range rather than becoming it.
3026
+ * `true` for a bare row click, which replaces the selection. `false` for a
3027
+ * checkbox, which is only ever additive: ticking one box does not clear the
3028
+ * others, and shift-clicking one adds the range rather than replacing it.
3004
3029
  */
3005
3030
  canReplaceSelection: boolean;
3006
3031
  };
@@ -3044,4 +3069,4 @@ declare function getSelectableRowIds<TData extends RowData>(row: Row<TMDataGridF
3044
3069
  */
3045
3070
  declare function resolveRowSelectionClick<TData extends RowData>({ rows, rowId, anchorRowId, modifiers, selection, canReplaceSelection }: ResolveRowSelectionClickArgs<TData>): ResolvedRowSelection;
3046
3071
  //#endregion
3047
- 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, isPagingActive, isSameCell, isWithinBounds, measureColumnContentWidth, mergeLabels, moveColumn, moveColumnByStep, normalizeFieldValidate, openColumnFilter, operatorNeedsValue, operatorTakesArrayValue, operatorTakesRangeValue, optionsToComboboxData, readFeatureFlags, resolveCellMove, resolveColumnOptions, resolveExpandAll, resolveRangeBounds, resolveRowSelectionClick, tmDataGridFeatures, toClipboardText, toExcelCsv, useCellControlTabIndex, useTMDataGrid, useTMDataGridContext, writeClipboardText };
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 };