@jielga/tmdatagrid 0.3.0 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +25 -2
  2. package/dist/index.d.ts +1789 -64
  3. package/dist/index.js +4432 -1561
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/dist/styles.layer.css +1 -0
  7. package/package.json +13 -3
  8. package/skills/columns/SKILL.md +1 -1
  9. package/skills/features/SKILL.md +61 -11
  10. package/skills/getting-started/SKILL.md +1 -1
  11. package/skills/options/SKILL.md +12 -2
  12. package/skills/server-side/SKILL.md +1 -1
  13. package/skills/testing/SKILL.md +198 -0
  14. package/src/tmdatagrid/TMDataGridContext.ts +26 -0
  15. package/src/tmdatagrid/components/TMDataGrid.module.css +21 -0
  16. package/src/tmdatagrid/components/TMDataGrid.tsx +57 -1
  17. package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +256 -0
  18. package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +38 -15
  19. package/src/tmdatagrid/components/TMDataGridDetailsColumn.module.css +33 -0
  20. package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +163 -0
  21. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +62 -0
  22. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +237 -0
  23. package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +164 -0
  24. package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +131 -38
  25. package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +11 -4
  26. package/src/tmdatagrid/components/TMDataGridFooter.tsx +21 -22
  27. package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +25 -11
  28. package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +15 -3
  29. package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +191 -53
  30. package/src/tmdatagrid/components/TMDataGridRowNumberColumn.tsx +44 -0
  31. package/src/tmdatagrid/components/TMDataGridSearch.tsx +124 -0
  32. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +26 -13
  33. package/src/tmdatagrid/components/TMDataGridTable.module.css +333 -6
  34. package/src/tmdatagrid/components/TMDataGridTable.tsx +1819 -62
  35. package/src/tmdatagrid/components/TMDataGridToolbar.tsx +41 -13
  36. package/src/tmdatagrid/components/editors/TMDataGridBooleanEditor.tsx +29 -0
  37. package/src/tmdatagrid/components/editors/TMDataGridDateEditor.tsx +57 -0
  38. package/src/tmdatagrid/components/editors/TMDataGridMultiSelectEditor.tsx +45 -0
  39. package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +38 -0
  40. package/src/tmdatagrid/components/editors/TMDataGridSelectEditor.tsx +53 -0
  41. package/src/tmdatagrid/components/editors/TMDataGridStringEditor.tsx +31 -0
  42. package/src/tmdatagrid/components/editors/editorShared.ts +48 -0
  43. package/src/tmdatagrid/components/filters/DgAutocompleteFilter.tsx +46 -0
  44. package/src/tmdatagrid/components/filters/DgDateRangeFilter.tsx +43 -0
  45. package/src/tmdatagrid/components/filters/DgRangeSliderFilter.tsx +52 -0
  46. package/src/tmdatagrid/components/filters/DgTriStateFilter.tsx +38 -0
  47. package/src/tmdatagrid/components/filters/TMDataGridFilterValueInput.tsx +122 -0
  48. package/src/tmdatagrid/components/icons.ts +5 -0
  49. package/src/tmdatagrid/components/sticky.module.css +77 -16
  50. package/src/tmdatagrid/core/autosize.ts +125 -0
  51. package/src/tmdatagrid/core/capabilities.ts +77 -0
  52. package/src/tmdatagrid/core/cellExport.ts +321 -0
  53. package/src/tmdatagrid/core/cellNavigation.ts +144 -0
  54. package/src/tmdatagrid/core/cellRange.ts +118 -0
  55. package/src/tmdatagrid/core/columnOptions.ts +123 -0
  56. package/src/tmdatagrid/core/columnUtils.ts +44 -1
  57. package/src/tmdatagrid/core/editEngine.ts +857 -0
  58. package/src/tmdatagrid/core/expanding.ts +93 -0
  59. package/src/tmdatagrid/core/filterControls.ts +45 -0
  60. package/src/tmdatagrid/core/filterOperators.ts +243 -14
  61. package/src/tmdatagrid/core/labels.ts +278 -0
  62. package/src/tmdatagrid/core/labelsSv.ts +131 -0
  63. package/src/tmdatagrid/core/matchHighlight.ts +96 -0
  64. package/src/tmdatagrid/core/persistence.ts +97 -3
  65. package/src/tmdatagrid/core/quickSearch.ts +144 -0
  66. package/src/tmdatagrid/core/rowPinning.ts +37 -0
  67. package/src/tmdatagrid/core/rowSelection.ts +10 -1
  68. package/src/tmdatagrid/core/summary.ts +35 -0
  69. package/src/tmdatagrid/index.ts +121 -0
  70. package/src/tmdatagrid/useTMDataGrid.tsx +782 -25
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { Cell, Column, ColumnPinningState, Row, RowData, RowSelectionState, Table, TableFeatures, TableOptions, TableState } from "@tanstack/react-table";
2
- import { CSSProperties, ReactNode } from "react";
1
+ import { Cell, Column, ColumnPinningState, ExpandedState, Row, RowData, RowSelectionState, Table, TableFeatures, TableOptions, TableState, aggregationFns } from "@tanstack/react-table";
2
+ import { CSSProperties, ComponentType, MouseEvent, MutableRefObject, ReactNode } from "react";
3
3
  import { MantineSize, MenuProps } from "@mantine/core";
4
4
  import { Store } from "@tanstack/store";
5
+ import { AnyFieldApi, AnyFormApi, StandardSchemaV1 } from "@tanstack/react-form";
6
+ import { RankingInfo } from "@tanstack/match-sorter-utils";
5
7
  //#region .types-tmp/components/TMDataGridColumnsPanel.d.ts
6
8
  /**
7
9
  * The "Manage columns" surface. Reachable from every column header menu and
@@ -10,6 +12,24 @@ import { Store } from "@tanstack/store";
10
12
  */
11
13
  declare function TMDataGridColumnsPanel(): import("react").JSX.Element;
12
14
  //#endregion
15
+ //#region .types-tmp/components/TMDataGridEditActions.d.ts
16
+ /**
17
+ * Batch mode's toolbar chrome: Save with the dirty-row count, and Discard.
18
+ * Both read the edit store, so they grey out while nothing is dirty and the
19
+ * Save spins while a submit is in flight. Works under any `editMode` — a
20
+ * cellConfirm grid accumulating drafts can offer the same pair — and renders
21
+ * nothing while editing is off.
22
+ *
23
+ * ```tsx
24
+ * <TMDataGrid.Toolbar>
25
+ * <TMDataGrid.SummaryCount />
26
+ * <TMDataGrid.Spacer />
27
+ * <TMDataGrid.EditActions />
28
+ * </TMDataGrid.Toolbar>
29
+ * ```
30
+ */
31
+ declare function TMDataGridEditActions(): import("react").JSX.Element | null;
32
+ //#endregion
13
33
  //#region .types-tmp/components/TMDataGridFilterPanel.d.ts
14
34
  /**
15
35
  * The MUI-style filter surface: one row per active column filter, each row a
@@ -33,6 +53,107 @@ declare const SIZE_ROW_HEIGHT: Record<TMDataGridSize, number>;
33
53
  /** Size of the Mantine controls rendered inside the grid chrome. */
34
54
  declare const SIZE_CONTROL_SIZE: Record<TMDataGridSize, MantineSize>;
35
55
  //#endregion
56
+ //#region .types-tmp/TMDataGridContext.d.ts
57
+ /**
58
+ * Row shape the chrome components work against. They only ever touch columns,
59
+ * rows and cells generically, so the concrete row type is erased at the context
60
+ * boundary — the same trick Mantine uses for its compound components.
61
+ */
62
+ type TMDataGridRowData = Record<string, unknown>;
63
+ type TMDataGridContextValue = TMDataGridApi<TMDataGridRowData> & {
64
+ size: TMDataGridSize;
65
+ /** Row height in px, already resolved from `size` and `meta.rowHeight`. */
66
+ rowHeight: number;
67
+ /** Mantine control size that pairs with `size`. */
68
+ controlSize: TMDataGridSize;
69
+ };
70
+ declare function useTMDataGridContext(): TMDataGridContextValue;
71
+ /**
72
+ * What a control inside a *body* cell should put in its `tabIndex`.
73
+ *
74
+ * `-1` once cell selection is on, and this is what makes the promise of one tab
75
+ * stop true. Without it the browser walks Tab into the checkbox of every
76
+ * mounted row — a grid showing twenty rows would be twenty tab stops, and
77
+ * scrolling would change how many. Enter or F2 steps into the cell instead,
78
+ * which reaches a `-1` control perfectly well.
79
+ *
80
+ * Header controls are not covered: the header row is not part of cell
81
+ * navigation, so its sort buttons and menus stay in the tab order, where they
82
+ * are the only way to reach them.
83
+ *
84
+ * A custom cell renderer with a control in it wants the same:
85
+ *
86
+ * ```tsx
87
+ * cell: ({ row }) => (
88
+ * <Button tabIndex={useCellControlTabIndex()} onClick={...}>Open</Button>
89
+ * )
90
+ * ```
91
+ */
92
+ declare function useCellControlTabIndex(): 0 | -1;
93
+ //#endregion
94
+ //#region .types-tmp/core/columnOptions.d.ts
95
+ /**
96
+ * One choice of a `select` / `multiSelect` column. A bare string in any options
97
+ * list is shorthand for `{ value }`.
98
+ */
99
+ type TMDataGridOption = {
100
+ value: string;
101
+ /** Shown in dropdowns. Defaults to the value itself. */
102
+ label?: string;
103
+ /** Mantine colour for the value's badge, where a cell renders one. */
104
+ color?: string;
105
+ disabled?: boolean;
106
+ /** Dropdown group heading. Ungrouped options render first. */
107
+ group?: string;
108
+ };
109
+ type TMDataGridOptionsArgs = {
110
+ table: TMDataGridTable<TMDataGridRowData>;
111
+ column: Column<TMDataGridFeatures, TMDataGridRowData, unknown>;
112
+ /** The row an editor is standing on. Absent when the filter panel asks. */
113
+ row?: Row<TMDataGridFeatures, TMDataGridRowData>;
114
+ /**
115
+ * Source to use when the column declares none. The filter panel passes
116
+ * `"faceted"` so a select column with no `meta.options` still offers the
117
+ * values that exist, rather than an empty dropdown.
118
+ */
119
+ fallback?: TMDataGridOptionsSource;
120
+ };
121
+ /**
122
+ * Where a column's options come from — `meta.options`. One declaration feeds
123
+ * both the filter panel's value control and the cell editor.
124
+ *
125
+ * | Form | For |
126
+ * | --- | --- |
127
+ * | array | a known, fixed set |
128
+ * | `"faceted"` | low-cardinality data columns: the distinct values present, via `getFacetedUniqueValues` |
129
+ * | function | large or contextual sets — `row` is set when an editor asks, so options can depend on the record (city given country) |
130
+ */
131
+ type TMDataGridOptionsSource = ReadonlyArray<TMDataGridOption | string> | "faceted" | ((args: TMDataGridOptionsArgs) => ReadonlyArray<TMDataGridOption | string>);
132
+ /**
133
+ * A column's options as a normalised list, whatever form `meta.options` took.
134
+ * Empty for a column that declares none.
135
+ *
136
+ * `"faceted"` reads the distinct values actually present in the data. A
137
+ * multiSelect cell holds an array, so array values contribute their elements
138
+ * rather than the array itself.
139
+ */
140
+ declare function resolveColumnOptions({ table, column, row, fallback }: TMDataGridOptionsArgs): Array<TMDataGridOption>;
141
+ type ComboboxItem = {
142
+ value: string;
143
+ label: string;
144
+ disabled?: boolean;
145
+ };
146
+ type ComboboxData = Array<ComboboxItem | {
147
+ group: string;
148
+ items: ComboboxItem[];
149
+ }>;
150
+ /**
151
+ * The same list in the shape Mantine's `Select` / `MultiSelect` take, with
152
+ * `group` fields folded into Mantine's group entries. Ungrouped options come
153
+ * first, then the groups in first-appearance order.
154
+ */
155
+ declare function optionsToComboboxData(options: ReadonlyArray<TMDataGridOption>): ComboboxData;
156
+ //#endregion
36
157
  //#region .types-tmp/core/filterOperators.d.ts
37
158
  /**
38
159
  * The value shape stored in `columnFilters` for every TMDataGrid column.
@@ -41,14 +162,29 @@ declare const SIZE_CONTROL_SIZE: Record<TMDataGridSize, MantineSize>;
41
162
  * inside the filter *value* instead. That keeps the whole filter model plain,
42
163
  * serialisable JSON — which is what makes it portable to a server-side
43
164
  * `manualFiltering` table (just forward `columnFilters` to the API).
165
+ *
166
+ * `value` is a string array under `isAnyOf` / `isNoneOf` (the set the cell is
167
+ * tested against), a `[min, max]` pair under `between` (an empty string means
168
+ * that end is open), and a single string everywhere else — dates travel as
169
+ * ISO `YYYY-MM-DD` strings, booleans as `"true"` / `"false"`. Still plain
170
+ * JSON.
44
171
  */
45
172
  type TMDataGridFilterValue = {
46
173
  operator: TMDataGridFilterOperator;
47
- value: string;
174
+ value: string | ReadonlyArray<string>;
48
175
  };
49
- type TMDataGridColumnType = "string" | "number";
50
- type TMDataGridFilterOperator = "contains" | "equals" | "notEquals" | "startsWith" | "endsWith" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "isEmpty" | "isNotEmpty";
176
+ type TMDataGridColumnType = "string" | "number" | "boolean" | "date" | "select" | "multiSelect";
177
+ type TMDataGridFilterOperator = "contains" | "equals" | "notEquals" | "startsWith" | "endsWith" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "between" | "before" | "after" | "onOrBefore" | "onOrAfter" | "isAnyOf" | "isNoneOf" | "isEmpty" | "isNotEmpty";
51
178
  declare const FILTER_OPERATOR_LABELS: Record<TMDataGridFilterOperator, string>;
179
+ declare function getOperatorsForType(type: TMDataGridColumnType): readonly TMDataGridFilterOperator[];
180
+ declare function getDefaultOperator(type: TMDataGridColumnType): TMDataGridFilterOperator;
181
+ declare function operatorNeedsValue(operator: TMDataGridFilterOperator): boolean;
182
+ /** Whether the operator's value is a string array — `isAnyOf` / `isNoneOf`. */
183
+ declare function operatorTakesArrayValue(operator: TMDataGridFilterOperator): boolean;
184
+ /** Whether the operator's value is a `[min, max]` pair — `between`. */
185
+ declare function operatorTakesRangeValue(operator: TMDataGridFilterOperator): boolean;
186
+ /** The untouched value a fresh filter starts with — the operator's shape, empty. */
187
+ declare function emptyValueForOperator(operator: TMDataGridFilterOperator): string | ReadonlyArray<string>;
52
188
  /**
53
189
  * A filter only narrows the row set once it has something to compare against.
54
190
  * Half-typed filters stay in state (so the panel keeps rendering their row) but
@@ -62,10 +198,12 @@ declare function isFilterActive(value: unknown): boolean;
62
198
  * way a person would say it — while any other operator is spelled out, since
63
199
  * that is the part a reader cannot guess.
64
200
  */
