@opencorestack/opengridx 2.1.0 → 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 +363 -0
- package/README.md +93 -72
- package/dist/index.d.ts +573 -124
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7890 -5636
- 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 +341 -163
- 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 +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 +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 +56 -19
- package/docs/features/pinning.md +23 -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 +28 -7
- 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 +4 -4
- package/lib/components/Cell/Cell.css +13 -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 +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 +77 -12
- package/lib/components/DataGrid/DataGrid.tsx +576 -874
- package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
- package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
- package/lib/components/DataGrid/GridListView.tsx +164 -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 +3 -3
- package/lib/components/Header/Header.tsx +179 -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 +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 +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 +82 -1
- 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 +299 -109
- 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 +260 -163
- 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
|
@@ -1,50 +1,86 @@
|
|
|
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';
|
|
11
|
-
import { useGridDevWarnings } from '../../hooks/core/useGridDevWarnings';
|
|
12
|
-
import {
|
|
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';
|
|
13
22
|
import { GridAggregationFooter } from './GridAggregationFooter';
|
|
14
23
|
import { GridEmptyState } from './GridEmptyState';
|
|
15
24
|
import { GridErrorOverlay } from './GridErrorOverlay';
|
|
16
25
|
import { Header } from '../Header/Header';
|
|
17
|
-
import { Pagination } from '../Pagination/Pagination';
|
|
18
26
|
import { useDataGrid } from '../../hooks/core/useDataGrid';
|
|
19
27
|
import { useRowReorder } from '../../hooks/useRowReorder';
|
|
20
|
-
import {
|
|
21
|
-
import { useRowGrouping } from '../../hooks/useRowGrouping';
|
|
28
|
+
import { useGridHierarchy } from '../../hooks/core/useGridHierarchy';
|
|
22
29
|
import { useGridEditing } from '../../hooks/features/useGridEditing';
|
|
23
30
|
import { useGridSpanning } from '../../hooks/features/useGridSpanning';
|
|
31
|
+
import { useGridSpanRowWindow, useGridSpanColumnWindow } from '../../hooks/features/useGridSpanRenderWindow';
|
|
32
|
+
import { useColumnGroupReorderGuard } from '../../hooks/features/useColumnGroupReorderGuard';
|
|
24
33
|
import { useGridDataSource } from '../../hooks/features/useGridDataSource';
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
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';
|
|
28
38
|
import { GridListView } from './GridListView';
|
|
39
|
+
import { GridLoadingOverlay } from './GridLoadingOverlay';
|
|
29
40
|
import { GridPinnedRows } from './GridPinnedRows';
|
|
30
41
|
import { GridVirtualRows } from './GridVirtualRows';
|
|
31
42
|
import { GridStandaloneColumnPanel } from './GridStandaloneColumnPanel';
|
|
32
|
-
import
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 {
|
|
37
72
|
const {
|
|
38
73
|
rows,
|
|
39
|
-
columns,
|
|
74
|
+
columns: columnsProp,
|
|
40
75
|
getRowId,
|
|
41
|
-
rowHeight
|
|
42
|
-
headerHeight
|
|
76
|
+
rowHeight: rowHeightProp,
|
|
77
|
+
headerHeight: headerHeightProp,
|
|
43
78
|
autoHeight = false,
|
|
44
79
|
density,
|
|
45
80
|
checkboxSelection = false,
|
|
46
81
|
disableRowSelectionOnClick = false,
|
|
47
82
|
disableMultipleRowSelection = false,
|
|
83
|
+
disableClipboardCopy = false,
|
|
48
84
|
rowSelectionModel: propRowSelectionModel,
|
|
49
85
|
onRowSelectionModelChange: propOnRowSelectionModelChange,
|
|
50
86
|
onRowClick,
|
|
@@ -72,8 +108,9 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
72
108
|
disableColumnReorder = false,
|
|
73
109
|
columnOrder,
|
|
74
110
|
onColumnOrderChange,
|
|
111
|
+
onColumnOrderModelChange,
|
|
75
112
|
height,
|
|
76
|
-
rowReordering = false,
|
|
113
|
+
rowReordering: rowReorderingProp = false,
|
|
77
114
|
onRowOrderChange,
|
|
78
115
|
loading = false,
|
|
79
116
|
|
|
@@ -115,7 +152,7 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
115
152
|
// Column Visibility
|
|
116
153
|
columnVisibilityModel: propColumnVisibilityModel,
|
|
117
154
|
onColumnVisibilityModelChange,
|
|
118
|
-
listView = false,
|
|
155
|
+
listView: listViewRequested = false,
|
|
119
156
|
listViewColumn,
|
|
120
157
|
columnGroupingModel,
|
|
121
158
|
noRowsLabel = 'No Data',
|
|
@@ -123,46 +160,18 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
123
160
|
apiRef: propApiRef,
|
|
124
161
|
overscanRowCount = 3,
|
|
125
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);
|
|
126
165
|
|
|
127
166
|
const effectiveNoRowsLabel = localeText?.noRowsLabel ?? noRowsLabel;
|
|
128
|
-
|
|
129
|
-
// Stable defaults
|
|
130
|
-
const defaultFilterModel: GridFilterModel = useMemo(() => ({ items: [] }), []);
|
|
131
|
-
const filterModel = (propFilterModel || defaultFilterModel) as GridFilterModel;
|
|
132
|
-
|
|
133
|
-
const defaultRowGroupingModel = useMemo(() => [], []);
|
|
134
|
-
const rowGroupingModel = propRowGroupingModel || defaultRowGroupingModel;
|
|
135
|
-
|
|
136
|
-
// ─── Stabilize toolbar component identity ────────────────────────────────
|
|
137
|
-
// Problem: demos/users often define their toolbar as an inline function
|
|
138
|
-
// INSIDE their component body, e.g.:
|
|
139
|
-
// const MyToolbar = (props) => <GridToolbar {...props} /> // inside render!
|
|
140
|
-
// This creates a NEW function reference on every parent re-render. React
|
|
141
|
-
// reconciles by component *identity*, so a new reference = unmount old
|
|
142
|
-
// toolbar + mount fresh one = all toolbar state (search expansion, filter
|
|
143
|
-
// open, typed text) is destroyed on every keystroke.
|
|
144
|
-
//
|
|
145
|
-
// Fix: a stable wrapper component created ONCE via useRef. Its identity
|
|
146
|
-
// never changes, so React keeps it mounted. It reads the latest toolbar
|
|
147
|
-
// from a separate ref that is updated on every render, so the rendered
|
|
148
|
-
// output is always current — zero stale closures.
|
|
149
|
-
const latestToolbarRef = useRef(slots?.toolbar);
|
|
150
|
-
latestToolbarRef.current = slots?.toolbar;
|
|
151
|
-
// The wrapper itself has a stable identity (created once via useRef).
|
|
152
|
-
// We call latestToolbarRef.current(props) as a PLAIN FUNCTION — not via
|
|
153
|
-
// React.createElement — so React never sees a changing component type.
|
|
154
|
-
// The elements the toolbar function returns are reconciled normally, so
|
|
155
|
-
// GridToolbar's internal state (filterOpen, search expansion) is preserved
|
|
156
|
-
// even when the toolbar is defined as an inline function inside the parent.
|
|
157
|
-
const StableToolbar = useRef((props: Record<string, unknown>) => {
|
|
158
|
-
const Toolbar = latestToolbarRef.current;
|
|
159
|
-
return Toolbar ? (Toolbar as (p: typeof props) => React.ReactElement | null)(props) : null;
|
|
160
|
-
}).current;
|
|
167
|
+
const rowGroupingModel = propRowGroupingModel || EMPTY_ROW_GROUPING_MODEL;
|
|
161
168
|
|
|
162
169
|
const controlledState = useGridControlledState({
|
|
163
170
|
initialState,
|
|
164
171
|
sortModel: propSortModel,
|
|
165
172
|
onSortModelChange,
|
|
173
|
+
filterModel: propFilterModel,
|
|
174
|
+
onFilterModelChange,
|
|
166
175
|
aggregationModel: propAggregationModel,
|
|
167
176
|
onAggregationModelChange,
|
|
168
177
|
columnVisibilityModel: propColumnVisibilityModel,
|
|
@@ -170,161 +179,93 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
170
179
|
pinnedColumns: propPinnedColumns,
|
|
171
180
|
onPinnedColumnsChange,
|
|
172
181
|
pivotModel: propPivotModel,
|
|
173
|
-
onPivotModelChange,
|
|
174
|
-
paginationModel,
|
|
175
|
-
onPaginationModelChange,
|
|
182
|
+
onPivotModelChange, paginationModel, onPaginationModelChange, pageSizeOptions,
|
|
176
183
|
rowSelectionModel: propRowSelectionModel,
|
|
177
184
|
onRowSelectionModelChange: propOnRowSelectionModelChange,
|
|
185
|
+
density,
|
|
178
186
|
});
|
|
179
187
|
|
|
180
188
|
const {
|
|
181
|
-
sortModel,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
pinnedColumns,
|
|
189
|
-
handlePinnedColumnsChange,
|
|
190
|
-
currentPivotModel,
|
|
191
|
-
handlePivotModelChange,
|
|
192
|
-
effectivePaginationModel,
|
|
193
|
-
handlePaginationModelChange,
|
|
194
|
-
selectedRowIds,
|
|
195
|
-
isSelectionControlled,
|
|
196
|
-
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,
|
|
197
196
|
} = controlledState;
|
|
198
197
|
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
(
|
|
224
|
-
|
|
225
|
-
{
|
|
226
|
-
headerName: 'Group',
|
|
227
|
-
width: 220,
|
|
228
|
-
...groupingColDef,
|
|
229
|
-
field: '__group__',
|
|
230
|
-
hideable: false,
|
|
231
|
-
sortable: false,
|
|
232
|
-
pinnable: false,
|
|
233
|
-
exportable: false,
|
|
234
|
-
} as unknown as GridColDef<R>,
|
|
235
|
-
...baseColumns,
|
|
236
|
-
]
|
|
237
|
-
: baseColumns
|
|
238
|
-
), [groupingColDef, isRowGroupingActive, pivotMode, baseColumns]);
|
|
239
|
-
|
|
240
|
-
const [serverAggregationResults, setServerAggregationResults] = useState<GridAggregationResult | null>(null);
|
|
241
|
-
|
|
242
|
-
useEffect(() => {
|
|
243
|
-
setServerAggregationResults(null);
|
|
244
|
-
}, [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
|
+
});
|
|
245
224
|
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const defaultGetRowId = useCallback((row: R) => row.id, []);
|
|
251
|
-
const effectiveGetRowId = getRowId || defaultGetRowId;
|
|
252
|
-
|
|
253
|
-
// Normalize rows so every row has `id === getRowId(row)`.
|
|
254
|
-
// createInitialState and SET_ROWS both key the internal store by row.id,
|
|
255
|
-
// so rows without a native id field collide on undefined without this.
|
|
256
|
-
// When getRowId is the default (row) => row.id this is a no-op per row.
|
|
257
|
-
const normalizedRows = useMemo(
|
|
258
|
-
() => activeRows.map(row => {
|
|
259
|
-
const id = effectiveGetRowId(row);
|
|
260
|
-
return id === row.id ? row : ({ ...row, id } as R);
|
|
261
|
-
}),
|
|
262
|
-
[activeRows, effectiveGetRowId]
|
|
263
|
-
);
|
|
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
|
+
});
|
|
264
229
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const setKeyboardMode = useCallback((on: boolean) => {
|
|
268
|
-
containerRef.current?.classList.toggle('ogx--kb', on);
|
|
269
|
-
}, []);
|
|
230
|
+
const activeRows = pivot.rows as unknown as R[];
|
|
231
|
+
const baseColumns = pivot.columns as unknown as GridColDef<R>[];
|
|
270
232
|
|
|
271
|
-
const
|
|
272
|
-
|
|
233
|
+
const { activeColumns, effectivePinnedColumns } = useGridGroupingColumn<R>({
|
|
234
|
+
baseColumns, pinnedColumns, hasGroupingColumn, groupingColDef, isTreeData, getTreeDataPath,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const columnLookup = useGridColumnLookup(activeColumns, columnVisibilityModel);
|
|
273
238
|
|
|
274
|
-
|
|
275
|
-
const
|
|
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
|
-
const
|
|
278
|
-
|
|
242
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
243
|
+
const viewportRef = useRef<HTMLDivElement>(null);
|
|
279
244
|
|
|
280
|
-
|
|
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;
|
|
281
249
|
|
|
282
|
-
|
|
283
|
-
fetchChildrenRef.current?.(node.id, groupKeys);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}, [treeData]);
|
|
250
|
+
const setKeyboardMode = useGridKeyboardMode(containerRef);
|
|
287
251
|
|
|
288
252
|
const gridData = useDataGrid({
|
|
289
|
-
rows:
|
|
253
|
+
rows: activeRows,
|
|
254
|
+
getRowId: effectiveGetRowId,
|
|
290
255
|
columns: activeColumns,
|
|
291
256
|
rowHeight: effectiveRowHeight,
|
|
292
257
|
headerHeight,
|
|
293
|
-
rowCount: propRowCount,
|
|
294
258
|
columnVisibilityModel,
|
|
295
|
-
initialState: props.initialState
|
|
259
|
+
initialState: props.initialState,
|
|
260
|
+
syncRows: !dataSource,
|
|
296
261
|
});
|
|
297
262
|
const {
|
|
298
|
-
state,
|
|
299
|
-
apiRef,
|
|
300
|
-
setRows,
|
|
301
|
-
setColumns,
|
|
302
|
-
setDimensions,
|
|
303
|
-
setDataSourceLoading,
|
|
304
|
-
setDataSourceError,
|
|
263
|
+
state, apiRef, setRows, replaceRow, setColumns, setDimensions, setDataSourceLoading, setDataSourceError,
|
|
305
264
|
setRowCount
|
|
306
265
|
} = gridData;
|
|
307
266
|
|
|
308
|
-
const {
|
|
309
|
-
|
|
310
|
-
useEffect(() => {
|
|
311
|
-
if (propApiRef) {
|
|
312
|
-
propApiRef.current = apiRef.current;
|
|
313
|
-
}
|
|
314
|
-
}, [propApiRef, apiRef]);
|
|
315
|
-
|
|
316
|
-
const { copySelectedRows } = useGridClipboard({
|
|
317
|
-
selectedRowIds,
|
|
318
|
-
columns: activeColumns as unknown as GridColDef[],
|
|
319
|
-
getVisibleRows: () => apiRef.current.getVisibleRows(),
|
|
320
|
-
getRowId: effectiveGetRowId as unknown as (row: GridRowModel) => GridRowId,
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// Expose on apiRef for programmatic use
|
|
324
|
-
useEffect(() => {
|
|
325
|
-
apiRef.current.copySelectedRows = copySelectedRows;
|
|
326
|
-
apiRef.current.getSelectedRows = () => Array.from(selectedRowIds);
|
|
327
|
-
}, [copySelectedRows, selectedRowIds, apiRef]);
|
|
267
|
+
const { getRowIdOf, getRowIdOfInEvents } = useGridRowIdOf(state.rows.idByRow);
|
|
268
|
+
useGridApiRefBinding(propApiRef, apiRef);
|
|
328
269
|
|
|
329
270
|
const isInternalLoading = state.dataSource.loading;
|
|
330
271
|
const effectiveLoading = loading || isInternalLoading;
|
|
@@ -333,479 +274,315 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
333
274
|
return state.rows.allRows.map(id => state.rows.idRowsLookup.get(id)!) as R[];
|
|
334
275
|
}, [state.rows]);
|
|
335
276
|
|
|
336
|
-
const treeDataHandlers =
|
|
277
|
+
const { treeDataHandlers, rowGroupingHandlers, activeHierarchyHandlers, rowMetaMap } = useGridHierarchy<R>({
|
|
337
278
|
rows: effectiveRows,
|
|
338
|
-
getRowId:
|
|
339
|
-
getTreeDataPath,
|
|
340
|
-
treeData,
|
|
341
|
-
defaultGroupingExpansionDepth,
|
|
342
|
-
filterModel,
|
|
343
|
-
|
|
344
|
-
sortModel,
|
|
345
|
-
onRowExpansionChange: handleNodeExpansion
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
useEffect(() => {
|
|
349
|
-
treeDataRef.current = treeDataHandlers;
|
|
350
|
-
}, [treeDataHandlers]);
|
|
351
|
-
|
|
352
|
-
const rowGroupingHandlers = useRowGrouping({
|
|
353
|
-
rows: effectiveRows,
|
|
354
|
-
getRowId: effectiveGetRowId,
|
|
279
|
+
getRowId: getRowIdOf,
|
|
280
|
+
getTreeDataPath, isTreeDataRequested, isTreeData,
|
|
355
281
|
columns: activeColumns,
|
|
356
|
-
rowGroupingModel,
|
|
357
|
-
aggregationModel,
|
|
358
|
-
|
|
359
|
-
filterModel,
|
|
360
|
-
sortModel,
|
|
361
|
-
getAggregationPosition
|
|
282
|
+
rowGroupingModel: hierarchyRowGroupingModel,
|
|
283
|
+
isRowGrouping, aggregationModel, defaultGroupingExpansionDepth, filterModel, sortModel,
|
|
284
|
+
getAggregationPosition, columnLookup, filterMode, sortingMode,
|
|
362
285
|
});
|
|
363
286
|
|
|
364
287
|
const editingHandlers = useGridEditing({
|
|
365
288
|
rows: effectiveRows,
|
|
366
|
-
getRowId:
|
|
289
|
+
getRowId: getRowIdOf,
|
|
290
|
+
columns: activeColumns,
|
|
367
291
|
processRowUpdate,
|
|
368
292
|
onProcessRowUpdateError,
|
|
369
|
-
onRowChange: (updatedRow) => {
|
|
370
|
-
//
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
);
|
|
376
|
-
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);
|
|
377
299
|
},
|
|
378
300
|
});
|
|
379
301
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}, [isTreeData, treeDataHandlers.rowMetaMap, isRowGrouping, rowGroupingHandlers.rowMetaMap]);
|
|
390
|
-
|
|
391
|
-
const pagination = propPagination && !isRowGrouping;
|
|
392
|
-
|
|
393
|
-
const handleRowClick = useCallback((params: GridRowParams<R>) => {
|
|
394
|
-
const { row, id } = params;
|
|
395
|
-
|
|
396
|
-
if (isHierarchyEnabled && rowMetaMap.get(row.id)?.hasChildren) {
|
|
397
|
-
activeHierarchyHandlers?.toggleExpansion(id);
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
onRowClick?.(params);
|
|
402
|
-
|
|
403
|
-
if (!disableRowSelectionOnClick) {
|
|
404
|
-
let next: GridRowId[];
|
|
405
|
-
if (disableMultipleRowSelection) {
|
|
406
|
-
const alreadySelected = selectedRowIds.has(id as GridRowId);
|
|
407
|
-
next = alreadySelected ? [] : [id as GridRowId];
|
|
408
|
-
} else {
|
|
409
|
-
const newSelection = new Set(selectedRowIds);
|
|
410
|
-
if (newSelection.has(id as GridRowId)) {
|
|
411
|
-
newSelection.delete(id as GridRowId);
|
|
412
|
-
} else {
|
|
413
|
-
newSelection.add(id as GridRowId);
|
|
414
|
-
}
|
|
415
|
-
next = Array.from(newSelection);
|
|
416
|
-
}
|
|
417
|
-
if (!isSelectionControlled) {
|
|
418
|
-
setInternalRowSelectionModel(next);
|
|
419
|
-
}
|
|
420
|
-
onRowSelectionModelChange?.(next);
|
|
421
|
-
}
|
|
422
|
-
}, [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
|
+
});
|
|
423
311
|
|
|
424
312
|
const dataSourceHandlers = useGridDataSource({
|
|
425
|
-
dataSource,
|
|
426
|
-
sortModel,
|
|
427
|
-
filterModel,
|
|
313
|
+
dataSource, sortModel, filterModel,
|
|
428
314
|
paginationModel: effectivePaginationModel,
|
|
429
|
-
paginationMode,
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
setRows,
|
|
434
|
-
setRowCount,
|
|
435
|
-
setDataSourceLoading,
|
|
436
|
-
setDataSourceError,
|
|
315
|
+
paginationMode, sortingMode, filterMode, aggregationModel,
|
|
316
|
+
rowGroupingActive: isRowGrouping,
|
|
317
|
+
getRowId: effectiveGetRowId as unknown as (row: GridRowModel) => GridRowId,
|
|
318
|
+
setRows, setRowCount, setDataSourceLoading, setDataSourceError,
|
|
437
319
|
onAggregationResults: setServerAggregationResults,
|
|
320
|
+
onPaginationModelChange: handlePaginationModelChange,
|
|
438
321
|
});
|
|
439
322
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
setRows(normalizedRows);
|
|
449
|
-
}
|
|
450
|
-
}, [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
|
+
});
|
|
451
331
|
|
|
452
332
|
// ── Detail panel (hoisted — hasDetailPanel feeds into useGridColumns) ──────
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
if (newExpandedRowIds.has(rowId)) {
|
|
460
|
-
newExpandedRowIds.delete(rowId);
|
|
461
|
-
} else {
|
|
462
|
-
newExpandedRowIds.add(rowId);
|
|
463
|
-
}
|
|
464
|
-
if (controlledExpandedRowIds === undefined) {
|
|
465
|
-
setInternalExpandedRowIds(newExpandedRowIds);
|
|
466
|
-
}
|
|
467
|
-
onDetailPanelExpandedRowIdsChange?.(newExpandedRowIds);
|
|
468
|
-
}, [expandedRowIds, controlledExpandedRowIds, onDetailPanelExpandedRowIdsChange]);
|
|
333
|
+
const {
|
|
334
|
+
hasDetailPanel, expandedRowIds, handleDetailPanelToggle, detailPanelHeights, reportDetailPanelHeight,
|
|
335
|
+
} = useGridDetailPanel({
|
|
336
|
+
hasDetailPanel: Boolean(getDetailPanelContent),
|
|
337
|
+
controlledExpandedRowIds, onDetailPanelExpandedRowIdsChange, rowMetaMap,
|
|
338
|
+
});
|
|
469
339
|
|
|
470
340
|
// ── Column management ─────────────────────────────────────────────────────
|
|
471
341
|
const {
|
|
472
|
-
effectiveColumns,
|
|
473
|
-
|
|
474
|
-
visibleOrderedColumns,
|
|
475
|
-
navigationColumns,
|
|
476
|
-
columnWidths,
|
|
477
|
-
effectiveColumnOrder,
|
|
478
|
-
setInternalColumnOrder,
|
|
479
|
-
columnReorderHandlers,
|
|
480
|
-
handleColumnResize,
|
|
342
|
+
effectiveColumns, hierarchyField, orderedColumns, visibleOrderedColumns, renderOrderedColumns, navigationColumns, columnIndexMap,
|
|
343
|
+
columnWidths, effectiveColumnOrder, columnReorderHandlers, moveColumn, resetColumnOrder, handleColumnResize,
|
|
481
344
|
} = useGridColumns<R>({
|
|
482
|
-
activeColumns,
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
disableColumnReorder,
|
|
491
|
-
pivotMode,
|
|
492
|
-
checkboxSelection,
|
|
493
|
-
hasDetailPanel,
|
|
494
|
-
rowReordering,
|
|
495
|
-
initialState,
|
|
496
|
-
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,
|
|
497
353
|
});
|
|
498
354
|
|
|
499
355
|
useGridStateSnapshot({
|
|
500
|
-
onStateChange,
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
effectivePaginationModel,
|
|
504
|
-
columnWidths,
|
|
505
|
-
effectiveColumnOrder,
|
|
506
|
-
columnVisibilityModel,
|
|
507
|
-
pinnedColumns: effectivePinnedColumns,
|
|
356
|
+
onStateChange, sortModel, filterModel, effectivePaginationModel, columnWidths, effectiveColumnOrder,
|
|
357
|
+
columnVisibilityModel, pinnedColumns,
|
|
358
|
+
density: effectiveDensity,
|
|
508
359
|
});
|
|
509
360
|
|
|
510
361
|
const rowPipeline = useGridRowPipeline<GridRowModel>({
|
|
511
362
|
effectiveRows: effectiveRows as GridRowModel[],
|
|
512
|
-
activeHierarchyHandlers
|
|
363
|
+
activeHierarchyHandlers,
|
|
513
364
|
filterMode,
|
|
514
|
-
filterModel,
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
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({
|
|
519
386
|
paginationMode,
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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[],
|
|
524
429
|
});
|
|
525
|
-
const filteredRows = rowPipeline.filteredRows as R[];
|
|
526
|
-
const pinnedTopRows = rowPipeline.pinnedTopRows as R[];
|
|
527
|
-
const pinnedBottomRows = rowPipeline.pinnedBottomRows as R[];
|
|
528
|
-
const sortedUnpinnedRows = rowPipeline.sortedUnpinnedRows as R[];
|
|
529
|
-
const paginatedUnpinnedRows = rowPipeline.paginatedUnpinnedRows as R[];
|
|
530
|
-
const allRenderableRows = rowPipeline.allRenderableRows as R[];
|
|
531
|
-
|
|
532
|
-
useEffect(() => {
|
|
533
|
-
gridData.apiRef.current.getVisibleRows = () => pagination ? paginatedUnpinnedRows : sortedUnpinnedRows;
|
|
534
|
-
gridData.apiRef.current.getAllFilteredRows = () => sortedUnpinnedRows;
|
|
535
|
-
gridData.apiRef.current.getVisibleColumns = () => effectiveColumns as unknown as GridColDef[];
|
|
536
|
-
}, [sortedUnpinnedRows, paginatedUnpinnedRows, pagination, effectiveColumns, gridData.apiRef]);
|
|
537
430
|
|
|
431
|
+
// Indices address the consumer's own rows, whatever the sort, filter, page or pinning.
|
|
538
432
|
const rowReorderHandlers = useRowReorder({
|
|
539
|
-
rows:
|
|
540
|
-
getRowId:
|
|
433
|
+
rows: effectiveRows,
|
|
434
|
+
getRowId: getRowIdOf,
|
|
541
435
|
onRowOrderChange,
|
|
542
436
|
rowReordering
|
|
543
437
|
});
|
|
544
438
|
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
navigationColumns,
|
|
548
|
-
columnWidths
|
|
549
|
-
);
|
|
550
|
-
|
|
551
|
-
const { aggregationResult } = useAggregation({
|
|
552
|
-
rows: filteredRows,
|
|
439
|
+
const { aggregationResult, isLoading: isAggregationLoading } = useAggregation({
|
|
440
|
+
rows: dataRows,
|
|
553
441
|
columns: activeColumns as unknown as GridColDef[],
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
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,
|
|
560
448
|
});
|
|
561
449
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const result: GridGroupedExportRow[] = [];
|
|
574
|
-
|
|
575
|
-
const traverse = (ids: GridRowId[]) => {
|
|
576
|
-
ids.forEach(id => {
|
|
577
|
-
const node = treeNodes.get(id);
|
|
578
|
-
if (!node) return;
|
|
579
|
-
const isGroup = Boolean(node.children && node.children.length > 0);
|
|
580
|
-
if (isGroup) {
|
|
581
|
-
result.push({
|
|
582
|
-
type: 'group-header',
|
|
583
|
-
depth: node.depth,
|
|
584
|
-
groupField: node.groupingField,
|
|
585
|
-
groupValue: node.groupingValue,
|
|
586
|
-
});
|
|
587
|
-
traverse(node.children!);
|
|
588
|
-
if (hasAggregation && node.aggregatedValues) {
|
|
589
|
-
result.push({
|
|
590
|
-
type: 'group-subtotal',
|
|
591
|
-
depth: node.depth,
|
|
592
|
-
groupField: node.groupingField,
|
|
593
|
-
groupValue: node.groupingValue,
|
|
594
|
-
aggregatedValues: node.aggregatedValues,
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
} else {
|
|
598
|
-
const row = rowLookup.get(id) ?? groupingRows.get(id);
|
|
599
|
-
if (row) {
|
|
600
|
-
result.push({ type: 'leaf', depth: node.depth, row });
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
});
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
traverse(Array.from(treeNodes.keys()).filter(id => treeNodes.get(id)?.parentId === null));
|
|
607
|
-
|
|
608
|
-
if (hasAggregation && aggregationResult) {
|
|
609
|
-
result.push({ type: 'grand-total', depth: 0, aggregatedValues: aggregationResult });
|
|
610
|
-
}
|
|
611
|
-
return result;
|
|
612
|
-
};
|
|
613
|
-
}, [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
|
+
});
|
|
614
460
|
|
|
615
461
|
const layout = useLayout({
|
|
616
462
|
rowHeight: effectiveRowHeight,
|
|
617
|
-
pagination,
|
|
618
|
-
|
|
619
|
-
sortedUnpinnedRows,
|
|
620
|
-
expandedRowIds,
|
|
621
|
-
getDetailPanelHeight,
|
|
463
|
+
pagination, paginatedUnpinnedRows, sortedUnpinnedRows, expandedRowIds, getDetailPanelHeight,
|
|
464
|
+
detailPanelHeights,
|
|
622
465
|
pinnedTopRowsLength: pinnedTopRows.length,
|
|
623
466
|
pinnedBottomRowsLength: pinnedBottomRows.length,
|
|
624
|
-
visibleOrderedColumns,
|
|
467
|
+
pinnedTopRows, pinnedBottomRows, visibleOrderedColumns,
|
|
625
468
|
pinnedColumns: effectivePinnedColumns,
|
|
626
469
|
columnWidths,
|
|
627
470
|
viewportWidth: state.dimensions.viewportWidth || 1000,
|
|
628
|
-
checkboxSelection,
|
|
629
|
-
hasDetailPanel,
|
|
630
|
-
rowReordering,
|
|
631
|
-
pinCheckboxColumn,
|
|
632
|
-
pinExpandColumn,
|
|
633
|
-
autoHeight,
|
|
471
|
+
checkboxSelection, hasDetailPanel, rowReordering, pinCheckboxColumn, pinExpandColumn, autoHeight,
|
|
634
472
|
paginationMode,
|
|
635
473
|
isLoading: state.dataSource.loading,
|
|
636
474
|
pageSize: effectivePaginationModel.pageSize,
|
|
475
|
+
getRowId: getRowIdOf,
|
|
637
476
|
});
|
|
638
477
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const colLocalLeft = unpinnedIndex > 0 ? layout.unpinnedAccWidths[unpinnedIndex - 1] : 0;
|
|
669
|
-
const colLocalRight = layout.unpinnedAccWidths[unpinnedIndex] ?? colLocalLeft;
|
|
670
|
-
const colRight = layout.leftWidth + colLocalRight;
|
|
671
|
-
const { scrollLeft, clientWidth } = el;
|
|
672
|
-
if (colLocalLeft < scrollLeft) {
|
|
673
|
-
el.scrollLeft = colLocalLeft;
|
|
674
|
-
} else if (colRight > scrollLeft + clientWidth) {
|
|
675
|
-
el.scrollLeft = colRight - clientWidth;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
}, [layout, viewportRef, gridData.apiRef]);
|
|
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,
|
|
501
|
+
});
|
|
502
|
+
useGridScrollToIndexesApi<R>({ apiRef, viewportRef, layout, rowHeight: effectiveRowHeight });
|
|
503
|
+
|
|
504
|
+
const { scrollTop, scrollLeft, overscanRows, handleScroll, setViewportElement } = useGridViewport({
|
|
505
|
+
onRowsScrollEnd, overscanRowCount, rowCount: layout.unpinnedRowsLength, autoHeight, setDimensions, viewportRef,
|
|
506
|
+
});
|
|
680
507
|
|
|
681
508
|
const virtualization = useGridVirtualization({
|
|
682
|
-
layout,
|
|
683
|
-
scrollTop,
|
|
684
|
-
scrollLeft,
|
|
509
|
+
layout, scrollTop, scrollLeft,
|
|
685
510
|
viewportWidth: state.dimensions.viewportWidth,
|
|
686
511
|
viewportHeight: state.dimensions.viewportHeight,
|
|
687
|
-
autoHeight,
|
|
688
|
-
rowReordering,
|
|
689
|
-
hasDetailPanel,
|
|
690
|
-
checkboxSelection,
|
|
691
|
-
pinCheckboxColumn,
|
|
692
|
-
pinExpandColumn,
|
|
512
|
+
autoHeight, rowReordering, hasDetailPanel, checkboxSelection, pinCheckboxColumn, pinExpandColumn,
|
|
693
513
|
overscanRows,
|
|
694
514
|
});
|
|
695
515
|
|
|
696
516
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
resizeObserver.observe(viewportRef.current);
|
|
708
|
-
|
|
709
|
-
return () => {
|
|
710
|
-
resizeObserver.disconnect();
|
|
711
|
-
};
|
|
712
|
-
}, [setDimensions]);
|
|
713
|
-
|
|
714
|
-
const handleSelectionChange = useCallback((rowId: GridRowId, isSelected: boolean) => {
|
|
715
|
-
const newSelection = new Set(selectedRowIds);
|
|
716
|
-
if (isSelected) {
|
|
717
|
-
newSelection.add(rowId);
|
|
718
|
-
} else {
|
|
719
|
-
newSelection.delete(rowId);
|
|
720
|
-
}
|
|
721
|
-
const newSelectionArray = Array.from(newSelection);
|
|
722
|
-
|
|
723
|
-
if (!isSelectionControlled) {
|
|
724
|
-
setInternalRowSelectionModel(newSelectionArray);
|
|
725
|
-
}
|
|
726
|
-
onRowSelectionModelChange?.(newSelectionArray);
|
|
727
|
-
}, [selectedRowIds, isSelectionControlled, onRowSelectionModelChange, setInternalRowSelectionModel]);
|
|
728
|
-
|
|
729
|
-
const handleSelectAll = useCallback((isSelected: boolean) => {
|
|
730
|
-
let newSelection: GridRowId[] = [];
|
|
731
|
-
if (isSelected) {
|
|
732
|
-
newSelection = effectiveRows.map((row: GridRowModel) => row.id);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
if (!isSelectionControlled) {
|
|
736
|
-
setInternalRowSelectionModel(newSelection);
|
|
737
|
-
}
|
|
738
|
-
onRowSelectionModelChange?.(newSelection);
|
|
739
|
-
}, [effectiveRows, isSelectionControlled, onRowSelectionModelChange, setInternalRowSelectionModel]);
|
|
740
|
-
|
|
741
|
-
const handleSort = useCallback((field: string, direction: GridSortDirection) => {
|
|
742
|
-
const newSortModel = direction ? [{ field, sort: direction }] : [];
|
|
743
|
-
|
|
744
|
-
if (!isSortControlled) {
|
|
745
|
-
setInternalSortModel(newSortModel as GridSortItem[]);
|
|
746
|
-
}
|
|
747
|
-
onSortModelChange?.(newSortModel as GridSortItem[]);
|
|
748
|
-
}, [isSortControlled, onSortModelChange, setInternalSortModel]);
|
|
749
|
-
|
|
750
|
-
const handleSortAdd = useCallback((field: string, direction: GridSortDirection) => {
|
|
751
|
-
const existing = sortModel.filter(item => item.field !== field);
|
|
752
|
-
const newSortModel: GridSortItem[] = direction
|
|
753
|
-
? [...existing, { field, sort: direction }]
|
|
754
|
-
: existing;
|
|
755
|
-
|
|
756
|
-
if (!isSortControlled) {
|
|
757
|
-
setInternalSortModel(newSortModel);
|
|
758
|
-
}
|
|
759
|
-
onSortModelChange?.(newSortModel);
|
|
760
|
-
}, [sortModel, isSortControlled, onSortModelChange, setInternalSortModel]);
|
|
761
|
-
|
|
762
|
-
const { focusedCell, setFocusedCell, handleFocus, handleBlur, handleKeyDown } = useGridKeyboardNavigation({
|
|
763
|
-
allRenderableRows,
|
|
764
|
-
navigationColumns,
|
|
765
|
-
checkboxSelection,
|
|
766
|
-
selectedRowIds,
|
|
767
|
-
handleSelectionChange,
|
|
768
|
-
handleDetailPanelToggle,
|
|
769
|
-
editingHandlers,
|
|
770
|
-
setKeyboardMode,
|
|
771
|
-
sortModel,
|
|
772
|
-
handleSort,
|
|
773
|
-
isCellEditable,
|
|
774
|
-
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,
|
|
775
527
|
pageSize: effectivePaginationModel.pageSize,
|
|
776
528
|
virtualization,
|
|
777
529
|
viewportRef,
|
|
778
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,
|
|
779
542
|
});
|
|
780
543
|
|
|
781
|
-
const handleCellClick =
|
|
782
|
-
setKeyboardMode
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
useEffect(() => {
|
|
791
|
-
const wasEditing = Boolean(prevEditingCellRef.current);
|
|
792
|
-
const isEditing = Boolean(editingHandlers.editingCell);
|
|
793
|
-
|
|
794
|
-
if (wasEditing && !isEditing) {
|
|
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
|
+
});
|
|
795
553
|
|
|
796
|
-
|
|
797
|
-
|
|
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
|
+
});
|
|
798
565
|
|
|
799
|
-
|
|
800
|
-
|
|
566
|
+
const spanRowWindow = useGridSpanRowWindow({
|
|
567
|
+
spanning,
|
|
568
|
+
renderContext: virtualization.renderContext,
|
|
569
|
+
offsetTop: virtualization.offsetTop,
|
|
570
|
+
cumulativeHeights: layout.cumulativeHeights,
|
|
571
|
+
});
|
|
801
572
|
|
|
802
573
|
const visibleRows = useGridVisibleRows<R>({
|
|
803
|
-
renderContext:
|
|
804
|
-
pinnedTopRows,
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
574
|
+
renderContext: spanRowWindow.renderContext,
|
|
575
|
+
pinnedTopRows, pinnedBottomRows, paginatedUnpinnedRows, sortedUnpinnedRows, pagination,
|
|
576
|
+
getRowId: getRowIdOf,
|
|
577
|
+
});
|
|
578
|
+
|
|
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,
|
|
809
586
|
});
|
|
810
587
|
|
|
811
588
|
useGridDevWarnings({
|
|
@@ -814,77 +591,71 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
814
591
|
autoHeight,
|
|
815
592
|
viewportHeight: state.dimensions.viewportHeight,
|
|
816
593
|
renderedRowCount: visibleRows.length,
|
|
817
|
-
totalRowCount: pinnedTopRows.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,
|
|
818
598
|
});
|
|
819
599
|
|
|
820
|
-
const allSelected
|
|
821
|
-
|
|
600
|
+
const { allSelected, someSelected } = rowSelection;
|
|
601
|
+
|
|
602
|
+
// Header drag-reorder keeps a column inside its column group (and ungrouped columns outside groups).
|
|
603
|
+
const headerReorderHandlers = useColumnGroupReorderGuard(columnGroupingModel, columnReorderHandlers);
|
|
822
604
|
|
|
823
605
|
const hasRowSpanning = React.useMemo(() => effectiveColumns.some(c => !!c.rowSpan), [effectiveColumns]);
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
const standalonePanelRef = React.useRef<HTMLDivElement>(null);
|
|
606
|
+
const columnsPanel = useGridColumnsPanel();
|
|
607
|
+
useGridStylesheetWarning(containerRef);
|
|
827
608
|
|
|
828
609
|
const NoRowsOverlaySlot = slots?.noRowsOverlay;
|
|
829
610
|
const LoadingOverlaySlot = slots?.loadingOverlay;
|
|
611
|
+
const loadingOverlay = LoadingOverlaySlot ? <LoadingOverlaySlot {...slotProps?.loadingOverlay} /> : undefined;
|
|
612
|
+
const noRowsOverlay = NoRowsOverlaySlot ? <NoRowsOverlaySlot {...slotProps?.noRowsOverlay} /> : undefined;
|
|
830
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
|
+
});
|
|
831
640
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
columns: orderedColumns as unknown as GridColDef[],
|
|
851
|
-
baseColumns: columns as unknown as GridColDef[],
|
|
852
|
-
aggregationModel,
|
|
853
|
-
onAggregationModelChange: handleAggregationModelChange,
|
|
854
|
-
...(pivotMode || propPivotModel || onPivotModelChange ? {
|
|
855
|
-
pivotModel: currentPivotModel,
|
|
856
|
-
onPivotModelChange: handlePivotModelChange,
|
|
857
|
-
} : {}),
|
|
858
|
-
filterModel,
|
|
859
|
-
onFilterModelChange,
|
|
860
|
-
columnVisibilityModel,
|
|
861
|
-
onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
|
|
862
|
-
onColumnReorder: reorderHandler,
|
|
863
|
-
onColumnOrderReset: disableColumnReorder ? undefined : () => setInternalColumnOrder(columns.map(c => c.field)),
|
|
864
|
-
forceColumnsOpen: columnsPanelOpen,
|
|
865
|
-
onColumnsPanelClose: () => setColumnsPanelOpen(false),
|
|
866
|
-
...slotProps?.toolbar,
|
|
867
|
-
};
|
|
868
|
-
}, [
|
|
869
|
-
slots?.toolbar, disableColumnReorder, effectiveColumnOrder, orderedColumns, effectiveColumns,
|
|
870
|
-
columnOrder, onColumnOrderChange, setInternalColumnOrder, gridData.apiRef,
|
|
871
|
-
columns, aggregationModel, handleAggregationModelChange, pivotMode,
|
|
872
|
-
propPivotModel, onPivotModelChange, currentPivotModel, handlePivotModelChange,
|
|
873
|
-
filterModel, onFilterModelChange, columnVisibilityModel,
|
|
874
|
-
handleColumnVisibilityModelChange, columnsPanelOpen, slotProps?.toolbar,
|
|
875
|
-
]);
|
|
876
|
-
|
|
877
|
-
// Click-outside handler for standalone column panel
|
|
878
|
-
useEffect(() => {
|
|
879
|
-
if (!columnsPanelOpen || slots?.toolbar) return;
|
|
880
|
-
function handleClickOutside(e: MouseEvent) {
|
|
881
|
-
if (standalonePanelRef.current && !standalonePanelRef.current.contains(e.target as Node)) {
|
|
882
|
-
setColumnsPanelOpen(false);
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
886
|
-
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
887
|
-
}, [columnsPanelOpen, slots?.toolbar]);
|
|
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
|
+
};
|
|
888
659
|
|
|
889
660
|
return (
|
|
890
661
|
<div
|
|
@@ -898,52 +669,65 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
898
669
|
} as unknown as React.CSSProperties}
|
|
899
670
|
aria-busy={effectiveLoading}
|
|
900
671
|
>
|
|
901
|
-
{
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
isOpen={columnsPanelOpen}
|
|
906
|
-
containerRef={containerRef}
|
|
907
|
-
panelRef={standalonePanelRef}
|
|
908
|
-
effectiveColumns={effectiveColumns}
|
|
909
|
-
columnVisibilityModel={columnVisibilityModel}
|
|
910
|
-
effectiveColumnOrder={effectiveColumnOrder}
|
|
911
|
-
columnOrder={columnOrder}
|
|
912
|
-
disableColumnReorder={disableColumnReorder}
|
|
913
|
-
onClose={() => setColumnsPanelOpen(false)}
|
|
914
|
-
onColumnVisibilityChange={handleColumnVisibilityModelChange}
|
|
915
|
-
onColumnOrderChange={onColumnOrderChange}
|
|
916
|
-
setInternalColumnOrder={setInternalColumnOrder}
|
|
917
|
-
/>
|
|
672
|
+
{ToolbarSlot && toolbarProps && (
|
|
673
|
+
<GridToolbarHostContext.Provider value={columnsPanel.toolbarHost}>
|
|
674
|
+
<GridToolbarSlot component={ToolbarSlot} toolbarProps={toolbarProps} />
|
|
675
|
+
</GridToolbarHostContext.Provider>
|
|
918
676
|
)}
|
|
919
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
|
+
|
|
920
694
|
{listView && listViewColumn && (
|
|
921
695
|
<GridListView<R>
|
|
922
696
|
ariaLabel={ariaLabel}
|
|
923
697
|
allRenderableRows={allRenderableRows}
|
|
924
|
-
|
|
698
|
+
dataRowCount={dataRows.length}
|
|
699
|
+
pinnedTopRowCount={pinnedTopRows.length}
|
|
700
|
+
pinnedBottomRowCount={pinnedBottomRows.length}
|
|
701
|
+
unpinnedRowCount={sortedUnpinnedRows.length}
|
|
925
702
|
pagination={pagination}
|
|
926
703
|
effectivePaginationModel={effectivePaginationModel}
|
|
704
|
+
currentPage={rowPipeline.currentPage}
|
|
927
705
|
pageSizeOptions={pageSizeOptions}
|
|
928
706
|
selectedRowIds={selectedRowIds}
|
|
929
707
|
listViewColumn={listViewColumn}
|
|
708
|
+
columnsByField={columnLookup.byField}
|
|
709
|
+
rowMetaMap={rowMetaMap}
|
|
930
710
|
noRowsLabel={effectiveNoRowsLabel}
|
|
931
711
|
rowHeight={effectiveRowHeight}
|
|
932
712
|
checkboxSelection={checkboxSelection}
|
|
933
713
|
paginationMode={paginationMode}
|
|
934
|
-
|
|
935
|
-
serverRowCount={state.pagination.rowCount || 0}
|
|
714
|
+
serverRowCount={paginationRowCount}
|
|
936
715
|
paginationSlot={slots?.pagination}
|
|
937
716
|
paginationSlotProps={slotProps?.pagination}
|
|
938
|
-
localeText={localeText
|
|
939
|
-
paginationRowsPerPage: localeText.paginationRowsPerPage,
|
|
940
|
-
paginationOf: localeText.paginationOf,
|
|
941
|
-
paginationPage: localeText.paginationPage,
|
|
942
|
-
} : undefined}
|
|
717
|
+
localeText={pickPaginationLocaleText(localeText)}
|
|
943
718
|
onRowClick={handleRowClick}
|
|
944
719
|
onRowDoubleClick={onRowDoubleClick}
|
|
945
720
|
onSelectionChange={handleSelectionChange}
|
|
946
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}
|
|
947
731
|
/>
|
|
948
732
|
)}
|
|
949
733
|
|
|
@@ -952,225 +736,150 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
952
736
|
══════════════════════════════════════════════════════════════ */}
|
|
953
737
|
{!listView && (
|
|
954
738
|
<div
|
|
955
|
-
ref={
|
|
956
|
-
viewportRef.current = el;
|
|
957
|
-
gridRef.current = el;
|
|
958
|
-
}}
|
|
739
|
+
ref={setViewportElement}
|
|
959
740
|
className="ogx__viewport"
|
|
960
741
|
onScroll={handleScroll}
|
|
961
742
|
role="grid"
|
|
962
743
|
aria-label={ariaLabel || 'Data grid'}
|
|
963
|
-
aria-rowcount={
|
|
964
|
-
aria-colcount={
|
|
965
|
-
|
|
966
|
-
(checkboxSelection ? 1 : 0) +
|
|
967
|
-
(hasDetailPanel ? 1 : 0) +
|
|
968
|
-
(rowReordering ? 1 : 0)
|
|
969
|
-
}
|
|
744
|
+
aria-rowcount={ariaRows.rowCount}
|
|
745
|
+
aria-colcount={navigationColumns.length}
|
|
746
|
+
aria-multiselectable={rowSelectionEnabled && !disableMultipleRowSelection}
|
|
970
747
|
aria-busy={effectiveLoading}
|
|
971
|
-
tabIndex={
|
|
748
|
+
tabIndex={viewportTabIndex}
|
|
972
749
|
onKeyDownCapture={() => { setKeyboardMode(true); }}
|
|
973
|
-
onMouseDownCapture={
|
|
750
|
+
onMouseDownCapture={handleMouseDownCapture}
|
|
974
751
|
onKeyDown={handleKeyDown}
|
|
975
752
|
onFocus={handleFocus}
|
|
976
753
|
onBlur={handleBlur}
|
|
977
754
|
>
|
|
978
755
|
<div
|
|
979
|
-
ref={contentRef}
|
|
980
756
|
className="ogx__content"
|
|
981
757
|
style={{
|
|
982
758
|
width: virtualization.totalWidth
|
|
983
759
|
}}
|
|
984
760
|
role="presentation"
|
|
985
761
|
>
|
|
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
|
-
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
if (side === 'left') {
|
|
1035
|
-
handlePinnedColumnsChange({ left: [...cleanLeft, field], right: cleanRight });
|
|
1036
|
-
} else if (side === 'right') {
|
|
1037
|
-
handlePinnedColumnsChange({ left: cleanLeft, right: [...cleanRight, field] });
|
|
1038
|
-
} else {
|
|
1039
|
-
handlePinnedColumnsChange({ left: cleanLeft, right: cleanRight });
|
|
1040
|
-
}
|
|
1041
|
-
}}
|
|
1042
|
-
/>
|
|
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>
|
|
1043
810
|
|
|
1044
811
|
{/* Empty State Overlay (Standard View) — showing after header */}
|
|
1045
812
|
{!effectiveLoading && !state.dataSource.error && filteredRows.length === 0 && (
|
|
1046
813
|
<GridEmptyState
|
|
1047
814
|
noRowsLabel={effectiveNoRowsLabel}
|
|
1048
815
|
width={virtualization.totalWidth}
|
|
1049
|
-
overlay={
|
|
816
|
+
overlay={noRowsOverlay}
|
|
1050
817
|
/>
|
|
1051
818
|
)}
|
|
1052
819
|
|
|
1053
|
-
<GridPinnedRows<R>
|
|
1054
|
-
rows={pinnedTopRows}
|
|
1055
|
-
position="top"
|
|
1056
|
-
columns={virtualization.virtualColumns}
|
|
1057
|
-
selectedRowIds={selectedRowIds}
|
|
1058
|
-
checkboxSelection={checkboxSelection}
|
|
1059
|
-
onRowClick={handleRowClick}
|
|
1060
|
-
onRowDoubleClick={onRowDoubleClick}
|
|
1061
|
-
onCellClick={handleCellClick}
|
|
1062
|
-
onSelectionChange={handleSelectionChange}
|
|
1063
|
-
columnWidths={columnWidths}
|
|
1064
|
-
pinnedColumns={effectivePinnedColumns}
|
|
1065
|
-
pinnedRows={pinnedRows}
|
|
1066
|
-
hasDetailPanel={hasDetailPanel}
|
|
1067
|
-
expandedRowIds={expandedRowIds}
|
|
1068
|
-
getDetailPanelContent={getDetailPanelContent}
|
|
1069
|
-
getDetailPanelHeight={getDetailPanelHeight}
|
|
1070
|
-
onDetailPanelToggle={handleDetailPanelToggle}
|
|
1071
|
-
pinCheckboxColumn={pinCheckboxColumn}
|
|
1072
|
-
pinExpandColumn={pinExpandColumn}
|
|
1073
|
-
focusedCell={focusedCell}
|
|
1074
|
-
colspanMap={spanning.colspanMap}
|
|
1075
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1076
|
-
rowHeight={effectiveRowHeight}
|
|
1077
|
-
rowMetaMap={rowMetaMap}
|
|
1078
|
-
/>
|
|
1079
|
-
|
|
1080
820
|
<GridVirtualRows<R>
|
|
821
|
+
{...rowRenderProps}
|
|
1081
822
|
virtualContainerHeight={virtualization.totalHeight - virtualization.pinnedTopHeight - virtualization.pinnedBottomHeight}
|
|
1082
|
-
offsetTop={
|
|
823
|
+
offsetTop={spanRowWindow.offsetTop}
|
|
1083
824
|
effectiveLoading={effectiveLoading}
|
|
1084
825
|
visibleRows={visibleRows}
|
|
1085
826
|
baseColumns={columns as unknown as GridColDef<R>[]}
|
|
1086
|
-
virtualColumns={
|
|
827
|
+
virtualColumns={renderColumns}
|
|
1087
828
|
viewportWidth={state.dimensions.viewportWidth}
|
|
1088
|
-
checkboxSelection={checkboxSelection}
|
|
1089
|
-
hasDetailPanel={hasDetailPanel}
|
|
1090
|
-
rowReordering={rowReordering}
|
|
1091
|
-
rowHeight={effectiveRowHeight}
|
|
1092
|
-
pinnedRows={pinnedRows}
|
|
1093
|
-
selectedRowIds={selectedRowIds}
|
|
1094
|
-
onRowClick={handleRowClick}
|
|
1095
|
-
onRowDoubleClick={onRowDoubleClick}
|
|
1096
|
-
onCellClick={handleCellClick}
|
|
1097
|
-
onSelectionChange={handleSelectionChange}
|
|
1098
|
-
columnWidths={columnWidths}
|
|
1099
|
-
pinnedColumns={effectivePinnedColumns}
|
|
1100
|
-
expandedRowIds={expandedRowIds}
|
|
1101
|
-
getDetailPanelContent={getDetailPanelContent}
|
|
1102
|
-
getDetailPanelHeight={getDetailPanelHeight}
|
|
1103
|
-
onDetailPanelToggle={handleDetailPanelToggle}
|
|
1104
|
-
pinCheckboxColumn={pinCheckboxColumn}
|
|
1105
|
-
pinExpandColumn={pinExpandColumn}
|
|
1106
829
|
rowReorderHandlers={rowReorderHandlers}
|
|
1107
|
-
editingHandlers={editingHandlers}
|
|
1108
|
-
focusedCell={focusedCell}
|
|
1109
|
-
colspanMap={spanning.colspanMap}
|
|
1110
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1111
830
|
paginationMode={paginationMode}
|
|
1112
831
|
dataSourceLoading={state.dataSource.loading}
|
|
1113
832
|
sortedUnpinnedRowCount={sortedUnpinnedRows.length}
|
|
1114
833
|
infiniteScrollSkeletonCount={Math.min(effectivePaginationModel.pageSize, 20)}
|
|
1115
834
|
unpinnedRowsLength={layout.unpinnedRowsLength}
|
|
1116
|
-
|
|
1117
|
-
|
|
835
|
+
lastRenderedRowIndex={spanRowWindow.renderContext.lastRowIndex}
|
|
836
|
+
ariaRowIndexOffset={ariaRows.centerOffset}
|
|
837
|
+
loadingOverlay={loadingOverlay}
|
|
1118
838
|
/>
|
|
1119
839
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
pinnedColumns={effectivePinnedColumns}
|
|
1132
|
-
pinnedRows={pinnedRows}
|
|
1133
|
-
hasDetailPanel={hasDetailPanel}
|
|
1134
|
-
expandedRowIds={expandedRowIds}
|
|
1135
|
-
getDetailPanelContent={getDetailPanelContent}
|
|
1136
|
-
getDetailPanelHeight={getDetailPanelHeight}
|
|
1137
|
-
onDetailPanelToggle={handleDetailPanelToggle}
|
|
1138
|
-
pinCheckboxColumn={pinCheckboxColumn}
|
|
1139
|
-
pinExpandColumn={pinExpandColumn}
|
|
1140
|
-
focusedCell={focusedCell}
|
|
1141
|
-
colspanMap={spanning.colspanMap}
|
|
1142
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1143
|
-
rowHeight={effectiveRowHeight}
|
|
1144
|
-
rowMetaMap={rowMetaMap}
|
|
1145
|
-
/>
|
|
1146
|
-
|
|
1147
|
-
{/* Aggregation Footer Row — suppressed in pivot mode because pivot rows
|
|
1148
|
-
already contain pre-aggregated values with synthetic field keys
|
|
1149
|
-
(e.g. 'Q1\u001frevenue\u001fsum') that don't match aggregationModel keys. */}
|
|
1150
|
-
{hasAggregation && !pivotMode && (
|
|
1151
|
-
<GridAggregationFooter
|
|
1152
|
-
columns={orderedColumns as unknown as GridColDef[]}
|
|
1153
|
-
aggregationModel={aggregationModel}
|
|
1154
|
-
aggregationResult={aggregationResult}
|
|
1155
|
-
columnWidths={resolvedColumnWidths}
|
|
1156
|
-
rowHeight={effectiveRowHeight}
|
|
1157
|
-
checkboxSelection={checkboxSelection}
|
|
1158
|
-
hasDetailPanel={hasDetailPanel}
|
|
1159
|
-
rowReordering={rowReordering}
|
|
1160
|
-
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}
|
|
1161
851
|
/>
|
|
1162
|
-
|
|
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>
|
|
1163
872
|
|
|
1164
873
|
</div>
|
|
1165
874
|
</div>
|
|
1166
875
|
)}
|
|
1167
876
|
|
|
1168
|
-
{
|
|
877
|
+
{FooterSlot && (
|
|
1169
878
|
<FooterSlot
|
|
1170
879
|
apiRef={gridData.apiRef}
|
|
1171
880
|
aggregationModel={aggregationModel}
|
|
1172
881
|
aggregationResult={hasAggregation ? aggregationResult : null}
|
|
1173
|
-
rowCount={
|
|
882
|
+
rowCount={isHierarchyEnabled && paginationMode !== 'server' ? dataRows.length : paginationRowCount}
|
|
1174
883
|
pagination={pagination}
|
|
1175
884
|
paginationModel={effectivePaginationModel}
|
|
1176
885
|
pageSizeOptions={pageSizeOptions}
|
|
@@ -1179,40 +888,33 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
1179
888
|
/>
|
|
1180
889
|
)}
|
|
1181
890
|
|
|
1182
|
-
{!listView && !FooterSlot && pagination && (
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
: (filterModel && ((filterModel.quickFilterValues?.length || 0) > 0 || (filterModel.items?.length || 0) > 0))
|
|
1210
|
-
? `${filteredRows.length} ${filteredRows.length === 1 ? 'row' : 'rows'} found`
|
|
1211
|
-
: ''
|
|
1212
|
-
)}
|
|
1213
|
-
</div>
|
|
1214
|
-
|
|
1215
|
-
<GridErrorOverlay error={state.dataSource.error} />
|
|
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} />
|
|
1216
918
|
</div>
|
|
1217
919
|
);
|
|
1218
920
|
}
|