@opencorestack/opengridx 3.8.1 → 3.9.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 +41 -0
- package/README.md +11 -7
- package/dist/index.d.ts +340 -1
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7529 -7285
- 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 +93 -4
- package/docs/architecture/datagrid-orchestration.md +4 -2
- package/docs/architecture/use-grid-virtualization.md +2 -0
- package/docs/components/pagination.md +1 -1
- package/docs/customization/theming.md +11 -2
- package/docs/features/ai-toolkit.md +1 -1
- package/docs/features/rtl.md +1 -1
- package/docs/performance.md +19 -1
- package/docs/roadmap.md +26 -5
- package/lib/components/AiAssistant/GridAiAssistantPanel.tsx +16 -14
- package/lib/components/Cell/CellErrorBoundary.tsx +17 -10
- package/lib/components/CellSelectionStats/CellSelectionStats.tsx +5 -3
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +3 -1
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +6 -4
- package/lib/components/DataGrid/GridAggregationFooter.tsx +3 -1
- package/lib/components/DataGrid/GridErrorOverlay.tsx +4 -2
- package/lib/components/DataGrid/GridListView.tsx +7 -5
- package/lib/components/DataGrid/GridLiveRegion.tsx +5 -3
- package/lib/components/DataGrid/GridLoadingOverlay.tsx +3 -1
- package/lib/components/DataGrid/GridPinnedRows.tsx +1 -1
- package/lib/components/DataGrid/GridRoot.tsx +8 -1
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +3 -1
- package/lib/components/DataGrid/GridViewport.tsx +3 -1
- package/lib/components/DataGrid/GridVirtualRows.tsx +1 -1
- package/lib/components/DataGrid/gridLocaleContext.ts +13 -0
- package/lib/components/FilterPanel/FilterPanel.tsx +18 -17
- package/lib/components/Header/ColumnMenu.css +5 -5
- package/lib/components/Header/ColumnMenu.tsx +17 -15
- package/lib/components/Header/Header.tsx +8 -6
- package/lib/components/HeaderFilter/HeaderFilterRow.tsx +3 -1
- package/lib/components/ListView/ListViewRow.tsx +3 -1
- package/lib/components/Pagination/Pagination.tsx +15 -18
- package/lib/components/QuickFilter/QuickFilter.tsx +5 -2
- package/lib/components/Row/Row.tsx +5 -3
- package/lib/components/Toolbar/GlobalSearch.tsx +6 -3
- package/lib/components/Toolbar/GridToolbar.tsx +35 -29
- package/lib/components/Toolbar/PivotPanel.tsx +26 -24
- package/lib/components/ui/Checkbox.css +5 -5
- package/lib/components/ui/DragHandleIcon.tsx +3 -1
- package/lib/components/ui/ExpandIcon.css +3 -3
- package/lib/components/ui/ExpandIcon.tsx +3 -1
- package/lib/hooks/core/useGridRowInteractions.ts +13 -3
- package/lib/hooks/core/useGridToolbarStack.ts +2 -2
- package/lib/hooks/core/useGridVirtualization.ts +40 -25
- package/lib/hooks/core/useShallowStableValue.ts +29 -0
- package/lib/hooks/features/useGridAiAssistant.ts +52 -22
- package/lib/theme/DataGridThemeProvider.tsx +9 -0
- package/lib/theme/types.ts +18 -0
- package/lib/types/locale.ts +344 -0
- package/lib/utils/gridLocale.ts +241 -0
- package/llms.txt +3 -1
- package/package.json +4 -2
- package/lib/theme/__baseline__/default-theme.darwin.chromium.json +0 -1
- package/lib/theme/__baseline__/default-theme.darwin.firefox.json +0 -1
- package/lib/theme/__baseline__/default-theme.darwin.webkit.json +0 -1
package/docs/API_REFERENCE.md
CHANGED
|
@@ -243,7 +243,7 @@ Public CSS: `ogx__cell-fill-handle` (24 × 24 px hit area in the corner cell; th
|
|
|
243
243
|
|
|
244
244
|
| Prop | Type | Default | Description |
|
|
245
245
|
| :--- | :--- | :--- | :--- |
|
|
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, the Ask AI button (`aiAssistantButton`)
|
|
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, the Ask AI button (`aiAssistantButton`), the header filter row (`headerFilter*`, v3.6) and, since v3.9, every other built-in string (toolbar, column menu, filter, columns, pivot and AI panels, rows, overlays, live region). See [`GridLocaleText`](#gridlocaletext). |
|
|
247
247
|
|
|
248
248
|
#### Imperative Ref
|
|
249
249
|
|
|
@@ -663,8 +663,8 @@ Context provider for overriding the grid's visual system.
|
|
|
663
663
|
- **`colors`**: `primary`, `primaryDark`, `primaryLight`, `primaryFocus`, `secondary*`, `success`, `warning`, `error`, `info`, `white`, `black`, `gray` (`{ 50 … 900 }`). Toolbar, menu, selection and focus accents derive from `primary*` unless set directly.
|
|
664
664
|
- **`typography`**: `fontFamily`, `fontFamilyMono`, `fontSizeXs` … `fontSizeXl`.
|
|
665
665
|
- **`spacing`**: `xs` … `xxl`. **`borders`**: `widthThin/Medium/Thick`, `radiusSm` … `radiusXl`, `color`, `colorHover`. **`shadows`**: `sm` … `xl`.
|
|
666
|
-
- **`grid`**: surfaces (`background`, `borderColor`, `headerBackground`, `headerText`, `headerHoverBackground`, `headerSortedBackground`, `rowText`, `rowHoverBackground`, `rowAlternateBackground`, `rowSelectedBackground`, `rowSelectedHoverBackground`, `cellFocusBorder`, `rangeBackground`, `rangeBorder` (v3.3), `pinnedLeftShadow`, `pinnedRightShadow`, `checkboxBg`, `checkboxBorder`), sizing (`rowHeightCompact`, `rowHeightStandard`, `rowHeightComfortable`, `headerHeight` in px, read by the grid's layout; the `rowHeight` / `headerHeight` props win), `cellPaddingX`, `cellPaddingY`, `cellFontSize`, `headerFontSize`; v3.7: fonts (`headerFontFamily`, `headerFontWeight`, `cellFontFamily`, `cellFontWeight`), `headerPaddingX`, outer `borderWidth` and `borderRadius`, dividers (`columnDividerWidth`, `headerColumnDividerWidth`, `rowDividerWidth`, `columnDividerColor`, `rowDividerColor`; `0` hides a divider).
|
|
667
|
-
- **`overlays`**: colours (`background`, `text`, `border`, `shadow`, `item*`) and, v3.7, `fontFamily`, `fontWeight`, `fontSize` for menus and panels.
|
|
666
|
+
- **`grid`**: surfaces (`background`, `borderColor`, `headerBackground`, `headerText`, `headerHoverBackground`, `headerSortedBackground`, `rowText`, `rowHoverBackground`, `rowAlternateBackground`, `rowSelectedBackground`, `rowSelectedHoverBackground`, `cellFocusBorder`, `rangeBackground`, `rangeBorder` (v3.3), `pinnedLeftShadow`, `pinnedRightShadow`, `checkboxBg`, `checkboxBorder`; v3.9: `checkboxCheckedBackground`, `checkboxCheckmark`, `expandIconColor`, `expandIconHoverColor`), sizing (`rowHeightCompact`, `rowHeightStandard`, `rowHeightComfortable`, `headerHeight` in px, read by the grid's layout; the `rowHeight` / `headerHeight` props win), `cellPaddingX`, `cellPaddingY`, `cellFontSize`, `headerFontSize`; v3.7: fonts (`headerFontFamily`, `headerFontWeight`, `cellFontFamily`, `cellFontWeight`), `headerPaddingX`, outer `borderWidth` and `borderRadius`, dividers (`columnDividerWidth`, `headerColumnDividerWidth`, `rowDividerWidth`, `columnDividerColor`, `rowDividerColor`; `0` hides a divider).
|
|
667
|
+
- **`overlays`**: colours (`background`, `text`, `border`, `shadow`, `item*`) and, v3.7, `fontFamily`, `fontWeight`, `fontSize` for menus and panels; v3.9: `itemIndicatorColor` (the selection dot), `itemSelectedIcon`, `iconColor`, `sectionLabelText`, `dividerColor`.
|
|
668
668
|
- **`toolbar`**, **`scrollbar`** (`thumbColor`, `trackColor`, `size`), **`skeleton`** (`baseColor`, `highlightColor`), **`transitions`**.
|
|
669
669
|
|
|
670
670
|
#### Theme types
|
|
@@ -906,7 +906,7 @@ interface GridPivotValueField {
|
|
|
906
906
|
|
|
907
907
|
### `GridLocaleText`
|
|
908
908
|
|
|
909
|
-
Override user-visible strings
|
|
909
|
+
Override the grid's user-visible strings (visible text, `aria-label`, `title`, placeholder). All fields are optional; each one left out keeps its English default. Strings that contain a value (a header, a row id, a count) are functions.
|
|
910
910
|
|
|
911
911
|
```typescript
|
|
912
912
|
interface GridLocaleText {
|
|
@@ -931,9 +931,98 @@ interface GridLocaleText {
|
|
|
931
931
|
headerFilterTrue?: string; // "Yes"
|
|
932
932
|
headerFilterFalse?: string; // "No"
|
|
933
933
|
headerFilterOperators?: Partial<Record<GridFilterOperator, string>>; // operator names
|
|
934
|
+
|
|
935
|
+
// ── v3.9: every other UI string (default English shown) ──
|
|
936
|
+
// Grid, list view, overlays, live region
|
|
937
|
+
gridLabel; listViewLabel; // "Data grid", "Data grid list view" (the aria-label prop wins)
|
|
938
|
+
listViewItemCount(n); listViewPage(p, pc); listViewSelectedCount(n); // "3 items", "page 1 of 2", "2 selected"
|
|
939
|
+
loadingLabel; liveRegionLoading; // "Loading data", "Loading data..."
|
|
940
|
+
liveRegionError(message); liveRegionRowsFound(n); // "Error: …", "4 rows found"
|
|
941
|
+
errorOverlayTitle; errorOverlayRetry; // "Oops! Something went wrong", "Retry"
|
|
942
|
+
aggregationFooterLabel; // "Aggregation totals"
|
|
943
|
+
cellErrorLabel(field); cellErrorTooltip; // "Error in cell: name", "Render error"
|
|
944
|
+
// Header
|
|
945
|
+
headerRowReorderLabel; headerRowReorderTooltip; headerDetailPanelLabel;
|
|
946
|
+
headerSelectAllLabel; headerDeselectAllLabel; // "Select all rows", "Deselect all rows"
|
|
947
|
+
headerSortDescription(direction, priority, total); // "Sorted ascending, sort priority 1 of 2"
|
|
948
|
+
headerColumnMenuButtonLabel(header); // "Open column menu for Name"
|
|
949
|
+
headerColumnResizeLabel(field); headerFilterNoFilterLabel(header);
|
|
950
|
+
// Rows
|
|
951
|
+
rowSelectLabel(id); rowDeselectLabel(id); // "Select row 1", "Deselect row 1"
|
|
952
|
+
rowReorderLabel; rowDetailPanelExpandLabel; rowDetailPanelCollapseLabel; rowExpandLabel; rowCollapseLabel;
|
|
953
|
+
// Column menu
|
|
954
|
+
columnMenuLabel(header); columnMenuSortAscending; columnMenuSortDescending; columnMenuUnsort;
|
|
955
|
+
columnMenuPinColumn; columnMenuPinLeft; columnMenuPinLeftLabel; columnMenuPinRight; columnMenuPinRightLabel;
|
|
956
|
+
columnMenuUnpin; columnMenuUnpinLabel; columnMenuHideColumn; columnMenuHideColumnLabel(header);
|
|
957
|
+
columnMenuManageColumns; columnMenuManageColumnsLabel;
|
|
958
|
+
// Columns panel
|
|
959
|
+
columnsPanelSearchPlaceholder; columnsPanelDragToReorder; columnsPanelShowHideAll; columnsPanelReset; columnsPanelClose;
|
|
960
|
+
// Filter panel
|
|
961
|
+
filterPanelValueLabel(header); filterPanelOperatorLabel(header); filterPanelClearLabel(header); filterPanelClearTooltip;
|
|
962
|
+
filterPanelAny; filterPanelTrue; filterPanelFalse; filterPanelNumberPlaceholder; filterPanelValuePlaceholder;
|
|
963
|
+
filterPanelMatch; filterPanelAnd; filterPanelOr; filterPanelHiddenConditions(n); filterPanelNoColumns;
|
|
964
|
+
filterPanelOperators; // Partial<Record<GridFilterOperator, string>>, default: the operator id
|
|
965
|
+
// Toolbar and search (toolbarSearchPlaceholder also for QuickFilter)
|
|
966
|
+
toolbarLabel; toolbarSearchPlaceholder; toolbarSearchLabel; toolbarSearchClear;
|
|
967
|
+
toolbarColumns; toolbarColumnsLabel; toolbarColumnsPanelLabel;
|
|
968
|
+
toolbarFilters; toolbarFiltersLabel; toolbarFiltersActive; toolbarFiltersClearAll; toolbarFiltersClearAllTooltip;
|
|
969
|
+
toolbarFiltersClose; toolbarFiltersCloseTooltip; toolbarFiltersCloseLabel;
|
|
970
|
+
toolbarPivot; toolbarPivotLabel; toolbarPivotActive;
|
|
971
|
+
toolbarSummaries; toolbarSummariesLabel; toolbarSummariesActive(n); toolbarSummariesPanelLabel;
|
|
972
|
+
toolbarSummariesClearAll; toolbarSummariesClearAllTooltip; toolbarSummariesEmpty;
|
|
973
|
+
toolbarSummariesEmptyHintBefore; toolbarSummariesEmptyHintAfter;
|
|
974
|
+
toolbarAggregationFunctions; // Partial<Record<string, string>>, default: the function id
|
|
975
|
+
// Pivot panel
|
|
976
|
+
pivotPanelLabel; pivotMode; pivotReset; pivotResetTooltip;
|
|
977
|
+
pivotRowFields; pivotColumnFields; pivotValueFields;
|
|
978
|
+
pivotRowFieldsPlaceholder; pivotColumnFieldsPlaceholder; pivotValueFieldsPlaceholder;
|
|
979
|
+
pivotRemoveTooltip(header); pivotRemoveRowLabel(header); pivotRemoveColumnLabel(header); pivotRemoveValueLabel(header, fn);
|
|
980
|
+
pivotAggregationTooltip; pivotAggregationLabel(header);
|
|
981
|
+
pivotAggregationFunctions; // Partial<Record<string, string>>, default: the id in upper case
|
|
982
|
+
pivotAvailableFields; pivotAllFieldsInUse; pivotAddRow; pivotAddColumn; pivotAddValue;
|
|
983
|
+
pivotAddRowTooltip; pivotAddColumnTooltip; pivotAddValueTooltip;
|
|
984
|
+
pivotAddRowLabel(header); pivotAddColumnLabel(header); pivotAddValueLabel(header);
|
|
985
|
+
// AI assistant panel (aiAssistant.placeholder wins over aiAssistantPlaceholder)
|
|
986
|
+
aiAssistantTitle; aiAssistantClose; aiAssistantPromptLabel; aiAssistantPlaceholder;
|
|
987
|
+
aiAssistantStartDictation; aiAssistantStopDictation; aiAssistantAsk; aiAssistantStop; aiAssistantSuggestions;
|
|
988
|
+
aiAssistantAppliedChanges; aiAssistantRemoveChange(label); aiAssistantUndo; aiAssistantIgnored; aiAssistantIgnoredItem(message);
|
|
989
|
+
aiAssistantEarlier; aiAssistantThinking; aiAssistantStopped; aiAssistantUndone; aiAssistantChangeRemoved;
|
|
990
|
+
aiAssistantApplied(applied, ignored); aiAssistantNotValidated; aiAssistantFailed(message); aiAssistantUnknownError;
|
|
991
|
+
// Pagination buttons
|
|
992
|
+
paginationLabel; paginationFirstPageLabel; paginationFirstPageTooltip; paginationPreviousPageLabel;
|
|
993
|
+
paginationPreviousPageTooltip; paginationNextPageLabel; paginationNextPageTooltip;
|
|
994
|
+
paginationLastPageLabel; paginationLastPageTooltip;
|
|
995
|
+
// Cell selection stats bar
|
|
996
|
+
cellSelectionStatsCount; cellSelectionStatsSum; cellSelectionStatsAverage;
|
|
934
997
|
}
|
|
935
998
|
```
|
|
936
999
|
|
|
1000
|
+
Each key's English default and parameter types are documented on `GridLocaleText` in `lib/types/locale.ts` (shown by editors on hover).
|
|
1001
|
+
|
|
1002
|
+
### Locale text for every UI string (v3.9)
|
|
1003
|
+
|
|
1004
|
+
Since v3.9 every built-in string of the grid goes through `localeText`: the toolbar and its panels, the column menu, the filter, columns, pivot and AI assistant panels, the row and select-all checkboxes, the pagination buttons, the loading and error overlays, the aggregation footer and the live-region announcements. Pass only the keys you translate; the rest stay English.
|
|
1005
|
+
|
|
1006
|
+
```tsx
|
|
1007
|
+
<DataGrid
|
|
1008
|
+
rows={rows}
|
|
1009
|
+
columns={columns}
|
|
1010
|
+
slots={{ toolbar: GridToolbar }}
|
|
1011
|
+
localeText={{
|
|
1012
|
+
toolbarSearchPlaceholder: 'Rechercher…',
|
|
1013
|
+
columnMenuSortAscending: 'Tri croissant',
|
|
1014
|
+
columnMenuHideColumnLabel: (header) => `Masquer la colonne ${header}`,
|
|
1015
|
+
filterPanelOperators: { contains: 'contient' },
|
|
1016
|
+
rowSelectLabel: (id) => `Sélectionner la ligne ${id}`,
|
|
1017
|
+
}}
|
|
1018
|
+
/>
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
- The strings reach portalled menus and panels through React context, so a custom toolbar slot that renders the built-in `GridToolbar` is translated too.
|
|
1022
|
+
- Components used outside a grid (`ColumnVisibilityPanel`, `GridToolbar`, `FilterPanel`, `Pagination`, `QuickFilter`) show English. Their own props (`placeholder`, `aiAssistantLabel`, `Pagination`'s `localeText`) still win.
|
|
1023
|
+
- Not covered: the grouping column's default header (`'Group'`, set `groupingColDef.headerName`), pivot's `'Grand Total'` row label, export file contents, the AI change chips' labels, and developer console warnings.
|
|
1024
|
+
- An inline object of strings is fine: while it holds the same entries as on the previous render (records such as `filterPanelOperators` compared one level deep), the grid keeps the resolved strings and the rows are not re-rendered. Functions are compared by identity, so define function entries (`rowSelectLabel: id => …`) outside the render, or keep the whole object in a module constant or `useMemo`.
|
|
1025
|
+
|
|
937
1026
|
### `GridRowMeta`
|
|
938
1027
|
|
|
939
1028
|
Available via `params.rowMeta` in `renderCell`. Undefined for non-hierarchy rows.
|
|
@@ -113,10 +113,12 @@ in an effect, so **keep the call order when you move or add a hook**. In particu
|
|
|
113
113
|
`GridToolbarSlot`, `GridAiAssistantArea` (the `aiAssistant` panel or `slots.aiAssistantPanel` while open, anchored under the toolbar), `GridStandaloneColumnPanel`, `GridListView` (list view) or `GridViewport` (`components/DataGrid/GridViewport.tsx`, the `role="grid"` viewport:
|
|
114
114
|
`Header`, `GridPinnedRows` top, `GridEmptyState`, `GridVirtualRows`, `GridPinnedRows` bottom,
|
|
115
115
|
`GridAggregationFooter`), `GridCellSelectionStatsArea` (`showCellSelectionStats` with `cellSelection`), then `slots.footer` or `GridPaginationArea`, `GridLiveRegion`,
|
|
116
|
-
`GridLoadingOverlay` and `GridErrorOverlay`. `GridRoot` builds the overlay slot elements and passes the
|
|
116
|
+
`GridLoadingOverlay` and `GridErrorOverlay`. `GridRoot` also provides `GridLocaleContext` (v3.9) around all of them: `localeText`, kept stable while shallowly equal (`useShallowStableValue`), resolved once by `resolveGridLocale` (`lib/utils/gridLocale.ts`); components and `Row` read it with `useGridLocale()` instead of a prop, so `Row` gets no prop that changes per render. `GridRoot` builds the overlay slot elements and passes the
|
|
117
117
|
rest of its props on to `GridViewport`. The props all three row renderers take alike are built once in
|
|
118
118
|
`GridViewport` (`rowRenderProps`) and spread into each. `rowRenderProps.cellRange` is the cell range's
|
|
119
119
|
render rectangle; each row renderer turns it into a per-row `cellRange` (`getRowCellRange`), `null` for rows
|
|
120
120
|
outside it, and `Row` is memoised with a value comparison of that prop, so a drag only re-renders the rows the
|
|
121
|
-
range enters or leaves.
|
|
121
|
+
range enters or leaves. The same rule holds for every row prop (v3.9): `editingCell` goes only to the row being
|
|
122
|
+
edited, `focusedCellField` only to the focused row, and the row click and checkbox handlers keep one identity
|
|
123
|
+
(`useGridRowInteractions` reads the latest handlers when called). `DataGrid.rowMemo.test.tsx` guards it. `rowRenderProps.fillHandle` (v3.5) adds `fillHandleCol` to the one row that draws the fill
|
|
122
124
|
handle (a single selected cell gets an empty column interval, so it draws the handle but no range).
|
|
@@ -90,6 +90,8 @@ Row heights include an expanded detail panel's height, so the prefix sums accoun
|
|
|
90
90
|
|
|
91
91
|
Columns use the same search on `unpinnedAccWidths` (also inclusive), relative to the left edge of the unpinned area (`scrollLeft - leftPinnedWidth`), widened by 6 columns on each side. The skipped widths become `__spacer_left__` / `__spacer_right__` entries (`isSpacer: true`) in `virtualColumns`.
|
|
92
92
|
|
|
93
|
+
The column window is computed in its own `useMemo` (v3.9), over the column parts of the layout (`unpinnedAccWidths`, `unpinnedColsWithWidth`, the pinned column lists and widths), `scrollLeft` and the viewport width only. A row change (an edit), a vertical scroll or a row-height change therefore keeps the same `virtualColumns` array, and `Row`, which is memoised on its props, does not re-render for it. `useLayout` returns the row and column parts from separate memos (v3.7.1), so the column fields keep their identity while rows change.
|
|
94
|
+
|
|
93
95
|
When a column declares `colSpan` / `rowSpan`, `DataGrid` widens this window afterwards (`useGridSpanRowWindow` / `useGridSpanColumnWindow`) so a span whose origin is outside the window is not cut.
|
|
94
96
|
|
|
95
97
|
---
|
|
@@ -41,7 +41,7 @@ You can replace the internal pagination UI using the `pagination` slot:
|
|
|
41
41
|
|
|
42
42
|
## 🌍 Internationalisation
|
|
43
43
|
|
|
44
|
-
Pass `localeText` on `<DataGrid />` to override the text labels in the Pagination component (rows-per-page, range, and page-counter labels). The rows-per-page select takes its accessible name from the `paginationRowsPerPage` label.
|
|
44
|
+
Pass `localeText` on `<DataGrid />` to override the text labels in the Pagination component (rows-per-page, range, and page-counter labels). The rows-per-page select takes its accessible name from the `paginationRowsPerPage` label. Since v3.9 the navigation landmark label (`paginationLabel`, default `"Pagination"`) and each button's label and tooltip (`paginationNextPageLabel` / `paginationNextPageTooltip` → `"Go to next page"` / `"Next page"`, and the same for First, Previous and Last) are `localeText` keys as well.
|
|
45
45
|
|
|
46
46
|
| Key | Type | Default |
|
|
47
47
|
| :--- | :--- | :--- |
|
|
@@ -262,8 +262,12 @@ For visible gaps between cells instead of lines, set the divider colour to the g
|
|
|
262
262
|
| `--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` |
|
|
263
263
|
| `--ogx-grid-pinned-left-shadow` | `4px 0 24px...` | (darker) | Shadow on left-pinned columns |
|
|
264
264
|
| `--ogx-grid-pinned-right-shadow` | `-4px 0 24px...` | (darker) | Shadow on right-pinned columns |
|
|
265
|
-
| `--ogx-checkbox-bg` | — | `#1e293b` | Checkbox background (dark only) |
|
|
266
|
-
| `--ogx-checkbox-border` | — | `#64748b` | Checkbox border (dark only) |
|
|
265
|
+
| `--ogx-checkbox-bg` | — | `#1e293b` | Checkbox background (dark only). Theme key `grid.checkboxBg` |
|
|
266
|
+
| `--ogx-checkbox-border` | — | `#64748b` | Checkbox border (dark only). Theme key `grid.checkboxBorder` |
|
|
267
|
+
| `--ogx-checkbox-checked-bg` | primary | primary | Fill and border of a checked or indeterminate checkbox (v3.9). Theme key `grid.checkboxCheckedBackground` |
|
|
268
|
+
| `--ogx-checkbox-checkmark` | `white` | `white` | Check mark and indeterminate dash (v3.9). Theme key `grid.checkboxCheckmark` |
|
|
269
|
+
| `--ogx-expand-icon-color` | header text | header text | Expand / collapse chevron of group and tree rows (v3.9). Theme key `grid.expandIconColor` |
|
|
270
|
+
| `--ogx-expand-icon-hover-color` | row text | row text | The chevron on hover (v3.9). Theme key `grid.expandIconHoverColor` |
|
|
267
271
|
|
|
268
272
|
### Toolbar, Overlay and Scrollbar Colors
|
|
269
273
|
|
|
@@ -282,6 +286,11 @@ Read with a fallback, so a grid without a provider looks the same as before. Ins
|
|
|
282
286
|
| `--ogx-overlay-*` | `overlays.*` | white surface, gray border | Menus, panels, tooltips |
|
|
283
287
|
| `--ogx-overlay-item-selected-bg` / `-text` | `overlays.itemSelected*` | 8% primary / primary-dark | Selected menu item |
|
|
284
288
|
| `--ogx-overlay-item-danger-bg` / `-text` | `overlays.itemDanger*` | red tints | Remove-condition button in the filter panel |
|
|
289
|
+
| `--ogx-overlay-item-indicator` | `overlays.itemIndicatorColor` (v3.9) | the selected item text | Dot before the selected option of a menu group (sort, pin) |
|
|
290
|
+
| `--ogx-overlay-item-selected-icon` | `overlays.itemSelectedIcon` (v3.9) | primary | Icon of the selected menu option |
|
|
291
|
+
| `--ogx-overlay-icon` | `overlays.iconColor` (v3.9) | gray-400 | Menu item icons |
|
|
292
|
+
| `--ogx-overlay-section-label-text` | `overlays.sectionLabelText` (v3.9) | gray-400 | Menu section labels ("Pin column") |
|
|
293
|
+
| `--ogx-overlay-divider` | `overlays.dividerColor` (v3.9) | overlay border | Lines between menu sections |
|
|
285
294
|
| `--ogx-scrollbar-thumb` / `-track` / `-size` | `scrollbar.thumbColor` / `trackColor` / `size` | gray-300 / transparent / 8px | Grid viewport scrollbars |
|
|
286
295
|
| `--ogx-skeleton-base` / `-highlight` | `skeleton.baseColor` / `highlightColor` | light grays | Loading skeleton rows |
|
|
287
296
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AI Toolkit: Schema, Validator, Assistant & Agent Tools
|
|
2
2
|
|
|
3
|
-
*Since v3.4.0 (schema and validator); v3.5.0 (assistant panel, prompt handler, agent tools)* · Demos: [
|
|
3
|
+
*Since v3.4.0 (schema and validator); v3.5.0 (assistant panel, prompt handler, agent tools)* · Demos: [Grid Schema & Validator](https://opencorestack.github.io/OpenGridX/ai-schema), [AI Assistant](https://opencorestack.github.io/OpenGridX/ai-assistant)
|
|
4
4
|
|
|
5
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
|
|
package/docs/features/rtl.md
CHANGED
|
@@ -42,7 +42,7 @@ The column menu is labelled by screen side: in RTL *Pin to Left* adds the column
|
|
|
42
42
|
|
|
43
43
|
## Known limitations
|
|
44
44
|
|
|
45
|
-
-
|
|
45
|
+
- ~~Menu and panel labels are hard-coded English~~: since v3.9 every built-in string, including the column menu (`columnMenuPinLeft`, `columnMenuSortAscending`, …), is a `localeText` key. See *Locale text for every UI string* in [`API_REFERENCE.md`](../API_REFERENCE.md).
|
|
46
46
|
- **Header filter operator symbols** are mirrored by the browser's bidi rules (`∋` shows as `∈`), as in any RTL text.
|
|
47
47
|
- **`direction` set through CSS** (a class or stylesheet, not the `dir` attribute) and changed at runtime is not detected; scroll the grid or remount it with a `key`.
|
|
48
48
|
- **Headless Chromium tests:** Playwright launches Chromium with `--hide-scrollbars`. With classic scrollbars (Linux) `scrollbar-gutter: stable` still reserves the gutter, and in RTL Chromium then cannot scroll the last gutter-width of the start into view (`scrollLeft` stops at minus the gutter). A plain scroller without the grid does the same and real browsers with visible scrollbars do not. Tests must compare with the browser's scroll origin, as `DataGrid.rtl.browser.test.tsx` does. To reproduce on macOS: `defaults write chrome-headless-shell AppleShowScrollBars Always` (undo with `defaults delete chrome-headless-shell`).
|
package/docs/performance.md
CHANGED
|
@@ -136,7 +136,7 @@ Measured with `npm run bench` (`bench/`), which installs the packed npm package
|
|
|
136
136
|
| 500,000 (3.5.0) | 295 ms | 493 / 641 ms | 59 ms | 958 ms | 331 ms | 0 % | 39.4 MB |
|
|
137
137
|
| 1,000,000 | 621 ms | 467 / 467 ms | 109 ms | 1,813 ms | 693 ms | 0 % | 76.9 MB |
|
|
138
138
|
|
|
139
|
-
### Before and after the faster sort, quick filter and grouping (
|
|
139
|
+
### Before and after the faster sort, quick filter and grouping (3.6.0)
|
|
140
140
|
|
|
141
141
|
Medians of 5 runs, the same machine, the 3.5.1 code (`122d431`) and the changed code (`e1df2f1`) measured back to back on 2026-10-12 (`bench/results/2026-10-12-apple-m1-darwin-before.json` and `bench/results/2026-10-12-apple-m1-darwin.json`). Load average at the start of each run: 2.9 (before) and 4.6 (after); an IDE, a browser and other tools were open. Row counts after every filter and grouping were identical in both runs.
|
|
142
142
|
|
|
@@ -162,6 +162,24 @@ What changed: sort keys are read once per row into typed arrays and strings are
|
|
|
162
162
|
- **Sorting, the quick filter and grouping run on the main thread in one piece.** Up to 100k rows they finish in a few frames; at 1M a sort blocks the page for about 0.35–0.6 s in every engine, grouping for 0.7 s (1.8 s in Firefox), and the first quick-filter keystroke for about 1.8–3 s. For sorting or searching a million rows interactively, use server-side sorting and filtering.
|
|
163
163
|
- **Reach:** past the browser's height cap rows cannot be scrolled to, and in Firefox the grid stops scrolling altogether. See [Reach](#reach-the-browser-height-ceiling).
|
|
164
164
|
|
|
165
|
+
### Editing, selection and grouping at 1M rows (3.8 – 3.9)
|
|
166
|
+
|
|
167
|
+
Measured in Chromium on an Apple M1, 1,000,000 rows, from the event to the end of its long task (best of three; not part of `npm run bench`, which covers mount, scroll, sort and filter).
|
|
168
|
+
|
|
169
|
+
| Interaction | 3.7.0 | 3.8.0 | |
|
|
170
|
+
| :--- | ---: | ---: | :--- |
|
|
171
|
+
| Edit one cell | 561 ms | ~35 ms | the row store is updated in place; id lists over the visible rows are reused |
|
|
172
|
+
| Paste 1,000 × 10 cells | ~790 ms | ~45 ms | |
|
|
173
|
+
| Undo / redo of that paste | ~790 ms | ~45 ms | |
|
|
174
|
+
| Fill 1,000 cells | 809 ms | ~50 ms | |
|
|
175
|
+
| Expand a group | 279 ms | ~135 ms | leaf row metadata built once per tree |
|
|
176
|
+
| Collapse a group | ~120 ms | ~1 ms | |
|
|
177
|
+
| Select all | ~270 ms | ~270 ms | bounded by building 1M-id sets for the array `rowSelectionModel` |
|
|
178
|
+
|
|
179
|
+
3.9.0 keeps rows memoised: selecting a row, starting or committing an edit, and vertical scrolling re-render only the rows they change (a click re-rendered every visible row, now one). React's own work per interaction is about 3–5 ms at 100k rows.
|
|
180
|
+
|
|
181
|
+
To keep this, change rows by passing new row objects (never mutate them), keep `columns` and `localeText` shallowly stable (inline objects of plain values are fine; define function entries outside the render). Handlers such as `onRowClick` may be inline: the grid passes rows its own stable handlers.
|
|
182
|
+
|
|
165
183
|
### Method
|
|
166
184
|
|
|
167
185
|
- **The app is the built package.** `bench/app` installs the tarball from `npm pack`, like a consumer, and is a production build (no React development checks).
|
package/docs/roadmap.md
CHANGED
|
@@ -85,14 +85,32 @@ This document tracks the current status of features in `OpenGridX` and outlines
|
|
|
85
85
|
| **3.3.0** ✅ | shipped 7 Oct | **Cell range selection** (opt-in `cellSelection` prop): mouse drag, Shift+click, Shift+arrows; Ctrl+C / Cmd+C copies the block as TSV | Selection status bar (count, sum, average of selected cells); wrapped header text; React Compiler compatibility check |
|
|
86
86
|
| **3.4.0** ✅ | shipped 8 Oct | **Paste from Excel / Google Sheets** into the selection, through `processRowUpdate` (values parsed per column type or `valueParser`, non-editable cells skipped, `onClipboardPaste` summary); **Delete clears a range**; built-in inputs and editors use the shared `Input` / `Checkbox` (`Input variant="cell"`). **Undo / redo** for cell edits and pastes (Ctrl+Z, Ctrl+Shift+Z / Ctrl+Y, `apiRef.undo()` / `redo()`) | **AI toolkit, part 1** in a new `@opencorestack/opengridx/ai` entry point: `getGridAiSchema(columns)` (JSON Schema of the filter, sort, grouping, aggregation, pivot and visibility models the columns allow) and `validateGridAiState(json, columns)` (drops unknown fields and operators, coerces values, returns errors) |
|
|
87
87
|
| **3.5.0** ✅ | shipped 9 Oct | **AI toolkit, part 2**: `aiAssistant={{ onPrompt }}` Ask AI panel (chips, Undo, voice) that calls the app's own model through `createGridAiPromptHandler`; only validated replies apply; `createGridAgentTools(apiRef, columns)` (plain tool objects for CopilotKit, the Vercel AI SDK, provider tool calling or WebMCP) | **Header filter row** (`headerFilters`); **fill handle** (series, Alt copy, Ctrl/Cmd+D / R); `rowGroupingModel` controlled/uncontrolled pair |
|
|
88
|
+
| **3.5.1** ✅ | shipped 10 Oct | **Content height capped to the browser's limit** (Firefox collapsed grids taller than ~17.9M px) | Dev warning names the reachable row count |
|
|
89
|
+
| **3.6.0** ✅ | shipped 12 Oct | **Sorting 3–5× faster** (typed-array keys) | Next.js `'use client'` banner; optional peers safe in webpack / Turbopack; **RTL parts 1 and 2** (pinned columns); header filter `localeText` |
|
|
90
|
+
| **3.7.0** ✅ | shipped 13 Oct | **Theme Builder** demo page + 16 theme keys | `DataGrid.tsx` split (`GridRoot` / `GridViewport`, composite hooks); types split per domain; demo smoke test |
|
|
91
|
+
| **3.7.1** ✅ | shipped 13 Oct | Audit fixes: exports survive a throwing `valueGetter`; **formula escaping of `valueFormatter` text** (security) | Quick filter matches shown text; date paste fixes; list view theme; CSS reset scoped to the grid |
|
|
92
|
+
| **3.8.0** ✅ | shipped 13 Oct | **Edits at 1M rows 10–20× faster** (in-place row store; edit ~35 ms, paste ~45 ms) | Group expand ~2×, collapse ~1 ms |
|
|
93
|
+
| **3.8.1** ✅ | shipped 13 Oct | **Grid buttons keep their own styles** (AI panel, toolbar active states) | Exact `bigint` sort; stricter number text; dead-code cleanup; every export documented |
|
|
94
|
+
| **3.9.0** ✅ | shipped 13 Oct | **`localeText` for every UI string** (~200 keys) | 9 theme keys + Theme Builder controls; rows stay memoised through selection and editing; demo sidebar by priority |
|
|
95
|
+
| **3.9.1** ✅ | shipped 13 Oct | **npm package no longer ships 1.6 MB of test baselines** | `check:package` guard in CI; version badges read `package.json`; docs brought up to date |
|
|
96
|
+
| 3.10.0 | open | AI change chips translatable | Backlog work below |
|
|
88
97
|
| Freeze | 19 Dec – 5 Jan | Bug fixes only | — |
|
|
89
98
|
|
|
99
|
+
### Now: backlog first (feature hold since 13 Oct)
|
|
100
|
+
|
|
101
|
+
New features (the *Next* list below) wait until the open fixes, refactors and performance work are done. Tracked in [`superpowers/plans/2026-10-13-audit-tracker.md`](superpowers/plans/2026-10-13-audit-tracker.md):
|
|
102
|
+
|
|
103
|
+
* **Refactors** (no behaviour change): about 40 `as unknown as` casts (R4), files over 600 lines such as `GridToolbar.tsx` (R5), hooks with very wide parameter lists such as keyboard navigation (R6).
|
|
104
|
+
* **Performance**: the time-sliced filter / sort pipeline (held: 1.5–2× slower in total, needs to be within ~20 %); select-all at 1M rows (~270 ms, bounded by the array `rowSelectionModel`).
|
|
105
|
+
* **Demo**: syntax highlighting in the source viewer.
|
|
106
|
+
* **Bundle size (4.0)**: an app using only `DataGrid` ships 87 KB gzipped; opt-in [feature modules](superpowers/specs/2026-10-13-feature-modules-proposal.md) would save ~20 KB. Breaking, so planned for 4.0.
|
|
107
|
+
|
|
90
108
|
### Across the quarter
|
|
91
109
|
|
|
92
110
|
* ✅ **Published benchmark** (done 9 Oct): reproducible 10k / 100k / 500k / 1M-row numbers (scroll frame times, sort, filter and grouping time, memory, the reachable row) in [`docs/performance.md`](performance.md#benchmarks); rerun with `npm run bench`.
|
|
93
111
|
* ✅ **Next.js App Router guide** (done 12 Oct): [`docs/features/nextjs.md`](features/nextjs.md), verified with `next build` / `next start` on Next.js 15.5 and 16.4. The ES bundle now starts with `'use client'`.
|
|
94
|
-
* ✅ **RTL check** (done 12 Oct): [`docs/features/rtl.md`](features/rtl.md). Fixed: text alignment, horizontal scrolling and column virtualization, arrow keys, the resize and fill handles, range outlines and auto-scroll, toolbar panel placement
|
|
95
|
-
* **Demo site**: source viewer on
|
|
112
|
+
* ✅ **RTL check** (done 12 Oct): [`docs/features/rtl.md`](features/rtl.md). Fixed: text alignment, horizontal scrolling and column virtualization, arrow keys, the resize and fill handles, range outlines and auto-scroll, toolbar panel placement; pinned columns followed in RTL part 2.
|
|
113
|
+
* **Demo site**: ✅ source viewer on every example (`DocsLayout` with Vite `?raw`); syntax highlighting still open.
|
|
96
114
|
|
|
97
115
|
### Definition of done for each feature
|
|
98
116
|
|
|
@@ -115,7 +133,7 @@ This document tracks the current status of features in `OpenGridX` and outlines
|
|
|
115
133
|
* **Undo must cover rejected updates**: a `processRowUpdate` that throws or a paste that partly fails must leave the history consistent.
|
|
116
134
|
* **Wrong AI filters** that look plausible: the validator, visible chips and undo are required, not optional.
|
|
117
135
|
|
|
118
|
-
## 🔭 Next (Q1 2027)
|
|
136
|
+
## 🔭 Next (Q1 2027) — on hold until the backlog above is closed
|
|
119
137
|
|
|
120
138
|
|
|
121
139
|
* **Row reordering inside tree data and row groups**, touch-friendly (MUI #4821, 405 👍, not in MUI X).
|
|
@@ -125,7 +143,7 @@ This document tracks the current status of features in `OpenGridX` and outlines
|
|
|
125
143
|
* **Sparklines** and a charts adapter that passes grid state to any chart library.
|
|
126
144
|
* **AI toolkit, part 3**: smart paste (unstructured text → pending rows) and `apiRef.getAiContext()` for "summarise selection"; an `opengridx-mcp` docs server for coding assistants.
|
|
127
145
|
* **Tailwind / shadcn theme preset**, sticky header against page scroll.
|
|
128
|
-
* ✅ **RTL, part 2** (done 12 Oct, [`rtl.md`](features/rtl.md)): pinned columns and pinned system columns with logical sticky offsets and mirrored shadows, column menu pinning by screen side, mirrored pagination arrows and tree chevrons, a direction change on a mounted grid, column reorder by drag checked. Remaining:
|
|
146
|
+
* ✅ **RTL, part 2** (done 12 Oct, [`rtl.md`](features/rtl.md)): pinned columns and pinned system columns with logical sticky offsets and mirrored shadows, column menu pinning by screen side, mirrored pagination arrows and tree chevrons, a direction change on a mounted grid, column reorder by drag checked. Remaining: the bidi-mirrored header filter operator symbols (the menu labels became `localeText` keys in 3.9).
|
|
129
147
|
|
|
130
148
|
### Not planned
|
|
131
149
|
|
|
@@ -136,6 +154,9 @@ This document tracks the current status of features in `OpenGridX` and outlines
|
|
|
136
154
|
|
|
137
155
|
## ✅ Implemented Features (Recent)
|
|
138
156
|
|
|
157
|
+
### 3.3 – 3.9 *(2026-10-07 → 2026-10-13)*
|
|
158
|
+
- Spreadsheet editing (range selection, paste, undo / redo, fill handle), the AI toolkit (schema, validator, Ask AI panel, agent tools), header filters, the 1M-row benchmark and height cap, 3–5× faster sorting, RTL, the Theme Builder, a full audit with security and correctness fixes, 10–20× faster edits at 1M rows and `localeText` for every string. See the release table above and [CHANGELOG.md](../CHANGELOG.md).
|
|
159
|
+
|
|
139
160
|
### 3.x releases *(2026-09-29 → 2026-10-01)*
|
|
140
161
|
- **3.0.0** correctness release (rows never modified, typed generics, React 18 support), **3.0.1** fill-height layout fix, **3.1.0** `sortComparator` and column auto-size, **3.2.0** non-blocking PDF export, **3.2.1** Safari boolean editor fix, **3.2.2** linear-time export regexes. Details in [CHANGELOG.md](../CHANGELOG.md); upgrade guide in [migration/v2-to-v3.md](migration/v2-to-v3.md).
|
|
141
162
|
- Package smoke suite against the packed tarball in React 18 and 19 apps, pull-request CI, community files and a wiki generated from these docs.
|
|
@@ -158,5 +179,5 @@ This document tracks the current status of features in `OpenGridX` and outlines
|
|
|
158
179
|
- **Core hook tests**: `useGridRowPipeline`, `useGridControlledState`, `useGridKeyboardNavigation` now have full test coverage (25 new tests).
|
|
159
180
|
- **`CLAUDE.md`**: Root-level AI context file auto-loaded by Claude Code and other AI coding assistants.
|
|
160
181
|
|
|
161
|
-
* **Demo app
|
|
182
|
+
* **Demo app**: 56 pages in 13 categories ordered by what developers look for first (3.9), a per-page table of contents, the source viewer on every example, and public deployment on GitHub Pages with a smoke test of every route. Syntax highlighting is still open.
|
|
162
183
|
* **Quickstart & Installation Guides**: Comprehensive onboarding documentation for developers.
|
|
@@ -3,6 +3,7 @@ import type { GridAiAssistantPanelProps } from '../../types';
|
|
|
3
3
|
import { Button } from '../ui/Button';
|
|
4
4
|
import { Input } from '../ui/Input';
|
|
5
5
|
import { useSpeechInput } from './useSpeechInput';
|
|
6
|
+
import { useGridLocale } from '../DataGrid/gridLocaleContext';
|
|
6
7
|
|
|
7
8
|
/** The sparkle of the Ask AI button and the panel title. */
|
|
8
9
|
export function AiSparkleIcon() {
|
|
@@ -33,6 +34,7 @@ export function GridAiAssistantPanel(props: GridAiAssistantPanelProps) {
|
|
|
33
34
|
status, statusText, message, errors, chips, history, suggestions, placeholder, voiceAvailable, canUndo,
|
|
34
35
|
submit, stop, undo, removeChip, close,
|
|
35
36
|
} = props;
|
|
37
|
+
const locale = useGridLocale();
|
|
36
38
|
const [text, setText] = useState('');
|
|
37
39
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
38
40
|
const speech = useSpeechInput(setText);
|
|
@@ -59,10 +61,10 @@ export function GridAiAssistantPanel(props: GridAiAssistantPanelProps) {
|
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
return (
|
|
62
|
-
<div className="ogx-ai-panel" role="dialog" aria-label=
|
|
64
|
+
<div className="ogx-ai-panel" role="dialog" aria-label={locale.aiAssistantTitle}>
|
|
63
65
|
<div className="ogx-ai-panel__header">
|
|
64
|
-
<span className="ogx-ai-panel__title"><AiSparkleIcon />
|
|
65
|
-
<Button size="small" className="ogx-ai-panel__close" aria-label=
|
|
66
|
+
<span className="ogx-ai-panel__title"><AiSparkleIcon />{locale.aiAssistantTitle}</span>
|
|
67
|
+
<Button size="small" className="ogx-ai-panel__close" aria-label={locale.aiAssistantClose} onClick={close}>×</Button>
|
|
66
68
|
</div>
|
|
67
69
|
|
|
68
70
|
<form className="ogx-ai-panel__form" onSubmit={handleSubmit}>
|
|
@@ -71,7 +73,7 @@ export function GridAiAssistantPanel(props: GridAiAssistantPanelProps) {
|
|
|
71
73
|
className="ogx-ai-panel__input"
|
|
72
74
|
value={text}
|
|
73
75
|
placeholder={placeholder}
|
|
74
|
-
aria-label=
|
|
76
|
+
aria-label={locale.aiAssistantPromptLabel}
|
|
75
77
|
autoComplete="off"
|
|
76
78
|
onChange={(event) => setText(event.target.value)}
|
|
77
79
|
/>
|
|
@@ -80,7 +82,7 @@ export function GridAiAssistantPanel(props: GridAiAssistantPanelProps) {
|
|
|
80
82
|
size="small"
|
|
81
83
|
variant="outlined"
|
|
82
84
|
className={`ogx-ai-panel__mic${speech.listening ? ' ogx-ai-panel__mic--on' : ''}`}
|
|
83
|
-
aria-label={speech.listening ?
|
|
85
|
+
aria-label={speech.listening ? locale.aiAssistantStopDictation : locale.aiAssistantStartDictation}
|
|
84
86
|
aria-pressed={speech.listening}
|
|
85
87
|
onClick={speech.toggle}
|
|
86
88
|
>
|
|
@@ -89,12 +91,12 @@ export function GridAiAssistantPanel(props: GridAiAssistantPanelProps) {
|
|
|
89
91
|
)}
|
|
90
92
|
{/* Separate keys: one reused <button> would turn into the submit button during the Stop click and submit again. */}
|
|
91
93
|
{running
|
|
92
|
-
? <Button key="stop" size="small" variant="outlined" onClick={thenFocusInput(stop)}>
|
|
93
|
-
: <Button key="ask" size="small" variant="contained" color="primary" type="submit" disabled={text.trim() === ''}>
|
|
94
|
+
? <Button key="stop" size="small" variant="outlined" onClick={thenFocusInput(stop)}>{locale.aiAssistantStop}</Button>
|
|
95
|
+
: <Button key="ask" size="small" variant="contained" color="primary" type="submit" disabled={text.trim() === ''}>{locale.aiAssistantAsk}</Button>}
|
|
94
96
|
</form>
|
|
95
97
|
|
|
96
98
|
{suggestions.length > 0 && (
|
|
97
|
-
<div className="ogx-ai-panel__suggestions" aria-label=
|
|
99
|
+
<div className="ogx-ai-panel__suggestions" aria-label={locale.aiAssistantSuggestions} role="group">
|
|
98
100
|
{suggestions.map((suggestion) => (
|
|
99
101
|
<button key={suggestion} type="button" className="ogx-ai-panel__suggestion" disabled={running} onClick={() => send(suggestion)}>
|
|
100
102
|
{suggestion}
|
|
@@ -108,29 +110,29 @@ export function GridAiAssistantPanel(props: GridAiAssistantPanelProps) {
|
|
|
108
110
|
|
|
109
111
|
{(chips.length > 0 || canUndo) && (
|
|
110
112
|
<div className="ogx-ai-panel__changes">
|
|
111
|
-
<ul className="ogx-ai-panel__chips" aria-label=
|
|
113
|
+
<ul className="ogx-ai-panel__chips" aria-label={locale.aiAssistantAppliedChanges}>
|
|
112
114
|
{chips.map((chip) => (
|
|
113
115
|
<li key={chip.id} className="ogx-ai-chip" data-part={chip.part}>
|
|
114
116
|
<span className="ogx-ai-chip__label">{chip.label}</span>
|
|
115
|
-
<button type="button" className="ogx-ai-chip__remove" aria-label={
|
|
117
|
+
<button type="button" className="ogx-ai-chip__remove" aria-label={locale.aiAssistantRemoveChange(chip.label)} onClick={thenFocusInput(() => removeChip(chip.id))}>×</button>
|
|
116
118
|
</li>
|
|
117
119
|
))}
|
|
118
120
|
</ul>
|
|
119
|
-
{canUndo && <Button size="small" variant="outlined" className="ogx-ai-panel__undo" onClick={thenFocusInput(undo)}>
|
|
121
|
+
{canUndo && <Button size="small" variant="outlined" className="ogx-ai-panel__undo" onClick={thenFocusInput(undo)}>{locale.aiAssistantUndo}</Button>}
|
|
120
122
|
</div>
|
|
121
123
|
)}
|
|
122
124
|
|
|
123
125
|
{errors.length > 0 && (
|
|
124
|
-
<ul className="ogx-ai-panel__errors" aria-label=
|
|
126
|
+
<ul className="ogx-ai-panel__errors" aria-label={locale.aiAssistantIgnored}>
|
|
125
127
|
{errors.map((error, i) => (
|
|
126
|
-
<li key={`${error.path}:${i}`}>{error.path ?
|
|
128
|
+
<li key={`${error.path}:${i}`}>{error.path ? locale.aiAssistantIgnoredItem(error.message) : error.message}</li>
|
|
127
129
|
))}
|
|
128
130
|
</ul>
|
|
129
131
|
)}
|
|
130
132
|
|
|
131
133
|
{history.length > 0 && (
|
|
132
134
|
<div className="ogx-ai-panel__history">
|
|
133
|
-
<div className="ogx-ai-panel__history-title">
|
|
135
|
+
<div className="ogx-ai-panel__history-title">{locale.aiAssistantEarlier}</div>
|
|
134
136
|
<ul>
|
|
135
137
|
{history.map((entry, i) => (
|
|
136
138
|
<li key={`${i}:${entry.prompt}`}>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { useGridLocale } from '../DataGrid/gridLocaleContext';
|
|
2
3
|
|
|
3
4
|
// Must live at module scope (not inline) so React sees a stable component type.
|
|
4
5
|
// Calling renderFn() here puts the throw one level BELOW CellErrorBoundary,
|
|
@@ -10,6 +11,21 @@ function CellRenderTarget({ renderFn }: { renderFn: () => React.ReactNode }) {
|
|
|
10
11
|
return <>{renderFn()}</>;
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
/** The cell content after `renderCell` threw: a warning sign labelled with the field. */
|
|
15
|
+
function CellErrorMarker({ field, message }: { field: string; message: string | undefined }) {
|
|
16
|
+
const locale = useGridLocale();
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className="ogx__cell-error"
|
|
20
|
+
role="img"
|
|
21
|
+
aria-label={locale.cellErrorLabel(field)}
|
|
22
|
+
title={message ?? locale.cellErrorTooltip}
|
|
23
|
+
>
|
|
24
|
+
⚠
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
13
29
|
interface CellErrorBoundaryProps {
|
|
14
30
|
renderFn: () => React.ReactNode;
|
|
15
31
|
field: string;
|
|
@@ -59,16 +75,7 @@ export class CellErrorBoundary extends React.Component<CellErrorBoundaryProps, C
|
|
|
59
75
|
|
|
60
76
|
override render() {
|
|
61
77
|
if (this.state.hasError) {
|
|
62
|
-
return
|
|
63
|
-
<div
|
|
64
|
-
className="ogx__cell-error"
|
|
65
|
-
role="img"
|
|
66
|
-
aria-label={`Error in cell: ${this.props.field}`}
|
|
67
|
-
title={this.state.error?.message ?? 'Render error'}
|
|
68
|
-
>
|
|
69
|
-
⚠
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
78
|
+
return <CellErrorMarker field={this.props.field} message={this.state.error?.message} />;
|
|
72
79
|
}
|
|
73
80
|
return <CellRenderTarget renderFn={this.props.renderFn} />;
|
|
74
81
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { formatAggregationValue } from '../../utils/aggregation';
|
|
2
2
|
import type { GridCellSelectionStatsSlotProps } from '../../types';
|
|
3
|
+
import { useGridLocale } from '../DataGrid/gridLocaleContext';
|
|
3
4
|
|
|
4
5
|
export type CellSelectionStatsProps = GridCellSelectionStatsSlotProps & Record<string, unknown>;
|
|
5
6
|
|
|
@@ -9,21 +10,22 @@ export type CellSelectionStatsProps = GridCellSelectionStatsSlotProps & Record<s
|
|
|
9
10
|
* @since v3.3
|
|
10
11
|
*/
|
|
11
12
|
export function CellSelectionStats({ count, sum, average }: CellSelectionStatsProps) {
|
|
13
|
+
const locale = useGridLocale();
|
|
12
14
|
return (
|
|
13
15
|
<div className="ogx__cell-selection-stats">
|
|
14
16
|
<span className="ogx__cell-selection-stat">
|
|
15
|
-
<span className="ogx__cell-selection-stat-label">
|
|
17
|
+
<span className="ogx__cell-selection-stat-label">{locale.cellSelectionStatsCount}</span>
|
|
16
18
|
<span className="ogx__cell-selection-stat-value" data-stat="count">{count.toLocaleString()}</span>
|
|
17
19
|
</span>
|
|
18
20
|
{sum !== null && (
|
|
19
21
|
<span className="ogx__cell-selection-stat">
|
|
20
|
-
<span className="ogx__cell-selection-stat-label">
|
|
22
|
+
<span className="ogx__cell-selection-stat-label">{locale.cellSelectionStatsSum}</span>
|
|
21
23
|
<span className="ogx__cell-selection-stat-value" data-stat="sum">{formatAggregationValue(sum, 'sum')}</span>
|
|
22
24
|
</span>
|
|
23
25
|
)}
|
|
24
26
|
{average !== null && (
|
|
25
27
|
<span className="ogx__cell-selection-stat">
|
|
26
|
-
<span className="ogx__cell-selection-stat-label">
|
|
28
|
+
<span className="ogx__cell-selection-stat-label">{locale.cellSelectionStatsAverage}</span>
|
|
27
29
|
<span className="ogx__cell-selection-stat-value" data-stat="average">{formatAggregationValue(average, 'avg')}</span>
|
|
28
30
|
</span>
|
|
29
31
|
)}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { clampResizeWidth } from './clampResizeWidth';
|
|
3
3
|
import { isRtl, logicalArrowKey } from '../../utils/direction';
|
|
4
|
+
import { useGridLocale } from '../DataGrid/gridLocaleContext';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
export interface ColumnResizeHandleProps {
|
|
@@ -49,6 +50,7 @@ function suppressNextClick(): void {
|
|
|
49
50
|
|
|
50
51
|
export function ColumnResizeHandle(props: ColumnResizeHandleProps) {
|
|
51
52
|
const { field, currentWidth, onResize, onAutosize, minWidth, maxWidth, edge = 'end' } = props;
|
|
53
|
+
const locale = useGridLocale();
|
|
52
54
|
const [isDragging, setIsDragging] = useState(false);
|
|
53
55
|
const activeRef = useRef<ActiveResize | null>(null);
|
|
54
56
|
|
|
@@ -164,7 +166,7 @@ export function ColumnResizeHandle(props: ColumnResizeHandleProps) {
|
|
|
164
166
|
onKeyDown={handleKeyDown}
|
|
165
167
|
role="separator"
|
|
166
168
|
aria-orientation="vertical"
|
|
167
|
-
aria-label={
|
|
169
|
+
aria-label={locale.headerColumnResizeLabel(field)}
|
|
168
170
|
aria-valuenow={Math.round(currentWidth)}
|
|
169
171
|
aria-valuemin={Math.round(Math.min(minWidth ?? 50, currentWidth))}
|
|
170
172
|
aria-valuemax={maxWidth}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, useMemo, useRef, useId } from 'react';
|
|
2
2
|
import { Checkbox } from '../ui/Checkbox';
|
|
3
3
|
import { Input } from '../ui/Input';
|
|
4
|
+
import { useGridLocale } from '../DataGrid/gridLocaleContext';
|
|
4
5
|
import type { GridColDef, GridRowModel, GridValidRowModel } from '../../types';
|
|
5
6
|
|
|
6
7
|
|
|
@@ -48,6 +49,7 @@ export function ColumnVisibilityPanel<R extends GridValidRowModel = GridRowModel
|
|
|
48
49
|
props: ColumnVisibilityPanelProps<R>
|
|
49
50
|
) {
|
|
50
51
|
const { columns, visibleColumns, onVisibilityChange, onShowAll, onHideAll, onColumnReorder, onColumnOrderReset, showNonHideableColumns } = props;
|
|
52
|
+
const locale = useGridLocale();
|
|
51
53
|
const [searchQuery, setSearchQuery] = useState('');
|
|
52
54
|
// Each checkbox is named by a <label htmlFor> holding the column name. (Wrapping Checkbox,
|
|
53
55
|
// which renders its own <label>, in another <label> nested labels and left the name to a
|
|
@@ -119,7 +121,7 @@ export function ColumnVisibilityPanel<R extends GridValidRowModel = GridRowModel
|
|
|
119
121
|
<Input
|
|
120
122
|
autoComplete="off"
|
|
121
123
|
inputClassName="ogx-column-visibility-panel__search-input"
|
|
122
|
-
placeholder=
|
|
124
|
+
placeholder={locale.columnsPanelSearchPlaceholder}
|
|
123
125
|
value={searchQuery}
|
|
124
126
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
125
127
|
/>
|
|
@@ -153,7 +155,7 @@ export function ColumnVisibilityPanel<R extends GridValidRowModel = GridRowModel
|
|
|
153
155
|
className="ogx-column-visibility-panel__drag-handle-wrapper"
|
|
154
156
|
draggable
|
|
155
157
|
onDragStart={handleDragStart(col.field)}
|
|
156
|
-
title=
|
|
158
|
+
title={locale.columnsPanelDragToReorder}
|
|
157
159
|
>
|
|
158
160
|
<DragHandleIcon />
|
|
159
161
|
</span>
|
|
@@ -185,7 +187,7 @@ export function ColumnVisibilityPanel<R extends GridValidRowModel = GridRowModel
|
|
|
185
187
|
onChange={handleToggleAll}
|
|
186
188
|
/>
|
|
187
189
|
<label htmlFor={`${idBase}-all`} className="ogx-column-visibility-panel__label">
|
|
188
|
-
|
|
190
|
+
{locale.columnsPanelShowHideAll}
|
|
189
191
|
</label>
|
|
190
192
|
</div>
|
|
191
193
|
<button
|
|
@@ -193,7 +195,7 @@ export function ColumnVisibilityPanel<R extends GridValidRowModel = GridRowModel
|
|
|
193
195
|
className="ogx-column-visibility-panel__reset-btn"
|
|
194
196
|
onClick={() => { onShowAll(); onColumnOrderReset?.(); }}
|
|
195
197
|
>
|
|
196
|
-
|
|
198
|
+
{locale.columnsPanelReset}
|
|
197
199
|
</button>
|
|
198
200
|
</div>
|
|
199
201
|
</div>
|
|
@@ -3,6 +3,7 @@ import { formatAggregateForColumn, isAggregationAllowed } from '../../utils/aggr
|
|
|
3
3
|
import type { GridColDef, GridAggregationModel, GridAggregationResult, GridColumnPinning } from '../../types';
|
|
4
4
|
import { calculatePinnedPositions, getPinnedEdgeFields, isColumnPinned } from '../../utils/pinning';
|
|
5
5
|
import { getRenderedColumnWidth } from '../../utils/columnWidth';
|
|
6
|
+
import { useGridLocale } from './gridLocaleContext';
|
|
6
7
|
|
|
7
8
|
const SYSTEM_COLUMN_WIDTH = 48;
|
|
8
9
|
|
|
@@ -41,6 +42,7 @@ export function GridAggregationFooter({
|
|
|
41
42
|
pinnedColumns,
|
|
42
43
|
loading = false,
|
|
43
44
|
}: GridAggregationFooterProps) {
|
|
45
|
+
const locale = useGridLocale();
|
|
44
46
|
// Same offsets as Row, so pinned totals sit exactly under their pinned body cells.
|
|
45
47
|
const pinnedOffsets = useMemo(
|
|
46
48
|
() => calculatePinnedPositions(
|
|
@@ -77,7 +79,7 @@ export function GridAggregationFooter({
|
|
|
77
79
|
<div
|
|
78
80
|
className={`ogx__aggregation-footer${loading ? ' ogx__aggregation-footer--loading' : ''}`}
|
|
79
81
|
role="row"
|
|
80
|
-
aria-label=
|
|
82
|
+
aria-label={locale.aggregationFooterLabel}
|
|
81
83
|
aria-live="polite"
|
|
82
84
|
aria-busy={loading || undefined}
|
|
83
85
|
style={{ minHeight: `${rowHeight}px` }}
|