@opencorestack/opengridx 3.5.1 → 3.7.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +2 -0
  3. package/dist/ai.cjs +4 -2
  4. package/dist/ai.cjs.map +1 -1
  5. package/dist/ai.d.ts +2 -2
  6. package/dist/ai.es.js +4 -2
  7. package/dist/ai.es.js.map +1 -1
  8. package/dist/index.d.ts +62 -0
  9. package/dist/opengridx.css +1 -1
  10. package/dist/opengridx.es.js +9643 -9024
  11. package/dist/opengridx.es.js.map +1 -1
  12. package/dist/opengridx.umd.js +16 -16
  13. package/dist/opengridx.umd.js.map +1 -1
  14. package/docs/API_REFERENCE.md +17 -3
  15. package/docs/README.md +2 -0
  16. package/docs/architecture/datagrid-orchestration.md +46 -29
  17. package/docs/architecture/grid-row-meta.md +1 -1
  18. package/docs/customization/slots-api.md +1 -1
  19. package/docs/customization/theming.md +43 -0
  20. package/docs/features/ai-toolkit.md +2 -2
  21. package/docs/features/export-guide.md +2 -0
  22. package/docs/features/header-filters.md +34 -0
  23. package/docs/features/keyboard-navigation.md +2 -0
  24. package/docs/features/nextjs.md +241 -0
  25. package/docs/features/pdf-export.md +2 -0
  26. package/docs/features/pinning.md +2 -0
  27. package/docs/features/rtl.md +58 -0
  28. package/docs/features/virtualization.md +16 -2
  29. package/docs/performance.md +89 -119
  30. package/docs/roadmap.md +4 -2
  31. package/lib/ai/promptHandler.ts +12 -8
  32. package/lib/ai/validate.ts +5 -2
  33. package/lib/components/AiAssistant/GridAiAssistantPanel.css +4 -2
  34. package/lib/components/Cell/Cell.css +31 -9
  35. package/lib/components/Cell/Cell.tsx +2 -2
  36. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +4 -4
  37. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +3 -3
  38. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +18 -2
  39. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +3 -1
  40. package/lib/components/DataGrid/DataGrid.css +19 -13
  41. package/lib/components/DataGrid/DataGrid.tsx +163 -670
  42. package/lib/components/DataGrid/GridAggregationFooter.tsx +3 -3
  43. package/lib/components/DataGrid/GridListView.tsx +3 -1
  44. package/lib/components/DataGrid/GridRoot.tsx +239 -0
  45. package/lib/components/DataGrid/GridViewport.tsx +314 -0
  46. package/lib/components/FilterPanel/FilterPanel.css +9 -8
  47. package/lib/components/Header/ColumnMenu.css +5 -4
  48. package/lib/components/Header/ColumnMenu.tsx +14 -6
  49. package/lib/components/Header/Header.css +23 -14
  50. package/lib/components/Header/Header.tsx +16 -9
  51. package/lib/components/Header/headerColumnStyle.ts +3 -2
  52. package/lib/components/HeaderFilter/HeaderFilter.css +9 -3
  53. package/lib/components/HeaderFilter/HeaderFilterCell.tsx +21 -18
  54. package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +5 -4
  55. package/lib/components/HeaderFilter/HeaderFilterRow.tsx +9 -3
  56. package/lib/components/ListView/ListViewRow.tsx +1 -1
  57. package/lib/components/Pagination/Pagination.css +5 -1
  58. package/lib/components/Pagination/Pagination.tsx +4 -4
  59. package/lib/components/Row/Row.css +2 -2
  60. package/lib/components/Row/Row.tsx +3 -3
  61. package/lib/components/SkeletonRow/SkeletonRow.tsx +2 -2
  62. package/lib/components/Toolbar/GridToolbar.css +8 -7
  63. package/lib/components/Toolbar/GridToolbar.tsx +8 -28
  64. package/lib/components/Toolbar/PivotPanel.css +3 -3
  65. package/lib/components/Toolbar/PivotPanel.tsx +4 -7
  66. package/lib/components/ui/ExpandIcon.css +13 -0
  67. package/lib/components/ui/ExpandIcon.tsx +2 -4
  68. package/lib/hooks/core/useGridCellSelection.ts +20 -5
  69. package/lib/hooks/core/useGridColumns.tsx +2 -2
  70. package/lib/hooks/core/useGridDevWarnings.ts +3 -1
  71. package/lib/hooks/core/useGridEditPipeline.ts +55 -0
  72. package/lib/hooks/core/useGridKeyboardNavigation.ts +7 -4
  73. package/lib/hooks/core/useGridRangeEditing.ts +129 -0
  74. package/lib/hooks/core/useGridRenderWindow.ts +66 -0
  75. package/lib/hooks/core/useGridScrollSync.ts +28 -5
  76. package/lib/hooks/core/useGridScrollViewport.ts +42 -0
  77. package/lib/hooks/core/useGridSelectionAndStateApi.ts +61 -0
  78. package/lib/hooks/core/useGridToolbarStack.ts +49 -0
  79. package/lib/hooks/core/useGridViewApis.ts +46 -0
  80. package/lib/hooks/core/useLayout.ts +13 -6
  81. package/lib/hooks/useRowGrouping.ts +9 -9
  82. package/lib/styles/base/variables.css +12 -0
  83. package/lib/theme/DataGridThemeProvider.tsx +15 -0
  84. package/lib/theme/__baseline__/default-theme.darwin.chromium.json +1503 -0
  85. package/lib/theme/__baseline__/default-theme.darwin.firefox.json +1503 -0
  86. package/lib/theme/__baseline__/default-theme.darwin.webkit.json +1503 -0
  87. package/lib/theme/types.ts +31 -0
  88. package/lib/types/ai.ts +109 -0
  89. package/lib/types/api.ts +169 -0
  90. package/lib/types/columns.ts +341 -0
  91. package/lib/types/dataSource.ts +40 -0
  92. package/lib/types/editing.ts +77 -0
  93. package/lib/types/export.ts +164 -0
  94. package/lib/types/filtering.ts +52 -0
  95. package/lib/types/grouping.ts +27 -0
  96. package/lib/types/index.ts +18 -1672
  97. package/lib/types/locale.ts +51 -0
  98. package/lib/types/props.ts +405 -0
  99. package/lib/types/rows.ts +132 -0
  100. package/lib/types/selection.ts +66 -0
  101. package/lib/types/slots.ts +56 -0
  102. package/lib/types/sorting.ts +25 -0
  103. package/lib/types/state.ts +35 -0
  104. package/lib/utils/aggregation/index.ts +56 -1
  105. package/lib/utils/direction.ts +52 -0
  106. package/lib/utils/export/exportToExcelAdvanced.ts +9 -2
  107. package/lib/utils/export/exportToPdf.ts +2 -1
  108. package/lib/utils/filtering/index.ts +58 -6
  109. package/lib/utils/headerFilterLocale.ts +37 -0
  110. package/lib/utils/scroll/index.ts +5 -3
  111. package/lib/utils/sorting/index.ts +141 -26
  112. package/lib/utils/values.ts +10 -6
  113. package/llms.txt +4 -2
  114. package/package.json +4 -2
@@ -4,48 +4,31 @@ import { useGridKeyboardNavigation } from '../../hooks/core/useGridKeyboardNavig
4
4
  import { useGridControlledState } from '../../hooks/core/useGridControlledState';
5
5
  import { useGridThemeDimensions } from '../../hooks/core/useGridThemeDimensions';
