@opencorestack/opengridx 2.0.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +408 -3
- package/README.md +93 -72
- package/dist/index.d.ts +611 -121
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7992 -5650
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +17 -23
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +348 -161
- package/docs/README.md +6 -1
- package/docs/architecture/datagrid-orchestration.md +81 -0
- package/docs/architecture/grid-row-meta.md +102 -0
- package/docs/architecture/use-grid-columns.md +128 -0
- package/docs/architecture/use-grid-controlled-state.md +157 -0
- package/docs/architecture/use-grid-row-pipeline.md +120 -0
- package/docs/architecture/use-grid-scroll-sync.md +111 -0
- package/docs/architecture/use-grid-state-snapshot.md +90 -0
- package/docs/architecture/use-grid-virtualization.md +115 -0
- package/docs/architecture/use-grid-visible-rows.md +85 -0
- package/docs/assets/banner-alt.png +0 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/hero.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/components/aggregation-footer.md +15 -10
- package/docs/components/cell.md +16 -6
- package/docs/components/column-group-header.md +55 -28
- package/docs/components/column-resize.md +17 -13
- package/docs/components/column-visibility.md +45 -22
- package/docs/components/datagrid.md +14 -12
- package/docs/components/empty-state.md +2 -1
- package/docs/components/error-overlay.md +12 -7
- package/docs/components/filter-panel.md +28 -8
- package/docs/components/header.md +28 -9
- package/docs/components/pagination.md +14 -8
- package/docs/components/row.md +21 -5
- package/docs/components/toolbar.md +27 -9
- package/docs/components/tooltip.md +16 -7
- package/docs/customization/slots-api.md +100 -36
- package/docs/customization/theming.md +66 -18
- package/docs/features/aggregation-pivot.md +75 -9
- package/docs/features/cell-spanning.md +80 -125
- package/docs/features/clipboard.md +41 -16
- package/docs/features/custom-pagination.md +38 -18
- package/docs/features/data-source.md +36 -13
- package/docs/features/editing-reordering.md +125 -16
- package/docs/features/export-guide.md +147 -41
- package/docs/features/filtering.md +44 -6
- package/docs/features/infinite-scroll.md +54 -46
- package/docs/features/keyboard-navigation.md +83 -0
- package/docs/features/list-view.md +58 -5
- package/docs/features/loading-states.md +18 -20
- package/docs/features/master-detail.md +18 -5
- package/docs/features/pdf-export.md +56 -19
- package/docs/features/pinning.md +23 -5
- package/docs/features/selection.md +50 -10
- package/docs/features/sorting-pagination.md +66 -14
- package/docs/features/state-persistence.md +78 -10
- package/docs/features/toolbar-customization.md +26 -17
- package/docs/features/tree-data-grouping.md +44 -9
- package/docs/features/virtualization.md +64 -15
- package/docs/migration/v1-to-v2.md +115 -0
- package/docs/migration/v2-to-v3.md +1222 -0
- package/docs/performance.md +124 -0
- package/docs/roadmap.md +16 -10
- package/lib/components/Cell/Cell.css +13 -1
- package/lib/components/Cell/Cell.tsx +130 -57
- package/lib/components/Cell/CellErrorBoundary.tsx +12 -6
- package/lib/components/Cell/GridEditInputCell.tsx +114 -41
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +7 -1
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +11 -0
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +104 -38
- package/lib/components/ColumnResizeHandle/clampResizeWidth.ts +13 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +6 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +21 -13
- package/lib/components/DataGrid/DataGrid.css +84 -12
- package/lib/components/DataGrid/DataGrid.tsx +606 -872
- package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
- package/lib/components/DataGrid/GridEmptyState.tsx +7 -1
- package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
- package/lib/components/DataGrid/GridListView.tsx +166 -23
- package/lib/components/DataGrid/GridLiveRegion.tsx +31 -0
- package/lib/components/DataGrid/GridLoadingOverlay.tsx +27 -0
- package/lib/components/DataGrid/GridPaginationArea.tsx +44 -0
- package/lib/components/DataGrid/GridPinnedRows.tsx +65 -11
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
- package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
- package/lib/components/DataGrid/GridVirtualRows.tsx +48 -25
- package/lib/components/DetailPanel/DetailPanel.css +0 -6
- package/lib/components/DetailPanel/DetailPanel.tsx +34 -5
- package/lib/components/DetailPanel/DetailPanelContent.tsx +17 -0
- package/lib/components/FilterPanel/FilterPanel.css +13 -2
- package/lib/components/FilterPanel/FilterPanel.tsx +272 -99
- package/lib/components/Header/ColumnMenu.tsx +91 -39
- package/lib/components/Header/Header.css +3 -3
- package/lib/components/Header/Header.tsx +179 -160
- package/lib/components/ListView/ListView.css +25 -0
- package/lib/components/ListView/ListViewRow.tsx +79 -10
- package/lib/components/Pagination/Pagination.tsx +15 -7
- package/lib/components/Row/Row.tsx +185 -75
- package/lib/components/Toolbar/GlobalSearch.css +6 -3
- package/lib/components/Toolbar/GlobalSearch.tsx +26 -27
- package/lib/components/Toolbar/GridToolbar.css +12 -11
- package/lib/components/Toolbar/GridToolbar.tsx +133 -89
- package/lib/components/Toolbar/PivotPanel.tsx +89 -49
- package/lib/components/Tooltip/Tooltip.css +20 -0
- package/lib/components/Tooltip/Tooltip.tsx +68 -35
- package/lib/components/ui/Button.tsx +3 -0
- package/lib/components/ui/Checkbox.tsx +2 -1
- package/lib/components/ui/ExpandIcon.css +0 -9
- package/lib/components/ui/ExpandIcon.tsx +4 -1
- package/lib/hooks/core/gridApiPlaceholder.ts +34 -0
- package/lib/hooks/core/gridToolbarHostContext.ts +14 -0
- package/lib/hooks/core/useDataGrid.ts +115 -173
- package/lib/hooks/core/useGridAggregationApi.ts +72 -0
- package/lib/hooks/core/useGridApiMethods.ts +115 -0
- package/lib/hooks/core/useGridApiRef.ts +15 -3
- package/lib/hooks/core/useGridApiRefBinding.ts +18 -0
- package/lib/hooks/core/useGridAriaRows.ts +38 -0
- package/lib/hooks/core/useGridClipboardApi.ts +38 -0
- package/lib/hooks/core/useGridColumnLookup.ts +30 -0
- package/lib/hooks/core/useGridColumns.tsx +284 -76
- package/lib/hooks/core/useGridColumnsPanel.ts +77 -0
- package/lib/hooks/core/useGridControlledState.ts +99 -6
- package/lib/hooks/core/useGridDetailPanel.ts +51 -0
- package/lib/hooks/core/useGridDevWarnings.ts +123 -0
- package/lib/hooks/core/useGridFocusHandlers.ts +50 -0
- package/lib/hooks/core/useGridGroupingColumn.ts +62 -0
- package/lib/hooks/core/useGridHeaderHandlers.ts +92 -0
- package/lib/hooks/core/useGridHierarchy.ts +81 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +452 -250
- package/lib/hooks/core/useGridLiveRowSelection.ts +67 -0
- package/lib/hooks/core/useGridPageCorrection.ts +55 -0
- package/lib/hooks/core/useGridRowIdOf.ts +32 -0
- package/lib/hooks/core/useGridRowInteractions.ts +81 -0
- package/lib/hooks/core/useGridRowPipeline.ts +69 -39
- package/lib/hooks/core/useGridRowSelection.ts +91 -0
- package/lib/hooks/core/useGridScrollSync.ts +80 -32
- package/lib/hooks/core/useGridScrollToIndexesApi.ts +45 -0
- package/lib/hooks/core/useGridStateSnapshot.ts +40 -5
- package/lib/hooks/core/useGridThemeDimensions.ts +49 -0
- package/lib/hooks/core/useGridToolbarProps.ts +97 -0
- package/lib/hooks/core/useGridViewport.ts +38 -0
- package/lib/hooks/core/useGridViewportSize.ts +26 -0
- package/lib/hooks/core/useGridVisibleRows.ts +20 -7
- package/lib/hooks/core/useLayout.ts +215 -195
- package/lib/hooks/core/useRowsScrollEndLatch.ts +41 -0
- package/lib/hooks/core/useStableColumns.ts +34 -0
- package/lib/hooks/features/useAggregation.ts +86 -90
- package/lib/hooks/features/useColumnGroupReorderGuard.ts +34 -0
- package/lib/hooks/features/useDetailPanelHeights.ts +29 -0
- package/lib/hooks/features/useGridClipboard.ts +133 -73
- package/lib/hooks/features/useGridDataSource.ts +354 -128
- package/lib/hooks/features/useGridEditing.ts +211 -51
- package/lib/hooks/features/useGridPivot.ts +92 -0
- package/lib/hooks/features/useGridSpanRenderWindow.ts +104 -0
- package/lib/hooks/features/useGridSpanning.ts +410 -306
- package/lib/hooks/features/usePivot.ts +0 -0
- package/lib/hooks/features/useServerTreeChildren.ts +50 -0
- package/lib/hooks/useColumnReorder.ts +38 -44
- package/lib/hooks/useRowGrouping.ts +335 -214
- package/lib/hooks/useRowReorder.ts +62 -31
- package/lib/hooks/useTreeData.ts +330 -262
- package/lib/index.ts +30 -2
- package/lib/state/index.ts +1 -0
- package/lib/state/types.ts +7 -1
- package/lib/state/useGridStateStorage.ts +88 -29
- package/lib/theme/DataGridThemeProvider.tsx +143 -38
- package/lib/theme/gridThemeContext.ts +5 -0
- package/lib/theme/index.ts +5 -0
- package/lib/theme/presets.ts +5 -4
- package/lib/theme/types.ts +40 -2
- package/lib/types/index.ts +311 -108
- package/lib/utils/aggregation/index.ts +157 -0
- package/lib/utils/aria/index.ts +40 -0
- package/lib/utils/columnGroups.ts +110 -0
- package/lib/utils/columnLookup.ts +33 -0
- package/lib/utils/columnWidth.ts +22 -0
- package/lib/utils/dataSource/index.ts +46 -0
- package/lib/utils/detailPanel.ts +66 -0
- package/lib/utils/dragData.ts +44 -0
- package/lib/utils/editing/index.ts +30 -0
- package/lib/utils/export/exportShared.ts +197 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +344 -121
- package/lib/utils/export/exportToPdf.ts +143 -92
- package/lib/utils/export/groupLabel.ts +14 -0
- package/lib/utils/export/index.ts +278 -272
- package/lib/utils/export/pdfText.ts +50 -0
- package/lib/utils/filtering/index.ts +277 -148
- package/lib/utils/focus/index.ts +115 -0
- package/lib/utils/gridApiRows.ts +35 -0
- package/lib/utils/gridModes.ts +77 -0
- package/lib/utils/grouping/groupedExportRows.ts +91 -0
- package/lib/utils/pagination/index.ts +56 -0
- package/lib/utils/pinning/index.ts +77 -33
- package/lib/utils/pivot/index.ts +368 -0
- package/lib/utils/scroll/index.ts +78 -0
- package/lib/utils/scroll/scrollEnd.ts +18 -0
- package/lib/utils/sorting/index.ts +154 -30
- package/lib/utils/syntheticRows.ts +12 -0
- package/lib/utils/values.ts +206 -0
- package/lib/utils/viewport.ts +14 -0
- package/llms.txt +272 -166
- package/package.json +18 -6
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
- package/lib/components/DataGrid/DataGrid.regression.test.tsx +0 -132
- package/lib/components/DataGrid/DataGrid.smoke.test.tsx +0 -58
- package/lib/components/DataGrid/DataGrid.v2.test.tsx +0 -127
- package/lib/components/Header/Header.test.tsx +0 -135
- package/lib/components/Pagination/Pagination.test.tsx +0 -64
- package/lib/hooks/core/useDataGrid.regression.test.ts +0 -66
- package/lib/hooks/core/useGridControlledState.test.ts +0 -86
- package/lib/hooks/core/useGridKeyboardNavigation.test.ts +0 -176
- package/lib/hooks/core/useGridRowPipeline.test.ts +0 -117
- package/lib/hooks/features/useAggregation.test.ts +0 -175
- package/lib/hooks/features/usePivot.test.ts +0 -202
- package/lib/hooks/useRowGrouping.test.ts +0 -137
- package/lib/utils/export/exportToPdf.test.ts +0 -120
- package/lib/utils/export/groupedExport.test.ts +0 -144
- package/lib/utils/filtering/filtering.test.ts +0 -178
- package/lib/utils/sorting/sorting.test.ts +0 -88
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# 🌐 Server-Side Data Source
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Connect OpenGridX to your backend API so the server does the sorting, filtering and paging.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## 📑 The `GridDataSource` Interface
|
|
8
8
|
|
|
9
|
-
The `dataSource` prop is the gateway to server-side operations.
|
|
9
|
+
The `dataSource` prop is the gateway to server-side operations. The grid calls `getRows` with a row range and the current sort, filter and aggregation models, and shows the rows it returns. Requests are page-based (see *Modes of Operation*), not driven by the scroll position.
|
|
10
10
|
|
|
11
11
|
### Implementation
|
|
12
12
|
```tsx
|
|
13
|
+
import { DataGrid, type GridDataSource } from '@opencorestack/opengridx';
|
|
14
|
+
|
|
13
15
|
const myDataSource: GridDataSource = {
|
|
14
16
|
getRows: async (params) => {
|
|
15
17
|
const { startRow, endRow, sortModel, filterModel } = params;
|
|
@@ -23,12 +25,20 @@ const myDataSource: GridDataSource = {
|
|
|
23
25
|
|
|
24
26
|
return {
|
|
25
27
|
rows: data.items,
|
|
26
|
-
rowCount: data.totalCount //
|
|
28
|
+
rowCount: data.totalCount // the total, used by the pager with paginationMode="server"
|
|
27
29
|
};
|
|
28
30
|
}
|
|
29
31
|
};
|
|
30
32
|
|
|
31
|
-
<DataGrid
|
|
33
|
+
<DataGrid
|
|
34
|
+
rows={[]}
|
|
35
|
+
columns={columns}
|
|
36
|
+
dataSource={myDataSource}
|
|
37
|
+
pagination
|
|
38
|
+
paginationMode="server"
|
|
39
|
+
sortingMode="server"
|
|
40
|
+
filterMode="server"
|
|
41
|
+
/>
|
|
32
42
|
```
|
|
33
43
|
|
|
34
44
|
---
|
|
@@ -38,28 +48,41 @@ const myDataSource: GridDataSource = {
|
|
|
38
48
|
| Parameter | Type | Description |
|
|
39
49
|
| :--- | :--- | :--- |
|
|
40
50
|
| `startRow` | `number` | The starting index of the requested range. |
|
|
41
|
-
| `endRow` | `number` | The ending index (exclusive). |
|
|
51
|
+
| `endRow` | `number` | The ending index (exclusive): return `rows.slice(startRow, endRow)`. `Number.MAX_SAFE_INTEGER` means "every row". |
|
|
42
52
|
| `sortModel` | `GridSortItem[]` | Current sorting configuration. |
|
|
43
53
|
| `filterModel` | `GridFilterModel` | Current filtering configuration. |
|
|
44
|
-
| `groupKeys` | `string[]` |
|
|
54
|
+
| `groupKeys` | `string[]` | Path of the parent whose children are requested (server-side tree data); empty for top-level rows. |
|
|
55
|
+
| `aggregationModel` | `GridAggregationModel \| undefined` | Current aggregation configuration, so the server can return `aggregationResults`. |
|
|
45
56
|
|
|
46
57
|
---
|
|
47
58
|
|
|
48
59
|
## 🔄 Modes of Operation
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
The grid calls `getRows` whenever a `dataSource` is set. Rapid changes are collapsed into one request (300 ms debounce); the loading state shows from the moment a request is scheduled. Rows are keyed with `getRowId`.
|
|
62
|
+
|
|
63
|
+
### 1. Client Pagination (default)
|
|
64
|
+
With `paginationMode="client"` (the default) the grid requests every row once (`startRow: 0`, `endRow: Number.MAX_SAFE_INTEGER`) and pages them itself. With `sortingMode="server"` or `filterMode="server"` a sort or filter change requests every row again with the new model; client-side sorts and filters, and page changes, never refetch.
|
|
65
|
+
|
|
66
|
+
### 2. Server-Side Pagination
|
|
67
|
+
Set `paginationMode="server"`. Each page change requests `[page * pageSize, (page + 1) * pageSize)` and the response replaces the rows. Return `rowCount` so the pager knows the total.
|
|
52
68
|
|
|
53
|
-
|
|
54
|
-
Set `paginationMode="infinite"`. The grid will request the next "chunk" of data as the user scrolls near the bottom of the list.
|
|
69
|
+
Row grouping turns pagination off (every group renders in one scrollable view). With `rowGroupingModel` set, a `paginationMode="server"` source is therefore asked for every row (`startRow: 0`, `endRow: Number.MAX_SAFE_INTEGER`) instead of the first page, and a development warning says so (v3.0+; before, only the first page was requested and the rest were unreachable).
|
|
55
70
|
|
|
56
|
-
### 3.
|
|
57
|
-
|
|
71
|
+
### 3. Infinite Loading
|
|
72
|
+
Set `paginationMode="infinite"` and advance `paginationModel.page` (for example from `onRowsScrollEnd`). The grid requests the rows from the end of what is loaded up to the current page and appends them, so a page that moves on while a request is in flight never leaves a gap. See [Infinite Scroll](infinite-scroll.md).
|
|
73
|
+
|
|
74
|
+
### 4. Server-Side Tree Data
|
|
75
|
+
When `treeData` is enabled with a `dataSource`, top-level rows come from the normal request. A row with `serverChildrenCount > 0` shows an expand toggle; expanding it calls `getRows` with that row's path in `groupKeys` (and `startRow: 0`, `endRow: Number.MAX_SAFE_INTEGER`). Return that parent's children. With `filterMode="server"` / `sortingMode="server"` the returned rows are neither re-filtered nor re-sorted in the tree. When a refetch replaces the rows (page, sort, filter), the children of nodes that are still expanded are requested again. If a children request fails, the node collapses again and the error is logged; expanding it retries. (It does not show the grid-level error overlay.) `defaultGroupingExpansionDepth` counts a node with `serverChildrenCount > 0` as expandable, so the nodes within that depth (all of them with `-1`) start expanded and their children are requested right away (v3.0+; before, lazy nodes were never expanded by the default depth).
|
|
76
|
+
|
|
77
|
+
### When a refetch happens
|
|
78
|
+
Models are compared by content, so an inline `filterModel={{ items: [] }}` or a `dataSource={{ getRows }}` object recreated with the same `getRows` function does not refetch. A new `getRows` function does. A response for parameters that have changed in the meantime is discarded.
|
|
58
79
|
|
|
59
80
|
---
|
|
60
81
|
|
|
61
82
|
## 🛠️ Error Handling
|
|
62
|
-
If your API call fails,
|
|
83
|
+
If your API call fails, throw an error or return a rejected promise. OpenGridX shows the **Error Overlay** with the rejection's `message` (an `Error`, a string, or any object with a string `message`) and a **Retry** button that requests the rows again.
|
|
84
|
+
|
|
85
|
+
A response the grid cannot use fails the same way (v3.0+): a response without a `rows` array, or a `getRowId` that throws for a fetched row, shows the error overlay and ends the loading state, instead of an unhandled promise rejection and an endless "Loading". For a children request (server-side tree data) it collapses the node as a failed request does.
|
|
63
86
|
|
|
64
87
|
```typescript
|
|
65
88
|
getRows: async () => {
|
|
@@ -10,12 +10,33 @@ OpenGridX supports inline cell editing. For a column to be editable, you must se
|
|
|
10
10
|
|
|
11
11
|
### Basic Setup
|
|
12
12
|
```tsx
|
|
13
|
-
|
|
13
|
+
import type { GridColDef } from '@opencorestack/opengridx';
|
|
14
|
+
|
|
15
|
+
const columns: GridColDef[] = [
|
|
14
16
|
{ field: 'name', editable: true },
|
|
15
17
|
{ field: 'role', editable: true, type: 'singleSelect', valueOptions: ['Admin', 'Editor'] }
|
|
16
18
|
];
|
|
17
19
|
```
|
|
18
20
|
|
|
21
|
+
Double-click a cell or press **Enter** on a focused cell to open its editor.
|
|
22
|
+
|
|
23
|
+
### Which cells can be edited
|
|
24
|
+
A cell is editable when its column has `editable: true` **and**, if you pass it, `isCellEditable` returns `true`. The same rule drives double-click, Enter, the cells **Tab** stops on while editing, and `aria-readonly`.
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
<DataGrid
|
|
28
|
+
columns={columns}
|
|
29
|
+
rows={rows}
|
|
30
|
+
// Lock archived rows, whatever the column says.
|
|
31
|
+
isCellEditable={({ row }) => row.status !== 'archived'}
|
|
32
|
+
/>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- `isCellEditable` can only restrict. It cannot make a column without `editable: true` editable. If it throws, the cell is treated as read-only.
|
|
36
|
+
- Row-grouping group rows and the ancestors tree data generates for missing path segments are never editable. Tree-data **parent rows are your own rows** and are editable like any other row.
|
|
37
|
+
- Pinned rows (`pinnedRows`) are edited like any other row, with double-click or Enter (v3.0; they used to show no editor).
|
|
38
|
+
- **Enter** on a cell that is not editable does what clicking its row does (`onRowClick`, click-to-select, expanding a group). See [Keyboard & Accessibility](keyboard-navigation.md).
|
|
39
|
+
|
|
19
40
|
### Persistence
|
|
20
41
|
When a cell edit is committed, the `processRowUpdate` callback is triggered.
|
|
21
42
|
|
|
@@ -33,6 +54,82 @@ When a cell edit is committed, the `processRowUpdate` callback is triggered.
|
|
|
33
54
|
/>
|
|
34
55
|
```
|
|
35
56
|
|
|
57
|
+
`processRowUpdate` must return the row to store (or a Promise of it). The grid stores that row under the id of the row you edited, so a server response that lacks the key field (for example the `uid` read by `getRowId={r => r.uid}`) is still applied. The row is stored as returned: the grid never adds an `id` field to it (v3.0+). Returning nothing is a mistake the grid reports through `onProcessRowUpdateError` (or `console.error` in development when no handler is set); the editor stays open.
|
|
58
|
+
|
|
59
|
+
### Commit and cancel
|
|
60
|
+
|
|
61
|
+
| Action | Result |
|
|
62
|
+
| :--- | :--- |
|
|
63
|
+
| **Enter** | Commits and closes the editor. |
|
|
64
|
+
| **Tab** / **Shift+Tab** | Commits and moves to the next / previous editable cell. With no editable cell left, focus moves on out of the grid and the edit commits. Outside edit mode Tab is not captured: it leaves the grid. |
|
|
65
|
+
| Moving focus away (clicking another cell or any control outside the grid) | Commits. Focus stays where you put it. |
|
|
66
|
+
| The edited cell leaving the grid (scrolled out of the render window, filtered out, another page) | Commits, as if the editor had lost focus. |
|
|
67
|
+
| Starting an edit on another cell | Commits the current edit first. |
|
|
68
|
+
| **Escape** | Discards the pending value and closes the editor. |
|
|
69
|
+
|
|
70
|
+
Clicks and double-clicks inside an open editor stay in the editor: you can place the caret, select a word or open a dropdown. They do not fire `onCellClick`, `onRowClick` or `onRowDoubleClick`, and do not change row selection. While an IME is composing (Japanese, Chinese, Korean input), **Enter** confirms the candidate and does not commit.
|
|
71
|
+
|
|
72
|
+
`processRowUpdate` runs **once per commit**. Actions that overlap, such as pressing Enter and then clicking elsewhere while an async save is in flight, share that one call.
|
|
73
|
+
|
|
74
|
+
With an async `processRowUpdate`, the editor stays open until the Promise settles:
|
|
75
|
+
- **Resolved:** the returned row is stored and the editor closes. If the user kept typing meanwhile, the editor stays open with the newer text, which the next commit saves.
|
|
76
|
+
- **Rejected:** `onProcessRowUpdateError` receives the error and the editor stays open with the pending value, so the user can fix it or press Escape.
|
|
77
|
+
- **Escape while pending** closes the editor at once, but cannot recall the save: when it resolves, the returned row is still stored, because your `processRowUpdate` has already run.
|
|
78
|
+
- A late result never closes an edit the user has started on another cell.
|
|
79
|
+
|
|
80
|
+
### Built-in editors
|
|
81
|
+
The editor follows the column `type`, and commits values of the same type the cell held.
|
|
82
|
+
|
|
83
|
+
| `type` | Editor | Committed value |
|
|
84
|
+
| :--- | :--- | :--- |
|
|
85
|
+
| `'string'` (default) | Text input | String. |
|
|
86
|
+
| `'number'` | Number input | Number, or `null` when cleared. |
|
|
87
|
+
| `'boolean'` | Checkbox | Toggling commits immediately. |
|
|
88
|
+
| `'singleSelect'` | `<select>` over `valueOptions` | The option's own value: `{ value: 2, label: 'Closed' }` commits the number `2`, not `'2'`. When the current value is empty or not among the options, an empty choice is shown, so any option can be picked. |
|
|
89
|
+
| `'date'` | Date input | Same kind as before: a `Date` stays a `Date` (keeping its time of day), a timestamp stays a timestamp, an ISO date-time string keeps its time part. `null` when cleared. |
|
|
90
|
+
|
|
91
|
+
Every editor is labelled with the column's `headerName` (or `field`) for screen readers.
|
|
92
|
+
|
|
93
|
+
### Custom editors (`renderEditCell`)
|
|
94
|
+
`renderEditCell` receives the usual cell params, with `value` set to the pending value, plus three callbacks:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import type { GridColDef, GridRenderEditCellParams } from '@opencorestack/opengridx';
|
|
98
|
+
|
|
99
|
+
function RatingEditor({ value, onValueChange, onCommit, onCancel }: GridRenderEditCellParams) {
|
|
100
|
+
return (
|
|
101
|
+
<input
|
|
102
|
+
type="range" min={0} max={5} autoFocus
|
|
103
|
+
value={Number(value ?? 0)}
|
|
104
|
+
onChange={e => onValueChange(Number(e.target.value))}
|
|
105
|
+
onBlur={onCommit}
|
|
106
|
+
onKeyDown={e => { if (e.key === 'Escape') onCancel(); }}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const columns: GridColDef[] = [
|
|
112
|
+
{ field: 'rating', type: 'number', editable: true, renderEditCell: params => <RatingEditor {...params} /> },
|
|
113
|
+
];
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Enter and Escape keydowns that bubble out of a custom editor also commit and cancel. An error thrown by `renderEditCell` is contained to its cell (the cell shows `⚠`), like `renderCell`.
|
|
117
|
+
|
|
118
|
+
### Computed columns (`valueGetter` + `valueSetter`)
|
|
119
|
+
An editable column with a `valueGetter` edits the derived value. Give it a `valueSetter` so the commit can write the value back to the fields it comes from; otherwise the commit writes `row[field]`, which the `valueGetter` ignores, and a development warning is logged.
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
{
|
|
123
|
+
field: 'fullName',
|
|
124
|
+
editable: true,
|
|
125
|
+
valueGetter: ({ row }) => `${row.firstName} ${row.lastName}`,
|
|
126
|
+
valueSetter: ({ value, row }) => {
|
|
127
|
+
const [firstName, ...rest] = String(value).split(' ');
|
|
128
|
+
return { ...row, firstName, lastName: rest.join(' ') };
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
36
133
|
---
|
|
37
134
|
|
|
38
135
|
## ↕️ Row Reordering
|
|
@@ -45,10 +142,9 @@ Allows users to rearrange rows by dragging a handle.
|
|
|
45
142
|
|
|
46
143
|
```tsx
|
|
47
144
|
<DataGrid
|
|
145
|
+
rows={rows}
|
|
48
146
|
rowReordering={true}
|
|
49
|
-
onRowOrderChange={(
|
|
50
|
-
const { oldIndex, targetIndex } = params;
|
|
51
|
-
// Move logic
|
|
147
|
+
onRowOrderChange={({ oldIndex, targetIndex }) => {
|
|
52
148
|
const newRows = [...rows];
|
|
53
149
|
const [moved] = newRows.splice(oldIndex, 1);
|
|
54
150
|
newRows.splice(targetIndex, 0, moved);
|
|
@@ -57,8 +153,19 @@ Allows users to rearrange rows by dragging a handle.
|
|
|
57
153
|
/>
|
|
58
154
|
```
|
|
59
155
|
|
|
60
|
-
|
|
61
|
-
|
|
156
|
+
### What the indices mean
|
|
157
|
+
`oldIndex` and `targetIndex` are positions in **your `rows` prop** (v3.0+), so `rows[oldIndex] === params.row` and the splice above always moves the row that was dragged. This holds on every page, with pinned rows, and while the grid is sorted or filtered. (Before v3.0 they were positions in the visible page, which moved the wrong row in all of those cases.)
|
|
158
|
+
|
|
159
|
+
`params.row` is your own row object, also with `getRowId`.
|
|
160
|
+
|
|
161
|
+
While the grid is sorted, the new position in `rows` does not change where the row shows up: the sort decides that. Turn sorting off if the drag should visibly move the row.
|
|
162
|
+
|
|
163
|
+
### Which rows can be dragged
|
|
164
|
+
- Every data row you passed in `rows` can be dragged and dropped on.
|
|
165
|
+
- Pinned rows (`pinnedRows`) keep their place. They show an empty handle cell, so their cells line up with the header, but cannot be dragged or dropped on.
|
|
166
|
+
- Rows the grid makes itself cannot be dragged or dropped on: row-grouping group rows and the tree-data parents generated for missing path segments.
|
|
167
|
+
- While pivot mode is active, row reordering is off (no handle column): pivot rows are generated, so their positions mean nothing in `rows`. It comes back when pivoting ends.
|
|
168
|
+
- Only the grid's own row drags are accepted: dropping a file, a text selection or a header on a row does nothing.
|
|
62
169
|
|
|
63
170
|
---
|
|
64
171
|
|
|
@@ -73,26 +180,26 @@ Use the `disableColumnReorder` prop to control this feature globally.
|
|
|
73
180
|
<DataGrid disableColumnReorder={true} />
|
|
74
181
|
```
|
|
75
182
|
|
|
183
|
+
`disableColumnReorder` only removes the user's ways to reorder (header drag, Columns-panel reorder). A controlled `columnOrder` or `initialState.columns.columnOrder` still sets the order, so you can fix a custom order and stop users from changing it.
|
|
184
|
+
|
|
76
185
|
### Controlled Column Order
|
|
77
|
-
|
|
186
|
+
Manage the order yourself with `columnOrder` and `onColumnOrderModelChange`, which receives the whole new order after every change: a header drag, a drag in the Columns panel, and the panel's **Reset**.
|
|
78
187
|
|
|
79
188
|
```tsx
|
|
80
|
-
const [colOrder, setColOrder] = useState(['id', 'name', 'status']);
|
|
189
|
+
const [colOrder, setColOrder] = useState<string[]>(['id', 'name', 'status']);
|
|
81
190
|
|
|
82
191
|
<DataGrid
|
|
83
192
|
columnOrder={colOrder}
|
|
84
|
-
|
|
85
|
-
// params: { column: GridColDef, oldIndex: number, targetIndex: number }
|
|
86
|
-
const newOrder = [...colOrder];
|
|
87
|
-
const [moved] = newOrder.splice(params.oldIndex, 1);
|
|
88
|
-
newOrder.splice(params.targetIndex, 0, moved);
|
|
89
|
-
setColOrder(newOrder);
|
|
90
|
-
}}
|
|
193
|
+
onColumnOrderModelChange={setColOrder}
|
|
91
194
|
/>
|
|
92
195
|
```
|
|
93
196
|
|
|
197
|
+
`onColumnOrderChange` still fires for every single move, with `{ column, oldIndex, targetIndex }`. The indices are positions in the grid's **full** column order: every current column (hidden columns and the row-grouping `__group__` column included), in its current order. Splicing your `columnOrder` with them is only right when it lists every column; prefer `onColumnOrderModelChange`. The panel's Reset does not fire `onColumnOrderChange`.
|
|
198
|
+
|
|
199
|
+
Columns missing from `columnOrder` (added later, for example) are still shown, placed by their position in `columns`.
|
|
200
|
+
|
|
94
201
|
### Non-Reorderable Columns
|
|
95
|
-
To prevent all columns from being reordered, use `disableColumnReorder` on the grid.
|
|
202
|
+
To prevent all columns from being reordered, use `disableColumnReorder` on the grid. Pinned columns (`pinnedColumns`, and the row-grouping column) keep their place: their headers cannot be dragged, and a header dropped on them does nothing. Unpin a column to move it. `pinnable: false` only stops a column from being pinned; it can still be reordered (v3.0+).
|
|
96
203
|
|
|
97
204
|
```tsx
|
|
98
205
|
// Disable reordering globally
|
|
@@ -101,3 +208,5 @@ To prevent all columns from being reordered, use `disableColumnReorder` on the g
|
|
|
101
208
|
// Keep a column fixed by pinning it
|
|
102
209
|
<DataGrid pinnedColumns={{ left: ['id'] }} />
|
|
103
210
|
```
|
|
211
|
+
|
|
212
|
+
Under `columnGroupingModel`, a column can only be dropped on a column of the same group.
|