65
- declare function formatFilterLabel({ label, type, filter }: {
201
+ declare function formatFilterLabel({ label, type, filter, operatorLabels }: {
66
202
  label: string;
67
203
  type: TMDataGridColumnType;
68
204
  filter: TMDataGridFilterValue;
205
+ /** Localized operator names — `labels.operators`. Defaults to English. */
206
+ operatorLabels?: Record<TMDataGridFilterOperator, string>;
69
207
  }): string;
70
208
  /**
71
209
  * The single filter function every TMDataGrid column uses. It dispatches on the
@@ -74,6 +212,461 @@ declare function formatFilterLabel({ label, type, filter }: {
74
212
  */
75
213
  declare function tmDataGridFilterFn<TFeatures extends TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown): boolean;
76
214
  //#endregion
215
+ //#region .types-tmp/core/editEngine.d.ts
216
+ /**
217
+ * How commits happen — one axis, each mode a thin policy over the same
218
+ * engine. See `editMode` on `UseTMDataGridOptions`.
219
+ */
220
+ type TMDataGridEditMode = "cell" | "cellConfirm" | "row" | "batch";
221
+ /**
222
+ * One editing row's live form. TanStack Form's `FormApi`, not a wrapper: the
223
+ * engine is a form library, and everything mid-edit — values, dirty state,
224
+ * errors, async validation, submit lifecycle — is form state, read off
225
+ * `form.store` with the same selector idiom as the rest of the grid.
226
+ *
227
+ * The alias erases Form's validator generics the way `TMDataGridRowData`
228
+ * erases the row type: the concrete types lived at the `useTMDataGrid` call.
229
+ */
230
+ type TMDataGridRowEditForm = AnyFormApi;
231
+ /** The live field a cell editor binds to — TanStack Form's own `FieldApi`. */
232
+ type TMDataGridEditField = AnyFieldApi;
233
+ /**
234
+ * A validator as TanStack Form takes it: a Standard Schema (Zod, Valibot,
235
+ * ArkType…) or a plain function returning an error or nothing. Forwarded
236
+ * untouched — the vocabulary is Form's, not a grid re-implementation.
237
+ */
238
+ type TMDataGridValidator = StandardSchemaV1<unknown, unknown> | ((args: {
239
+ value: never;
240
+ fieldApi: never;
241
+ }) => unknown);
242
+ /**
243
+ * `meta.validate` — per-column field validators. A bare schema or function is
244
+ * shorthand for `{ onChange: it }`; the object form takes every trigger
245
+ * TanStack Form defines, `Async` variants and debounce included.
246
+ */
247
+ type TMDataGridFieldValidate = TMDataGridValidator | {
248
+ onMount?: TMDataGridValidator;
249
+ onChange?: TMDataGridValidator;
250
+ onChangeAsync?: TMDataGridValidator;
251
+ onChangeAsyncDebounceMs?: number;
252
+ onBlur?: TMDataGridValidator;
253
+ onBlurAsync?: TMDataGridValidator;
254
+ onSubmit?: TMDataGridValidator;
255
+ onSubmitAsync?: TMDataGridValidator;
256
+ };
257
+ /**
258
+ * `rowValidators` — form-level validators for the whole row, where
259
+ * cross-field rules live. Passed into each row form's `validators` untouched;
260
+ * pathed issues land on the matching fields, pathless ones on the row.
261
+ */
262
+ type TMDataGridRowValidators = {
263
+ onMount?: TMDataGridValidator;
264
+ onChange?: TMDataGridValidator;
265
+ onChangeAsync?: TMDataGridValidator;
266
+ onChangeAsyncDebounceMs?: number;
267
+ onBlur?: TMDataGridValidator;
268
+ onBlurAsync?: TMDataGridValidator;
269
+ onSubmit?: TMDataGridValidator;
270
+ onSubmitAsync?: TMDataGridValidator;
271
+ onSubmitAsyncDebounceMs?: number;
272
+ };
273
+ /** One field's before/after across a commit. */
274
+ type TMDataGridEditChange = {
275
+ /** Column the field maps back to, for consumers thinking in columns. */
276
+ columnId: string;
277
+ /** The data path — `getEditFieldName` of the column. */
278
+ field: string;
279
+ previous: unknown;
280
+ next: unknown;
281
+ };
282
+ type TMDataGridEditCommitArgs<TData extends RowData> = {
283
+ rowId: string;
284
+ /** The whole row as edited — for the consumer who saves records. */
285
+ value: TData;
286
+ /** The row as it was when editing began. */
287
+ original: TData;
288
+ /** Per-field diff — for the consumer who PATCHes. One entry in cell mode. */
289
+ changes: Array<TMDataGridEditChange>;
290
+ /** Which policy committed. */
291
+ source: TMDataGridEditMode;
292
+ };
293
+ /** What one open row's form looks like from outside — the cell markers. */
294
+ type TMDataGridEditRowProjection = {
295
+ /** Field names whose value differs from the original. */
296
+ dirtyFields: ReadonlyArray<string>;
297
+ /** Field names carrying a validation error. */
298
+ errorFields: ReadonlyArray<string>;
299
+ /** A row-level error — a pathless `.refine()`, or a rejected commit. */
300
+ hasRowError: boolean;
301
+ isSubmitting: boolean;
302
+ };
303
+ /**
304
+ * The grid-facing index of everything mid-edit. A projection synced from the
305
+ * open forms' stores, so body cells subscribe to this one store for their
306
+ * dirty/error markers instead of one store per form. Only the editor host
307
+ * reads a form's store directly — it is mounted for one cell at a time.
308
+ */
309
+ type TMDataGridEditState = {
310
+ /** The cell whose editor is open; `columnId: null` is a whole row (row mode). */
311
+ active: {
312
+ rowId: string;
313
+ columnId: string | null;
314
+ } | null;
315
+ /** Rows with a live form. In cell mode at most one; in batch, many. */
316
+ openRowIds: ReadonlyArray<string>;
317
+ rows: Record<string, TMDataGridEditRowProjection>;
318
+ /** Phase 4 — rows being created, not yet in `data`. */
319
+ newRows: ReadonlyArray<{
320
+ tempId: string;
321
+ }>;
322
+ /** Phase 4 — rows marked deleted under batch mode. */
323
+ deletedRowIds: ReadonlyArray<string>;
324
+ };
325
+ type ErasedRow = Row<TMDataGridFeatures, TMDataGridRowData>;
326
+ type ErasedColumn = Column<TMDataGridFeatures, TMDataGridRowData, unknown>;
327
+ /**
328
+ * What a cell editor is handed — deliberately both vocabularies at once. The
329
+ * form side is TanStack Form's real `field` API (`field.state.value`,
330
+ * `field.state.meta.errors`, `field.handleChange`, `field.handleBlur`), so a
331
+ * custom calendar, slider or async combobox binds to it exactly as it would
332
+ * inside any TanStack Form. The table side is where the editor is standing.
333
+ *
334
+ * The built-ins are implemented against this same contract, so
335
+ * `meta.editor` is not a special case — it is the slot the defaults
336
+ * fill, and the exported built-ins can be wrapped instead of replaced.
337
+ */
338
+ type TMDataGridEditorArgs = {
339
+ /** The live TanStack Form field for this cell. */
340
+ field: TMDataGridEditField;
341
+ /** The whole row form, for the rare editor that reads sibling fields. */
342
+ form: TMDataGridRowEditForm;
343
+ cell: Cell<TMDataGridFeatures, TMDataGridRowData, unknown>;
344
+ row: ErasedRow;
345
+ column: ErasedColumn;
346
+ table: TMDataGridTable<TMDataGridRowData>;
347
+ /** What Enter would do — commit the edit. For the editor's own UI. */
348
+ commit: () => Promise<boolean>;
349
+ /** What Escape would do — drop the draft. */
350
+ cancel: () => void;
351
+ size: TMDataGridSize;
352
+ /**
353
+ * Whether this editor should take the focus on mount. True for a single
354
+ * opened cell; in row mode only the row's first editable cell gets it.
355
+ */
356
+ autoFocus: boolean;
357
+ /**
358
+ * Set when typing opened the editor (the Sheets gesture) — the built-ins
359
+ * replace the value with it and keep typing. A custom editor may ignore it.
360
+ */
361
+ seedText?: string;
362
+ };
363
+ /**
364
+ * `meta.editor` — replaces the built-in editor for this column. Rendered as
365
+ * JSX, never invoked as a bare function, so hooks are legal inside. Define it
366
+ * at module scope: a new identity per render remounts the editor mid-edit.
367
+ */
368
+ type TMDataGridEditorComponent = ComponentType<TMDataGridEditorArgs>;
369
+ /** A new row being committed — `onRowAdd`, and `submitAll`'s `added`. */
370
+ type TMDataGridRowAddArgs<TData extends RowData> = {
371
+ /** The engine's placeholder id; the real id is the consumer's to mint. */
372
+ tempId: string;
373
+ value: TData;
374
+ };
375
+ /** A deletion — `onRowDelete`. */
376
+ type TMDataGridRowDeleteArgs<TData extends RowData> = {
377
+ rowId: string;
378
+ row: Row<TMDataGridFeatures, TData>;
379
+ };
380
+ /** What `submitAll` hands `onEditCommitBatch` — everything pending at once. */
381
+ type TMDataGridEditCommitBatchArgs<TData extends RowData> = {
382
+ /** Every valid dirty existing row. */
383
+ rows: Array<TMDataGridEditCommitArgs<TData>>;
384
+ /** Every valid new row from the entry block. */
385
+ added: Array<TMDataGridRowAddArgs<TData>>;
386
+ /** Ids marked deleted while the batch accumulated. */
387
+ deleted: Array<string>;
388
+ };
389
+ /**
390
+ * The data path a column edits, or `null` for a column that has none.
391
+ *
392
+ * `accessorKey` is the true path and Form addresses fields by dot-path, so
393
+ * nested rows work for free: `accessorKey: "address.city"` edits
394
+ * `values.address.city`. A column built on `accessorFn` has no path and is
395
+ * not editable unless `meta.editField` names one. TanStack's default column
396
+ * id turns dots into underscores — which is why this starts from
397
+ * `accessorKey`, never from `id`.
398
+ */
399
+ declare function getEditFieldName(column: {
400
+ columnDef: {
401
+ meta?: {
402
+ editField?: string;
403
+ };
404
+ };
405
+ }): string | null;
406
+ /** What Delete writes into a cell — the type's honest empty value. */
407
+ declare function clearedValueForType(type: TMDataGridColumnType): unknown;
408
+ /**
409
+ * The engine plus its store — `api.edit`.
410
+ *
411
+ * "One row, one form": `getForm` hands out the same `FormApi` the inline
412
+ * editors write through, so a consumer can render it in a drawer or a detail
413
+ * panel and share values, dirty state and errors with the cells.
414
+ */
415
+ type TMDataGridEditApi = {
416
+ /** The projection store — subscribe with `useSelector(edit.store, …)`. */
417
+ store: Store<TMDataGridEditState>;
418
+ /** Current snapshot, for reads outside React. */
419
+ readonly state: TMDataGridEditState;
420
+ /** rowId → live form. The source of truth for everything mid-edit. */
421
+ getForm: (rowId: string) => TMDataGridRowEditForm | undefined;
422
+ /**
423
+ * Whether this cell may open an editor: the column maps to a field, nothing
424
+ * switched it off, and the row takes edits at all.
425
+ */
426
+ canEditCell: (row: ErasedRow, column: ErasedColumn) => boolean;
427
+ /** Whether the row takes edits at all — the edit lane's pencil gate. */
428
+ canEditRow: (row: ErasedRow) => boolean;
429
+ /** Opens an editor. `columnId: null` opens the whole row (row mode). */
430
+ begin: (target: {
431
+ rowId: string;
432
+ columnId: string | null;
433
+ }) => void;
434
+ /**
435
+ * Commits one row — `form.handleSubmit` under the hood. Resolves `true`
436
+ * when the form is gone: validation passed and `onEditCommit` resolved, or
437
+ * there was nothing to save. `false` keeps the form open with its errors.
438
+ */
439
+ commit: (rowId: string) => Promise<boolean>;
440
+ /** Drops one row's draft. */
441
+ cancel: (rowId: string) => void;
442
+ /**
443
+ * Closes the editor without touching the draft — what blur does under
444
+ * `"cellConfirm"`, where the dirty cell keeps waiting for its ✓.
445
+ */
446
+ deactivate: () => void;
447
+ /** Drops every draft. */
448
+ cancelAll: () => void;
449
+ /** Commits every open row — batch mode's save. `true` when all landed. */
450
+ submitAll: () => Promise<boolean>;
451
+ /** Writes the type's empty value into a cell and commits it — Delete. */
452
+ clearCell: (rowId: string, columnId: string) => Promise<boolean>;
453
+ /**
454
+ * Opens a new entry row (the sticky block under the header) seeded from
455
+ * `newRowDefaults`. Returns its temporary id — a form with no backing row
456
+ * yet. Committing it calls `onRowAdd` (immediate modes) or joins
457
+ * `submitAll`'s `added` (batch).
458
+ */
459
+ addRow: () => string;
460
+ /**
461
+ * Deletes a row: `onRowDelete` straight away under the immediate modes;
462
+ * under batch it toggles the id in `deletedRowIds` — the row renders
463
+ * struck through until `submitAll` reports it. On an uncommitted entry
464
+ * row it just discards the entry.
465
+ */
466
+ deleteRow: (rowId: string) => void;
467
+ /** Whether delete chrome makes sense — the lane's trash gate. */
468
+ canDeleteRows: () => boolean;
469
+ };
470
+ /**
471
+ * `meta.validate` normalised to the object TanStack Form's `validators`
472
+ * option takes — a bare schema or function is shorthand for `{ onChange }`.
473
+ */
474
+ declare function normalizeFieldValidate(validate: TMDataGridFieldValidate | undefined): Record<string, unknown> | undefined;
475
+ //#endregion
476
+ //#region .types-tmp/core/labels.d.ts
477
+ /**
478
+ * Every user-facing string in the grid — menu items, panels, tooltips, the
479
+ * pager, and the `aria-label`s a screen reader speaks. One flat object, so an
480
+ * override is a spread rather than a deep merge; `operators` is the single
481
+ * nested record and {@link mergeLabels} folds it separately.
482
+ *
483
+ * Labels that carry a value are functions rather than template strings, so a
484
+ * language is free to put the value wherever its grammar wants it.
485
+ */
486
+ type TMDataGridLabels = {
487
+ /** Filter operator names, as shown in the operator dropdown and on pills. */
488
+ operators: Record<TMDataGridFilterOperator, string>;
489
+ /** "Manage columns" — the burger button and the header menu item. */
490
+ manageColumns: string;
491
+ /** "Filters" — the funnel button and the filter panel's title. */
492
+ filters: string;
493
+ searchPlaceholder: string;
494
+ searchLabel: string;
495
+ clearSearch: string;
496
+ columnsSearchPlaceholder: string;
497
+ columnsNoMatch: (search: string) => string;
498
+ columnsShowHideAll: string;
499
+ columnsReset: string;
500
+ /** Tooltip on the reset button, stating everything the reset covers. */
501
+ columnsResetHint: string;
502
+ /** Menu/panel name of the generated row-number gutter. */
503
+ rowNumberColumnLabel: string;
504
+ /**
505
+ * The truly-empty message — no data and no filters. Filtered-empty says
506
+ * {@link noResults} instead; only one of the two is the user's own doing.
507
+ */
508
+ noRows: string;
509
+ filterColumn: string;
510
+ filterOperator: string;
511
+ filterValue: string;
512
+ filterValuePlaceholder: string;
513
+ /** The lower bound of a `between` filter. */
514
+ filterFrom: string;
515
+ /** The upper bound of a `between` filter. */
516
+ filterTo: string;
517
+ /** `DgTriStateFilter`'s no-filter segment. */
518
+ filterAll: string;
519
+ /** What a boolean column's `true` reads as — its filter choice and cell text. */
520
+ booleanTrue: string;
521
+ booleanFalse: string;
522
+ addFilter: string;
523
+ clearAllFilters: string;
524
+ closeFilters: string;
525
+ removeFilter: string;
526
+ activeFilters: string;
527
+ clearFilter: (column: string) => string;
528
+ sortAsc: string;
529
+ sortDesc: string;
530
+ filterMenuItem: string;
531
+ groupBy: (column: string) => string;
532
+ ungroup: (column: string) => string;
533
+ expandAllGroups: string;
534
+ collapseAllGroups: string;
535
+ pinLeft: string;
536
+ pinRight: string;
537
+ unpin: string;
538
+ moveLeft: string;
539
+ moveRight: string;
540
+ autosizeColumn: string;
541
+ hideColumn: string;
542
+ filterOn: (column: string) => string;
543
+ sortColumn: (column: string) => string;
544
+ columnMenu: (column: string) => string;
545
+ rowsPerPage: string;
546
+ pageRange: (args: {
547
+ from: number;
548
+ to: number;
549
+ total: number;
550
+ }) => string;
551
+ groupedAllRows: (total: number) => string;
552
+ pagingSuspendedHint: string;
553
+ previousPage: string;
554
+ nextPage: string;
555
+ noResults: string;
556
+ loading: string;
557
+ /** `aria-label` of an open cell editor's input. */
558
+ editCell: (column: string) => string;
559
+ /** cellConfirm's ✓ beside the input. */
560
+ confirmEdit: string;
561
+ /** cellConfirm's ✕ beside the input. */
562
+ cancelEdit: string;
563
+ /** The generated edit lane's name in the column manager. */
564
+ editColumnLabel: string;
565
+ /** The lane's pencil. */
566
+ editRow: string;
567
+ /** The lane's ✓ while a row edit is open. */
568
+ saveRow: string;
569
+ /** The lane's ✕ while a row edit is open. */
570
+ cancelRowEdit: string;
571
+ /** Save tooltip when field errors block the row, with no row message. */
572
+ editRowErrors: string;
573
+ /** `EditActions`' Save, with the dirty-row count. */
574
+ saveAllEdits: (rows: number) => string;
575
+ /** `EditActions`' Discard. */
576
+ discardAllEdits: string;
577
+ /** The entry row's ✓ — commit the add. */
578
+ confirmNewRow: string;
579
+ /** The entry row's ✕ — drop the entry. */
580
+ discardNewRow: string;
581
+ /** The lane's trash can. */
582
+ deleteRow: string;
583
+ /** The lane's undo on a row marked deleted (batch). */
584
+ restoreRow: string;
585
+ cellCount: (count: number) => string;
586
+ copy: string;
587
+ exportCsv: string;
588
+ includeHeaders: string;
589
+ selectColumnLabel: string;
590
+ selectAllRows: string;
591
+ selectRow: string;
592
+ selectGroup: string;
593
+ detailsColumnLabel: string;
594
+ showDetails: string;
595
+ hideDetails: string;
596
+ expandAllDetails: string;
597
+ collapseAllDetails: string;
598
+ groupColumnLabel: string;
599
+ blankGroupValue: string;
600
+ expandGroup: (label: string) => string;
601
+ collapseGroup: (label: string) => string;
602
+ };
603
+ /**
604
+ * What the `labels` option accepts: any subset, merged over the English
605
+ * defaults — so `{ noResults: "Inga rader" }` is a complete configuration.
606
+ */
607
+ type TMDataGridLabelsOverride = Partial<Omit<TMDataGridLabels, "operators">> & {
608
+ operators?: Partial<Record<TMDataGridFilterOperator, string>>;
609
+ };
610
+ /** The built-in defaults. Also the reference for what a preset must cover. */
611
+ declare const TMDATAGRID_LABELS_EN: TMDataGridLabels;
612
+ /** A partial override folded over the English defaults. */
613
+ declare function mergeLabels(override?: TMDataGridLabelsOverride): TMDataGridLabels;
614
+ //#endregion
615
+ //#region .types-tmp/core/filterControls.d.ts
616
+ /**
617
+ * What a filter control is handed — the value slot of one filter-panel row.
618
+ *
619
+ * The contract is value-only: the control reads `operator` to shape itself
620
+ * (a `between` pair renders two ends, an `equals` a single input) and calls
621
+ * `onChange` with the bare value; the grid composes the operator-aware
622
+ * `TMDataGridFilterValue` around it. A control never builds that wrapper and
623
+ * never writes the operator — `table` is the escape hatch for the rare
624
+ * control that must.
625
+ */
626
+ type TMDataGridFilterControlArgs = {
627
+ column: Column<TMDataGridFeatures, TMDataGridRowData, unknown>;
628
+ table: TMDataGridTable<TMDataGridRowData>;
629
+ /** The row's currently selected operator. Read-only for the control. */
630
+ operator: TMDataGridFilterOperator;
631
+ /** The bare filter value — never the `{ operator, value }` wrapper. */
632
+ value: string | ReadonlyArray<string>;
633
+ /** Writes the bare value; the grid pairs it with the current operator. */
634
+ onChange: (next: string | ReadonlyArray<string>) => void;
635
+ /**
636
+ * The column's options through `resolveColumnOptions`, pre-resolved for a
637
+ * column that declares `meta.options` or is select-shaped. Empty otherwise —
638
+ * a control wanting faceted values on other columns resolves them itself.
639
+ */
640
+ options: ReadonlyArray<TMDataGridOption>;
641
+ size: TMDataGridSize;
642
+ labels: TMDataGridLabels;
643
+ };
644
+ /**
645
+ * `meta.filterControl` — replaces the built-in value control for this column.
646
+ * Rendered as JSX, never invoked as a bare function, so hooks are legal
647
+ * inside. Define it at module scope so its identity is stable across renders.
648
+ */
649
+ type TMDataGridFilterControlComponent = ComponentType<TMDataGridFilterControlArgs>;
650
+ //#endregion
651
+ //#region .types-tmp/core/quickSearch.d.ts
652
+ /** How the quick search matches — see `quickSearchMode` on the hook options. */
653
+ type TMDataGridQuickSearchMode = "fuzzy" | "contains";
654
+ /** What {@link fuzzyGlobalFilterFn} records per column via `addMeta`. */
655
+ type FuzzyFilterMeta = {
656
+ fuzzyRank: RankingInfo;
657
+ };
658
+ /**
659
+ * Match-sorter ranking as the global filter: a row passes when a globally
660
+ * filterable column ranks above match-sorter's threshold — typos and skipped
661
+ * characters forgiven — and the rank is recorded for the ordering to read.
662
+ *
663
+ * TanStack stops probing a row's columns at the first passing one, so the
664
+ * recorded ranks cover the columns up to and including it; the best of those
665
+ * stands for the row. Good enough for a quick search: the first passing
666
+ * column is almost always the one the user is looking at.
667
+ */
668
+ declare function fuzzyGlobalFilterFn<TFeatures extends TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown, addMeta?: (meta: FuzzyFilterMeta) => void): boolean;
669
+ //#endregion
77
670
  //#region .types-tmp/core/persistence.d.ts
