@opencorestack/opengridx 3.3.0 → 3.5.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 (101) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +10 -1
  3. package/dist/ai.cjs +2 -0
  4. package/dist/ai.cjs.map +1 -0
  5. package/dist/ai.d.ts +366 -0
  6. package/dist/ai.es.js +2 -0
  7. package/dist/ai.es.js.map +1 -0
  8. package/dist/index.d.ts +396 -6
  9. package/dist/opengridx.css +1 -1
  10. package/dist/opengridx.es.js +8029 -6090
  11. package/dist/opengridx.es.js.map +1 -1
  12. package/dist/opengridx.umd.js +16 -14
  13. package/dist/opengridx.umd.js.map +1 -1
  14. package/docs/API_REFERENCE.md +182 -4
  15. package/docs/README.md +5 -1
  16. package/docs/architecture/datagrid-orchestration.md +19 -5
  17. package/docs/components/filter-panel.md +1 -0
  18. package/docs/components/header.md +4 -1
  19. package/docs/components/toolbar.md +7 -0
  20. package/docs/customization/theming.md +12 -1
  21. package/docs/features/ai-toolkit.md +213 -0
  22. package/docs/features/cell-selection.md +8 -2
  23. package/docs/features/clipboard.md +88 -0
  24. package/docs/features/editing-reordering.md +50 -0
  25. package/docs/features/fill-handle.md +125 -0
  26. package/docs/features/filtering.md +3 -0
  27. package/docs/features/header-filters.md +138 -0
  28. package/docs/features/keyboard-navigation.md +31 -2
  29. package/docs/features/undo-redo.md +79 -0
  30. package/docs/roadmap.md +3 -4
  31. package/lib/ai/agentTools.ts +160 -0
  32. package/lib/ai/coerce.ts +90 -0
  33. package/lib/ai/columns.ts +90 -0
  34. package/lib/ai/index.ts +33 -0
  35. package/lib/ai/promptHandler.ts +109 -0
  36. package/lib/ai/schema.ts +214 -0
  37. package/lib/ai/types.ts +152 -0
  38. package/lib/ai/validate.ts +296 -0
  39. package/lib/components/AiAssistant/GridAiAssistantArea.tsx +26 -0
  40. package/lib/components/AiAssistant/GridAiAssistantPanel.css +171 -0
  41. package/lib/components/AiAssistant/GridAiAssistantPanel.tsx +145 -0
  42. package/lib/components/AiAssistant/useSpeechInput.ts +74 -0
  43. package/lib/components/Cell/Cell.css +33 -0
  44. package/lib/components/Cell/Cell.tsx +6 -2
  45. package/lib/components/Cell/GridEditInputCell.css +12 -4
  46. package/lib/components/Cell/GridEditInputCell.tsx +19 -12
  47. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +14 -0
  48. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +3 -2
  49. package/lib/components/DataGrid/DataGrid.tsx +138 -5
  50. package/lib/components/DataGrid/GridLiveRegion.tsx +5 -2
  51. package/lib/components/DataGrid/GridPinnedRows.tsx +5 -1
  52. package/lib/components/DataGrid/GridVirtualRows.tsx +5 -1
  53. package/lib/components/FilterPanel/FilterPanel.css +14 -0
  54. package/lib/components/FilterPanel/FilterPanel.tsx +5 -11
  55. package/lib/components/Header/Header.tsx +44 -23
  56. package/lib/components/Header/headerColumnStyle.ts +28 -0
  57. package/lib/components/HeaderFilter/HeaderFilter.css +160 -0
  58. package/lib/components/HeaderFilter/HeaderFilterCell.tsx +370 -0
  59. package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +124 -0
  60. package/lib/components/HeaderFilter/HeaderFilterRow.tsx +157 -0
  61. package/lib/components/ListView/ListView.css +2 -4
  62. package/lib/components/ListView/ListViewRow.tsx +2 -2
  63. package/lib/components/Toolbar/GlobalSearch.css +16 -0
  64. package/lib/components/Toolbar/GlobalSearch.tsx +3 -2
  65. package/lib/components/Toolbar/GridToolbar.tsx +51 -0
  66. package/lib/components/ui/Checkbox.tsx +16 -5
  67. package/lib/components/ui/Input.css +43 -0
  68. package/lib/components/ui/Input.tsx +24 -5
  69. package/lib/hooks/core/gridApiPlaceholder.ts +16 -1
  70. package/lib/hooks/core/gridToolbarHostContext.ts +5 -0
  71. package/lib/hooks/core/useDataGrid.ts +27 -0
  72. package/lib/hooks/core/useGridApiMethods.ts +39 -0
  73. package/lib/hooks/core/useGridAriaRows.ts +5 -3
  74. package/lib/hooks/core/useGridCellSelection.ts +107 -13
  75. package/lib/hooks/core/useGridClipboardPaste.ts +283 -0
  76. package/lib/hooks/core/useGridColumnsPanel.ts +24 -1
  77. package/lib/hooks/core/useGridControlledState.ts +27 -0
  78. package/lib/hooks/core/useGridFillHandle.ts +323 -0
  79. package/lib/hooks/core/useGridKeyboardNavigation.ts +29 -10
  80. package/lib/hooks/core/useGridToolbarProps.ts +19 -0
  81. package/lib/hooks/core/useGridUndoRedo.ts +220 -0
  82. package/lib/hooks/features/useGridAiAssistant.ts +284 -0
  83. package/lib/hooks/features/useGridBatchEdit.ts +217 -0
  84. package/lib/hooks/features/useGridEditing.ts +24 -45
  85. package/lib/index.ts +10 -0
  86. package/lib/styles/opengridx.css +4 -1
  87. package/lib/theme/DataGridThemeProvider.tsx +2 -0
  88. package/lib/theme/types.ts +2 -0
  89. package/lib/types/index.ts +343 -1
  90. package/lib/utils/aiAssistant.ts +205 -0
  91. package/lib/utils/aiBrand.ts +17 -0
  92. package/lib/utils/cellSelection.ts +25 -5
  93. package/lib/utils/editing/commit.ts +69 -0
  94. package/lib/utils/editing/fill.ts +238 -0
  95. package/lib/utils/editing/targets.ts +109 -0
  96. package/lib/utils/filtering/index.ts +14 -0
  97. package/lib/utils/focus/index.ts +9 -3
  98. package/lib/utils/headerFilters.ts +189 -0
  99. package/lib/utils/parsing.ts +252 -0
  100. package/llms.txt +97 -3
  101. package/package.json +8 -2