6
6
  import { useGridRowPipeline, type GridRowPipelineResult } from '../../hooks/core/useGridRowPipeline';
7
- import { useGridMaxContentHeight } from '../../hooks/core/useGridMaxContentHeight';
8
7
  import { countReachableRows } from '../../utils/maxElementHeight';
9
- import { useGridVirtualization } from '../../hooks/core/useGridVirtualization';
10
8
  import { useGridColumns } from '../../hooks/core/useGridColumns';
11
- import { useGridVisibleRows } from '../../hooks/core/useGridVisibleRows';
12
- import { useGridViewport } from '../../hooks/core/useGridViewport';
13
9
  import { useGridDetailPanel } from '../../hooks/core/useGridDetailPanel';
14
10
  import { useGridStateSnapshot } from '../../hooks/core/useGridStateSnapshot';
15
- import { useGridDevWarnings, useGridStylesheetWarning } from '../../hooks/core/useGridDevWarnings';
16
- import { useGridRowInteractions } from '../../hooks/core/useGridRowInteractions';
11
+ import { useGridDevWarnings } from '../../hooks/core/useGridDevWarnings';
17
12
  import { useGridLiveRowSelection } from '../../hooks/core/useGridLiveRowSelection';
18
- import { useGridApiMethods } from '../../hooks/core/useGridApiMethods';
13
+ import { useGridSelectionAndStateApi } from '../../hooks/core/useGridSelectionAndStateApi';
19
14
  import { useGridColumnLookup } from '../../hooks/core/useGridColumnLookup';
20
15
  import { useGridPageCorrection } from '../../hooks/core/useGridPageCorrection';
21
- import { useGridColumnsPanel } from '../../hooks/core/useGridColumnsPanel';
22
- import { GridToolbarHostContext } from '../../hooks/core/gridToolbarHostContext';
23
- import { GridToolbarSlot } from './GridToolbarSlot';
24
- import { GridAggregationFooter } from './GridAggregationFooter';
25
- import { GridEmptyState } from './GridEmptyState';
26
- import { GridErrorOverlay } from './GridErrorOverlay';
27
- import { Header } from '../Header/Header';
28
16
  import { useDataGrid } from '../../hooks/core/useDataGrid';
29
17
  import { useRowReorder } from '../../hooks/useRowReorder';
30
18
  import { useGridHierarchy } from '../../hooks/core/useGridHierarchy';
31
- import { useGridEditing } from '../../hooks/features/useGridEditing';
32
- import { useGridBatchEdit } from '../../hooks/features/useGridBatchEdit';
33
- import { useGridClipboardPaste } from '../../hooks/core/useGridClipboardPaste';
34
- import { useGridUndoRedo, useGridEditCommitChannel, UNDO_HISTORY_LIMIT } from '../../hooks/core/useGridUndoRedo';
35
- import { useGridFillHandle } from '../../hooks/core/useGridFillHandle';
19
+ import { useGridRenderWindow } from '../../hooks/core/useGridRenderWindow';
20
+ import { useGridRangeEditing } from '../../hooks/core/useGridRangeEditing';
21
+ import { useGridScrollViewport } from '../../hooks/core/useGridScrollViewport';
22
+ import { useGridViewApis } from '../../hooks/core/useGridViewApis';
23
+ import { useGridEditPipeline } from '../../hooks/core/useGridEditPipeline';
36
24
  import { useGridSpanning } from '../../hooks/features/useGridSpanning';
37
- import { useGridSpanRowWindow, useGridSpanColumnWindow } from '../../hooks/features/useGridSpanRenderWindow';
38
25
  import { useColumnGroupReorderGuard } from '../../hooks/features/useColumnGroupReorderGuard';
39
26
  import { useGridDataSource } from '../../hooks/features/useGridDataSource';
40
27
  import { useServerTreeChildren } from '../../hooks/features/useServerTreeChildren';
41
28
  import { useAggregation, useServerAggregationResults } from '../../hooks/features/useAggregation';
42
29
  import { useGridPivot } from '../../hooks/features/useGridPivot';
43
30
  import { isServerDrivenDataSource } from '../../utils/dataSource';
44
- import { GridListView } from './GridListView';
45
- import { GridLoadingOverlay } from './GridLoadingOverlay';
46
- import { GridPinnedRows } from './GridPinnedRows';
47
- import { GridVirtualRows } from './GridVirtualRows';
48
- import { GridStandaloneColumnPanel } from './GridStandaloneColumnPanel';
31
+ import { GridRoot, type GridRootProps } from './GridRoot';
49
32
  import { resolveGridModes } from '../../utils/gridModes';
50
33
  import { useGridGroupingColumn } from '../../hooks/core/useGridGroupingColumn';
51
34
  import { useGridRowIdOf, getDefaultRowId } from '../../hooks/core/useGridRowIdOf';
@@ -55,21 +38,11 @@ import { NO_AGGREGATION_MODEL } from '../../utils/aggregation';
55
38
  import { isSyntheticRowId } from '../../utils/syntheticRows';
56
39
  import { useStableColumns } from '../../hooks/core/useStableColumns';
57
40
  import { useGridAggregationApi } from '../../hooks/core/useGridAggregationApi';
58
- import { useGridClipboardApi } from '../../hooks/core/useGridClipboardApi';
59
- import { useGridScrollToIndexesApi } from '../../hooks/core/useGridScrollToIndexesApi';
60
- import { useGridColumnAutosize } from '../../hooks/core/useGridColumnAutosize';
61
41
  import { useGridCellSelection } from '../../hooks/core/useGridCellSelection';
62
- import { useGridCellSelectionApi } from '../../hooks/core/useGridCellSelectionApi';
63
- import { GridCellSelectionStatsArea } from '../CellSelectionStats/GridCellSelectionStatsArea';
64
42
  import { useGridSortHandlers, useGridColumnMenuHandlers } from '../../hooks/core/useGridHeaderHandlers';
65
43
  import { useGridKeyboardMode, useGridPointerFocusHandlers } from '../../hooks/core/useGridFocusHandlers';
66
- import { getPaginationRowCount, pickPaginationLocaleText } from '../../utils/pagination';
67
- import { GridPaginationArea } from './GridPaginationArea';
68
- import { GridLiveRegion } from './GridLiveRegion';
69
- import { useGridAriaRows } from '../../hooks/core/useGridAriaRows';
70
- import { useGridToolbarProps } from '../../hooks/core/useGridToolbarProps';
71
- import { useGridAiAssistant } from '../../hooks/features/useGridAiAssistant';
72
- import { GridAiAssistantArea } from '../AiAssistant/GridAiAssistantArea';
44
+ import { getPaginationRowCount } from '../../utils/pagination';
45
+ import { useGridToolbarStack } from '../../hooks/core/useGridToolbarStack';
73
46
  import { DEFAULT_HEADER_FILTER_HEIGHT } from '../../utils/headerFilters';
74
47
  import type { DataGridProps, DataGridUntypedColumnsProps, GridValidRowModel, GridRowModel, GridRowId, GridColDef } from '../../types';
75
48
 
