@opencorestack/opengridx 3.4.0 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/README.md +10 -3
- package/dist/ai.cjs +2 -1
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.d.ts +203 -3
- package/dist/ai.es.js +2 -1
- package/dist/ai.es.js.map +1 -1
- package/dist/index.d.ts +248 -4
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7334 -5906
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +16 -16
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +88 -7
- package/docs/README.md +3 -1
- package/docs/architecture/datagrid-orchestration.md +11 -5
- package/docs/components/filter-panel.md +1 -0
- package/docs/components/header.md +4 -1
- package/docs/components/toolbar.md +7 -0
- package/docs/customization/theming.md +3 -1
- package/docs/features/ai-toolkit.md +99 -5
- package/docs/features/cell-selection.md +8 -2
- package/docs/features/fill-handle.md +125 -0
- package/docs/features/filtering.md +3 -0
- package/docs/features/header-filters.md +138 -0
- package/docs/features/keyboard-navigation.md +20 -2
- package/docs/features/virtualization.md +5 -5
- package/docs/performance.md +212 -1
- package/docs/roadmap.md +3 -4
- package/lib/ai/agentTools.ts +160 -0
- package/lib/ai/index.ts +19 -2
- package/lib/ai/promptHandler.ts +109 -0
- package/lib/ai/types.ts +89 -25
- package/lib/ai/validate.ts +10 -0
- package/lib/components/AiAssistant/GridAiAssistantArea.tsx +26 -0
- package/lib/components/AiAssistant/GridAiAssistantPanel.css +171 -0
- package/lib/components/AiAssistant/GridAiAssistantPanel.tsx +145 -0
- package/lib/components/AiAssistant/useSpeechInput.ts +74 -0
- package/lib/components/Cell/Cell.css +28 -0
- package/lib/components/Cell/Cell.tsx +6 -2
- package/lib/components/DataGrid/DataGrid.tsx +84 -4
- package/lib/components/DataGrid/GridLiveRegion.tsx +5 -2
- package/lib/components/DataGrid/GridPinnedRows.tsx +5 -1
- package/lib/components/DataGrid/GridVirtualRows.tsx +5 -1
- package/lib/components/FilterPanel/FilterPanel.tsx +2 -9
- package/lib/components/Header/Header.tsx +44 -23
- package/lib/components/Header/headerColumnStyle.ts +28 -0
- package/lib/components/HeaderFilter/HeaderFilter.css +160 -0
- package/lib/components/HeaderFilter/HeaderFilterCell.tsx +370 -0
- package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +124 -0
- package/lib/components/HeaderFilter/HeaderFilterRow.tsx +157 -0
- package/lib/components/Toolbar/GridToolbar.tsx +51 -0
- package/lib/hooks/core/gridApiPlaceholder.ts +8 -0
- package/lib/hooks/core/gridToolbarHostContext.ts +5 -0
- package/lib/hooks/core/useGridApiMethods.ts +39 -0
- package/lib/hooks/core/useGridAriaRows.ts +5 -3
- package/lib/hooks/core/useGridCellSelection.ts +77 -11
- package/lib/hooks/core/useGridColumnsPanel.ts +24 -1
- package/lib/hooks/core/useGridControlledState.ts +27 -0
- package/lib/hooks/core/useGridDevWarnings.ts +21 -6
- package/lib/hooks/core/useGridFillHandle.ts +323 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +29 -10
- package/lib/hooks/core/useGridMaxContentHeight.ts +16 -0
- package/lib/hooks/core/useGridToolbarProps.ts +19 -0
- package/lib/hooks/core/useGridVirtualization.ts +19 -0
- package/lib/hooks/features/useGridAiAssistant.ts +284 -0
- package/lib/hooks/features/useGridBatchEdit.ts +2 -2
- package/lib/index.ts +3 -0
- package/lib/styles/opengridx.css +2 -0
- package/lib/theme/DataGridThemeProvider.tsx +2 -0
- package/lib/theme/types.ts +2 -0
- package/lib/types/index.ts +219 -1
- package/lib/utils/aiAssistant.ts +205 -0
- package/lib/utils/aiBrand.ts +17 -0
- package/lib/utils/cellSelection.ts +25 -5
- package/lib/utils/editing/fill.ts +238 -0
- package/lib/utils/filtering/index.ts +14 -0
- package/lib/utils/focus/index.ts +9 -3
- package/lib/utils/headerFilters.ts +189 -0
- package/lib/utils/maxElementHeight.ts +53 -0
- package/llms.txt +44 -4
- package/package.json +3 -2
package/docs/API_REFERENCE.md
CHANGED
|
@@ -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. |
|
|
@@ -111,6 +113,28 @@ interface GridHistoryChangeParams { canUndo: boolean; canRedo: boolean; size: nu
|
|
|
111
113
|
interface GridUndoRedoOptions { limit?: number }
|
|
112
114
|
```
|
|
113
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
|
+
|
|
114
138
|
#### Column Visibility
|
|
115
139
|
|
|
116
140
|
| Prop | Type | Default | Description |
|
|
@@ -168,7 +192,8 @@ interface GridUndoRedoOptions { limit?: number }
|
|
|
168
192
|
|
|
169
193
|
| Prop | Type | Default | Description |
|
|
170
194
|
| :--- | :--- | :--- | :--- |
|
|
171
|
-
| `rowGroupingModel` | `GridRowGroupingModel` |
|
|
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+). |
|
|
172
197
|
| `aggregationModel` | `GridAggregationModel` | — | Map of `field → aggFn` (e.g. `{ salary: 'sum', age: 'avg' }`). See [Aggregation Reference](#-aggregation-reference). |
|
|
173
198
|
| `onAggregationModelChange` | `(model: GridAggregationModel) => void` | — | Fired when the aggregation model changes. |
|
|
174
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). |
|
|
@@ -181,6 +206,24 @@ interface GridUndoRedoOptions { limit?: number }
|
|
|
181
206
|
| `pivotModel` | `GridPivotModel` | — | Controlled pivot configuration (row fields, column fields, value fields). |
|
|
182
207
|
| `onPivotModelChange` | `(model: GridPivotModel) => void` | — | Fired when the pivot model changes. |
|
|
183
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
|
+
|
|
184
227
|
#### Scroll & Viewport
|
|
185
228
|
|
|
186
229
|
| Prop | Type | Default | Description |
|
|
@@ -200,7 +243,7 @@ interface GridUndoRedoOptions { limit?: number }
|
|
|
200
243
|
|
|
201
244
|
| Prop | Type | Default | Description |
|
|
202
245
|
| :--- | :--- | :--- | :--- |
|
|
203
|
-
| `localeText` | `GridLocaleText` | — | Override user-visible strings: the Pagination labels
|
|
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). |
|
|
204
247
|
|
|
205
248
|
#### Imperative Ref
|
|
206
249
|
|
|
@@ -261,6 +304,7 @@ The types of the `slots` and `slotProps` props (v3.0+ exports). Each slot is typ
|
|
|
261
304
|
| `noRowsOverlay` | The empty-state icon and label (shown when there are no rows and the grid is not loading). | `slotProps.noRowsOverlay` only (`GridOverlaySlotProps`). |
|
|
262
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`). |
|
|
263
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`. |
|
|
264
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. |
|
|
265
309
|
|
|
266
310
|
```ts
|
|
@@ -293,6 +337,8 @@ The built-in toolbar component. Mount it via `slots={{ toolbar: GridToolbar }}`.
|
|
|
293
337
|
| `onColumnOrderReset` | `() => void` | — | Called when the user clicks "Reset order" in the Columns panel. |
|
|
294
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. |
|
|
295
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). |
|
|
296
342
|
| `children` | `ReactNode` | — | Content rendered on the **left** side of the toolbar, before the spacer. |
|
|
297
343
|
| `rightContent` | `ReactNode` | — | Content rendered on the **right** side, after all built-in buttons. |
|
|
298
344
|
| `className` | `string` | — | Additional CSS class on the toolbar root `<div>`. Use for visual theme overrides. |
|
|
@@ -302,6 +348,9 @@ The built-in toolbar component. Mount it via `slots={{ toolbar: GridToolbar }}`.
|
|
|
302
348
|
| `renderAggregationButton` | `(props: ToolbarButtonRenderProps) => ReactNode` | — | Replace the built-in Summaries toggle button. The Aggregation panel still functions normally. |
|
|
303
349
|
| `renderExportButton` | `() => ReactNode` | — | Inject an Export button after the Aggregation button. No built-in export button exists. |
|
|
304
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). |
|
|
305
354
|
|
|
306
355
|
### `ToolbarButtonRenderProps`
|
|
307
356
|
|
|
@@ -363,6 +412,13 @@ Access these methods via the `apiRef` prop.
|
|
|
363
412
|
| `redo()` | `Promise<GridBatchEditResult>` | Redo the last undone action (v3.4). |
|
|
364
413
|
| `canUndo()` / `canRedo()` | `boolean` | Whether there is an action to undo / redo (v3.4). |
|
|
365
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). |
|
|
366
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. |
|
|
367
423
|
|
|
368
424
|
---
|
|
@@ -419,6 +475,7 @@ Defines the behavior and appearance of a single column.
|
|
|
419
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. |
|
|
420
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. |
|
|
421
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). |
|
|
422
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). |
|
|
423
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+). |
|
|
424
481
|
|
|
@@ -458,7 +515,9 @@ Span values are floored; `Infinity` means "to the end"; `NaN`, `0` and negative
|
|
|
458
515
|
| :--- | :--- | :--- | :--- |
|
|
459
516
|
| `sortable` | `boolean` | `true` | Enable/disable sorting for this column. |
|
|
460
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"`. |
|
|
461
|
-
| `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). |
|
|
462
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+). |
|
|
463
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. |
|
|
464
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+). |
|
|
@@ -494,14 +553,16 @@ Every exporter takes `columns` typed for your rows (`GridColDef<R>[]`) or untype
|
|
|
494
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).
|
|
495
554
|
|
|
496
555
|
```ts
|
|
497
|
-
import { getGridAiSchema, validateGridAiState } from '@opencorestack/opengridx/ai';
|
|
498
|
-
import type { GridAiState, GridAiValidationError } from '@opencorestack/opengridx/ai';
|
|
556
|
+
import { getGridAiSchema, validateGridAiState, createGridAiPromptHandler, createGridAgentTools } from '@opencorestack/opengridx/ai';
|
|
557
|
+
import type { GridAiState, GridAiValidationError, GridAgentTool } from '@opencorestack/opengridx/ai';
|
|
499
558
|
```
|
|
500
559
|
|
|
501
560
|
| Function | Return | Description |
|
|
502
561
|
| :--- | :--- | :--- |
|
|
503
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. |
|
|
504
|
-
| `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. |
|
|
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. |
|
|
505
566
|
|
|
506
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.
|
|
507
568
|
|
|
@@ -511,7 +572,23 @@ import type { GridAiState, GridAiValidationError } from '@opencorestack/opengrid
|
|
|
511
572
|
| `GridAiSchema` | The returned JSON Schema object: `$schema`, `schemaVersion: 1`, `title`, `type: 'object'`, `properties` (one per offered part) and `$defs`. |
|
|
512
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. |
|
|
513
574
|
| `GridAiValidationError` | `{ path: string; message: string }`, e.g. `{ path: 'filterModel.items[2].field', message: 'Unknown field "revenue"' }`. At most 100 are listed. |
|
|
514
|
-
| `GridAiValidationResult` | `{ state: GridAiState; errors: GridAiValidationError[] }` |
|
|
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.
|
|
515
592
|
|
|
516
593
|
---
|
|
517
594
|
|
|
@@ -810,6 +887,8 @@ interface GridLocaleText {
|
|
|
810
887
|
noRowsLabel?: string;
|
|
811
888
|
/** v3.3: live-region text after a cell range change. Default "12 cells selected, 3 rows by 4 columns". */
|
|
812
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;
|
|
813
892
|
}
|
|
814
893
|
```
|
|
815
894
|
|
|
@@ -1183,6 +1262,8 @@ The filter panel shows only the operators relevant to each column's `type`; an o
|
|
|
1183
1262
|
| `boolean` | `is` | `is` |
|
|
1184
1263
|
| `singleSelect` | `isAnyOf` | `isAnyOf`, `is`, `not` |
|
|
1185
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
|
+
|
|
1186
1267
|
### Nested Group Example
|
|
1187
1268
|
|
|
1188
1269
|
```tsx
|
package/docs/README.md
CHANGED
|
@@ -32,6 +32,7 @@ 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
|
|
@@ -39,6 +40,7 @@ In-depth guides on the grid's functional capabilities.
|
|
|
39
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
|
|
41
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
|
|
42
44
|
- **[Pinning](features/pinning.md)** - Sticky columns and rows
|
|
43
45
|
- **[State Persistence](features/state-persistence.md)** - Save/Restore grid configuration
|
|
44
46
|
- **[Aggregation & Pivot](features/aggregation-pivot.md)** - Data summarization and analytics
|
|
@@ -50,7 +52,7 @@ In-depth guides on the grid's functional capabilities.
|
|
|
50
52
|
- **[Infinite Scroll](features/infinite-scroll.md)** - Advanced performance loading
|
|
51
53
|
- **[Data Source](features/data-source.md)** - Server-side fetching and SSR
|
|
52
54
|
- **[Export Guide](features/export-guide.md)** - Excel, CSV, JSON, and Print
|
|
53
|
-
- **[AI Toolkit](features/ai-toolkit.md)** - JSON Schema of the grid state for your own model,
|
|
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`)
|
|
54
56
|
|
|
55
57
|
---
|
|
56
58
|
|
|
@@ -25,6 +25,8 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
|
|
|
25
25
|
late (36c); commits reach it through `useGridEditCommitChannel` (12a), whose listener it sets in a layout effect.
|
|
26
26
|
`useGridClipboardPaste` (36b) and `useGridUndoRedo` listen for keys on the grid root with native listeners, which
|
|
27
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.
|
|
28
30
|
- `useGridLiveRowSelection` prunes the selection, and `useGridPageCorrection` corrects a page past the
|
|
29
31
|
end, in effects that run before the later hooks' effects.
|
|
30
32
|
|
|
@@ -33,7 +35,7 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
|
|
|
33
35
|
| # | Hook / util | File | Produces |
|
|
34
36
|
| :- | :--- | :--- | :--- |
|
|
35
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) |
|
|
36
|
-
| 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) |
|
|
37
39
|
| 2 | `useGridPivot` | `hooks/features/useGridPivot.ts` | Pivot rows/columns (or the source ones) and the pipeline filter/sort models |
|
|
38
40
|
| 3 | `resolveGridModes` (pure) | `utils/gridModes.ts` | Which features are in effect: tree data, row grouping, pagination, row reordering, list view, grouping column |
|
|
39
41
|
| 4 | `useGridThemeDimensions` | `hooks/core/useGridThemeDimensions.ts` | Row and header heights (props → theme provider → defaults) |
|
|
@@ -58,7 +60,7 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
|
|
|
58
60
|
| 21 | `useGridPageCorrection` | `hooks/core/useGridPageCorrection.ts` | Moves a page left past the end back to the last page |
|
|
59
61
|
| 22 | `getPaginationRowCount` (pure) | `utils/pagination/index.ts` | What the pager pages through |
|
|
60
62
|
| 23 | `useGridRowInteractions` | `hooks/core/useGridRowInteractions.ts` | Row selection, `handleRowClick`, `handleSelectionChange` |
|
|
61
|
-
| 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` |
|
|
62
64
|
| 25 | `useRowReorder` | `hooks/useRowReorder.ts` | Row drag-reorder |
|
|
63
65
|
| 26 | `useAggregation` | `hooks/features/useAggregation.ts` | Footer aggregation result |
|
|
64
66
|
| 27 | `useGridAggregationApi` | `hooks/core/useGridAggregationApi.ts` | `getAggregationResult`, `getAggregationModel`, `getGroupedExportRows` |
|
|
@@ -69,13 +71,15 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
|
|
|
69
71
|
| 31 | `useGridScrollToIndexesApi` | `hooks/core/useGridScrollToIndexesApi.ts` | `scrollToIndexes` |
|
|
70
72
|
| 31a | `useGridColumnAutosize` | `hooks/core/useGridColumnAutosize.ts` | `autosizeColumn` / `autosizeColumns` on the API, and the resize handle's auto-size handler (v3.1) |
|
|
71
73
|
| 32 | `useGridViewport` | `hooks/core/useGridViewport.ts` | Scroll sync, viewport measurement, viewport callback ref |
|
|
72
|
-
|
|
|
74
|
+
| 32a | `useGridMaxContentHeight` | `hooks/core/useGridMaxContentHeight.ts` | The tallest element this browser lays out (`utils/maxElementHeight.ts`, measured once per document after mount; `undefined` until then, `Infinity` without a layout engine) |
|
|
75
|
+
| 33 | `useGridVirtualization` | `hooks/core/useGridVirtualization.ts` | Render window; `virtualContainerHeight` caps the rows' container to `maxContentHeight` (Firefox collapses taller elements) |
|
|
73
76
|
| 34 | `useGridSortHandlers` | `hooks/core/useGridHeaderHandlers.ts` | Header sort / shift-sort |
|
|
74
77
|
| 35 | `useGridKeyboardNavigation` | `hooks/core/useGridKeyboardNavigation.ts` | Focus and keyboard handling; takes `cellSelection.keyboard` (Shift+navigation, Escape, Ctrl/Cmd+A) |
|
|
75
78
|
| 36 | `useGridPointerFocusHandlers` | `hooks/core/useGridFocusHandlers.ts` | Cell and header click focus |
|
|
76
79
|
| 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) |
|
|
77
80
|
| 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` |
|
|
78
81
|
| 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` |
|
|
82
|
+
| 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 |
|
|
79
83
|
| 37 | `useGridColumnMenuHandlers` | `hooks/core/useGridHeaderHandlers.ts` | Column menu Hide / Pin (`pinColumnTo` in `utils/pinning`) |
|
|
80
84
|
| 38 | `useGridAriaRows` | `hooks/core/useGridAriaRows.ts` | `aria-rowcount` and `aria-rowindex` bases |
|
|
81
85
|
| 39 | `useGridSpanRowWindow` | `hooks/features/useGridSpanRenderWindow.ts` | Render window widened to whole row spans |
|
|
@@ -85,15 +89,17 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
|
|
|
85
89
|
| 43 | `useColumnGroupReorderGuard` | `hooks/features/useColumnGroupReorderGuard.ts` | Header drag-reorder kept inside column groups |
|
|
86
90
|
| 44 | `useGridColumnsPanel` | `hooks/core/useGridColumnsPanel.ts` | Columns panel (toolbar or standalone) |
|
|
87
91
|
| 45 | `useGridStylesheetWarning` | `hooks/core/useGridDevWarnings.ts` | Warns when the stylesheet is missing |
|
|
92
|
+
| 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 |
|
|
88
93
|
| 46 | `useGridToolbarProps` | `hooks/core/useGridToolbarProps.ts` | Props for `slots.toolbar` |
|
|
89
94
|
|
|
90
95
|
## Rendered components
|
|
91
96
|
|
|
92
|
-
`GridToolbarSlot`, `GridStandaloneColumnPanel`, `GridListView` (list view) or the viewport
|
|
97
|
+
`GridToolbarSlot`, `GridAiAssistantArea` (the `aiAssistant` panel or `slots.aiAssistantPanel` while open, anchored under the toolbar), `GridStandaloneColumnPanel`, `GridListView` (list view) or the viewport
|
|
93
98
|
(`Header`, `GridPinnedRows` top, `GridEmptyState`, `GridVirtualRows`, `GridPinnedRows` bottom,
|
|
94
99
|
`GridAggregationFooter`), `GridCellSelectionStatsArea` (`showCellSelectionStats` with `cellSelection`), then `slots.footer` or `GridPaginationArea`, `GridLiveRegion`,
|
|
95
100
|
`GridLoadingOverlay` and `GridErrorOverlay`. The props all three row renderers take alike are built
|
|
96
101
|
once in `DataGrid.tsx` (`rowRenderProps`) and spread into each. `rowRenderProps.cellRange` is the cell range's
|
|
97
102
|
render rectangle; each row renderer turns it into a per-row `cellRange` (`getRowCellRange`), `null` for rows
|
|
98
103
|
outside it, and `Row` is memoised with a value comparison of that prop, so a drag only re-renders the rows the
|
|
99
|
-
range enters or leaves.
|
|
104
|
+
range enters or leaves. `rowRenderProps.fillHandle` (v3.5) adds `fillHandleCol` to the one row that draws the fill
|
|
105
|
+
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) |
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
# AI Toolkit:
|
|
1
|
+
# AI Toolkit: Schema, Validator, Assistant & Agent Tools
|
|
2
2
|
|
|
3
|
-
*Since v3.4.0* ·
|
|
3
|
+
*Since v3.4.0 (schema and validator); v3.5.0 (assistant panel, prompt handler, agent tools)* · Demos: [AI: Grid Schema & Validator](https://opencorestack.github.io/OpenGridX/ai-schema), [AI Assistant](https://opencorestack.github.io/OpenGridX/ai-assistant)
|
|
4
4
|
|
|
5
|
-
Let users drive the grid in plain language ("paid orders over $10k in the North, biggest first") with the model your app already uses. The `@opencorestack/opengridx/ai` entry point gives you the
|
|
5
|
+
Let users drive the grid in plain language ("paid orders over $10k in the North, biggest first") with the model your app already uses. The `@opencorestack/opengridx/ai` entry point gives you the pieces the grid can own:
|
|
6
6
|
|
|
7
7
|
- **`getGridAiSchema(columns, options?)`** turns your column definitions into a JSON Schema (draft 2020-12) of the grid state a model may return: filters, sort, row grouping, aggregation, pivot and column visibility, each limited to what the columns allow.
|
|
8
8
|
- **`validateGridAiState(json, columns, options?)`** checks the model's reply against the columns and returns the state that is safe to apply, plus a list of what it dropped.
|
|
9
|
+
- **`createGridAiPromptHandler(...)`** (v3.5) connects those two to your model for the grid's [**Ask AI** panel](#ai-assistant-panel) (`aiAssistant` prop).
|
|
10
|
+
- **`createGridAgentTools(apiRef, columns)`** (v3.5) gives [AI agents](#agent-tools) plain tools to read and change the grid.
|
|
9
11
|
|
|
10
12
|
OpenGridX never calls an AI service and bundles no AI SDK. Your app sends the prompt, the schema and the current state to its own model (with structured output), and passes the reply to the validator.
|
|
11
13
|
|
|
@@ -30,14 +32,15 @@ async function ask(prompt: string) {
|
|
|
30
32
|
}
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
The entry point has no React import and no dependencies (about
|
|
35
|
+
The entry point has no React import and no dependencies (about 6.7 kB gzipped with the v3.5 additions; the budget is 8 kB). Importing `@opencorestack/opengridx` never loads it, and it works on a server too, so you can validate the reply in the same endpoint that calls the model.
|
|
34
36
|
|
|
35
37
|
## Privacy rules
|
|
36
38
|
|
|
37
39
|
- **No row data by default.** The schema is built from column definitions only: `field`, `headerName`, `description`, `type`, the operators of the type, `valueOptions` and the allowed aggregation functions. The grid never reads a row for it.
|
|
38
40
|
- **`aiExamples` is real data.** `GridColDef.aiExamples` puts example values into the schema to help the model ("Acme" → `customer`). Those values are sent to the model. List only what you are happy to share; leave it out for anything personal. `options.examples: false` drops all of them.
|
|
39
41
|
- **`valueOptions` are sent.** The options of a `singleSelect` column become an `enum` in the schema. If an option list is itself sensitive, mark the column `filterable: false` or pass a copy of the columns without it.
|
|
40
|
-
- **Always validate before applying.** Model output is untrusted input. Apply `state`, never the raw reply; show `errors` (or log them) so users can see what was ignored. Show the change to the user and keep it easy to undo.
|
|
42
|
+
- **Always validate before applying.** Model output is untrusted input. Apply `state`, never the raw reply; show `errors` (or log them) so users can see what was ignored. Show the change to the user and keep it easy to undo. The `aiAssistant` panel enforces this: it applies only a validated (branded) state, shows every change as a chip and offers Undo.
|
|
43
|
+
- **Rows stay in the app unless you opt in.** The assistant sends the prompt, the schema, the current models and the session's earlier prompts, never rows. Of the agent tools, only `get_row_summary` reads rows, and it exists only with `allowRowAccess: true`.
|
|
41
44
|
- **Check `schemaVersion`.** The schema carries `schemaVersion: 1`. It changes only when the shape of the schema changes, so you can cache prompts or fine-tuning data per version. The validator accepts a `schemaVersion` key in the reply and reports any value other than 1.
|
|
42
45
|
|
|
43
46
|
## `getGridAiSchema(columns, options?)`
|
|
@@ -113,6 +116,97 @@ Returns `{ state, errors }`, where `state` is a `GridAiState` (`filterModel`, `s
|
|
|
113
116
|
|
|
114
117
|
Applying an empty part is meaningful: `{ sortModel: [] }` clears the sort. Only apply the parts present in `state`.
|
|
115
118
|
|
|
119
|
+
## AI assistant panel
|
|
120
|
+
|
|
121
|
+
*Since v3.5.0.* The `aiAssistant` prop adds an **Ask AI** panel: users type (or dictate) what they want to see, your model answers, and the grid applies the validated reply at once, as one step they can undo.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { DataGrid, GridToolbar } from '@opencorestack/opengridx';
|
|
125
|
+
import { createGridAiPromptHandler } from '@opencorestack/opengridx/ai';
|
|
126
|
+
|
|
127
|
+
const onPrompt = createGridAiPromptHandler({
|
|
128
|
+
columns,
|
|
129
|
+
// Your endpoint calls your model with request.schema as the structured-output format.
|
|
130
|
+
callModel: async (request, { signal }) => {
|
|
131
|
+
const res = await fetch('/api/grid-ai', { method: 'POST', body: JSON.stringify(request), signal });
|
|
132
|
+
return res.json();
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
<DataGrid
|
|
137
|
+
rows={rows}
|
|
138
|
+
columns={columns}
|
|
139
|
+
slots={{ toolbar: GridToolbar }}
|
|
140
|
+
aiAssistant={{ onPrompt, suggestions: ['Top 10 by revenue', 'Group by region'] }}
|
|
141
|
+
/>;
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- **Opening it.** The built-in toolbar shows an **Ask AI** button (sparkle icon; label `localeText.aiAssistantButton`). Without the toolbar, call `apiRef.current.openAiAssistant()`. `slots.aiAssistantPanel` replaces the panel; it receives `GridAiAssistantPanelProps`.
|
|
145
|
+
- **The panel.** A prompt input (Enter sends), the `suggestions` as chips, a microphone button where the browser has `SpeechRecognition` (hidden elsewhere; the microphone is asked for only on click; `voice: false` turns it off), **Stop** while a request runs (aborts `context.signal`), the reply's `message`, and the session's earlier prompts.
|
|
146
|
+
- **Applying.** The reply is applied immediately as one undoable step. Each change shows as a removable chip: a filter item, the quick-filter words, a sort key, a grouping field, an aggregation, a column shown or hidden, the pivot. Removing a chip re-applies the reply without it (a part with no chip left returns to its value from before the reply). **Undo** restores the state from before the reply. This view-state undo is separate from the cell-edit undo history (`undoRedo`).
|
|
147
|
+
- **What is applied.** Each part in `result.state` replaces the grid's model, except column visibility, which is merged over the current model (`{ tax: false }` hides one column and leaves the others). Parts outside `aiAssistant.parts` are ignored. A part the validator emptied (every entry dropped, such as a sort on an unknown field) is not applied, so it cannot clear the grid's model by accident. Changes go through the same handlers as the UI, so `onSortModelChange`, `onRowGroupingModelChange` and the rest fire; with a controlled model, update your state from them.
|
|
148
|
+
- **What was dropped** is listed under the chips, such as `Ignored: Unknown field "revnue"`.
|
|
149
|
+
- **Accessibility.** The panel is a `role="dialog"` labelled "Ask AI". Focus moves to the input when it opens and back to the toolbar button (or wherever it was) when it closes. Escape closes it. The status ("Thinking…", "Applied 3 changes", errors) is announced through the grid's live region.
|
|
150
|
+
- **Events.** `onAiAssistantApply(result)` after a reply was applied; `onAiAssistantError(error)` when `onPrompt` rejects (Stop does not count) or its result was not validated.
|
|
151
|
+
|
|
152
|
+
### The brand rule
|
|
153
|
+
|
|
154
|
+
The grid applies a result only when its `state` carries the brand `Symbol.for('opengridx.ai.validated')`. `validateGridAiState` sets it (non-enumerable, on the result and on its `state`), and `createGridAiPromptHandler` returns such a result. An unbranded result is not applied: the panel shows "The reply was not validated" and a development warning says why. This makes "validate before applying" a rule the grid enforces rather than advice.
|
|
155
|
+
|
|
156
|
+
Writing `onPrompt` yourself:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { validateGridAiState } from '@opencorestack/opengridx/ai';
|
|
160
|
+
|
|
161
|
+
const onPrompt = async (prompt, { currentState, history, signal }) => {
|
|
162
|
+
const reply = await myModel({ prompt, currentState, history, signal });
|
|
163
|
+
const result = validateGridAiState(reply.json, columns);
|
|
164
|
+
return { ...result, message: reply.text }; // spreading keeps the branded state
|
|
165
|
+
};
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
A copied state (`{ ...result.state }`) or a hand-built one is not branded.
|
|
169
|
+
|
|
170
|
+
### `createGridAiPromptHandler({ columns, callModel, parts?, schemaOptions? })`
|
|
171
|
+
|
|
172
|
+
Returns the `onPrompt` function. It builds the schema once (from `columns`, limited to `parts` and `schemaOptions`), then for each prompt:
|
|
173
|
+
|
|
174
|
+
1. calls `callModel({ prompt, schema, currentState, history }, { signal })`;
|
|
175
|
+
2. reads the reply: a state object, a JSON string, or text with a fenced `json` block (the text around the block becomes `result.message`). An object's string `message` key is the message, not state. Plain text with no JSON becomes the message with nothing to apply;
|
|
176
|
+
3. validates it with `validateGridAiState` (same `parts`) and returns the branded `{ state, errors, message? }`.
|
|
177
|
+
|
|
178
|
+
A `callModel` throw or rejection becomes `{ state: {}, errors: [{ path: '', message: 'The model call failed: …' }] }`. An abort (Stop, a new prompt, closing the panel) rejects with an `AbortError`, even when `callModel` ignores the signal.
|
|
179
|
+
|
|
180
|
+
## Agent tools
|
|
181
|
+
|
|
182
|
+
*Since v3.5.0.* `createGridAgentTools(apiRef, columns, options?)` returns plain tool objects, `{ name, description, inputSchema, execute }`, for an AI agent to read and change the grid. They have no SDK dependency, so they work with the Vercel AI SDK, CopilotKit, OpenAI or Anthropic tool calling, and WebMCP (`navigator.modelContext.registerTool`).
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { createGridAgentTools } from '@opencorestack/opengridx/ai';
|
|
186
|
+
|
|
187
|
+
const tools = createGridAgentTools(apiRef, columns);
|
|
188
|
+
// Anthropic / OpenAI style: describe them to the model …
|
|
189
|
+
const toolSpecs = tools.map(({ name, description, inputSchema }) => ({ name, description, input_schema: inputSchema }));
|
|
190
|
+
// … and run the call the model asks for.
|
|
191
|
+
const result = await tools.find((t) => t.name === call.name)?.execute(call.input);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
| Tool | Input | Does |
|
|
195
|
+
| :--- | :--- | :--- |
|
|
196
|
+
| `get_grid_state` | `{}` | Returns `{ ok, state, columns }`: the current models (`apiRef.getGridAiState()`) and `{ field, headerName, type }` per column |
|
|
197
|
+
| `set_filter` | `{ filterModel }` | Replaces the filter model |
|
|
198
|
+
| `set_sort` | `{ sortModel }` | Replaces the sort model |
|
|
199
|
+
| `set_grouping` | `{ rowGroupingModel }` | Replaces the row grouping |
|
|
200
|
+
| `set_aggregation` | `{ aggregationModel }` | Replaces the summaries |
|
|
201
|
+
| `set_column_visibility` | `{ columnVisibilityModel }` | Shows or hides the listed columns; the others keep their visibility |
|
|
202
|
+
| `clear_filters` | `{}` | Removes every filter and the quick-filter words |
|
|
203
|
+
| `get_row_summary` | `{ limit? }` | **Only with `allowRowAccess: true`.** Returns `{ ok, rowCount, rows }`: the number of rows that pass the filter and the first `maxRows` (default 20) of them, limited to `options.fields`, values read through `valueGetter` (JSON-safe: dates as ISO strings, objects as `null`) |
|
|
204
|
+
|
|
205
|
+
- Each `set_*` tool's `inputSchema` is the part's schema from `getGridAiSchema`; a tool whose part no column allows is left out.
|
|
206
|
+
- Inputs are checked with `validateGridAiState`. A call with any error applies **nothing** and returns `{ ok: false, errors }`, so the agent can correct it; a valid call returns `{ ok: true, applied }`.
|
|
207
|
+
- `execute` never throws or rejects: a grid that is not mounted, a throwing change callback or any input gives `{ ok: false, errors }`.
|
|
208
|
+
- The tools read `apiRef.current` only when they run, so they can be created before the grid mounts.
|
|
209
|
+
|
|
116
210
|
## Related
|
|
117
211
|
|
|
118
212
|
- [Filtering](filtering.md), [Sorting & Pagination](sorting-pagination.md), [Aggregation & Pivot](aggregation-pivot.md), [Tree Data & Grouping](tree-data-grouping.md): the models the schema describes.
|
|
@@ -115,6 +115,8 @@ function MyStats({ count, sum }: GridCellSelectionStatsSlotProps) {
|
|
|
115
115
|
| `ogx--range-dragging` | On the grid root during a pointer drag (`user-select: none`). |
|
|
116
116
|
| `--ogx-range-background` | Range tint. Theme key `grid.rangeBackground`. |
|
|
117
117
|
| `--ogx-range-border` | Range outline. Theme key `grid.rangeBorder`. |
|
|
118
|
+
| `ogx__cell-fill-handle` | The fill handle on the range's bottom-right cell (v3.5, see [Fill Handle](fill-handle.md)). |
|
|
119
|
+
| `--ogx-fill-handle-color` | Fill handle colour; defaults to the range outline. Theme key `grid.fillHandleColor` (v3.5). |
|
|
118
120
|
|
|
119
121
|
All five built-in themes define both variables. A custom `DataGridThemeProvider` theme derives them from `colors.primary` unless it sets them.
|
|
120
122
|
|
|
@@ -124,8 +126,12 @@ All five built-in themes define both variables. A custom `DataGridThemeProvider`
|
|
|
124
126
|
- DOM focus stays on the anchor. The grid stays a single Tab stop.
|
|
125
127
|
- After each change the polite live region announces the size, for example "12 cells selected, 3 rows by 4 columns", debounced to 300 ms. Translate it with `localeText.cellSelectionAnnouncement(cells, rows, columns)`.
|
|
126
128
|
|
|
129
|
+
## Fill handle (v3.5)
|
|
130
|
+
|
|
131
|
+
The range's bottom-right cell carries a fill handle: drag it to continue a series or repeat the range into the next cells, or press Ctrl/Cmd+D / Ctrl/Cmd+R. See [Fill Handle](fill-handle.md); `disableFillHandle` turns it off.
|
|
132
|
+
|
|
127
133
|
## Not in 3.3
|
|
128
134
|
|
|
129
|
-
Paste, Delete-to-clear and undo (
|
|
135
|
+
Paste, Delete-to-clear and undo (added in 3.4), the fill handle (added in 3.5), several ranges at once (Ctrl+drag), touch selection (on touch a drag scrolls; the fill handle accepts touch drags) and ranges across pages.
|
|
130
136
|
|
|
131
|
-
See also: [Clipboard](clipboard.md), [Keyboard Navigation](keyboard-navigation.md), [Theming](../customization/theming.md).
|
|
137
|
+
See also: [Fill Handle](fill-handle.md), [Clipboard](clipboard.md), [Undo & Redo](undo-redo.md), [Keyboard Navigation](keyboard-navigation.md), [Theming](../customization/theming.md).
|