78
671
  type GridState = TableState<TMDataGridFeatures>;
79
672
  /**
@@ -124,22 +717,15 @@ type TMDataGridPersistence = {
124
717
  /** Parses a stored payload. Defaults to `JSON.parse`. */
125
718
  deserialize?: (value: string) => unknown;
126
719
  };
127
- //#endregion
128
- //#region .types-tmp/TMDataGridContext.d.ts
129
720
  /**
130
- * Row shape the chrome components work against. They only ever touch columns,
131
- * rows and cells generically, so the concrete row type is erased at the context
132
- * boundary — the same trick Mantine uses for its compound components.
721
+ * Version stamped into every stored payload, under a key no state slice can
722
+ * collide with. A payload whose version does not match is dropped whole: a
723
+ * migration would be guessing at a shape this code no longer knows, and the
724
+ * cost of dropping is one lost layout. Payloads written before versioning
725
+ * existed (≤0.4.0) have no stamp and are dropped the same way — the 1.0
726
+ * wave's one-time break, named in its changeset.
133
727
  */
134
- type TMDataGridRowData = Record<string, unknown>;
135
- type TMDataGridContextValue = TMDataGridApi<TMDataGridRowData> & {
136
- size: TMDataGridSize;
137
- /** Row height in px, already resolved from `size` and `meta.rowHeight`. */
138
- rowHeight: number;
139
- /** Mantine control size that pairs with `size`. */
140
- controlSize: TMDataGridSize;
141
- };
142
- declare function useTMDataGridContext(): TMDataGridContextValue;
728
+ declare const PERSIST_PAYLOAD_VERSION = 1;
143
729
  //#endregion
144
730
  //#region .types-tmp/core/capabilities.d.ts
145
731
  /**
@@ -172,9 +758,26 @@ type TMDataGridSelectionMode =
172
758
  "checkboxAndHighlight" |
173
759
  /** No selection at all — a row click only highlights. Master-detail. */
174
760
  "highlight";
761
+ /**
762
+ * How cells are selected — see `cellSelection` on {@link UseTMDataGridOptions}.
763
+ *
764
+ * A mode rather than a pair of booleans, for the reason
765
+ * {@link TMDataGridSelectionMode} is one: "cells can be selected" and "more
766
+ * than one at a time" are not independent, and a range that cannot be anchored
767
+ * anywhere is not a state worth being able to write down.
768
+ */
769
+ type TMDataGridCellSelectionMode =
770
+ /** No cell cursor at all. The body's tab stop stays on the row. */
771
+ "none" |
772
+ /** One cell takes the focus and the arrow keys move it. */
773
+ "single" |
774
+ /** As `"single"`, plus a rectangle: drag, Shift+click, Shift+arrows, Ctrl+C. */
775
+ "range";
175
776
  type TMDataGridFeatureFlags = {
176
777
  sorting: boolean;
177
778
  filtering: boolean;
779
+ /** Whether the quick search may filter — `enableGlobalFilter`. */
780
+ globalFiltering: boolean;
178
781
  hiding: boolean;
179
782
  pinning: boolean;
180
783
  resizing: boolean;
@@ -204,6 +807,17 @@ type TMDataGridFeatureFlags = {
204
807
  * what lets it coexist with a checkbox multi-selection.
205
808
  */
206
809
  highlightRow: boolean;
810
+ /**
811
+ * Whether cells can be selected at all. Off unless `cellSelection` asks for
812
+ * it — it takes the body's tab stop off the row and puts it on a cell, and
813
+ * reports the grid to assistive technology as a `grid` rather than a `table`,
814
+ * which is a different promise about what the keyboard does.
815
+ */
816
+ cellSelection: boolean;
817
+ /** Defaults to `"none"`. */
818
+ cellSelectionMode: TMDataGridCellSelectionMode;
819
+ /** Whether a rectangle of cells can be selected. Only under `"range"`. */
820
+ cellRangeSelection: boolean;
207
821
  /**
208
822
  * The one default-off flag: pagination must be asked for, either with the
209
823
  * grid's `enablePagination` or implicitly by declaring `manualPagination`.
@@ -222,8 +836,27 @@ type TMDataGridFeatureFlags = {
222
836
  * its own grouping can still say `enableGrouping: true` to override.
223
837
  */
224
838
  grouping: boolean;
839
+ /** Whether cells can be edited at all — `editMode` was set. */
840
+ editing: boolean;
841
+ /** The commit policy, or `null` while editing is off. */
842
+ editMode: TMDataGridEditMode | null;
843
+ /** The generated row-number gutter — `enableRowNumbers`. Off by default. */
844
+ rowNumbers: boolean;
845
+ /**
846
+ * Whether rows can be pinned to the top or bottom edge — `enableRowPinning`,
847
+ * boolean or per-row predicate. Off by default: pinning has no built-in
848
+ * gesture, so a grid that never calls `row.pin()` has nothing to gain from
849
+ * the body watching the state.
850
+ */
851
+ rowPinning: boolean;
852
+ /**
853
+ * Whether cells highlight the matched text while a contains-family filter
854
+ * or the quick search is active — `enableMatchHighlighting`. Off by
855
+ * default, so a grid that has not asked pays nothing per cell.
856
+ */
857
+ matchHighlighting: boolean;
225
858
  };
226
- declare function readFeatureFlags<TData extends RowData>(options: Pick<UseTMDataGridOptions<TData>, "enableSorting" | "enableColumnFilters" | "enableHiding" | "enableColumnPinning" | "enableColumnResizing" | "enableColumnOrdering" | "enableRowSelection" | "enableMultiRowSelection" | "selectionMode" | "showSelectedBackground" | "enablePagination" | "manualPagination" | "enableGrouping">): TMDataGridFeatureFlags;
859
+ 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;
227
860
  /**
228
861
  * What one column's header may offer.
229
862
  *
@@ -257,25 +890,202 @@ type TMDataGridCapabilities = {
257
890
  canGroupAny: boolean;
258
891
  canSelectRows: boolean;
259
892
  canPaginate: boolean;
893
+ /** At least one leaf column takes part in the global quick search. */
894
+ canSearch: boolean;
260
895
  };
261
896
  declare function getGridCapabilities(table: TMDataGridTable<TMDataGridRowData>, features: TMDataGridFeatureFlags): TMDataGridCapabilities;
262
897
  //#endregion
898
+ //#region .types-tmp/core/cellNavigation.d.ts
899
+ /**
900
+ * Which cell has the focus, by id rather than by position.
901
+ *
902
+ * Ids, because every other thing the grid does moves cells around: sorting
903
+ * reorders rows, filtering removes them, dragging a header reorders columns. A
904
+ * coordinate pair would silently come to mean a different cell after any of
905
+ * them, while a pair of ids either still resolves or does not resolve at all —
906
+ * and "does not resolve" is a state the grid can handle honestly.
907
+ *
908
+ * Indices are what navigation is actually computed in, so they are resolved
909
+ * from the ids on each keystroke and turned straight back. See resolveCellMove.
910
+ */
911
+ type TMDataGridCellPosition = {
912
+ rowId: string;
913
+ columnId: string;
914
+ };
915
+ /** Where the focused cell sits in the rows and columns on screen. */
916
+ type TMDataGridCellCoords = {
917
+ rowIndex: number;
918
+ columnIndex: number;
919
+ };
920
+ type ResolveCellMoveArgs = {
921
+ /** `KeyboardEvent.key`. */
922
+ key: string;
923
+ /** Ctrl or Cmd — Home and End jump to the corner rather than the row end. */
924
+ ctrlKey: boolean;
925
+ from: TMDataGridCellCoords;
926
+ rowCount: number;
927
+ columnCount: number;
928
+ /**
929
+ * How far PageUp and PageDown travel: one viewport of rows. Passed in rather
930
+ * than assumed, since only the body knows how tall it is.
931
+ */
932
+ pageRows: number;
933
+ };
934
+ /**
935
+ * The next cell for a navigation key, or `null` when the key is not one.
936
+ *
937
+ * Moves clamp at the edges instead of wrapping. Wrapping suits a menu, where
938
+ * the items are a short ring; a grid is a coordinate space, and a Right at the
939
+ * last column that lands on the first column of the next row loses the one
940
+ * thing arrow keys are for — knowing where you will end up without looking.
941
+ *
942
+ * A clamped move returns the position it started from rather than `null`. The
943
+ * caller still needs to know the key was handled: an arrow at the last row must
944
+ * not fall through to the scroll container, which would scroll the body out
945
+ * from under a focus that did not move.
946
+ */
947
+ declare function resolveCellMove({ key, ctrlKey, from, rowCount, columnCount, pageRows }: ResolveCellMoveArgs): TMDataGridCellCoords | null;
948
+ /** Whether two positions address the same cell. `null` equals only `null`. */
949
+ declare function isSameCell(a: TMDataGridCellPosition | null, b: TMDataGridCellPosition | null): boolean;
950
+ //#endregion
951
+ //#region .types-tmp/core/cellRange.d.ts
952
+ /**
953
+ * A selected rectangle of cells, held as the two cells that span it.
954
+ *
955
+ * Two corners rather than a list of cells, because a range is a gesture, not a
956
+ * set: dragging over 40 columns of a 100k-row grid would otherwise build — and
957
+ * rebuild, on every mouse move — a list with millions of entries in it. Two
958
+ * positions describe the same thing and cost nothing to extend.
959
+ *
960
+ * `anchor` is where the gesture started and stays put; `focus` is the end that
961
+ * moves. Which of the two is top-left depends on the direction it was dragged,
962
+ * so nothing here assumes an order — see {@link resolveRangeBounds}.
963
+ */
964
+ type TMDataGridCellRange = {
965
+ anchor: TMDataGridCellPosition;
966
+ focus: TMDataGridCellPosition;
967
+ };
968
+ /** The rectangle a range covers, in row and column indices, both ends included. */
969
+ type TMDataGridRangeBounds = {
970
+ top: number;
971
+ bottom: number;
972
+ left: number;
973
+ right: number;
974
+ };
975
+ type ResolveRangeBoundsArgs = {
976
+ range: TMDataGridCellRange | null;
977
+ /** Index of a row id among the rows on screen, or `-1`. */
978
+ rowIndexOf: (rowId: string) => number;
979
+ columnIndexOf: (columnId: string) => number;
980
+ };
981
+ /**
982
+ * Turns a range into the rectangle to paint and copy, or `null` when either
983
+ * corner no longer exists.
984
+ *
985
+ * A corner goes missing whenever a filter drops its row or a column is hidden,
986
+ * and the honest answer then is that there is no rectangle — better than
987
+ * guessing at a replacement corner and quietly copying cells the user never
988
+ * selected. The range itself is left alone: clearing it here would throw away
989
+ * a selection that comes straight back when the filter is lifted.
990
+ */
991
+ declare function resolveRangeBounds({ range, rowIndexOf, columnIndexOf }: ResolveRangeBoundsArgs): TMDataGridRangeBounds | null;
992
+ /** Whether a cell is inside the rectangle. */
993
+ declare function isWithinBounds(bounds: TMDataGridRangeBounds | null, rowIndex: number, columnIndex: number): boolean;
994
+ /** How many cells the rectangle covers. `0` for no range at all. */
995
+ declare function boundsCellCount(bounds: TMDataGridRangeBounds | null): number;
996
+ /**
997
+ * Which edges of the rectangle a cell sits on, for the outline.
998
+ *
999
+ * The border is drawn per cell rather than as one box over the top, because the
1000
+ * body is a scrolling CSS grid with sticky columns in it: an overlay would have
1001
+ * to be positioned against a moving target and would still be wrong the moment
1002
+ * a pinned lane slid over it. Four booleans per cell need no positioning at all.
1003
+ */
1004
+ declare function boundsEdges(bounds: TMDataGridRangeBounds | null, rowIndex: number, columnIndex: number): {
1005
+ top: boolean;
1006
+ bottom: boolean;
1007
+ left: boolean;
1008
+ right: boolean;
1009
+ } | null;
1010
+ //#endregion
263
1011
  //#region .types-tmp/useTMDataGrid.d.ts
