@mui/x-data-grid 5.16.0 → 5.17.2

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 (141) hide show
  1. package/CHANGELOG.md +138 -1
  2. package/components/GridRow.d.ts +2 -1
  3. package/components/GridRow.js +132 -83
  4. package/components/cell/GridBooleanCell.js +2 -1
  5. package/components/cell/GridCell.js +9 -1
  6. package/components/cell/GridEditBooleanCell.js +2 -1
  7. package/components/cell/GridEditDateCell.js +2 -1
  8. package/components/cell/GridEditInputCell.js +2 -1
  9. package/components/cell/GridEditSingleSelectCell.js +2 -1
  10. package/components/cell/GridSkeletonCell.d.ts +12 -0
  11. package/components/cell/GridSkeletonCell.js +60 -0
  12. package/components/cell/index.d.ts +1 -0
  13. package/components/cell/index.js +2 -1
  14. package/components/columnSelection/GridCellCheckboxRenderer.js +2 -1
  15. package/components/containers/GridRootStyles.js +2 -0
  16. package/components/panel/GridColumnsPanel.d.ts +6 -1
  17. package/components/panel/GridColumnsPanel.js +38 -6
  18. package/constants/defaultGridSlotsComponents.js +2 -1
  19. package/constants/gridClasses.d.ts +8 -0
  20. package/constants/gridClasses.js +1 -1
  21. package/hooks/core/pipeProcessing/gridPipeProcessingApi.d.ts +5 -1
  22. package/hooks/features/editRows/useGridCellEditing.new.js +8 -2
  23. package/hooks/features/editRows/useGridRowEditing.new.js +8 -2
  24. package/hooks/features/filter/gridFilterUtils.d.ts +1 -1
  25. package/hooks/features/filter/gridFilterUtils.js +55 -54
  26. package/hooks/features/filter/useGridFilter.js +1 -1
  27. package/hooks/features/focus/useGridFocus.js +13 -3
  28. package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +2 -0
  29. package/hooks/features/rows/useGridParamsApi.js +1 -1
  30. package/hooks/features/rows/useGridRows.js +65 -8
  31. package/hooks/features/rows/useGridRowsMeta.js +36 -16
  32. package/hooks/features/virtualization/useGridVirtualScroller.d.ts +1 -1
  33. package/hooks/features/virtualization/useGridVirtualScroller.js +17 -5
  34. package/index.js +1 -1
  35. package/internals/index.d.ts +1 -1
  36. package/internals/index.js +1 -1
  37. package/legacy/components/GridRow.js +135 -83
  38. package/legacy/components/cell/GridBooleanCell.js +2 -1
  39. package/legacy/components/cell/GridCell.js +11 -1
  40. package/legacy/components/cell/GridEditBooleanCell.js +2 -1
  41. package/legacy/components/cell/GridEditDateCell.js +2 -1
  42. package/legacy/components/cell/GridEditInputCell.js +2 -1
  43. package/legacy/components/cell/GridEditSingleSelectCell.js +2 -1
  44. package/legacy/components/cell/GridSkeletonCell.js +57 -0
  45. package/legacy/components/cell/index.js +2 -1
  46. package/legacy/components/columnSelection/GridCellCheckboxRenderer.js +2 -1
  47. package/legacy/components/containers/GridRootStyles.js +3 -3
  48. package/legacy/components/panel/GridColumnsPanel.js +41 -6
  49. package/legacy/constants/defaultGridSlotsComponents.js +2 -1
  50. package/legacy/constants/gridClasses.js +1 -1
  51. package/legacy/hooks/features/editRows/useGridCellEditing.new.js +11 -5
  52. package/legacy/hooks/features/editRows/useGridRowEditing.new.js +8 -2
  53. package/legacy/hooks/features/filter/gridFilterUtils.js +61 -56
  54. package/legacy/hooks/features/filter/useGridFilter.js +1 -1
  55. package/legacy/hooks/features/focus/useGridFocus.js +13 -3
  56. package/legacy/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +2 -0
  57. package/legacy/hooks/features/rows/useGridParamsApi.js +1 -1
  58. package/legacy/hooks/features/rows/useGridRows.js +73 -8
  59. package/legacy/hooks/features/rows/useGridRowsMeta.js +45 -18
  60. package/legacy/hooks/features/virtualization/useGridVirtualScroller.js +31 -13
  61. package/legacy/index.js +1 -1
  62. package/legacy/internals/index.js +1 -1
  63. package/legacy/models/events/gridEvents.js +2 -0
  64. package/legacy/models/params/gridRenderedRowsIntervalChangeParams.js +1 -0
  65. package/legacy/models/params/index.js +2 -1
  66. package/legacy/utils/utils.js +25 -0
  67. package/models/api/gridParamsApi.d.ts +1 -1
  68. package/models/api/gridRowApi.d.ts +6 -0
  69. package/models/api/gridRowsMetaApi.d.ts +6 -1
  70. package/models/events/gridEventLookup.d.ts +7 -1
  71. package/models/events/gridEvents.d.ts +3 -1
  72. package/models/events/gridEvents.js +2 -0
  73. package/models/gridSlotsComponent.d.ts +5 -0
  74. package/models/params/gridCellParams.d.ts +7 -2
  75. package/models/params/gridRenderedRowsIntervalChangeParams.d.ts +10 -0
  76. package/models/params/gridRenderedRowsIntervalChangeParams.js +1 -0
  77. package/models/params/index.d.ts +1 -0
  78. package/models/params/index.js +2 -1
  79. package/modern/components/GridRow.js +129 -82
  80. package/modern/components/cell/GridBooleanCell.js +2 -1
  81. package/modern/components/cell/GridCell.js +9 -1
  82. package/modern/components/cell/GridEditBooleanCell.js +2 -1
  83. package/modern/components/cell/GridEditDateCell.js +2 -1
  84. package/modern/components/cell/GridEditInputCell.js +2 -1
  85. package/modern/components/cell/GridEditSingleSelectCell.js +2 -1
  86. package/modern/components/cell/GridSkeletonCell.js +60 -0
  87. package/modern/components/cell/index.js +2 -1
  88. package/modern/components/columnSelection/GridCellCheckboxRenderer.js +2 -1
  89. package/modern/components/containers/GridRootStyles.js +2 -0
  90. package/modern/components/panel/GridColumnsPanel.js +38 -6
  91. package/modern/constants/defaultGridSlotsComponents.js +2 -1
  92. package/modern/constants/gridClasses.js +1 -1
  93. package/modern/hooks/features/editRows/useGridCellEditing.new.js +8 -2
  94. package/modern/hooks/features/editRows/useGridRowEditing.new.js +8 -2
  95. package/modern/hooks/features/filter/gridFilterUtils.js +54 -53
  96. package/modern/hooks/features/filter/useGridFilter.js +1 -1
  97. package/modern/hooks/features/focus/useGridFocus.js +13 -3
  98. package/modern/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +2 -0
  99. package/modern/hooks/features/rows/useGridParamsApi.js +1 -1
  100. package/modern/hooks/features/rows/useGridRows.js +65 -8
  101. package/modern/hooks/features/rows/useGridRowsMeta.js +36 -16
  102. package/modern/hooks/features/virtualization/useGridVirtualScroller.js +17 -5
  103. package/modern/index.js +1 -1
  104. package/modern/internals/index.js +1 -1
  105. package/modern/models/events/gridEvents.js +2 -0
  106. package/modern/models/params/gridRenderedRowsIntervalChangeParams.js +1 -0
  107. package/modern/models/params/index.js +2 -1
  108. package/modern/utils/utils.js +23 -0
  109. package/node/components/GridRow.js +131 -75
  110. package/node/components/cell/GridBooleanCell.js +2 -1
  111. package/node/components/cell/GridCell.js +9 -1
  112. package/node/components/cell/GridEditBooleanCell.js +2 -1
  113. package/node/components/cell/GridEditDateCell.js +2 -1
  114. package/node/components/cell/GridEditInputCell.js +2 -1
  115. package/node/components/cell/GridEditSingleSelectCell.js +2 -1
  116. package/node/components/cell/GridSkeletonCell.js +81 -0
  117. package/node/components/cell/index.js +13 -0
  118. package/node/components/columnSelection/GridCellCheckboxRenderer.js +2 -1
  119. package/node/components/containers/GridRootStyles.js +2 -0
  120. package/node/components/panel/GridColumnsPanel.js +36 -5
  121. package/node/constants/defaultGridSlotsComponents.js +1 -0
  122. package/node/constants/gridClasses.js +1 -1
  123. package/node/hooks/features/editRows/useGridCellEditing.new.js +9 -2
  124. package/node/hooks/features/editRows/useGridRowEditing.new.js +9 -2
  125. package/node/hooks/features/filter/gridFilterUtils.js +55 -55
  126. package/node/hooks/features/filter/useGridFilter.js +1 -1
  127. package/node/hooks/features/focus/useGridFocus.js +13 -3
  128. package/node/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +2 -0
  129. package/node/hooks/features/rows/useGridParamsApi.js +1 -1
  130. package/node/hooks/features/rows/useGridRows.js +60 -7
  131. package/node/hooks/features/rows/useGridRowsMeta.js +35 -15
  132. package/node/hooks/features/virtualization/useGridVirtualScroller.js +17 -5
  133. package/node/index.js +1 -1
  134. package/node/internals/index.js +6 -0
  135. package/node/models/events/gridEvents.js +2 -0
  136. package/node/models/params/gridRenderedRowsIntervalChangeParams.js +5 -0
  137. package/node/models/params/index.js +13 -0
  138. package/node/utils/utils.js +27 -0
  139. package/package.json +1 -1
  140. package/utils/utils.d.ts +2 -0
  141. package/utils/utils.js +23 -0