@@ -83,114 +56,41 @@ export function DataGrid<R extends GridValidRowModel = GridRowModel>(props: Data
83
56
  // public signatures, and a consumer's row objects are passed through untouched.
84
57
  export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridProps<R>): React.JSX.Element {
85
58
  const {
86
- rows,
87
- columns: columnsProp,
88
- getRowId,
89
- rowHeight: rowHeightProp,
90
- headerHeight: headerHeightProp,
91
- wrapHeaderText = false,
92
- headerFilters = false,
93
- headerFilterHeight = DEFAULT_HEADER_FILTER_HEIGHT,
94
- autoHeight = false,
95
- density,
96
- checkboxSelection = false,
97
- disableRowSelectionOnClick = false,
98
- disableMultipleRowSelection = false,
99
- disableClipboardCopy = false,
100
- cellSelection: cellSelectionProp = false,
101
- cellSelectionModel: propCellSelectionModel,
102
- onCellSelectionModelChange,
103
- showCellSelectionStats = false,
104
- disableClipboardPaste = false,
105
- disableRangeClear = false,
106
- onClipboardPaste,
107
- onBeforeClipboardPaste,
108
- undoRedo = false,
109
- disableFillHandle = false,
110
- onFill,
111
- onHistoryChange,
112
- rowSelectionModel: propRowSelectionModel,
113
- onRowSelectionModelChange: propOnRowSelectionModelChange,
114
- onRowClick,
115
- onRowDoubleClick,
116
- onCellClick,
117
-
118
- filterModel: propFilterModel,
119
- onFilterModelChange,
120
- sortModel: propSortModel,
121
- onSortModelChange,
122
- pagination: propPagination = false,
123
- paginationModel,
124
- onPaginationModelChange,
59
+ rows, columns: columnsProp, getRowId, rowHeight: rowHeightProp, headerHeight: headerHeightProp,
60
+ wrapHeaderText = false, headerFilters = false, headerFilterHeight = DEFAULT_HEADER_FILTER_HEIGHT,
61
+ autoHeight = false, density, height, className = '', style, ariaLabel, loading = false,
62
+ // Selection
63
+ checkboxSelection = false, disableRowSelectionOnClick = false, disableMultipleRowSelection = false,
64
+ disableClipboardCopy = false, cellSelection: cellSelectionProp = false,
65
+ cellSelectionModel: propCellSelectionModel, onCellSelectionModelChange, showCellSelectionStats = false,
66
+ rowSelectionModel: propRowSelectionModel, onRowSelectionModelChange: propOnRowSelectionModelChange,
67
+ onRowClick, onRowDoubleClick, onCellClick,
68
+ // Filter, sort, pagination, pinning
69
+ filterModel: propFilterModel, onFilterModelChange, sortModel: propSortModel, onSortModelChange,
70
+ pagination: propPagination = false, paginationModel, onPaginationModelChange,
125
71
  pageSizeOptions = [10, 25, 50, 100],
126
- pinnedColumns: propPinnedColumns,
127
- onPinnedColumnsChange,
128
- pinnedRows,
129
-
130
- getDetailPanelContent,
131
- getDetailPanelHeight,
132
- detailPanelExpandedRowIds: controlledExpandedRowIds,
133
- onDetailPanelExpandedRowIdsChange,
134
- pinCheckboxColumn = true,
135
- pinExpandColumn = true,
136
- disableColumnReorder = false,
137
- columnOrder,
138
- onColumnOrderChange,
139
- onColumnOrderModelChange,
140
- height,
141
- rowReordering: rowReorderingProp = false,
142
- onRowOrderChange,
143
- loading = false,
144
-
145
- treeData = false,
146
- getTreeDataPath,
147
- defaultGroupingExpansionDepth,
148
- groupingColDef,
149
-
150
- rowGroupingModel: propRowGroupingModel,
151
- onRowGroupingModelChange,
152
-
153
- aggregationModel: propAggregationModel,
154
- onAggregationModelChange,
155
- getAggregationPosition,
156
-
157
- isCellEditable,
158
- processRowUpdate,
159
- onProcessRowUpdateError,
160
-
161
- dataSource,
162
- multiSort = false,
163
- sortingMode = 'client',
164
- filterMode = 'client',
165
- paginationMode = 'client',
72
+ pinnedColumns: propPinnedColumns, onPinnedColumnsChange, pinnedRows,
73
+ // Detail panel, column order, row reorder
74
+ getDetailPanelContent, getDetailPanelHeight, detailPanelExpandedRowIds: controlledExpandedRowIds,
75
+ onDetailPanelExpandedRowIdsChange, pinCheckboxColumn = true, pinExpandColumn = true,
76
+ disableColumnReorder = false, columnOrder, onColumnOrderChange, onColumnOrderModelChange,
77
+ rowReordering: rowReorderingProp = false, onRowOrderChange,
78
+ // Tree data, row grouping, aggregation
79
+ treeData = false, getTreeDataPath, defaultGroupingExpansionDepth, groupingColDef,
80
+ rowGroupingModel: propRowGroupingModel, onRowGroupingModelChange,
81
+ aggregationModel: propAggregationModel, onAggregationModelChange, getAggregationPosition,
82
+ // Editing (paste, undo/redo and fill handle props are read by useGridRangeEditing)
83
+ isCellEditable, processRowUpdate, onProcessRowUpdateError,
84
+ // Server data
85
+ dataSource, multiSort = false, sortingMode = 'client', filterMode = 'client', paginationMode = 'client',
166
86
  rowCount: propRowCount,
167
-
168
- slots,
169
- slotProps,
170
-
171
- pivotMode = false,
172
- pivotModel: propPivotModel,
173
- onPivotModelChange,
174
-
175
- className = '',
176
- style,
177
- onRowsScrollEnd,
178
- ariaLabel,
179
- initialState,
180
- onStateChange,
181
- // Column Visibility
182
- columnVisibilityModel: propColumnVisibilityModel,
183
- onColumnVisibilityModelChange,
184
- listView: listViewRequested = false,
185
- listViewColumn,
186
- columnGroupingModel,
187
- noRowsLabel = 'No Data',
188
- localeText,
189
- apiRef: propApiRef,
190
- overscanRowCount = 3,
191
- aiAssistant,
192
- onAiAssistantApply,
193
- onAiAssistantError,
87
+ slots, slotProps,
88
+ pivotMode = false, pivotModel: propPivotModel, onPivotModelChange,
89
+ onRowsScrollEnd, initialState, onStateChange,
90
+ columnVisibilityModel: propColumnVisibilityModel, onColumnVisibilityModelChange,
91
+ listView: listViewRequested = false, listViewColumn, columnGroupingModel,
92
+ noRowsLabel = 'No Data', localeText, apiRef: propApiRef, overscanRowCount = 3,
93
+ aiAssistant, onAiAssistantApply, onAiAssistantError,
194
94
  } = props;
195
95
  // Equal inline column definitions keep one identity, so the row passes memoised on it do not re-run.
196
96
  const columns = useStableColumns(columnsProp);
@@ -228,7 +128,7 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
228
128
  selectedRowIds: selectionModelRowIds,
229
129
  handleRowSelectionModelChange,
230
130
  density: effectiveDensity,
231
- rowGroupingModel, handleRowGroupingModelChange,
131
+ rowGroupingModel,
232
132
  } = controlledState;
233
133
 
234
134
  const pivot = useGridPivot({
@@ -322,32 +222,15 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
322
222
  getAggregationPosition, columnLookup, filterMode, sortingMode,
323
223
  });
324
224
 
