@opencorestack/opengridx 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +399 -0
- package/README.md +95 -72
- package/dist/index.d.ts +590 -131
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7891 -5631
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +17 -23
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +348 -166
- package/docs/README.md +6 -1
- package/docs/architecture/datagrid-orchestration.md +81 -0
- package/docs/architecture/grid-row-meta.md +102 -0
- package/docs/architecture/use-grid-columns.md +128 -0
- package/docs/architecture/use-grid-controlled-state.md +157 -0
- package/docs/architecture/use-grid-row-pipeline.md +120 -0
- package/docs/architecture/use-grid-scroll-sync.md +111 -0
- package/docs/architecture/use-grid-state-snapshot.md +90 -0
- package/docs/architecture/use-grid-virtualization.md +115 -0
- package/docs/architecture/use-grid-visible-rows.md +85 -0
- package/docs/assets/banner-alt.png +0 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/hero.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/components/aggregation-footer.md +15 -10
- package/docs/components/cell.md +16 -6
- package/docs/components/column-group-header.md +55 -28
- package/docs/components/column-resize.md +17 -13
- package/docs/components/column-visibility.md +6 -7
- package/docs/components/datagrid.md +15 -13
- package/docs/components/empty-state.md +2 -1
- package/docs/components/error-overlay.md +12 -7
- package/docs/components/filter-panel.md +28 -8
- package/docs/components/header.md +28 -9
- package/docs/components/pagination.md +14 -8
- package/docs/components/row.md +21 -5
- package/docs/components/toolbar.md +27 -9
- package/docs/components/tooltip.md +16 -7
- package/docs/customization/slots-api.md +90 -38
- package/docs/customization/theming.md +66 -18
- package/docs/features/aggregation-pivot.md +75 -9
- package/docs/features/cell-spanning.md +80 -125
- package/docs/features/clipboard.md +41 -16
- package/docs/features/custom-pagination.md +38 -18
- package/docs/features/data-source.md +36 -13
- package/docs/features/editing-reordering.md +125 -16
- package/docs/features/export-guide.md +126 -39
- package/docs/features/filtering.md +44 -6
- package/docs/features/infinite-scroll.md +54 -46
- package/docs/features/keyboard-navigation.md +83 -0
- package/docs/features/list-view.md +58 -5
- package/docs/features/loading-states.md +18 -20
- package/docs/features/master-detail.md +18 -5
- package/docs/features/pdf-export.md +72 -19
- package/docs/features/pinning.md +24 -5
- package/docs/features/selection.md +50 -10
- package/docs/features/sorting-pagination.md +64 -14
- package/docs/features/state-persistence.md +78 -10
- package/docs/features/toolbar-customization.md +26 -17
- package/docs/features/tree-data-grouping.md +36 -8
- package/docs/features/virtualization.md +37 -14
- package/docs/migration/v1-to-v2.md +115 -0
- package/docs/migration/v2-to-v3.md +1233 -0
- package/docs/performance.md +124 -0
- package/docs/roadmap.md +5 -5
- package/lib/components/Cell/Cell.css +17 -1
- package/lib/components/Cell/Cell.tsx +129 -57
- package/lib/components/Cell/CellErrorBoundary.tsx +12 -6
- package/lib/components/Cell/GridEditInputCell.tsx +114 -41
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +7 -1
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +15 -2
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +104 -38
- package/lib/components/ColumnResizeHandle/clampResizeWidth.ts +13 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +6 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +21 -13
- package/lib/components/DataGrid/DataGrid.css +85 -12
- package/lib/components/DataGrid/DataGrid.tsx +582 -876
- package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
- package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
- package/lib/components/DataGrid/GridListView.tsx +165 -24
- package/lib/components/DataGrid/GridLiveRegion.tsx +31 -0
- package/lib/components/DataGrid/GridLoadingOverlay.tsx +27 -0
- package/lib/components/DataGrid/GridPaginationArea.tsx +44 -0
- package/lib/components/DataGrid/GridPinnedRows.tsx +62 -11
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
- package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
- package/lib/components/DataGrid/GridVirtualRows.tsx +40 -24
- package/lib/components/DetailPanel/DetailPanel.css +0 -6
- package/lib/components/DetailPanel/DetailPanel.tsx +34 -5
- package/lib/components/DetailPanel/DetailPanelContent.tsx +17 -0
- package/lib/components/FilterPanel/FilterPanel.css +13 -2
- package/lib/components/FilterPanel/FilterPanel.tsx +272 -99
- package/lib/components/Header/ColumnMenu.tsx +91 -39
- package/lib/components/Header/Header.css +6 -3
- package/lib/components/Header/Header.tsx +181 -160
- package/lib/components/ListView/ListView.css +25 -0
- package/lib/components/ListView/ListViewRow.tsx +76 -10
- package/lib/components/Pagination/Pagination.tsx +15 -7
- package/lib/components/Row/Row.tsx +177 -77
- package/lib/components/Toolbar/GlobalSearch.css +6 -3
- package/lib/components/Toolbar/GlobalSearch.tsx +26 -27
- package/lib/components/Toolbar/GridToolbar.css +12 -11
- package/lib/components/Toolbar/GridToolbar.tsx +133 -89
- package/lib/components/Toolbar/PivotPanel.tsx +89 -49
- package/lib/components/Tooltip/Tooltip.css +20 -0
- package/lib/components/Tooltip/Tooltip.tsx +68 -35
- package/lib/components/ui/Button.tsx +3 -0
- package/lib/components/ui/Checkbox.tsx +2 -1
- package/lib/components/ui/ExpandIcon.css +0 -9
- package/lib/components/ui/ExpandIcon.tsx +4 -1
- package/lib/hooks/core/gridApiPlaceholder.ts +34 -0
- package/lib/hooks/core/gridToolbarHostContext.ts +14 -0
- package/lib/hooks/core/useDataGrid.ts +115 -173
- package/lib/hooks/core/useGridAggregationApi.ts +72 -0
- package/lib/hooks/core/useGridApiMethods.ts +115 -0
- package/lib/hooks/core/useGridApiRef.ts +19 -4
- package/lib/hooks/core/useGridApiRefBinding.ts +18 -0
- package/lib/hooks/core/useGridAriaRows.ts +38 -0
- package/lib/hooks/core/useGridClipboardApi.ts +38 -0
- package/lib/hooks/core/useGridColumnLookup.ts +30 -0
- package/lib/hooks/core/useGridColumns.tsx +279 -76
- package/lib/hooks/core/useGridColumnsPanel.ts +77 -0
- package/lib/hooks/core/useGridControlledState.ts +99 -6
- package/lib/hooks/core/useGridDetailPanel.ts +51 -0
- package/lib/hooks/core/useGridDevWarnings.ts +104 -5
- package/lib/hooks/core/useGridFocusHandlers.ts +50 -0
- package/lib/hooks/core/useGridGroupingColumn.ts +62 -0
- package/lib/hooks/core/useGridHeaderHandlers.ts +92 -0
- package/lib/hooks/core/useGridHierarchy.ts +81 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +447 -243
- package/lib/hooks/core/useGridLiveRowSelection.ts +67 -0
- package/lib/hooks/core/useGridPageCorrection.ts +55 -0
- package/lib/hooks/core/useGridRowIdOf.ts +32 -0
- package/lib/hooks/core/useGridRowInteractions.ts +81 -0
- package/lib/hooks/core/useGridRowPipeline.ts +69 -39
- package/lib/hooks/core/useGridRowSelection.ts +91 -0
- package/lib/hooks/core/useGridScrollSync.ts +80 -32
- package/lib/hooks/core/useGridScrollToIndexesApi.ts +45 -0
- package/lib/hooks/core/useGridStateSnapshot.ts +40 -5
- package/lib/hooks/core/useGridThemeDimensions.ts +49 -0
- package/lib/hooks/core/useGridToolbarProps.ts +97 -0
- package/lib/hooks/core/useGridViewport.ts +38 -0
- package/lib/hooks/core/useGridViewportSize.ts +26 -0
- package/lib/hooks/core/useGridVisibleRows.ts +17 -5
- package/lib/hooks/core/useLayout.ts +215 -195
- package/lib/hooks/core/useRowsScrollEndLatch.ts +41 -0
- package/lib/hooks/core/useStableColumns.ts +34 -0
- package/lib/hooks/features/useAggregation.ts +82 -51
- package/lib/hooks/features/useColumnGroupReorderGuard.ts +34 -0
- package/lib/hooks/features/useDetailPanelHeights.ts +29 -0
- package/lib/hooks/features/useGridClipboard.ts +133 -73
- package/lib/hooks/features/useGridDataSource.ts +354 -128
- package/lib/hooks/features/useGridEditing.ts +211 -51
- package/lib/hooks/features/useGridPivot.ts +92 -0
- package/lib/hooks/features/useGridSpanRenderWindow.ts +104 -0
- package/lib/hooks/features/useGridSpanning.ts +410 -306
- package/lib/hooks/features/usePivot.ts +0 -0
- package/lib/hooks/features/useServerTreeChildren.ts +50 -0
- package/lib/hooks/useColumnReorder.ts +38 -44
- package/lib/hooks/useRowGrouping.ts +298 -160
- package/lib/hooks/useRowReorder.ts +62 -31
- package/lib/hooks/useTreeData.ts +287 -220
- package/lib/index.ts +28 -2
- package/lib/state/index.ts +1 -0
- package/lib/state/types.ts +7 -1
- package/lib/state/useGridStateStorage.ts +88 -29
- package/lib/theme/DataGridThemeProvider.tsx +143 -38
- package/lib/theme/gridThemeContext.ts +5 -0
- package/lib/theme/index.ts +5 -0
- package/lib/theme/presets.ts +5 -4
- package/lib/theme/types.ts +40 -2
- package/lib/types/index.ts +313 -116
- package/lib/utils/aggregation/index.ts +119 -24
- package/lib/utils/aria/index.ts +40 -0
- package/lib/utils/columnGroups.ts +110 -0
- package/lib/utils/columnLookup.ts +33 -0
- package/lib/utils/columnWidth.ts +22 -0
- package/lib/utils/dataSource/index.ts +46 -0
- package/lib/utils/detailPanel.ts +66 -0
- package/lib/utils/dragData.ts +44 -0
- package/lib/utils/editing/index.ts +30 -0
- package/lib/utils/export/exportShared.ts +197 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +278 -139
- package/lib/utils/export/exportToPdf.ts +143 -92
- package/lib/utils/export/groupLabel.ts +14 -0
- package/lib/utils/export/index.ts +278 -272
- package/lib/utils/export/pdfText.ts +50 -0
- package/lib/utils/filtering/index.ts +277 -148
- package/lib/utils/focus/index.ts +115 -0
- package/lib/utils/gridApiRows.ts +35 -0
- package/lib/utils/gridModes.ts +77 -0
- package/lib/utils/grouping/groupedExportRows.ts +91 -0
- package/lib/utils/pagination/index.ts +56 -0
- package/lib/utils/pinning/index.ts +77 -33
- package/lib/utils/pivot/index.ts +368 -0
- package/lib/utils/scroll/index.ts +55 -5
- package/lib/utils/scroll/scrollEnd.ts +18 -0
- package/lib/utils/sorting/index.ts +154 -30
- package/lib/utils/syntheticRows.ts +12 -0
- package/lib/utils/values.ts +206 -0
- package/lib/utils/viewport.ts +14 -0
- package/llms.txt +261 -164
- package/package.json +13 -5
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
- package/lib/components/DataGrid/DataGrid.defects.test.tsx +0 -103
- package/lib/components/DataGrid/DataGrid.regression.test.tsx +0 -132
- package/lib/components/DataGrid/DataGrid.smoke.test.tsx +0 -58
- package/lib/components/DataGrid/DataGrid.v2.test.tsx +0 -127
- package/lib/components/DataGrid/DataGrid.virtualization.browser.test.tsx +0 -183
- package/lib/components/Header/Header.test.tsx +0 -135
- package/lib/components/Pagination/Pagination.test.tsx +0 -64
- package/lib/hooks/core/useDataGrid.regression.test.ts +0 -66
- package/lib/hooks/core/useGridControlledState.test.ts +0 -86
- package/lib/hooks/core/useGridKeyboardNavigation.test.ts +0 -176
- package/lib/hooks/core/useGridRowPipeline.test.ts +0 -117
- package/lib/hooks/features/useAggregation.test.ts +0 -175
- package/lib/hooks/features/usePivot.test.ts +0 -202
- package/lib/hooks/useRowGrouping.test.ts +0 -298
- package/lib/hooks/useTreeData.test.ts +0 -83
- package/lib/utils/aggregation/aggregation.test.ts +0 -16
- package/lib/utils/export/exportToExcelAdvanced.test.ts +0 -109
- package/lib/utils/export/exportToPdf.test.ts +0 -120
- package/lib/utils/export/groupedExport.test.ts +0 -144
- package/lib/utils/filtering/filtering.test.ts +0 -178
- package/lib/utils/sorting/sorting.test.ts +0 -88
|
@@ -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,82 +591,77 @@ 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,
|
|
598
|
+
listViewRowCount: listView && listViewColumn ? allRenderableRows.length : 0,
|
|
818
599
|
});
|
|
819
600
|
|
|
820
|
-
const allSelected
|
|
821
|
-
|
|
601
|
+
const { allSelected, someSelected } = rowSelection;
|
|
602
|
+
|
|
603
|
+
// Header drag-reorder keeps a column inside its column group (and ungrouped columns outside groups).
|
|
604
|
+
const headerReorderHandlers = useColumnGroupReorderGuard(columnGroupingModel, columnReorderHandlers);
|
|
822
605
|
|
|
823
606
|
const hasRowSpanning = React.useMemo(() => effectiveColumns.some(c => !!c.rowSpan), [effectiveColumns]);
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
const standalonePanelRef = React.useRef<HTMLDivElement>(null);
|
|
607
|
+
const columnsPanel = useGridColumnsPanel();
|
|
608
|
+
useGridStylesheetWarning(containerRef);
|
|
827
609
|
|
|
828
610
|
const NoRowsOverlaySlot = slots?.noRowsOverlay;
|
|
829
611
|
const LoadingOverlaySlot = slots?.loadingOverlay;
|
|
612
|
+
const loadingOverlay = LoadingOverlaySlot ? <LoadingOverlaySlot {...slotProps?.loadingOverlay} /> : undefined;
|
|
613
|
+
const noRowsOverlay = NoRowsOverlaySlot ? <NoRowsOverlaySlot {...slotProps?.noRowsOverlay} /> : undefined;
|
|
830
614
|
const FooterSlot = slots?.footer;
|
|
615
|
+
// Loading with rows on screen: the rows stay and an indicator runs over them. With no rows the
|
|
616
|
+
// body shows skeletons or the loading overlay instead, and infinite scroll appends skeleton rows.
|
|
617
|
+
const showLoadingOverRows = effectiveLoading && allRenderableRows.length > 0 && paginationMode !== 'infinite';
|
|
618
|
+
const ToolbarSlot = slots?.toolbar;
|
|
619
|
+
|
|
620
|
+
const toolbarProps = useGridToolbarProps<R>({
|
|
621
|
+
toolbar: slots?.toolbar,
|
|
622
|
+
toolbarSlotProps: slotProps?.toolbar,
|
|
623
|
+
apiRef,
|
|
624
|
+
orderedColumns,
|
|
625
|
+
baseColumns: columns,
|
|
626
|
+
aggregationModel,
|
|
627
|
+
onAggregationModelChange: handleAggregationModelChange,
|
|
628
|
+
pivotMode,
|
|
629
|
+
pivotModelProp: propPivotModel,
|
|
630
|
+
onPivotModelChangeProp: onPivotModelChange,
|
|
631
|
+
pivotModel: currentPivotModel,
|
|
632
|
+
onPivotModelChange: handlePivotModelChange,
|
|
633
|
+
filterModel,
|
|
634
|
+
onFilterModelChange: handleFilterModelChange,
|
|
635
|
+
columnVisibilityModel,
|
|
636
|
+
onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
|
|
637
|
+
disableColumnReorder, columnGroupingModel, moveColumn, resetColumnOrder,
|
|
638
|
+
forceColumnsOpen: columnsPanel.toolbarPanelRequested,
|
|
639
|
+
onColumnsPanelClose: columnsPanel.closeToolbarPanel,
|
|
640
|
+
});
|
|
831
641
|
|
|
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]);
|
|
642
|
+
// Props the row renderers (top-pinned, centre and bottom-pinned rows) all take.
|
|
643
|
+
const rowRenderProps = {
|
|
644
|
+
rowReordering, columnIndexMap, editingHandlers, isCellEditable, selectedRowIds, checkboxSelection,
|
|
645
|
+
onRowClick: handleRowClick,
|
|
646
|
+
onRowDoubleClick,
|
|
647
|
+
onCellClick: handleCellClick,
|
|
648
|
+
onSelectionChange: handleSelectionChange,
|
|
649
|
+
columnWidths,
|
|
650
|
+
pinnedColumns: effectivePinnedColumns,
|
|
651
|
+
hasDetailPanel, expandedRowIds, getDetailPanelContent, getDetailPanelHeight,
|
|
652
|
+
onDetailPanelToggle: handleDetailPanelToggle,
|
|
653
|
+
onDetailPanelHeightChange: reportDetailPanelHeight,
|
|
654
|
+
pinCheckboxColumn, pinExpandColumn, focusedCell,
|
|
655
|
+
colspanMap: spanning.colspanMap,
|
|
656
|
+
rowSpanningCaches: spanning.rowSpanningCaches,
|
|
657
|
+
rowHeight: effectiveRowHeight,
|
|
658
|
+
rowMetaMap,
|
|
659
|
+
};
|
|
888
660
|
|
|
889
661
|
return (
|
|
890
662
|
<div
|
|
891
663
|
ref={containerRef}
|
|
892
|
-
className={['ogx', className, autoHeight && 'ogx--auto-height', hasRowSpanning && 'ogx--row-spanning', listView && 'ogx--list-view'].filter(Boolean).join(' ')}
|
|
664
|
+
className={['ogx', className, autoHeight && 'ogx--auto-height', !autoHeight && height === undefined && style?.height === undefined && 'ogx--fill', hasRowSpanning && 'ogx--row-spanning', listView && 'ogx--list-view'].filter(Boolean).join(' ')}
|
|
893
665
|
style={{
|
|
894
666
|
...style,
|
|
895
667
|
height: height ?? style?.height,
|
|
@@ -898,52 +670,65 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
898
670
|
} as unknown as React.CSSProperties}
|
|
899
671
|
aria-busy={effectiveLoading}
|
|
900
672
|
>
|
|
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
|
-
/>
|
|
673
|
+
{ToolbarSlot && toolbarProps && (
|
|
674
|
+
<GridToolbarHostContext.Provider value={columnsPanel.toolbarHost}>
|
|
675
|
+
<GridToolbarSlot component={ToolbarSlot} toolbarProps={toolbarProps} />
|
|
676
|
+
</GridToolbarHostContext.Provider>
|
|
918
677
|
)}
|
|
919
678
|
|
|
679
|
+
{/* Used by the column menu's Manage columns when no GridToolbar can show the panel */}
|
|
680
|
+
<GridStandaloneColumnPanel<R>
|
|
681
|
+
isOpen={columnsPanel.standalonePanelOpen}
|
|
682
|
+
containerRef={containerRef}
|
|
683
|
+
panelRef={columnsPanel.standalonePanelRef}
|
|
684
|
+
columns={orderedColumns}
|
|
685
|
+
columnVisibilityModel={columnVisibilityModel}
|
|
686
|
+
disableColumnReorder={disableColumnReorder}
|
|
687
|
+
onClose={columnsPanel.closeStandalonePanel}
|
|
688
|
+
onColumnVisibilityChange={handleColumnVisibilityModelChange}
|
|
689
|
+
onColumnMove={moveColumn}
|
|
690
|
+
onColumnOrderReset={resetColumnOrder}
|
|
691
|
+
columnGroupingModel={columnGroupingModel}
|
|
692
|
+
/>
|
|
693
|
+
|
|
694
|
+
|
|
920
695
|
{listView && listViewColumn && (
|
|
921
696
|
<GridListView<R>
|
|
922
697
|
ariaLabel={ariaLabel}
|
|
923
698
|
allRenderableRows={allRenderableRows}
|
|
924
|
-
|
|
699
|
+
dataRowCount={dataRows.length}
|
|
700
|
+
pinnedTopRowCount={pinnedTopRows.length}
|
|
701
|
+
pinnedBottomRowCount={pinnedBottomRows.length}
|
|
702
|
+
unpinnedRowCount={sortedUnpinnedRows.length}
|
|
925
703
|
pagination={pagination}
|
|
926
704
|
effectivePaginationModel={effectivePaginationModel}
|
|
705
|
+
currentPage={rowPipeline.currentPage}
|
|
927
706
|
pageSizeOptions={pageSizeOptions}
|
|
928
707
|
selectedRowIds={selectedRowIds}
|
|
929
708
|
listViewColumn={listViewColumn}
|
|
709
|
+
columnsByField={columnLookup.byField}
|
|
710
|
+
rowMetaMap={rowMetaMap}
|
|
930
711
|
noRowsLabel={effectiveNoRowsLabel}
|
|
931
712
|
rowHeight={effectiveRowHeight}
|
|
932
713
|
checkboxSelection={checkboxSelection}
|
|
933
714
|
paginationMode={paginationMode}
|
|
934
|
-
|
|
935
|
-
serverRowCount={state.pagination.rowCount || 0}
|
|
715
|
+
serverRowCount={paginationRowCount}
|
|
936
716
|
paginationSlot={slots?.pagination}
|
|
937
717
|
paginationSlotProps={slotProps?.pagination}
|
|
938
|
-
localeText={localeText
|
|
939
|
-
paginationRowsPerPage: localeText.paginationRowsPerPage,
|
|
940
|
-
paginationOf: localeText.paginationOf,
|
|
941
|
-
paginationPage: localeText.paginationPage,
|
|
942
|
-
} : undefined}
|
|
718
|
+
localeText={pickPaginationLocaleText(localeText)}
|
|
943
719
|
onRowClick={handleRowClick}
|
|
944
720
|
onRowDoubleClick={onRowDoubleClick}
|
|
945
721
|
onSelectionChange={handleSelectionChange}
|
|
946
722
|
onPaginationModelChange={handlePaginationModelChange}
|
|
723
|
+
onRowsScrollEnd={onRowsScrollEnd}
|
|
724
|
+
getRowId={getRowIdOf}
|
|
725
|
+
multiselectable={rowSelectionEnabled && !disableMultipleRowSelection}
|
|
726
|
+
selectable={rowSelectionEnabled}
|
|
727
|
+
onToggleExpansion={activeHierarchyHandlers?.toggleExpansion}
|
|
728
|
+
loading={effectiveLoading}
|
|
729
|
+
loadingOverlay={loadingOverlay}
|
|
730
|
+
noRowsOverlay={noRowsOverlay}
|
|
731
|
+
showPaginationControls={!FooterSlot}
|
|
947
732
|
/>
|
|
948
733
|
)}
|
|
949
734
|
|
|
@@ -952,225 +737,153 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
952
737
|
══════════════════════════════════════════════════════════════ */}
|
|
953
738
|
{!listView && (
|
|
954
739
|
<div
|
|
955
|
-
ref={
|
|
956
|
-
viewportRef.current = el;
|
|
957
|
-
gridRef.current = el;
|
|
958
|
-
}}
|
|
740
|
+
ref={setViewportElement}
|
|
959
741
|
className="ogx__viewport"
|
|
960
742
|
onScroll={handleScroll}
|
|
961
743
|
role="grid"
|
|
962
744
|
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
|
-
}
|
|
745
|
+
aria-rowcount={ariaRows.rowCount}
|
|
746
|
+
aria-colcount={navigationColumns.length}
|
|
747
|
+
aria-multiselectable={rowSelectionEnabled && !disableMultipleRowSelection}
|
|
970
748
|
aria-busy={effectiveLoading}
|
|
971
|
-
tabIndex={
|
|
749
|
+
tabIndex={viewportTabIndex}
|
|
972
750
|
onKeyDownCapture={() => { setKeyboardMode(true); }}
|
|
973
|
-
onMouseDownCapture={
|
|
751
|
+
onMouseDownCapture={handleMouseDownCapture}
|
|
974
752
|
onKeyDown={handleKeyDown}
|
|
975
753
|
onFocus={handleFocus}
|
|
976
754
|
onBlur={handleBlur}
|
|
977
755
|
>
|
|
978
756
|
<div
|
|
979
|
-
ref={contentRef}
|
|
980
757
|
className="ogx__content"
|
|
981
758
|
style={{
|
|
982
|
-
|
|
759
|
+
// With right-pinned columns the content spans at least the viewport, so they sit at its right edge.
|
|
760
|
+
width: effectivePinnedColumns?.right?.length
|
|
761
|
+
? `max(100%, ${virtualization.totalWidth}px)`
|
|
762
|
+
: virtualization.totalWidth
|
|
983
763
|
}}
|
|
984
764
|
role="presentation"
|
|
985
765
|
>
|
|
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
|
-
/>
|
|
766
|
+
{/* Header and top-pinned rows stick together, so pinned rows sit below every header row. */}
|
|
767
|
+
<div className="ogx__sticky-top" role="presentation">
|
|
768
|
+
<Header
|
|
769
|
+
columns={renderColumns}
|
|
770
|
+
allColumns={renderedDataColumns}
|
|
771
|
+
columnGroupingModel={columnGroupingModel}
|
|
772
|
+
checkboxSelection={checkboxSelection}
|
|
773
|
+
allSelected={allSelected}
|
|
774
|
+
someSelected={someSelected}
|
|
775
|
+
onSelectAll={rowSelection.selectAll}
|
|
776
|
+
sortModel={sortModel}
|
|
777
|
+
onSort={handleSort}
|
|
778
|
+
onSortAdd={handleSortAdd}
|
|
779
|
+
multiSort={multiSort}
|
|
780
|
+
|
|
781
|
+
onColumnResize={handleColumnResize}
|
|
782
|
+
columnWidths={columnWidths}
|
|
783
|
+
pinnedColumns={effectivePinnedColumns}
|
|
784
|
+
|
|
785
|
+
focusedCell={focusedCell}
|
|
786
|
+
columnIndexMap={columnIndexMap}
|
|
787
|
+
onHeaderClick={handleHeaderClick}
|
|
788
|
+
onDragStart={headerReorderHandlers.onDragStart}
|
|
789
|
+
onDragOver={headerReorderHandlers.onDragOver}
|
|
790
|
+
onDragEnd={headerReorderHandlers.onDragEnd}
|
|
791
|
+
onDrop={headerReorderHandlers.onDrop}
|
|
792
|
+
draggedColumn={headerReorderHandlers.draggedColumn}
|
|
793
|
+
dragOverColumn={headerReorderHandlers.dragOverColumn}
|
|
794
|
+
rowReordering={rowReordering}
|
|
795
|
+
hasDetailPanel={hasDetailPanel}
|
|
796
|
+
pinCheckboxColumn={pinCheckboxColumn}
|
|
797
|
+
pinExpandColumn={pinExpandColumn}
|
|
798
|
+
aggregationModel={aggregationModel}
|
|
799
|
+
onHideColumn={handleHideColumn}
|
|
800
|
+
onManageColumns={columnsPanel.openColumnsPanel}
|
|
801
|
+
onPinColumn={handlePinColumn}
|
|
802
|
+
/>
|
|
803
|
+
|
|
804
|
+
<GridPinnedRows<R>
|
|
805
|
+
{...rowRenderProps}
|
|
806
|
+
rows={pinnedTopRows}
|
|
807
|
+
position="top"
|
|
808
|
+
ariaRowIndexBase={ariaRows.topBase}
|
|
809
|
+
columns={renderColumns}
|
|
810
|
+
pinnedRows={pinnedRows}
|
|
811
|
+
getRowId={getRowIdOf}
|
|
812
|
+
/>
|
|
813
|
+
</div>
|
|
1043
814
|
|
|
1044
815
|
{/* Empty State Overlay (Standard View) — showing after header */}
|
|
1045
816
|
{!effectiveLoading && !state.dataSource.error && filteredRows.length === 0 && (
|
|
1046
817
|
<GridEmptyState
|
|
1047
818
|
noRowsLabel={effectiveNoRowsLabel}
|
|
1048
819
|
width={virtualization.totalWidth}
|
|
1049
|
-
overlay={
|
|
820
|
+
overlay={noRowsOverlay}
|
|
1050
821
|
/>
|
|
1051
822
|
)}
|
|
1052
823
|
|
|
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
824
|
<GridVirtualRows<R>
|
|
825
|
+
{...rowRenderProps}
|
|
1081
826
|
virtualContainerHeight={virtualization.totalHeight - virtualization.pinnedTopHeight - virtualization.pinnedBottomHeight}
|
|
1082
|
-
offsetTop={
|
|
827
|
+
offsetTop={spanRowWindow.offsetTop}
|
|
1083
828
|
effectiveLoading={effectiveLoading}
|
|
1084
829
|
visibleRows={visibleRows}
|
|
1085
830
|
baseColumns={columns as unknown as GridColDef<R>[]}
|
|
1086
|
-
virtualColumns={
|
|
831
|
+
virtualColumns={renderColumns}
|
|
1087
832
|
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
833
|
rowReorderHandlers={rowReorderHandlers}
|
|
1107
|
-
editingHandlers={editingHandlers}
|
|
1108
|
-
focusedCell={focusedCell}
|
|
1109
|
-
colspanMap={spanning.colspanMap}
|
|
1110
|
-
rowSpanningCaches={spanning.rowSpanningState.caches}
|
|
1111
834
|
paginationMode={paginationMode}
|
|
1112
835
|
dataSourceLoading={state.dataSource.loading}
|
|
1113
836
|
sortedUnpinnedRowCount={sortedUnpinnedRows.length}
|
|
1114
837
|
infiniteScrollSkeletonCount={Math.min(effectivePaginationModel.pageSize, 20)}
|
|
1115
838
|
unpinnedRowsLength={layout.unpinnedRowsLength}
|
|
1116
|
-
|
|
1117
|
-
|
|
839
|
+
lastRenderedRowIndex={spanRowWindow.renderContext.lastRowIndex}
|
|
840
|
+
ariaRowIndexOffset={ariaRows.centerOffset}
|
|
841
|
+
loadingOverlay={loadingOverlay}
|
|
1118
842
|
/>
|
|
1119
843
|
|
|
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}
|
|
844
|
+
{/* Bottom-pinned rows and the aggregation footer stick together, footer last. */}
|
|
845
|
+
<div className="ogx__sticky-bottom" role="presentation">
|
|
846
|
+
<GridPinnedRows<R>
|
|
847
|
+
{...rowRenderProps}
|
|
848
|
+
rows={pinnedBottomRows}
|
|
849
|
+
position="bottom"
|
|
850
|
+
rowIndexOffset={ariaRows.bottomRowIndexOffset}
|
|
851
|
+
ariaRowIndexBase={ariaRows.bottomBase}
|
|
852
|
+
columns={renderColumns}
|
|
853
|
+
pinnedRows={pinnedRows}
|
|
854
|
+
getRowId={getRowIdOf}
|
|
1161
855
|
/>
|
|
1162
|
-
|
|
856
|
+
|
|
857
|
+
{/* Aggregation Footer Row — laid out from the same virtual columns as the rows, so
|
|
858
|
+
hidden, pinned and scrolled columns line up. Off in pivot mode (hasAggregation). */}
|
|
859
|
+
{hasAggregation && rowGroupingHandlers.rootAggregationPosition !== null && (
|
|
860
|
+
<GridAggregationFooter
|
|
861
|
+
columns={virtualization.virtualColumns as unknown as GridColDef[]}
|
|
862
|
+
aggregationModel={aggregationModel}
|
|
863
|
+
aggregationResult={aggregationResult}
|
|
864
|
+
columnWidths={columnWidths}
|
|
865
|
+
rowHeight={effectiveRowHeight}
|
|
866
|
+
checkboxSelection={checkboxSelection}
|
|
867
|
+
hasDetailPanel={hasDetailPanel}
|
|
868
|
+
rowReordering={rowReordering}
|
|
869
|
+
pinCheckboxColumn={pinCheckboxColumn}
|
|
870
|
+
pinExpandColumn={pinExpandColumn}
|
|
871
|
+
pinnedColumns={effectivePinnedColumns}
|
|
872
|
+
loading={isAggregationLoading}
|
|
873
|
+
/>
|
|
874
|
+
)}
|
|
875
|
+
</div>
|
|
1163
876
|
|
|
1164
877
|
</div>
|
|
1165
878
|
</div>
|
|
1166
879
|
)}
|
|
1167
880
|
|
|
1168
|
-
{
|
|
881
|
+
{FooterSlot && (
|
|
1169
882
|
<FooterSlot
|
|
1170
883
|
apiRef={gridData.apiRef}
|
|
1171
884
|
aggregationModel={aggregationModel}
|
|
1172
885
|
aggregationResult={hasAggregation ? aggregationResult : null}
|
|
1173
|
-
rowCount={
|
|
886
|
+
rowCount={isHierarchyEnabled && paginationMode !== 'server' ? dataRows.length : paginationRowCount}
|
|
1174
887
|
pagination={pagination}
|
|
1175
888
|
paginationModel={effectivePaginationModel}
|
|
1176
889
|
pageSizeOptions={pageSizeOptions}
|
|
@@ -1179,40 +892,33 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
|
|
|
1179
892
|
/>
|
|
1180
893
|
)}
|
|
1181
894
|
|
|
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} />
|
|
895
|
+
{!listView && !FooterSlot && pagination && (
|
|
896
|
+
<GridPaginationArea
|
|
897
|
+
paginationSlot={slots?.pagination}
|
|
898
|
+
paginationSlotProps={slotProps?.pagination}
|
|
899
|
+
page={rowPipeline.currentPage}
|
|
900
|
+
paginationModel={effectivePaginationModel}
|
|
901
|
+
rowCount={paginationRowCount}
|
|
902
|
+
pageSizeOptions={pageSizeOptions}
|
|
903
|
+
onPaginationModelChange={handlePaginationModelChange}
|
|
904
|
+
localeText={localeText}
|
|
905
|
+
/>
|
|
906
|
+
)}
|
|
907
|
+
|
|
908
|
+
<GridLiveRegion
|
|
909
|
+
loading={effectiveLoading}
|
|
910
|
+
error={state.dataSource.error}
|
|
911
|
+
noRowsLabel={effectiveNoRowsLabel}
|
|
912
|
+
filteredRowCount={filteredRows.length}
|
|
913
|
+
dataRowCount={dataRows.length}
|
|
914
|
+
filterModel={filterModel}
|
|
915
|
+
/>
|
|
916
|
+
|
|
917
|
+
{showLoadingOverRows && (
|
|
918
|
+
<GridLoadingOverlay overlay={loadingOverlay} />
|
|
919
|
+
)}
|
|
920
|
+
|
|
921
|
+
<GridErrorOverlay error={state.dataSource.error} onRetry={dataSource ? dataSourceHandlers.fetchRows : undefined} />
|
|
1216
922
|
</div>
|
|
1217
923
|
);
|
|
1218
924
|
}
|