@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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Keyboard Navigation & Accessibility
|
|
2
|
+
|
|
3
|
+
The grid follows the [WAI-ARIA data grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/): it is a single Tab stop, and the arrow keys move a focused cell inside it. This page lists the keys, explains how focus behaves, and documents the ARIA structure the grid exposes (v3.0).
|
|
4
|
+
|
|
5
|
+
## Focus model
|
|
6
|
+
|
|
7
|
+
- **One Tab stop.** The grid viewport (`role="grid"`) is in the page Tab order. Tabbing in puts focus on the last focused cell, or on the first cell (the select-all header checkbox with `checkboxSelection`, the first column header when there are no rows). While focus is inside the grid the viewport leaves the Tab order, so **Tab** and **Shift+Tab** leave the grid in one press.
|
|
8
|
+
- **Tab is not captured** outside edit mode. It moves to the next focusable element in the page, which may be a control you render in a cell (`renderCell`) or inside an expanded detail panel.
|
|
9
|
+
- **Focus is remembered.** Leaving the grid (Tab, clicking elsewhere, switching window) keeps the focused cell; coming back restores it. The focus ring is only drawn while the grid has focus and the keyboard is in use.
|
|
10
|
+
- **Focus survives virtualization.** When the focused row scrolls out of the render window, focus stays on the grid so keys keep working; the cell gets DOM focus back when it is rendered again. The grid never takes focus back from an element outside it.
|
|
11
|
+
- **Rows and columns that disappear.** If the focused row is removed or filtered out, focus moves to the row now at the same position; if the focused column is hidden, to the first visible data column; with no rows left, to the header.
|
|
12
|
+
- **Your own controls keep their keys.** Keys pressed in text inputs, textareas, selects and editable content rendered in cells, and anything inside a detail panel, are left to that element. On a button, link or checkbox rendered in a cell, **Enter** and **Space** activate it and the arrow keys still move grid focus.
|
|
13
|
+
|
|
14
|
+
## Keys
|
|
15
|
+
|
|
16
|
+
### Cells
|
|
17
|
+
|
|
18
|
+
| Key | Action |
|
|
19
|
+
| :--- | :--- |
|
|
20
|
+
| **Arrow keys** | Move one cell. Left/Right wrap to the previous/next row. Up from the first row moves to the header. Merged (spanned) cells count as one cell. |
|
|
21
|
+
| **Home** / **End** | First / last column of the row. |
|
|
22
|
+
| **Ctrl+Home** / **Ctrl+End** (Cmd on macOS) | First column of the header row / last column of the last row. |
|
|
23
|
+
| **PageUp** / **PageDown** | Up / down one page (`pageSize` with pagination, otherwise 10 rows). |
|
|
24
|
+
| **Enter** | Editable cell: open the editor. Other cells of a row with children (group row or tree-data parent): expand or collapse it. Other cells: same as clicking the row — fires `onRowClick` and toggles selection unless `disableRowSelectionOnClick`. |
|
|
25
|
+
| **Alt+ArrowRight** / **Alt+ArrowLeft** | Tree data / row grouping: expand / collapse the focused row. |
|
|
26
|
+
| **Shift+Space** | Select or deselect the focused row (when rows can be selected: `checkboxSelection`, or click selection not disabled). Synthetic group rows are not selectable. |
|
|
27
|
+
| **Space** | On the row checkbox: toggle the row. On the detail-panel toggle: expand or collapse the panel. Elsewhere it does nothing (it never scrolls the grid). |
|
|
28
|
+
| **Ctrl+A** (Cmd+A) | Select every row, when several rows can be selected. |
|
|
29
|
+
| **Ctrl+C** (Cmd+C) | Copy the selected rows (see [Clipboard](clipboard.md)). |
|
|
30
|
+
|
|
31
|
+
Arrow, Home/End, PageUp/PageDown and Space are always consumed, so the viewport does not scroll natively when focus cannot move further.
|
|
32
|
+
|
|
33
|
+
### While editing
|
|
34
|
+
|
|
35
|
+
| Key | Action |
|
|
36
|
+
| :--- | :--- |
|
|
37
|
+
| **Enter** | Commit. |
|
|
38
|
+
| **Escape** | Cancel. |
|
|
39
|
+
| **Tab** / **Shift+Tab** | Commit and open the next / previous editable cell (checkbox, expand and reorder columns are skipped). With no editable cell left, focus leaves the grid and the edit commits. |
|
|
40
|
+
|
|
41
|
+
When an edit ends, focus returns to the edited cell unless you moved it elsewhere.
|
|
42
|
+
|
|
43
|
+
### Column headers
|
|
44
|
+
|
|
45
|
+
| Key | Action |
|
|
46
|
+
| :--- | :--- |
|
|
47
|
+
| **Enter** / **Space** | Sort the column (asc → desc → none), replacing the sort model; with `multiSort`, or with **Shift** held, the column is added to (or updated or removed from) the sort model instead, as a header click or shift-click does. On the select-all header: select or clear all rows. |
|
|
48
|
+
| **Alt+ArrowDown** or **Ctrl+Enter** (Cmd+Enter) | Open the column menu. |
|
|
49
|
+
| **Alt+ArrowRight** / **Alt+ArrowLeft** | Widen / narrow the column by 10px (with **Shift**: 50px). Not for `resizable: false` columns. |
|
|
50
|
+
| **ArrowDown** | Move to the first row. |
|
|
51
|
+
|
|
52
|
+
In the column menu, **ArrowUp** / **ArrowDown** / **Home** / **End** move between items, **Enter** / **Space** choose one, and **Escape** or **Tab** closes the menu. Focus returns to the column header.
|
|
53
|
+
|
|
54
|
+
### List view
|
|
55
|
+
|
|
56
|
+
In `listView`, focus moves between whole rows instead of cells:
|
|
57
|
+
|
|
58
|
+
| Key | Action |
|
|
59
|
+
| :--- | :--- |
|
|
60
|
+
| **Tab** | The list is one Tab stop: it lands on the last focused row (the first row at first). Row checkboxes are not separate Tab stops. |
|
|
61
|
+
| **ArrowDown** / **ArrowUp** | Next / previous row. |
|
|
62
|
+
| **Home** / **End** | First / last row. |
|
|
63
|
+
| **PageDown** / **PageUp** | Ten rows down / up. |
|
|
64
|
+
| **Enter** / **Space** | A row with children (tree-data parent, group row): expand or collapse it. Any other row: same as clicking it (`onRowClick`, and click selection unless `disableRowSelectionOnClick`). |
|
|
65
|
+
| **Alt+ArrowRight** / **Alt+ArrowLeft** | Expand / collapse the focused parent row. |
|
|
66
|
+
| **Shift+Space** | Select or deselect the focused row, when rows can be selected. |
|
|
67
|
+
|
|
68
|
+
Keys pressed in content your `renderCell` puts in a row (inputs, buttons) are left to that content.
|
|
69
|
+
|
|
70
|
+
## ARIA structure
|
|
71
|
+
|
|
72
|
+
| Element | Attributes |
|
|
73
|
+
| :--- | :--- |
|
|
74
|
+
| Viewport | `role="grid"`, `aria-rowcount`, `aria-colcount`, `aria-multiselectable` (true when several rows can be selected), `aria-busy`. |
|
|
75
|
+
| Header rows | `role="row"` with `aria-rowindex`: column-group rows first, then the column header row. |
|
|
76
|
+
| Data rows | `role="row"`, `aria-rowindex` counted across the whole dataset (page 2 continues after page 1; bottom-pinned rows come after every page), `aria-selected`. Tree-data and row-grouping rows add `aria-level`; rows with children add `aria-expanded`. |
|
|
77
|
+
| Cells and headers | `aria-colindex`, identical for a header and the body cells below it. The system columns (reorder handle, detail-panel toggle, checkbox) come first. |
|
|
78
|
+
| Sorted headers | Only the primary sort column has `aria-sort="ascending"` / `"descending"`; with several sort keys every sorted header also gets an `aria-description` such as "Sorted descending, sort priority 2 of 2". |
|
|
79
|
+
| Detail panel | A `role="row"` with one `role="gridcell"` spanning every column (`aria-colspan`). The expand cell has `aria-expanded` and, while open, `aria-controls` pointing at the panel. |
|
|
80
|
+
|
|
81
|
+
`aria-rowcount` counts the header rows plus top-pinned, centre and bottom-pinned rows; under server-side pagination it uses `rowCount`. `aria-colcount` counts the rendered columns: visible data columns (including the `groupingColDef` column and generated pivot columns) plus the system columns.
|
|
82
|
+
|
|
83
|
+
`GridCellParams.colIndex` / `GridRenderCellParams.colIndex` (and `renderHeader`'s `colIndex`) are the zero-based position of the column among the **visible data columns in render order** (left-pinned, unpinned, right-pinned). They do not change with horizontal scrolling. `aria-colindex` is `colIndex + 1 +` the number of system columns.
|
|
@@ -6,9 +6,16 @@ Switch from a multi-column grid to a single-column detailed list. Perfect for mo
|
|
|
6
6
|
|
|
7
7
|
## 🏗️ Usage
|
|
8
8
|
|
|
9
|
-
Enable List View by passing the `listView` prop. You must also provide a `listViewColumn` object which defines how each "Card" should be rendered.
|
|
9
|
+
Enable List View by passing the `listView` prop. You must also provide a `listViewColumn` object which defines how each "Card" should be rendered. Without `listViewColumn` the grid view is shown instead and a dev warning is logged.
|
|
10
|
+
|
|
11
|
+
List view honours `loading`, `slots.loadingOverlay`, `slots.noRowsOverlay` and `slots.footer` like the grid view: while loading it shows a progress bar (or your loading overlay) rather than the empty state, and `slots.footer` replaces its pagination controls.
|
|
10
12
|
|
|
11
13
|
```tsx
|
|
14
|
+
import { DataGrid, type GridListViewColDef } from '@opencorestack/opengridx';
|
|
15
|
+
|
|
16
|
+
// Your own row type: an interface or a type alias both work (v3+).
|
|
17
|
+
interface Employee { id: number; name: string; role: string; status: string; avatar: string }
|
|
18
|
+
|
|
12
19
|
const listColDef: GridListViewColDef<Employee> = {
|
|
13
20
|
field: 'card',
|
|
14
21
|
renderCell: (params) => <MyEmployeeCard row={params.row} />
|
|
@@ -32,10 +39,24 @@ When `listView` is active:
|
|
|
32
39
|
- **Card Containers**: Each row maintains its standard selection and hover behaviors, but visually acts as a card.
|
|
33
40
|
|
|
34
41
|
### Custom Card Rendering
|
|
35
|
-
The `renderCell` function in `listViewColumn` receives all standard `GridRenderCellParams`, allowing you to build rich, complex UIs for each item
|
|
42
|
+
The `renderCell` function in `listViewColumn` receives all standard `GridRenderCellParams`, allowing you to build rich, complex UIs for each item:
|
|
43
|
+
|
|
44
|
+
| Param | Value |
|
|
45
|
+
| :--- | :--- |
|
|
46
|
+
| `row` | The consumer's row object. |
|
|
47
|
+
| `field` | `listViewColumn.field`. |
|
|
48
|
+
| `value` | The cell value for that field: the grid column with the same `field` reads it through its `valueGetter`; otherwise `row[field]` (so a synthetic field such as `'card'` gives `undefined`). |
|
|
49
|
+
| `formattedValue` | That column's `valueFormatter` result, or `String(value)` (`''` for null/undefined). |
|
|
50
|
+
| `colDef` | The grid column with the same `field`, or `listViewColumn` itself. |
|
|
51
|
+
| `rowMeta` | Tree-data / row-grouping metadata (`treeDepth`, `hasChildren`, …), `undefined` for flat rows. |
|
|
52
|
+
| `rowIndex` | Index of the row among the rendered rows (pinned rows first). |
|
|
53
|
+
|
|
54
|
+
`renderCell` only ever receives real rows: while an infinite-scroll page loads, no placeholder rows are passed to it.
|
|
55
|
+
|
|
56
|
+
Under row grouping (and for auto-created tree parents) `renderCell` is also called for group rows (`rowMeta.isGroupRow`). Returning `undefined` for one shows its `rowMeta.groupLabel`. Group rows have no selection checkbox, and the `N items` summary counts data rows only, as in the grid view (v3.0+). A `renderCell` that throws shows an error in that row only, and a throwing `valueGetter` / `valueFormatter` of the grid column reads as `undefined` / the unformatted value (v3.0+).
|
|
36
57
|
|
|
37
58
|
```tsx
|
|
38
|
-
function MyEmployeeCard({ row }) {
|
|
59
|
+
function MyEmployeeCard({ row }: { row: Employee }) {
|
|
39
60
|
return (
|
|
40
61
|
<div className="employee-card">
|
|
41
62
|
<Avatar src={row.avatar} />
|
|
@@ -51,15 +72,47 @@ function MyEmployeeCard({ row }) {
|
|
|
51
72
|
|
|
52
73
|
---
|
|
53
74
|
|
|
75
|
+
## 📄 Pagination and infinite scroll
|
|
76
|
+
|
|
77
|
+
List view pages exactly like the grid view: with `pagination`, one page of the (unpinned) rows is shown between any pinned rows, also under tree data. The summary line above the list reads `N items · page X of Y`, where under server pagination (`paginationMode="server"` with a `dataSource`) `N` and the page count come from the server's `rowCount`.
|
|
78
|
+
|
|
79
|
+
`onRowsScrollEnd` fires when the list is scrolled to within 100px of its bottom, so the [infinite scroll](./infinite-scroll.md) pattern works in list view too. As in the grid view, it fires once per arrival: it fires again only after the list leaves that zone or the row count changes (for example, when the next page has loaded).
|
|
80
|
+
|
|
81
|
+
The list view is **not virtualized**: it renders every row it shows (one page with `pagination`, otherwise all rows). Use pagination for large datasets. `slots.footer` is rendered below the list (in place of its pagination controls); the aggregation footer row is not shown in list view.
|
|
82
|
+
|
|
83
|
+
## ♿ Accessibility
|
|
84
|
+
|
|
85
|
+
The list is a `role="grid"` whose rows carry an `aria-rowindex` over the whole data set (row 11 on the second page of 10) and whose `aria-rowcount` is the total number of rows. There is no header row in list view. Tree-data and grouped rows also carry `aria-level` and, for parents, `aria-expanded`; they are indented by depth, and parents show a chevron that expands or collapses them on click (the chevron is not a Tab stop).
|
|
86
|
+
|
|
87
|
+
### Keyboard (v3.0)
|
|
88
|
+
|
|
89
|
+
Rows are focusable with a roving tab stop:
|
|
90
|
+
|
|
91
|
+
| Key | Action |
|
|
92
|
+
| :--- | :--- |
|
|
93
|
+
| **Tab** | The list is one Tab stop: it lands on the last focused row (the first row at first). Row checkboxes are not separate Tab stops. |
|
|
94
|
+
| **ArrowDown** / **ArrowUp** | Next / previous row. |
|
|
95
|
+
| **Home** / **End** | First / last row. |
|
|
96
|
+
| **PageDown** / **PageUp** | Ten rows down / up. |
|
|
97
|
+
| **Enter** / **Space** | A row with children (tree-data parent, group row): expand or collapse it. Any other row: same as clicking it (`onRowClick`, and click selection unless `disableRowSelectionOnClick`). |
|
|
98
|
+
| **Alt+ArrowRight** / **Alt+ArrowLeft** | Expand / collapse the focused parent row. |
|
|
99
|
+
| **Shift+Space** | Select or deselect the focused row, when rows can be selected. |
|
|
100
|
+
|
|
101
|
+
Keys pressed in content your `renderCell` puts in a row (inputs, buttons) are left to that content.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
54
105
|
## 📱 Responsive Toggle
|
|
55
106
|
|
|
56
107
|
A common pattern is to toggle List View based on screen width:
|
|
57
108
|
|
|
58
109
|
```tsx
|
|
59
|
-
const isMobile = window.innerWidth < 768;
|
|
110
|
+
const isMobile = window.innerWidth < 768; // read once; use a resize listener or matchMedia to follow changes
|
|
60
111
|
|
|
61
112
|
<DataGrid
|
|
113
|
+
rows={rows}
|
|
114
|
+
columns={columns}
|
|
62
115
|
listView={isMobile}
|
|
63
|
-
|
|
116
|
+
listViewColumn={listColDef}
|
|
64
117
|
/>
|
|
65
118
|
```
|
|
@@ -6,17 +6,22 @@ OpenGridX provides multiple ways to handle data loading, from initial shimmers t
|
|
|
6
6
|
|
|
7
7
|
## 🦴 Skeleton Loading
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
While `loading` is true and there are no rows to show, the grid body shows ten animated skeleton rows laid out with the current columns.
|
|
10
10
|
|
|
11
11
|
### Usage
|
|
12
12
|
```tsx
|
|
13
|
-
<DataGrid
|
|
13
|
+
<DataGrid rows={[]} columns={columns} loading />
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
### Features
|
|
17
|
-
- **
|
|
17
|
+
- **Column-aware**: Skeleton cells use the current column widths, plus the checkbox, detail-panel and drag-handle columns when those are enabled. With no columns yet, placeholder columns fill the width.
|
|
18
18
|
- **Shimmer Animation**: Uses a CSS-optimized animation for a premium feel.
|
|
19
|
-
- **
|
|
19
|
+
- **Custom overlay**: Pass `slots.loadingOverlay` to render your own component instead of the skeleton rows.
|
|
20
|
+
|
|
21
|
+
### Loading with rows already shown
|
|
22
|
+
When `loading` is true (or a data source request is running) and the grid already has rows, for example during a reload or a server-side sort, the rows stay visible and usable and a thin progress bar (`role="progressbar"`, class `ogx__loading-bar`) runs along the top of the grid. Pass `slots.loadingOverlay` to show your own indicator centred over the rows instead. Infinite scroll keeps its own indicator (skeleton rows at the bottom).
|
|
23
|
+
|
|
24
|
+
List view follows the same rules: while loading it shows a progress bar or `slots.loadingOverlay`, never the "No rows" state.
|
|
20
25
|
|
|
21
26
|
---
|
|
22
27
|
|
|
@@ -24,45 +29,38 @@ The grid features a smart skeleton loader that automatically calculates the numb
|
|
|
24
29
|
|
|
25
30
|
For large datasets, use the `paginationMode="infinite"` to load data as the user scrolls.
|
|
26
31
|
|
|
27
|
-
- **Trigger**:
|
|
32
|
+
- **Trigger**: `onRowsScrollEnd` fires when the user scrolls near the bottom; advance `paginationModel.page` there and the `dataSource` loads the next rows.
|
|
28
33
|
- **Feedback**: Displays skeleton rows at the bottom while new data is being fetched.
|
|
29
34
|
- **Guide**: See [Infinite Scroll Guide](./infinite-scroll.md) for full implementation details.
|
|
30
35
|
|
|
31
36
|
---
|
|
32
37
|
|
|
33
|
-
## 💤 Lazy Loading (Viewport)
|
|
34
|
-
|
|
35
|
-
Unlike infinite scroll which appends data to the end, Lazy Loading fetches specific chunks based on the user's current scroll position (viewport).
|
|
36
|
-
|
|
37
|
-
- **Benefit**: Best for datasets with millions of records where users might "jump" to the middle of the scrollbar.
|
|
38
|
-
- **Implementation**: Managed via the `GridDataSource` and `rowCount` props.
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
38
|
## 🔍 Global Search (Quick Filter)
|
|
43
39
|
|
|
44
|
-
Quickly filter the
|
|
40
|
+
Quickly filter the rows across all visible, filterable columns. The search box is part of `GridToolbar`.
|
|
45
41
|
|
|
46
42
|
### Basic Setup
|
|
47
43
|
|
|
48
|
-
Add the toolbar
|
|
44
|
+
Add the toolbar. The search box filters the grid on its own; pass `filterModel` / `onFilterModelChange` only when you want to control or observe the filter:
|
|
49
45
|
|
|
50
46
|
```tsx
|
|
51
47
|
<DataGrid
|
|
48
|
+
rows={rows}
|
|
49
|
+
columns={columns}
|
|
52
50
|
slots={{ toolbar: GridToolbar }}
|
|
53
|
-
filterModel={filterModel}
|
|
54
|
-
onFilterModelChange={setFilterModel}
|
|
55
51
|
/>
|
|
56
52
|
```
|
|
57
53
|
|
|
58
54
|
### Controlled Search
|
|
59
|
-
You can also control the search value externally via the `filterModel`.
|
|
55
|
+
You can also control the search value externally via the `filterModel`. Each entry is one term, and a row matches when every term is found in some visible column (the toolbar box splits typed text on whitespace the same way).
|
|
60
56
|
|
|
61
57
|
```tsx
|
|
62
58
|
<DataGrid
|
|
59
|
+
rows={rows}
|
|
60
|
+
columns={columns}
|
|
63
61
|
filterModel={{
|
|
64
62
|
items: [],
|
|
65
|
-
quickFilterValues: ['
|
|
63
|
+
quickFilterValues: ['john', 'london']
|
|
66
64
|
}}
|
|
67
65
|
/>
|
|
68
66
|
```
|
|
@@ -6,7 +6,7 @@ Display supplementary information for a row in an expandable panel without leavi
|
|
|
6
6
|
|
|
7
7
|
## 🛠️ Basic Implementation
|
|
8
8
|
|
|
9
|
-
To enable detail panels,
|
|
9
|
+
To enable detail panels, provide two main props: `getDetailPanelContent` and `getDetailPanelHeight`.
|
|
10
10
|
|
|
11
11
|
```tsx
|
|
12
12
|
<DataGrid
|
|
@@ -14,14 +14,16 @@ To enable detail panels, provided two main props: `getDetailPanelContent` and `g
|
|
|
14
14
|
columns={columns}
|
|
15
15
|
getDetailPanelContent={(params) => (
|
|
16
16
|
<div style={{ padding: '20px' }}>
|
|
17
|
-
<h3>Details for {params.row.name}</h3>
|
|
18
|
-
<p>{params.row.description}</p>
|
|
17
|
+
<h3>Details for {String(params.row.name)}</h3>
|
|
18
|
+
<p>{String(params.row.description)}</p>
|
|
19
19
|
</div>
|
|
20
20
|
)}
|
|
21
21
|
getDetailPanelHeight={() => 'auto'} // or a fixed number
|
|
22
22
|
/>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
`getDetailPanelContent` and `getDetailPanelHeight` are called only for **expanded** rows, while they render (v3.0+). A collapsed row costs nothing, and the callbacks may read fields that only data rows have. Synthetic hierarchy rows (row-grouping group rows and generated tree-data parents) have no detail panel: they keep an empty cell in the expand column, are never passed to the callbacks, and their ids in `detailPanelExpandedRowIds` are ignored. Tree-data parents that are real rows do get a panel. If `getDetailPanelContent` throws, that panel shows an error marker and the rest of the grid keeps working.
|
|
26
|
+
|
|
25
27
|
---
|
|
26
28
|
|
|
27
29
|
## 🕹️ Controlled Expansion
|
|
@@ -29,7 +31,9 @@ To enable detail panels, provided two main props: `getDetailPanelContent` and `g
|
|
|
29
31
|
You can manage which rows are expanded by using the `detailPanelExpandedRowIds` and `onDetailPanelExpandedRowIdsChange` props.
|
|
30
32
|
|
|
31
33
|
```tsx
|
|
32
|
-
|
|
34
|
+
import type { GridRowId } from '@opencorestack/opengridx';
|
|
35
|
+
|
|
36
|
+
const [expandedIds, setExpandedIds] = useState<Set<GridRowId>>(new Set());
|
|
33
37
|
|
|
34
38
|
<DataGrid
|
|
35
39
|
detailPanelExpandedRowIds={expandedIds}
|
|
@@ -43,4 +47,13 @@ const [expandedIds, setExpandedIds] = useState(new Set());
|
|
|
43
47
|
|
|
44
48
|
- **Expansion Column**: A `+` icon is automatically added to the start of the row.
|
|
45
49
|
- **Pinning**: The expansion column can be pinned using `pinExpandColumn={true}`. This ensures the expansion trigger is always visible even when scrolling horizontally.
|
|
46
|
-
- **
|
|
50
|
+
- **Height**: `getDetailPanelHeight` returns a pixel height (a fixed-height scroll box; `0` renders a 0px panel) or `'auto'`. Without the prop every panel is 200px. An `'auto'` panel is measured when it renders and whenever its content resizes, and the rows below are laid out at the measured height. Until a panel has rendered once, 200px is reserved for it.
|
|
51
|
+
- **Virtualization**: The grid engine accounts for variable row heights when detail panels are open, including panels on pinned rows (keyboard navigation and `scrollToIndexes` keep rows clear of an expanded bottom-pinned panel).
|
|
52
|
+
|
|
53
|
+
## ⌨️ Keyboard & Accessibility
|
|
54
|
+
|
|
55
|
+
- **Space** or **Enter** on the expand cell toggles the panel (v3.0: Enter too).
|
|
56
|
+
- Keys typed into content you render in the panel (inputs, selects, buttons) are left to that content: the grid does not react to them, so typing a space no longer collapses the panel and arrow keys move the caret.
|
|
57
|
+
- **Tab** is not captured by the grid, so it reaches focusable content inside an open panel.
|
|
58
|
+
- Keyboard scrolling brings the row itself into view, not the row plus its panel, so moving onto a row with a panel taller than the viewport keeps the row visible.
|
|
59
|
+
- The panel is exposed as a `role="row"` containing one `role="gridcell"` that spans every column; the expand cell has `aria-expanded` and, while open, `aria-controls` pointing at the panel. The `+`/`−` button inside the cell is not a separate Tab stop.
|
|
@@ -13,15 +13,18 @@ npm install jspdf jspdf-autotable
|
|
|
13
13
|
## Basic Usage
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
DataGrid, GridToolbar, exportToPdf, useGridApiRef,
|
|
18
|
+
type GridColDef, type GridRowModel,
|
|
19
|
+
} from '@opencorestack/opengridx';
|
|
17
20
|
|
|
18
|
-
function MyGrid() {
|
|
21
|
+
function MyGrid({ rows, columns }: { rows: GridRowModel[]; columns: GridColDef[] }) {
|
|
19
22
|
const apiRef = useGridApiRef();
|
|
20
23
|
|
|
21
24
|
const handleExport = async () => {
|
|
22
25
|
await exportToPdf(
|
|
23
|
-
apiRef.current.
|
|
24
|
-
apiRef.current.getVisibleColumns(),
|
|
26
|
+
apiRef.current.getAllFilteredRows(), // every row passing the filter, all pages
|
|
27
|
+
apiRef.current.getVisibleColumns(), // on-screen columns, in display order
|
|
25
28
|
{ fileName: 'my-report', title: 'Sales Report' }
|
|
26
29
|
);
|
|
27
30
|
};
|
|
@@ -31,14 +34,13 @@ function MyGrid() {
|
|
|
31
34
|
apiRef={apiRef}
|
|
32
35
|
rows={rows}
|
|
33
36
|
columns={columns}
|
|
34
|
-
slots={{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
),
|
|
37
|
+
slots={{ toolbar: GridToolbar }}
|
|
38
|
+
slotProps={{
|
|
39
|
+
toolbar: {
|
|
40
|
+
renderExportButton: () => (
|
|
41
|
+
<button onClick={handleExport}>Export PDF</button>
|
|
42
|
+
),
|
|
43
|
+
},
|
|
42
44
|
}}
|
|
43
45
|
/>
|
|
44
46
|
);
|
|
@@ -49,7 +51,7 @@ function MyGrid() {
|
|
|
49
51
|
|
|
50
52
|
```tsx
|
|
51
53
|
await exportToPdf(
|
|
52
|
-
apiRef.current.
|
|
54
|
+
apiRef.current.getAllFilteredRows(),
|
|
53
55
|
apiRef.current.getVisibleColumns(),
|
|
54
56
|
{
|
|
55
57
|
fileName: 'employee-report',
|
|
@@ -76,14 +78,49 @@ await exportToPdf(
|
|
|
76
78
|
| `title` | `string` | — | Adds a branded header block above the table |
|
|
77
79
|
| `logoUrl` | `string` | — | Data URI or URL for a logo image (requires `title`) |
|
|
78
80
|
| `orientation` | `'portrait' \| 'landscape'` | `'landscape'` | Page orientation |
|
|
79
|
-
| `selectedRows` | `(string \| number)[]` | — | Export only rows with these IDs |
|
|
81
|
+
| `selectedRows` | `(string \| number)[]` | — | Export only rows with these IDs. Takes precedence over `groupedRows`; the footer totals are recomputed over the selected rows (v3.0+) |
|
|
82
|
+
| `getRowId` | `(row) => GridRowId` | `row.id` | The grid's `getRowId`, when it has one, so `selectedRows` match rows that keep their id in another field (v3.0+) |
|
|
80
83
|
| `aggregationResult` | `Record<string, unknown>` | — | From `apiRef.current.getAggregationResult()` |
|
|
81
84
|
| `aggregationModel` | `GridAggregationModel` | — | From `apiRef.current.getAggregationModel()` |
|
|
82
|
-
| `filterModel` | `GridFilterModel` | — | From `apiRef.current.getFilterModel()
|
|
85
|
+
| `filterModel` | `GridFilterModel` | — | From `apiRef.current.getFilterModel()`. Summarised under the title (see below) |
|
|
86
|
+
| `groupedRows` | `GridGroupedExportRow[]` | — | From `apiRef.current.getGroupedExportRows()`: group headers, subtotals and a grand-total footer |
|
|
83
87
|
| `alternateRowColor` | `boolean` | `true` | Alternating row background shading |
|
|
84
|
-
| `headerBackgroundColor` | `string` | `'#4f46e5'` | Column header cell background (
|
|
85
|
-
| `headerTextColor` | `string` | `'#ffffff'` | Column header cell text color (
|
|
88
|
+
| `headerBackgroundColor` | `string` | `'#4f46e5'` | Column header cell background (`#rrggbb` or `#rgb`). Invalid values fall back to the default |
|
|
89
|
+
| `headerTextColor` | `string` | `'#ffffff'` | Column header cell text color (`#rrggbb` or `#rgb`). Invalid values fall back to the default |
|
|
86
90
|
| `fontSize` | `number` | `9` | Body cell font size in points |
|
|
91
|
+
| `font` | `{ name: string; data: string; boldData?: string }` | — | A TrueType font (base64 `.ttf`) for text outside Latin-1 (v3.0+). See [Non-Latin text](#non-latin-text-and-unicode-fonts) |
|
|
92
|
+
|
|
93
|
+
## Totals and filter summary
|
|
94
|
+
|
|
95
|
+
- The footer shows `TOTAL` in the first column; when the first column has its own aggregate, the value is kept next to it (`TOTAL: 30`). Grouped `Subtotal` and `Grand Total` rows do the same.
|
|
96
|
+
- `count` and `unique` are plain counts, not run through the column's `valueFormatter`. `sum`, `avg`, `min` and `max` use the formatter; if it throws (e.g. it reads a data-row field), the value is formatted like the grid footer instead of aborting the export. See [Aggregate values](export-guide.md#aggregate-values).
|
|
97
|
+
- The filter line under the title lists the applied filter as the grid evaluates it: `A equals "1" OR (B contains "x" AND C isEmpty) • Search: "acme"` — nested groups in parentheses, the model's logic operator, and the quick-search terms. Rules without a value (an unfinished row in the filter panel) are left out. Long titles and filter lines wrap within the page margins.
|
|
98
|
+
|
|
99
|
+
## Non-latin text and Unicode fonts
|
|
100
|
+
|
|
101
|
+
jsPDF's built-in Helvetica font only covers Latin-1 and the WinAnsi punctuation (`é`, `ü`, `€`, `“ ”`, `•`). A string with any other character used to come out entirely garbled; since v3.0 only the undrawable characters are replaced with `?` (special spaces and the minus sign become their ASCII forms, so `fr-FR` totals such as `1 234 567` print correctly) and a console warning is logged.
|
|
102
|
+
|
|
103
|
+
To print `₹`, Greek, Cyrillic, CJK or Devanagari text, pass a Unicode TrueType font such as [Noto Sans](https://fonts.google.com/noto) as base64:
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
const toBase64 = async (url: string) => {
|
|
107
|
+
const bytes = new Uint8Array(await (await fetch(url)).arrayBuffer());
|
|
108
|
+
let binary = '';
|
|
109
|
+
bytes.forEach(b => { binary += String.fromCharCode(b); });
|
|
110
|
+
return btoa(binary);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
await exportToPdf(rows, columns, {
|
|
114
|
+
title: 'बिक्री रिपोर्ट',
|
|
115
|
+
font: {
|
|
116
|
+
name: 'NotoSans',
|
|
117
|
+
data: await toBase64('/fonts/NotoSans-Regular.ttf'),
|
|
118
|
+
boldData: await toBase64('/fonts/NotoSans-Bold.ttf'), // optional; the regular face is used for bold otherwise
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
jsPDF does not shape complex scripts, so Devanagari or Arabic conjuncts may not join.
|
|
87
124
|
|
|
88
125
|
## Column Exclusion
|
|
89
126
|
|
|
@@ -93,7 +130,7 @@ Columns with `exportable: false` are excluded automatically:
|
|
|
93
130
|
{ field: 'internalNotes', headerName: 'Notes', exportable: false }
|
|
94
131
|
```
|
|
95
132
|
|
|
96
|
-
System columns (`__check__`, `__actions__`) are also always excluded.
|
|
133
|
+
System columns (`__check__`, `__actions__`) and spacer columns (`isSpacer: true`) are also always excluded.
|
|
97
134
|
|
|
98
135
|
## Troubleshooting
|
|
99
136
|
|
|
@@ -107,4 +144,4 @@ Ensure `logoUrl` is a data URI (base64-encoded) or an absolute URL that is CORS-
|
|
|
107
144
|
|
|
108
145
|
## Exporting unfiltered data
|
|
109
146
|
|
|
110
|
-
`getVisibleRows()` returns
|
|
147
|
+
`getVisibleRows()` returns the rows on screen: those that pass the current filter, only the current page when pagination is on, plus pinned rows. `getAllFilteredRows()` returns every filtered row regardless of pagination (and, under grouping or tree data, of expansion), in the grid's sort order with top- and bottom-pinned rows first and last; it is the right source for a full export. Use `getAllRows()` if you want to export all data regardless of active filters. `getVisibleColumns()` returns the columns on screen (hidden columns omitted), in display order. `getFilterModel()` returns the live filter model, including filters applied from the toolbar or filter panel.
|
package/docs/features/pinning.md
CHANGED
|
@@ -18,12 +18,20 @@ Columns can be pinned to the left or right edges of the grid. Pinned columns rem
|
|
|
18
18
|
/>
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
### Order and widths
|
|
22
|
+
- Pinned columns render in the order of `pinnedColumns.left` / `pinnedColumns.right`, not in column order. Pinning from the column menu appends the column to the end of its side, so it lands next to the scrolling columns.
|
|
23
|
+
- A pinned column is sized exactly as it would be unpinned: numbers, percentages, `flex` and `'auto'` all apply, clamped to `minWidth` / `maxWidth`. The sticky offsets use those widths, so pinned columns never overlap.
|
|
24
|
+
|
|
21
25
|
### Column Configuration
|
|
22
|
-
Individual columns can be marked as non-pinnable:
|
|
26
|
+
Individual columns can be marked as non-pinnable. Their column menu has no pin actions:
|
|
23
27
|
```typescript
|
|
24
28
|
{ field: 'id', pinnable: false }
|
|
25
29
|
```
|
|
26
30
|
|
|
31
|
+
`pinnable: false` only affects the UI; a column listed in `pinnedColumns` is still pinned. It does not block drag-reordering (v3.0+).
|
|
32
|
+
|
|
33
|
+
Pinned column headers are not draggable and are not drop targets for header drag-reorder: to move a pinned column, change the order in `pinnedColumns`.
|
|
34
|
+
|
|
27
35
|
---
|
|
28
36
|
|
|
29
37
|
## ⬆️ Row Pinning
|
|
@@ -40,8 +48,13 @@ Rows can be pinned to the top or bottom of the grid. Pinned rows remain visible
|
|
|
40
48
|
/>
|
|
41
49
|
```
|
|
42
50
|
|
|
51
|
+
### Behaviour
|
|
52
|
+
- Pinned rows are split out after filtering: a pinned row that does not match the active filter or quick filter is hidden. They are never sorted; they keep the order of `pinnedRows.top` / `.bottom`.
|
|
53
|
+
- `pinnedRows` is **ignored while `treeData` or `rowGroupingModel` is active**: the rows stay in their place in the hierarchy, and a development warning is logged.
|
|
54
|
+
- Top-pinned rows stick directly below the whole header, including column group header rows. Bottom-pinned rows stick directly above the aggregation footer; both stay visible.
|
|
55
|
+
|
|
43
56
|
### Use Cases
|
|
44
|
-
- **Header Summary**: Keep a
|
|
57
|
+
- **Header Summary**: Keep a summary row at the top (for grid-wide totals that follow the filter, prefer `aggregationModel`, whose footer never scrolls away).
|
|
45
58
|
- **Comparison**: Pin a specific row to compare it against other data.
|
|
46
59
|
- **Actions footer**: Pin a specialized row for bulk actions at the bottom.
|
|
47
60
|
|
|
@@ -59,8 +72,13 @@ Rows can be pinned to the top or bottom of the grid. Pinned rows remain visible
|
|
|
59
72
|
---
|
|
60
73
|
|
|
61
74
|
## 🎨 Styling Pinning
|
|
62
|
-
|
|
63
|
-
- `.
|
|
64
|
-
- `.
|
|
75
|
+
The last left-pinned cell and the first right-pinned cell of each row carry section-edge classes (the body cells draw an edge shadow):
|
|
76
|
+
- body cells: `.ogx__cell--pinned-left-last`, `.ogx__cell--pinned-right-first`
|
|
77
|
+
- header cells: `.ogx__header-cell--pinned-left-last`, `.ogx__header-cell--pinned-right-first`
|
|
78
|
+
- aggregation footer: `.ogx__aggregation-cell--pinned-left-last`, `.ogx__aggregation-cell--pinned-right-first`
|
|
79
|
+
|
|
80
|
+
The edge is the last / first pinned column that is actually shown, so hiding a pinned column moves it. All pinned cells also carry `.ogx__cell--pinned-left` / `--pinned-right` (`.ogx__header-cell--pinned-left` / `--pinned-right`).
|
|
81
|
+
|
|
82
|
+
Sticky row areas are wrapped (v3.0+): the header and the top-pinned rows sit in `div.ogx__sticky-top`, and the bottom-pinned rows and the aggregation footer sit in `div.ogx__sticky-bottom`. The `.ogx__pinned-rows--top` / `.ogx__pinned-rows--bottom` containers inside them are no longer sticky themselves, so custom sticky CSS belongs on the wrappers.
|
|
65
83
|
|
|
66
84
|
These can be customized via your theme or global CSS.
|
|
@@ -19,6 +19,8 @@ OpenGridX provides various ways for users to select one or multiple rows.
|
|
|
19
19
|
### Enable Checkbox Selection
|
|
20
20
|
```tsx
|
|
21
21
|
<DataGrid
|
|
22
|
+
rows={rows}
|
|
23
|
+
columns={columns}
|
|
22
24
|
checkboxSelection
|
|
23
25
|
pinCheckboxColumn // Optional: keeps checkbox on the left during horizontal scroll
|
|
24
26
|
/>
|
|
@@ -31,6 +33,8 @@ Use the `rowSelectionModel` to control the selection state from your parent comp
|
|
|
31
33
|
const [selection, setSelection] = useState<GridRowId[]>([]);
|
|
32
34
|
|
|
33
35
|
<DataGrid
|
|
36
|
+
rows={rows}
|
|
37
|
+
columns={columns}
|
|
34
38
|
rowSelectionModel={selection}
|
|
35
39
|
onRowSelectionModelChange={(newSelection) => setSelection(newSelection)}
|
|
36
40
|
/>
|
|
@@ -42,6 +46,8 @@ Use `disableRowSelectionOnClick` to prevent clicking a row from changing the sel
|
|
|
42
46
|
|
|
43
47
|
```tsx
|
|
44
48
|
<DataGrid
|
|
49
|
+
rows={rows}
|
|
50
|
+
columns={columns}
|
|
45
51
|
checkboxSelection
|
|
46
52
|
disableRowSelectionOnClick
|
|
47
53
|
/>
|
|
@@ -49,15 +55,41 @@ Use `disableRowSelectionOnClick` to prevent clicking a row from changing the sel
|
|
|
49
55
|
|
|
50
56
|
### Single-Row Selection Only
|
|
51
57
|
|
|
52
|
-
Use `disableMultipleRowSelection` to cap selection to one row at a time. Clicking a second row deselects the first; clicking an already-selected row deselects it.
|
|
58
|
+
Use `disableMultipleRowSelection` to cap selection to one row at a time. Clicking a second row deselects the first; clicking an already-selected row deselects it. The cap applies to row clicks, row checkboxes, the Space key and `apiRef.selectRow` / `selectRows` alike, and the header select-all checkbox is not shown.
|
|
53
59
|
|
|
54
60
|
```tsx
|
|
55
61
|
<DataGrid
|
|
62
|
+
rows={rows}
|
|
63
|
+
columns={columns}
|
|
56
64
|
disableMultipleRowSelection
|
|
57
65
|
onRowSelectionModelChange={(model) => console.log('selected:', model)}
|
|
58
66
|
/>
|
|
59
67
|
```
|
|
60
68
|
|
|
69
|
+
### Select All
|
|
70
|
+
|
|
71
|
+
With `checkboxSelection`, the header checkbox selects the rows that pass the current filter (including pinned rows) and adds them to the selection; unchecking it removes those rows again. Rows hidden by the filter keep their selection state, and under row grouping group rows are not part of select-all. Synthetic rows (row-grouping group and subtotal rows, auto-created tree-data parents, the pivot Grand Total) have no checkbox and are never selected, by click, checkbox, Space key or `apiRef.selectRow` / `selectRows` (v3.0+ for the Grand Total and `apiRef`); tree-data parents that are your own rows are selectable like any row. A click on the Grand Total still fires `onRowClick`. `apiRef.selectRow` on a row that is already selected reports nothing, as a click on the checkbox would not. The header shows checked when every such row is selected and indeterminate when only some are, so ids of rows that are no longer in `rows` do not affect it.
|
|
72
|
+
|
|
73
|
+
### Removed Rows
|
|
74
|
+
|
|
75
|
+
When rows leave `rows`, their ids leave the selection (v3.0+): `apiRef.current.getSelectedRows()`, the header checkbox and the next model a click produces no longer contain them, and the pruned model is reported once through `onRowSelectionModelChange`. An uncontrolled selection forgets the ids, so a row that comes back is not selected again; a controlled model should adopt the reported value. This applies when the grid holds every row: without a `dataSource`, with client pagination and filtering, and outside pivot mode. With `paginationMode="server"`, `filterMode="server"` or a `dataSource`, ids of rows that are not loaded are kept, so a selection survives paging.
|
|
76
|
+
|
|
77
|
+
In pivot mode the pivot rows have their own ids (`'__pivot_row__:["North"]'`, derived from the row-field values), so a selection made on the source rows never marks a pivot row, and leaving pivot mode gives the source selection back.
|
|
78
|
+
|
|
79
|
+
### Keyboard Selection
|
|
80
|
+
|
|
81
|
+
With focus in the grid (see [Keyboard & Accessibility](keyboard-navigation.md)):
|
|
82
|
+
|
|
83
|
+
| Key | Action |
|
|
84
|
+
| :--- | :--- |
|
|
85
|
+
| **Shift+Space** | Select or deselect the focused row. Available when rows can be selected at all (`checkboxSelection`, or click selection not disabled with `disableRowSelectionOnClick`). |
|
|
86
|
+
| **Space** / **Enter** on a row checkbox | Toggle that row. |
|
|
87
|
+
| **Space** / **Enter** on the select-all header | Select or clear all rows, like clicking it. |
|
|
88
|
+
| **Enter** on a non-editable cell | Same as clicking the row: `onRowClick`, then click-to-select unless `disableRowSelectionOnClick`. |
|
|
89
|
+
| **Ctrl+A** / **Cmd+A** | Select every row, unless `disableMultipleRowSelection` (or selection is not possible). |
|
|
90
|
+
|
|
91
|
+
Synthetic rows (row-grouping groups and subtotals, auto-created tree parents, the pivot Grand Total) are never selected from the keyboard. The grid sets `aria-multiselectable="true"` when several rows can be selected.
|
|
92
|
+
|
|
61
93
|
---
|
|
62
94
|
|
|
63
95
|
## ⚙️ API Reference
|
|
@@ -77,17 +109,25 @@ Use `disableMultipleRowSelection` to cap selection to one row at a time. Clickin
|
|
|
77
109
|
## 🖱️ Interaction Callbacks
|
|
78
110
|
|
|
79
111
|
### `onRowClick`
|
|
80
|
-
Fired when a row is clicked
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
112
|
+
Fired when a row is clicked, or Enter is pressed on one of its non-editable cells, even if selection is disabled on click. It is not fired for synthetic row-grouping group rows (a click toggles them instead).
|
|
113
|
+
```tsx
|
|
114
|
+
<DataGrid
|
|
115
|
+
rows={rows}
|
|
116
|
+
columns={columns}
|
|
117
|
+
onRowClick={(params: GridRowParams) => {
|
|
118
|
+
console.log('Row clicked:', params.id, params.row);
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
85
121
|
```
|
|
86
122
|
|
|
87
123
|
### `onCellClick`
|
|
88
124
|
Fired when a specific cell is clicked.
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
125
|
+
```tsx
|
|
126
|
+
<DataGrid
|
|
127
|
+
rows={rows}
|
|
128
|
+
columns={columns}
|
|
129
|
+
onCellClick={(params: GridCellParams) => {
|
|
130
|
+
console.log('Cell clicked:', params.field, params.value);
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
93
133
|
```
|