325
- // Commits (single edits and batch edits) reach the undo/redo history created further down.
326
- const editCommitChannel = useGridEditCommitChannel();
327
- // Batch edits (paste, range clear, undo, redo): one processRowUpdate per row, one store update.
328
- const batchEdit = useGridBatchEdit<R>({
225
+ // Steps 12a–13: the edit commit channel, the batch edit and single-cell editing.
226
+ const { editCommitChannel, batchEdit, editingHandlers } = useGridEditPipeline<R>({
329
227
  rowsLookup: state.rows.idRowsLookup as unknown as ReadonlyMap<GridRowId, R>,
330
- columns: activeColumns,
331
- processRowUpdate,
332
- onProcessRowUpdateError,
333
- replaceRows: replaceRows as unknown as (rows: ReadonlyMap<GridRowId, R>) => void,
334
- onCommitted: editCommitChannel.emit,
335
- });
336
-
337
- const editingHandlers = useGridEditing({
338
228
  rows: effectiveRows,
339
229
  getRowId: getRowIdOf,
340
230
  columns: activeColumns,
341
231
  processRowUpdate,
342
232
  onProcessRowUpdateError,
343
- onRowChange: (updatedRow, rowId) => {
344
- // Replaces the edited row in the *current* store, under the edited row's id: this runs
345
- // after an awaited processRowUpdate, by which time the rows prop (or a dataSource
346
- // fetch) may have replaced the rows this render saw. The returned row is stored as is
347
- // (the grid never writes an id onto it), even if it does not carry its key itself.
348
- batchEdit.storeRow(rowId, updatedRow);
349
- },
350
- onCommitted: (changes) => editCommitChannel.emit(changes, 'edit'),
233
+ replaceRows: replaceRows as unknown as (rows: ReadonlyMap<GridRowId, R>) => void,
351
234
  });
352
235
 
353
236
  // The selection without ids of removed rows. Only client-owned rows are pruned: a server page
@@ -441,50 +324,31 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
441
324
  clientRowCount: sortedUnpinnedRows.length,
442
325
  });
443
326
 
444
- const { rowSelection, handleRowClick, handleSelectionChange } = useGridRowInteractions<R>({
445
- dataRows,
446
- getRowId: getRowIdOf,
447
- isPivotActive,
448
- selectedRowIds,
449
- onSelectionModelChange: handleRowSelectionModelChange,
450
- disableMultipleRowSelection, disableRowSelectionOnClick, isHierarchyEnabled, rowMetaMap,
451
- activeHierarchyHandlers, onRowClick,
452
- });
453
-
454
- useGridApiMethods({
455
- apiRef: gridData.apiRef,
456
- sortModel,
457
- multiSort,
458
- onSortModelChange: handleSortModelChange,
459
- filterModel,
460
- onFilterModelChange: handleFilterModelChange,
461
- paginationModel: effectivePaginationModel,
462
- onPaginationModelChange: handlePaginationModelChange,
463
- selectedRowIds,
464
- getPendingRowSelectionModel: controlledState.getPendingRowSelectionModel,
465
- onRowSelectionModelChange: handleRowSelectionModelChange,
466
- disableMultipleRowSelection,
467
- isSyntheticRowId: (id) => isSyntheticRowId(id, rowMetaMap),
468
- getVisibleRows: () => [...pinnedTopRows, ...centerRows, ...pinnedBottomRows],
469
- getAllFilteredRows: () => collectAllFilteredRows<GridRowModel>({
470
- hierarchyHandlers: activeHierarchyHandlers,
471
- pinnedTopRows,
472
- sortedUnpinnedRows,
473
- pinnedBottomRows,
474
- rowMetaMap,
475
- getRowId: getRowIdOf,
476
- hierarchyField,
327
+ // Steps 23–24: row selection and click handlers, then the state API methods.
328
+ const { rowSelection, handleRowClick, handleSelectionChange } = useGridSelectionAndStateApi<R>({
329
+ controlledState,
330
+ interactions: {
477
331
  dataRows,
478
- }),
479
- visibleColumns: renderOrderedColumns as unknown as GridColDef[],
480
- rowGroupingModel,
481
- onRowGroupingModelChange: handleRowGroupingModelChange,
482
- aggregationModel,
483
- onAggregationModelChange: handleAggregationModelChange,
484
- columnVisibilityModel,
485
- onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
486
- pivotModel: currentPivotModel,
487
- onPivotModelChange: handlePivotModelChange,
332
+ getRowId: getRowIdOf,
333
+ isPivotActive, disableRowSelectionOnClick, isHierarchyEnabled, rowMetaMap, activeHierarchyHandlers, onRowClick,
334
+ },
335
+ api: {
336
+ apiRef: gridData.apiRef,
337
+ multiSort, selectedRowIds, disableMultipleRowSelection,
338
+ isSyntheticRowId: (id) => isSyntheticRowId(id, rowMetaMap),
339
+ getVisibleRows: () => [...pinnedTopRows, ...centerRows, ...pinnedBottomRows],
340
+ getAllFilteredRows: () => collectAllFilteredRows<GridRowModel>({
341
+ hierarchyHandlers: activeHierarchyHandlers,
342
+ pinnedTopRows,
343
+ sortedUnpinnedRows,
344
+ pinnedBottomRows,
345
+ rowMetaMap,
346
+ getRowId: getRowIdOf,
347
+ hierarchyField,
348
+ dataRows,
349
+ }),
350
+ visibleColumns: renderOrderedColumns as unknown as GridColDef[],
351
+ },
488
352
  });
489
353
 
490
354
  // Indices address the consumer's own rows, whatever the sort, filter, page or pinning.
@@ -572,29 +436,26 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
572
436
  showStats: showCellSelectionStats,
573
437
  });
574
438
 