@@ -69,72 +69,72 @@ export const sanitizeFilterModel = (model, disableMultipleColumnsFiltering, apiR
69
69
  export const mergeStateWithFilterModel = (filterModel, disableMultipleColumnsFiltering, apiRef) => filteringState => _extends({}, filteringState, {
70
70
  filterModel: sanitizeFilterModel(filterModel, disableMultipleColumnsFiltering, apiRef)
71
71
  });
72
- /**
73
- * Generates a method to easily check if a row is matching the current filter model.
74
- * @param {GridFilterModel} filterModel The model with which we want to filter the rows.
75
- * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
76
- * @returns {GridAggregatedFilterItemApplier | null} A method that checks if a row is matching the current filter model. If `null`, we consider that all the rows are matching the filters.
77
- */
78
72
 
79
- export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
80
- const {
81
- items
82
- } = filterModel;
83
-
84
- const getFilterCallbackFromItem = filterItem => {
85
- if (!filterItem.columnField || !filterItem.operatorValue) {
86
- return null;
87
- }
73
+ const getFilterCallbackFromItem = (filterItem, apiRef) => {
74
+ if (!filterItem.columnField || !filterItem.operatorValue) {
75
+ return null;
76
+ }
88
77
 
89
- const column = apiRef.current.getColumn(filterItem.columnField);
78
+ const column = apiRef.current.getColumn(filterItem.columnField);
90
79
 
91
- if (!column) {
92
- return null;
93
- }
80
+ if (!column) {
81
+ return null;
82
+ }
94
83
 
95
- let parsedValue;
84
+ let parsedValue;
96
85
 
97
- if (column.valueParser) {
98
- const parser = column.valueParser;
99
- parsedValue = Array.isArray(filterItem.value) ? filterItem.value?.map(x => parser(x)) : parser(filterItem.value);
100
- } else {
101
- parsedValue = filterItem.value;
102
- }
86
+ if (column.valueParser) {
87
+ const parser = column.valueParser;
88
+ parsedValue = Array.isArray(filterItem.value) ? filterItem.value?.map(x => parser(x)) : parser(filterItem.value);
89
+ } else {
90
+ parsedValue = filterItem.value;
91
+ }
103
92
 
104
- const newFilterItem = _extends({}, filterItem, {
105
- value: parsedValue
106
- });
93
+ const newFilterItem = _extends({}, filterItem, {
94
+ value: parsedValue
95
+ });
107
96
 
108
- const filterOperators = column.filterOperators;
97
+ const filterOperators = column.filterOperators;
109
98
 
110
- if (!filterOperators?.length) {
111
- throw new Error(`MUI: No filter operators found for column '${column.field}'.`);
112
- }
99
+ if (!filterOperators?.length) {
100
+ throw new Error(`MUI: No filter operators found for column '${column.field}'.`);
101
+ }
113
102
 
114
- const filterOperator = filterOperators.find(operator => operator.value === newFilterItem.operatorValue);
103
+ const filterOperator = filterOperators.find(operator => operator.value === newFilterItem.operatorValue);
115
104
 
116
- if (!filterOperator) {
117
- throw new Error(`MUI: No filter operator found for column '${column.field}' and operator value '${newFilterItem.operatorValue}'.`);
118
- }
105
+ if (!filterOperator) {
106
+ throw new Error(`MUI: No filter operator found for column '${column.field}' and operator value '${newFilterItem.operatorValue}'.`);
107
+ }
119
108
 
120
- const applyFilterOnRow = filterOperator.getApplyFilterFn(newFilterItem, column);
109
+ const applyFilterOnRow = filterOperator.getApplyFilterFn(newFilterItem, column);
121
110
 
122
- if (typeof applyFilterOnRow !== 'function') {
123
- return null;
124
- }
111
+ if (typeof applyFilterOnRow !== 'function') {
112
+ return null;
113
+ }
125
114
 
126
- const fn = rowId => {
127
- const cellParams = apiRef.current.getCellParams(rowId, newFilterItem.columnField);
128
- return applyFilterOnRow(cellParams);
129
- };
115
+ const fn = rowId => {
116
+ const cellParams = apiRef.current.getCellParams(rowId, newFilterItem.columnField);
117
+ return applyFilterOnRow(cellParams);
118
+ };
130
119
 
131
- return {
132
- fn,
133
- item: newFilterItem
134
- };
120
+ return {
121
+ fn,
122
+ item: newFilterItem
135
123
  };
124
+ };
125
+ /**
126
+ * Generates a method to easily check if a row is matching the current filter model.
127
+ * @param {GridFilterModel} filterModel The model with which we want to filter the rows.
128
+ * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
129
+ * @returns {GridAggregatedFilterItemApplier | null} A method that checks if a row is matching the current filter model. If `null`, we consider that all the rows are matching the filters.
130
+ */
136
131
 
137
- const appliers = items.map(getFilterCallbackFromItem).filter(callback => !!callback);
132
+
133
+ export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
134
+ const {
135
+ items
136
+ } = filterModel;
137
+ const appliers = items.map(item => getFilterCallbackFromItem(item, apiRef)).filter(callback => !!callback);
138
138
 
139
139
  if (appliers.length === 0) {
140
140
  return null;
@@ -215,7 +215,8 @@ export const buildAggregatedFilterApplier = (filterModel, apiRef) => {
215
215
  passingQuickFilterValues: isRowMatchingQuickFilter && isRowMatchingQuickFilter(rowId, shouldApplyFilter)
216
216
  });
217
217
  };
218
- export const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel) => {
218
+ export const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel, apiRef) => {
219
+ const cleanedFilterItems = filterModel.items.filter(item => getFilterCallbackFromItem(item, apiRef) !== null);
219
220
  const cleanedAllFilterItemResults = allFilterItemResults.filter(result => result != null);
220
221
  const cleanedAllQuickFilterResults = allQuickFilterResults.filter(result => result != null); // Defaultize operators
221
222
 
@@ -229,13 +230,13 @@ export const passFilterLogic = (allFilterItemResults, allQuickFilterResults, fil
229
230
  };
230
231
 
231
232
  if (linkOperator === GridLinkOperator.And) {
232
- const passesAllFilters = filterModel.items.every(filterItemPredicate);
233
+ const passesAllFilters = cleanedFilterItems.every(filterItemPredicate);
233
234
 
234
235
  if (!passesAllFilters) {
235
236
  return false;
236
237
  }
237
238
  } else {
238
- const passesSomeFilters = filterModel.items.some(filterItemPredicate);
239
+ const passesSomeFilters = cleanedFilterItems.some(filterItemPredicate);
239
240
 
240
241
  if (!passesSomeFilters) {
241
242
  return false;
@@ -259,7 +259,7 @@ export const useGridFilter = (apiRef, props) => {
259
259
  passingFilterItems,
260
260
  passingQuickFilterValues
261
261
  } = params.isRowMatchingFilters(rowId);
262
- isRowPassing = passFilterLogic([passingFilterItems], [passingQuickFilterValues], params.filterModel);
262
+ isRowPassing = passFilterLogic([passingFilterItems], [passingQuickFilterValues], params.filterModel, apiRef);
263
263
  }
264
264
 
265
265
  filteredRowsLookup[rowId] = isRowPassing;
@@ -131,8 +131,18 @@ export const useGridFocus = (apiRef, props) => {
131
131
  }
132
132
 
133
133
  rowIndexToFocus = clamp(rowIndexToFocus, 0, currentPage.rows.length - 1);
134
- columnIndexToFocus = clamp(columnIndexToFocus, 0, visibleColumns.length - 1);
135
134
  const rowToFocus = currentPage.rows[rowIndexToFocus];
135
+ const colSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowToFocus.id, columnIndexToFocus);
136
+
137
+ if (colSpanInfo && colSpanInfo.spannedByColSpan) {
138
+ if (direction === 'left' || direction === 'below') {
139
+ columnIndexToFocus = colSpanInfo.leftVisibleCellIndex;
140
+ } else if (direction === 'right') {
141
+ columnIndexToFocus = colSpanInfo.rightVisibleCellIndex;
142
+ }
143
+ }
144
+
145
+ columnIndexToFocus = clamp(columnIndexToFocus, 0, visibleColumns.length - 1);
136
146
  const columnToFocus = visibleColumns[columnIndexToFocus];
137
147
  apiRef.current.setCellFocus(rowToFocus.id, columnToFocus.field);
138
148
  }, [apiRef, props.pagination, props.paginationMode]);