264
1012
  /** Per-column configuration the TMDataGrid chrome reads. */
265
1013
  type TMDataGridColumnMeta = {
266
1014
  /** Name shown in menus and the column manager. Falls back to a string header. */
267
1015
  label?: string;
268
- /** Drives which filter operators are offered. Defaults to `"string"`. */
1016
+ /**
1017
+ * Drives which filter operators are offered and, once editing is on, which
1018
+ * editor the cell opens. Defaults to `"string"`.
1019
+ */
269
1020
  type?: TMDataGridColumnType;
1021
+ /**
1022
+ * The choices of a `select` / `multiSelect` column — one declaration feeding
1023
+ * the filter panel's value control and the cell editor alike. A static
1024
+ * array, `"faceted"` (the distinct values present in the data), or a
1025
+ * function of the table, column and — for editors — the row. See
1026
+ * {@link TMDataGridOptionsSource}.
1027
+ */
1028
+ options?: TMDataGridOptionsSource;
270
1029
  /** Share of the leftover width this column claims. Defaults to `1`. */
271
1030
  flex?: number;
272
1031
  align?: "left" | "right" | "center";
1032
+ /**
1033
+ * Size the column to its widest mounted content once, after the first rows
1034
+ * render — unless a persisted or user-set width already covers it. The same
1035
+ * measurement as double-clicking the resize divider; see `autosizeColumn`.
1036
+ */
1037
+ autoSize?: boolean;
273
1038
  /**
274
1039
  * `false` keeps the column where it is: no header dragging, no move items.
275
1040
  * Column ordering is the one feature TanStack defines no column option for,
276
1041
  * so its switch lives here rather than on the column definition.
277
1042
  */
278
1043
  enableOrdering?: boolean;
1044
+ /**
1045
+ * The operator a fresh filter on this column starts with, instead of the
1046
+ * type's default — a salary column can open on `"between"`. Must be one of
1047
+ * the type's own operators.
1048
+ */
1049
+ defaultFilterOperator?: TMDataGridFilterOperator;
1050
+ /**
1051
+ * Replaces the built-in value control in this column's filter-panel row. A
1052
+ * component rendered as JSX — hooks are legal inside — receiving the
1053
+ * value-only contract: it reads the current operator, writes the bare
1054
+ * value, and the grid composes the stored filter around it. Define it at
1055
+ * module scope. See {@link TMDataGridFilterControlArgs}.
1056
+ */
1057
+ filterControl?: TMDataGridFilterControlComponent;
1058
+ /**
1059
+ * Whether this column's cells take edits, once `editMode` is on. `false`
1060
+ * switches the column off outright; a predicate decides per row. Defaults
1061
+ * to editable for any column that maps to a field — see {@link editField}.
1062
+ */
1063
+ editable?: boolean | ((row: Row<TMDataGridFeatures, TMDataGridRowData>) => boolean);
1064
+ /**
1065
+ * The data path this column edits, when it is not the `accessorKey` — the
1066
+ * only way a column built on `accessorFn` becomes editable. Dot paths reach
1067
+ * into nested records: `"address.city"`.
1068
+ */
1069
+ editField?: string;
1070
+ /**
1071
+ * Field-level validators, in TanStack Form's own vocabulary. A bare Zod
1072
+ * schema (or any Standard Schema, or a plain function) means
1073
+ * `{ onChange: it }`; the object form takes every trigger Form defines.
1074
+ *
1075
+ * ```tsx
1076
+ * meta: { validate: z.string().min(2, "Too short") }
1077
+ * meta: { validate: { onBlur: z.string().email() } }
1078
+ * ```
1079
+ */
1080
+ validate?: TMDataGridFieldValidate;
1081
+ /**
1082
+ * Replaces the built-in editor for this column. A component rendered as
1083
+ * JSX — hooks are legal inside — receiving the live TanStack Form `field`
1084
+ * API plus the table context, the same contract the built-ins fill. Define
1085
+ * it at module scope so its identity is stable across renders. See
1086
+ * {@link TMDataGridEditorArgs}.
1087
+ */
1088
+ editor?: TMDataGridEditorComponent;
279
1089
  };
280
1090
  /** Grid-wide configuration passed through `options.meta`. */
281
1091
  type TMDataGridTableMeta = {
@@ -307,6 +1117,7 @@ declare const tmDataGridFeatures: {
307
1117
  columnFacetingFeature: import("@tanstack/table-core").TableFeature;
308
1118
  columnGroupingFeature: import("@tanstack/table-core").TableFeature;
309
1119
  rowExpandingFeature: import("@tanstack/table-core").TableFeature;
1120
+ rowPinningFeature: import("@tanstack/table-core").TableFeature;
310
1121
  filteredRowModel: (table: Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
311
1122
  groupedRowModel: (table: Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
312
1123
  sortedRowModel: (table: Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
@@ -316,50 +1127,51 @@ declare const tmDataGridFeatures: {
316
1127
  facetedMinMaxValues: (table: Table<import("@tanstack/table-core").TableFeatures, any>, columnId: string) => () => undefined | [number, number];
317
1128
  facetedUniqueValues: (table: Table<import("@tanstack/table-core").TableFeatures, any>, columnId: string) => () => Map<any, number>;
318
1129
  filterFns: {
319
- arrIncludes: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean) & {
1130
+ arrIncludes: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean) & {
320
1131
  autoRemove: (val: any) => boolean;
321
1132
  };
322
- arrIncludesAll: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean) & {
1133
+ arrIncludesAll: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean) & {
323
1134
  autoRemove: (val: any) => boolean;
324
1135
  };
325
- arrHas: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean;
326
- arrIncludesSome: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean) & {
1136
+ arrHas: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean;
1137
+ arrIncludesSome: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: Array<unknown>) => boolean) & {
327
1138
  autoRemove: (val: any) => boolean;
328
1139
  };
329
- between: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
1140
+ between: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
330
1141
  autoRemove: (val: any) => boolean;
331
1142
  };
332
- betweenInclusive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
1143
+ betweenInclusive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
333
1144
  autoRemove: (val: any) => boolean;
334
1145
  };
335
- equals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
1146
+ equals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
336
1147
  autoRemove: (val: any) => boolean;
337
1148
  };
338
- equalsString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
1149
+ equalsString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
339
1150
  autoRemove: (val: any) => boolean;
340
1151
  };
341
- inNumberRange: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: [number, number]) => boolean) & {
1152
+ inNumberRange: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: [number, number]) => boolean) & {
342
1153
  resolveFilterValue: (val: [any, any]) => readonly [number, number];
343
1154
  autoRemove: (val: any) => boolean;
344
1155
  };
345
- includesString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
1156
+ includesString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
346
1157
  autoRemove: (val: any) => boolean;
347
1158
  };
348
- includesStringSensitive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
1159
+ includesStringSensitive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
349
1160
  autoRemove: (val: any) => boolean;
350
1161
  };
351
- weakEquals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
1162
+ weakEquals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, columnId: string, filterValue: unknown) => boolean) & {
352
1163
  autoRemove: (val: any) => boolean;
353
1164
  };
354
1165
  tmDataGrid: typeof tmDataGridFilterFn;
1166
+ tmDataGridFuzzy: typeof fuzzyGlobalFilterFn;
355
1167
  };
356
1168
  sortFns: {
357
- alphanumeric: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData>, rowB: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string) => number;
358
- alphanumericCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData>, rowB: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string) => number;
359
- basic: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData>, rowB: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
360
- datetime: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData>, rowB: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
361
- text: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData>, rowB: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
362
- textCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData>, rowB: import("@tanstack/table-core").Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
1169
+ alphanumeric: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: Row<TFeatures, TData>, rowB: Row<TFeatures, TData>, columnId: string) => number;
1170
+ alphanumericCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: Row<TFeatures, TData>, rowB: Row<TFeatures, TData>, columnId: string) => number;
1171
+ basic: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: Row<TFeatures, TData>, rowB: Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
1172
+ datetime: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: Row<TFeatures, TData>, rowB: Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
1173
+ text: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: Row<TFeatures, TData>, rowB: Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
1174
+ textCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData extends RowData>(rowA: Row<TFeatures, TData>, rowB: Row<TFeatures, TData>, columnId: string) => 0 | 1 | -1;
363
1175
  };
364
1176
  aggregationFns: {
365
1177
  sum: typeof import("@tanstack/table-core").aggregationFn_sum;
@@ -391,6 +1203,7 @@ declare function createTMDataGridColumnHelper<TData extends RowData>(): import("
391
1203
  columnFacetingFeature: import("@tanstack/table-core").TableFeature;
392
1204
  columnGroupingFeature: import("@tanstack/table-core").TableFeature;
393
1205
  rowExpandingFeature: import("@tanstack/table-core").TableFeature;
1206
+ rowPinningFeature: import("@tanstack/table-core").TableFeature;
394
1207
  filteredRowModel: (table: Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
395
1208
  groupedRowModel: (table: Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
396
1209
  sortedRowModel: (table: Table<any, any>) => () => import("@tanstack/table-core").RowModel<any, any>;
@@ -400,50 +1213,51 @@ declare function createTMDataGridColumnHelper<TData extends RowData>(): import("
400
1213
  facetedMinMaxValues: (table: Table<import("@tanstack/table-core").TableFeatures, any>, columnId: string) => () => undefined | [number, number];
401
1214
  facetedUniqueValues: (table: Table<import("@tanstack/table-core").TableFeatures, any>, columnId: string) => () => Map<any, number>;
402
1215
  filterFns: {
403
- arrIncludes: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean) & {
1216
+ arrIncludes: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean) & {
404
1217
  autoRemove: (val: any) => boolean;
405
1218
  };
406
- arrIncludesAll: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean) & {
1219
+ arrIncludesAll: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean) & {
407
1220
  autoRemove: (val: any) => boolean;
408
1221
  };
409
- arrHas: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean;
410
- arrIncludesSome: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean) & {
1222
+ arrHas: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean;
1223
+ arrIncludesSome: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: Array<unknown>) => boolean) & {
411
1224
  autoRemove: (val: any) => boolean;
412
1225
  };
413
- between: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
1226
+ between: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
414
1227
  autoRemove: (val: any) => boolean;
415
1228
  };
416
- betweenInclusive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
1229
+ betweenInclusive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValues: [unknown, unknown]) => boolean) & {
417
1230
  autoRemove: (val: any) => boolean;
418
1231
  };
419
- equals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
1232
+ equals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
420
1233
  autoRemove: (val: any) => boolean;
421
1234
  };
422
- equalsString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
1235
+ equalsString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
423
1236
  autoRemove: (val: any) => boolean;
424
1237
  };
425
- inNumberRange: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: [number, number]) => boolean) & {
1238
+ inNumberRange: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: [number, number]) => boolean) & {
426
1239
  resolveFilterValue: (val: [any, any]) => readonly [number, number];
427
1240
  autoRemove: (val: any) => boolean;
428
1241
  };
429
- includesString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
1242
+ includesString: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
430
1243
  autoRemove: (val: any) => boolean;
431
1244
  };
432
- includesStringSensitive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
1245
+ includesStringSensitive: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
433
1246
  autoRemove: (val: any) => boolean;
434
1247
  };
435
- weakEquals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
1248
+ weakEquals: (<TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(row: Row<TFeatures, TData_1>, columnId: string, filterValue: unknown) => boolean) & {
436
1249
  autoRemove: (val: any) => boolean;
437
1250
  };
438
1251
  tmDataGrid: typeof tmDataGridFilterFn;
1252
+ tmDataGridFuzzy: typeof fuzzyGlobalFilterFn;
439
1253
  };
440
1254
  sortFns: {
441
- alphanumeric: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData_1>, rowB: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string) => number;
442
- alphanumericCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData_1>, rowB: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string) => number;
443
- basic: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData_1>, rowB: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
444
- datetime: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData_1>, rowB: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
445
- text: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData_1>, rowB: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
446
- textCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: import("@tanstack/table-core").Row<TFeatures, TData_1>, rowB: import("@tanstack/table-core").Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
1255
+ alphanumeric: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: Row<TFeatures, TData_1>, rowB: Row<TFeatures, TData_1>, columnId: string) => number;
1256
+ alphanumericCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: Row<TFeatures, TData_1>, rowB: Row<TFeatures, TData_1>, columnId: string) => number;
1257
+ basic: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: Row<TFeatures, TData_1>, rowB: Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
1258
+ datetime: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: Row<TFeatures, TData_1>, rowB: Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
1259
+ text: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: Row<TFeatures, TData_1>, rowB: Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
1260
+ textCaseSensitive: <TFeatures extends import("@tanstack/table-core").TableFeatures, TData_1 extends RowData>(rowA: Row<TFeatures, TData_1>, rowB: Row<TFeatures, TData_1>, columnId: string) => 0 | 1 | -1;
447
1261
  };