575
- useGridClipboardApi({
576
- apiRef,
577
- columns: renderedDataColumns as unknown as GridColDef[],
578
- getRowId: getRowIdOf,
579
- containerRef,
580
- disableKeyboardShortcut: disableClipboardCopy,
439
+ // Steps 30–31a: copy, scrollToIndexes and column auto-size on the API.
440
+ const handleColumnAutosize = useGridViewApis<R>({
441
+ apiRef, containerRef, viewportRef,
442
+ copyColumns: renderedDataColumns as unknown as GridColDef[],
443
+ getRowId: getRowIdOf as unknown as (row: GridRowModel) => GridRowId,
444
+ disableClipboardCopy,
581
445
  getCellRangeCopyText: cellSelection.enabled ? cellSelection.getCopyText : undefined,
582
- });
583
- useGridScrollToIndexesApi<R>({ apiRef, viewportRef, layout, rowHeight: effectiveRowHeight });
584
- const handleColumnAutosize = useGridColumnAutosize<R>({ apiRef, containerRef, columns: orderedColumns, onColumnResize: handleColumnResize });
585
-
586
- const { scrollTop, scrollLeft, overscanRows, handleScroll, setViewportElement } = useGridViewport({
587
- onRowsScrollEnd, overscanRowCount, rowCount: layout.unpinnedRowsLength, autoHeight, setDimensions, viewportRef,
446
+ layout,
447
+ rowHeight: effectiveRowHeight,
448
+ orderedColumns,
449
+ onColumnResize: handleColumnResize,
588
450
  });
589
451
 
590
- const maxContentHeight = useGridMaxContentHeight(containerRef);
591
- const virtualization = useGridVirtualization({
592
- layout, scrollTop, scrollLeft,
452
+ // Steps 32–33: scroll sync, viewport measurement and the render window.
453
+ const { handleScroll, setViewportElement, maxContentHeight, virtualization } = useGridScrollViewport<R>({
454
+ viewport: { onRowsScrollEnd, overscanRowCount, autoHeight, setDimensions },
455
+ viewportRef, containerRef, layout,
593
456
  viewportWidth: state.dimensions.viewportWidth,
594
457
  viewportHeight: state.dimensions.viewportHeight,
595
- autoHeight, rowReordering, hasDetailPanel, checkboxSelection, pinCheckboxColumn, pinExpandColumn,
596
- overscanRows,
597
- maxContentHeight: maxContentHeight ?? Infinity,
458
+ virtualization: { autoHeight, rowReordering, hasDetailPanel, checkboxSelection, pinCheckboxColumn, pinExpandColumn },
598
459
  });
599
460
 
600
461
 
@@ -630,72 +491,25 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
630
491
  const { handleCellClick, handleHeaderClick } = useGridPointerFocusHandlers<R>({
631
492
  ensureGridFocus, setKeyboardMode, setFocusedCell, getRowId: getRowIdOf, onCellClick,
632
493
  });
633
- // Keeps the range anchor and the focused cell together; installs the cell selection API.
634
- useGridCellSelectionApi({
635
- apiRef,
494
+ // Steps 36a–36d: the cell selection API, paste and range clear, undo/redo, the fill handle.
495
+ const fillHandle = useGridRangeEditing<R>({
496
+ props, apiRef, containerRef, viewportRef,
636
497
  selection: cellSelection,
637
498
  model: controlledState.cellSelectionModel,
638
499
  getPendingModel: controlledState.getPendingCellSelectionModel,
639
- focusedCell,
640
- setFocusedCell,
641
- containerRef,
642
- });
643
-
644
- // Ctrl/Cmd+V and Delete on a range (cellSelection); apiRef.pasteText.
645
- useGridClipboardPaste<R>({
646
- apiRef, containerRef, viewportRef,
647
- selection: cellSelection,
648
- disableClipboardPaste, disableRangeClear,
649
- focusedCell,
650
- allRenderableRows,
500
+ focusedCell, setFocusedCell, allRenderableRows,
651
501
  getRowId: getRowIdOf,
652
502
  navigationColumns: navigationColumns as unknown as GridColDef<R>[],
653
- isCellEditable,
654
- rowMetaMap,
503
+ columnIndexMap, isCellEditable, rowMetaMap,
655
504
  getSpanOrigin: spanning.getSpanOrigin,
656
505
  isEditing: editingHandlers.editingCell !== null,
657
506
  batchEdit,
658
- onClipboardPaste,
659
- onBeforeClipboardPaste,
660
- });
661
-
662
- // Undo / redo (undoRedo): history of committed edits, keys and apiRef methods.
663
- useGridUndoRedo<R>({
664
- apiRef,
665
- enabled: Boolean(undoRedo),
666
- limit: (typeof undoRedo === 'object' && undoRedo.limit) || UNDO_HISTORY_LIMIT,
667
- onHistoryChange,
668
507
  channel: editCommitChannel,
669
- batchEdit,
670
- isEditing: editingHandlers.editingCell !== null,
671
- containerRef, viewportRef,
672
- selection: cellSelection,
673
- setFocusedCell,
674
- allRenderableRows,
675
- getRowId: getRowIdOf,
676
- navigationColumns: navigationColumns as unknown as GridColDef<R>[],
677
508
  layout,
678
509
  rowHeight: effectiveRowHeight,
679
510
  pinnedTopRowCount: pinnedTopRows.length,
680
511
  });
681
512
 
682
- // Fill handle (cellSelection): drag the range's corner, Ctrl/Cmd+D and Ctrl/Cmd+R.
683
- const fillHandle = useGridFillHandle<R>({
684
- containerRef, viewportRef,
685
- selection: cellSelection,
686
- disableFillHandle,
687
- isEditing: editingHandlers.editingCell !== null,
688
- allRenderableRows,
689
- getRowId: getRowIdOf,
690
- navigationColumns: navigationColumns as unknown as GridColDef<R>[],
691
- columnIndexMap,
692
- isCellEditable,
693
- rowMetaMap,
694
- getSpanOrigin: spanning.getSpanOrigin,
695
- batchEdit,
696
- onFill,
697
- });
698
-
699
513
  const { handleHideColumn, handlePinColumn } = useGridColumnMenuHandlers({
700
514
  columnVisibilityModel,
701
515
  onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
@@ -703,41 +517,25 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
703
517
  onPinnedColumnsChange: handlePinnedColumnsChange,
704
518
  });
705
519
 
706
- const ariaRows = useGridAriaRows({
707
- columnGroupingModel,
708
- headerFilterRow: showHeaderFilters,
709
- pinnedTopCount: pinnedTopRows.length,
710
- pinnedBottomCount: pinnedBottomRows.length,
711
- pagination,
712
- paginationMode,
713
- paginationModel: effectivePaginationModel,
714
- paginationRowCount,
715
- paginatedUnpinnedRowCount: paginatedUnpinnedRows.length,
716
- sortedUnpinnedRowCount: sortedUnpinnedRows.length,
717
- });
718
-
719
- const spanRowWindow = useGridSpanRowWindow({
720
- spanning,
721
- renderContext: virtualization.renderContext,
722
- offsetTop: virtualization.offsetTop,
723
- cumulativeHeights: layout.cumulativeHeights,
724
- });
725
-
726
- const visibleRows = useGridVisibleRows<R>({
727
- renderContext: spanRowWindow.renderContext,
520
+ // Steps 38–41: aria row bases, the span-widened row window, the rows and the columns to render.
521
+ const { ariaRows, spanRowWindow, visibleRows, renderColumns } = useGridRenderWindow<R>({
522
+ aria: {
523
+ columnGroupingModel,
524
+ headerFilterRow: showHeaderFilters,
525
+ pinnedTopCount: pinnedTopRows.length,
526
+ pinnedBottomCount: pinnedBottomRows.length,
527
+ pagination,
528
+ paginationMode,
529
+ paginationModel: effectivePaginationModel,
530
+ paginationRowCount,
531
+ paginatedUnpinnedRowCount: paginatedUnpinnedRows.length,
532
+ sortedUnpinnedRowCount: sortedUnpinnedRows.length,
533
+ },
534
+ spanning, virtualization, layout,
728
535
  pinnedTopRows, pinnedBottomRows, paginatedUnpinnedRows, sortedUnpinnedRows, pagination,
729
536
  getRowId: getRowIdOf,
730
537
  });
731
538
 
732
- const renderColumns = useGridSpanColumnWindow<R>({
733
- spanning,
734
- firstColumnIndex: virtualization.renderContext.firstColumnIndex,
735
- lastColumnIndex: virtualization.renderContext.lastColumnIndex,
736
- virtualColumns: virtualization.virtualColumns,
737
- layout,
738
- rows: visibleRows,
739
- });
740
-
741
539
  useGridDevWarnings({
742
540
  paginationRequested: propPagination,
743
541
  isRowGrouping,
@@ -754,374 +552,69 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
754
552
  listViewRowCount: listView && listViewColumn ? allRenderableRows.length : 0,
755
553
  });
756
554
 
757
- const { allSelected, someSelected } = rowSelection;
758
-
759
555
  // Header drag-reorder keeps a column inside its column group (and ungrouped columns outside groups).
760
556
  const headerReorderHandlers = useColumnGroupReorderGuard(columnGroupingModel, columnReorderHandlers);
761
557
 
762
558
  const hasRowSpanning = React.useMemo(() => effectiveColumns.some(c => !!c.rowSpan), [effectiveColumns]);
763
- const columnsPanel = useGridColumnsPanel();
764
- useGridStylesheetWarning(containerRef);
765
-
766
- // The aiAssistant prompt panel (v3.5): applies validated replies through apiRef; apiRef.openAiAssistant.
767
- const aiAssistantPanel = useGridAiAssistant({
768
- apiRef,
769
- options: aiAssistant,
770
- columns: activeColumns as unknown as GridColDef[],
771
- onApply: onAiAssistantApply,
772
- onError: onAiAssistantError,
773
- });
774
-
775
- const NoRowsOverlaySlot = slots?.noRowsOverlay;
776
- const LoadingOverlaySlot = slots?.loadingOverlay;
777
- const loadingOverlay = LoadingOverlaySlot ? <LoadingOverlaySlot {...slotProps?.loadingOverlay} /> : undefined;
778
- const noRowsOverlay = NoRowsOverlaySlot ? <NoRowsOverlaySlot {...slotProps?.noRowsOverlay} /> : undefined;
779
- const FooterSlot = slots?.footer;
780
- // Loading with rows on screen: the rows stay and an indicator runs over them. With no rows the
781
- // body shows skeletons or the loading overlay instead, and infinite scroll appends skeleton rows.
782
- const showLoadingOverRows = effectiveLoading && allRenderableRows.length > 0 && paginationMode !== 'infinite';
783
- const ToolbarSlot = slots?.toolbar;
784
-
785
- const toolbarProps = useGridToolbarProps<R>({
786
- toolbar: slots?.toolbar,
787
- toolbarSlotProps: slotProps?.toolbar,
788
- apiRef,
789
- orderedColumns,
790
- baseColumns: columns,
791
- aggregationModel,
792
- onAggregationModelChange: handleAggregationModelChange,
793
- pivotMode,
794
- pivotModelProp: propPivotModel,
795
- onPivotModelChangeProp: onPivotModelChange,
796
- pivotModel: currentPivotModel,
797
- onPivotModelChange: handlePivotModelChange,
798
- filterModel,
799
- onFilterModelChange: handleFilterModelChange,
800
- columnVisibilityModel,
801
- onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
802
- disableColumnReorder, columnGroupingModel, moveColumn, resetColumnOrder,
803
- forceColumnsOpen: columnsPanel.toolbarPanelRequested,
804
- onColumnsPanelClose: columnsPanel.closeToolbarPanel,
805
- aiAssistantEnabled: aiAssistantPanel.enabled,
806
- aiAssistantOpen: aiAssistantPanel.open,
807
- onAiAssistantToggle: aiAssistantPanel.togglePanel,
808
- aiAssistantLabel: localeText?.aiAssistantButton,
809
- forceFiltersOpen: columnsPanel.toolbarFiltersRequested,
810
- onFiltersPanelClose: columnsPanel.closeToolbarFiltersPanel,
559
+ // Steps 44–46: the columns panel, the stylesheet warning, the aiAssistant panel and the toolbar's props.
560
+ const { columnsPanel, aiAssistantPanel, toolbarProps } = useGridToolbarStack<R>({
561
+ apiRef, containerRef, localeText,
562
+ aiAssistant: {
563
+ options: aiAssistant,
564
+ columns: activeColumns as unknown as GridColDef[],
565
+ onApply: onAiAssistantApply,
566
+ onError: onAiAssistantError,
567
+ },
568
+ toolbar: {
569
+ toolbar: slots?.toolbar,
570
+ toolbarSlotProps: slotProps?.toolbar,
571
+ orderedColumns,
572
+ baseColumns: columns,
573
+ aggregationModel,
574
+ onAggregationModelChange: handleAggregationModelChange,
575
+ pivotMode,
576
+ pivotModelProp: propPivotModel,
577
+ onPivotModelChangeProp: onPivotModelChange,
578
+ pivotModel: currentPivotModel,
579
+ onPivotModelChange: handlePivotModelChange,
580
+ filterModel,
581
+ onFilterModelChange: handleFilterModelChange,
582
+ columnVisibilityModel,
583
+ onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
584
+ disableColumnReorder, columnGroupingModel, moveColumn, resetColumnOrder,
585
+ },
811
586
  });
812
587
 
813
- // Props the row renderers (top-pinned, centre and bottom-pinned rows) all take.
814
- const rowRenderProps = {
815
- rowReordering, columnIndexMap, editingHandlers, isCellEditable, selectedRowIds, checkboxSelection,
816
- onRowClick: handleRowClick,
817
- onRowDoubleClick,
818
- onCellClick: handleCellClick,
819
- onSelectionChange: handleSelectionChange,
820
- columnWidths,
821
- pinnedColumns: effectivePinnedColumns,
822
- hasDetailPanel, expandedRowIds, getDetailPanelContent, getDetailPanelHeight,
823
- onDetailPanelToggle: handleDetailPanelToggle,
824
- onDetailPanelHeightChange: reportDetailPanelHeight,
825
- pinCheckboxColumn, pinExpandColumn, focusedCell,
826
- colspanMap: spanning.colspanMap,
827
- rowSpanningCaches: spanning.rowSpanningCaches,
828
- rowHeight: effectiveRowHeight,
829
- rowMetaMap,
830
- cellRange: cellSelection.displayRange,
831
- cellRangeHasRowSpan: cellSelection.hasRowSpan,
832
- fillHandle: fillHandle.handle,
588
+ const rootProps: GridRootProps<R> = {
589
+ setViewportElement, handleScroll, ariaLabel, ariaRows,
590
+ navigationColumnCount: navigationColumns.length,
591
+ rowSelectionEnabled, disableMultipleRowSelection, cellSelection, effectiveLoading, viewportTabIndex, setKeyboardMode,
592
+ handleMouseDownCapture, handleKeyDown, handleFocus, handleBlur, effectivePinnedColumns, virtualization, renderColumns,
593
+ renderedDataColumns, columnGroupingModel, checkboxSelection, rowSelection, sortModel, handleSort, handleSortAdd,
594
+ multiSort, handleColumnResize, handleColumnAutosize, columnWidths, focusedCell, columnIndexMap, handleHeaderClick,
595
+ headerReorderHandlers, rowReordering, hasDetailPanel, pinCheckboxColumn, pinExpandColumn, aggregationModel,
596
+ handleHideColumn, columnsPanel, handlePinColumn, wrapHeaderText, headerHeight, showHeaderFilters, filterModel,
597
+ handleFilterModelChange, localeText, editingHandlers, isCellEditable, selectedRowIds, handleRowClick,
598
+ onRowDoubleClick, handleCellClick, handleSelectionChange, expandedRowIds, getDetailPanelContent, getDetailPanelHeight,
599
+ handleDetailPanelToggle, reportDetailPanelHeight, spanning, rowMetaMap, fillHandle,
600
+ pinnedTopRows, pinnedBottomRows, pinnedRows, getRowIdOf,
601
+ showEmptyState: !effectiveLoading && !state.dataSource.error && filteredRows.length === 0,
602
+ effectiveNoRowsLabel, spanRowWindow, visibleRows,
603
+ baseColumns: columns as unknown as GridColDef<R>[], viewportWidth: state.dimensions.viewportWidth,
604
+ rowReorderHandlers, paginationMode, dataSourceLoading: state.dataSource.loading,
605
+ sortedUnpinnedRowCount: sortedUnpinnedRows.length, pageSize: effectivePaginationModel.pageSize,
606
+ unpinnedRowsLength: layout.unpinnedRowsLength,
607
+ showAggregationFooter: hasAggregation && rowGroupingHandlers.rootAggregationPosition !== null,
608
+ aggregationResult, effectiveRowHeight, isAggregationLoading,
609
+ containerRef, className, autoHeight, height, style, hasRowSpanning, listView, headerFilterHeight, slots, slotProps,
610
+ toolbarProps, aiAssistantPanel, orderedColumns, columnVisibilityModel, disableColumnReorder,
611
+ handleColumnVisibilityModelChange, moveColumn, resetColumnOrder, listViewColumn, allRenderableRows, dataRows,
612
+ pagination, effectivePaginationModel, currentPage: rowPipeline.currentPage, pageSizeOptions,
613
+ columnsByField: columnLookup.byField, paginationRowCount, handlePaginationModelChange, onRowsScrollEnd,
614
+ toggleExpansion: activeHierarchyHandlers?.toggleExpansion, showCellSelectionStats, apiRef: gridData.apiRef,
615
+ hasAggregation, isHierarchyEnabled, dataSourceError: state.dataSource.error, filteredRowCount: filteredRows.length,
616
+ onRetry: dataSource ? dataSourceHandlers.fetchRows : undefined,
833
617
  };
834
618
 
835
- return (
836
- <div
837
- ref={containerRef}
838
- 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(' ')}
839
- style={{
840
- ...style,
841
- height: height ?? style?.height,
842
- '--ogx-row-height': `${effectiveRowHeight}px`,
843
- '--ogx-header-height': `${headerHeight}px`,
844
- ...(showHeaderFilters ? { '--ogx-header-filter-height': `${headerFilterHeight}px` } : undefined),
845
- } as unknown as React.CSSProperties}
846
- aria-busy={effectiveLoading}
847
- >
848
- {ToolbarSlot && toolbarProps && (
849
- <GridToolbarHostContext.Provider value={columnsPanel.toolbarHost}>
850
- <GridToolbarSlot component={ToolbarSlot} toolbarProps={toolbarProps} />
851
- </GridToolbarHostContext.Provider>
852
- )}
853
-
854
- {aiAssistantPanel.panelProps && (
855
- <GridAiAssistantArea
856
- panelProps={aiAssistantPanel.panelProps}
857
- slot={slots?.aiAssistantPanel}
858
- slotProps={slotProps?.aiAssistantPanel}
859
- />
860
- )}
861
-
862
- {/* Used by the column menu's Manage columns when no GridToolbar can show the panel */}
863
- <GridStandaloneColumnPanel<R>
864
- isOpen={columnsPanel.standalonePanelOpen}
865
- containerRef={containerRef}
866
- panelRef={columnsPanel.standalonePanelRef}
867
- columns={orderedColumns}
868
- columnVisibilityModel={columnVisibilityModel}
869
- disableColumnReorder={disableColumnReorder}
870
- onClose={columnsPanel.closeStandalonePanel}
871
- onColumnVisibilityChange={handleColumnVisibilityModelChange}
872
- onColumnMove={moveColumn}
873
- onColumnOrderReset={resetColumnOrder}
874
- columnGroupingModel={columnGroupingModel}
875
- />
876
-
877
-
878
- {listView && listViewColumn && (
879
- <GridListView<R>
880
- ariaLabel={ariaLabel}
881
- allRenderableRows={allRenderableRows}
882
- dataRowCount={dataRows.length}
883
- pinnedTopRowCount={pinnedTopRows.length}
884
- pinnedBottomRowCount={pinnedBottomRows.length}
885
- unpinnedRowCount={sortedUnpinnedRows.length}
886
- pagination={pagination}
887
- effectivePaginationModel={effectivePaginationModel}
888
- currentPage={rowPipeline.currentPage}
889
- pageSizeOptions={pageSizeOptions}
890
- selectedRowIds={selectedRowIds}
891
- listViewColumn={listViewColumn}
892
- columnsByField={columnLookup.byField}
893
- rowMetaMap={rowMetaMap}
894
- noRowsLabel={effectiveNoRowsLabel}
895
- rowHeight={effectiveRowHeight}
896
- checkboxSelection={checkboxSelection}
897
- paginationMode={paginationMode}
898
- serverRowCount={paginationRowCount}
899
- paginationSlot={slots?.pagination}
900
- paginationSlotProps={slotProps?.pagination}
901
- localeText={pickPaginationLocaleText(localeText)}
902
- onRowClick={handleRowClick}
903
- onRowDoubleClick={onRowDoubleClick}
904
- onSelectionChange={handleSelectionChange}
905
- onPaginationModelChange={handlePaginationModelChange}
906
- onRowsScrollEnd={onRowsScrollEnd}
907
- getRowId={getRowIdOf}
908
- multiselectable={rowSelectionEnabled && !disableMultipleRowSelection}
909
- selectable={rowSelectionEnabled}
910
- onToggleExpansion={activeHierarchyHandlers?.toggleExpansion}
911
- loading={effectiveLoading}
912
- loadingOverlay={loadingOverlay}
913
- noRowsOverlay={noRowsOverlay}
914
- showPaginationControls={!FooterSlot}
915
- />
916
- )}
917
-
918
- {/* ══════════════════════════════════════════════════════════════
919
- STANDARD GRID VIEWPORT (hidden when listView=true)
920
- ══════════════════════════════════════════════════════════════ */}
921
- {!listView && (
922
- <div
923
- ref={setViewportElement}
924
- className="ogx__viewport"
925
- onScroll={handleScroll}
926
- role="grid"
927
- aria-label={ariaLabel || 'Data grid'}
928
- aria-rowcount={ariaRows.rowCount}
929
- aria-colcount={navigationColumns.length}
930
- aria-multiselectable={(rowSelectionEnabled && !disableMultipleRowSelection) || cellSelection.enabled}
931
- aria-busy={effectiveLoading}
932
- tabIndex={viewportTabIndex}
933
- onKeyDownCapture={() => { setKeyboardMode(true); }}
934
- onMouseDownCapture={handleMouseDownCapture}
935
- onMouseDown={cellSelection.handleMouseDown}
936
- onClickCapture={cellSelection.handleClickCapture}
937
- onKeyDown={handleKeyDown}
938
- onFocus={handleFocus}
939
- onBlur={handleBlur}
940
- >
941
- <div
942
- className="ogx__content"
943
- style={{
944
- // With right-pinned columns the content spans at least the viewport, so they sit at its right edge.
945
- width: effectivePinnedColumns?.right?.length
946
- ? `max(100%, ${virtualization.totalWidth}px)`
947
- : virtualization.totalWidth
948
- }}
949
- role="presentation"
950
- >
951
- {/* Header and top-pinned rows stick together, so pinned rows sit below every header row. */}
952
- <div className="ogx__sticky-top" role="presentation">
953
- <Header
954
- columns={renderColumns}
955
- allColumns={renderedDataColumns}
956
- columnGroupingModel={columnGroupingModel}
957
- checkboxSelection={checkboxSelection}
958
- allSelected={allSelected}
959
- someSelected={someSelected}
960
- onSelectAll={rowSelection.selectAll}
961
- sortModel={sortModel}
962
- onSort={handleSort}
963
- onSortAdd={handleSortAdd}
964
- multiSort={multiSort}
965
-
966
- onColumnResize={handleColumnResize}
967
- onColumnAutosize={handleColumnAutosize}
968
- columnWidths={columnWidths}
969
- pinnedColumns={effectivePinnedColumns}
970
-
971
- focusedCell={focusedCell}
972
- columnIndexMap={columnIndexMap}
973
- onHeaderClick={handleHeaderClick}
974
- onDragStart={headerReorderHandlers.onDragStart}
975
- onDragOver={headerReorderHandlers.onDragOver}
976
- onDragEnd={headerReorderHandlers.onDragEnd}
977
- onDrop={headerReorderHandlers.onDrop}
978
- draggedColumn={headerReorderHandlers.draggedColumn}
979
- dragOverColumn={headerReorderHandlers.dragOverColumn}
980
- rowReordering={rowReordering}
981
- hasDetailPanel={hasDetailPanel}
982
- pinCheckboxColumn={pinCheckboxColumn}
983
- pinExpandColumn={pinExpandColumn}
984
- aggregationModel={aggregationModel}
985
- onHideColumn={handleHideColumn}
986
- onManageColumns={columnsPanel.openColumnsPanel}
987
- onPinColumn={handlePinColumn}
988
- wrapHeaderText={wrapHeaderText}
989
- headerHeight={headerHeight}
990
- headerFilters={showHeaderFilters}
991
- filterModel={filterModel}
992
- onFilterModelChange={handleFilterModelChange}
993
- onOpenFilterPanel={columnsPanel.openFiltersPanel}
994
- />
995
-
996
- <GridPinnedRows<R>
997
- {...rowRenderProps}
998
- rows={pinnedTopRows}
999
- position="top"
1000
- ariaRowIndexBase={ariaRows.topBase}
1001
- columns={renderColumns}
1002
- pinnedRows={pinnedRows}
1003
- getRowId={getRowIdOf}
1004
- />
1005
- </div>
1006
-
1007
- {/* Empty State Overlay (Standard View) — showing after header */}
1008
- {!effectiveLoading && !state.dataSource.error && filteredRows.length === 0 && (
1009
- <GridEmptyState
1010
- noRowsLabel={effectiveNoRowsLabel}
1011
- width={virtualization.totalWidth}
1012
- overlay={noRowsOverlay}
1013
- />
1014
- )}
1015
-
1016
- <GridVirtualRows<R>
1017
- {...rowRenderProps}
1018
- virtualContainerHeight={virtualization.virtualContainerHeight}
1019
- offsetTop={spanRowWindow.offsetTop}
1020
- effectiveLoading={effectiveLoading}
1021
- visibleRows={visibleRows}
1022
- baseColumns={columns as unknown as GridColDef<R>[]}
1023
- virtualColumns={renderColumns}
1024
- viewportWidth={state.dimensions.viewportWidth}
1025
- rowReorderHandlers={rowReorderHandlers}
1026
- paginationMode={paginationMode}
1027
- dataSourceLoading={state.dataSource.loading}
1028
- sortedUnpinnedRowCount={sortedUnpinnedRows.length}
1029
- infiniteScrollSkeletonCount={Math.min(effectivePaginationModel.pageSize, 20)}
1030
- unpinnedRowsLength={layout.unpinnedRowsLength}
1031
- lastRenderedRowIndex={spanRowWindow.renderContext.lastRowIndex}
1032
- ariaRowIndexOffset={ariaRows.centerOffset}
1033
- loadingOverlay={loadingOverlay}
1034
- />
1035
-
1036
- {/* Bottom-pinned rows and the aggregation footer stick together, footer last. */}
1037
- <div className="ogx__sticky-bottom" role="presentation">
1038
- <GridPinnedRows<R>
1039
- {...rowRenderProps}
1040
- rows={pinnedBottomRows}
1041
- position="bottom"
1042
- rowIndexOffset={ariaRows.bottomRowIndexOffset}
1043
- ariaRowIndexBase={ariaRows.bottomBase}
1044
- columns={renderColumns}
1045
- pinnedRows={pinnedRows}
1046
- getRowId={getRowIdOf}
1047
- />
1048
-
1049
- {/* Aggregation Footer Row — laid out from the same virtual columns as the rows, so
1050
- hidden, pinned and scrolled columns line up. Off in pivot mode (hasAggregation). */}
1051
- {hasAggregation && rowGroupingHandlers.rootAggregationPosition !== null && (
1052
- <GridAggregationFooter
1053
- columns={virtualization.virtualColumns as unknown as GridColDef[]}
1054
- aggregationModel={aggregationModel}
1055
- aggregationResult={aggregationResult}
1056
- columnWidths={columnWidths}
1057
- rowHeight={effectiveRowHeight}
1058
- checkboxSelection={checkboxSelection}
1059
- hasDetailPanel={hasDetailPanel}
1060
- rowReordering={rowReordering}
1061
- pinCheckboxColumn={pinCheckboxColumn}
1062
- pinExpandColumn={pinExpandColumn}
1063
- pinnedColumns={effectivePinnedColumns}
1064
- loading={isAggregationLoading}
1065
- />
1066
- )}
1067
- </div>
1068
-
1069
- </div>
1070
- </div>
1071
- )}
1072
-
1073
- {cellSelection.enabled && showCellSelectionStats && (
1074
- <GridCellSelectionStatsArea
1075
- stats={cellSelection.stats}
1076
- apiRef={gridData.apiRef}
1077
- slot={slots?.cellSelectionStats}
1078
- slotProps={slotProps?.cellSelectionStats}
1079
- />
1080
- )}
1081
-
1082
- {FooterSlot && (
1083
- <FooterSlot
1084
- apiRef={gridData.apiRef}
1085
- aggregationModel={aggregationModel}
1086
- aggregationResult={hasAggregation ? aggregationResult : null}
1087
- rowCount={isHierarchyEnabled && paginationMode !== 'server' ? dataRows.length : paginationRowCount}
1088
- pagination={pagination}
1089
- paginationModel={effectivePaginationModel}
1090
- pageSizeOptions={pageSizeOptions}
1091
- onPaginationModelChange={handlePaginationModelChange}
1092
- {...slotProps?.footer}
1093
- />
1094
- )}
1095
-
1096
- {!listView && !FooterSlot && pagination && (
1097
- <GridPaginationArea
1098
- paginationSlot={slots?.pagination}
1099
- paginationSlotProps={slotProps?.pagination}
1100
- page={rowPipeline.currentPage}
1101
- paginationModel={effectivePaginationModel}
1102
- rowCount={paginationRowCount}
1103
- pageSizeOptions={pageSizeOptions}
1104
- onPaginationModelChange={handlePaginationModelChange}
1105
- localeText={localeText}
1106
- />
1107
- )}
1108
-
1109
- <GridLiveRegion
1110
- loading={effectiveLoading}
1111
- error={state.dataSource.error}
1112
- noRowsLabel={effectiveNoRowsLabel}
1113
- filteredRowCount={filteredRows.length}
1114
- dataRowCount={dataRows.length}
1115
- filterModel={filterModel}
1116
- cellSelectionAnnouncement={cellSelection.announcement}
1117
- aiAssistantAnnouncement={aiAssistantPanel.announcement}
1118
- />
1119
-
1120
- {showLoadingOverRows && (
1121
- <GridLoadingOverlay overlay={loadingOverlay} />
1122
- )}
1123
-
1124
- <GridErrorOverlay error={state.dataSource.error} onRetry={dataSource ? dataSourceHandlers.fetchRows : undefined} />
1125
- </div>
1126
- );
619
+ return <GridRoot<R> {...rootProps} />;
1127
620
  }