@opencorestack/opengridx 2.1.0 → 3.0.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 +399 -0
- package/README.md +95 -72
- package/dist/index.d.ts +590 -131
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7891 -5631
- 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 -166
- 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 +6 -7
- package/docs/components/datagrid.md +15 -13
- 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 +90 -38
- 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 +126 -39
- 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 +72 -19
- package/docs/features/pinning.md +24 -5
- package/docs/features/selection.md +50 -10
- package/docs/features/sorting-pagination.md +64 -14
- package/docs/features/state-persistence.md +78 -10
- package/docs/features/toolbar-customization.md +26 -17
- package/docs/features/tree-data-grouping.md +36 -8
- package/docs/features/virtualization.md +37 -14
- package/docs/migration/v1-to-v2.md +115 -0
- package/docs/migration/v2-to-v3.md +1233 -0
- package/docs/performance.md +124 -0
- package/docs/roadmap.md +5 -5
- package/lib/components/Cell/Cell.css +17 -1
- package/lib/components/Cell/Cell.tsx +129 -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 +15 -2
- 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 +85 -12
- package/lib/components/DataGrid/DataGrid.tsx +582 -876
- package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
- package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
- package/lib/components/DataGrid/GridListView.tsx +165 -24
- 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 +62 -11
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
- package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
- package/lib/components/DataGrid/GridVirtualRows.tsx +40 -24
- 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 +6 -3
- package/lib/components/Header/Header.tsx +181 -160
- package/lib/components/ListView/ListView.css +25 -0
- package/lib/components/ListView/ListViewRow.tsx +76 -10
- package/lib/components/Pagination/Pagination.tsx +15 -7
- package/lib/components/Row/Row.tsx +177 -77
- 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 +19 -4
- 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 +279 -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 +104 -5
- 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 +447 -243
- 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 +17 -5
- 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 +82 -51
- 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 +298 -160
- package/lib/hooks/useRowReorder.ts +62 -31
- package/lib/hooks/useTreeData.ts +287 -220
- package/lib/index.ts +28 -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 +313 -116
- package/lib/utils/aggregation/index.ts +119 -24
- 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 +278 -139
- 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 +55 -5
- 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 +261 -164
- package/package.json +13 -5
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
- package/lib/components/DataGrid/DataGrid.defects.test.tsx +0 -103
- 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/DataGrid/DataGrid.virtualization.browser.test.tsx +0 -183
- 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 -298
- package/lib/hooks/useTreeData.test.ts +0 -83
- package/lib/utils/aggregation/aggregation.test.ts +0 -16
- package/lib/utils/export/exportToExcelAdvanced.test.ts +0 -109
- 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
|
@@ -4,57 +4,85 @@ The Slots API allows you to replace any built-in component in the DataGrid with
|
|
|
4
4
|
|
|
5
5
|
## Available Slots
|
|
6
6
|
|
|
7
|
+
Every slot is typed `React.ComponentType<Record<string, unknown>>`, and every `slotProps` entry is `Record<string, unknown>`. A slot component therefore takes `props: Record<string, unknown>` and narrows the props it uses; the examples below cast to a type alias describing the props the grid passes. (A component declared with its own required props, such as `(props: { page: number }) => …`, is rejected by TypeScript.) The props from `slotProps.<slot>` are spread last, so they can override the grid's props.
|
|
8
|
+
|
|
7
9
|
### 1. `toolbar`
|
|
8
10
|
Add a custom toolbar above the grid (commonly used for export buttons, filters, actions).
|
|
9
11
|
|
|
10
12
|
**Props received:**
|
|
11
13
|
```typescript
|
|
12
14
|
{
|
|
13
|
-
|
|
15
|
+
apiRef: React.MutableRefObject<GridApi>;
|
|
16
|
+
columns: GridColDef[]; // every column in display order, hidden ones included
|
|
17
|
+
baseColumns: GridColDef[]; // the `columns` prop as passed
|
|
18
|
+
aggregationModel: GridAggregationModel;
|
|
19
|
+
onAggregationModelChange: (model: GridAggregationModel) => void;
|
|
20
|
+
pivotModel?: GridPivotModel; // only when pivotMode, pivotModel or onPivotModelChange is set
|
|
21
|
+
onPivotModelChange?: (model: GridPivotModel) => void;
|
|
22
|
+
filterModel: GridFilterModel;
|
|
23
|
+
onFilterModelChange: (model: GridFilterModel) => void;
|
|
24
|
+
columnVisibilityModel: GridColumnVisibilityModel;
|
|
25
|
+
onColumnVisibilityModelChange: (model: GridColumnVisibilityModel) => void;
|
|
26
|
+
onColumnReorder?: (fromField: string, toField: string) => void; // undefined with disableColumnReorder
|
|
27
|
+
onColumnOrderReset?: () => void; // undefined with disableColumnReorder
|
|
28
|
+
forceColumnsOpen: boolean; // the column menu's "Manage columns" asked for the Columns panel
|
|
29
|
+
onColumnsPanelClose: () => void;
|
|
30
|
+
// ...plus any props from slotProps.toolbar
|
|
14
31
|
}
|
|
15
32
|
```
|
|
16
33
|
|
|
34
|
+
These match `GridToolbarProps`, so `slots={{ toolbar: GridToolbar }}` gives the built-in toolbar.
|
|
35
|
+
|
|
17
36
|
**Example:**
|
|
18
37
|
```tsx
|
|
19
|
-
import { exportToCsv, exportToExcel } from '@opencorestack/opengridx';
|
|
38
|
+
import { DataGrid, exportToCsv, exportToExcel, type GridApi, type GridColDef } from '@opencorestack/opengridx';
|
|
39
|
+
import type { MutableRefObject } from 'react';
|
|
40
|
+
|
|
41
|
+
type ToolbarSlotProps = { apiRef: MutableRefObject<GridApi>; columns: GridColDef[] };
|
|
20
42
|
|
|
21
|
-
function CustomToolbar(
|
|
43
|
+
function CustomToolbar(props: Record<string, unknown>) {
|
|
44
|
+
const { apiRef, columns } = props as ToolbarSlotProps;
|
|
45
|
+
const exportRows = () => apiRef.current.getAllFilteredRows();
|
|
22
46
|
return (
|
|
23
47
|
<div style={{ padding: '12px', display: 'flex', gap: '8px' }}>
|
|
24
|
-
<button onClick={() => exportToCsv(
|
|
48
|
+
<button type="button" onClick={() => exportToCsv(exportRows(), columns)}>
|
|
25
49
|
Export CSV
|
|
26
50
|
</button>
|
|
27
|
-
<button onClick={() => exportToExcel(
|
|
51
|
+
<button type="button" onClick={() => exportToExcel(exportRows(), columns)}>
|
|
28
52
|
Export Excel
|
|
29
53
|
</button>
|
|
30
54
|
</div>
|
|
31
55
|
);
|
|
32
56
|
}
|
|
33
57
|
|
|
34
|
-
<DataGrid
|
|
35
|
-
slots={{ toolbar: CustomToolbar }}
|
|
36
|
-
slotProps={{ toolbar: { rows, columns } }}
|
|
37
|
-
/>
|
|
58
|
+
<DataGrid rows={rows} columns={columns} slots={{ toolbar: CustomToolbar }} />
|
|
38
59
|
```
|
|
39
60
|
|
|
61
|
+
`toolbar` accepts any React component type: function, class, `React.memo`, `forwardRef` or `lazy`. A plain function toolbar may be defined inline inside your own component: the grid keys it on its source code, so it keeps its state (open panels, typed search) when your component re-renders and remounts only when you pass a toolbar with different code. A class, memo or forwardRef toolbar is rendered as a normal element, so define it outside render to keep its identity stable.
|
|
62
|
+
|
|
40
63
|
### 2. `pagination`
|
|
41
|
-
Replace the default pagination component.
|
|
64
|
+
Replace the default pagination component. It is rendered only while pagination is in effect (`pagination` set, no row grouping, `paginationMode` not `"infinite"`), is not rendered when a `footer` slot is set, and is used by list view too.
|
|
42
65
|
|
|
43
66
|
**Props received:**
|
|
44
67
|
```typescript
|
|
45
68
|
{
|
|
46
|
-
page: number; // Current page (0-based)
|
|
69
|
+
page: number; // Current page (0-based), clamped to the last page client-side
|
|
47
70
|
pageSize: number; // Current page size
|
|
48
|
-
rowCount: number; //
|
|
49
|
-
pageSizeOptions: number[]; // Available page sizes
|
|
71
|
+
rowCount: number; // Rows being paged: filtered, unpinned rows; the server total in paginationMode="server"
|
|
72
|
+
pageSizeOptions: number[]; // Available page sizes (default [10, 25, 50, 100])
|
|
50
73
|
onPageChange: (page: number) => void;
|
|
51
|
-
onPageSizeChange: (size: number) => void;
|
|
74
|
+
onPageSizeChange: (size: number) => void; // also resets to page 0
|
|
75
|
+
localeText?: Pick<GridLocaleText, 'paginationRowsPerPage' | 'paginationOf' | 'paginationPage'>; // only when the localeText prop is set
|
|
76
|
+
// ...plus any props from slotProps.pagination
|
|
52
77
|
}
|
|
53
78
|
```
|
|
54
79
|
|
|
55
80
|
**Example:**
|
|
56
81
|
```tsx
|
|
57
82
|
<DataGrid
|
|
83
|
+
rows={rows}
|
|
84
|
+
columns={columns}
|
|
85
|
+
pagination
|
|
58
86
|
slots={{ pagination: CustomPagination }}
|
|
59
87
|
slotProps={{ pagination: { customProp: 'value' } }}
|
|
60
88
|
/>
|
|
@@ -66,7 +94,7 @@ Replace the empty state shown when there are no rows.
|
|
|
66
94
|
**Props received:**
|
|
67
95
|
```typescript
|
|
68
96
|
{
|
|
69
|
-
//
|
|
97
|
+
// Only the props from slotProps.noRowsOverlay
|
|
70
98
|
}
|
|
71
99
|
```
|
|
72
100
|
|
|
@@ -82,6 +110,8 @@ function CustomNoRows() {
|
|
|
82
110
|
}
|
|
83
111
|
|
|
84
112
|
<DataGrid
|
|
113
|
+
rows={rows}
|
|
114
|
+
columns={columns}
|
|
85
115
|
slots={{ noRowsOverlay: CustomNoRows }}
|
|
86
116
|
/>
|
|
87
117
|
```
|
|
@@ -92,7 +122,7 @@ Replace the loading state overlay.
|
|
|
92
122
|
**Props received:**
|
|
93
123
|
```typescript
|
|
94
124
|
{
|
|
95
|
-
//
|
|
125
|
+
// Only the props from slotProps.loadingOverlay
|
|
96
126
|
}
|
|
97
127
|
```
|
|
98
128
|
|
|
@@ -108,40 +138,53 @@ function CustomLoader() {
|
|
|
108
138
|
}
|
|
109
139
|
|
|
110
140
|
<DataGrid
|
|
141
|
+
rows={rows}
|
|
142
|
+
columns={columns}
|
|
143
|
+
loading={isLoading}
|
|
111
144
|
slots={{ loadingOverlay: CustomLoader }}
|
|
112
145
|
/>
|
|
113
146
|
```
|
|
114
147
|
|
|
115
148
|
### 5. `footer`
|
|
116
|
-
Replace the entire footer section below the grid, including the default pagination. Rendered whenever the slot is set, including while row grouping is active.
|
|
149
|
+
Replace the entire footer section below the grid, including the default pagination. Rendered whenever the slot is set, including while row grouping is active, except in list view.
|
|
117
150
|
|
|
118
|
-
**Props received
|
|
151
|
+
**Props received** (`GridFooterSlotProps`, v3.0+):
|
|
119
152
|
```typescript
|
|
120
153
|
{
|
|
121
154
|
apiRef: React.MutableRefObject<GridApi>;
|
|
122
155
|
aggregationModel: GridAggregationModel;
|
|
123
|
-
aggregationResult: GridAggregationResult | null; // null when
|
|
124
|
-
rowCount: number; //
|
|
125
|
-
pagination: boolean; // effective: false while row grouping is active
|
|
126
|
-
paginationModel: GridPaginationModel;
|
|
156
|
+
aggregationResult: GridAggregationResult | null; // null when aggregationModel is empty, and in pivot mode
|
|
157
|
+
rowCount: number; // see below
|
|
158
|
+
pagination: boolean; // effective: false while row grouping is active or with paginationMode="infinite"
|
|
159
|
+
paginationModel: GridPaginationModel; // the model as held (not clamped to the last page)
|
|
127
160
|
pageSizeOptions: number[];
|
|
128
161
|
onPaginationModelChange: (model: GridPaginationModel) => void;
|
|
129
162
|
// ...plus any props from slotProps.footer
|
|
130
163
|
}
|
|
131
164
|
```
|
|
132
165
|
|
|
166
|
+
`rowCount` is:
|
|
167
|
+
- with `paginationMode="server"`: the server total (the `dataSource` response's `rowCount`, else the `rowCount` prop, else the number of loaded rows);
|
|
168
|
+
- otherwise, in a flat grid: the pager's `rowCount`, the filtered rows **without** pinned rows (v3.0+; before, pinned rows were counted). With `filterMode="server"` it is every row the grid holds; with `paginationMode="infinite"` the rows loaded so far; in pivot mode the pivot rows including the Grand Total row;
|
|
169
|
+
- under row grouping and tree data: the data rows that pass the client filter (never group rows), whatever is expanded.
|
|
170
|
+
|
|
133
171
|
**Example — a persistent grand-total bar that stays in sync with filtering:**
|
|
134
172
|
```tsx
|
|
135
|
-
|
|
136
|
-
|
|
173
|
+
import type { GridFooterSlotProps } from '@opencorestack/opengridx';
|
|
174
|
+
|
|
175
|
+
// Type the props you read; the grid checks them against GridFooterSlotProps.
|
|
176
|
+
function TotalsFooter({ aggregationResult, rowCount }: Pick<GridFooterSlotProps, 'aggregationResult' | 'rowCount'>) {
|
|
177
|
+
const total = aggregationResult?.amount;
|
|
137
178
|
return (
|
|
138
179
|
<div style={{ padding: '12px', borderTop: '1px solid #e0e0e0' }}>
|
|
139
|
-
{
|
|
180
|
+
{rowCount} rows · Total: {typeof total === 'number' ? total.toLocaleString() : '—'}
|
|
140
181
|
</div>
|
|
141
182
|
);
|
|
142
183
|
}
|
|
143
184
|
|
|
144
185
|
<DataGrid
|
|
186
|
+
rows={rows}
|
|
187
|
+
columns={columns}
|
|
145
188
|
aggregationModel={{ amount: 'sum' }}
|
|
146
189
|
slots={{ footer: TotalsFooter }}
|
|
147
190
|
/>
|
|
@@ -155,9 +198,19 @@ function TotalsFooter({ aggregationResult, rowCount }: Record<string, unknown>)
|
|
|
155
198
|
import { Select, Pagination, Spin, Empty } from 'antd';
|
|
156
199
|
import { DataGrid } from '@opencorestack/opengridx';
|
|
157
200
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
201
|
+
type PaginationSlotProps = {
|
|
202
|
+
page: number;
|
|
203
|
+
pageSize: number;
|
|
204
|
+
rowCount: number;
|
|
205
|
+
pageSizeOptions: number[];
|
|
206
|
+
onPageChange: (page: number) => void;
|
|
207
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
function AntdPagination(props: Record<string, unknown>) {
|
|
211
|
+
const { page, pageSize, rowCount, pageSizeOptions, onPageChange, onPageSizeChange } =
|
|
212
|
+
props as PaginationSlotProps;
|
|
213
|
+
|
|
161
214
|
return (
|
|
162
215
|
<div style={{ display: 'flex', gap: '16px', padding: '12px 16px', justifyContent: 'flex-end' }}>
|
|
163
216
|
<Select
|
|
@@ -211,18 +264,17 @@ function MyApp() {
|
|
|
211
264
|
|
|
212
265
|
## TypeScript Support
|
|
213
266
|
|
|
214
|
-
|
|
267
|
+
The library exports no props type for the pagination, overlay or footer slots (the toolbar's props are `GridToolbarProps`). Declare a type alias for the props you read and narrow `Record<string, unknown>` to it, as above. Use a `type` alias rather than an `interface`: an interface has no index signature, so `props as MyInterface` needs `as unknown as`.
|
|
215
268
|
|
|
216
269
|
```typescript
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
customProp?: string;
|
|
221
|
-
}
|
|
270
|
+
type CustomPaginationProps = PaginationSlotProps & {
|
|
271
|
+
customProp?: string; // from slotProps.pagination
|
|
272
|
+
};
|
|
222
273
|
|
|
223
|
-
|
|
274
|
+
function CustomPagination(props: Record<string, unknown>) {
|
|
275
|
+
const { page, customProp } = props as CustomPaginationProps;
|
|
224
276
|
// Your implementation
|
|
225
|
-
}
|
|
277
|
+
}
|
|
226
278
|
```
|
|
227
279
|
|
|
228
280
|
## Best Practices
|
|
@@ -235,5 +287,5 @@ const CustomPagination: React.FC<CustomPaginationProps> = (props) => {
|
|
|
235
287
|
|
|
236
288
|
## See Also
|
|
237
289
|
|
|
238
|
-
- [Custom Pagination Guide](
|
|
239
|
-
- [DataGrid Props](
|
|
290
|
+
- [Custom Pagination Guide](../features/custom-pagination.md) - Detailed examples with Ant Design and MUI
|
|
291
|
+
- [DataGrid Props](../../lib/types/index.ts) - Full TypeScript definitions
|
|
@@ -11,6 +11,7 @@ OpenGridX ships with a complete design-token system built on CSS custom properti
|
|
|
11
11
|
|
|
12
12
|
```tsx
|
|
13
13
|
import { DataGrid, DataGridThemeProvider } from '@opencorestack/opengridx';
|
|
14
|
+
import '@opencorestack/opengridx/styles'; // required: the tokens only take effect through the grid's stylesheet
|
|
14
15
|
|
|
15
16
|
const myTheme = {
|
|
16
17
|
colors: {
|
|
@@ -38,11 +39,27 @@ export default function App() {
|
|
|
38
39
|
|
|
39
40
|
The `DataGridThemeProvider` resolves each key in the `GridTheme` object to its corresponding `--ogx-*` CSS variable and applies it as an inline style on a wrapper `div`. **No CSS-in-JS, no runtime overhead.**
|
|
40
41
|
|
|
42
|
+
How the provider builds the variables (v3.0+):
|
|
43
|
+
|
|
44
|
+
- **It pins a complete palette.** It starts from a full light palette (or a full dark one with `mode: 'dark'`) that sets every colour token, neutral scale included, and then applies your keys on top. A light theme therefore stays light, and readable, when the operating system is in dark mode, and a dark theme needs no other CSS.
|
|
45
|
+
- **Accents follow `colors.primary`.** The toolbar's primary button, active chips, search focus ring, selected menu items, selected rows and the keyboard focus ring are all derived from the `colors.primary*` tokens (with `var()` / `color-mix()`), so a theme that only sets `colors.primary` recolours all of them. Set the specific `toolbar.*`, `overlays.*` or `grid.*` key to override one.
|
|
46
|
+
- **Toolbar tokens follow the grid surface.** Unless you set `toolbar.*`, the toolbar uses the header background, header text and grid border colours.
|
|
47
|
+
- **Row and header heights reach the layout.** `grid.rowHeightStandard` / `grid.headerHeight` (and `rowHeightCompact` / `rowHeightComfortable` with `density`) are read by the grid itself, which virtualizes from them. They must be pixel values (`'36px'` or `'36'`); other units are ignored. The `rowHeight` / `headerHeight` props win over the theme.
|
|
48
|
+
|
|
49
|
+
> **Sizing:** the wrapper `div` (`.ogx-theme-provider`) is a normal auto-height block. A grid without a `height` prop (or with `height="100%"`) fills its parent, which here is the wrapper, so inside a bounded container pass `style={{ height: '100%' }}` (or a `className` that sets a height) to the provider too. Otherwise the wrapper grows to fit every row and row virtualization is effectively off. See [Virtualization → The grid needs a bounded height](../features/virtualization.md#the-grid-needs-a-bounded-height).
|
|
50
|
+
|
|
41
51
|
---
|
|
42
52
|
|
|
43
53
|
## Dark Mode
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
Without a provider, the grid automatically switches to its dark palette via `@media (prefers-color-scheme: dark)`. Inside a `DataGridThemeProvider` the theme decides instead: `darkTheme` (or any theme with `mode: 'dark'`) is dark and every other theme is light, whatever the operating-system setting. To follow the OS with the provider, pick the theme in your app:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
59
|
+
<DataGridThemeProvider theme={prefersDark ? darkTheme : roseTheme}>…</DataGridThemeProvider>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If your app manages dark mode manually without the provider (e.g. via a `data-theme` attribute), override the dark tokens with:
|
|
46
63
|
|
|
47
64
|
```css
|
|
48
65
|
[data-theme="dark"] {
|
|
@@ -60,20 +77,23 @@ The grid automatically switches to its dark palette via `@media (prefers-color-s
|
|
|
60
77
|
|
|
61
78
|
```ts
|
|
62
79
|
interface GridTheme {
|
|
63
|
-
|
|
80
|
+
mode?: 'light' | 'dark'; // base palette, default 'light'
|
|
81
|
+
colors?: GridThemeColors; // primary*, secondary*, success/warning/error/info, white, black, gray: { 50…900 }
|
|
64
82
|
typography?: GridThemeTypography;
|
|
65
83
|
spacing?: GridThemeSpacing;
|
|
66
84
|
borders?: GridThemeBorders;
|
|
67
85
|
shadows?: GridThemeShadows;
|
|
68
|
-
grid?: GridThemeGrid;
|
|
86
|
+
grid?: GridThemeGrid; // surfaces, heights (px), cellPaddingX/Y, cellFontSize, headerFontSize, …
|
|
69
87
|
toolbar?: GridThemeToolbar;
|
|
70
88
|
overlays?: GridThemeOverlays;
|
|
71
89
|
scrollbar?: GridThemeScrollbar;
|
|
72
|
-
skeleton?: GridThemeSkeleton;
|
|
90
|
+
skeleton?: GridThemeSkeleton; // baseColor, highlightColor
|
|
73
91
|
transitions?: GridThemeTransitions;
|
|
74
92
|
}
|
|
75
93
|
```
|
|
76
94
|
|
|
95
|
+
All sub-theme types (`GridThemeColors`, `GridThemeGrayScale`, `GridThemeTypography`, `GridThemeSpacing`, `GridThemeBorders`, `GridThemeShadows`, `GridThemeGrid`, `GridThemeToolbar`, `GridThemeOverlays`, `GridThemeScrollbar`, `GridThemeSkeleton`, `GridThemeTransitions`) are exported from the package.
|
|
96
|
+
|
|
77
97
|
---
|
|
78
98
|
|
|
79
99
|
## All CSS Tokens
|
|
@@ -110,8 +130,8 @@ interface GridTheme {
|
|
|
110
130
|
|
|
111
131
|
| Token | Default | Description |
|
|
112
132
|
|---|---|---|
|
|
113
|
-
| `--ogx-font-family` | `'Inter', system
|
|
114
|
-
| `--ogx-font-family-mono` | `'JetBrains Mono', 'Fira Code', monospace` | Monospace (code cells, IDs) |
|
|
133
|
+
| `--ogx-font-family` | `'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', …, sans-serif` | Primary UI font |
|
|
134
|
+
| `--ogx-font-family-mono` | `'JetBrains Mono', 'Fira Code', 'Courier New', Courier, monospace` | Monospace (code cells, IDs) |
|
|
115
135
|
| `--ogx-font-size-xs` | `0.75rem` (12px) | Extra-small |
|
|
116
136
|
| `--ogx-font-size-sm` | `0.875rem` (14px) | Small |
|
|
117
137
|
| `--ogx-font-size-md` | `1rem` (16px) | Medium |
|
|
@@ -165,16 +185,16 @@ interface GridTheme {
|
|
|
165
185
|
|
|
166
186
|
| Token | Default | Description |
|
|
167
187
|
|---|---|---|
|
|
168
|
-
| `--ogx-row-height` | `52px` |
|
|
169
|
-
| `--ogx-header-height` | `56px` | Column header row height |
|
|
170
|
-
| `--ogx-grid-row-height-compact` | `32px` |
|
|
171
|
-
| `--ogx-grid-row-height-standard` | `52px` |
|
|
172
|
-
| `--ogx-grid-row-height-comfortable` | `72px` |
|
|
173
|
-
| `--ogx-grid-header-height` | `56px` |
|
|
188
|
+
| `--ogx-row-height` | `52px` | Row height. The grid sets it inline on `.ogx` from the `rowHeight` / `density` props (or the provider's `grid.rowHeight*`); read it in custom CSS, don't set it. |
|
|
189
|
+
| `--ogx-header-height` | `56px` | Column header row height; set inline by the grid like `--ogx-row-height`. |
|
|
190
|
+
| `--ogx-grid-row-height-compact` | `32px` | Informational copy of the theme's `grid.rowHeightCompact`; the grid reads the theme value, not this variable |
|
|
191
|
+
| `--ogx-grid-row-height-standard` | `52px` | Informational copy of `grid.rowHeightStandard` |
|
|
192
|
+
| `--ogx-grid-row-height-comfortable` | `72px` | Informational copy of `grid.rowHeightComfortable` |
|
|
193
|
+
| `--ogx-grid-header-height` | `56px` | Informational copy of `grid.headerHeight` |
|
|
174
194
|
| `--ogx-grid-cell-padding-x` | `10px` | Horizontal cell padding |
|
|
175
195
|
| `--ogx-grid-cell-padding-y` | `8px` | Vertical cell padding |
|
|
176
|
-
| `--ogx-grid-cell-font-size` | `13px` | Body cell font size |
|
|
177
|
-
| `--ogx-grid-header-font-size` | `13px` | Header cell font size |
|
|
196
|
+
| `--ogx-grid-cell-font-size` | `13px` | Body cell font size (`grid.cellFontSize`) |
|
|
197
|
+
| `--ogx-grid-header-font-size` | `13px` | Header cell font size (`grid.headerFontSize`) |
|
|
178
198
|
| `--ogx-grid-line-height` | `var(--ogx-line-height-normal)` | Row line height |
|
|
179
199
|
|
|
180
200
|
### Grid Colors
|
|
@@ -198,6 +218,26 @@ interface GridTheme {
|
|
|
198
218
|
| `--ogx-checkbox-bg` | — | `#1e293b` | Checkbox background (dark only) |
|
|
199
219
|
| `--ogx-checkbox-border` | — | `#64748b` | Checkbox border (dark only) |
|
|
200
220
|
|
|
221
|
+
### Toolbar, Overlay and Scrollbar Colors
|
|
222
|
+
|
|
223
|
+
Read with a fallback, so a grid without a provider looks the same as before. Inside a provider they come from `toolbar.*`, `overlays.*` and `scrollbar.*`, or from the derivations described above.
|
|
224
|
+
|
|
225
|
+
| Token | Theme key | Default | Used by |
|
|
226
|
+
|---|---|---|---|
|
|
227
|
+
| `--ogx-toolbar-background` / `-text` / `-border` | `toolbar.background` / `text` / `border` | header background / header text / grid border | Toolbar bar |
|
|
228
|
+
| `--ogx-toolbar-btn-bg` / `-btn-hover` / `-btn-text` | `toolbar.buttonBackground` / `buttonHoverBackground` / `buttonText` | transparent / header hover / header text | Toolbar icon buttons |
|
|
229
|
+
| `--ogx-toolbar-btn-primary-bg` / `-hover` / `-text` | `toolbar.buttonPrimary*` | primary / primary-dark / white | Active summary pills |
|
|
230
|
+
| `--ogx-toolbar-btn-danger-bg` / `-hover` / `-text` | `toolbar.buttonDanger*` | red tints | Clear buttons |
|
|
231
|
+
| `--ogx-toolbar-input-bg` / `-text` / `-border` | `toolbar.inputBackground` / `inputText` / `inputBorder` | grid background / row text / gray-300 | Quick search |
|
|
232
|
+
| `--ogx-toolbar-input-focus-border` / `-focus-shadow` | `toolbar.inputFocus*` | primary / 12% primary | Focused quick search |
|
|
233
|
+
| `--ogx-toolbar-chip-bg` / `-text` | `toolbar.chipBackground` / `chipText` | transparent / row text | Summary pills |
|
|
234
|
+
| `--ogx-toolbar-chip-active-bg` / `-text` | `toolbar.chipActive*` | 12% primary / primary-dark | Active pills, filter chips, pivot chips |
|
|
235
|
+
| `--ogx-overlay-*` | `overlays.*` | white surface, gray border | Menus, panels, tooltips |
|
|
236
|
+
| `--ogx-overlay-item-selected-bg` / `-text` | `overlays.itemSelected*` | 8% primary / primary-dark | Selected menu item |
|
|
237
|
+
| `--ogx-overlay-item-danger-bg` / `-text` | `overlays.itemDanger*` | red tints | Remove-condition button in the filter panel |
|
|
238
|
+
| `--ogx-scrollbar-thumb` / `-track` / `-size` | `scrollbar.thumbColor` / `trackColor` / `size` | gray-300 / transparent / 8px | Grid viewport scrollbars |
|
|
239
|
+
| `--ogx-skeleton-base` / `-highlight` | `skeleton.baseColor` / `highlightColor` | light grays | Loading skeleton rows |
|
|
240
|
+
|
|
201
241
|
### Transitions
|
|
202
242
|
|
|
203
243
|
| Token | Default | Description |
|
|
@@ -247,17 +287,25 @@ You can theme the grid without the `DataGridThemeProvider` by overriding variabl
|
|
|
247
287
|
|
|
248
288
|
## Built-in Presets
|
|
249
289
|
|
|
250
|
-
OpenGridX
|
|
290
|
+
OpenGridX exports five presets as named exports:
|
|
251
291
|
|
|
252
292
|
```tsx
|
|
253
|
-
import { DataGridThemeProvider,
|
|
293
|
+
import { DataGridThemeProvider, darkTheme } from '@opencorestack/opengridx';
|
|
294
|
+
// Also: roseTheme, emeraldTheme, amberTheme, compactTheme
|
|
254
295
|
|
|
255
|
-
|
|
256
|
-
<DataGridThemeProvider theme={themes.dark}>
|
|
296
|
+
<DataGridThemeProvider theme={darkTheme}>
|
|
257
297
|
<DataGrid ... />
|
|
258
298
|
</DataGridThemeProvider>
|
|
259
299
|
```
|
|
260
300
|
|
|
301
|
+
| Preset | What it sets |
|
|
302
|
+
|---|---|
|
|
303
|
+
| `darkTheme` | `mode: 'dark'` plus a dark grid, toolbar and overlay palette |
|
|
304
|
+
| `roseTheme`, `emeraldTheme`, `amberTheme` | A brand primary colour and tinted header / selection backgrounds on the light palette |
|
|
305
|
+
| `compactTheme` | 36px rows, 40px header (28px rows with `density="compact"`), tighter cell padding and 12px cell / header text |
|
|
306
|
+
|
|
307
|
+
Presets are plain objects, so you can combine them: `theme={{ ...compactTheme, ...roseTheme, grid: { ...compactTheme.grid, ...roseTheme.grid } }}`.
|
|
308
|
+
|
|
261
309
|
---
|
|
262
310
|
|
|
263
311
|
## Example: Custom Purple Theme
|
|
@@ -21,19 +21,45 @@ Aggregation allows you to calculate summary values (Sum, Avg, etc.) for groups o
|
|
|
21
21
|
/>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
### What the footer totals
|
|
25
|
+
|
|
26
|
+
The footer (and `apiRef.current.getAggregationResult()`, and the `aggregationResult` passed to `slots.footer`) always aggregates **every data row that passes the current filter**. That holds with or without row grouping or tree data, and however many groups are expanded. Group rows show their own subtotals inline; the grand total is computed from the underlying rows, never from those subtotals. (Before v3.0 the footer aggregated the *visible* rows under grouping, so expanding a group double-counted it, and `count` / `avg` were wrong even when collapsed.)
|
|
27
|
+
|
|
28
|
+
Cells are read the way the grid shows them: a column with a `valueGetter` (for example `total = price × qty`) totals the computed values, not `row[field]`.
|
|
29
|
+
|
|
30
|
+
### Footer layout
|
|
31
|
+
|
|
32
|
+
The footer is laid out exactly like the rows: a hidden column has no footer cell, pinned columns keep their totals under the pinned column (left-pinned first, right-pinned last), and the totals stay aligned while scrolling horizontally, including when column virtualization renders only part of the columns and when the checkbox, detail-panel or row-reorder column is (or is not) pinned.
|
|
33
|
+
|
|
34
|
+
### Server-side totals
|
|
35
|
+
|
|
36
|
+
When a `dataSource` drives the rows (server or infinite pagination, server sorting, or server filtering), the grid only holds the rows the server returned, so it never totals them itself. The footer shows the `aggregationResults` returned by `getRows`, or the result of `dataSource.getAggregations`.
|
|
37
|
+
|
|
38
|
+
- A result is only shown for the request it answered: after changing the aggregation model, filter or sort, the footer shows `—` until the new totals arrive, and keeps showing `—` if that request fails (the error is logged). It never shows the previous model's or filter's totals under the new label.
|
|
39
|
+
- While a `getAggregations` request is pending the footer has `aria-busy="true"` and the class `ogx__aggregation-footer--loading`.
|
|
40
|
+
- An inline `aggregationModel={{ salary: 'sum' }}` is a new object on every render of your component. The grid compares the model by content, so re-rendering with an equal model neither refetches nor clears the totals.
|
|
41
|
+
|
|
42
|
+
If the server provides neither `aggregationResults` nor `getAggregations`, the footer shows `—`.
|
|
43
|
+
|
|
24
44
|
### Configuration
|
|
25
|
-
|
|
26
|
-
- **`
|
|
27
|
-
- **`
|
|
28
|
-
- **`null`**:
|
|
45
|
+
`getAggregationPosition(groupNode)` controls where aggregation results appear. It is called for every group node (with its current `isExpanded`) and once with `null` for the grand total:
|
|
46
|
+
- **`inline`** (default for groups): values on the group row.
|
|
47
|
+
- **`footer`**: values on a subtotal row after the group's children while the group is expanded; the group row shows none. While the group is collapsed there is no subtotal row, so the values stay on the group row. For the grand total (`null`), `'footer'` (the default) shows the footer row.
|
|
48
|
+
- **`null`**: no aggregation for that group (on screen and in `getGroupedExportRows()`); for the grand total, the footer row is hidden.
|
|
29
49
|
|
|
30
50
|
```tsx
|
|
31
51
|
<DataGrid
|
|
52
|
+
rows={rows}
|
|
53
|
+
columns={columns}
|
|
32
54
|
aggregationModel={model}
|
|
33
|
-
|
|
55
|
+
rowGroupingModel={['department']}
|
|
56
|
+
// Subtotal rows below expanded groups, inline values on collapsed ones, and the grand total.
|
|
57
|
+
getAggregationPosition={() => 'footer'}
|
|
34
58
|
/>
|
|
35
59
|
```
|
|
36
60
|
|
|
61
|
+
Group subtotals and the `(n)` count next to a group label cover only the rows that pass the filter, like the grand total; a group with no matching row is not shown.
|
|
62
|
+
|
|
37
63
|
---
|
|
38
64
|
|
|
39
65
|
## 🔄 Pivot Mode
|
|
@@ -51,29 +77,69 @@ const pivotModel: GridPivotModel = {
|
|
|
51
77
|
};
|
|
52
78
|
|
|
53
79
|
<DataGrid
|
|
80
|
+
rows={rows}
|
|
81
|
+
columns={columns}
|
|
54
82
|
pivotMode={true}
|
|
55
83
|
pivotModel={pivotModel}
|
|
56
84
|
/>
|
|
57
85
|
```
|
|
58
86
|
|
|
87
|
+
`aggFn` is a `GridPivotAggFn`: `'sum' | 'avg' | 'count' | 'min' | 'max'`. `unique` is available to `aggregationModel`, but not to pivot value fields.
|
|
88
|
+
|
|
59
89
|
### Key Concepts
|
|
60
90
|
- **Row Fields**: These become the static vertical axis of your pivot table.
|
|
61
91
|
- **Column Fields**: Unique values in these fields become new columns.
|
|
62
92
|
- **Value Fields**: The data that gets summarized at the intersection of row and column fields.
|
|
63
93
|
|
|
94
|
+
The generated value columns are named `<field>␟<aggFn>` (for example `'salary\u001fsum'`) without column fields, and `<column key>␟<field>␟<aggFn>` with them.
|
|
95
|
+
|
|
96
|
+
### Rows, filtering and sorting
|
|
97
|
+
|
|
98
|
+
- **Filtering.** Filters on source fields (including the row fields) and the quick filter are applied to the **source rows before pivoting**, so every pivot value and the Grand Total reflect them. In pivot mode the quick filter searches every filterable source column. A condition on a generated value column (for example `'salary\u001fsum' > 1000`) is applied to the pivot rows. If a filter model mixes both kinds with `logicOperator: 'or'`, each kind is applied in its own stage, so the result is as if they were joined with `and`.
|
|
99
|
+
- **Sorting** orders the pivot data rows. The Grand Total row always stays last.
|
|
100
|
+
- **Pivot row ids** are derived from the row-field values (`'__pivot_row__:["Eng"]'`, `'__pivot_row__:["North","Q1"]'` for two row fields), so they never collide with source row ids and stay the same for the same group when the data changes (v3.0+; they were `0, 1, …`).
|
|
101
|
+
- **Grand Total** is the last row (id `'__pivot_grand_total__'`). It totals the pivot rows shown, recomputed from the raw values (an average is the average of all underlying values, not of the row averages). It is not selected by the header select-all checkbox. When no source row is left, there is no Grand Total row and the no-rows overlay is shown; the value columns stay.
|
|
102
|
+
- **Row ids.** Pivot rows carry their own ids (the `'__pivot_row__:…'` ids above and the Grand Total id). Your `getRowId` is not applied to them.
|
|
103
|
+
- **Groups** are formed by each value's displayed string, as in row grouping, so `1` and `'1'` are one group. `null`, `undefined` and `''` form one blank group, labelled `null`.
|
|
104
|
+
|
|
105
|
+
### Generated columns
|
|
106
|
+
|
|
107
|
+
- **Row-label columns** keep the source column's `valueFormatter`, `renderCell`, `type`, alignment and `valueOptions` (the formatter and renderer receive a source row of that group). They always show, even if `columnVisibilityModel` hides the source column of the same field, and are `hideable: false`.
|
|
108
|
+
- **Value columns** are formatted like every other aggregate (see [Formatting Totals](#-formatting-totals)).
|
|
109
|
+
- **Column keys** are ordered by value: numbers and dates numerically, strings naturally (`'9'` before `'10'`), blanks last. Column-field header labels use the source column's `valueFormatter` (a boolean column formatted as Yes / No reads `Active: Yes — Salary (sum)`).
|
|
110
|
+
- **Column rules.** A row or column field on a `groupable: false` column is skipped (as in row grouping), and a value field on an `aggregable: false` column, or whose function the column's `availableAggregationFunctions` does not allow, is skipped. Listing the same field and function twice produces one column. The toolbar's pivot panel offers only what these rules allow and never offers an `aggregable: false` column as a value.
|
|
111
|
+
- **Column order.** The generated columns keep an order of their own: reordering them (in the header or the Columns panel) does not change your column order, and a controlled `columnOrder` (which names source columns) does not apply to them. When pivot mode is turned off, the previous column order is back.
|
|
112
|
+
|
|
113
|
+
### Not combined with pivot mode
|
|
114
|
+
|
|
115
|
+
- **Tree data and row grouping** are turned off while pivoting (the pivot rows are already grouped by the row fields). A development warning says so.
|
|
116
|
+
- **`dataSource`**: pivoting is client-side, and a server-driven grid only holds one page of rows, so `pivotMode` is ignored when a `dataSource` is set (development warning). Pivot on the server, or pass the full dataset as `rows`.
|
|
117
|
+
- **`aggregationModel`**: the footer is not shown, `apiRef.current.getAggregationResult()` returns `null` and `slots.footer` receives `aggregationResult: null`; the Grand Total row is the pivot's aggregate. The toolbar's Summaries panel does not list generated pivot columns.
|
|
118
|
+
|
|
64
119
|
---
|
|
65
120
|
|
|
66
121
|
## ⚙️ Aggregation Functions
|
|
67
122
|
|
|
68
|
-
Built-in functions available:
|
|
123
|
+
Built-in functions available (the same functions drive the footer, group rows, pivot and exports):
|
|
69
124
|
- `sum`: Total of numeric values.
|
|
70
125
|
- `avg`: Arithmetic mean.
|
|
71
126
|
- `min`: Smallest value.
|
|
72
127
|
- `max`: Largest value.
|
|
73
|
-
- `count`: Number of
|
|
74
|
-
- `unique`: Number of
|
|
128
|
+
- `count`: Number of non-empty values.
|
|
129
|
+
- `unique`: Number of distinct non-empty values.
|
|
130
|
+
|
|
131
|
+
`sum`, `avg`, `min` and `max` use numbers, numeric strings and dates. Empty values (`null`, `undefined`, and strings that are empty or only whitespace), booleans and other values are ignored, so a blank cell never counts as `0`. `count` and `unique` ignore empty values too. `min` and `max` of dates return the date itself.
|
|
132
|
+
|
|
133
|
+
The toolbar's Summaries panel offers these for each aggregable column, or only the ones listed in the column's `availableAggregationFunctions`. The same rules bind `aggregationModel` itself: an entry for an `aggregable: false` column, or with a function the column does not allow, is ignored by the footer, group rows and exports.
|
|
75
134
|
|
|
76
135
|
---
|
|
77
136
|
|
|
78
137
|
## 🎨 Formatting Totals
|
|
79
|
-
|
|
138
|
+
|
|
139
|
+
The footer, group rows, pivot value cells and every export format aggregates the same way:
|
|
140
|
+
|
|
141
|
+
- `sum`, `avg`, `min` and `max` go through the column's `valueFormatter`, so totals keep the column's currency, unit or percent format. The formatter's `row` is the record of aggregated values: the footer totals, the group row, or the pivot row. A formatter that throws (typically because it reads row data an aggregate does not have) falls back to the default format instead of breaking the grid.
|
|
142
|
+
- `count` and `unique` are plain counts: the column's `valueFormatter` is not applied (a count of a currency column is not an amount).
|
|
143
|
+
- Without a formatter, numbers are locale-formatted (`avg` to at most two decimals) and dates show as locale dates.
|
|
144
|
+
|
|
145
|
+
Exports follow the same rules; see [Aggregate values](export-guide.md#aggregate-values). Use `formatAggregationValue(value, fnName)` for the default number formatting elsewhere.
|