@@ -168,7 +178,7 @@ export const useGridFocus = (apiRef, props) => {
168
178
  }
169
179
  }));
170
180
  }, [logger, apiRef]);
171
- const handleCellMouseUp = React.useCallback(params => {
181
+ const handleCellMouseDown = React.useCallback(params => {
172
182
  lastClickedCell.current = params;
173
183
  }, []);
174
184
  const handleDocumentClick = React.useCallback(event => {
@@ -251,7 +261,7 @@ export const useGridFocus = (apiRef, props) => {
251
261
  }, [apiRef, handleDocumentClick]);
252
262
  useGridApiEventHandler(apiRef, 'columnHeaderBlur', handleBlur);
253
263
  useGridApiEventHandler(apiRef, 'cellDoubleClick', handleCellDoubleClick);
254
- useGridApiEventHandler(apiRef, 'cellMouseUp', handleCellMouseUp);
264
+ useGridApiEventHandler(apiRef, 'cellMouseDown', handleCellMouseDown);
255
265
  useGridApiEventHandler(apiRef, 'cellKeyDown', handleCellKeyDown);
256
266
  useGridApiEventHandler(apiRef, 'cellModeChange', handleCellModeChange);
257
267
  useGridApiEventHandler(apiRef, 'columnHeaderFocus', handleColumnHeaderFocus);
@@ -34,6 +34,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
34
34
  * @param {number} colIndex Index of the column to focus
35
35
  * @param {number} rowIndex index of the row to focus
36
36
  * @param {string} closestColumnToUse Which closest column cell to use when the cell is spanned by `colSpan`.
37
+ * TODO replace with apiRef.current.unstable_moveFocusToRelativeCell()
37
38
  */
38
39
 
39
40
  const goToCell = React.useCallback((colIndex, rowId, closestColumnToUse = 'left') => {
@@ -90,6 +91,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
90
91
  case 'ArrowDown':
91
92
  case 'Enter':
92
93
  {
94
+ // TODO v6: Remove Enter case because `cellNavigationKeyDown` is not fired by the new editing API
93
95
  // "Enter" is only triggered by the row / cell editing feature
94
96
  if (rowIndexBefore < lastRowIndexInPage) {
95
97
  goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore + 1));
@@ -105,7 +105,7 @@ export function useGridParamsApi(apiRef) {
105
105
  formattedValue: value
106
106
  };
107
107
 
108
- if (colDef.valueFormatter) {
108
+ if (colDef && colDef.valueFormatter) {
109
109
  params.formattedValue = colDef.valueFormatter({
110
110
  id,
111
111
  field: params.field,
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { useGridApiMethod } from '../../utils/useGridApiMethod';
4
4
  import { useGridLogger } from '../../utils/useGridLogger';
5
- import { gridRowCountSelector, gridRowsLookupSelector, gridRowTreeSelector, gridRowIdsSelector, gridRowGroupingNameSelector } from './gridRowsSelector';
5
+ import { gridRowCountSelector, gridRowsLookupSelector, gridRowTreeSelector, gridRowIdsSelector, gridRowGroupingNameSelector, gridRowsIdToIdLookupSelector } from './gridRowsSelector';
6
6
  import { GridSignature, useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
7
7
  import { useGridVisibleRows } from '../../utils/useGridVisibleRows';
8
8
  import { gridSortedRowIdsSelector } from '../sorting/gridSortingSelector';
@@ -100,14 +100,14 @@ export const useGridRows = (apiRef, props) => {
100
100
  } // we remove duplicate updates. A server can batch updates, and send several updates for the same row in one fn call.
101
101
 
102
102
 
103
- const uniqUpdates = new Map();
103
+ const uniqueUpdates = new Map();
104
104
  updates.forEach(update => {
105
105
  const id = getRowIdFromRowModel(update, props.getRowId, 'A row was provided without id when calling updateRows():');
106
106
 
107
- if (uniqUpdates.has(id)) {
108
- uniqUpdates.set(id, _extends({}, uniqUpdates.get(id), update));
107
+ if (uniqueUpdates.has(id)) {
108
+ uniqueUpdates.set(id, _extends({}, uniqueUpdates.get(id), update));
109
109
  } else {
110
- uniqUpdates.set(id, update);
110
+ uniqueUpdates.set(id, update);
111
111
  }
112
112
  });
113
113
  const deletedRowIds = [];
@@ -119,7 +119,7 @@ export const useGridRows = (apiRef, props) => {
119
119
  idToIdLookup: _extends({}, prevCache.idToIdLookup),
120
120
  ids: [...prevCache.ids]
121
121
  };
122
- uniqUpdates.forEach((partialRow, id) => {
122
+ uniqueUpdates.forEach((partialRow, id) => {
123
123
  // eslint-disable-next-line no-underscore-dangle
124
124
  if (partialRow._action === 'delete') {
125
125
  delete newCache.idRowsLookup[id];
@@ -233,8 +233,64 @@ export const useGridRows = (apiRef, props) => {
233
233
  ids: updatedRows
234
234
  })
235
235
  }));
236
- apiRef.current.applySorting();
236
+ apiRef.current.publishEvent('rowsSet');
237
237
  }, [apiRef, logger]);
238
+ const replaceRows = React.useCallback((firstRowToRender, newRows) => {
239
+ if (props.signature === GridSignature.DataGrid && newRows.length > 1) {
240
+ throw new Error(["MUI: You can't replace rows using `apiRef.current.unstable_replaceRows` on the DataGrid.", 'You need to upgrade to DataGridPro or DataGridPremium component to unlock this feature.'].join('\n'));
241
+ }
242
+
243
+ if (newRows.length === 0) {
244
+ return;
245
+ }
246
+
247
+ const allRows = gridRowIdsSelector(apiRef);
248
+ const updatedRows = [...allRows];
249
+ const idRowsLookup = gridRowsLookupSelector(apiRef);
250
+ const idToIdLookup = gridRowsIdToIdLookupSelector(apiRef);
251
+ const tree = gridRowTreeSelector(apiRef);
252
+
253
+ const updatedIdRowsLookup = _extends({}, idRowsLookup);
254
+
255
+ const updatedIdToIdLookup = _extends({}, idToIdLookup);
256
+
257
+ const updatedTree = _extends({}, tree);
258
+
259
+ const newRowEntries = newRows.map(newRowModel => {
260
+ const rowId = getRowIdFromRowModel(newRowModel, props.getRowId, 'A row was provided without id when calling replaceRows().');
261
+ return {
262
+ id: rowId,
263
+ model: newRowModel
264
+ };
265
+ });
266
+ newRowEntries.forEach((row, index) => {
267
+ const [replacedRowId] = updatedRows.splice(firstRowToRender + index, 1, row.id);
268
+ delete updatedIdRowsLookup[replacedRowId];
269
+ delete updatedIdToIdLookup[replacedRowId];
270
+ delete updatedTree[replacedRowId];
271
+ });
272
+ newRowEntries.forEach(row => {
273
+ const rowTreeNodeConfig = {
274
+ id: row.id,
275
+ parent: null,
276
+ depth: 0,
277
+ groupingKey: null,
278
+ groupingField: null
279
+ };
280
+ updatedIdRowsLookup[row.id] = row.model;
281
+ updatedIdToIdLookup[row.id] = row.id;
282
+ updatedTree[row.id] = rowTreeNodeConfig;
283
+ });
284
+ apiRef.current.setState(state => _extends({}, state, {
285
+ rows: _extends({}, state.rows, {
286
+ idRowsLookup: updatedIdRowsLookup,
287
+ idToIdLookup: updatedIdToIdLookup,
288
+ tree: updatedTree,
289
+ ids: updatedRows
290
+ })
291
+ }));
292
+ apiRef.current.publishEvent('rowsSet');
293
+ }, [apiRef, props.signature, props.getRowId]);
238
294
  const rowApi = {
239
295
  getRow,
240
296
  getRowModels,
@@ -246,7 +302,8 @@ export const useGridRows = (apiRef, props) => {
246
302
  setRowChildrenExpansion,
247
303
  getRowNode,
248
304
  getRowIndexRelativeToVisibleRows,
249
- getRowGroupChildren
305
+ getRowGroupChildren,
306
+ unstable_replaceRows: replaceRows
250
307
  };
251
308
  /**
252
309
  * EVENTS
@@ -1,6 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import { debounce } from '@mui/material/utils';
3
+ import { debounce, capitalize } from '@mui/material/utils';
4
4
  import { useGridVisibleRows } from '../../utils/useGridVisibleRows';
5
5
  import { useGridApiMethod } from '../../utils/useGridApiMethod';
6
6
  import { useGridSelector } from '../../utils/useGridSelector';
@@ -45,7 +45,7 @@ export const useGridRowsMeta = (apiRef, props) => {
45
45
  if (!rowsHeightLookup.current[row.id]) {
46
46
  rowsHeightLookup.current[row.id] = {
47
47
  sizes: {
48
- base: rowHeightFromDensity
48
+ baseCenter: rowHeightFromDensity
49
49
  },
50
50
  isResized: false,
51
51
  autoHeight: false,
@@ -60,7 +60,7 @@ export const useGridRowsMeta = (apiRef, props) => {
60
60
  sizes
61
61
  } = rowsHeightLookup.current[row.id];
62
62
  let baseRowHeight = rowHeightFromDensity;
63
- const existingBaseRowHeight = sizes.base;
63
+ const existingBaseRowHeight = sizes.baseCenter;
64
64
 
65
65
  if (isResized) {
66
66
  // Do not recalculate resized row height and use the value from the lookup
@@ -91,12 +91,19 @@ export const useGridRowsMeta = (apiRef, props) => {
91
91
  }
92
92
  } else {
93
93
  rowsHeightLookup.current[row.id].needsFirstMeasurement = false;
94
- } // We use an object to make simple to check if a height is already added or not
94
+ }
95
95
 
96
+ const existingBaseSizes = Object.entries(sizes).reduce((acc, [key, size]) => {
97
+ if (/^base[A-Z]/.test(key)) {
98
+ acc[key] = size;
99
+ }
96
100
 
97
- const initialHeights = {
98
- base: baseRowHeight
99
- };
101
+ return acc;
102
+ }, {}); // We use an object to make simple to check if a height is already added or not
103
+
104
+ const initialHeights = _extends({}, existingBaseSizes, {
105
+ baseCenter: baseRowHeight
106
+ });
100
107
 
101
108
  if (getRowSpacing) {
102
109
  const indexRelativeToCurrentPage = apiRef.current.getRowIndexRelativeToVisibleRows(row.id);
@@ -117,9 +124,17 @@ export const useGridRowsMeta = (apiRef, props) => {
117
124
  const positions = [];
118
125
  const currentPageTotalHeight = currentPage.rows.reduce((acc, row) => {
119
126
  positions.push(acc);
127
+ let maximumBaseSize = 0;
128
+ let otherSizes = 0;
120
129
  const processedSizes = calculateRowProcessedSizes(row);
121
- const finalRowHeight = Object.values(processedSizes).reduce((acc2, value) => acc2 + value, 0);
122
- return acc + finalRowHeight;
130
+ Object.entries(processedSizes).forEach(([size, value]) => {
131
+ if (/^base[A-Z]/.test(size)) {
132
+ maximumBaseSize = value > maximumBaseSize ? value : maximumBaseSize;
133
+ } else {
134
+ otherSizes += value;
135
+ }
136
+ });
137
+ return acc + maximumBaseSize + otherSizes;
123
138
  }, 0);
124
139
  pinnedRows?.top?.forEach(row => {
125
140
  calculateRowProcessedSizes(row);
@@ -145,27 +160,27 @@ export const useGridRowsMeta = (apiRef, props) => {
145
160
  }, [apiRef, currentPage.rows, rowHeightFromDensity, getRowHeightProp, getRowSpacing, getEstimatedRowHeight, pinnedRows]);
146
161
  const getRowHeight = React.useCallback(rowId => {
147
162
  const height = rowsHeightLookup.current[rowId];
148
- return height ? height.sizes.base : rowHeightFromDensity;
163
+ return height ? height.sizes.baseCenter : rowHeightFromDensity;
149
164
  }, [rowHeightFromDensity]);
150
165
 
151
166
  const getRowInternalSizes = rowId => rowsHeightLookup.current[rowId]?.sizes;
152
167
 
153
168
  const setRowHeight = React.useCallback((id, height) => {
154
- rowsHeightLookup.current[id].sizes.base = height;
169
+ rowsHeightLookup.current[id].sizes.baseCenter = height;
155
170
  rowsHeightLookup.current[id].isResized = true;
156
171
  rowsHeightLookup.current[id].needsFirstMeasurement = false;
157
172
  hydrateRowsMeta();
158
173
  }, [hydrateRowsMeta]);
159
174
  const debouncedHydrateRowsMeta = React.useMemo(() => debounce(hydrateRowsMeta), [hydrateRowsMeta]);
160
- const storeMeasuredRowHeight = React.useCallback((id, height) => {
175
+ const storeMeasuredRowHeight = React.useCallback((id, height, position) => {
161
176
  if (!rowsHeightLookup.current[id] || !rowsHeightLookup.current[id].autoHeight) {
162
177
  return;
163
178
  } // Only trigger hydration if the value is different, otherwise we trigger a loop
164
179
 
165
180
 
166
- const needsHydration = rowsHeightLookup.current[id].sizes.base !== height;
181
+ const needsHydration = rowsHeightLookup.current[id].sizes[`base${capitalize(position)}`] !== height;
167
182
  rowsHeightLookup.current[id].needsFirstMeasurement = false;
168
- rowsHeightLookup.current[id].sizes.base = height;
183
+ rowsHeightLookup.current[id].sizes[`base${capitalize(position)}`] = height;
169
184
 
170
185
  if (needsHydration) {
171
186
  debouncedHydrateRowsMeta();
@@ -181,7 +196,11 @@ export const useGridRowsMeta = (apiRef, props) => {
181
196
  if (hasRowWithAutoHeight.current && index > lastMeasuredRowIndex.current) {
182
197
  lastMeasuredRowIndex.current = index;
183
198
  }
184
- }, []); // The effect is used to build the rows meta data - currentPageTotalHeight and positions.
199
+ }, []);
200
+ const resetRowHeights = React.useCallback(() => {
201
+ rowsHeightLookup.current = {};
202
+ hydrateRowsMeta();
203
+ }, [hydrateRowsMeta]); // The effect is used to build the rows meta data - currentPageTotalHeight and positions.
185
204
  // Because of variable row height this is needed for the virtualization
186
205
 
187
206
  React.useEffect(() => {
@@ -195,7 +214,8 @@ export const useGridRowsMeta = (apiRef, props) => {
195
214
  unstable_getRowHeight: getRowHeight,
196
215
  unstable_getRowInternalSizes: getRowInternalSizes,
197
216
  unstable_setRowHeight: setRowHeight,
198
- unstable_storeRowHeightMeasurement: storeMeasuredRowHeight
217
+ unstable_storeRowHeightMeasurement: storeMeasuredRowHeight,
218
+ resetRowHeights
199
219
  };
200
220
  useGridApiMethod(apiRef, rowsMetaApi, 'GridRowsMetaApi');
201
221
  };
@@ -211,8 +211,19 @@ export const useGridVirtualScroller = props => {
211
211
  }, [renderContext, updateRenderZonePosition]);
212
212
  const updateRenderContext = React.useCallback(nextRenderContext => {
213
213
  setRenderContext(nextRenderContext);
214
+ const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
215
+ firstIndex: nextRenderContext.firstRowIndex,
216
+ lastIndex: nextRenderContext.lastRowIndex,
217
+ minFirstIndex: 0,
218
+ maxLastIndex: currentPage.rows.length,
219
+ buffer: rootProps.rowBuffer
220
+ });
221
+ apiRef.current.publishEvent('renderedRowsIntervalChange', {
222
+ firstRowToRender,
223
+ lastRowToRender
224
+ });
214
225
  prevRenderContext.current = nextRenderContext;
215
- }, [setRenderContext, prevRenderContext]);
226
+ }, [apiRef, setRenderContext, prevRenderContext, currentPage.rows.length, rootProps.rowBuffer]);
216
227
  React.useEffect(() => {
217
228
  if (containerWidth == null) {
218
229
  return;
@@ -283,8 +294,8 @@ export const useGridVirtualScroller = props => {
283
294
  minFirstColumn = renderZoneMinColumnIndex,
284
295
  maxLastColumn = renderZoneMaxColumnIndex,
285
296
  availableSpace = containerWidth,
286
- ignoreAutoHeight,
287
- rowIndexOffset = 0
297
+ rowIndexOffset = 0,
298
+ position = 'center'
288
299
  } = params;
289
300
 
290
301
  if (!nextRenderContext || availableSpace == null) {
@@ -352,7 +363,7 @@ export const useGridVirtualScroller = props => {
352
363
  model
353
364
  } = renderedRows[i];
354
365
  const lastVisibleRowIndex = firstRowToRender + i === currentPage.rows.length - 1;
355
- const baseRowHeight = !apiRef.current.unstable_rowHasAutoHeight(id) || ignoreAutoHeight ? apiRef.current.unstable_getRowHeight(id) : 'auto';
366
+ const baseRowHeight = !apiRef.current.unstable_rowHasAutoHeight(id) ? apiRef.current.unstable_getRowHeight(id) : 'auto';
356
367
  let isSelected;
357
368
 
358
369
  if (selectedRowsLookup[id] == null) {
@@ -378,7 +389,8 @@ export const useGridVirtualScroller = props => {
378
389
  selected: isSelected,
379
390
  index: rowIndexOffset + (currentPage?.range?.firstRowIndex || 0) + firstRowToRender + i,
380
391
  containerWidth: availableSpace,
381
- isLastVisible: lastVisibleRowIndex
392
+ isLastVisible: lastVisibleRowIndex,
393
+ position: position
382
394
  }, typeof getRowProps === 'function' ? getRowProps(id, model) : {}, rootProps.componentsProps?.row), id));
383
395
  }
384
396
 
package/modern/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license MUI v5.16.0
1
+ /** @license MUI v5.17.2
2
2
  *
3
3
  * This source code is licensed under the MIT license found in the
4
4
  * LICENSE file in the root directory of this source tree.
@@ -38,7 +38,7 @@ export { useGridScroll } from '../hooks/features/scroll/useGridScroll';
38
38
  export { useGridEvents } from '../hooks/features/events/useGridEvents';
39
39
  export { useGridDimensions } from '../hooks/features/dimensions/useGridDimensions';
40
40
  export { useGridStatePersistence } from '../hooks/features/statePersistence/useGridStatePersistence';
41
- export { useGridVirtualScroller } from '../hooks/features/virtualization/useGridVirtualScroller';
41
+ export { useGridVirtualScroller, getRenderableIndexes } from '../hooks/features/virtualization/useGridVirtualScroller';
42
42
  export { useGridVisibleRows } from '../hooks/utils/useGridVisibleRows';
43
43
  export { useGridInitializeState } from '../hooks/utils/useGridInitializeState';
44
44
  export { getColumnsToExport, defaultGetRowsToExport } from '../hooks/features/export/utils';
@@ -85,6 +85,8 @@ var GridEvents;
85
85
  GridEvents["preferencePanelOpen"] = "preferencePanelOpen";
86
86
  GridEvents["menuOpen"] = "menuOpen";
87
87
  GridEvents["menuClose"] = "menuClose";
88
+ GridEvents["renderedRowsIntervalChange"] = "renderedRowsIntervalChange";
89
+ GridEvents["fetchRows"] = "fetchRows";
88
90
  })(GridEvents || (GridEvents = {}));
89
91
 
90
92
  export { GridEvents };
@@ -11,4 +11,5 @@ export * from './gridValueOptionsParams';
11
11
  export * from './gridCellParams';
12
12
  export * from './gridSortModelParams';
13
13
  export * from './gridPreferencePanelParams';
14
- export * from './gridMenuParams';
14
+ export * from './gridMenuParams';
15
+ export * from './gridRenderedRowsIntervalChangeParams';
@@ -177,4 +177,27 @@ export function isDeepEqual(a, b) {
177
177
 
178
178
 
179
179
  return a !== a && b !== b;
180
+ } // Pseudo random number. See https://stackoverflow.com/a/47593316
181
+
182
+ function mulberry32(a) {
183
+ return () => {
184
+ /* eslint-disable */
185
+ let t = a += 0x6d2b79f5;
186
+ t = Math.imul(t ^ t >>> 15, t | 1);
187
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
188
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
189
+ /* eslint-enable */
190
+ };
191
+ }
192
+
193
+ export function randomNumberBetween(seed, min, max) {
194
+ const random = mulberry32(seed);
195
+ return () => min + (max - min) * random();
196
+ }
197
+ export function deepClone(obj) {
198
+ if (typeof structuredClone === 'function') {
199
+ return structuredClone(obj);
200
+ }
201
+
202
+ return JSON.parse(JSON.stringify(obj));
180
203
  }