448
1262
  aggregationFns: {
449
1263
  sum: typeof import("@tanstack/table-core").aggregationFn_sum;
@@ -459,6 +1273,13 @@ declare function createTMDataGridColumnHelper<TData extends RowData>(): import("
459
1273
  tableMeta: TMDataGridTableMeta;
460
1274
  columnMeta: TMDataGridColumnMeta;
461
1275
  }, TData>;
1276
+ /** What the `renderDetails` render prop is handed for an expanded row. */
1277
+ type TMDataGridDetailsArgs<TData extends RowData> = {
1278
+ row: Row<TMDataGridFeatures, TData>;
1279
+ table: TMDataGridTable<TData>;
1280
+ };
1281
+ /** Builds the panel shown underneath an expanded row. See `renderDetails`. */
1282
+ type TMDataGridDetailsRenderer<TData extends RowData> = (args: TMDataGridDetailsArgs<TData>) => ReactNode;
462
1283
  /**
463
1284
  * Chrome state that is *not* table state: which panels are open, and which
464
1285
  * column opened the filter panel. Kept in a TanStack Store so consumers can
@@ -488,6 +1309,25 @@ type TMDataGridUiState = {
488
1309
  highlightedRowId: string | null;
489
1310
  /** The pivot a shift-click extends from. See resolveRowSelectionClick. */
490
1311
  selectionAnchorRowId: string | null;
1312
+ /**
1313
+ * The cell the keyboard is on, under `enableCellSelection`. `null` until the
1314
+ * grid is first entered — and again whenever a consumer clears it.
1315
+ *
1316
+ * The state is the source of truth and DOM focus follows it, not the other
1317
+ * way around: under virtualization the cell it names is often not mounted,
1318
+ * which is exactly what a coordinate has to survive. Held as ids for the
1319
+ * same reason — see {@link TMDataGridCellPosition}.
1320
+ */
1321
+ focusedCell: TMDataGridCellPosition | null;
1322
+ /**
1323
+ * The selected rectangle, under `cellSelection: "range"`. Held as the two
1324
+ * cells that span it — see {@link TMDataGridCellRange}.
1325
+ *
1326
+ * Always covers the focused cell: every gesture that moves the focus either
1327
+ * extends the rectangle or collapses it onto the new cell, so the two never
1328
+ * describe different places.
1329
+ */
1330
+ cellRange: TMDataGridCellRange | null;
491
1331
  };
