@opencorestack/opengridx 2.0.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +408 -3
- package/README.md +93 -72
- package/dist/index.d.ts +611 -121
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7992 -5650
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +17 -23
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +348 -161
- package/docs/README.md +6 -1
- package/docs/architecture/datagrid-orchestration.md +81 -0
- package/docs/architecture/grid-row-meta.md +102 -0
- package/docs/architecture/use-grid-columns.md +128 -0
- package/docs/architecture/use-grid-controlled-state.md +157 -0
- package/docs/architecture/use-grid-row-pipeline.md +120 -0
- package/docs/architecture/use-grid-scroll-sync.md +111 -0
- package/docs/architecture/use-grid-state-snapshot.md +90 -0
- package/docs/architecture/use-grid-virtualization.md +115 -0
- package/docs/architecture/use-grid-visible-rows.md +85 -0
- package/docs/assets/banner-alt.png +0 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/hero.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/components/aggregation-footer.md +15 -10
- package/docs/components/cell.md +16 -6
- package/docs/components/column-group-header.md +55 -28
- package/docs/components/column-resize.md +17 -13
- package/docs/components/column-visibility.md +45 -22
- package/docs/components/datagrid.md +14 -12
- package/docs/components/empty-state.md +2 -1
- package/docs/components/error-overlay.md +12 -7
- package/docs/components/filter-panel.md +28 -8
- package/docs/components/header.md +28 -9
- package/docs/components/pagination.md +14 -8
- package/docs/components/row.md +21 -5
- package/docs/components/toolbar.md +27 -9
- package/docs/components/tooltip.md +16 -7
- package/docs/customization/slots-api.md +100 -36
- package/docs/customization/theming.md +66 -18
- package/docs/features/aggregation-pivot.md +75 -9
- package/docs/features/cell-spanning.md +80 -125
- package/docs/features/clipboard.md +41 -16
- package/docs/features/custom-pagination.md +38 -18
- package/docs/features/data-source.md +36 -13
- package/docs/features/editing-reordering.md +125 -16
- package/docs/features/export-guide.md +147 -41
- package/docs/features/filtering.md +44 -6
- package/docs/features/infinite-scroll.md +54 -46
- package/docs/features/keyboard-navigation.md +83 -0
- package/docs/features/list-view.md +58 -5
- package/docs/features/loading-states.md +18 -20
- package/docs/features/master-detail.md +18 -5
- package/docs/features/pdf-export.md +56 -19
- package/docs/features/pinning.md +23 -5
- package/docs/features/selection.md +50 -10
- package/docs/features/sorting-pagination.md +66 -14
- package/docs/features/state-persistence.md +78 -10
- package/docs/features/toolbar-customization.md +26 -17
- package/docs/features/tree-data-grouping.md +44 -9
- package/docs/features/virtualization.md +64 -15
- package/docs/migration/v1-to-v2.md +115 -0
- package/docs/migration/v2-to-v3.md +1222 -0
- package/docs/performance.md +124 -0
- package/docs/roadmap.md +16 -10
- package/lib/components/Cell/Cell.css +13 -1
- package/lib/components/Cell/Cell.tsx +130 -57
- package/lib/components/Cell/CellErrorBoundary.tsx +12 -6
- package/lib/components/Cell/GridEditInputCell.tsx +114 -41
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +7 -1
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +11 -0
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +104 -38
- package/lib/components/ColumnResizeHandle/clampResizeWidth.ts +13 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +6 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +21 -13
- package/lib/components/DataGrid/DataGrid.css +84 -12
- package/lib/components/DataGrid/DataGrid.tsx +606 -872
- package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
- package/lib/components/DataGrid/GridEmptyState.tsx +7 -1
- package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
- package/lib/components/DataGrid/GridListView.tsx +166 -23
- package/lib/components/DataGrid/GridLiveRegion.tsx +31 -0
- package/lib/components/DataGrid/GridLoadingOverlay.tsx +27 -0
- package/lib/components/DataGrid/GridPaginationArea.tsx +44 -0
- package/lib/components/DataGrid/GridPinnedRows.tsx +65 -11
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
- package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
- package/lib/components/DataGrid/GridVirtualRows.tsx +48 -25
- package/lib/components/DetailPanel/DetailPanel.css +0 -6
- package/lib/components/DetailPanel/DetailPanel.tsx +34 -5
- package/lib/components/DetailPanel/DetailPanelContent.tsx +17 -0
- package/lib/components/FilterPanel/FilterPanel.css +13 -2
- package/lib/components/FilterPanel/FilterPanel.tsx +272 -99
- package/lib/components/Header/ColumnMenu.tsx +91 -39
- package/lib/components/Header/Header.css +3 -3
- package/lib/components/Header/Header.tsx +179 -160
- package/lib/components/ListView/ListView.css +25 -0
- package/lib/components/ListView/ListViewRow.tsx +79 -10
- package/lib/components/Pagination/Pagination.tsx +15 -7
- package/lib/components/Row/Row.tsx +185 -75
- package/lib/components/Toolbar/GlobalSearch.css +6 -3
- package/lib/components/Toolbar/GlobalSearch.tsx +26 -27
- package/lib/components/Toolbar/GridToolbar.css +12 -11
- package/lib/components/Toolbar/GridToolbar.tsx +133 -89
- package/lib/components/Toolbar/PivotPanel.tsx +89 -49
- package/lib/components/Tooltip/Tooltip.css +20 -0
- package/lib/components/Tooltip/Tooltip.tsx +68 -35
- package/lib/components/ui/Button.tsx +3 -0
- package/lib/components/ui/Checkbox.tsx +2 -1
- package/lib/components/ui/ExpandIcon.css +0 -9
- package/lib/components/ui/ExpandIcon.tsx +4 -1
- package/lib/hooks/core/gridApiPlaceholder.ts +34 -0
- package/lib/hooks/core/gridToolbarHostContext.ts +14 -0
- package/lib/hooks/core/useDataGrid.ts +115 -173
- package/lib/hooks/core/useGridAggregationApi.ts +72 -0
- package/lib/hooks/core/useGridApiMethods.ts +115 -0
- package/lib/hooks/core/useGridApiRef.ts +15 -3
- package/lib/hooks/core/useGridApiRefBinding.ts +18 -0
- package/lib/hooks/core/useGridAriaRows.ts +38 -0
- package/lib/hooks/core/useGridClipboardApi.ts +38 -0
- package/lib/hooks/core/useGridColumnLookup.ts +30 -0
- package/lib/hooks/core/useGridColumns.tsx +284 -76
- package/lib/hooks/core/useGridColumnsPanel.ts +77 -0
- package/lib/hooks/core/useGridControlledState.ts +99 -6
- package/lib/hooks/core/useGridDetailPanel.ts +51 -0
- package/lib/hooks/core/useGridDevWarnings.ts +123 -0
- package/lib/hooks/core/useGridFocusHandlers.ts +50 -0
- package/lib/hooks/core/useGridGroupingColumn.ts +62 -0
- package/lib/hooks/core/useGridHeaderHandlers.ts +92 -0
- package/lib/hooks/core/useGridHierarchy.ts +81 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +452 -250
- package/lib/hooks/core/useGridLiveRowSelection.ts +67 -0
- package/lib/hooks/core/useGridPageCorrection.ts +55 -0
- package/lib/hooks/core/useGridRowIdOf.ts +32 -0
- package/lib/hooks/core/useGridRowInteractions.ts +81 -0
- package/lib/hooks/core/useGridRowPipeline.ts +69 -39
- package/lib/hooks/core/useGridRowSelection.ts +91 -0
- package/lib/hooks/core/useGridScrollSync.ts +80 -32
- package/lib/hooks/core/useGridScrollToIndexesApi.ts +45 -0
- package/lib/hooks/core/useGridStateSnapshot.ts +40 -5
- package/lib/hooks/core/useGridThemeDimensions.ts +49 -0
- package/lib/hooks/core/useGridToolbarProps.ts +97 -0
- package/lib/hooks/core/useGridViewport.ts +38 -0
- package/lib/hooks/core/useGridViewportSize.ts +26 -0
- package/lib/hooks/core/useGridVisibleRows.ts +20 -7
- package/lib/hooks/core/useLayout.ts +215 -195
- package/lib/hooks/core/useRowsScrollEndLatch.ts +41 -0
- package/lib/hooks/core/useStableColumns.ts +34 -0
- package/lib/hooks/features/useAggregation.ts +86 -90
- package/lib/hooks/features/useColumnGroupReorderGuard.ts +34 -0
- package/lib/hooks/features/useDetailPanelHeights.ts +29 -0
- package/lib/hooks/features/useGridClipboard.ts +133 -73
- package/lib/hooks/features/useGridDataSource.ts +354 -128
- package/lib/hooks/features/useGridEditing.ts +211 -51
- package/lib/hooks/features/useGridPivot.ts +92 -0
- package/lib/hooks/features/useGridSpanRenderWindow.ts +104 -0
- package/lib/hooks/features/useGridSpanning.ts +410 -306
- package/lib/hooks/features/usePivot.ts +0 -0
- package/lib/hooks/features/useServerTreeChildren.ts +50 -0
- package/lib/hooks/useColumnReorder.ts +38 -44
- package/lib/hooks/useRowGrouping.ts +335 -214
- package/lib/hooks/useRowReorder.ts +62 -31
- package/lib/hooks/useTreeData.ts +330 -262
- package/lib/index.ts +30 -2
- package/lib/state/index.ts +1 -0
- package/lib/state/types.ts +7 -1
- package/lib/state/useGridStateStorage.ts +88 -29
- package/lib/theme/DataGridThemeProvider.tsx +143 -38
- package/lib/theme/gridThemeContext.ts +5 -0
- package/lib/theme/index.ts +5 -0
- package/lib/theme/presets.ts +5 -4
- package/lib/theme/types.ts +40 -2
- package/lib/types/index.ts +311 -108
- package/lib/utils/aggregation/index.ts +157 -0
- package/lib/utils/aria/index.ts +40 -0
- package/lib/utils/columnGroups.ts +110 -0
- package/lib/utils/columnLookup.ts +33 -0
- package/lib/utils/columnWidth.ts +22 -0
- package/lib/utils/dataSource/index.ts +46 -0
- package/lib/utils/detailPanel.ts +66 -0
- package/lib/utils/dragData.ts +44 -0
- package/lib/utils/editing/index.ts +30 -0
- package/lib/utils/export/exportShared.ts +197 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +344 -121
- package/lib/utils/export/exportToPdf.ts +143 -92
- package/lib/utils/export/groupLabel.ts +14 -0
- package/lib/utils/export/index.ts +278 -272
- package/lib/utils/export/pdfText.ts +50 -0
- package/lib/utils/filtering/index.ts +277 -148
- package/lib/utils/focus/index.ts +115 -0
- package/lib/utils/gridApiRows.ts +35 -0
- package/lib/utils/gridModes.ts +77 -0
- package/lib/utils/grouping/groupedExportRows.ts +91 -0
- package/lib/utils/pagination/index.ts +56 -0
- package/lib/utils/pinning/index.ts +77 -33
- package/lib/utils/pivot/index.ts +368 -0
- package/lib/utils/scroll/index.ts +78 -0
- package/lib/utils/scroll/scrollEnd.ts +18 -0
- package/lib/utils/sorting/index.ts +154 -30
- package/lib/utils/syntheticRows.ts +12 -0
- package/lib/utils/values.ts +206 -0
- package/lib/utils/viewport.ts +14 -0
- package/llms.txt +272 -166
- package/package.json +18 -6
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
- package/lib/components/DataGrid/DataGrid.regression.test.tsx +0 -132
- package/lib/components/DataGrid/DataGrid.smoke.test.tsx +0 -58
- package/lib/components/DataGrid/DataGrid.v2.test.tsx +0 -127
- package/lib/components/Header/Header.test.tsx +0 -135
- package/lib/components/Pagination/Pagination.test.tsx +0 -64
- package/lib/hooks/core/useDataGrid.regression.test.ts +0 -66
- package/lib/hooks/core/useGridControlledState.test.ts +0 -86
- package/lib/hooks/core/useGridKeyboardNavigation.test.ts +0 -176
- package/lib/hooks/core/useGridRowPipeline.test.ts +0 -117
- package/lib/hooks/features/useAggregation.test.ts +0 -175
- package/lib/hooks/features/usePivot.test.ts +0 -202
- package/lib/hooks/useRowGrouping.test.ts +0 -137
- package/lib/utils/export/exportToPdf.test.ts +0 -120
- package/lib/utils/export/groupedExport.test.ts +0 -144
- package/lib/utils/filtering/filtering.test.ts +0 -178
- package/lib/utils/sorting/sorting.test.ts +0 -88
|
@@ -1,51 +1,90 @@
|
|
|
1
|
-
import React, { useRef,
|
|
1
|
+
import React, { useRef, useMemo } from 'react';
|
|
2
2
|
import { useLayout } from '../../hooks/core/useLayout';
|
|
3
3
|
import { useGridKeyboardNavigation } from '../../hooks/core/useGridKeyboardNavigation';
|
|
4
4
|
import { useGridControlledState } from '../../hooks/core/useGridControlledState';
|
|
5
|
-
import {
|
|
5
|
+
import { useGridThemeDimensions } from '../../hooks/core/useGridThemeDimensions';
|
|
6
|
+
import { useGridRowPipeline, type GridRowPipelineResult } from '../../hooks/core/useGridRowPipeline';
|
|
6
7
|
import { useGridVirtualization } from '../../hooks/core/useGridVirtualization';
|
|
7
8
|
import { useGridColumns } from '../../hooks/core/useGridColumns';
|
|
8
9
|
import { useGridVisibleRows } from '../../hooks/core/useGridVisibleRows';
|
|
9
|
-
import {
|
|
10
|
+
import { useGridViewport } from '../../hooks/core/useGridViewport';
|
|
11
|
+
import { useGridDetailPanel } from '../../hooks/core/useGridDetailPanel';
|
|
10
12
|
import { useGridStateSnapshot } from '../../hooks/core/useGridStateSnapshot';
|
|
13
|
+
import { useGridDevWarnings, useGridStylesheetWarning } from '../../hooks/core/useGridDevWarnings';
|
|
14
|
+
import { useGridRowInteractions } from '../../hooks/core/useGridRowInteractions';
|
|
15
|
+
import { useGridLiveRowSelection } from '../../hooks/core/useGridLiveRowSelection';
|
|
16
|
+
import { useGridApiMethods } from '../../hooks/core/useGridApiMethods';
|
|
17
|
+
import { useGridColumnLookup } from '../../hooks/core/useGridColumnLookup';
|
|
18
|
+
import { useGridPageCorrection } from '../../hooks/core/useGridPageCorrection';
|
|
19
|
+
import { useGridColumnsPanel } from '../../hooks/core/useGridColumnsPanel';
|
|
20
|
+
import { GridToolbarHostContext } from '../../hooks/core/gridToolbarHostContext';
|
|
21
|
+
import { GridToolbarSlot } from './GridToolbarSlot';
|
|
11
22
|
import { GridAggregationFooter } from './GridAggregationFooter';
|
|
12
23
|
import { GridEmptyState } from './GridEmptyState';
|
|
13
24
|
import { GridErrorOverlay } from './GridErrorOverlay';
|
|
14
25
|
import { Header } from '../Header/Header';
|
|
15
|
-
import { Pagination } from '../Pagination/Pagination';
|
|
16
26
|
import { useDataGrid } from '../../hooks/core/useDataGrid';
|
|
17
27
|
import { useRowReorder } from '../../hooks/useRowReorder';
|
|
18
|
-
import {
|
|
19
|
-
import { useRowGrouping } from '../../hooks/useRowGrouping';
|
|
28
|
+
import { useGridHierarchy } from '../../hooks/core/useGridHierarchy';
|
|
20
29
|
import { useGridEditing } from '../../hooks/features/useGridEditing';
|
|
21
30
|
import { useGridSpanning } from '../../hooks/features/useGridSpanning';
|
|
31
|
+
import { useGridSpanRowWindow, useGridSpanColumnWindow } from '../../hooks/features/useGridSpanRenderWindow';
|
|
32
|
+
import { useColumnGroupReorderGuard } from '../../hooks/features/useColumnGroupReorderGuard';
|
|
22
33
|
import { useGridDataSource } from '../../hooks/features/useGridDataSource';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
34
|
+
import { useServerTreeChildren } from '../../hooks/features/useServerTreeChildren';
|
|
35
|
+
import { useAggregation, useServerAggregationResults } from '../../hooks/features/useAggregation';
|
|
36
|
+
import { useGridPivot } from '../../hooks/features/useGridPivot';
|
|
37
|
+
import { isServerDrivenDataSource } from '../../utils/dataSource';
|
|
26
38
|
import { GridListView } from './GridListView';
|
|
39
|
+
import { GridLoadingOverlay } from './GridLoadingOverlay';
|
|
27
40
|
import { GridPinnedRows } from './GridPinnedRows';
|
|
28
41
|
import { GridVirtualRows } from './GridVirtualRows';
|
|
29
42
|
import { GridStandaloneColumnPanel } from './GridStandaloneColumnPanel';
|
|
30
|
-
import
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
import { resolveGridModes, EMPTY_ROW_GROUPING_MODEL } from '../../utils/gridModes';
|
|
44
|
+
import { useGridGroupingColumn } from '../../hooks/core/useGridGroupingColumn';
|
|
45
|
+
import { useGridRowIdOf, getDefaultRowId } from '../../hooks/core/useGridRowIdOf';
|
|
46
|
+
import { useGridApiRefBinding } from '../../hooks/core/useGridApiRefBinding';
|
|
47
|
+
import { collectAllFilteredRows } from '../../utils/gridApiRows';
|
|
48
|
+
import { NO_AGGREGATION_MODEL } from '../../utils/aggregation';
|
|
49
|
+
import { isSyntheticRowId } from '../../utils/syntheticRows';
|
|
50
|
+
import { useStableColumns } from '../../hooks/core/useStableColumns';
|
|
51
|
+
import { useGridAggregationApi } from '../../hooks/core/useGridAggregationApi';
|
|
52
|
+
import { useGridClipboardApi } from '../../hooks/core/useGridClipboardApi';
|
|
53
|
+
import { useGridScrollToIndexesApi } from '../../hooks/core/useGridScrollToIndexesApi';
|
|
54
|
+
import { useGridSortHandlers, useGridColumnMenuHandlers } from '../../hooks/core/useGridHeaderHandlers';
|
|
55
|
+
import { useGridKeyboardMode, useGridPointerFocusHandlers } from '../../hooks/core/useGridFocusHandlers';
|
|
56
|
+
import { getPaginationRowCount, pickPaginationLocaleText } from '../../utils/pagination';
|
|
57
|
+
import { GridPaginationArea } from './GridPaginationArea';
|
|
58
|
+
import { GridLiveRegion } from './GridLiveRegion';
|
|
59
|
+
import { useGridAriaRows } from '../../hooks/core/useGridAriaRows';
|
|
60
|
+
import { useGridToolbarProps } from '../../hooks/core/useGridToolbarProps';
|
|
61
|
+
import type { DataGridProps, DataGridUntypedColumnsProps, GridValidRowModel, GridRowModel, GridRowId, GridColDef } from '../../types';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The grid. `R` is your row type: any object type (an interface works), inferred from `rows`. `columns`
|
|
65
|
+
* can be typed for it (`GridColDef<R>[]`, so callbacks see `params.row` as `R`) or untyped (`GridColDef[]`).
|
|
66
|
+
*/
|
|
67
|
+
export function DataGrid<R extends GridValidRowModel = GridRowModel>(props: DataGridProps<R>): React.JSX.Element;
|
|
68
|
+
export function DataGrid<R extends GridValidRowModel = GridRowModel>(props: DataGridUntypedColumnsProps<R>): React.JSX.Element;
|
|
69
|
+
// Internally every row is read as a GridRowModel (a record keyed by field): the overloads above are the
|
|
70
|
+
// public signatures, and a consumer's row objects are passed through untouched.
|
|
71
|
+
export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridProps<R>): React.JSX.Element {
|
|
35
72
|
const {
|
|
36
73
|
rows,
|
|
37
|
-
columns,
|
|
74
|
+
columns: columnsProp,
|
|
38
75
|
getRowId,
|
|
39
|
-
rowHeight
|
|
40
|
-
headerHeight
|
|
76
|
+
rowHeight: rowHeightProp,
|
|
77
|
+
headerHeight: headerHeightProp,
|
|
41
78
|
autoHeight = false,
|
|
42
79
|
density,
|
|
43
80
|
checkboxSelection = false,
|
|
44
81
|
disableRowSelectionOnClick = false,
|
|
45
82
|
disableMultipleRowSelection = false,
|
|
83
|
+
disableClipboardCopy = false,
|
|
46
84
|
rowSelectionModel: propRowSelectionModel,
|
|
47
85
|
onRowSelectionModelChange: propOnRowSelectionModelChange,
|
|
48
86
|
onRowClick,
|
|
87
|
+
onRowDoubleClick,
|
|
49
88
|
onCellClick,
|
|
50
89
|
|
|
51
90
|
filterModel: propFilterModel,
|
|
@@ -69,8 +108,9 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
69
108
|
disableColumnReorder = false,
|
|
70
109
|
columnOrder,
|
|
71
110
|
onColumnOrderChange,
|
|
111
|
+
onColumnOrderModelChange,
|
|
72
112
|
height,
|
|
73
|
-
rowReordering = false,
|
|
113
|
+
rowReordering: rowReorderingProp = false,
|
|
74
114
|
onRowOrderChange,
|
|
75
115
|
loading = false,
|
|
76
116
|
|
|
@@ -112,7 +152,7 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
112
152
|
// Column Visibility
|
|
113
153
|
columnVisibilityModel: propColumnVisibilityModel,
|
|
114
154
|
onColumnVisibilityModelChange,
|
|
115
|
-
listView = false,
|
|
155
|
+
listView: listViewRequested = false,
|
|
116
156
|
listViewColumn,
|
|
117
157
|
columnGroupingModel,
|
|
118
158
|
noRowsLabel = 'No Data',
|
|
@@ -120,46 +160,18 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
120
160
|
apiRef: propApiRef,
|
|
121
161
|
overscanRowCount = 3,
|
|
122
162
|
} = props;
|
|
163
|
+
// Equal inline column definitions keep one identity, so the row passes memoised on it do not re-run.
|
|
164
|
+
const columns = useStableColumns(columnsProp);
|
|
123
165
|
|
|
124
166
|
const effectiveNoRowsLabel = localeText?.noRowsLabel ?? noRowsLabel;
|
|
125
|
-
|
|
126
|
-
// Stable defaults
|
|
127
|
-
const defaultFilterModel: GridFilterModel = useMemo(() => ({ items: [] }), []);
|
|
128
|
-
const filterModel = (propFilterModel || defaultFilterModel) as GridFilterModel;
|
|
129
|
-
|
|
130
|
-
const defaultRowGroupingModel = useMemo(() => [], []);
|
|
131
|
-
const rowGroupingModel = propRowGroupingModel || defaultRowGroupingModel;
|
|
132
|
-
|
|
133
|
-
// ─── Stabilize toolbar component identity ────────────────────────────────
|
|
134
|
-
// Problem: demos/users often define their toolbar as an inline function
|
|
135
|
-
// INSIDE their component body, e.g.:
|
|
136
|
-
// const MyToolbar = (props) => <GridToolbar {...props} /> // inside render!
|
|
137
|
-
// This creates a NEW function reference on every parent re-render. React
|
|
138
|
-
// reconciles by component *identity*, so a new reference = unmount old
|
|
139
|
-
// toolbar + mount fresh one = all toolbar state (search expansion, filter
|
|
140
|
-
// open, typed text) is destroyed on every keystroke.
|
|
141
|
-
//
|
|
142
|
-
// Fix: a stable wrapper component created ONCE via useRef. Its identity
|
|
143
|
-
// never changes, so React keeps it mounted. It reads the latest toolbar
|
|
144
|
-
// from a separate ref that is updated on every render, so the rendered
|
|
145
|
-
// output is always current — zero stale closures.
|
|
146
|
-
const latestToolbarRef = useRef(slots?.toolbar);
|
|
147
|
-
latestToolbarRef.current = slots?.toolbar;
|
|
148
|
-
// The wrapper itself has a stable identity (created once via useRef).
|
|
149
|
-
// We call latestToolbarRef.current(props) as a PLAIN FUNCTION — not via
|
|
150
|
-
// React.createElement — so React never sees a changing component type.
|
|
151
|
-
// The elements the toolbar function returns are reconciled normally, so
|
|
152
|
-
// GridToolbar's internal state (filterOpen, search expansion) is preserved
|
|
153
|
-
// even when the toolbar is defined as an inline function inside the parent.
|
|
154
|
-
const StableToolbar = useRef((props: Record<string, unknown>) => {
|
|
155
|
-
const Toolbar = latestToolbarRef.current;
|
|
156
|
-
return Toolbar ? (Toolbar as (p: typeof props) => React.ReactElement | null)(props) : null;
|
|
157
|
-
}).current;
|
|
167
|
+
const rowGroupingModel = propRowGroupingModel || EMPTY_ROW_GROUPING_MODEL;
|
|
158
168
|
|
|
159
169
|
const controlledState = useGridControlledState({
|
|
160
170
|
initialState,
|
|
161
171
|
sortModel: propSortModel,
|
|
162
172
|
onSortModelChange,
|
|
173
|
+
filterModel: propFilterModel,
|
|
174
|
+
onFilterModelChange,
|
|
163
175
|
aggregationModel: propAggregationModel,
|
|
164
176
|
onAggregationModelChange,
|
|
165
177
|
columnVisibilityModel: propColumnVisibilityModel,
|
|
@@ -167,161 +179,93 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
167
179
|
pinnedColumns: propPinnedColumns,
|
|
168
180
|
onPinnedColumnsChange,
|
|
169
181
|
pivotModel: propPivotModel,
|
|
170
|
-
onPivotModelChange,
|
|
171
|
-
paginationModel,
|
|
172
|
-
onPaginationModelChange,
|
|
182
|
+
onPivotModelChange, paginationModel, onPaginationModelChange, pageSizeOptions,
|
|
173
183
|
rowSelectionModel: propRowSelectionModel,
|
|
174
184
|
onRowSelectionModelChange: propOnRowSelectionModelChange,
|
|
185
|
+
density,
|
|
175
186
|
});
|
|
176
187
|
|
|
177
188
|
const {
|
|
178
|
-
sortModel,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
pinnedColumns,
|
|
186
|
-
handlePinnedColumnsChange,
|
|
187
|
-
currentPivotModel,
|
|
188
|
-
handlePivotModelChange,
|
|
189
|
-
effectivePaginationModel,
|
|
190
|
-
handlePaginationModelChange,
|
|
191
|
-
selectedRowIds,
|
|
192
|
-
isSelectionControlled,
|
|
193
|
-
setInternalRowSelectionModel,
|
|
189
|
+
sortModel, handleSortModelChange, filterModel,
|
|
190
|
+
handleFilterModelChange, aggregationModel, handleAggregationModelChange, columnVisibilityModel,
|
|
191
|
+
handleColumnVisibilityModelChange, pinnedColumns, handlePinnedColumnsChange, currentPivotModel,
|
|
192
|
+
handlePivotModelChange, effectivePaginationModel, handlePaginationModelChange,
|
|
193
|
+
selectedRowIds: selectionModelRowIds,
|
|
194
|
+
handleRowSelectionModelChange,
|
|
195
|
+
density: effectiveDensity,
|
|
194
196
|
} = controlledState;
|
|
195
197
|
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
(
|
|
221
|
-
|
|
222
|
-
{
|
|
223
|
-
headerName: 'Group',
|
|
224
|
-
width: 220,
|
|
225
|
-
...groupingColDef,
|
|
226
|
-
field: '__group__',
|
|
227
|
-
hideable: false,
|
|
228
|
-
sortable: false,
|
|
229
|
-
pinnable: false,
|
|
230
|
-
exportable: false,
|
|
231
|
-
} as unknown as GridColDef<R>,
|
|
232
|
-
...baseColumns,
|
|
233
|
-
]
|
|
234
|
-
: baseColumns
|
|
235
|
-
), [groupingColDef, isRowGroupingActive, pivotMode, baseColumns]);
|
|
236
|
-
|
|
237
|
-
const [serverAggregationResults, setServerAggregationResults] = useState<GridAggregationResult | null>(null);
|
|
238
|
-
|
|
239
|
-
useEffect(() => {
|
|
240
|
-
setServerAggregationResults(null);
|
|
241
|
-
}, [aggregationModel]);
|
|
198
|
+
const pivot = useGridPivot({
|
|
199
|
+
rows: rows as GridRowModel[],
|
|
200
|
+
columns: columns as unknown as GridColDef[],
|
|
201
|
+
pivotMode,
|
|
202
|
+
pivotModel: currentPivotModel,
|
|
203
|
+
filterModel,
|
|
204
|
+
sortModel,
|
|
205
|
+
hasDataSource: Boolean(dataSource),
|
|
206
|
+
hierarchyRequested: treeData || rowGroupingModel.length > 0,
|
|
207
|
+
});
|
|
208
|
+
const isPivotActive = pivot.isActive;
|
|
209
|
+
const {
|
|
210
|
+
rowReordering, hierarchyRowGroupingModel, isTreeDataRequested, isTreeData,
|
|
211
|
+
isRowGrouping, isHierarchyEnabled, hasGroupingColumn, pagination, listView,
|
|
212
|
+
} = resolveGridModes({
|
|
213
|
+
rowGroupingModel,
|
|
214
|
+
treeData,
|
|
215
|
+
hasTreeDataPath: Boolean(getTreeDataPath),
|
|
216
|
+
isPivotActive,
|
|
217
|
+
rowReordering: rowReorderingProp,
|
|
218
|
+
hasGroupingColDef: Boolean(groupingColDef),
|
|
219
|
+
pagination: propPagination,
|
|
220
|
+
paginationMode,
|
|
221
|
+
listView: listViewRequested,
|
|
222
|
+
hasListViewColumn: Boolean(listViewColumn),
|
|
223
|
+
});
|
|
242
224
|
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const defaultGetRowId = useCallback((row: R) => row.id, []);
|
|
248
|
-
const effectiveGetRowId = getRowId || defaultGetRowId;
|
|
249
|
-
|
|
250
|
-
// Normalize rows so every row has `id === getRowId(row)`.
|
|
251
|
-
// createInitialState and SET_ROWS both key the internal store by row.id,
|
|
252
|
-
// so rows without a native id field collide on undefined without this.
|
|
253
|
-
// When getRowId is the default (row) => row.id this is a no-op per row.
|
|
254
|
-
const normalizedRows = useMemo(
|
|
255
|
-
() => activeRows.map(row => {
|
|
256
|
-
const id = effectiveGetRowId(row);
|
|
257
|
-
return id === row.id ? row : ({ ...row, id } as R);
|
|
258
|
-
}),
|
|
259
|
-
[activeRows, effectiveGetRowId]
|
|
260
|
-
);
|
|
225
|
+
// Props, then the enclosing DataGridThemeProvider's heights, then the defaults (52 / 56).
|
|
226
|
+
const { rowHeight: effectiveRowHeight, headerHeight } = useGridThemeDimensions({
|
|
227
|
+
rowHeight: rowHeightProp, headerHeight: headerHeightProp, density: effectiveDensity,
|
|
228
|
+
});
|
|
261
229
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const setKeyboardMode = useCallback((on: boolean) => {
|
|
265
|
-
containerRef.current?.classList.toggle('ogx--kb', on);
|
|
266
|
-
}, []);
|
|
230
|
+
const activeRows = pivot.rows as unknown as R[];
|
|
231
|
+
const baseColumns = pivot.columns as unknown as GridColDef<R>[];
|
|
267
232
|
|
|
268
|
-
const
|
|
269
|
-
|
|
233
|
+
const { activeColumns, effectivePinnedColumns } = useGridGroupingColumn<R>({
|
|
234
|
+
baseColumns, pinnedColumns, hasGroupingColumn, groupingColDef, isTreeData, getTreeDataPath,
|
|
235
|
+
});
|
|
270
236
|
|
|
271
|
-
const
|
|
272
|
-
const treeDataRef = useRef<ReturnType<typeof useTreeData> | null>(null);
|
|
237
|
+
const columnLookup = useGridColumnLookup(activeColumns, columnVisibilityModel);
|
|
273
238
|
|
|
274
|
-
|
|
275
|
-
|
|
239
|
+
// getRows-provided totals, dropped as soon as the aggregation model they were computed for changes.
|
|
240
|
+
const [serverAggregationResults, setServerAggregationResults] = useServerAggregationResults(aggregationModel);
|
|
276
241
|
|
|
277
|
-
|
|
242
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
243
|
+
const viewportRef = useRef<HTMLDivElement>(null);
|
|
244
|
+
|
|
245
|
+
// Rows are stored and handed to consumers untouched: getRowId only decides the internal
|
|
246
|
+
// key. Pivot rows are the grid's own and carry their own ids, so a getRowId written for
|
|
247
|
+
// the source rows does not apply to them.
|
|
248
|
+
const effectiveGetRowId = (!isPivotActive && getRowId) || getDefaultRowId;
|
|
278
249
|
|
|
279
|
-
|
|
280
|
-
fetchChildrenRef.current?.(node.id, groupKeys);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}, [treeData]);
|
|
250
|
+
const setKeyboardMode = useGridKeyboardMode(containerRef);
|
|
284
251
|
|
|
285
252
|
const gridData = useDataGrid({
|
|
286
|
-
rows:
|
|
253
|
+
rows: activeRows,
|
|
254
|
+
getRowId: effectiveGetRowId,
|
|
287
255
|
columns: activeColumns,
|
|
288
256
|
rowHeight: effectiveRowHeight,
|
|
289
257
|
headerHeight,
|
|
290
|
-
rowCount: propRowCount,
|
|
291
258
|
columnVisibilityModel,
|
|
292
|
-
initialState: props.initialState
|
|
259
|
+
initialState: props.initialState,
|
|
260
|
+
syncRows: !dataSource,
|
|
293
261
|
});
|
|
294
262
|
const {
|
|
295
|
-
state,
|
|
296
|
-
apiRef,
|
|
297
|
-
setRows,
|
|
298
|
-
setColumns,
|
|
299
|
-
setDimensions,
|
|
300
|
-
setDataSourceLoading,
|
|
301
|
-
setDataSourceError,
|
|
263
|
+
state, apiRef, setRows, replaceRow, setColumns, setDimensions, setDataSourceLoading, setDataSourceError,
|
|
302
264
|
setRowCount
|
|
303
265
|
} = gridData;
|
|
304
266
|
|
|
305
|
-
const {
|
|
306
|
-
|
|
307
|
-
useEffect(() => {
|
|
308
|
-
if (propApiRef) {
|
|
309
|
-
propApiRef.current = apiRef.current;
|
|
310
|
-
}
|
|
311
|
-
}, [propApiRef, apiRef]);
|
|
312
|
-
|
|
313
|
-
const { copySelectedRows } = useGridClipboard({
|
|
314
|
-
selectedRowIds,
|
|
315
|
-
columns: activeColumns as unknown as GridColDef[],
|
|
316
|
-
getVisibleRows: () => apiRef.current.getVisibleRows(),
|
|
317
|
-
getRowId: effectiveGetRowId as unknown as (row: GridRowModel) => GridRowId,
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
// Expose on apiRef for programmatic use
|
|
321
|
-
useEffect(() => {
|
|
322
|
-
apiRef.current.copySelectedRows = copySelectedRows;
|
|
323
|
-
apiRef.current.getSelectedRows = () => Array.from(selectedRowIds);
|
|
324
|
-
}, [copySelectedRows, selectedRowIds, apiRef]);
|
|
267
|
+
const { getRowIdOf, getRowIdOfInEvents } = useGridRowIdOf(state.rows.idByRow);
|
|
268
|
+
useGridApiRefBinding(propApiRef, apiRef);
|
|
325
269
|
|
|
326
270
|
const isInternalLoading = state.dataSource.loading;
|
|
327
271
|
const effectiveLoading = loading || isInternalLoading;
|
|
@@ -330,552 +274,388 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
330
274
|
return state.rows.allRows.map(id => state.rows.idRowsLookup.get(id)!) as R[];
|
|
331
275
|
}, [state.rows]);
|
|
332
276
|
|
|
333
|
-
const treeDataHandlers =
|
|
277
|
+
const { treeDataHandlers, rowGroupingHandlers, activeHierarchyHandlers, rowMetaMap } = useGridHierarchy<R>({
|
|
334
278
|
rows: effectiveRows,
|
|
335
|
-
getRowId:
|
|
336
|
-
getTreeDataPath,
|
|
337
|
-
treeData,
|
|
338
|
-
defaultGroupingExpansionDepth,
|
|
339
|
-
filterModel,
|
|
340
|
-
|
|
341
|
-
sortModel,
|
|
342
|
-
onRowExpansionChange: handleNodeExpansion
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
useEffect(() => {
|
|
346
|
-
treeDataRef.current = treeDataHandlers;
|
|
347
|
-
}, [treeDataHandlers]);
|
|
348
|
-
|
|
349
|
-
const rowGroupingHandlers = useRowGrouping({
|
|
350
|
-
rows: effectiveRows,
|
|
351
|
-
getRowId: effectiveGetRowId,
|
|
279
|
+
getRowId: getRowIdOf,
|
|
280
|
+
getTreeDataPath, isTreeDataRequested, isTreeData,
|
|
352
281
|
columns: activeColumns,
|
|
353
|
-
rowGroupingModel,
|
|
354
|
-
aggregationModel,
|
|
355
|
-
|
|
356
|
-
filterModel,
|
|
357
|
-
sortModel,
|
|
358
|
-
getAggregationPosition
|
|
282
|
+
rowGroupingModel: hierarchyRowGroupingModel,
|
|
283
|
+
isRowGrouping, aggregationModel, defaultGroupingExpansionDepth, filterModel, sortModel,
|
|
284
|
+
getAggregationPosition, columnLookup, filterMode, sortingMode,
|
|
359
285
|
});
|
|
360
286
|
|
|
361
287
|
const editingHandlers = useGridEditing({
|
|
362
288
|
rows: effectiveRows,
|
|
363
|
-
getRowId:
|
|
289
|
+
getRowId: getRowIdOf,
|
|
290
|
+
columns: activeColumns,
|
|
364
291
|
processRowUpdate,
|
|
365
292
|
onProcessRowUpdateError,
|
|
366
|
-
onRowChange: (updatedRow) => {
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
);
|
|
373
|
-
dispatch({ type: 'SET_ROWS', payload: nextRows });
|
|
293
|
+
onRowChange: (updatedRow, rowId) => {
|
|
294
|
+
// Replaces the edited row in the *current* store, under the edited row's id: this runs
|
|
295
|
+
// after an awaited processRowUpdate, by which time the rows prop (or a dataSource
|
|
296
|
+
// fetch) may have replaced the rows this render saw. The returned row is stored as is
|
|
297
|
+
// (the grid never writes an id onto it), even if it does not carry its key itself.
|
|
298
|
+
replaceRow(rowId, updatedRow);
|
|
374
299
|
},
|
|
375
300
|
});
|
|
376
301
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}, [isTreeData, treeDataHandlers.rowMetaMap, isRowGrouping, rowGroupingHandlers.rowMetaMap]);
|
|
387
|
-
|
|
388
|
-
const pagination = propPagination && !isRowGrouping;
|
|
389
|
-
|
|
390
|
-
const handleRowClick = useCallback((params: GridRowParams<R>) => {
|
|
391
|
-
const { row, id } = params;
|
|
392
|
-
|
|
393
|
-
if (isHierarchyEnabled && rowMetaMap.get(row.id)?.hasChildren) {
|
|
394
|
-
activeHierarchyHandlers?.toggleExpansion(id);
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
onRowClick?.(params);
|
|
399
|
-
|
|
400
|
-
if (!disableRowSelectionOnClick) {
|
|
401
|
-
let next: GridRowId[];
|
|
402
|
-
if (disableMultipleRowSelection) {
|
|
403
|
-
const alreadySelected = selectedRowIds.has(id as GridRowId);
|
|
404
|
-
next = alreadySelected ? [] : [id as GridRowId];
|
|
405
|
-
} else {
|
|
406
|
-
const newSelection = new Set(selectedRowIds);
|
|
407
|
-
if (newSelection.has(id as GridRowId)) {
|
|
408
|
-
newSelection.delete(id as GridRowId);
|
|
409
|
-
} else {
|
|
410
|
-
newSelection.add(id as GridRowId);
|
|
411
|
-
}
|
|
412
|
-
next = Array.from(newSelection);
|
|
413
|
-
}
|
|
414
|
-
if (!isSelectionControlled) {
|
|
415
|
-
setInternalRowSelectionModel(next);
|
|
416
|
-
}
|
|
417
|
-
onRowSelectionModelChange?.(next);
|
|
418
|
-
}
|
|
419
|
-
}, [isHierarchyEnabled, activeHierarchyHandlers, onRowClick, rowMetaMap, disableRowSelectionOnClick, disableMultipleRowSelection, selectedRowIds, isSelectionControlled, setInternalRowSelectionModel, onRowSelectionModelChange]);
|
|
302
|
+
// The selection without ids of removed rows. Only client-owned rows are pruned: a server page
|
|
303
|
+
// or a pivot of the rows does not hold every row a selection may name.
|
|
304
|
+
const selectedRowIds = useGridLiveRowSelection({
|
|
305
|
+
selectedRowIds: selectionModelRowIds,
|
|
306
|
+
rowsLookup: state.rows.idRowsLookup,
|
|
307
|
+
rowMetaMap,
|
|
308
|
+
enabled: !dataSource && !isPivotActive && paginationMode === 'client' && filterMode === 'client',
|
|
309
|
+
onSelectionModelChange: handleRowSelectionModelChange,
|
|
310
|
+
});
|
|
420
311
|
|
|
421
312
|
const dataSourceHandlers = useGridDataSource({
|
|
422
|
-
dataSource,
|
|
423
|
-
sortModel,
|
|
424
|
-
filterModel,
|
|
313
|
+
dataSource, sortModel, filterModel,
|
|
425
314
|
paginationModel: effectivePaginationModel,
|
|
426
|
-
paginationMode,
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
setRows,
|
|
431
|
-
setRowCount,
|
|
432
|
-
setDataSourceLoading,
|
|
433
|
-
setDataSourceError,
|
|
315
|
+
paginationMode, sortingMode, filterMode, aggregationModel,
|
|
316
|
+
rowGroupingActive: isRowGrouping,
|
|
317
|
+
getRowId: effectiveGetRowId as unknown as (row: GridRowModel) => GridRowId,
|
|
318
|
+
setRows, setRowCount, setDataSourceLoading, setDataSourceError,
|
|
434
319
|
onAggregationResults: setServerAggregationResults,
|
|
320
|
+
onPaginationModelChange: handlePaginationModelChange,
|
|
435
321
|
});
|
|
436
322
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
setRows(normalizedRows);
|
|
446
|
-
}
|
|
447
|
-
}, [normalizedRows, setRows, dataSource]);
|
|
323
|
+
useServerTreeChildren({
|
|
324
|
+
enabled: isTreeData && Boolean(dataSource),
|
|
325
|
+
treeNodes: treeDataHandlers.treeNodes,
|
|
326
|
+
isGroupExpanded: treeDataHandlers.isGroupExpanded,
|
|
327
|
+
getNodePath: treeDataHandlers.getNodePath,
|
|
328
|
+
toggleExpansion: treeDataHandlers.toggleExpansion,
|
|
329
|
+
fetchChildren: dataSourceHandlers.fetchChildren,
|
|
330
|
+
});
|
|
448
331
|
|
|
449
332
|
// ── Detail panel (hoisted — hasDetailPanel feeds into useGridColumns) ──────
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
if (newExpandedRowIds.has(rowId)) {
|
|
457
|
-
newExpandedRowIds.delete(rowId);
|
|
458
|
-
} else {
|
|
459
|
-
newExpandedRowIds.add(rowId);
|
|
460
|
-
}
|
|
461
|
-
if (controlledExpandedRowIds === undefined) {
|
|
462
|
-
setInternalExpandedRowIds(newExpandedRowIds);
|
|
463
|
-
}
|
|
464
|
-
onDetailPanelExpandedRowIdsChange?.(newExpandedRowIds);
|
|
465
|
-
}, [expandedRowIds, controlledExpandedRowIds, onDetailPanelExpandedRowIdsChange]);
|
|
333
|
+
const {
|
|
334
|
+
hasDetailPanel, expandedRowIds, handleDetailPanelToggle, detailPanelHeights, reportDetailPanelHeight,
|
|
335
|
+
} = useGridDetailPanel({
|
|
336
|
+
hasDetailPanel: Boolean(getDetailPanelContent),
|
|
337
|
+
controlledExpandedRowIds, onDetailPanelExpandedRowIdsChange, rowMetaMap,
|
|
338
|
+
});
|
|
466
339
|
|
|
467
340
|
// ── Column management ─────────────────────────────────────────────────────
|
|
468
341
|
const {
|
|
469
|
-
effectiveColumns,
|
|
470
|
-
|
|
471
|
-
visibleOrderedColumns,
|
|
472
|
-
navigationColumns,
|
|
473
|
-
columnWidths,
|
|
474
|
-
effectiveColumnOrder,
|
|
475
|
-
setInternalColumnOrder,
|
|
476
|
-
columnReorderHandlers,
|
|
477
|
-
handleColumnResize,
|
|
342
|
+
effectiveColumns, hierarchyField, orderedColumns, visibleOrderedColumns, renderOrderedColumns, navigationColumns, columnIndexMap,
|
|
343
|
+
columnWidths, effectiveColumnOrder, columnReorderHandlers, moveColumn, resetColumnOrder, handleColumnResize,
|
|
478
344
|
} = useGridColumns<R>({
|
|
479
|
-
activeColumns,
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
disableColumnReorder,
|
|
488
|
-
pivotMode,
|
|
489
|
-
checkboxSelection,
|
|
490
|
-
hasDetailPanel,
|
|
491
|
-
rowReordering,
|
|
492
|
-
initialState,
|
|
493
|
-
setColumns,
|
|
345
|
+
activeColumns, isHierarchyEnabled, isRowGrouping, isTreeData, activeHierarchyHandlers,
|
|
346
|
+
columnVisibilityModel, columnOrder, onColumnOrderChange, onColumnOrderModelChange, disableColumnReorder,
|
|
347
|
+
pivotMode: isPivotActive,
|
|
348
|
+
checkboxSelection, hasDetailPanel, rowReordering, initialState, setColumns,
|
|
349
|
+
pinnedColumns: effectivePinnedColumns,
|
|
350
|
+
getRowId: getRowIdOfInEvents,
|
|
351
|
+
aggregationModel,
|
|
352
|
+
groupingRows: isRowGrouping ? rowGroupingHandlers.groupingRows : undefined,
|
|
494
353
|
});
|
|
495
354
|
|
|
496
355
|
useGridStateSnapshot({
|
|
497
|
-
onStateChange,
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
effectivePaginationModel,
|
|
501
|
-
columnWidths,
|
|
502
|
-
effectiveColumnOrder,
|
|
503
|
-
columnVisibilityModel,
|
|
504
|
-
pinnedColumns: effectivePinnedColumns,
|
|
356
|
+
onStateChange, sortModel, filterModel, effectivePaginationModel, columnWidths, effectiveColumnOrder,
|
|
357
|
+
columnVisibilityModel, pinnedColumns,
|
|
358
|
+
density: effectiveDensity,
|
|
505
359
|
});
|
|
506
360
|
|
|
507
361
|
const rowPipeline = useGridRowPipeline<GridRowModel>({
|
|
508
362
|
effectiveRows: effectiveRows as GridRowModel[],
|
|
509
|
-
activeHierarchyHandlers
|
|
363
|
+
activeHierarchyHandlers,
|
|
510
364
|
filterMode,
|
|
511
|
-
filterModel,
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
365
|
+
filterModel: pivot.pipelineFilterModel,
|
|
366
|
+
sortModel: pivot.pipelineSortModel,
|
|
367
|
+
sortingMode, pagination, paginationMode, effectivePaginationModel, pinnedRows,
|
|
368
|
+
getRowId: getRowIdOf,
|
|
369
|
+
columnLookup,
|
|
370
|
+
hierarchyField,
|
|
371
|
+
});
|
|
372
|
+
const {
|
|
373
|
+
filteredRows, dataRows, pinnedTopRows, pinnedBottomRows, sortedUnpinnedRows, paginatedUnpinnedRows, allRenderableRows,
|
|
374
|
+
} = rowPipeline as unknown as GridRowPipelineResult<R>;
|
|
375
|
+
// The unpinned rows on screen: the current page, or every row without pagination.
|
|
376
|
+
const centerRows = pagination ? paginatedUnpinnedRows : sortedUnpinnedRows;
|
|
377
|
+
|
|
378
|
+
useGridPageCorrection({
|
|
379
|
+
paginationModel: effectivePaginationModel,
|
|
380
|
+
currentPage: rowPipeline.currentPage,
|
|
381
|
+
enabled: pagination && !effectiveLoading && sortedUnpinnedRows.length > 0,
|
|
382
|
+
onPaginationModelChange: handlePaginationModelChange,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const paginationRowCount = getPaginationRowCount({
|
|
516
386
|
paginationMode,
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
387
|
+
hasDataSource: Boolean(dataSource),
|
|
388
|
+
dataSourceRowCount: state.pagination.rowCount,
|
|
389
|
+
rowCountProp: propRowCount,
|
|
390
|
+
clientRowCount: sortedUnpinnedRows.length,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const { rowSelection, handleRowClick, handleSelectionChange } = useGridRowInteractions<R>({
|
|
394
|
+
dataRows,
|
|
395
|
+
getRowId: getRowIdOf,
|
|
396
|
+
isPivotActive,
|
|
397
|
+
selectedRowIds,
|
|
398
|
+
onSelectionModelChange: handleRowSelectionModelChange,
|
|
399
|
+
disableMultipleRowSelection, disableRowSelectionOnClick, isHierarchyEnabled, rowMetaMap,
|
|
400
|
+
activeHierarchyHandlers, onRowClick,
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
useGridApiMethods({
|
|
404
|
+
apiRef: gridData.apiRef,
|
|
405
|
+
sortModel,
|
|
406
|
+
multiSort,
|
|
407
|
+
onSortModelChange: handleSortModelChange,
|
|
408
|
+
filterModel,
|
|
409
|
+
onFilterModelChange: handleFilterModelChange,
|
|
410
|
+
paginationModel: effectivePaginationModel,
|
|
411
|
+
onPaginationModelChange: handlePaginationModelChange,
|
|
412
|
+
selectedRowIds,
|
|
413
|
+
getPendingRowSelectionModel: controlledState.getPendingRowSelectionModel,
|
|
414
|
+
onRowSelectionModelChange: handleRowSelectionModelChange,
|
|
415
|
+
disableMultipleRowSelection,
|
|
416
|
+
isSyntheticRowId: (id) => isSyntheticRowId(id, rowMetaMap),
|
|
417
|
+
getVisibleRows: () => [...pinnedTopRows, ...centerRows, ...pinnedBottomRows],
|
|
418
|
+
getAllFilteredRows: () => collectAllFilteredRows<GridRowModel>({
|
|
419
|
+
hierarchyHandlers: activeHierarchyHandlers,
|
|
420
|
+
pinnedTopRows,
|
|
421
|
+
sortedUnpinnedRows,
|
|
422
|
+
pinnedBottomRows,
|
|
423
|
+
rowMetaMap,
|
|
424
|
+
getRowId: getRowIdOf,
|
|
425
|
+
hierarchyField,
|
|
426
|
+
dataRows,
|
|
427
|
+
}),
|
|
428
|
+
visibleColumns: renderOrderedColumns as unknown as GridColDef[],
|
|
521
429
|
});
|
|
522
|
-
const filteredRows = rowPipeline.filteredRows as R[];
|
|
523
|
-
const pinnedTopRows = rowPipeline.pinnedTopRows as R[];
|
|
524
|
-
const pinnedBottomRows = rowPipeline.pinnedBottomRows as R[];
|
|
525
|
-
const sortedUnpinnedRows = rowPipeline.sortedUnpinnedRows as R[];
|
|
526
|
-
const paginatedUnpinnedRows = rowPipeline.paginatedUnpinnedRows as R[];
|
|
527
|
-
const allRenderableRows = rowPipeline.allRenderableRows as R[];
|
|
528
|
-
|
|
529
|
-
useEffect(() => {
|
|
530
|
-
gridData.apiRef.current.getVisibleRows = () => pagination ? paginatedUnpinnedRows : sortedUnpinnedRows;
|
|
531
|
-
gridData.apiRef.current.getAllFilteredRows = () => sortedUnpinnedRows;
|
|
532
|
-
gridData.apiRef.current.getVisibleColumns = () => effectiveColumns as unknown as GridColDef[];
|
|
533
|
-
}, [sortedUnpinnedRows, paginatedUnpinnedRows, pagination, effectiveColumns, gridData.apiRef]);
|
|
534
430
|
|
|
431
|
+
// Indices address the consumer's own rows, whatever the sort, filter, page or pinning.
|
|
535
432
|
const rowReorderHandlers = useRowReorder({
|
|
536
|
-
rows:
|
|
537
|
-
getRowId:
|
|
433
|
+
rows: effectiveRows,
|
|
434
|
+
getRowId: getRowIdOf,
|
|
538
435
|
onRowOrderChange,
|
|
539
436
|
rowReordering
|
|
540
437
|
});
|
|
541
438
|
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
navigationColumns,
|
|
545
|
-
columnWidths
|
|
546
|
-
);
|
|
547
|
-
|
|
548
|
-
const { aggregationResult } = useAggregation({
|
|
549
|
-
rows: filteredRows,
|
|
439
|
+
const { aggregationResult, isLoading: isAggregationLoading } = useAggregation({
|
|
440
|
+
rows: dataRows,
|
|
550
441
|
columns: activeColumns as unknown as GridColDef[],
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
serverAggregationResults,
|
|
442
|
+
// The pivot's Grand Total row is the aggregate in pivot mode: nothing to total here.
|
|
443
|
+
aggregationModel: isPivotActive ? NO_AGGREGATION_MODEL : aggregationModel,
|
|
444
|
+
// When the server drives the rows (paginates, sorts or filters them), the grid only holds
|
|
445
|
+
// the rows it returned, so client totals would be partial.
|
|
446
|
+
isServerSide: isServerDrivenDataSource({ dataSource, paginationMode, sortingMode, filterMode }),
|
|
447
|
+
dataSource, filterModel, sortModel, serverAggregationResults,
|
|
557
448
|
});
|
|
558
449
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const result: GridGroupedExportRow[] = [];
|
|
571
|
-
|
|
572
|
-
const traverse = (ids: GridRowId[]) => {
|
|
573
|
-
ids.forEach(id => {
|
|
574
|
-
const node = treeNodes.get(id);
|
|
575
|
-
if (!node) return;
|
|
576
|
-
const isGroup = Boolean(node.children && node.children.length > 0);
|
|
577
|
-
if (isGroup) {
|
|
578
|
-
result.push({
|
|
579
|
-
type: 'group-header',
|
|
580
|
-
depth: node.depth,
|
|
581
|
-
groupField: node.groupingField,
|
|
582
|
-
groupValue: node.groupingValue,
|
|
583
|
-
});
|
|
584
|
-
traverse(node.children!);
|
|
585
|
-
if (hasAggregation && node.aggregatedValues) {
|
|
586
|
-
result.push({
|
|
587
|
-
type: 'group-subtotal',
|
|
588
|
-
depth: node.depth,
|
|
589
|
-
groupField: node.groupingField,
|
|
590
|
-
groupValue: node.groupingValue,
|
|
591
|
-
aggregatedValues: node.aggregatedValues,
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
} else {
|
|
595
|
-
const row = rowLookup.get(id) ?? groupingRows.get(id);
|
|
596
|
-
if (row) {
|
|
597
|
-
result.push({ type: 'leaf', depth: node.depth, row });
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
};
|
|
602
|
-
|
|
603
|
-
traverse(Array.from(treeNodes.keys()).filter(id => treeNodes.get(id)?.parentId === null));
|
|
604
|
-
|
|
605
|
-
if (hasAggregation && aggregationResult) {
|
|
606
|
-
result.push({ type: 'grand-total', depth: 0, aggregatedValues: aggregationResult });
|
|
607
|
-
}
|
|
608
|
-
return result;
|
|
609
|
-
};
|
|
610
|
-
}, [aggregationResult, aggregationModel, hasAggregation, gridData.apiRef, isRowGrouping, rowGroupingHandlers, sortedUnpinnedRows]);
|
|
450
|
+
// In pivot mode the pivot's own Grand Total row is the aggregate; aggregationModel keys name source
|
|
451
|
+
// fields that the pivot rows do not have.
|
|
452
|
+
const hasAggregation = Object.keys(aggregationModel).length > 0 && !isPivotActive;
|
|
453
|
+
|
|
454
|
+
useGridAggregationApi<R>({
|
|
455
|
+
apiRef, hasAggregation, aggregationResult, aggregationModel, isRowGrouping, rowGroupingHandlers, rowMetaMap,
|
|
456
|
+
columns: activeColumns,
|
|
457
|
+
getRowId: getRowIdOf,
|
|
458
|
+
hierarchyField,
|
|
459
|
+
});
|
|
611
460
|
|
|
612
461
|
const layout = useLayout({
|
|
613
462
|
rowHeight: effectiveRowHeight,
|
|
614
|
-
pagination,
|
|
615
|
-
|
|
616
|
-
sortedUnpinnedRows,
|
|
617
|
-
expandedRowIds,
|
|
618
|
-
getDetailPanelHeight,
|
|
463
|
+
pagination, paginatedUnpinnedRows, sortedUnpinnedRows, expandedRowIds, getDetailPanelHeight,
|
|
464
|
+
detailPanelHeights,
|
|
619
465
|
pinnedTopRowsLength: pinnedTopRows.length,
|
|
620
466
|
pinnedBottomRowsLength: pinnedBottomRows.length,
|
|
621
|
-
visibleOrderedColumns,
|
|
467
|
+
pinnedTopRows, pinnedBottomRows, visibleOrderedColumns,
|
|
622
468
|
pinnedColumns: effectivePinnedColumns,
|
|
623
469
|
columnWidths,
|
|
624
470
|
viewportWidth: state.dimensions.viewportWidth || 1000,
|
|
625
|
-
checkboxSelection,
|
|
626
|
-
hasDetailPanel,
|
|
627
|
-
rowReordering,
|
|
628
|
-
pinCheckboxColumn,
|
|
629
|
-
pinExpandColumn,
|
|
630
|
-
autoHeight,
|
|
471
|
+
checkboxSelection, hasDetailPanel, rowReordering, pinCheckboxColumn, pinExpandColumn, autoHeight,
|
|
631
472
|
paginationMode,
|
|
632
473
|
isLoading: state.dataSource.loading,
|
|
633
474
|
pageSize: effectivePaginationModel.pageSize,
|
|
475
|
+
getRowId: getRowIdOf,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
const spanning = useGridSpanning<R>({
|
|
479
|
+
pinnedTopRows, centerRows, pinnedBottomRows,
|
|
480
|
+
columns: visibleOrderedColumns,
|
|
481
|
+
leftPinnedColumns: layout.leftPinnedCols,
|
|
482
|
+
unpinnedColumns: layout.unpinnedColsWithWidth,
|
|
483
|
+
rightPinnedColumns: layout.rightPinnedCols,
|
|
484
|
+
expandedRowIds: hasDetailPanel ? expandedRowIds : undefined,
|
|
485
|
+
rowMetaMap,
|
|
486
|
+
getRowId: getRowIdOf,
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
// Rendered data columns with their layout-resolved widths, in render order (column group header rows).
|
|
490
|
+
const renderedDataColumns = useMemo(
|
|
491
|
+
() => [...layout.leftPinnedCols, ...layout.unpinnedColsWithWidth, ...layout.rightPinnedCols],
|
|
492
|
+
[layout.leftPinnedCols, layout.unpinnedColsWithWidth, layout.rightPinnedCols]
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
useGridClipboardApi({
|
|
496
|
+
apiRef,
|
|
497
|
+
columns: renderedDataColumns as unknown as GridColDef[],
|
|
498
|
+
getRowId: getRowIdOf,
|
|
499
|
+
containerRef,
|
|
500
|
+
disableKeyboardShortcut: disableClipboardCopy,
|
|
634
501
|
});
|
|
502
|
+
useGridScrollToIndexesApi<R>({ apiRef, viewportRef, layout, rowHeight: effectiveRowHeight });
|
|
635
503
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
// manually resized — causing them to fall back to the raw `col.width` prop instead
|
|
640
|
-
// of the actual rendered width.
|
|
641
|
-
const resolvedColumnWidths = useMemo(() => {
|
|
642
|
-
const result: Record<string, number> = {};
|
|
643
|
-
for (const col of [...layout.leftPinnedCols, ...layout.unpinnedColsWithWidth, ...layout.rightPinnedCols]) {
|
|
644
|
-
if (!col.isSpacer) result[col.field] = col.width;
|
|
645
|
-
}
|
|
646
|
-
return { ...result, ...columnWidths };
|
|
647
|
-
}, [layout.leftPinnedCols, layout.unpinnedColsWithWidth, layout.rightPinnedCols, columnWidths]);
|
|
648
|
-
|
|
649
|
-
useEffect(() => {
|
|
650
|
-
gridData.apiRef.current.scrollToIndexes = ({ rowIndex, colIndex }) => {
|
|
651
|
-
const el = viewportRef.current;
|
|
652
|
-
if (!el) return;
|
|
653
|
-
|
|
654
|
-
if (rowIndex !== undefined && rowIndex >= 0) {
|
|
655
|
-
const rowTop = rowIndex > 0 ? layout.cumulativeHeights[rowIndex - 1] : 0;
|
|
656
|
-
const rowBottom = layout.cumulativeHeights[rowIndex] ?? rowTop;
|
|
657
|
-
const { scrollTop, clientHeight } = el;
|
|
658
|
-
if (rowTop < scrollTop) {
|
|
659
|
-
el.scrollTop = rowTop;
|
|
660
|
-
} else if (rowBottom > scrollTop + clientHeight) {
|
|
661
|
-
el.scrollTop = rowBottom - clientHeight;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
if (colIndex !== undefined && colIndex >= 0) {
|
|
666
|
-
// colIndex is an index into all data columns: leftPinned + unpinned + rightPinned
|
|
667
|
-
const allDataCols = [...layout.leftPinnedCols, ...layout.unpinnedColsWithWidth, ...layout.rightPinnedCols];
|
|
668
|
-
const targetCol = allDataCols[colIndex];
|
|
669
|
-
if (!targetCol) return;
|
|
670
|
-
const unpinnedIndex = layout.unpinnedColsWithWidth.findIndex(c => c.field === targetCol.field);
|
|
671
|
-
if (unpinnedIndex === -1) return; // pinned column — always visible, no scroll needed
|
|
672
|
-
const colLocalLeft = unpinnedIndex > 0 ? layout.unpinnedAccWidths[unpinnedIndex - 1] : 0;
|
|
673
|
-
const colLocalRight = layout.unpinnedAccWidths[unpinnedIndex] ?? colLocalLeft;
|
|
674
|
-
const colRight = layout.leftWidth + colLocalRight;
|
|
675
|
-
const { scrollLeft, clientWidth } = el;
|
|
676
|
-
if (colLocalLeft < scrollLeft) {
|
|
677
|
-
el.scrollLeft = colLocalLeft;
|
|
678
|
-
} else if (colRight > scrollLeft + clientWidth) {
|
|
679
|
-
el.scrollLeft = colRight - clientWidth;
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
}, [layout, viewportRef, gridData.apiRef]);
|
|
504
|
+
const { scrollTop, scrollLeft, overscanRows, handleScroll, setViewportElement } = useGridViewport({
|
|
505
|
+
onRowsScrollEnd, overscanRowCount, rowCount: layout.unpinnedRowsLength, autoHeight, setDimensions, viewportRef,
|
|
506
|
+
});
|
|
684
507
|
|
|
685
508
|
const virtualization = useGridVirtualization({
|
|
686
|
-
layout,
|
|
687
|
-
scrollTop,
|
|
688
|
-
scrollLeft,
|
|
509
|
+
layout, scrollTop, scrollLeft,
|
|
689
510
|
viewportWidth: state.dimensions.viewportWidth,
|
|
690
511
|
viewportHeight: state.dimensions.viewportHeight,
|
|
691
|
-
autoHeight,
|
|
692
|
-
rowReordering,
|
|
693
|
-
hasDetailPanel,
|
|
694
|
-
checkboxSelection,
|
|
695
|
-
pinCheckboxColumn,
|
|
696
|
-
pinExpandColumn,
|
|
512
|
+
autoHeight, rowReordering, hasDetailPanel, checkboxSelection, pinCheckboxColumn, pinExpandColumn,
|
|
697
513
|
overscanRows,
|
|
698
514
|
});
|
|
699
515
|
|
|
700
516
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
resizeObserver.observe(viewportRef.current);
|
|
712
|
-
|
|
713
|
-
return () => {
|
|
714
|
-
resizeObserver.disconnect();
|
|
715
|
-
};
|
|
716
|
-
}, [setDimensions]);
|
|
717
|
-
|
|
718
|
-
const handleSelectionChange = useCallback((rowId: GridRowId, isSelected: boolean) => {
|
|
719
|
-
const newSelection = new Set(selectedRowIds);
|
|
720
|
-
if (isSelected) {
|
|
721
|
-
newSelection.add(rowId);
|
|
722
|
-
} else {
|
|
723
|
-
newSelection.delete(rowId);
|
|
724
|
-
}
|
|
725
|
-
const newSelectionArray = Array.from(newSelection);
|
|
726
|
-
|
|
727
|
-
if (!isSelectionControlled) {
|
|
728
|
-
setInternalRowSelectionModel(newSelectionArray);
|
|
729
|
-
}
|
|
730
|
-
onRowSelectionModelChange?.(newSelectionArray);
|
|
731
|
-
}, [selectedRowIds, isSelectionControlled, onRowSelectionModelChange, setInternalRowSelectionModel]);
|
|
732
|
-
|
|
733
|
-
const handleSelectAll = useCallback((isSelected: boolean) => {
|
|
734
|
-
let newSelection: GridRowId[] = [];
|
|
735
|
-
if (isSelected) {
|
|
736
|
-
newSelection = effectiveRows.map((row: GridRowModel) => row.id);
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
if (!isSelectionControlled) {
|
|
740
|
-
setInternalRowSelectionModel(newSelection);
|
|
741
|
-
}
|
|
742
|
-
onRowSelectionModelChange?.(newSelection);
|
|
743
|
-
}, [effectiveRows, isSelectionControlled, onRowSelectionModelChange, setInternalRowSelectionModel]);
|
|
744
|
-
|
|
745
|
-
const handleSort = useCallback((field: string, direction: GridSortDirection) => {
|
|
746
|
-
const newSortModel = direction ? [{ field, sort: direction }] : [];
|
|
747
|
-
|
|
748
|
-
if (!isSortControlled) {
|
|
749
|
-
setInternalSortModel(newSortModel as GridSortItem[]);
|
|
750
|
-
}
|
|
751
|
-
onSortModelChange?.(newSortModel as GridSortItem[]);
|
|
752
|
-
}, [isSortControlled, onSortModelChange, setInternalSortModel]);
|
|
753
|
-
|
|
754
|
-
const handleSortAdd = useCallback((field: string, direction: GridSortDirection) => {
|
|
755
|
-
const existing = sortModel.filter(item => item.field !== field);
|
|
756
|
-
const newSortModel: GridSortItem[] = direction
|
|
757
|
-
? [...existing, { field, sort: direction }]
|
|
758
|
-
: existing;
|
|
759
|
-
|
|
760
|
-
if (!isSortControlled) {
|
|
761
|
-
setInternalSortModel(newSortModel);
|
|
762
|
-
}
|
|
763
|
-
onSortModelChange?.(newSortModel);
|
|
764
|
-
}, [sortModel, isSortControlled, onSortModelChange, setInternalSortModel]);
|
|
765
|
-
|
|
766
|
-
const { focusedCell, setFocusedCell, handleFocus, handleBlur, handleKeyDown } = useGridKeyboardNavigation({
|
|
767
|
-
allRenderableRows,
|
|
768
|
-
navigationColumns,
|
|
769
|
-
checkboxSelection,
|
|
770
|
-
selectedRowIds,
|
|
771
|
-
handleSelectionChange,
|
|
772
|
-
handleDetailPanelToggle,
|
|
773
|
-
editingHandlers,
|
|
774
|
-
setKeyboardMode,
|
|
775
|
-
sortModel,
|
|
776
|
-
handleSort,
|
|
777
|
-
isCellEditable,
|
|
778
|
-
pagination,
|
|
517
|
+
const { handleSort, handleSortAdd } = useGridSortHandlers({ sortModel, onSortModelChange: handleSortModelChange });
|
|
518
|
+
|
|
519
|
+
const rowSelectionEnabled = checkboxSelection || !disableRowSelectionOnClick;
|
|
520
|
+
const {
|
|
521
|
+
focusedCell, setFocusedCell, viewportTabIndex, ensureGridFocus, handleFocus, handleBlur, handleKeyDown,
|
|
522
|
+
handleMouseDownCapture,
|
|
523
|
+
} = useGridKeyboardNavigation({
|
|
524
|
+
allRenderableRows, navigationColumns, checkboxSelection, selectedRowIds, handleSelectionChange,
|
|
525
|
+
handleDetailPanelToggle, editingHandlers, setKeyboardMode, sortModel, handleSort, handleSortAdd, multiSort,
|
|
526
|
+
isCellEditable, pagination,
|
|
779
527
|
pageSize: effectivePaginationModel.pageSize,
|
|
780
528
|
virtualization,
|
|
781
529
|
viewportRef,
|
|
530
|
+
pinnedTopRowCount: pinnedTopRows.length,
|
|
531
|
+
getRowId: getRowIdOf,
|
|
532
|
+
rowMetaMap,
|
|
533
|
+
getSpanOrigin: spanning.getSpanOrigin,
|
|
534
|
+
onRowActivate: handleRowClick,
|
|
535
|
+
toggleRowExpansion: activeHierarchyHandlers?.toggleExpansion,
|
|
536
|
+
handleSelectAll: rowSelection.selectAll,
|
|
537
|
+
rowSelectionEnabled,
|
|
538
|
+
multipleRowSelectionEnabled: !disableMultipleRowSelection,
|
|
539
|
+
pinCheckboxColumn,
|
|
540
|
+
pinExpandColumn,
|
|
541
|
+
rowHeight: effectiveRowHeight,
|
|
782
542
|
});
|
|
783
543
|
|
|
784
|
-
const handleCellClick =
|
|
785
|
-
setKeyboardMode
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
544
|
+
const { handleCellClick, handleHeaderClick } = useGridPointerFocusHandlers<R>({
|
|
545
|
+
ensureGridFocus, setKeyboardMode, setFocusedCell, getRowId: getRowIdOf, onCellClick,
|
|
546
|
+
});
|
|
547
|
+
const { handleHideColumn, handlePinColumn } = useGridColumnMenuHandlers({
|
|
548
|
+
columnVisibilityModel,
|
|
549
|
+
onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
|
|
550
|
+
pinnedColumns,
|
|
551
|
+
onPinnedColumnsChange: handlePinnedColumnsChange,
|
|
552
|
+
});
|
|
791
553
|
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
554
|
+
const ariaRows = useGridAriaRows({
|
|
555
|
+
columnGroupingModel,
|
|
556
|
+
pinnedTopCount: pinnedTopRows.length,
|
|
557
|
+
pinnedBottomCount: pinnedBottomRows.length,
|
|
558
|
+
pagination,
|
|
559
|
+
paginationMode,
|
|
560
|
+
paginationModel: effectivePaginationModel,
|
|
561
|
+
paginationRowCount,
|
|
562
|
+
paginatedUnpinnedRowCount: paginatedUnpinnedRows.length,
|
|
563
|
+
sortedUnpinnedRowCount: sortedUnpinnedRows.length,
|
|
564
|
+
});
|
|
796
565
|
|
|
797
|
-
|
|
566
|
+
const spanRowWindow = useGridSpanRowWindow({
|
|
567
|
+
spanning,
|
|
568
|
+
renderContext: virtualization.renderContext,
|
|
569
|
+
offsetTop: virtualization.offsetTop,
|
|
570
|
+
cumulativeHeights: layout.cumulativeHeights,
|
|
571
|
+
});
|
|
798
572
|
|
|
799
|
-
|
|
800
|
-
|
|
573
|
+
const visibleRows = useGridVisibleRows<R>({
|
|
574
|
+
renderContext: spanRowWindow.renderContext,
|
|
575
|
+
pinnedTopRows, pinnedBottomRows, paginatedUnpinnedRows, sortedUnpinnedRows, pagination,
|
|
576
|
+
getRowId: getRowIdOf,
|
|
577
|
+
});
|
|
801
578
|
|
|
802
|
-
|
|
803
|
-
|
|
579
|
+
const renderColumns = useGridSpanColumnWindow<R>({
|
|
580
|
+
spanning,
|
|
581
|
+
firstColumnIndex: virtualization.renderContext.firstColumnIndex,
|
|
582
|
+
lastColumnIndex: virtualization.renderContext.lastColumnIndex,
|
|
583
|
+
virtualColumns: virtualization.virtualColumns,
|
|
584
|
+
layout,
|
|
585
|
+
rows: visibleRows,
|
|
586
|
+
});
|
|
804
587
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
588
|
+
useGridDevWarnings({
|
|
589
|
+
paginationRequested: propPagination,
|
|
590
|
+
isRowGrouping,
|
|
591
|
+
autoHeight,
|
|
592
|
+
viewportHeight: state.dimensions.viewportHeight,
|
|
593
|
+
renderedRowCount: visibleRows.length,
|
|
594
|
+
totalRowCount: pinnedTopRows.length + centerRows.length + pinnedBottomRows.length,
|
|
595
|
+
pinnedRowsIgnored: isHierarchyEnabled && Boolean(pinnedRows?.top?.length || pinnedRows?.bottom?.length),
|
|
596
|
+
scrollHeight: virtualization.totalHeight,
|
|
597
|
+
listViewWithoutColumn: listViewRequested && !listViewColumn,
|
|
812
598
|
});
|
|
813
599
|
|
|
600
|
+
const { allSelected, someSelected } = rowSelection;
|
|
814
601
|
|
|
815
|
-
|
|
816
|
-
const
|
|
602
|
+
// Header drag-reorder keeps a column inside its column group (and ungrouped columns outside groups).
|
|
603
|
+
const headerReorderHandlers = useColumnGroupReorderGuard(columnGroupingModel, columnReorderHandlers);
|
|
817
604
|
|
|
818
605
|
const hasRowSpanning = React.useMemo(() => effectiveColumns.some(c => !!c.rowSpan), [effectiveColumns]);
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
if (standalonePanelRef.current && !standalonePanelRef.current.contains(e.target as Node)) {
|
|
873
|
-
setColumnsPanelOpen(false);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
877
|
-
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
878
|
-
}, [columnsPanelOpen, slots?.toolbar]);
|
|
606
|
+
const columnsPanel = useGridColumnsPanel();
|
|
607
|
+
useGridStylesheetWarning(containerRef);
|
|
608
|
+
|
|
609
|
+
const NoRowsOverlaySlot = slots?.noRowsOverlay;
|
|
610
|
+
const LoadingOverlaySlot = slots?.loadingOverlay;
|
|
611
|
+
const loadingOverlay = LoadingOverlaySlot ? <LoadingOverlaySlot {...slotProps?.loadingOverlay} /> : undefined;
|
|
612
|
+
const noRowsOverlay = NoRowsOverlaySlot ? <NoRowsOverlaySlot {...slotProps?.noRowsOverlay} /> : undefined;
|
|
613
|
+
const FooterSlot = slots?.footer;
|
|
614
|
+
// Loading with rows on screen: the rows stay and an indicator runs over them. With no rows the
|
|
615
|
+
// body shows skeletons or the loading overlay instead, and infinite scroll appends skeleton rows.
|
|
616
|
+
const showLoadingOverRows = effectiveLoading && allRenderableRows.length > 0 && paginationMode !== 'infinite';
|
|
617
|
+
const ToolbarSlot = slots?.toolbar;
|
|
618
|
+
|
|
619
|
+
const toolbarProps = useGridToolbarProps<R>({
|
|
620
|
+
toolbar: slots?.toolbar,
|
|
621
|
+
toolbarSlotProps: slotProps?.toolbar,
|
|
622
|
+
apiRef,
|
|
623
|
+
orderedColumns,
|
|
624
|
+
baseColumns: columns,
|
|
625
|
+
aggregationModel,
|
|
626
|
+
onAggregationModelChange: handleAggregationModelChange,
|
|
627
|
+
pivotMode,
|
|
628
|
+
pivotModelProp: propPivotModel,
|
|
629
|
+
onPivotModelChangeProp: onPivotModelChange,
|
|
630
|
+
pivotModel: currentPivotModel,
|
|
631
|
+
onPivotModelChange: handlePivotModelChange,
|
|
632
|
+
filterModel,
|
|
633
|
+
onFilterModelChange: handleFilterModelChange,
|
|
634
|
+
columnVisibilityModel,
|
|
635
|
+
onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
|
|
636
|
+
disableColumnReorder, columnGroupingModel, moveColumn, resetColumnOrder,
|
|
637
|
+
forceColumnsOpen: columnsPanel.toolbarPanelRequested,
|
|
638
|
+
onColumnsPanelClose: columnsPanel.closeToolbarPanel,
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
// Props the row renderers (top-pinned, centre and bottom-pinned rows) all take.
|
|
642
|
+
const rowRenderProps = {
|
|
643
|
+
rowReordering, columnIndexMap, editingHandlers, isCellEditable, selectedRowIds, checkboxSelection,
|
|
644
|
+
onRowClick: handleRowClick,
|
|
645
|
+
onRowDoubleClick,
|
|
646
|
+
onCellClick: handleCellClick,
|
|
647
|
+
onSelectionChange: handleSelectionChange,
|
|
648
|
+
columnWidths,
|
|
649
|
+
pinnedColumns: effectivePinnedColumns,
|
|
650
|
+
hasDetailPanel, expandedRowIds, getDetailPanelContent, getDetailPanelHeight,
|
|
651
|
+
onDetailPanelToggle: handleDetailPanelToggle,
|
|
652
|
+
onDetailPanelHeightChange: reportDetailPanelHeight,
|
|
653
|
+
pinCheckboxColumn, pinExpandColumn, focusedCell,
|
|
654
|
+
colspanMap: spanning.colspanMap,
|
|
655
|
+
rowSpanningCaches: spanning.rowSpanningCaches,
|
|
656
|
+
rowHeight: effectiveRowHeight,
|
|
657
|
+
rowMetaMap,
|
|
658
|
+
};
|
|
879
659
|
|
|
880
660
|
return (
|
|
881
661
|
<div
|
|
@@ -889,51 +669,65 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
889
669
|
} as unknown as React.CSSProperties}
|
|
890
670
|
aria-busy={effectiveLoading}
|
|
891
671
|
>
|
|
892
|
-
{
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
isOpen={columnsPanelOpen}
|
|
897
|
-
containerRef={containerRef}
|
|
898
|
-
panelRef={standalonePanelRef}
|
|
899
|
-
effectiveColumns={effectiveColumns}
|
|
900
|
-
columnVisibilityModel={columnVisibilityModel}
|
|
901
|
-
effectiveColumnOrder={effectiveColumnOrder}
|
|
902
|
-
columnOrder={columnOrder}
|
|
903
|
-
disableColumnReorder={disableColumnReorder}
|
|
904
|
-
onClose={() => setColumnsPanelOpen(false)}
|
|
905
|
-
onColumnVisibilityChange={handleColumnVisibilityModelChange}
|
|
906
|
-
onColumnOrderChange={onColumnOrderChange}
|
|
907
|
-
setInternalColumnOrder={setInternalColumnOrder}
|
|
908
|
-
/>
|
|
672
|
+
{ToolbarSlot && toolbarProps && (
|
|
673
|
+
<GridToolbarHostContext.Provider value={columnsPanel.toolbarHost}>
|
|
674
|
+
<GridToolbarSlot component={ToolbarSlot} toolbarProps={toolbarProps} />
|
|
675
|
+
</GridToolbarHostContext.Provider>
|
|
909
676
|
)}
|
|
910
677
|
|
|
678
|
+
{/* Used by the column menu's Manage columns when no GridToolbar can show the panel */}
|
|
679
|
+
<GridStandaloneColumnPanel<R>
|
|
680
|
+
isOpen={columnsPanel.standalonePanelOpen}
|
|
681
|
+
containerRef={containerRef}
|
|
682
|
+
panelRef={columnsPanel.standalonePanelRef}
|
|
683
|
+
columns={orderedColumns}
|
|
684
|
+
columnVisibilityModel={columnVisibilityModel}
|
|
685
|
+
disableColumnReorder={disableColumnReorder}
|
|
686
|
+
onClose={columnsPanel.closeStandalonePanel}
|
|
687
|
+
onColumnVisibilityChange={handleColumnVisibilityModelChange}
|
|
688
|
+
onColumnMove={moveColumn}
|
|
689
|
+
onColumnOrderReset={resetColumnOrder}
|
|
690
|
+
columnGroupingModel={columnGroupingModel}
|
|
691
|
+
/>
|
|
692
|
+
|
|
693
|
+
|
|
911
694
|
{listView && listViewColumn && (
|
|
912
695
|
<GridListView<R>
|
|
913
696
|
ariaLabel={ariaLabel}
|
|
914
697
|
allRenderableRows={allRenderableRows}
|
|
915
|
-
|
|
698
|
+
dataRowCount={dataRows.length}
|
|
699
|
+
pinnedTopRowCount={pinnedTopRows.length}
|
|
700
|
+
pinnedBottomRowCount={pinnedBottomRows.length}
|
|
701
|
+
unpinnedRowCount={sortedUnpinnedRows.length}
|
|
916
702
|
pagination={pagination}
|
|
917
703
|
effectivePaginationModel={effectivePaginationModel}
|
|
704
|
+
currentPage={rowPipeline.currentPage}
|
|
918
705
|
pageSizeOptions={pageSizeOptions}
|
|
919
706
|
selectedRowIds={selectedRowIds}
|
|
920
707
|
listViewColumn={listViewColumn}
|
|
708
|
+
columnsByField={columnLookup.byField}
|
|
709
|
+
rowMetaMap={rowMetaMap}
|
|
921
710
|
noRowsLabel={effectiveNoRowsLabel}
|
|
922
711
|
rowHeight={effectiveRowHeight}
|
|
923
712
|
checkboxSelection={checkboxSelection}
|
|
924
713
|
paginationMode={paginationMode}
|
|
925
|
-
|
|
926
|
-
serverRowCount={state.pagination.rowCount || 0}
|
|
714
|
+
serverRowCount={paginationRowCount}
|
|
927
715
|
paginationSlot={slots?.pagination}
|
|
928
716
|
paginationSlotProps={slotProps?.pagination}
|
|
929
|
-
localeText={localeText
|
|
930
|
-
paginationRowsPerPage: localeText.paginationRowsPerPage,
|
|
931
|
-
paginationOf: localeText.paginationOf,
|
|
932
|
-
paginationPage: localeText.paginationPage,
|
|
933
|
-
} : undefined}
|
|
717
|
+
localeText={pickPaginationLocaleText(localeText)}
|
|
934
718
|
onRowClick={handleRowClick}
|
|
719
|
+
onRowDoubleClick={onRowDoubleClick}
|
|
935
720
|
onSelectionChange={handleSelectionChange}
|
|
936
721
|
onPaginationModelChange={handlePaginationModelChange}
|
|
722
|
+
onRowsScrollEnd={onRowsScrollEnd}
|
|
723
|
+
getRowId={getRowIdOf}
|
|
724
|
+
multiselectable={rowSelectionEnabled && !disableMultipleRowSelection}
|
|
725
|
+
selectable={rowSelectionEnabled}
|
|
726
|
+
onToggleExpansion={activeHierarchyHandlers?.toggleExpansion}
|
|
727
|
+
loading={effectiveLoading}
|
|
728
|
+
loadingOverlay={loadingOverlay}
|
|
729
|
+
noRowsOverlay={noRowsOverlay}
|
|
730
|
+
showPaginationControls={!FooterSlot}
|
|
937
731
|
/>
|
|
938
732
|
)}
|
|
939
733
|
|
|
@@ -942,245 +736,185 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
942
736
|
══════════════════════════════════════════════════════════════ */}
|
|
943
737
|
{!listView && (
|
|
944
738
|
<div
|
|
945
|
-
ref={
|
|
946
|
-
viewportRef.current = el;
|
|
947
|
-
gridRef.current = el;
|
|
948
|
-
}}
|
|
739
|
+
ref={setViewportElement}
|
|
949
740
|
className="ogx__viewport"
|
|
950
741
|
onScroll={handleScroll}
|
|
951
742
|
role="grid"
|
|
952
743
|
aria-label={ariaLabel || 'Data grid'}
|
|
953
|
-
aria-rowcount={
|
|
954
|
-
aria-colcount={
|
|
955
|
-
|
|
956
|
-
(checkboxSelection ? 1 : 0) +
|
|
957
|
-
(hasDetailPanel ? 1 : 0) +
|
|
958
|
-
(rowReordering ? 1 : 0)
|
|
959
|
-
}
|
|
744
|
+
aria-rowcount={ariaRows.rowCount}
|
|
745
|
+
aria-colcount={navigationColumns.length}
|
|
746
|
+
aria-multiselectable={rowSelectionEnabled && !disableMultipleRowSelection}
|
|
960
747
|
aria-busy={effectiveLoading}
|
|
961
|
-
tabIndex={
|
|
748
|
+
tabIndex={viewportTabIndex}
|
|
962
749
|
onKeyDownCapture={() => { setKeyboardMode(true); }}
|
|
963
|
-
onMouseDownCapture={
|
|
750
|
+
onMouseDownCapture={handleMouseDownCapture}
|
|
964
751
|
onKeyDown={handleKeyDown}
|
|
965
752
|
onFocus={handleFocus}
|
|
966
753
|
onBlur={handleBlur}
|
|
967
754
|
>
|
|
968
755
|
<div
|
|
969
|
-
ref={contentRef}
|
|
970
756
|
className="ogx__content"
|
|
971
757
|
style={{
|
|
972
758
|
width: virtualization.totalWidth
|
|
973
759
|
}}
|
|
974
760
|
role="presentation"
|
|
975
761
|
>
|
|
976
|
-
{ }
|
|
977
|
-
<
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
if (side === 'left') {
|
|
1025
|
-
handlePinnedColumnsChange({ left: [...cleanLeft, field], right: cleanRight });
|
|
1026
|
-
} else if (side === 'right') {
|
|
1027
|
-
handlePinnedColumnsChange({ left: cleanLeft, right: [...cleanRight, field] });
|
|
1028
|
-
} else {
|
|
1029
|
-
handlePinnedColumnsChange({ left: cleanLeft, right: cleanRight });
|
|
1030
|
-
}
|
|
1031
|
-
}}
|
|
1032
|
-
/>
|
|
762
|
+
{/* Header and top-pinned rows stick together, so pinned rows sit below every header row. */}
|
|
763
|
+
<div className="ogx__sticky-top" role="presentation">
|
|
764
|
+
<Header
|
|
765
|
+
columns={renderColumns}
|
|
766
|
+
allColumns={renderedDataColumns}
|
|
767
|
+
columnGroupingModel={columnGroupingModel}
|
|
768
|
+
checkboxSelection={checkboxSelection}
|
|
769
|
+
allSelected={allSelected}
|
|
770
|
+
someSelected={someSelected}
|
|
771
|
+
onSelectAll={rowSelection.selectAll}
|
|
772
|
+
sortModel={sortModel}
|
|
773
|
+
onSort={handleSort}
|
|
774
|
+
onSortAdd={handleSortAdd}
|
|
775
|
+
multiSort={multiSort}
|
|
776
|
+
|
|
777
|
+
onColumnResize={handleColumnResize}
|
|
778
|
+
columnWidths={columnWidths}
|
|
779
|
+
pinnedColumns={effectivePinnedColumns}
|
|
780
|
+
|
|
781
|
+
focusedCell={focusedCell}
|
|
782
|
+
columnIndexMap={columnIndexMap}
|
|
783
|
+
onHeaderClick={handleHeaderClick}
|
|
784
|
+
onDragStart={headerReorderHandlers.onDragStart}
|
|
785
|
+
onDragOver={headerReorderHandlers.onDragOver}
|
|
786
|
+
onDragEnd={headerReorderHandlers.onDragEnd}
|
|
787
|
+
onDrop={headerReorderHandlers.onDrop}
|
|
788
|
+
draggedColumn={headerReorderHandlers.draggedColumn}
|
|
789
|
+
dragOverColumn={headerReorderHandlers.dragOverColumn}
|
|
790
|
+
rowReordering={rowReordering}
|
|
791
|
+
hasDetailPanel={hasDetailPanel}
|
|
792
|
+
pinCheckboxColumn={pinCheckboxColumn}
|
|
793
|
+
pinExpandColumn={pinExpandColumn}
|
|
794
|
+
aggregationModel={aggregationModel}
|
|
795
|
+
onHideColumn={handleHideColumn}
|
|
796
|
+
onManageColumns={columnsPanel.openColumnsPanel}
|
|
797
|
+
onPinColumn={handlePinColumn}
|
|
798
|
+
/>
|
|
799
|
+
|
|
800
|
+
<GridPinnedRows<R>
|
|
801
|
+
{...rowRenderProps}
|
|
802
|
+
rows={pinnedTopRows}
|
|
803
|
+
position="top"
|
|
804
|
+
ariaRowIndexBase={ariaRows.topBase}
|
|
805
|
+
columns={renderColumns}
|
|
806
|
+
pinnedRows={pinnedRows}
|
|
807
|
+
getRowId={getRowIdOf}
|
|
808
|
+
/>
|
|
809
|
+
</div>
|
|
1033
810
|
|
|
1034
811
|
{/* Empty State Overlay (Standard View) — showing after header */}
|
|
1035
812
|
{!effectiveLoading && !state.dataSource.error && filteredRows.length === 0 && (
|
|
1036
|
-
<GridEmptyState
|
|
813
|
+
<GridEmptyState
|
|
814
|
+
noRowsLabel={effectiveNoRowsLabel}
|
|
815
|
+
width={virtualization.totalWidth}
|
|
816
|
+
overlay={noRowsOverlay}
|
|
817
|
+
/>
|
|
1037
818
|
)}
|
|
1038
819
|
|
|
1039
|
-
<GridPinnedRows<R>
|
|
1040
|
-
rows={pinnedTopRows}
|
|
1041
|
-
position="top"
|
|
1042
|
-
columns={virtualization.virtualColumns}
|
|
1043
|
-
selectedRowIds={selectedRowIds}
|
|
1044
|
-
checkboxSelection={checkboxSelection}
|
|
1045
|
-
onRowClick={handleRowClick}
|
|
1046
|
-
onCellClick={handleCellClick}
|
|
1047
|
-
onSelectionChange={handleSelectionChange}
|
|
1048
|
-
columnWidths={columnWidths}
|
|
1049
|
-
pinnedColumns={effectivePinnedColumns}
|
|
1050
|
-
pinnedRows={pinnedRows}
|
|
1051
|
-
hasDetailPanel={hasDetailPanel}
|
|
1052
|
-
expandedRowIds={expandedRowIds}
|
|
1053
|
-
getDetailPanelContent={getDetailPanelContent}
|
|
1054
|
-
getDetailPanelHeight={getDetailPanelHeight}
|
|
1055
|
-
onDetailPanelToggle={handleDetailPanelToggle}
|
|
1056
|
-
pinCheckboxColumn={pinCheckboxColumn}
|
|
1057
|
-
pinExpandColumn={pinExpandColumn}
|
|
1058
|
-
focusedCell={focusedCell}
|
|
1059
|
-
colspanMap={spanning.colspanMap}
|
|
1060
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1061
|
-
rowHeight={effectiveRowHeight}
|
|
1062
|
-
rowMetaMap={rowMetaMap}
|
|
1063
|
-
/>
|
|
1064
|
-
|
|
1065
820
|
<GridVirtualRows<R>
|
|
821
|
+
{...rowRenderProps}
|
|
1066
822
|
virtualContainerHeight={virtualization.totalHeight - virtualization.pinnedTopHeight - virtualization.pinnedBottomHeight}
|
|
1067
|
-
offsetTop={
|
|
823
|
+
offsetTop={spanRowWindow.offsetTop}
|
|
1068
824
|
effectiveLoading={effectiveLoading}
|
|
1069
825
|
visibleRows={visibleRows}
|
|
1070
826
|
baseColumns={columns as unknown as GridColDef<R>[]}
|
|
1071
|
-
virtualColumns={
|
|
827
|
+
virtualColumns={renderColumns}
|
|
1072
828
|
viewportWidth={state.dimensions.viewportWidth}
|
|
1073
|
-
checkboxSelection={checkboxSelection}
|
|
1074
|
-
hasDetailPanel={hasDetailPanel}
|
|
1075
|
-
rowReordering={rowReordering}
|
|
1076
|
-
rowHeight={effectiveRowHeight}
|
|
1077
|
-
pinnedRows={pinnedRows}
|
|
1078
|
-
selectedRowIds={selectedRowIds}
|
|
1079
|
-
onRowClick={handleRowClick}
|
|
1080
|
-
onCellClick={handleCellClick}
|
|
1081
|
-
onSelectionChange={handleSelectionChange}
|
|
1082
|
-
columnWidths={columnWidths}
|
|
1083
|
-
pinnedColumns={effectivePinnedColumns}
|
|
1084
|
-
expandedRowIds={expandedRowIds}
|
|
1085
|
-
getDetailPanelContent={getDetailPanelContent}
|
|
1086
|
-
getDetailPanelHeight={getDetailPanelHeight}
|
|
1087
|
-
onDetailPanelToggle={handleDetailPanelToggle}
|
|
1088
|
-
pinCheckboxColumn={pinCheckboxColumn}
|
|
1089
|
-
pinExpandColumn={pinExpandColumn}
|
|
1090
829
|
rowReorderHandlers={rowReorderHandlers}
|
|
1091
|
-
editingHandlers={editingHandlers}
|
|
1092
|
-
focusedCell={focusedCell}
|
|
1093
|
-
colspanMap={spanning.colspanMap}
|
|
1094
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1095
830
|
paginationMode={paginationMode}
|
|
1096
831
|
dataSourceLoading={state.dataSource.loading}
|
|
1097
832
|
sortedUnpinnedRowCount={sortedUnpinnedRows.length}
|
|
1098
833
|
infiniteScrollSkeletonCount={Math.min(effectivePaginationModel.pageSize, 20)}
|
|
1099
834
|
unpinnedRowsLength={layout.unpinnedRowsLength}
|
|
1100
|
-
|
|
835
|
+
lastRenderedRowIndex={spanRowWindow.renderContext.lastRowIndex}
|
|
836
|
+
ariaRowIndexOffset={ariaRows.centerOffset}
|
|
837
|
+
loadingOverlay={loadingOverlay}
|
|
1101
838
|
/>
|
|
1102
839
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
pinnedRows={pinnedRows}
|
|
1115
|
-
hasDetailPanel={hasDetailPanel}
|
|
1116
|
-
expandedRowIds={expandedRowIds}
|
|
1117
|
-
getDetailPanelContent={getDetailPanelContent}
|
|
1118
|
-
getDetailPanelHeight={getDetailPanelHeight}
|
|
1119
|
-
onDetailPanelToggle={handleDetailPanelToggle}
|
|
1120
|
-
pinCheckboxColumn={pinCheckboxColumn}
|
|
1121
|
-
pinExpandColumn={pinExpandColumn}
|
|
1122
|
-
focusedCell={focusedCell}
|
|
1123
|
-
colspanMap={spanning.colspanMap}
|
|
1124
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1125
|
-
rowHeight={effectiveRowHeight}
|
|
1126
|
-
rowMetaMap={rowMetaMap}
|
|
1127
|
-
/>
|
|
1128
|
-
|
|
1129
|
-
{/* Aggregation Footer Row — suppressed in pivot mode because pivot rows
|
|
1130
|
-
already contain pre-aggregated values with synthetic field keys
|
|
1131
|
-
(e.g. 'Q1\u001frevenue\u001fsum') that don't match aggregationModel keys. */}
|
|
1132
|
-
{hasAggregation && !pivotMode && (
|
|
1133
|
-
<GridAggregationFooter
|
|
1134
|
-
columns={orderedColumns as unknown as GridColDef[]}
|
|
1135
|
-
aggregationModel={aggregationModel}
|
|
1136
|
-
aggregationResult={aggregationResult}
|
|
1137
|
-
columnWidths={resolvedColumnWidths}
|
|
1138
|
-
rowHeight={effectiveRowHeight}
|
|
1139
|
-
checkboxSelection={checkboxSelection}
|
|
1140
|
-
hasDetailPanel={hasDetailPanel}
|
|
1141
|
-
rowReordering={rowReordering}
|
|
1142
|
-
pinnedColumns={effectivePinnedColumns}
|
|
840
|
+
{/* Bottom-pinned rows and the aggregation footer stick together, footer last. */}
|
|
841
|
+
<div className="ogx__sticky-bottom" role="presentation">
|
|
842
|
+
<GridPinnedRows<R>
|
|
843
|
+
{...rowRenderProps}
|
|
844
|
+
rows={pinnedBottomRows}
|
|
845
|
+
position="bottom"
|
|
846
|
+
rowIndexOffset={ariaRows.bottomRowIndexOffset}
|
|
847
|
+
ariaRowIndexBase={ariaRows.bottomBase}
|
|
848
|
+
columns={renderColumns}
|
|
849
|
+
pinnedRows={pinnedRows}
|
|
850
|
+
getRowId={getRowIdOf}
|
|
1143
851
|
/>
|
|
1144
|
-
|
|
852
|
+
|
|
853
|
+
{/* Aggregation Footer Row — laid out from the same virtual columns as the rows, so
|
|
854
|
+
hidden, pinned and scrolled columns line up. Off in pivot mode (hasAggregation). */}
|
|
855
|
+
{hasAggregation && rowGroupingHandlers.rootAggregationPosition !== null && (
|
|
856
|
+
<GridAggregationFooter
|
|
857
|
+
columns={virtualization.virtualColumns as unknown as GridColDef[]}
|
|
858
|
+
aggregationModel={aggregationModel}
|
|
859
|
+
aggregationResult={aggregationResult}
|
|
860
|
+
columnWidths={columnWidths}
|
|
861
|
+
rowHeight={effectiveRowHeight}
|
|
862
|
+
checkboxSelection={checkboxSelection}
|
|
863
|
+
hasDetailPanel={hasDetailPanel}
|
|
864
|
+
rowReordering={rowReordering}
|
|
865
|
+
pinCheckboxColumn={pinCheckboxColumn}
|
|
866
|
+
pinExpandColumn={pinExpandColumn}
|
|
867
|
+
pinnedColumns={effectivePinnedColumns}
|
|
868
|
+
loading={isAggregationLoading}
|
|
869
|
+
/>
|
|
870
|
+
)}
|
|
871
|
+
</div>
|
|
1145
872
|
|
|
1146
873
|
</div>
|
|
1147
874
|
</div>
|
|
1148
875
|
)}
|
|
1149
876
|
|
|
1150
|
-
{
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
877
|
+
{FooterSlot && (
|
|
878
|
+
<FooterSlot
|
|
879
|
+
apiRef={gridData.apiRef}
|
|
880
|
+
aggregationModel={aggregationModel}
|
|
881
|
+
aggregationResult={hasAggregation ? aggregationResult : null}
|
|
882
|
+
rowCount={isHierarchyEnabled && paginationMode !== 'server' ? dataRows.length : paginationRowCount}
|
|
883
|
+
pagination={pagination}
|
|
884
|
+
paginationModel={effectivePaginationModel}
|
|
885
|
+
pageSizeOptions={pageSizeOptions}
|
|
886
|
+
onPaginationModelChange={handlePaginationModelChange}
|
|
887
|
+
{...slotProps?.footer}
|
|
888
|
+
/>
|
|
889
|
+
)}
|
|
890
|
+
|
|
891
|
+
{!listView && !FooterSlot && pagination && (
|
|
892
|
+
<GridPaginationArea
|
|
893
|
+
paginationSlot={slots?.pagination}
|
|
894
|
+
paginationSlotProps={slotProps?.pagination}
|
|
895
|
+
page={rowPipeline.currentPage}
|
|
896
|
+
paginationModel={effectivePaginationModel}
|
|
897
|
+
rowCount={paginationRowCount}
|
|
898
|
+
pageSizeOptions={pageSizeOptions}
|
|
899
|
+
onPaginationModelChange={handlePaginationModelChange}
|
|
900
|
+
localeText={localeText}
|
|
901
|
+
/>
|
|
902
|
+
)}
|
|
903
|
+
|
|
904
|
+
<GridLiveRegion
|
|
905
|
+
loading={effectiveLoading}
|
|
906
|
+
error={state.dataSource.error}
|
|
907
|
+
noRowsLabel={effectiveNoRowsLabel}
|
|
908
|
+
filteredRowCount={filteredRows.length}
|
|
909
|
+
dataRowCount={dataRows.length}
|
|
910
|
+
filterModel={filterModel}
|
|
911
|
+
/>
|
|
912
|
+
|
|
913
|
+
{showLoadingOverRows && (
|
|
914
|
+
<GridLoadingOverlay overlay={loadingOverlay} />
|
|
915
|
+
)}
|
|
916
|
+
|
|
917
|
+
<GridErrorOverlay error={state.dataSource.error} onRetry={dataSource ? dataSourceHandlers.fetchRows : undefined} />
|
|
1184
918
|
</div>
|
|
1185
919
|
);
|
|
1186
920
|
}
|