@@ -34,6 +34,8 @@ The main component for displaying and interacting with data.
34
34
  | `slots` | `GridSlots` | — | Custom component overrides: `toolbar`, `pagination`, `noRowsOverlay`, `loadingOverlay`, `footer`, `cellSelectionStats`. See [`GridSlots`](#gridslots-and-gridslotprops) and the [Slots API](customization/slots-api.md). |
35
35
  | `slotProps` | `GridSlotProps` | — | Props passed to the slots, keyed like `slots`. `slotProps.toolbar` is typed as `Partial<GridToolbarProps>` (plus any extra keys your own toolbar reads), so `GridToolbar` render props are type-checked (v3.0+). |
36
36
  | `filterModel` | `GridFilterModel` | `undefined` | Active filters (controlled). Omit it to let the grid keep its own filter state, seeded from `initialState.filter` and changed by the toolbar or `apiRef.setFilterModel` (v3.0+). |
37
+ | `headerFilters` | `boolean` | `false` | A filter row under the column headers (v3.5): text, number and date boxes (the shared `Input`), a Yes / No select for `boolean`, a `valueOptions` select for `singleSelect`, an operator menu and a clear button per column. Each cell owns the root `filterModel` item with `id: 'header:<field>'` and leaves every other entry alone; a model it cannot show (root `logicOperator: 'or'`, the field in a group, another root item on the field) is shown as a read-only "Custom filter" that opens the toolbar's filter panel. Typing is debounced by 300 ms. Not rendered in pivot mode. Classes `ogx__header-filter-row`, `ogx__header-filter-cell` (`--focused`, `--active`, `--custom`, `--empty`, `--system`, `--pinned*`), `ogx__header-filter-operator`, `ogx__header-filter-menu`, `ogx__header-filter-input-wrapper`, `ogx__header-filter-input`, `ogx__header-filter-select`, `ogx__header-filter-operator-label`, `ogx__header-filter-clear`, `ogx__header-filter-custom`. See [Header Filters](features/header-filters.md). |
38
+ | `headerFilterHeight` | `number` | `40` | Height of the header filter row in pixels; sets `--ogx-header-filter-height` (v3.5). |
37
39
  | `sortModel` | `GridSortItem[]` | `undefined` | Active sorting. |
38
40
  | `onRowClick` | `(params: GridRowParams) => void` | — | Fired when a row is clicked. Tree-data parent rows are real rows: a click fires this and selects them (their chevron expands them). Not fired for synthetic rows (row-grouping group rows, subtotal rows, auto-created tree parents): clicking a group row toggles it. |
39
41
  | `onRowDoubleClick` | `(params: GridRowParams) => void` | — | Fired when a row is double-clicked (v2.1+). Also fires for group rows, and (v3.0+) for the double-click that opens an editor on an editable cell; not fired on the checkbox, expand icon, drag handle or inside an open editor. |
@@ -82,6 +84,57 @@ interface GridSelectedCell { id: GridRowId; field: string; value: unknown }
82
84
 
83
85
  Public CSS: `ogx__cell--range`, `ogx__cell--range-top` / `-bottom` / `-left` / `-right`, `ogx--range-dragging` (root, during a drag), `--ogx-range-background`, `--ogx-range-border`. Range cells carry `aria-selected="true"`.
84
86
 
87
+ #### Paste and Range Clear (v3.4)
88
+
89
+ | Prop | Type | Default | Description |
90
+ | :--- | :--- | :--- | :--- |
91
+ | `disableClipboardPaste` | `boolean` | `false` | With `cellSelection` on, Ctrl/Cmd+V pastes tab-separated text into the editable cells (through `valueSetter` and `processRowUpdate`, once per row). `true` turns the shortcut off; `apiRef.current.pasteText()` still works. See [Clipboard](features/clipboard.md#-paste-from-excel-and-google-sheets-v34). |
92
+ | `onClipboardPaste` | `(result: GridClipboardPasteResult) => void` | — | Fired after every paste, once every row has settled: `{ updated, failed, skipped, text }`. |
93
+ | `onBeforeClipboardPaste` | `(params: GridBeforeClipboardPasteParams) => boolean \| string` | — | Runs before a paste with `{ text, anchor }`. Return `false` to cancel, a string to paste instead. A throw cancels the paste. |
94
+ | `disableRangeClear` | `boolean` | `false` | With `cellSelection`, Delete / Backspace on a range of more than one cell empties its editable cells (`''` for strings, `null` otherwise) as one edit. `true` turns that off. |
95
+
96
+ #### Undo / Redo (v3.4)
97
+
98
+ | Prop | Type | Default | Description |
99
+ | :--- | :--- | :--- | :--- |
100
+ | `undoRedo` | `boolean \| GridUndoRedoOptions` | `false` | History of committed edits, pastes and range clears: Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl+Y (focus on a cell, no editor open) and `apiRef.undo()` / `redo()`. Undo and redo write through `valueSetter` and `processRowUpdate`; cells changed since are skipped (`'changed'`). `{ limit }`: actions kept, default 100. See [Undo & Redo](features/undo-redo.md). |
101
+ | `onHistoryChange` | `(params: GridHistoryChangeParams) => void` | — | Fired when `canUndo`, `canRedo` or `size` (actions that can be undone) changes. |
102
+
103
+ ```ts
104
+ type GridEditSkipReason = 'notEditable' | 'invalidValue' | 'changed' | 'missing';
105
+ interface GridBatchEditResult {
106
+ updated: GridRowId[]; // rows stored (processRowUpdate succeeded)
107
+ failed: { id: GridRowId; error: unknown }[]; // also sent to onProcessRowUpdateError
108
+ skipped: { id: GridRowId; field: string; reason: GridEditSkipReason }[];
109
+ }
110
+ interface GridClipboardPasteResult extends GridBatchEditResult { text: string }
111
+ interface GridBeforeClipboardPasteParams { text: string; anchor: GridCellCoordinates | null }
112
+ interface GridHistoryChangeParams { canUndo: boolean; canRedo: boolean; size: number }
113
+ interface GridUndoRedoOptions { limit?: number }
114
+ ```
115
+
116
+ #### Fill Handle (v3.5)
117
+
118
+ | Prop | Type | Default | Description |
119
+ | :--- | :--- | :--- | :--- |
120
+ | `disableFillHandle` | `boolean` | `false` | With `cellSelection` on, the range's bottom-right cell carries a fill handle: dragging it down, up, right or left (one direction; auto-scrolls; touch works) fills the new cells from the range, continuing numbers and dates with an exactly equal step and repeating anything else; Alt at release copies. Ctrl/Cmd+D fills down from the range's top row and Ctrl/Cmd+R right from its left column. Writes through `valueSetter` and `processRowUpdate` once per row, as one undo step; non-editable and synthetic cells are skipped (`'notEditable'`). `true` hides the handle and leaves the keys to the browser. See [Fill Handle](features/fill-handle.md). |
121
+ | `onFill` | `(result: GridFillResult) => void` | — | Fired after every fill, once every row has settled: `{ updated, failed, skipped, direction }`. |
122
+
123
+ ```ts
124
+ type GridFillDirection = 'down' | 'up' | 'right' | 'left';
125
+ interface GridFillResult extends GridBatchEditResult { direction: GridFillDirection }
126
+ interface GridFillValueParams<R> {
127
+ row: R; id: GridRowId; field: string; colDef: GridColDef<R>;
128
+ direction: GridFillDirection;
129
+ sourceValues: unknown[]; // the line's source values in fill order
130
+ index: number; // 0 for the cell next to the source
131
+ value: unknown; // what the grid would write
132
+ copy: boolean; // Alt held, or Ctrl/Cmd+D / Ctrl/Cmd+R
133
+ }
134
+ ```
135
+
136
+ Public CSS: `ogx__cell-fill-handle` (24 × 24 px hit area in the corner cell; the visible square is its `::after`), `--ogx-fill-handle-color` (defaults to `--ogx-range-border`; theme key `grid.fillHandleColor`).
137
+
85
138
  #### Column Visibility
86
139
 
87
140
  | Prop | Type | Default | Description |
@@ -139,7 +192,8 @@ Public CSS: `ogx__cell--range`, `ogx__cell--range-top` / `-bottom` / `-left` / `
139
192
 
140
193
  | Prop | Type | Default | Description |
141
194
  | :--- | :--- | :--- | :--- |
142
- | `rowGroupingModel` | `GridRowGroupingModel` | `[]` | Array of field names to group rows by (e.g. `['department', 'team']`). See [Row Grouping](#️-row-grouping). |
195
+ | `rowGroupingModel` | `GridRowGroupingModel` | — | Array of field names to group rows by (e.g. `['department', 'team']`). Passing it controls grouping; without it the grid keeps its own model (initially `[]`), which `apiRef.setRowGroupingModel()` and the AI assistant change (v3.5.0+). See [Row Grouping](#️-row-grouping). |
196
+ | `onRowGroupingModelChange` | `(model: GridRowGroupingModel) => void` | — | Fired when the grouping model changes through `apiRef.setRowGroupingModel()` or the AI assistant. With a controlled `rowGroupingModel`, update the prop from it (v3.5.0+). |
143
197
  | `aggregationModel` | `GridAggregationModel` | — | Map of `field → aggFn` (e.g. `{ salary: 'sum', age: 'avg' }`). See [Aggregation Reference](#-aggregation-reference). |
144
198
  | `onAggregationModelChange` | `(model: GridAggregationModel) => void` | — | Fired when the aggregation model changes. |
145
199
  | `getAggregationPosition` | `(groupNode: GridTreeNode \| null) => 'inline' \| 'footer' \| null` | — | Controls where aggregation results appear. Called for every group node (with its current `isExpanded`) and once with `null` for the grand total. `'inline'` (group default) = on the group row, `'footer'` = on a subtotal row after the group's children while it is expanded (on the group row while collapsed), `null` = hidden. For the grand total, `null` hides the footer row. A callback that throws gets the default (`'inline'` for a group, `'footer'` for the grand total; v3.0+). See [the callback](#getaggregationposition-callback). |
@@ -152,6 +206,24 @@ Public CSS: `ogx__cell--range`, `ogx__cell--range-top` / `-bottom` / `-left` / `
152
206
  | `pivotModel` | `GridPivotModel` | — | Controlled pivot configuration (row fields, column fields, value fields). |
153
207
  | `onPivotModelChange` | `(model: GridPivotModel) => void` | — | Fired when the pivot model changes. |
154
208
 
209
+ #### AI Assistant (v3.5)
210
+
211
+ | Prop | Type | Default | Description |
212
+ | :--- | :--- | :--- | :--- |
213
+ | `aiAssistant` | `GridAiAssistantOptions` | — | The "Ask AI" prompt panel: `{ onPrompt, placeholder?, suggestions?, voice?, parts? }`. The built-in toolbar shows an **Ask AI** button (`localeText.aiAssistantButton`); `apiRef.openAiAssistant()` opens the panel without one; `slots.aiAssistantPanel` replaces it. A reply is applied only when its `state` carries the brand `validateGridAiState` sets (build `onPrompt` with `createGridAiPromptHandler`); it is applied at once as one undoable step, shown as removable chips. See [AI Toolkit](features/ai-toolkit.md#ai-assistant-panel). Grids without it are unchanged. |
214
+ | `onAiAssistantApply` | `(result: GridAiPromptResult) => void` | — | Fired after the assistant applied a reply. |
215
+ | `onAiAssistantError` | `(error: unknown) => void` | — | Fired when `onPrompt` rejects (not on Stop) or returns a result that was not validated. |
216
+
217
+ `GridAiAssistantOptions`:
218
+
219
+ | Option | Type | Default | Description |
220
+ | :--- | :--- | :--- | :--- |
221
+ | `onPrompt` | `(prompt: string, context: GridAiPromptContext) => Promise<GridAiPromptResult>` | — | Answers a prompt. `context` is `{ currentState, history, signal }`: the grid's models (`GridAiState`), earlier prompts of the session (`GridAiHistoryEntry[]`: `{ prompt, applied }`) and an `AbortSignal` aborted by Stop, a new prompt or closing the panel. Resolve with `{ state, errors, message? }` from `validateGridAiState` or `createGridAiPromptHandler`. |
222
+ | `placeholder` | `string` | `'Ask about this table…'` | Placeholder of the prompt input. |
223
+ | `suggestions` | `string[]` | — | Example prompts shown as clickable chips. |
224
+ | `voice` | `boolean` | `true` | Shows a microphone button where the browser has `SpeechRecognition` / `webkitSpeechRecognition`. The microphone is asked for only when the button is clicked; elsewhere the button is hidden. |
225
+ | `parts` | `GridAiPart[]` | every part | The parts of the state the assistant may change. Other parts of a reply are ignored ("Part not allowed"). |
226
+
155
227
  #### Scroll & Viewport
156
228
 
157
229
  | Prop | Type | Default | Description |
@@ -171,7 +243,7 @@ Public CSS: `ogx__cell--range`, `ogx__cell--range-top` / `-bottom` / `-left` / `
171
243
 
172
244
  | Prop | Type | Default | Description |
173
245
  | :--- | :--- | :--- | :--- |
174
- | `localeText` | `GridLocaleText` | — | Override user-visible strings: the Pagination labels and the empty-state label (`noRowsLabel`, which wins over the `noRowsLabel` prop). See [`GridLocaleText`](#gridlocaletext). |
246
+ | `localeText` | `GridLocaleText` | — | Override user-visible strings: the Pagination labels, the empty-state label (`noRowsLabel`, which wins over the `noRowsLabel` prop), the cell-range announcement and the Ask AI button (`aiAssistantButton`). See [`GridLocaleText`](#gridlocaletext). |
175
247
 
176
248
  #### Imperative Ref
177
249
 
@@ -232,6 +304,7 @@ The types of the `slots` and `slotProps` props (v3.0+ exports). Each slot is typ
232
304
  | `noRowsOverlay` | The empty-state icon and label (shown when there are no rows and the grid is not loading). | `slotProps.noRowsOverlay` only (`GridOverlaySlotProps`). |
233
305
  | `loadingOverlay` | The loading indicator: the skeleton rows while loading with no rows, the progress bar while loading with rows shown (the slot is then shown over them). | `slotProps.loadingOverlay` only (`GridOverlaySlotProps`). |
234
306
  | `cellSelectionStats` | The status bar of `showCellSelectionStats` (v3.3). Rendered while more than one cell is selected. | `GridCellSelectionStatsSlotProps`: `apiRef`, `cellCount`, `rowCount`, `columnCount`, `count`, `numericCount`, `sum`, `average` (`null` without numeric cells), then `slotProps.cellSelectionStats`. |
307
+ | `aiAssistantPanel` | The `aiAssistant` panel (v3.5). Rendered while the panel is open, under the toolbar; Escape inside it closes it. | `GridAiAssistantPanelProps`: `status`, `statusText`, `message`, `errors`, `chips` (`GridAiChip[]`: `{ id, part, label }`), `history`, `suggestions`, `placeholder`, `voiceAvailable`, `canUndo`, and the actions `submit(prompt)`, `stop()`, `undo()`, `removeChip(id)`, `close()`; then `slotProps.aiAssistantPanel`. |
235
308
  | `footer` | The pagination area. | `GridFooterSlotProps`: `apiRef`, `aggregationModel`, `aggregationResult`, `rowCount`, `pagination`, `paginationModel`, `pageSizeOptions`, `onPaginationModelChange`, then `slotProps.footer`. `rowCount` is the built-in pager's count (pinned rows excluded, v3.0+); under tree data or row grouping, the filtered data rows. |
236
309
 
237
310
  ```ts
@@ -264,6 +337,8 @@ The built-in toolbar component. Mount it via `slots={{ toolbar: GridToolbar }}`.
264
337
  | `onColumnOrderReset` | `() => void` | — | Called when the user clicks "Reset order" in the Columns panel. |
265
338
  | `forceColumnsOpen` | `boolean` | — | Opens the Columns panel when it becomes `true` (set by `DataGrid` for the column menu's **Manage columns**). If the toolbar slot does not render a `GridToolbar` that receives it, the grid opens its standalone Columns panel instead. |
266
339
  | `onColumnsPanelClose` | `() => void` | — | Called whenever the Columns panel closes (its button, a custom button, another panel opening, click-outside or Escape). |
340
+ | `forceFiltersOpen` | `boolean` | — | Opens the filter panel when it becomes `true` (v3.5; set by `DataGrid` for a header filter cell's "Custom filter"). Only a `GridToolbar` that receives it lets that label open the panel. |
341
+ | `onFiltersPanelClose` | `() => void` | — | Called whenever the filter panel closes (v3.5). |
267
342
  | `children` | `ReactNode` | — | Content rendered on the **left** side of the toolbar, before the spacer. |
268
343
  | `rightContent` | `ReactNode` | — | Content rendered on the **right** side, after all built-in buttons. |
269
344
  | `className` | `string` | — | Additional CSS class on the toolbar root `<div>`. Use for visual theme overrides. |
@@ -273,6 +348,9 @@ The built-in toolbar component. Mount it via `slots={{ toolbar: GridToolbar }}`.
273
348
  | `renderAggregationButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | — | Replace the built-in Summaries toggle button. The Aggregation panel still functions normally. |
274
349
  | `renderExportButton` | `() => ReactNode` | — | Inject an Export button after the Aggregation button. No built-in export button exists. |
275
350
  | `renderQuickFilter` | `(props: ToolbarQuickFilterRenderProps) => ReactNode` | — | Replace the built-in `GlobalSearch` input with your own component. |
351
+ | `onAiAssistantToggle` | `(trigger: HTMLElement \| null) => void` | — | Opens or closes the `aiAssistant` panel. The grid injects it when `aiAssistant` is set; its presence renders the **Ask AI** button (sparkle icon), first in the button row. Focus returns to `trigger` when the panel closes (v3.5). |
352
+ | `aiAssistantOpen` | `boolean` | `false` | Whether the panel is open (`aria-expanded` of the button; injected by the grid) (v3.5). |
353
+ | `aiAssistantLabel` | `string` | `'Ask AI'` | The button's label; the grid passes `localeText.aiAssistantButton` (v3.5). |
276
354
 
277
355
  ### `ToolbarButtonRenderProps`
278
356
 
@@ -329,6 +407,18 @@ Access these methods via the `apiRef` prop.
329
407
  | `clearCellSelection()` | `void` | Empty the cell selection (`reason: 'clear'`) (v3.3). |
330
408
  | `getSelectedCells()` | `GridSelectedCell[]` | Cells of the range in display order with values read through `valueGetter`. Synthetic rows and span-covered positions are left out (v3.3). |
331
409
  | `copySelectedCells()` | `Promise<void>` | Copy the range (the focused cell when nothing else is selected) as TSV without a header line. Resolves without writing when there is nothing to copy; rejects when the clipboard write fails (v3.3). |
410
+ | `pasteText(text, anchor?)` | `Promise<GridBatchEditResult>` | Paste tab-separated text as Ctrl/Cmd+V does, from `anchor` (default: the range's top-left cell, else the focused cell), with `onBeforeClipboardPaste` / `onClipboardPaste`. Works with `disableClipboardPaste` and without `cellSelection` (then pass `anchor` or focus a cell) (v3.4). |
411
+ | `undo()` | `Promise<GridBatchEditResult>` | Undo the last action (`undoRedo`); resolves once every row has settled (v3.4). |
412
+ | `redo()` | `Promise<GridBatchEditResult>` | Redo the last undone action (v3.4). |
413
+ | `canUndo()` / `canRedo()` | `boolean` | Whether there is an action to undo / redo (v3.4). |
414
+ | `clearHistory()` | `void` | Forget every undo and redo action (v3.4). |
415
+ | `setSortModel(model)` | `void` | Replace the sort model. Fires `onSortModelChange` (v3.5). |
416
+ | `setRowGroupingModel(model)` | `void` | Replace the row grouping model. Fires `onRowGroupingModelChange`; with a controlled `rowGroupingModel`, update the prop from it (v3.5). |
417
+ | `setAggregationModel(model)` | `void` | Replace the aggregation model. Fires `onAggregationModelChange` (v3.5). |
418
+ | `setColumnVisibilityModel(model)` | `void` | Replace the column visibility model. Fires `onColumnVisibilityModelChange` (v3.5). |
419
+ | `setPivotModel(model)` | `void` | Replace the pivot model. Fires `onPivotModelChange` (v3.5). |
420
+ | `getGridAiState()` | `GridAiState` | The current `filterModel`, `sortModel`, `rowGroupingModel`, `aggregationModel`, `pivotModel` and `columnVisibilityModel`, as the AI toolkit reads them. Like the other getters it sees a setter's value in the same tick (v3.5). |
421
+ | `openAiAssistant()` / `closeAiAssistant()` | `void` | Open or close the `aiAssistant` panel; `openAiAssistant` does nothing without `aiAssistant` (v3.5). |
332
422
  | `copySelectedRows()` | `Promise<void>` | Copy every selected row that passes the filter (other pages, collapsed groups and pinned rows included) as TSV, with the visible columns in screen order. Resolves without writing when no selected row is found; rejects when the clipboard write fails. |
333
423
 
334
424
  ---
@@ -385,6 +475,8 @@ Defines the behavior and appearance of a single column.
385
475
  | `valueOptions` | `Array<string \| number \| { value: unknown; label: string }>` | — | Allowed values for `type: 'singleSelect'` — the filter panel offers them as a (multi-)select, and the edit cell uses them; cells and exports show the option's label. |
386
476
  | `valueGetter` | `(params: GridValueGetterParams) => unknown` | — | Derive a computed value from the row object. Runs before `valueFormatter` and `renderCell`. Client-side sorting, column filters and the quick filter use this value, and editors start from it (double-click and Enter alike). Keep it pure: the quick filter caches each row's search text per row object and column set. A getter that throws for a row shows an error in that cell and reads as `undefined` for sorting, filtering, aggregation, grouping, pivot and list view (v3.0+, with a one-time development warning per column); before, it crashed the grid once the column was sorted, filtered or aggregated. |
387
477
  | `valueSetter` | `(params: GridValueSetterParams) => R` | — | v3.0+. Maps an edited value back onto the row (`{ value, row, field }` → updated row) when an edit is committed. Needed for editable `valueGetter` columns; without it the commit writes `row[field]` and a development warning is logged. |
478
+ | `fillValue` | `(params: GridFillValueParams) => unknown` | — | v3.5+. Decides what a fill (handle drag, Ctrl/Cmd+D, Ctrl/Cmd+R) writes into a cell of this column. `params.value` is the grid's choice (series, pattern or copy); return it to keep it. A throw skips the cell (`'invalidValue'`). See [Fill Handle](features/fill-handle.md#gridcoldeffillvalue). |
479
+ | `valueParser` | `(text: string, params: GridValueParserParams) => unknown` | — | v3.4+. Turns pasted text into this column's value instead of the default parser for its `type` (`{ row, field, colDef }`). Throw or return `undefined` to skip the cell (`'invalidValue'`). See [Clipboard](features/clipboard.md#valueparser). |
388
480
  | `valueFormatter` | `(params: GridValueFormatterParams) => string` | — | Format the value into a display string (e.g. currency, dates). Does not affect editing, sorting or column filters; the quick filter also searches the formatted text. A formatter that throws leaves the value unformatted (the quick filter searches the raw value; v3.0+). |
389
481
 
390
482
  #### Rendering
@@ -423,7 +515,9 @@ Span values are floored; `Infinity` means "to the end"; `NaN`, `0` and negative
423
515
  | :--- | :--- | :--- | :--- |
424
516
  | `sortable` | `boolean` | `true` | Enable/disable sorting for this column. |
425
517
  | `sortComparator` | `(v1, v2, params1, params2) => number` | — | Custom ascending comparator for client-side sorting (v3.1.0+). `v1`/`v2` are `valueGetter` values **including `null`/`undefined`**; `params` are `GridSortCellParams` `{ id, field, row, value }`. Negated for `desc`, chained in multi-sort, used for group ordering under row grouping, tree-data siblings and pivot row labels. Throw / `NaN` reads as 0 (dev warning once). Ignored with `sortingMode="server"`. |
426
- | `filterable` | `boolean` | `true` | Enable/disable filtering for this column. `false` also removes it from the quick-filter search. |
518
+ | `filterable` | `boolean` | `true` | Enable/disable filtering for this column. `false` also removes it from the quick-filter search and the header filter row. |
519
+ | `headerFilter` | `boolean` | `true` | `false` leaves this column's cell in the header filter row (`headerFilters`) empty (v3.5). `image` columns never get a control. |
520
+ | `headerFilterOperator` | `GridFilterOperator` | by type | The operator a new header filter starts with (v3.5). Defaults: `contains` (string), `=` (number), `is` (date, boolean, singleSelect). |
427
521
  | `resizable` | `boolean` | `true` | Allow the user to drag-resize this column; double-click the handle (or Enter on it) to auto-size to content (v3.1.0+). |
428
522
  | `hideable` | `boolean` | `true` | Allow the user to hide this column from the UI. `false` removes it from the Columns panel (unless `showNonHideableColumns`) and removes **Hide Column** from its column menu. |
429
523
  | `pinnable` | `boolean` | `true` | Allow this column to be pinned via the UI. `false` removes the pin actions from its column menu. Does not affect drag-reordering (v3.0+). |
@@ -433,6 +527,7 @@ Span values are floored; `Infinity` means "to the end"; `NaN`, `0` and negative
433
527
  | `groupingValueFormatter` | `(params: { field: string; value: unknown }) => string` | — | Custom formatter for group-header labels when this column is the active grouping field. Falls back to `"field: value"` when omitted or when it throws (v3.0+). |
434
528
  | `aggregable` | `boolean` | — | Whether this column can be aggregated. Unset, the toolbar's Summaries panel and the pivot panel's value fields offer it only for `type: 'number'` columns; `true` offers it for any type. `false` keeps it out of both panels, and an `aggregationModel` or `pivotModel` entry naming it is ignored (no footer total, group aggregate, pivot value or export total). |
435
529
  | `availableAggregationFunctions` | `string[]` | all built-ins | Restrict which aggregation functions are computed and available for this column (e.g. `['sum', 'avg']`). Functions outside this list are skipped even if set in `aggregationModel` or a pivot value field, the toolbar's Summaries panel and the pivot panel offer only these. |
530
+ | `aiExamples` | `unknown[]` | — | Example values put into the schema from `getGridAiSchema` (`@opencorestack/opengridx/ai`) to help a model write filters. **These values are sent to the model**: the schema never reads row data, so only what you list here leaves the app. Strings, numbers and booleans, at most 10. Not used by the grid itself (v3.4.0+). |
436
531
 
437
532
  ---
438
533
 
@@ -453,6 +548,50 @@ Every exporter takes `columns` typed for your rows (`GridColDef<R>[]`) or untype
453
548
 
454
549
  ---
455
550
 
551
+ ## 🤖 AI Toolkit (`@opencorestack/opengridx/ai`)
552
+
553
+ A separate entry point (v3.4.0+) with no React import and no dependencies; the core package never loads it. It does not call any AI service: the app sends the schema to its own model and validates the reply. Guide: [AI Toolkit](features/ai-toolkit.md).
554
+
555
+ ```ts
556
+ import { getGridAiSchema, validateGridAiState, createGridAiPromptHandler, createGridAgentTools } from '@opencorestack/opengridx/ai';
557
+ import type { GridAiState, GridAiValidationError, GridAgentTool } from '@opencorestack/opengridx/ai';
558
+ ```
559
+
560
+ | Function | Return | Description |
561
+ | :--- | :--- | :--- |
562
+ | `getGridAiSchema(columns, options?)` | `GridAiSchema` | JSON Schema (draft 2020-12, `schemaVersion: 1`) of the `filterModel` (nested AND/OR groups up to 3 levels, `quickFilterValues`), `sortModel`, `rowGroupingModel`, `aggregationModel`, `pivotModel` and `columnVisibilityModel` the columns allow, honouring `filterable`, `sortable`, `groupable`, `hideable`, `aggregable`, `availableAggregationFunctions` and `valueOptions`. Operators per column come from the column type. Reads column definitions only, never rows; deterministic for the same input. |
563
+ | `validateGridAiState(json, columns, options?)` | `GridAiValidationResult` | `{ state, errors }`. `json` is an object or a JSON string. Drops unknown parts, fields, operators and enum values (each with an `{ path, message }` error), coerces values to the column type (`"1,200"` → `1200`, dates → `"YYYY-MM-DD"`), removes empty filter groups. Never throws. Since v3.5 the result and its `state` carry the non-enumerable brand `Symbol.for('opengridx.ai.validated')`, which `aiAssistant` requires. |
564
+ | `createGridAiPromptHandler({ columns, callModel, parts?, schemaOptions? })` | `(prompt, context) => Promise<GridAiPromptResult>` | Builds `aiAssistant.onPrompt` (v3.5). Builds the schema once; per prompt calls `callModel({ prompt, schema, currentState, history }, { signal })`, reads the reply (a state object, a JSON string, or a fenced JSON block inside text; a `message` key or the text around the JSON becomes `result.message`; plain text becomes the message with nothing to apply), validates it and returns the branded result. A `callModel` throw or rejection gives `{ state: {}, errors: [{ path: '', message }] }`; an abort rejects with an `AbortError`, also when `callModel` ignores the signal. |
565
+ | `createGridAgentTools(apiRef, columns, options?)` | `GridAgentTool[]` | Plain tools for AI agents (v3.5): `get_grid_state`, `set_filter`, `set_sort`, `set_grouping`, `set_aggregation`, `set_column_visibility` (merged over the current model), `clear_filters`, and `get_row_summary` only with `options.allowRowAccess: true`. Each is `{ name, description, inputSchema, execute(input) }`; inputs are validated with `validateGridAiState` and applied through `apiRef` only when they have no errors. `execute` never throws. A `set_*` tool whose part no column allows is left out. |
566
+
567
+ `GridAiSchemaOptions`: `include` / `exclude` (`GridAiPart[]`: `'filter' \| 'sort' \| 'grouping' \| 'aggregation' \| 'pivot' \| 'columnVisibility'`; `exclude` wins), `descriptions` (default `true`: each column's `headerName` and `description` go into the schema), `examples` (default `true`: the columns' `aiExamples` go into the schema). `GridAiValidateOptions` takes `include` / `exclude`; parts outside them are dropped with an error.
568
+
569
+ | Type | Description |
570
+ | :--- | :--- |
571
+ | `GridAiColumn` | The column properties the toolkit reads. A `GridColDef` (typed or untyped) is accepted as is. Fields starting with `__` (system columns) are skipped. |
572
+ | `GridAiSchema` | The returned JSON Schema object: `$schema`, `schemaVersion: 1`, `title`, `type: 'object'`, `properties` (one per offered part) and `$defs`. |
573
+ | `GridAiState` | The validated state: `filterModel?`, `sortModel?`, `rowGroupingModel?`, `aggregationModel?`, `pivotModel?`, `columnVisibilityModel?`, the same types the grid's props take. Only parts present in the reply are set. |
574
+ | `GridAiValidationError` | `{ path: string; message: string }`, e.g. `{ path: 'filterModel.items[2].field', message: 'Unknown field "revenue"' }`. At most 100 are listed. |
575
+ | `GridAiValidationResult` | `{ state: GridAiState; errors: GridAiValidationError[] }` (branded since v3.5). |
576
+ | `GridAiPart` | `'filter' \| 'sort' \| 'grouping' \| 'aggregation' \| 'pivot' \| 'columnVisibility'`. |
577
+ | `GridAiPromptHandlerOptions` | `{ columns, callModel, parts?, schemaOptions? }` of `createGridAiPromptHandler` (v3.5). |
578
+ | `GridAiModelRequest` | What `callModel` receives: `{ prompt, schema, currentState, history }` (v3.5). |
579
+ | `GridAiPromptContext` | `onPrompt`'s second argument: `{ currentState: GridAiState; history: GridAiHistoryEntry[]; signal: AbortSignal }` (v3.5). |
580
+ | `GridAiPromptResult` | `{ state: GridAiState; errors: GridAiValidationError[]; message?: string }` (v3.5). |
581
+ | `GridAiHistoryEntry` | `{ prompt: string; applied: GridAiState }` (v3.5). |
582
+ | `GridAiAssistantOptions` | The `aiAssistant` prop (v3.5). |
583
+ | `GridAiAssistantPanelProps` | Props of `slots.aiAssistantPanel` (v3.5). |
584
+ | `GridAiAssistantStatus` | `'idle' \| 'running' \| 'applied' \| 'stopped' \| 'error'` (v3.5). |
585
+ | `GridAiChip` | `{ id: string; part: GridAiPart; label: string }`: one applied change (v3.5). |
586
+ | `GridAgentTool` | `{ name: string; description: string; inputSchema: GridAiJsonSchema; execute: (input: unknown) => Promise<GridAgentToolResult> }` (v3.5). |
587
+ | `GridAgentToolResult` | `{ ok: boolean; applied?; errors?; state?; columns?; rowCount?; rows? }` (v3.5). |
588
+ | `GridAgentToolsOptions` | `{ allowRowAccess?: boolean; fields?: string[]; maxRows?: number }`: `get_row_summary` returns the row count and at most `maxRows` (default 20) rows, limited to `fields` (default: every column given), values read through `valueGetter` (v3.5). |
589
+ | `GridAgentApi` | The part of `GridApi` the tools use; `apiRef.current` fits it (v3.5). |
590
+
591
+ The state and assistant types (`GridAiState`, `GridAiPart`, `GridAiValidationError`, `GridAiPrompt*`, `GridAiAssistant*`, `GridAiChip`) are declared with the grid's own types since v3.5 and exported from `@opencorestack/opengridx/ai`; they are type-only, so importing them adds nothing to a bundle.
592
+
593
+ ---
594
+
456
595
  ## 🧩 Standalone Components
457
596
 
458
597
  The grid's building blocks are exported with their props types (the props types since v3.0). `DataGrid` renders all of them itself; import them to build your own layout or slot.
@@ -469,7 +608,33 @@ The grid's building blocks are exported with their props types (the props types
469
608
  | `Cell` | `CellProps` | One body cell. See [Cell](components/cell.md). |
470
609
  | `CellSelectionStats` | `CellSelectionStatsProps` | The default status bar of `showCellSelectionStats` (v3.3), e.g. to wrap in a `cellSelectionStats` slot. |
471
610
  | `Skeleton` | `SkeletonProps` | Loading placeholder (`rows`, `columns`, both default 5). |
472
- | `Button`, `Input`, `Checkbox` | `ButtonProps`, `InputProps`, `CheckboxProps` | The grid's form controls. `Button` defaults to `type="button"`. |
611
+ | `Button`, `Input`, `Checkbox` | `ButtonProps`, `InputProps`, `CheckboxProps` | The grid's form controls. `Button` defaults to `type="button"`. See [`Input`](#input) and [`Checkbox`](#checkbox) below. |
612
+
613
+ ### `Input`
614
+ A text field: an `<input class="ogx-input">` inside a `<div class="ogx-input-wrapper">` that also holds the adornments. The grid's search boxes, filter value box and text / number / date cell editors render through it. Every other `<input>` attribute (`value`, `onChange`, `type`, `id`, `name`, `aria-*`, …) goes to the `<input>`.
615
+
616
+ | Prop | Type | Default | Description |
617
+ | :--- | :--- | :--- | :--- |
618
+ | `ref` | `Ref<HTMLInputElement>` | — | Reaches the `<input>` (`forwardRef`, React 18 and 19). Since v3.3.1. |
619
+ | `variant` | `'field' \| 'cell'` | `'field'` | `'field'`: bordered form field. `'cell'`: fills its container (a grid cell), no border, radius, background or focus shadow, cell font and the editor padding; adds `ogx-input-wrapper--cell`. Since v3.3.1. |
620
+ | `inputClassName` | `string` | — | Classes added to the `<input>` next to `ogx-input`. Since v3.3.1. |
621
+ | `className` | `string` | — | Classes added to the wrapper `<div>`. |
622
+ | `fullWidth` | `boolean` | `false` | Wrapper takes 100% width (`ogx-input-wrapper--full-width`). |
623
+ | `error` | `boolean` | `false` | `ogx-input-wrapper--error` (error border; inset error edge in the cell variant) and `aria-invalid="true"` on the `<input>`. |
624
+ | `startAdornment` / `endAdornment` | `ReactNode` | — | Content before / after the `<input>` (`ogx-input__adornment--start` / `--end`), e.g. a currency or a unit. |
625
+ | `disabled` | `boolean` | — | Disables the `<input>` and adds `ogx-input-wrapper--disabled`. |
626
+
627
+ ### `Checkbox`
628
+ A styled checkbox: a visually hidden `<input type="checkbox" class="ogx-checkbox__input">` and a drawn `.ogx-checkbox__box`, inside a `<label class="ogx-checkbox-wrapper">`. Other props (`checked`, `onChange`, `onMouseDown`, `tabIndex`, `aria-*`, …) go to the `<input>`. The grid's row checkboxes, column panel, list view and boolean cell editor use it.
629
+
630
+ | Prop | Type | Default | Description |
631
+ | :--- | :--- | :--- | :--- |
632
+ | `ref` | `Ref<HTMLInputElement>` | — | Reaches the `<input>` (`forwardRef`). Since v3.3.1. |
633
+ | `inputRef` | `Ref<HTMLInputElement>` | — | Also reaches the `<input>` (kept for compatibility). |
634
+ | `inputClassName` | `string` | — | Classes added to the `<input>` next to `ogx-checkbox__input`. Since v3.3.1. |
635
+ | `className` | `string` | — | Classes added to the wrapper `<label>`. |
636
+ | `indeterminate` | `boolean` | `false` | Shows the indeterminate mark and sets the input's `indeterminate`. |
637
+ | `label` | `string` | — | Visible label text after the box; also the accessible name. |
473
638
 
474
639
  ---
475
640
 
@@ -722,6 +887,8 @@ interface GridLocaleText {
722
887
  noRowsLabel?: string;
723
888
  /** v3.3: live-region text after a cell range change. Default "12 cells selected, 3 rows by 4 columns". */
724
889
  cellSelectionAnnouncement?: (cellCount: number, rowCount: number, columnCount: number) => string;
890
+ /** v3.5: label of the toolbar's Ask AI button. Default "Ask AI". */
891
+ aiAssistantButton?: string;
725
892
  }
726
893
  ```
727
894
 
@@ -814,6 +981,15 @@ Passed to `valueSetter` (v3.0+).
814
981
  | `row` | `R` | The row as it was before the edit. |
815
982
  | `field` | `string` | The column field name. |
816
983
 
984
+ ### `GridValueParserParams<R>`
985
+ Passed to `valueParser` (v3.4+).
986
+
987
+ | Property | Type | Description |
988
+ | :--- | :--- | :--- |
989
+ | `row` | `R` | The row the text is pasted into, as stored now. |
990
+ | `field` | `string` | The column field name. |
991
+ | `colDef` | `GridColDef<R>` | The column. |
992
+
817
993
  ### `GridColumnOrderChangeParams`
818
994
  Passed to `onColumnOrderChange`.
819
995
 
@@ -1086,6 +1262,8 @@ The filter panel shows only the operators relevant to each column's `type`; an o
1086
1262
  | `boolean` | `is` | `is` |
1087
1263
  | `singleSelect` | `isAnyOf` | `isAnyOf`, `is`, `not` |
1088
1264
 
1265
+ The header filter row (`headerFilters`) offers the same operators; it starts `singleSelect` columns with `is` (one value from a select) and any column with its `headerFilterOperator`.
1266
+
1089
1267
  ### Nested Group Example
1090
1268
 
1091
1269
  ```tsx
package/docs/README.md CHANGED
@@ -32,12 +32,15 @@ In-depth guides on the grid's functional capabilities.
32
32
 
33
33
  - **[Virtualization](features/virtualization.md)** - Handling massive datasets
34
34
  - **[Filtering & Search](features/filtering.md)** - Column filters and Global Quick Search
35
+ - **[Header Filters](features/header-filters.md)** - A filter row under the column headers, sharing the filter model
35
36
  - **[Sorting & Pagination](features/sorting-pagination.md)** - Organizing and navigating data
36
37
  - **[Editing & Reordering](features/editing-reordering.md)** - Inline edits and Drag-and-Drop
37
38
  - **[Loading & Performance](features/loading-states.md)** - Skeletons, Lazy, and Infinite loading
38
39
  - **[Row Selection](features/selection.md)** - Multi & single choice selection
39
- - **[Clipboard](features/clipboard.md)** - Copy and Paste grid data
40
+ - **[Clipboard](features/clipboard.md)** - Copy rows and ranges, paste from Excel / Sheets, clear a range with Delete
40
41
  - **[Cell Range Selection](features/cell-selection.md)** - Spreadsheet-style cell ranges, copy and a sum / average status bar
42
+ - **[Undo & Redo](features/undo-redo.md)** - Ctrl+Z / Ctrl+Shift+Z for edits, pastes and range clears
43
+ - **[Fill Handle](features/fill-handle.md)** - Drag the range corner to continue a series or copy, Ctrl+D / Ctrl+R
41
44
  - **[Pinning](features/pinning.md)** - Sticky columns and rows
42
45
  - **[State Persistence](features/state-persistence.md)** - Save/Restore grid configuration
43
46
  - **[Aggregation & Pivot](features/aggregation-pivot.md)** - Data summarization and analytics
@@ -49,6 +52,7 @@ In-depth guides on the grid's functional capabilities.
49
52
  - **[Infinite Scroll](features/infinite-scroll.md)** - Advanced performance loading
50
53
  - **[Data Source](features/data-source.md)** - Server-side fetching and SSR
51
54
  - **[Export Guide](features/export-guide.md)** - Excel, CSV, JSON, and Print
55
+ - **[AI Toolkit](features/ai-toolkit.md)** - JSON Schema of the grid state for your own model, a validator for its replies, the **Ask AI** panel (`aiAssistant`) and tools for AI agents (`@opencorestack/opengridx/ai`)
52
56
 
53
57
  ---
54
58
 
@@ -20,6 +20,13 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
20
20
  - `useGridCellSelection` runs after `useGridSpanning` (it needs `getSpanOrigin` and the span caches) and
21
21
  before `useGridKeyboardNavigation`, which receives its Shift-key handlers. `useGridCellSelectionApi` runs
22
22
  after the keyboard hook because it reads and sets `focusedCell`.
23
+ - `useGridBatchEdit` is created before `useGridEditing` (single edits store through it, so an undo right after an
24
+ edit reads the stored row before the next render). The history hook needs the focus and selection hooks, so it runs
25
+ late (36c); commits reach it through `useGridEditCommitChannel` (12a), whose listener it sets in a layout effect.
26
+ `useGridClipboardPaste` (36b) and `useGridUndoRedo` listen for keys on the grid root with native listeners, which
27
+ fire before React's delegated `onKeyDown` of the viewport; they act only on cell targets with no editor open.
28
+ `useGridFillHandle` (36d) does the same for Ctrl/Cmd+D and Ctrl/Cmd+R; its fills commit through the batch edit
29
+ with source `'fill'`, so the history records them like a paste.
23
30
  - `useGridLiveRowSelection` prunes the selection, and `useGridPageCorrection` corrects a page past the
24
31
  end, in effects that run before the later hooks' effects.
25
32
 
@@ -28,7 +35,7 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
28
35
  | # | Hook / util | File | Produces |
29
36
  | :- | :--- | :--- | :--- |
30
37
  | 0 | `useStableColumns` | `hooks/core/useStableColumns.ts` | The `columns` prop with a stable identity while every column is shallowly equal (inline columns do not re-run the row passes) |
31
- | 1 | `useGridControlledState` | `hooks/core/useGridControlledState.ts` | Controlled/uncontrolled sort, filter, aggregation, visibility, pinning, pivot, pagination, selection, density, cell selection (v3.3) |
38
+ | 1 | `useGridControlledState` | `hooks/core/useGridControlledState.ts` | Controlled/uncontrolled sort, filter, aggregation, row grouping (v3.5), visibility, pinning, pivot, pagination, selection, density, cell selection (v3.3) |
32
39
  | 2 | `useGridPivot` | `hooks/features/useGridPivot.ts` | Pivot rows/columns (or the source ones) and the pipeline filter/sort models |
33
40
  | 3 | `resolveGridModes` (pure) | `utils/gridModes.ts` | Which features are in effect: tree data, row grouping, pagination, row reordering, list view, grouping column |
34
41
  | 4 | `useGridThemeDimensions` | `hooks/core/useGridThemeDimensions.ts` | Row and header heights (props → theme provider → defaults) |
@@ -40,7 +47,9 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
40
47
  | 10 | `useGridRowIdOf` | `hooks/core/useGridRowIdOf.ts` | `getRowIdOf` and its stable event-handler twin |
41
48
  | 11 | `useGridApiRefBinding` | `hooks/core/useGridApiRefBinding.ts` | Binds the `apiRef` prop (layout effect) |
42
49
  | 12 | `useGridHierarchy` | `hooks/core/useGridHierarchy.ts` | `useTreeData` + `useRowGrouping`, the active handlers and `rowMetaMap` |
43
- | 13 | `useGridEditing` | `hooks/features/useGridEditing.ts` | Cell editing state and handlers |
50
+ | 12a | `useGridEditCommitChannel` | `hooks/core/useGridUndoRedo.ts` | Stable `emit` / `setListener` pair: the commit paths below report stored changes through `emit`, and `useGridUndoRedo` (36c) registers the listener (v3.4) |
51
+ | 12b | `useGridBatchEdit` | `hooks/features/useGridBatchEdit.ts` | Batch edits (v3.4): `applyEdits` runs `valueSetter` → `processRowUpdate` once per row (rows in parallel, failures isolated and sent to `onProcessRowUpdateError`) and stores every successful row in one `replaceRows` update; `getRow` sees rows stored since the last render; `storeRow` stores a single edit |
52
+ | 13 | `useGridEditing` | `hooks/features/useGridEditing.ts` | Cell editing state and handlers; stores through `useGridBatchEdit.storeRow` and reports the committed change to the channel |
44
53
  | 14 | `useGridLiveRowSelection` | `hooks/core/useGridLiveRowSelection.ts` | Selection without removed rows |
45
54
  | 15 | `useGridDataSource` | `hooks/features/useGridDataSource.ts` | Server fetching |
46
55
  | 16 | `useServerTreeChildren` | `hooks/features/useServerTreeChildren.ts` | Lazy server tree children |
@@ -51,7 +60,7 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
51
60
  | 21 | `useGridPageCorrection` | `hooks/core/useGridPageCorrection.ts` | Moves a page left past the end back to the last page |
52
61
  | 22 | `getPaginationRowCount` (pure) | `utils/pagination/index.ts` | What the pager pages through |
53
62
  | 23 | `useGridRowInteractions` | `hooks/core/useGridRowInteractions.ts` | Row selection, `handleRowClick`, `handleSelectionChange` |
54
- | 24 | `useGridApiMethods` | `hooks/core/useGridApiMethods.ts` | State API methods (`getAllFilteredRows` via `utils/gridApiRows.ts`) |
63
+ | 24 | `useGridApiMethods` | `hooks/core/useGridApiMethods.ts` | State API methods (`getAllFilteredRows` via `utils/gridApiRows.ts`); since v3.5 also `setSortModel`, `setRowGroupingModel`, `setAggregationModel`, `setColumnVisibilityModel`, `setPivotModel` and `getGridAiState` |
55
64
  | 25 | `useRowReorder` | `hooks/useRowReorder.ts` | Row drag-reorder |
56
65
  | 26 | `useAggregation` | `hooks/features/useAggregation.ts` | Footer aggregation result |
57
66
  | 27 | `useGridAggregationApi` | `hooks/core/useGridAggregationApi.ts` | `getAggregationResult`, `getAggregationModel`, `getGroupedExportRows` |
@@ -67,6 +76,9 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
67
76
  | 35 | `useGridKeyboardNavigation` | `hooks/core/useGridKeyboardNavigation.ts` | Focus and keyboard handling; takes `cellSelection.keyboard` (Shift+navigation, Escape, Ctrl/Cmd+A) |
68
77
  | 36 | `useGridPointerFocusHandlers` | `hooks/core/useGridFocusHandlers.ts` | Cell and header click focus |
69
78
  | 36a | `useGridCellSelectionApi` | `hooks/core/useGridCellSelectionApi.ts` | Keeps the range anchor and the focused cell together (layout effect: a new anchor moves focus; focus moved to another data cell collapses the range), clears a range whose corner is gone (`'dataChange'`), and installs `getCellSelectionModel`, `setCellSelectionModel`, `selectCellRange`, `clearCellSelection`, `getSelectedCells`, `copySelectedCells` (once per `apiRef`, reading the latest values from a ref) |
79
+ | 36b | `useGridClipboardPaste` | `hooks/core/useGridClipboardPaste.ts` | Paste and range clear (v3.4): `paste` and Delete/Backspace listeners on the grid root (only for cell targets, not editors or nested grids), TSV parsing (`utils/parsing.ts`), placement against the renderable rows and range columns (`utils/editing/targets.ts`), the batch edit, the new selection, `onBeforeClipboardPaste` / `onClipboardPaste`, and `apiRef.pasteText`. Inert without `cellSelection` except for `pasteText` |
80
+ | 36c | `useGridUndoRedo` | `hooks/core/useGridUndoRedo.ts` | History (v3.4, `undoRedo`): records the channel's changes, replays them as batch edits with an `expect` value per cell (stale cells skipped), queues undo/redo, selects and scrolls to the affected cells, Ctrl/Cmd+Z / Shift+Z / Ctrl+Y on the grid root, `onHistoryChange`, and `apiRef.undo` / `redo` / `canUndo` / `canRedo` / `clearHistory` |
81
+ | 36d | `useGridFillHandle` | `hooks/core/useGridFillHandle.ts` | Fill handle (v3.5, `cellSelection` without `disableFillHandle`): where the handle is drawn (`rowRenderProps.fillHandle`, the range's bottom-right cell or its span origin), a `pointerdown` listener on the viewport for `.ogx__cell-fill-handle` that runs `cellSelection.startTrackedDrag` (the range drag's hit testing, auto-scroll and slow-machine fallback, on pointer events so touch works), the fill itself (`utils/editing/fill.ts`: series detection, lines, `GridColDef.fillValue`) as one batch edit with source `'fill'`, the new selection, `onFill`, and Ctrl/Cmd+D / Ctrl/Cmd+R on the grid root |
70
82
  | 37 | `useGridColumnMenuHandlers` | `hooks/core/useGridHeaderHandlers.ts` | Column menu Hide / Pin (`pinColumnTo` in `utils/pinning`) |
71
83
  | 38 | `useGridAriaRows` | `hooks/core/useGridAriaRows.ts` | `aria-rowcount` and `aria-rowindex` bases |
72
84
  | 39 | `useGridSpanRowWindow` | `hooks/features/useGridSpanRenderWindow.ts` | Render window widened to whole row spans |
@@ -76,15 +88,17 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
76
88
  | 43 | `useColumnGroupReorderGuard` | `hooks/features/useColumnGroupReorderGuard.ts` | Header drag-reorder kept inside column groups |
77
89
  | 44 | `useGridColumnsPanel` | `hooks/core/useGridColumnsPanel.ts` | Columns panel (toolbar or standalone) |
78
90
  | 45 | `useGridStylesheetWarning` | `hooks/core/useGridDevWarnings.ts` | Warns when the stylesheet is missing |
91
+ | 45a | `useGridAiAssistant` | `hooks/features/useGridAiAssistant.ts` | The `aiAssistant` panel (v3.5): open state, the request and its `AbortController` (Stop), applying a branded reply through the `apiRef` setters of step 24 (`utils/aiAssistant.ts`: allowed parts, the Undo snapshot, chips, chip removal), the live-region status, and `apiRef.openAiAssistant` / `closeAiAssistant`. Inert without `aiAssistant`; it runs before step 46 because the toolbar gets its Ask AI button from it |
79
92
  | 46 | `useGridToolbarProps` | `hooks/core/useGridToolbarProps.ts` | Props for `slots.toolbar` |
80
93
 
81
94
  ## Rendered components
82
95
 
83
- `GridToolbarSlot`, `GridStandaloneColumnPanel`, `GridListView` (list view) or the viewport
96
+ `GridToolbarSlot`, `GridAiAssistantArea` (the `aiAssistant` panel or `slots.aiAssistantPanel` while open, anchored under the toolbar), `GridStandaloneColumnPanel`, `GridListView` (list view) or the viewport
84
97
  (`Header`, `GridPinnedRows` top, `GridEmptyState`, `GridVirtualRows`, `GridPinnedRows` bottom,
85
98
  `GridAggregationFooter`), `GridCellSelectionStatsArea` (`showCellSelectionStats` with `cellSelection`), then `slots.footer` or `GridPaginationArea`, `GridLiveRegion`,
86
99
  `GridLoadingOverlay` and `GridErrorOverlay`. The props all three row renderers take alike are built
87
100
  once in `DataGrid.tsx` (`rowRenderProps`) and spread into each. `rowRenderProps.cellRange` is the cell range's
88
101
  render rectangle; each row renderer turns it into a per-row `cellRange` (`getRowCellRange`), `null` for rows
89
102
  outside it, and `Row` is memoised with a value comparison of that prop, so a drag only re-renders the rows the
90
- range enters or leaves.
103
+ range enters or leaves. `rowRenderProps.fillHandle` (v3.5) adds `fillHandleCol` to the one row that draws the fill
104
+ handle (a single selected cell gets an empty column interval, so it draws the handle but no range).
@@ -51,6 +51,7 @@ The panel shows one row per column with `filterable !== false` (the synthetic ro
51
51
  - Typing is debounced by 300 ms before `onFilterModelChange` fires. Opening the panel never emits anything and never rewrites existing values (arrays, numbers and dates stay as they are).
52
52
  - Changing the operator right after typing keeps the typed text.
53
53
  - Each row edits the **first** root-level item for its column and replaces it in place. Filter groups (`GridFilterGroup`) and further items for the same column are passed through untouched; the panel notes how many such conditions it does not show.
54
+ - With `headerFilters` (v3.5) that item is often the header filter row's `id: 'header:<field>'` item. The panel keeps the item's `id` when it edits it, so the header row goes on showing it; see [Header Filters](../features/header-filters.md).
54
55
  - Picking an operator without typing, or clearing the input, leaves an item with an empty value, which does not filter. The row's **×** button removes the item.
55
56
  - If the model is changed from outside the panel (the toolbar's **Clear all**, or your own code) while typing is still pending, the pending text is dropped instead of being re-applied.
56
57
 
@@ -21,8 +21,11 @@ Manages the column headers, sorting triggers, column resizing, and column groupi
21
21
  | `checkboxSelection` | `boolean` | Reserves the checkbox column. The "Select All" checkbox is rendered only when `onSelectAll` is also passed (the grid omits it with `disableMultipleRowSelection`). |
22
22
  | `onSelectAll` | `(isSelected: boolean) => void` | Called by the "Select All" checkbox. |
23
23
  | `allSelected` / `someSelected` | `boolean` | Checked / indeterminate state of the "Select All" checkbox. |
24
- | `focusedCell` | `{ id: GridRowId \| null; field: string } \| null` | The grid's focus position. `id: null` means the header cell of `field` is focused (v3.0; it used to be the string `'HEADER'`, which a real row id could collide with). DOM focus is moved by the grid, not by `<Header />`. |
24
+ | `focusedCell` | `{ id: GridRowId \| null; field: string; headerFilter?: boolean } \| null` | The grid's focus position. `id: null` means the header cell of `field` is focused (v3.0; it used to be the string `'HEADER'`, which a real row id could collide with); with `headerFilter: true`, its cell in the header filter row (v3.5). DOM focus is moved by the grid, not by `<Header />`. |
25
25
  | `columnIndexMap` | `Map<string, number>` | Position of each visible data column in render order. Used for `aria-colindex` and the `colIndex` passed to `renderHeader`, so they match the body cells and do not change with horizontal scrolling. |
26
+ | `headerFilters` | `boolean` | Renders the header filter row under the column header row (v3.5, see [Header Filters](../features/header-filters.md)). |
27
+ | `filterModel` / `onFilterModelChange` | `GridFilterModel` / `(model) => void` | The model the filter row reads and the callback it reports changes to. |
28
+ | `onOpenFilterPanel` | `() => void` | Called by a filter cell's "Custom filter" button; without it the label is plain text. |
26
29
 
27
30
  ## ↩️ Wrapped Header Text
28
31
 
@@ -56,6 +56,13 @@ The Summaries panel lists each aggregable column with the functions it allows: i
56
56
  | `renderAggregationButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | — | Replace the built-in Summaries button. The Aggregation panel still opens and closes normally. |
57
57
  | `renderExportButton` | `() => ReactNode` | — | Inject an Export button after the Aggregation button. No built-in export button exists — this is the slot for it. |
58
58
  | `renderQuickFilter` | `(props: ToolbarQuickFilterRenderProps) => ReactNode` | — | Replace the built-in quick-filter search input with your own component. |
59
+ | `onAiAssistantToggle` | `(trigger: HTMLElement \| null) => void` | — | Opens or closes the `aiAssistant` panel. The grid injects it when the `aiAssistant` prop is set; its presence renders the **Ask AI** button (sparkle icon), first in the button row. Focus returns to `trigger` when the panel closes (v3.5). |
60
+ | `aiAssistantOpen` | `boolean` | `false` | Whether the AI panel is open: the button's `aria-expanded` (injected by the grid, v3.5). |
61
+ | `aiAssistantLabel` | `string` | `'Ask AI'` | The Ask AI button's label; the grid passes `localeText.aiAssistantButton` (v3.5). |
62
+
63
+ ### Ask AI button (v3.5)
64
+
65
+ With the grid's `aiAssistant` prop set, `GridToolbar` shows an **Ask AI** button that opens the prompt panel under the toolbar (a `role="dialog"` labelled "Ask AI"; Escape closes it and focus returns to the button). Opening it closes any open toolbar panel. A custom toolbar can render its own button: call `onAiAssistantToggle(buttonElement)` from the props the grid passes, or `apiRef.current.openAiAssistant()`. See [AI Toolkit](../features/ai-toolkit.md#ai-assistant-panel).
59
66
 
60
67
  ---
61
68
 
@@ -83,7 +83,7 @@ interface GridTheme {
83
83
  spacing?: GridThemeSpacing;
84
84
  borders?: GridThemeBorders;
85
85
  shadows?: GridThemeShadows;
86
- grid?: GridThemeGrid; // surfaces, heights (px), cellPaddingX/Y, cellFontSize, headerFontSize, rangeBackground, rangeBorder, …
86
+ grid?: GridThemeGrid; // surfaces, heights (px), cellPaddingX/Y, cellFontSize, headerFontSize, rangeBackground, rangeBorder, fillHandleColor, …
87
87
  toolbar?: GridThemeToolbar;
88
88
  overlays?: GridThemeOverlays;
89
89
  scrollbar?: GridThemeScrollbar;
@@ -187,6 +187,7 @@ All sub-theme types (`GridThemeColors`, `GridThemeGrayScale`, `GridThemeTypograp
187
187
  |---|---|---|
188
188
  | `--ogx-row-height` | `52px` | Row height. The grid sets it inline on `.ogx` from the `rowHeight` / `density` props (or the provider's `grid.rowHeight*`); read it in custom CSS, don't set it. |
189
189
  | `--ogx-header-height` | `56px` | Column header row height; set inline by the grid like `--ogx-row-height`. |
190
+ | `--ogx-header-filter-height` | `40px` | Header filter row height (`headerFilters`, v3.5); set inline by the grid from `headerFilterHeight`. The row's colours come from the header variables, so themes need no new keys. |
190
191
  | `--ogx-grid-row-height-compact` | `32px` | Informational copy of the theme's `grid.rowHeightCompact`; the grid reads the theme value, not this variable |
191
192
  | `--ogx-grid-row-height-standard` | `52px` | Informational copy of `grid.rowHeightStandard` |
192
193
  | `--ogx-grid-row-height-comfortable` | `72px` | Informational copy of `grid.rowHeightComfortable` |
@@ -215,6 +216,7 @@ All sub-theme types (`GridThemeColors`, `GridThemeGrayScale`, `GridThemeTypograp
215
216
  | `--ogx-grid-cell-focus-border` | `#3b82f6` | `#60a5fa` | Keyboard focus ring |
216
217
  | `--ogx-range-background` | `rgba(59, 130, 246, 0.12)` | `rgba(96, 165, 250, 0.18)` | Tint over a selected cell range (`cellSelection`, v3.3). Theme key `grid.rangeBackground` |
217
218
  | `--ogx-range-border` | `var(--ogx-color-primary)` | `#60a5fa` | Outline of a selected cell range, drawn as an inset box-shadow on `ogx__cell--range-top/-bottom/-left/-right` (v3.3). Theme key `grid.rangeBorder` |
219
+ | `--ogx-fill-handle-color` | `var(--ogx-range-border)` | `var(--ogx-range-border)` | The fill handle square (`ogx__cell-fill-handle`, v3.5). Unset in the stylesheet, where it falls back to `--ogx-range-border`; every theme of `DataGridThemeProvider` sets it to `var(--ogx-range-border)`. Theme key `grid.fillHandleColor` |
218
220
  | `--ogx-grid-pinned-left-shadow` | `4px 0 24px...` | (darker) | Shadow on left-pinned columns |
219
221
  | `--ogx-grid-pinned-right-shadow` | `-4px 0 24px...` | (darker) | Shadow on right-pinned columns |
220
222
  | `--ogx-checkbox-bg` | — | `#1e293b` | Checkbox background (dark only) |
@@ -340,4 +342,13 @@ const purpleTheme: GridTheme = {
340
342
  - The dark mode overrides are in the same file under `@media (prefers-color-scheme: dark)`
341
343
  - The CSS entry point for the entire library is `lib/styles/opengridx.css` (single barrel import)
342
344
  - BEM class prefix: `ogx__` (e.g. `ogx__cell`, `ogx__header-cell`)
345
+ - **Form controls** — the toolbar search, column-panel search, filter value box and the text / number / date cell
346
+ editors render through the shared `Input` (v3.3.1+): their `<input>` keeps its own class (`ogx-global-search__input`,
347
+ `ogx-column-visibility-panel__search-input`, `ogx-filter__value-input`, `ogx__edit-input`) and also has `ogx-input`,
348
+ and sits inside a `div.ogx-input-wrapper`. Target it with a descendant selector (`.ogx-global-search input`), not a
349
+ child one (`.ogx-global-search > input`). Cell editors' wrappers also have `ogx-input-wrapper--cell` (fills the cell,
350
+ no border, background or focus shadow; `ogx-input-wrapper--error` adds an inset `--ogx-color-error` edge). The boolean
351
+ editor and list-view row checkbox are the shared `Checkbox` (`ogx-checkbox-wrapper`, `ogx-checkbox__box`; the `<input>`
352
+ keeps `ogx__edit-checkbox` and is visually hidden). `Input.css` loads first in `opengridx.css`, so component rules
353
+ override it at equal specificity.
343
354
  - Variable prefix: `--ogx-` (e.g. `--ogx-color-primary`)