492
1332
  type TMDataGridUiActions = {
493
1333
  openFilterPanel: (columnId?: string | null) => void;
@@ -502,16 +1342,190 @@ type TMDataGridUiActions = {
502
1342
  */
503
1343
  setHighlightedRow: (rowId: string | null) => void;
504
1344
  setSelectionAnchor: (rowId: string | null) => void;
1345
+ /**
1346
+ * Moves the focused cell, or clears it with `null`. DOM focus follows while
1347
+ * the grid holds it — so this both moves the keyboard and, when the row is
1348
+ * off screen, scrolls it into view. Called for every arrow key, and available
1349
+ * for a consumer putting the keyboard somewhere itself.
1350
+ */
1351
+ setFocusedCell: (cell: TMDataGridCellPosition | null) => void;
1352
+ /**
1353
+ * Sets the selected rectangle, or clears it with `null`. Does not move the
1354
+ * focused cell — the two are set together by the gestures that change both,
1355
+ * which is what keeps "extend the selection" and "move the cursor" separable.
1356
+ */
1357
+ setCellRange: (range: TMDataGridCellRange | null) => void;
505
1358
  };
506
1359
  type TMDataGridUiStore = Store<TMDataGridUiState, TMDataGridUiActions>;
1360
+ /** Where a scrolled-to row lands in the viewport. TanStack's own alignments. */
1361
+ type TMDataGridScrollAlign = "auto" | "start" | "center" | "end";
1362
+ type TMDataGridScrollToRowArgs = {
1363
+ /** The row's id, as `getRowId` produced it. */
1364
+ rowId: string;
1365
+ /** Defaults to `"auto"` — the nearest edge, leaving a visible row alone. */
1366
+ align?: TMDataGridScrollAlign;
1367
+ };
1368
+ /** @internal The body's scroll implementation. See `scrollToRow`. */
1369
+ type TMDataGridScroller = (args: TMDataGridScrollToRowArgs) => boolean;
507
1370
  /** What `useTMDataGrid` returns — spread straight onto `<TMDataGrid />`. */
508
1371
  type TMDataGridApi<TData extends RowData> = {
509
1372
  table: TMDataGridTable<TData>;
510
1373
  ui: TMDataGridUiStore;
1374
+ /**
1375
+ * The edit engine — open forms, dirty/error projections, and the verbs
1376
+ * (`begin`, `commit`, `cancel`, `submitAll`). `edit.getForm(rowId)` hands
1377
+ * out the same TanStack Form the inline editors write through, so a drawer
1378
+ * or detail panel can share a row's draft. Inert until `editMode` is set.
1379
+ */
1380
+ edit: TMDataGridEditApi;
511
1381
  /** Table-level feature switches, re-read from options on every render. */
512
1382
  features: TMDataGridFeatureFlags;
1383
+ /** Every string the chrome renders, `labels` merged over the English defaults. */
1384
+ labels: TMDataGridLabels;
1385
+ /** The detail renderer, when row details are on. See `renderDetails`. */
1386
+ renderDetails?: TMDataGridDetailsRenderer<TData>;
1387
+ /** Detail estimate in px: the option, or {@link DEFAULT_DETAILS_EST_HEIGHT}. */
1388
+ renderDetailsEstHeight: number;
1389
+ /** Virtualizer overscan: the option, or {@link DEFAULT_OVERSCAN}. */
1390
+ overscan: number;
1391
+ /**
1392
+ * Puts the settings state — visibility, order, widths, pinning, grouping —
1393
+ * back to what a first visit with clean storage would have shown: the
1394
+ * consumer's `initialState` plus the structural lanes. With persistence
1395
+ * configured the reset writes through to storage like any other change.
1396
+ *
1397
+ * This, not TanStack's `resetColumnX()` family, is the reset for a
1398
+ * persisted grid: those reset to `initialState`, and the grid bakes the
1399
+ * restored payload into `initialState` at mount — they would "reset" to
1400
+ * the very layout being discarded.
1401
+ */
1402
+ resetSettings: () => void;
1403
+ /**
1404
+ * Scrolls a row into view. The grid is always virtualized, so a row far down
1405
+ * the list has no element to scroll to — this moves the virtualizer instead,
1406
+ * which is the only thing that can put one there.
1407
+ *
1408
+ * ```ts
1409
+ * grid.scrollToRow({ rowId: "42", align: "center" });
1410
+ * ```
1411
+ *
1412
+ * Answers whether the row could be reached. `false` means it is not in the
1413
+ * current view at all — filtered out, on another page, or an id that matches
1414
+ * no row — and nothing scrolled. A pinned row answers `true` without
1415
+ * scrolling: it is already parked at an edge.
1416
+ *
1417
+ * Identity is stable, so it is safe in a dependency array.
1418
+ */
1419
+ scrollToRow: (args: TMDataGridScrollToRowArgs) => boolean;
1420
+ /**
1421
+ * @internal Wiring for `TMDataGrid.Table`, which owns the virtualizer and
1422
+ * fills this in. Not part of the supported surface.
1423
+ */
1424
+ scrollerRef: MutableRefObject<TMDataGridScroller>;
1425
+ };
1426
+ /** The editing callbacks every mode shares. See {@link TMDataGridEditingOptions}. */
1427
+ type TMDataGridEditingCallbacks<TData extends RowData> = {
1428
+ /**
1429
+ * `getRowId` stops being optional once editing is on: the forms are keyed
1430
+ * by row id and live outside the DOM, and the index fallback points at a
1431
+ * different record after any sort.
1432
+ */
1433
+ getRowId: NonNullable<TableOptions<TMDataGridFeatures, TData>["getRowId"]>;
1434
+ /**
1435
+ * Form-level validators for the whole editing row — where cross-field
1436
+ * rules live. TanStack Form's own vocabulary, Standard Schema included:
1437
+ *
1438
+ * ```tsx
1439
+ * rowValidators: {
1440
+ * onSubmit: z.object({ salary: z.number().positive() })
1441
+ * .refine((r) => r.status !== "Terminated" || r.salary === 0, {
1442
+ * message: "A terminated employee has no salary",
1443
+ * }),
1444
+ * }
1445
+ * ```
1446
+ *
1447
+ * Pathed issues land on the matching columns; pathless ones on the row.
1448
+ */
1449
+ rowValidators?: TMDataGridRowValidators;
1450
+ /** Rows the pencil skips — `false` keeps a row read-only in every mode. */
1451
+ isRowEditable?: (row: Row<TMDataGridFeatures, TData>) => boolean;
1452
+ /**
1453
+ * Called when an edit commits. The grid never mutates `data`: apply the
1454
+ * change and let the new data arrive back through `data` as always. The
1455
+ * engine drops the draft only when this resolves — a slow save keeps the
1456
+ * draft visible with a busy marker — and a rejection keeps the form open
1457
+ * with the error on the row.
1458
+ *
1459
+ * `changes` is the per-field diff (one entry in cell mode) for consumers
1460
+ * who PATCH; `value` is the whole edited row for those who save records.
1461
+ */
1462
+ onEditCommit?: (args: TMDataGridEditCommitArgs<TData>) => void | Promise<void>;
1463
+ /**
1464
+ * Seed values for `edit.addRow()` — the entry row's starting point. A
1465
+ * function is called per added row (fresh timestamps, empty arrays).
1466
+ */
1467
+ newRowDefaults?: TData | (() => TData);
1468
+ /**
1469
+ * Called when an entry row commits: `Enter` or the lane's ✓ under the
1470
+ * immediate modes, `submitAll` under batch. Create the record and let it
1471
+ * arrive back through `data`; the engine's `tempId` never leaves the grid.
1472
+ */
1473
+ onRowAdd?: (args: TMDataGridRowAddArgs<TData>) => void | Promise<void>;
1474
+ /**
1475
+ * Called by `edit.deleteRow` under the immediate modes — confirmation, if
1476
+ * any, belongs in here. Under batch, deletions accumulate in
1477
+ * `edit.state.deletedRowIds` instead and are reported by `submitAll`.
1478
+ * Setting this also puts the trash can in the edit lane.
1479
+ */
1480
+ onRowDelete?: (args: TMDataGridRowDeleteArgs<TData>) => void | Promise<void>;
513
1481
  };
514
- type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridFeatures, TData>, "features"> & {
1482
+ /**
1483
+ * The editing options travel together, and the type states it: without
1484
+ * `editMode` none of them has anything to act on, so passing one is a
1485
+ * compile error rather than a dead option; with it, `getRowId` becomes
1486
+ * required; and `onEditCommitBatch` exists only under `"batch"` — the one
1487
+ * mode whose `submitAll` calls it.
1488
+ *
1489
+ * `editMode` itself turns cell editing on and picks how commits happen. Off
1490
+ * by default.
1491
+ *
1492
+ * | Mode | Commit | Cancel |
1493
+ * | ---- | ------ | ------ |
1494
+ * | `"cell"` | Enter, Tab, blur — Sheets | Escape |
1495
+ * | `"cellConfirm"` | ✓ or Enter only; blur keeps the draft | ✕ or Escape |
1496
+ * | `"row"` | Save in the edit lane, or Ctrl+Enter | Cancel, or Escape |
1497
+ * | `"batch"` | `edit.submitAll()` | `edit.cancelAll()` |
1498
+ *
1499
+ * One TanStack Form per editing row; drafts survive scrolling because the
1500
+ * forms live outside the DOM, keyed by row id. Which columns edit, and with
1501
+ * what, is declared per column: `meta.type` picks the built-in editor,
1502
+ * `meta.validate` its validators, `meta.editable` / `meta.editor` the
1503
+ * overrides.
1504
+ */
1505
+ type TMDataGridEditingOptions<TData extends RowData> = (TMDataGridEditingCallbacks<TData> & {
1506
+ editMode: "batch";
1507
+ /**
1508
+ * Batch mode's save, called once by `edit.submitAll()` with every
1509
+ * valid dirty row. Without it, `submitAll` falls back to the per-row
1510
+ * {@link TMDataGridEditingCallbacks.onEditCommit} loop. Rows failing
1511
+ * validation stay open either way; a rejection keeps every draft.
1512
+ */
1513
+ onEditCommitBatch?: (args: TMDataGridEditCommitBatchArgs<TData>) => void | Promise<void>;
1514
+ }) | (TMDataGridEditingCallbacks<TData> & {
1515
+ editMode: Exclude<TMDataGridEditMode, "batch">;
1516
+ /** Only `"batch"`'s `submitAll` ever calls it — see the other branch. */
1517
+ onEditCommitBatch?: never;
1518
+ }) | {
1519
+ editMode?: never;
1520
+ rowValidators?: never;
1521
+ isRowEditable?: never;
1522
+ onEditCommit?: never;
1523
+ onEditCommitBatch?: never;
1524
+ newRowDefaults?: never;
1525
+ onRowAdd?: never;
1526
+ onRowDelete?: never;
1527
+ };
1528
+ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridFeatures, TData>, "features"> & TMDataGridEditingOptions<TData> & {
515
1529
  /**
516
1530
  * Restore and persist table state across mounts. Two keys, because the two
517
1531
  * kinds of state have different lifetimes — see {@link TMDataGridPersistence}.
@@ -520,6 +1534,20 @@ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridF
520
1534
  * dependency of the subscription that writes back.
521
1535
  */
522
1536
  persist?: TMDataGridPersistence;
1537
+ /**
1538
+ * Overrides for the grid's strings — menu items, panels, the pager, and
1539
+ * every `aria-label`. Any subset, merged over the English defaults; a full
1540
+ * Swedish dictionary ships as `TMDATAGRID_LABELS_SV`.
1541
+ *
1542
+ * ```tsx
1543
+ * useTMDataGrid({ data, columns, labels: TMDATAGRID_LABELS_SV });
1544
+ * useTMDataGrid({ data, columns, labels: { noResults: "Inga rader" } });
1545
+ * ```
1546
+ *
1547
+ * Keep the object referentially stable (module scope or `useMemo`) — the
1548
+ * chrome re-renders when its identity changes.
1549
+ */
1550
+ labels?: TMDataGridLabelsOverride;
523
1551
  /**
524
1552
  * Header drag-and-drop and the move items in the column menu. Defaults to
525
1553
  * `true`.
@@ -539,6 +1567,28 @@ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridF
539
1567
  * no extra flag.
540
1568
  */
541
1569
  enablePagination?: boolean;
1570
+ /**
1571
+ * The row-number gutter: a generated lane, outermost left, numbering the
1572
+ * rows of the current view — sorted, filtered, continuing across pages,
1573
+ * with group rows unnumbered. Off by default.
1574
+ */
1575
+ enableRowNumbers?: boolean;
1576
+ /**
1577
+ * How the quick search (`TMDataGrid.Search`) matches. `"fuzzy"` — the
1578
+ * default — forgives typos and skipped characters, and while it is the
1579
+ * only thing narrowing the grid (no sort, no grouping) the rows order by
1580
+ * match quality, best first. `"contains"` is plain substring matching.
1581
+ * An explicit `globalFilterFn` overrides both.
1582
+ */
1583
+ quickSearchMode?: TMDataGridQuickSearchMode;
1584
+ /**
1585
+ * Highlights the matched text in cells while a contains-family column
1586
+ * filter or the quick search is active. Default-rendered cells only — a
1587
+ * column with its own `cell` renderer opts out by existing; a fuzzy
1588
+ * typo-match with no contiguous occurrence shows no highlight. Off by
1589
+ * default.
1590
+ */
1591
+ enableMatchHighlighting?: boolean;
542
1592
  /**
543
1593
  * How rows are selected. Defaults to `"checkbox"`.
544
1594
  *
@@ -602,6 +1652,113 @@ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridF
602
1652
  * Fires for `ui.actions.setHighlightedRow` too, not only for clicks.
603
1653
  */
604
1654
  onHighlightedRowChange?: (rowId: string | null) => void;
1655
+ /**
1656
+ * How cells are selected. Defaults to `"none"`.
1657
+ *
1658
+ * | Mode | What it gives |
1659
+ * | ---- | ------------- |
1660
+ * | `"none"` | nothing; the body's tab stop stays on the row |
1661
+ * | `"single"` | one focused cell, moved with the arrow keys |
1662
+ * | `"range"` | as `"single"`, plus a rectangle of cells |
1663
+ *
1664
+ * Under either live mode:
1665
+ *
1666
+ * | Key | Moves to |
1667
+ * | --- | --- |
1668
+ * | Arrows | the neighbouring cell, clamped at the edges |
1669
+ * | PageUp / PageDown | one viewport of rows |
1670
+ * | Home / End | first / last cell of the row |
1671
+ * | Ctrl+Home / Ctrl+End | first / last cell of the grid |
1672
+ * | Enter or F2 | into the cell — the checkbox, link or button it holds |
1673
+ * | Escape | back out to the cell |
1674
+ * | Space | selects the row, as it does in row-selection mode |
1675
+ *
1676
+ * And under `"range"`, additionally:
1677
+ *
1678
+ * | Gesture | Does |
1679
+ * | ------- | ---- |
1680
+ * | Drag across cells | selects the rectangle they span |
1681
+ * | Shift+click, Shift+arrows | extends the rectangle from its anchor |
1682
+ * | Ctrl+C | copies it as tab-separated text — paste lands in Excel's cells |
1683
+ * | Right-click inside it | offers the CSV export, headers optional |
1684
+ *
1685
+ * Off, nothing about the body changes. On, three things do: the body's tab
1686
+ * stop moves from the row to a cell, so the whole grid is one Tab stop; the
1687
+ * grid reports itself as a `grid` of `gridcell`s rather than a `table` of
1688
+ * `cell`s, which is what tells a screen reader the arrow keys are live; and
1689
+ * the cells take `data-focused` / `data-selected` for the ring and the tint.
1690
+ *
1691
+ * The state is `ui.state.focusedCell` and `ui.state.cellRange`, and moving it
1692
+ * is `ui.actions.setFocusedCell` / `setCellRange` — so a consumer can put the
1693
+ * keyboard on a cell, or follow it:
1694
+ *
1695
+ * ```tsx
1696
+ * const grid = useTMDataGrid({
1697
+ * data,
1698
+ * columns,
1699
+ * cellSelection: "range",
1700
+ * onFocusedCellChange: (cell) => setStatus(cell?.columnId ?? ""),
1701
+ * });
1702
+ * ```
1703
+ *
1704
+ * Ids rather than a row/column index pair, so sorting, filtering and column
1705
+ * reordering move the selection with the cells instead of leaving it over
1706
+ * whatever slid into those positions.
1707
+ */
1708
+ cellSelection?: TMDataGridCellSelectionMode;
1709
+ /**
1710
+ * Called with the newly focused cell, or `null` when it is cleared. Fires for
1711
+ * `ui.actions.setFocusedCell` too, not only for keys and clicks.
1712
+ */
1713
+ onFocusedCellChange?: (cell: TMDataGridCellPosition | null) => void;
1714
+ /**
1715
+ * Renders a panel underneath an expanded row, spanning every column. Setting
1716
+ * it is what turns row details on.
1717
+ *
1718
+ * Which rows are open is TanStack's own `expanded` state, so opening one is
1719
+ * `row.toggleExpanded()` from wherever suits — a chevron in a cell, a button
1720
+ * in the context menu, a double-click:
1721
+ *
1722
+ * ```tsx
1723
+ * const grid = useTMDataGrid({
1724
+ * data,
1725
+ * columns,
1726
+ * renderDetails: ({ row }) => <EmployeeCard employee={row.original} />,
1727
+ * });
1728
+ * ```
1729
+ *
1730
+ * The panel is as tall as what it renders — see {@link renderDetailsEstHeight}
1731
+ * for what the virtualizer assumes before it has measured one.
1732
+ *
1733
+ * Group rows are left out: expanding one opens its children, and a panel there
1734
+ * would be about an arbitrary one of them. The same reason they sit out
1735
+ * `onRowClick`.
1736
+ *
1737
+ * Row details and `selectionMode: "highlight"` are two answers to the same
1738
+ * question. Details keep the record in place and in context, which suits a few
1739
+ * fields or an action strip; a highlight-driven side panel has room for more
1740
+ * and survives scrolling. Nothing stops a grid from doing both.
1741
+ */
1742
+ renderDetails?: TMDataGridDetailsRenderer<TData>;
1743
+ /**
1744
+ * What the virtualizer assumes an unmeasured detail panel is worth, in px.
1745
+ * Defaults to 160.
1746
+ *
1747
+ * An estimate, not a height: every mounted row is measured, so the real one
1748
+ * takes over as soon as the panel is on screen. It keeps the scrollbar honest
1749
+ * for panels that open off screen — restored `expanded` state, say — and being
1750
+ * roughly right is enough.
1751
+ */
1752
+ renderDetailsEstHeight?: number;
1753
+ /**
1754
+ * Rows the virtualizer keeps mounted above and below the viewport. Defaults
1755
+ * to 6.
1756
+ *
1757
+ * Raise it to trade memory for a scroll that stays painted — fast wheel or
1758
+ * touch flings can outrun the virtualizer and flash blank rows, and a larger
1759
+ * buffer covers the gap. Lower it when rows are expensive to render.
1760
+ */
1761
+ overscan?: number;
605
1762
  };
606
1763
  /**
607
1764
  * Builds a TMDataGrid table plus its chrome store.
@@ -614,7 +1771,7 @@ type UseTMDataGridOptions<TData extends RowData> = Omit<TableOptions<TMDataGridF
614
1771
  * flag on, so `<TMDataGrid.Footer />` renders its pager without further
615
1772
  * options.
616
1773
  */
617
- declare function useTMDataGrid<TData extends RowData>({ persist, enableColumnOrdering, enablePagination, selectionMode, showSelectedBackground, defaultHighlightedRowId, onHighlightedRowChange, ...options }: UseTMDataGridOptions<TData>): TMDataGridApi<TData>;
1774
+ 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>;
618
1775
  /**
619
1776
  * Opens the filter panel for a column, seeding an empty filter row when the
620
1777
  * column has none yet — mirrors "Filter" in the column header menu.
@@ -698,6 +1855,171 @@ type TMDataGridFooterProps = {
698
1855
  */
699
1856
  declare function TMDataGridFooter({ pageSizeOptions, pagination }: TMDataGridFooterProps): import("react").JSX.Element | null;
700
1857
  //#endregion
1858
+ //#region .types-tmp/components/TMDataGridSearch.d.ts
1859
+ type TMDataGridSearchProps = {
1860
+ /** Defaults to `labels.searchPlaceholder`. */
1861
+ placeholder?: string;
1862
+ /**
1863
+ * How long typing pauses before the filter is applied, in ms. Defaults to
1864
+ * 250. `0` writes on every keystroke — what the tests use, and fine for
1865
+ * small client-side data sets.
1866
+ */
1867
+ debounce?: number;
1868
+ /** Width of the input. Defaults to 220. */
1869
+ w?: number | string;
1870
+ };
1871
+ /**
1872
+ * Quick search over every column — a debounced input writing the table's
1873
+ * `globalFilter` state through the `"includesString"` filter the grid
1874
+ * configures by default.
1875
+ *
1876
+ * ```tsx
1877
+ * <TMDataGrid.Toolbar>
1878
+ * <TMDataGrid.Search />
1879
+ * <TMDataGrid.Spacer />
1880
+ * <TMDataGrid.FilterButton />
1881
+ * </TMDataGrid.Toolbar>
1882
+ * ```
1883
+ *
1884
+ * Renders nothing under `enableGlobalFilter: false`. Columns opt out with
1885
+ * their own `enableGlobalFilter: false` — the generated lanes already do.
1886
+ *
1887
+ * The state is TanStack's `globalFilter`, so everything around it comes free:
1888
+ * `manualFiltering` grids forward it to the server, and it is one of the
1889
+ * persisted `data` slices. A grid that wants its own input entirely writes
1890
+ * `table.setGlobalFilter` itself — this component is only the built-in one.
1891
+ */
1892
+ declare function TMDataGridSearch({ placeholder, debounce, w }: TMDataGridSearchProps): import("react").JSX.Element | null;
1893
+ //#endregion
1894
+ //#region .types-tmp/core/cellExport.d.ts
1895
+ /** The selected block, flattened to text. One inner array per row. */
1896
+ type TMDataGridCellMatrix = Array<Array<string>>;
1897
+ /**
1898
+ * How values are written out.
1899
+ *
1900
+ * The defaults are the Nordic ones, because they are the ones that need
1901
+ * choosing: an Excel running a Swedish, Norwegian, Danish or Finnish locale
1902
+ * reads `;` as its list separator and `,` as its decimal mark, and a file
1903
+ * written the other way opens as one column of text. Both are settable for a
1904
+ * grid whose users run something else.
1905
+ */
1906
+ type TMDataGridCellExportOptions = {
1907
+ /** CSV field separator. Defaults to `";"`. */
1908
+ separator?: string;
1909
+ /** Write numbers as `1,5` rather than `1.5`. Defaults to `true`. */
1910
+ decimalComma?: boolean;
1911
+ /** Column labels as the first row. Defaults to `true`. */
1912
+ includeHeaders?: boolean;
1913
+ /** Without extension. Defaults to `"export"`. */
1914
+ fileName?: string;
1915
+ };
1916
+ type ResolvedExportOptions = Required<TMDataGridCellExportOptions>;
1917
+ declare const DEFAULT_CELL_EXPORT_OPTIONS: ResolvedExportOptions;
1918
+ /**
1919
+ * One value as text.
1920
+ *
1921
+ * Deliberately not the rendered cell: what a cell renders is React, and often a
1922
+ * badge, a link or an icon rather than the value. The value is what a
1923
+ * spreadsheet wants, and it is the one thing every column is guaranteed to
1924
+ * have.
1925
+ */
1926
+ declare function formatExportValue(value: unknown, { decimalComma }: {
1927
+ decimalComma: boolean;
1928
+ }): string;
1929
+ type BuildCellMatrixArgs = {
1930
+ rows: ReadonlyArray<Row<TMDataGridFeatures, TMDataGridRowData>>;
1931
+ /** Every visible column, in render order — the same list the bounds index into. */
1932
+ columns: ReadonlyArray<Column<TMDataGridFeatures, TMDataGridRowData, unknown>>;
1933
+ bounds: TMDataGridRangeBounds;
1934
+ includeHeaders: boolean;
1935
+ decimalComma: boolean;
1936
+ };
1937
+ /**
1938
+ * The selected rectangle as rows of text.
1939
+ *
1940
+ * The generated lanes — the checkbox, the tree chevron, the details chevron —
1941
+ * are dropped even when the rectangle covers them. They hold controls rather
1942
+ * than data, so a column of empty strings is all they could contribute, and
1943
+ * pasting one into a spreadsheet only shifts everything to its right.
1944
+ */
1945
+ declare function buildCellMatrix({ rows, columns, bounds, includeHeaders, decimalComma }: BuildCellMatrixArgs): TMDataGridCellMatrix;
1946
+ /**
1947
+ * The whole grid as rows of text: every filtered and sorted data row — all
1948
+ * pages, not the one on screen — by every visible non-control column, in
1949
+ * render order.
1950
+ *
1951
+ * The values are the same ones a cell-range export writes; only the bounds
1952
+ * differ. Group rows are left out (their records are the rows themselves),
1953
+ * and hidden columns are not exported — what you see is what you get, minus
1954
+ * paging.
1955
+ */
1956
+ declare function buildGridCellMatrix<TData extends RowData>({ table, includeHeaders, decimalComma }: {
1957
+ table: TMDataGridTable<TData>;
1958
+ includeHeaders?: boolean;
1959
+ decimalComma?: boolean;
1960
+ }): TMDataGridCellMatrix;
1961
+ /**
1962
+ * Downloads the whole grid as a CSV for Excel — {@link buildGridCellMatrix}
1963
+ * through {@link toExcelCsv}, with the same Nordic defaults and overrides as
1964
+ * the cell-range export.
1965
+ *
1966
+ * No built-in button: wire it to your own toolbar.
1967
+ *
1968
+ * ```tsx
1969
+ * <Button onClick={() => exportGridToCsv({ table: grid.table })}>Export</Button>
1970
+ * ```
1971
+ */
1972
+ declare function exportGridToCsv<TData extends RowData>({ table, options }: {
1973
+ table: TMDataGridTable<TData>;
1974
+ options?: TMDataGridCellExportOptions;
1975
+ }): void;
1976
+ /**
1977
+ * The clipboard format spreadsheets read: tab between cells, CRLF between rows.
1978
+ *
1979
+ * Tabs rather than commas because that is what Excel, Sheets and Numbers all
1980
+ * put on the clipboard themselves — paste it and the cells land in cells. A
1981
+ * comma-separated string pastes into a single column, which is the thing this
1982
+ * exists to avoid.
1983
+ */
1984
+ declare function toClipboardText(matrix: TMDataGridCellMatrix): string;
1985
+ /**
1986
+ * A CSV that opens straight into columns in Excel.
1987
+ *
1988
+ * Three things make that true, and all three are needed:
1989
+ *
1990
+ * | Part | Why |
1991
+ * | ---- | --- |
1992
+ * | `sep=;` first line | Excel's own directive — it stops guessing and uses this |
1993
+ * | UTF-8 BOM | without it Excel reads the file as ANSI, and å ä ö arrive broken |
1994
+ * | CRLF line endings | what Excel writes, and what its importer is happiest with |
1995
+ *
1996
+ * The `sep=` line is Excel's alone; other readers show it as a first row. That
1997
+ * is the trade this makes — the file is for Excel, and "it just opens" is worth
1998
+ * more than being a well-behaved CSV nobody was going to feed to a parser.
1999
+ */
2000
+ declare function toExcelCsv(matrix: TMDataGridCellMatrix, { separator }: {
2001
+ separator: string;
2002
+ }): string;
2003
+ /**
2004
+ * Puts text on the clipboard, reporting whether it landed.
2005
+ *
2006
+ * The async clipboard API only resolves for a document that has the focus and a
2007
+ * user gesture behind it — both true when this runs off Ctrl+C or a menu item.
2008
+ * It is still allowed to reject (a permissions policy, a page that lost focus
2009
+ * mid-copy), so the result is a boolean rather than a promise nobody checks.
2010
+ */
2011
+ declare function writeClipboardText(text: string): Promise<boolean>;
2012
+ /**
2013
+ * Downloads text as a file, through the one mechanism a library can use: an
2014
+ * anchor with an object URL behind it, clicked. Revoked on the next frame —
2015
+ * immediately would race the browser's own read of it.
2016
+ */
2017
+ declare function downloadTextFile({ fileName, text, mimeType }: {
2018
+ fileName: string;
2019
+ text: string;
2020
+ mimeType?: string;
2021
+ }): void;
2022
+ //#endregion
701
2023
  //#region .types-tmp/components/TMDataGridTable.d.ts
702
2024
  /** Where a column sits relative to the pinned regions, resolved once per render. */
703
2025
  type TMDataGridColumnLayout = {
@@ -707,6 +2029,35 @@ type TMDataGridColumnLayout = {
707
2029
  /** Last left-pinned / first right-pinned column — the one that casts the edge. */
708
2030
  isBoundary: boolean;
709
2031
  };
2032
+ /**
2033
+ * What a cell needs to take part in cell selection, or `undefined` while the
2034
+ * feature is off — which is what keeps a plain grid's cells exactly as they
2035
+ * were: no tab stop, no `gridcell` role, no coordinates in the DOM.
2036
+ *
2037
+ * The coordinates are there for the delegated key handler, which reads them off
2038
+ * `event.target` rather than closing over per-cell state, and for the effect
2039
+ * that puts DOM focus where {@link TMDataGridUiState.focusedCell} says.
2040
+ */
2041
+ type TMDataGridCellNav = {
2042
+ rowId: string;
2043
+ /** 1-based, for `aria-colindex`. */
2044
+ columnIndex: number;
2045
+ focused: boolean;
2046
+ /** The roving tab stop: `0` on exactly one mounted cell, `-1` on the rest. */
2047
+ tabIndex: 0 | -1;
2048
+ /** Inside the selected rectangle. Always `false` under `"single"`. */
2049
+ selected: boolean;
2050
+ /**
2051
+ * Which sides of the rectangle this cell is on, or `null` when it is not in
2052
+ * one. The outline is drawn per cell — see {@link boundsEdges}.
2053
+ */
2054
+ edges: {
2055
+ top: boolean;
2056
+ bottom: boolean;
2057
+ left: boolean;
2058
+ right: boolean;
2059
+ } | null;
2060
+ };
710
2061
  /** What a `rowContextMenu` render prop is handed for the right-clicked row. */
711
2062
  type TMDataGridRowContextMenuArgs<TData extends RowData> = {
712
2063
  table: Table<TMDataGridFeatures, TData>;
@@ -729,12 +2080,93 @@ type TMDataGridRowContextMenuArgs<TData extends RowData> = {
729
2080
  * its `Menu.Dropdown`; this fills the dropdown.
730
2081
  */
731
2082
  type TMDataGridRowContextMenu<TData extends RowData> = (args: TMDataGridRowContextMenuArgs<TData>) => ReactNode;
2083
+ /**
2084
+ * What the `onCellClick` family receives — the cell with its row and column,
2085
+ * in the consumer's own row type, plus the pointer event.
2086
+ */
2087
+ type TMDataGridCellEventArgs<TData extends RowData> = {
2088
+ cell: Cell<TMDataGridFeatures, TData, unknown>;
2089
+ row: Row<TMDataGridFeatures, TData>;
2090
+ column: Column<TMDataGridFeatures, TData, unknown>;
2091
+ event: MouseEvent<HTMLElement>;
2092
+ };
2093
+ /**
2094
+ * Inline styles for a row. Widened to accept CSS variables, because setting
2095
+ * `--row-bg` is the supported way to colour a row — see {@link
2096
+ * TMDataGridTableProps.rowStyle}.
2097
+ */
2098
+ type TMDataGridRowStyle = CSSProperties | (CSSProperties & Record<`--${string}`, string | number>);
732
2099
  type TMDataGridTableProps<TData extends RowData> = {
733
2100
  /**
734
2101
  * Called when a body row is clicked. Runs in addition to row selection under
735
2102
  * `selectionMode: "row"`, not instead of it.
736
2103
  */
737
2104
  onRowClick?: (row: Row<TMDataGridFeatures, TData>) => void;
2105
+ /**
2106
+ * Called when a body cell is clicked. Composes, never suppresses: whatever
2107
+ * the click already does — selecting, highlighting, moving the cell cursor
2108
+ * — still happens. Group rows sit out the cell handlers the way they sit
2109
+ * out `onRowClick`, and for the same reason.
2110
+ */
2111
+ onCellClick?: (args: TMDataGridCellEventArgs<TData>) => void;
2112
+ /** As {@link onCellClick}; a double-click that opens an editor still does. */
2113
+ onCellDoubleClick?: (args: TMDataGridCellEventArgs<TData>) => void;
2114
+ /**
2115
+ * As {@link onCellClick}; `rowContextMenu` and the cell-selection menu still
2116
+ * open. To suppress the browser's own menu on a grid with neither, call
2117
+ * `event.preventDefault()` here.
2118
+ */
2119
+ onCellContextMenu?: (args: TMDataGridCellEventArgs<TData>) => void;
2120
+ /**
2121
+ * Class for a body row — a string, or a function of the row (group rows
2122
+ * included; test `row.getIsGrouped()` to skip them). Added after the grid's
2123
+ * own row class.
2124
+ */
2125
+ rowClassName?: string | ((row: Row<TMDataGridFeatures, TData>) => string | undefined);
2126
+ /**
2127
+ * Inline style for a body row. To colour a row, set `--row-bg` rather than
2128
+ * `background`: the row's own background, its sticky pinned cells and the
2129
+ * cell-range tint all read that variable, and hover/selection/highlight
2130
+ * keep working on top of it — a raw `background` bypasses all of them.
2131
+ *
2132
+ * ```tsx
2133
+ * rowStyle={(row) =>
2134
+ * row.original.overdue ? { "--row-bg": "var(--mantine-color-red-0)" } : undefined
2135
+ * }
2136
+ * ```
2137
+ */
2138
+ rowStyle?: TMDataGridRowStyle | ((row: Row<TMDataGridFeatures, TData>) => TMDataGridRowStyle | undefined);
2139
+ /**
2140
+ * Every second row takes `--dg-row-striped-bg`. Computed from the row's
2141
+ * position in the view — sorting and filtering restripe, and the stripes
2142
+ * stay put while the virtualizer mounts and unmounts rows.
2143
+ */
2144
+ striped?: boolean;
2145
+ /**
2146
+ * Called when the scroll *arrives* at an edge — once per arrival, not per
2147
+ * scroll event, and not on mount (the grid starts at the top-left edge).
2148
+ * For loading more rows as the end approaches, `onReachEnd` is the better
2149
+ * hook: it fires rows-early and latches per row count.
2150
+ */
2151
+ onScrollToTop?: () => void;
2152
+ /** As {@link onScrollToTop}, for the bottom edge. */
2153
+ onScrollToBottom?: () => void;
2154
+ /** As {@link onScrollToTop}, for the left edge. */
2155
+ onScrollToLeft?: () => void;
2156
+ /** As {@link onScrollToTop}, for the right edge. */
2157
+ onScrollToRight?: () => void;
2158
+ /**
2159
+ * Rendered centred in the body when the view is empty — the branded blank
2160
+ * slate. It takes over states 3 and 4 of the empty matrix (see the docs):
2161
+ * loading still shows the loader, and open entry rows still show only
2162
+ * themselves. `hasActiveFilters` says which emptiness this is — a filter
2163
+ * that matched nothing wants a "clear filters" invitation, a grid with no
2164
+ * data wants a "create the first one".
2165
+ */
2166
+ renderEmptyState?: (args: {
2167
+ hasActiveFilters: boolean;
2168
+ table: Table<TMDataGridFeatures, TData>;
2169
+ }) => ReactNode;
738
2170
  /**
739
2171
  * Contents of the menu a right-click on a row opens, at the pointer. Return
740
2172
  * `null` to leave a row without one — the browser's own menu stays suppressed
@@ -764,6 +2196,39 @@ type TMDataGridTableProps<TData extends RowData> = {
764
2196
  * `position`, `transitionProps` and the rest. Its open state is the grid's.
765
2197
  */
766
2198
  rowContextMenuProps?: Omit<MenuProps, "opened" | "onChange" | "children">;
2199
+ /**
2200
+ * How Ctrl+C and the export item write values, under
2201
+ * `cellSelection: "range"`. Defaults to the Nordic Excel conventions — see
2202
+ * {@link TMDataGridCellExportOptions}.
2203
+ */
2204
+ cellExport?: TMDataGridCellExportOptions;
2205
+ /**
2206
+ * Called when the scroll approaches the last row — the infinite-scroll
2207
+ * hook-in. Append the next page to `data` and the virtualizer keeps its
2208
+ * position; fires once per row count, so a pending fetch is not asked
2209
+ * again until it lands.
2210
+ *
2211
+ * ```tsx
2212
+ * <TMDataGrid.Table onReachEnd={() => query.fetchNextPage()} />
2213
+ * ```
2214
+ *
2215
+ * Sorting and filtering must be server-side (`manual*`) on a grid that
2216
+ * loads this way — the client only ever holds a prefix of the data. Not
2217
+ * compatible with `enablePagination`, which slices the same scroll.
2218
+ */
2219
+ onReachEnd?: () => void;
2220
+ /**
2221
+ * How many rows before the end {@link onReachEnd} fires at. Defaults to 10.
2222
+ */
2223
+ reachEndThreshold?: number;
2224
+ /**
2225
+ * Accessible name for the grid — what a screen reader announces on entry,
2226
+ * and what `getByRole("grid", { name })` matches. Worth setting on any page
2227
+ * holding more than one grid; without it they are all just "grid".
2228
+ */
2229
+ "aria-label"?: string;
2230
+ /** As {@link "aria-label"}, pointing at an element that already names it. */
2231
+ "aria-labelledby"?: string;
767
2232
  };
768
2233
  /**
769
2234
  * The scrollable grid surface. Always virtualized: only the rows inside the
@@ -771,7 +2236,7 @@ type TMDataGridTableProps<TData extends RowData> = {
771
2236
  * no-pagination mode viable at any row count. Pagination is opt-in via
772
2237
  * `enablePagination` (or implied by `manualPagination`).
773
2238
  */
774
- declare function TMDataGridTable$1<TData extends RowData = TMDataGridRowData>({ onRowClick, rowContextMenu, rowContextMenuProps }: TMDataGridTableProps<TData>): import("react").JSX.Element;
2239
+ declare function TMDataGridTable$1<TData extends RowData = TMDataGridRowData>({ onRowClick, onCellClick, onCellDoubleClick, onCellContextMenu, rowClassName, rowStyle, striped, onScrollToTop, onScrollToBottom, onScrollToLeft, onScrollToRight, renderEmptyState, rowContextMenu, rowContextMenuProps, cellExport, onReachEnd, reachEndThreshold, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }: TMDataGridTableProps<TData>): import("react").JSX.Element;
775
2240
  //#endregion
776
2241
  //#region .types-tmp/components/TMDataGridToolbar.d.ts
777
2242
  /** Row above the grid. Compose it from the pieces below, or anything else. */
@@ -780,6 +2245,24 @@ declare function TMDataGridToolbar({ children }: {
780
2245
  }): import("react").JSX.Element;
781
2246
  /** Pushes the following toolbar items to the right. */
782
2247
  declare function TMDataGridToolbarSpacer(): import("react").JSX.Element;
2248
+ /**
2249
+ * A small spinner shown while `meta.loading` is true, and nothing otherwise.
2250
+ *
2251
+ * The body only shows its loading state while the grid is *empty* — a
2252
+ * server-driven grid refetching with rows on screen keeps showing them, which
2253
+ * is right, but leaves nothing saying a fetch is running. This is that signal,
2254
+ * and the consumer decides where it sits by placing it in the toolbar:
2255
+ *
2256
+ * ```tsx
2257
+ * <TMDataGrid.Toolbar>
2258
+ * <TMDataGrid.SummaryCount />
2259
+ * <TMDataGrid.Spacer />
2260
+ * <TMDataGrid.LoadingIndicator />
2261
+ * <TMDataGrid.FilterButton />
2262
+ * </TMDataGrid.Toolbar>
2263
+ * ```
2264
+ */
2265
+ declare function TMDataGridLoadingIndicator(): import("react").JSX.Element | null;
783
2266
  /**
784
2267
  * Visible rows over total rows. On a server-driven grid, set
785
2268
  * `meta.totalRowCount` for the denominator — the client never sees every row.
@@ -813,6 +2296,20 @@ type TMDataGridProps<TData extends RowData> = TMDataGridApi<TData> & {
813
2296
  * background. Plain `CSSProperties` rejects `--*` keys.
814
2297
  */
815
2298
  style?: CSSProperties & Record<`--${string}`, string | number>;
2299
+ /** Set on the root element. */
2300
+ id?: string;
2301
+ /**
2302
+ * Names this grid for tests. The grid names its own pieces with
2303
+ * `data-dg-part` rather than minting test ids, and those repeat across
2304
+ * grids — scope through this one and they stop colliding:
2305
+ *
2306
+ * ```ts
2307
+ * page.getByTestId("orders").locator('[data-dg-part="row"][data-row-id="42"]')
2308
+ * ```
2309
+ *
2310
+ * See the Testing docs page for the full attribute contract.
2311
+ */
2312
+ "data-testid"?: string;
816
2313
  };
817
2314
  /**
818
2315
  * Root of the grid. Takes the object returned by `useTMDataGrid` — spread it —
@@ -832,11 +2329,14 @@ type TMDataGridProps<TData extends RowData> = TMDataGridApi<TData> & {
832
2329
  * </TMDataGrid>
833
2330
  * ```
834
2331
  */
835
- declare function TMDataGridRoot<TData extends RowData>({ table, ui, features, size, children, className, style }: TMDataGridProps<TData>): import("react").JSX.Element;
2332
+ declare function TMDataGridRoot<TData extends RowData>({ table, ui, edit, features, labels, renderDetails, renderDetailsEstHeight, overscan, resetSettings, scrollToRow, scrollerRef, size, children, className, style, id, "data-testid": testId }: TMDataGridProps<TData>): import("react").JSX.Element;
836
2333
  declare const TMDataGrid: typeof TMDataGridRoot & {
837
2334
  Toolbar: typeof TMDataGridToolbar;
838
2335
  Spacer: typeof TMDataGridToolbarSpacer;
839
2336
  SummaryCount: typeof TMDataGridSummaryCount;
2337
+ LoadingIndicator: typeof TMDataGridLoadingIndicator;
2338
+ Search: typeof TMDataGridSearch;
2339
+ EditActions: typeof TMDataGridEditActions;
840
2340
  ColumnsButton: typeof TMDataGridColumnsButton;
841
2341
  FilterButton: typeof TMDataGridFilterButton;
842
2342
  Table: typeof TMDataGridTable$1;
@@ -855,6 +2355,15 @@ declare const TMDataGrid: typeof TMDataGridRoot & {
855
2355
  //#region .types-tmp/components/TMDataGridSelectColumn.d.ts
856
2356
  declare const SELECT_COLUMN_ID = "__select__";
857
2357
  //#endregion
2358
+ //#region .types-tmp/components/TMDataGridDetailsColumn.d.ts
2359
+ declare const DETAILS_COLUMN_ID = "__details__";
2360
+ //#endregion
2361
+ //#region .types-tmp/components/TMDataGridEditColumn.d.ts
2362
+ declare const EDIT_COLUMN_ID = "__edit__";
2363
+ //#endregion
2364
+ //#region .types-tmp/components/TMDataGridRowNumberColumn.d.ts
2365
+ declare const ROW_NUMBER_COLUMN_ID = "__rowNumber__";
2366
+ //#endregion
858
2367
  //#region .types-tmp/components/TMDataGridGroupColumn.d.ts
859
2368
  declare const GROUP_COLUMN_ID = "__group__";
860
2369
  /**
@@ -864,7 +2373,105 @@ declare const GROUP_COLUMN_ID = "__group__";
864
2373
  * written for a data row and is free to reach into `row.original`, which on a
865
2374
  * group row is the first leaf's record rather than anything about the group.
866
2375
  */
867
- declare function formatGroupValue(value: unknown): string;
2376
+ declare function formatGroupValue(value: unknown, blankLabel?: string): string;
2377
+ //#endregion
2378
+ //#region .types-tmp/components/filters/TMDataGridFilterValueInput.d.ts
2379
+ /**
2380
+ * The built-in value control of a filter-panel row — what renders when a
2381
+ * column declares no `meta.filterControl`. Shaped by the operator: a
2382
+ * multi-select for the set operators, a From/To pair for `between`, a Yes/No
2383
+ * dropdown for booleans, a typed input otherwise.
2384
+ *
2385
+ * Exported so a custom control can fall back to it for the operators it does
2386
+ * not care about, instead of rebuilding them.
2387
+ */
2388
+ declare function TMDataGridFilterValueInput({ column, operator, value, onChange, options, size, labels }: TMDataGridFilterControlArgs): import("react").JSX.Element;
2389
+ //#endregion
2390
+ //#region .types-tmp/components/filters/DgRangeSliderFilter.d.ts
2391
+ /**
2392
+ * A built-in `meta.filterControl` for `number` columns: a range slider whose
2393
+ * bounds are seeded from the values present in the data, writing the
2394
+ * `between` pair. Pair it with `meta.defaultFilterOperator: "between"` so
2395
+ * the filter opens on it; any non-range operator falls back to the standard
2396
+ * input.
2397
+ */
2398
+ declare function DgRangeSliderFilter(args: TMDataGridFilterControlArgs): import("react").JSX.Element;
2399
+ //#endregion
2400
+ //#region .types-tmp/components/filters/DgDateRangeFilter.d.ts
2401
+ /**
2402
+ * A built-in `meta.filterControl` for `date` columns: a From/To pair of
2403
+ * native date inputs writing the `between` pair — no `@mantine/dates`
2404
+ * involved, like the built-in date editor. Pair it with
2405
+ * `meta.defaultFilterOperator: "between"`; any non-range operator falls back
2406
+ * to the standard input.
2407
+ */
2408
+ declare function DgDateRangeFilter(args: TMDataGridFilterControlArgs): import("react").JSX.Element;
2409
+ //#endregion
2410
+ //#region .types-tmp/components/filters/DgAutocompleteFilter.d.ts
2411
+ /**
2412
+ * A built-in `meta.filterControl` for text-shaped columns: a free-text input
2413
+ * that also offers the values present in the data (or the column's declared
2414
+ * `meta.options`) as suggestions. Set or range operators fall back to the
2415
+ * standard input.
2416
+ */
2417
+ declare function DgAutocompleteFilter(args: TMDataGridFilterControlArgs): import("react").JSX.Element;
2418
+ //#endregion
2419
+ //#region .types-tmp/components/filters/DgTriStateFilter.d.ts
2420
+ /**
2421
+ * A built-in `meta.filterControl` for `boolean` columns: an All / Yes / No
2422
+ * segmented control — All clears the value, which deactivates the filter.
2423
+ * Set or range operators fall back to the standard input.
2424
+ */
2425
+ declare function DgTriStateFilter(args: TMDataGridFilterControlArgs): import("react").JSX.Element;
2426
+ //#endregion
2427
+ //#region .types-tmp/components/editors/TMDataGridStringEditor.d.ts
2428
+ /** The built-in editor for `meta.type: "string"` (and the default). */
2429
+ declare function TMDataGridStringEditor({ field, autoFocus, column, size }: TMDataGridEditorArgs): import("react").JSX.Element;
2430
+ //#endregion
2431
+ //#region .types-tmp/components/editors/TMDataGridNumberEditor.d.ts
2432
+ /** The built-in editor for `meta.type: "number"`. */
2433
+ declare function TMDataGridNumberEditor({ field, autoFocus, column, size }: TMDataGridEditorArgs): import("react").JSX.Element;
2434
+ //#endregion
2435
+ //#region .types-tmp/components/editors/TMDataGridBooleanEditor.d.ts
2436
+ /** The built-in editor for `meta.type: "boolean"` — a focused checkbox. */
2437
+ declare function TMDataGridBooleanEditor({ field, autoFocus, column, size }: TMDataGridEditorArgs): import("react").JSX.Element;
2438
+ //#endregion
2439
+ //#region .types-tmp/components/editors/TMDataGridDateEditor.d.ts
2440
+ /**
2441
+ * The built-in editor for `meta.type: "date"` — the native
2442
+ * `<input type="date">` styled by Mantine, no `@mantine/dates` involved. A
2443
+ * consumer wanting a real picker plugs one in through `meta.editor`.
2444
+ */
2445
+ declare function TMDataGridDateEditor({ field, autoFocus, column, size }: TMDataGridEditorArgs): import("react").JSX.Element;
2446
+ //#endregion
2447
+ //#region .types-tmp/components/editors/TMDataGridSelectEditor.d.ts
2448
+ /**
2449
+ * The built-in editor for `meta.type: "select"`. Options come from the same
2450
+ * `meta.options` the filter panel reads — with the row in hand, so a
2451
+ * function source can depend on the record being edited.
2452
+ */
2453
+ declare function TMDataGridSelectEditor({ field, autoFocus, column, row, table, size, commit }: TMDataGridEditorArgs): import("react").JSX.Element;
2454
+ //#endregion
2455
+ //#region .types-tmp/components/editors/TMDataGridMultiSelectEditor.d.ts
2456
+ /**
2457
+ * The built-in editor for `meta.type: "multiSelect"` — cells holding string
2458
+ * arrays. Never commits on pick: building a set takes several, so the commit
2459
+ * stays on Enter/blur like a text edit.
2460
+ */
2461
+ declare function TMDataGridMultiSelectEditor({ field, autoFocus, column, row, table, size }: TMDataGridEditorArgs): import("react").JSX.Element;
2462
+ //#endregion
2463
+ //#region .types-tmp/core/labelsSv.d.ts
2464
+ /**
2465
+ * The complete Swedish dictionary. Typed as {@link TMDataGridLabels} rather
2466
+ * than as an override, so a label added to the grid without a Swedish
2467
+ * translation is a compile error here instead of English quietly leaking
2468
+ * through.
2469
+ *
2470
+ * ```tsx
2471
+ * useTMDataGrid({ data, columns, labels: TMDATAGRID_LABELS_SV });
2472
+ * ```
2473
+ */
2474
+ declare const TMDATAGRID_LABELS_SV: TMDataGridLabels;
868
2475
  //#endregion
869
2476
  //#region .types-tmp/core/columnUtils.d.ts
870
2477
  /**
@@ -884,6 +2491,25 @@ type ColumnLike = {
884
2491
  /** Menu- and panel-facing column name. */
885
2492
  declare function getColumnLabel(column: ColumnLike): string;
886
2493
  declare function getColumnType(column: ColumnLike): TMDataGridColumnType;
2494
+ /**
2495
+ * The operator a fresh filter on this column starts with —
2496
+ * `meta.defaultFilterOperator`, else the type's default.
2497
+ */
2498
+ declare function getColumnDefaultOperator(column: ColumnLike): TMDataGridFilterOperator;
2499
+ /**
2500
+ * A generated lane holding one fixed-width thing — the checkbox, the details
2501
+ * chevron, the row number.
2502
+ *
2503
+ * They are laid out differently from every other column: cell padding is sized
2504
+ * for text and grows with the scale, which at `xl` squeezed a 16px checkbox out
2505
+ * of its track, so these lanes centre their content in an unpadded cell.
2506
+ * Their headers carry no column menu, and none of them is ever exported —
2507
+ * they hold chrome, not values.
2508
+ *
2509
+ * The tree column is deliberately not one of them: it holds a label as well as a
2510
+ * chevron, and wants the padding.
2511
+ */
2512
+ declare function isControlColumn(columnId: string): boolean;
887
2513
  /**
888
2514
  * Whether a column may be moved. Ordering is the one column feature TanStack
889
2515
  * has no column option for, so the switch lives in `meta.enableOrdering`.
@@ -909,6 +2535,101 @@ declare function isColumnReorderable(column: ColumnLike): boolean;
909
2535
  */
910
2536
  declare function getGroupDataRows<TData extends RowData>(row: Row<TMDataGridFeatures, TData>): Array<Row<TMDataGridFeatures, TData>>;
911
2537
  //#endregion
2538
+ //#region .types-tmp/core/summary.d.ts
2539
+ /** The registered aggregation names — the same set `aggregationFn` accepts. */
2540
+ type TMDataGridAggregationName = keyof typeof aggregationFns;
2541
+ /**
2542
+ * One column aggregated over every filtered row — the number a summary-row
2543
+ * `footer` wants:
2544
+ *
2545
+ * ```tsx
2546
+ * columnHelper.accessor("salary", {
2547
+ * footer: ({ table }) => sek(Number(aggregateColumn({ table, columnId: "salary" }))),
2548
+ * });
2549
+ * ```
2550
+ *
2551
+ * Filtered rather than paginated rows, so the total covers everything the
2552
+ * filters left — all pages — and follows the filters as they change. Reuses
2553
+ * TanStack's registered aggregation functions; `fn` defaults to `"sum"`.
2554
+ */
2555
+ declare function aggregateColumn<TData extends RowData>({ table, columnId, fn }: {
2556
+ table: TMDataGridTable<TData>;
2557
+ columnId: string;
2558
+ fn?: TMDataGridAggregationName;
2559
+ }): unknown;
2560
+ //#endregion
2561
+ //#region .types-tmp/core/autosize.d.ts
2562
+ /**
2563
+ * Widest rendered content of one column, in px, measured from the DOM.
2564
+ *
2565
+ * Mounted cells only: under virtualization the unmounted rows do not exist to
2566
+ * be measured, so this reads the visible window plus overscan — the same
2567
+ * trade AG Grid's autosize makes by default.
2568
+ */
2569
+ declare function measureColumnContentWidth({ container, columnId }: {
2570
+ /** The grid's scroll container — anything enclosing the column's cells. */
2571
+ container: HTMLElement;
2572
+ columnId: string;
2573
+ }): number;
2574
+ /**
2575
+ * Sizes a column to its widest mounted content — what double-clicking the
2576
+ * resize divider does, exported so a menu item or consumer code can trigger
2577
+ * the same thing.
2578
+ *
2579
+ * The width lands in `columnSizing`, so it persists with the other widths and
2580
+ * a later resize drag takes over from it. Clamped to the column's
2581
+ * `minSize`/`maxSize`; a no-op (returning `false`) for a column that cannot
2582
+ * be resized or has nothing mounted to measure.
2583
+ */
2584
+ declare function autosizeColumn<TData extends RowData>({ table, columnId, container }: {
2585
+ table: TMDataGridTable<TData>;
2586
+ columnId: string;
2587
+ container: HTMLElement;
2588
+ }): boolean;
2589
+ //#endregion
2590
+ //#region .types-tmp/core/expanding.d.ts
2591
+ /**
2592
+ * Which rows an expand-all control is about.
2593
+ *
2594
+ * TanStack keeps one `expanded` state, and the grid opens two unrelated things
2595
+ * out of it: a group row opens into its children, a data row opens into its
2596
+ * detail panel. So `toggleAllRowsExpanded` — which writes the state's
2597
+ * whole-table form — is the wrong verb for either control. "Expand all groups"
2598
+ * in the tree menu would open every panel in the grid, and the details lane's
2599
+ * chevron would unfold the whole tree.
2600
+ *
2601
+ * These helpers narrow both to the rows their control is for, and leave the
2602
+ * other kind exactly as it was.
2603
+ */
2604
+ type TMDataGridExpandTarget = "groups" | "details";
2605
+ type TMDataGridExpandAllArgs<TData extends RowData> = {
2606
+ /**
2607
+ * Every row in the model, groups and records alike — `flatRows` off any of
2608
+ * them. A grouped model lists its leaves both under their group and in the
2609
+ * flat list, so this may repeat rows; both helpers are written so that a
2610
+ * repeat costs nothing.
2611
+ */
2612
+ rows: ReadonlyArray<Row<TMDataGridFeatures, TData>>;
2613
+ expanded: ExpandedState;
2614
+ target: TMDataGridExpandTarget;
2615
+ };
2616
+ /**
2617
+ * Whether every row of this kind is open — what the control shows, and what a
2618
+ * bare toggle inverts.
2619
+ *
2620
+ * `false` when there are none of them, matching TanStack's own
2621
+ * `getIsAllRowsExpanded()` on an empty state: an empty set is nothing to
2622
+ * collapse.
2623
+ */
2624
+ declare function areAllRowsExpanded<TData extends RowData>({ rows, expanded, target }: TMDataGridExpandAllArgs<TData>): boolean;
2625
+ /**
2626
+ * The next `expanded` state after an expand-all or collapse-all on one kind of
2627
+ * row. Rows of the other kind keep whatever they had.
2628
+ */
2629
+ declare function resolveExpandAll<TData extends RowData>({ rows, expanded, target, expand }: TMDataGridExpandAllArgs<TData> & {
2630
+ expand: boolean;
2631
+ }): ExpandedState;
2632
+ //#endregion
912
2633
  //#region .types-tmp/core/columnOrdering.d.ts
913
2634
  type GridColumn = Column<TMDataGridFeatures, TMDataGridRowData, unknown>;
914
2635
  type GridTable = TMDataGridTable<TMDataGridRowData>;
@@ -971,6 +2692,10 @@ declare function moveColumnByStep({ table, columnId, direction }: ColumnStepArgs
971
2692
  * is the right list for a range: it is what the user can see, and a range that
972
2693
  * swept collapsed rows would select things off screen. What a group row in the
973
2694
  * range contributes is decided by {@link getSelectableRowIds}.
2695
+ *
2696
+ * Rows pinned to an edge leave this list — they render in their own sticky
2697
+ * blocks, outside the scrolling order a shift-click range or the virtualizer
2698
+ * walks. See `readPinnedRows`.
974
2699
  */
975
2700
  declare function getDisplayedRows<TData extends RowData>(table: TMDataGridTable<TData>, features: TMDataGridFeatureFlags): Array<Row<TMDataGridFeatures, TData>>;
976
2701
  /**
@@ -1054,4 +2779,4 @@ declare function getSelectableRowIds<TData extends RowData>(row: Row<TMDataGridF
1054
2779
  */
1055
2780
  declare function resolveRowSelectionClick<TData extends RowData>({ rows, rowId, anchorRowId, modifiers, selection, canReplaceSelection }: ResolveRowSelectionClickArgs<TData>): ResolvedRowSelection;
1056
2781
  //#endregion
1057
- export { type ColumnStepArgs, DATA_STATE_SLICES, DEFAULT_TMDATAGRID_SIZE, FILTER_OPERATOR_LABELS, GROUP_COLUMN_ID, type MoveColumnArgs, type ResolveRowSelectionClickArgs, type ResolvedRowSelection, SELECT_COLUMN_ID, SETTINGS_STATE_SLICES, SIZE_CONTROL_SIZE, SIZE_ROW_HEIGHT, TMDataGrid, type TMDataGridApi, type TMDataGridCapabilities, type TMDataGridColumnCapabilities, type TMDataGridColumnLayout, type TMDataGridColumnMeta, type TMDataGridColumnRegion, type TMDataGridColumnType, type TMDataGridContextValue, type TMDataGridDataSlice, type TMDataGridDropSide, type TMDataGridFeatureFlags, type TMDataGridFeatures, type TMDataGridFilterOperator, TMDataGridFilterPills, type TMDataGridFilterPillsProps, type TMDataGridFilterValue, type TMDataGridFooterProps, type TMDataGridPaginationApi, type TMDataGridPersistKey, type TMDataGridPersistence, type TMDataGridProps, type TMDataGridRowClickModifiers, type TMDataGridRowContextMenu, type TMDataGridRowContextMenuArgs, type TMDataGridRowData, type TMDataGridSelectionMode, type TMDataGridSettingsSlice, type TMDataGridSize, type TMDataGridStorageMode, type TMDataGridTable, type TMDataGridTableMeta, type TMDataGridTableProps, type TMDataGridUiActions, type TMDataGridUiState, type TMDataGridUiStore, type UseTMDataGridOptions, createTMDataGridColumnHelper, formatFilterLabel, formatGroupValue, getColumnCapabilities, getColumnLabel, getColumnRegion, getColumnType, getDisplayedRows, getGridCapabilities, getGroupDataRows, getSelectableRowIds, getStepTargetColumn, getTMDataGridPaginationApi, isColumnReorderable, isFilterActive, isPagingActive, moveColumn, moveColumnByStep, openColumnFilter, readFeatureFlags, resolveRowSelectionClick, tmDataGridFeatures, useTMDataGrid, useTMDataGridContext };
2782
+ 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 TMDataGridColumnLayout, type TMDataGridColumnMeta, type TMDataGridColumnRegion, type TMDataGridColumnType, type TMDataGridContextValue, type TMDataGridDataSlice, TMDataGridDateEditor, type TMDataGridDetailsArgs, type TMDataGridDetailsRenderer, type TMDataGridDropSide, TMDataGridEditActions, type TMDataGridEditApi, type TMDataGridEditChange, type TMDataGridEditCommitArgs, type TMDataGridEditCommitBatchArgs, type TMDataGridEditField, type TMDataGridEditMode, type TMDataGridEditRowProjection, type TMDataGridEditState, 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 TMDataGridPaginationApi, type TMDataGridPersistKey, type TMDataGridPersistence, type TMDataGridProps, type TMDataGridQuickSearchMode, type TMDataGridRangeBounds, type TMDataGridRowAddArgs, type TMDataGridRowClickModifiers, type TMDataGridRowContextMenu, type TMDataGridRowContextMenuArgs, 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, getColumnLabel, getColumnRegion, getColumnType, getDefaultOperator, getDisplayedRows, getEditFieldName, getGridCapabilities, getGroupDataRows, getOperatorsForType, getSelectableRowIds, getStepTargetColumn, getTMDataGridPaginationApi, 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 };