@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
@@ -31,6 +31,8 @@ var _warning = require("../../../utils/warning");
31
31
 
32
32
  var _gridRowsSelector = require("../rows/gridRowsSelector");
33
33
 
34
+ var _utils = require("../../../utils/utils");
35
+
34
36
  var _gridRowParams = require("../../../models/params/gridRowParams");
35
37
 
36
38
  const _excluded = ["id"],
@@ -421,7 +423,11 @@ const useGridRowEditing = (apiRef, props) => {
421
423
  const hasSomeFieldWithError = Object.values(editingState[id]).some(fieldProps => fieldProps.error);
422
424
 
423
425
  if (hasSomeFieldWithError) {
424
- prevRowModesModel.current[id].mode = _gridEditRowModel.GridRowModes.Edit;
426
+ prevRowModesModel.current[id].mode = _gridEditRowModel.GridRowModes.Edit; // Revert the mode in the rowModesModel prop back to "edit"
427
+
428
+ updateRowInRowModesModel(id, {
429
+ mode: _gridEditRowModel.GridRowModes.Edit
430
+ });
425
431
  return;
426
432
  }
427
433
 
@@ -597,7 +603,8 @@ const useGridRowEditing = (apiRef, props) => {
597
603
  const idToIdLookup = (0, _gridRowsSelector.gridRowsIdToIdLookupSelector)(apiRef); // Update the ref here because updateStateToStopRowEditMode may change it later
598
604
 
599
605
  const copyOfPrevRowModesModel = prevRowModesModel.current;
600
- prevRowModesModel.current = rowModesModel;
606
+ prevRowModesModel.current = (0, _utils.deepClone)(rowModesModel); // Do a deep-clone because the attributes might be changed later
607
+
601
608
  Object.entries(rowModesModel).forEach(([id, params]) => {
602
609
  var _copyOfPrevRowModesMo, _idToIdLookup$id;
603
610
 
@@ -88,76 +88,75 @@ exports.sanitizeFilterModel = sanitizeFilterModel;
88
88
  const mergeStateWithFilterModel = (filterModel, disableMultipleColumnsFiltering, apiRef) => filteringState => (0, _extends2.default)({}, filteringState, {
89
89
  filterModel: sanitizeFilterModel(filterModel, disableMultipleColumnsFiltering, apiRef)
90
90
  });
91
- /**
92
- * Generates a method to easily check if a row is matching the current filter model.
93
- * @param {GridFilterModel} filterModel The model with which we want to filter the rows.
94
- * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
95
- * @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.
96
- */
97
-
98
91
 
99
92
  exports.mergeStateWithFilterModel = mergeStateWithFilterModel;
100
93
 
101
- const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
102
- const {
103
- items
104
- } = filterModel;
105
-
106
- const getFilterCallbackFromItem = filterItem => {
107
- if (!filterItem.columnField || !filterItem.operatorValue) {
108
- return null;
109
- }
94
+ const getFilterCallbackFromItem = (filterItem, apiRef) => {
95
+ if (!filterItem.columnField || !filterItem.operatorValue) {
96
+ return null;
97
+ }
110
98
 
111
- const column = apiRef.current.getColumn(filterItem.columnField);
99
+ const column = apiRef.current.getColumn(filterItem.columnField);
112
100
 
113
- if (!column) {
114
- return null;
115
- }
101
+ if (!column) {
102
+ return null;
103
+ }
116
104
 
117
- let parsedValue;
105
+ let parsedValue;
118
106
 
119
- if (column.valueParser) {
120
- var _filterItem$value;
107
+ if (column.valueParser) {
108
+ var _filterItem$value;
121
109
 
122
- const parser = column.valueParser;
123
- parsedValue = Array.isArray(filterItem.value) ? (_filterItem$value = filterItem.value) == null ? void 0 : _filterItem$value.map(x => parser(x)) : parser(filterItem.value);
124
- } else {
125
- parsedValue = filterItem.value;
126
- }
110
+ const parser = column.valueParser;
111
+ parsedValue = Array.isArray(filterItem.value) ? (_filterItem$value = filterItem.value) == null ? void 0 : _filterItem$value.map(x => parser(x)) : parser(filterItem.value);
112
+ } else {
113
+ parsedValue = filterItem.value;
114
+ }
127
115
 
128
- const newFilterItem = (0, _extends2.default)({}, filterItem, {
129
- value: parsedValue
130
- });
131
- const filterOperators = column.filterOperators;
116
+ const newFilterItem = (0, _extends2.default)({}, filterItem, {
117
+ value: parsedValue
118
+ });
119
+ const filterOperators = column.filterOperators;
132
120
 
133
- if (!(filterOperators != null && filterOperators.length)) {
134
- throw new Error(`MUI: No filter operators found for column '${column.field}'.`);
135
- }
121
+ if (!(filterOperators != null && filterOperators.length)) {
122
+ throw new Error(`MUI: No filter operators found for column '${column.field}'.`);
123
+ }
136
124
 
137
- const filterOperator = filterOperators.find(operator => operator.value === newFilterItem.operatorValue);
125
+ const filterOperator = filterOperators.find(operator => operator.value === newFilterItem.operatorValue);
138
126
 
139
- if (!filterOperator) {
140
- throw new Error(`MUI: No filter operator found for column '${column.field}' and operator value '${newFilterItem.operatorValue}'.`);
141
- }
127
+ if (!filterOperator) {
128
+ throw new Error(`MUI: No filter operator found for column '${column.field}' and operator value '${newFilterItem.operatorValue}'.`);
129
+ }
142
130
 
143
- const applyFilterOnRow = filterOperator.getApplyFilterFn(newFilterItem, column);
131
+ const applyFilterOnRow = filterOperator.getApplyFilterFn(newFilterItem, column);
144
132
 
145
- if (typeof applyFilterOnRow !== 'function') {
146
- return null;
147
- }
133
+ if (typeof applyFilterOnRow !== 'function') {
134
+ return null;
135
+ }
148
136
 
149
- const fn = rowId => {
150
- const cellParams = apiRef.current.getCellParams(rowId, newFilterItem.columnField);
151
- return applyFilterOnRow(cellParams);
152
- };
137
+ const fn = rowId => {
138
+ const cellParams = apiRef.current.getCellParams(rowId, newFilterItem.columnField);
139
+ return applyFilterOnRow(cellParams);
140
+ };
153
141
 
154
- return {
155
- fn,
156
- item: newFilterItem
157
- };
142
+ return {
143
+ fn,
144
+ item: newFilterItem
158
145
  };
146
+ };
147
+ /**
148
+ * Generates a method to easily check if a row is matching the current filter model.
149
+ * @param {GridFilterModel} filterModel The model with which we want to filter the rows.
150
+ * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
151
+ * @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.
152
+ */
159
153
 
160
- const appliers = items.map(getFilterCallbackFromItem).filter(callback => !!callback);
154
+
155
+ const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
156
+ const {
157
+ items
158
+ } = filterModel;
159
+ const appliers = items.map(item => getFilterCallbackFromItem(item, apiRef)).filter(callback => !!callback);
161
160
 
162
161
  if (appliers.length === 0) {
163
162
  return null;
@@ -249,9 +248,10 @@ const buildAggregatedFilterApplier = (filterModel, apiRef) => {
249
248
 
250
249
  exports.buildAggregatedFilterApplier = buildAggregatedFilterApplier;
251
250
 
252
- const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel) => {
251
+ const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel, apiRef) => {
253
252
  var _filterModel$quickFil, _filterModel$linkOper;
254
253
 
254
+ const cleanedFilterItems = filterModel.items.filter(item => getFilterCallbackFromItem(item, apiRef) !== null);
255
255
  const cleanedAllFilterItemResults = allFilterItemResults.filter(result => result != null);
256
256
  const cleanedAllQuickFilterResults = allQuickFilterResults.filter(result => result != null); // Defaultize operators
257
257
 
@@ -265,13 +265,13 @@ const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterMode
265
265
  };
266
266
 
267
267
  if (linkOperator === _models.GridLinkOperator.And) {
268
- const passesAllFilters = filterModel.items.every(filterItemPredicate);
268
+ const passesAllFilters = cleanedFilterItems.every(filterItemPredicate);
269
269
 
270
270
  if (!passesAllFilters) {
271
271
  return false;
272
272
  }
273
273
  } else {
274
- const passesSomeFilters = filterModel.items.some(filterItemPredicate);
274
+ const passesSomeFilters = cleanedFilterItems.some(filterItemPredicate);
275
275
 
276
276
  if (!passesSomeFilters) {
277
277
  return false;
@@ -304,7 +304,7 @@ const useGridFilter = (apiRef, props) => {
304
304
  passingFilterItems,
305
305
  passingQuickFilterValues
306
306
  } = params.isRowMatchingFilters(rowId);
307
- isRowPassing = (0, _gridFilterUtils.passFilterLogic)([passingFilterItems], [passingQuickFilterValues], params.filterModel);
307
+ isRowPassing = (0, _gridFilterUtils.passFilterLogic)([passingFilterItems], [passingQuickFilterValues], params.filterModel, apiRef);
308
308
  }
309
309
 
310
310
  filteredRowsLookup[rowId] = isRowPassing;
@@ -158,8 +158,18 @@ const useGridFocus = (apiRef, props) => {
158
158
  }
159
159
 
160
160
  rowIndexToFocus = (0, _utils2.clamp)(rowIndexToFocus, 0, currentPage.rows.length - 1);
161
- columnIndexToFocus = (0, _utils2.clamp)(columnIndexToFocus, 0, visibleColumns.length - 1);
162
161
  const rowToFocus = currentPage.rows[rowIndexToFocus];
162
+ const colSpanInfo = apiRef.current.unstable_getCellColSpanInfo(rowToFocus.id, columnIndexToFocus);
163
+
164
+ if (colSpanInfo && colSpanInfo.spannedByColSpan) {
165
+ if (direction === 'left' || direction === 'below') {
166
+ columnIndexToFocus = colSpanInfo.leftVisibleCellIndex;
167
+ } else if (direction === 'right') {
168
+ columnIndexToFocus = colSpanInfo.rightVisibleCellIndex;
169
+ }
170
+ }
171
+
172
+ columnIndexToFocus = (0, _utils2.clamp)(columnIndexToFocus, 0, visibleColumns.length - 1);
163
173
  const columnToFocus = visibleColumns[columnIndexToFocus];
164
174
  apiRef.current.setCellFocus(rowToFocus.id, columnToFocus.field);
165
175
  }, [apiRef, props.pagination, props.paginationMode]);
@@ -195,7 +205,7 @@ const useGridFocus = (apiRef, props) => {
195
205
  }
196
206
  }));
197
207
  }, [logger, apiRef]);
198
- const handleCellMouseUp = React.useCallback(params => {
208
+ const handleCellMouseDown = React.useCallback(params => {
199
209
  lastClickedCell.current = params;
200
210
  }, []);
201
211
  const handleDocumentClick = React.useCallback(event => {
@@ -278,7 +288,7 @@ const useGridFocus = (apiRef, props) => {
278
288
  }, [apiRef, handleDocumentClick]);
279
289
  (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'columnHeaderBlur', handleBlur);
280
290
  (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellDoubleClick', handleCellDoubleClick);
281
- (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellMouseUp', handleCellMouseUp);
291
+ (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellMouseDown', handleCellMouseDown);
282
292
  (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellKeyDown', handleCellKeyDown);
283
293
  (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'cellModeChange', handleCellModeChange);
284
294
  (0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'columnHeaderFocus', handleColumnHeaderFocus);
@@ -56,6 +56,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
56
56
  * @param {number} colIndex Index of the column to focus
57
57
  * @param {number} rowIndex index of the row to focus
58
58
  * @param {string} closestColumnToUse Which closest column cell to use when the cell is spanned by `colSpan`.
59
+ * TODO replace with apiRef.current.unstable_moveFocusToRelativeCell()
59
60
  */
60
61
 
61
62
  const goToCell = React.useCallback((colIndex, rowId, closestColumnToUse = 'left') => {
@@ -112,6 +113,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
112
113
  case 'ArrowDown':
113
114
  case 'Enter':
114
115
  {
116
+ // TODO v6: Remove Enter case because `cellNavigationKeyDown` is not fired by the new editing API
115
117
  // "Enter" is only triggered by the row / cell editing feature
116
118
  if (rowIndexBefore < lastRowIndexInPage) {
117
119
  goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore + 1));
@@ -121,7 +121,7 @@ function useGridParamsApi(apiRef) {
121
121
  formattedValue: value
122
122
  };
123
123
 
124
- if (colDef.valueFormatter) {
124
+ if (colDef && colDef.valueFormatter) {
125
125
  params.formattedValue = colDef.valueFormatter({
126
126
  id,
127
127
  field: params.field,
@@ -131,14 +131,14 @@ const useGridRows = (apiRef, props) => {
131
131
  } // we remove duplicate updates. A server can batch updates, and send several updates for the same row in one fn call.
132
132
 
133
133
 
134
- const uniqUpdates = new Map();
134
+ const uniqueUpdates = new Map();
135
135
  updates.forEach(update => {
136
136
  const id = (0, _gridRowsUtils.getRowIdFromRowModel)(update, props.getRowId, 'A row was provided without id when calling updateRows():');
137
137
 
138
- if (uniqUpdates.has(id)) {
139
- uniqUpdates.set(id, (0, _extends2.default)({}, uniqUpdates.get(id), update));
138
+ if (uniqueUpdates.has(id)) {
139
+ uniqueUpdates.set(id, (0, _extends2.default)({}, uniqueUpdates.get(id), update));
140
140
  } else {
141
- uniqUpdates.set(id, update);
141
+ uniqueUpdates.set(id, update);
142
142
  }
143
143
  });
144
144
  const deletedRowIds = [];
@@ -150,7 +150,7 @@ const useGridRows = (apiRef, props) => {
150
150
  idToIdLookup: (0, _extends2.default)({}, prevCache.idToIdLookup),
151
151
  ids: [...prevCache.ids]
152
152
  };
153
- uniqUpdates.forEach((partialRow, id) => {
153
+ uniqueUpdates.forEach((partialRow, id) => {
154
154
  // eslint-disable-next-line no-underscore-dangle
155
155
  if (partialRow._action === 'delete') {
156
156
  delete newCache.idRowsLookup[id];
@@ -267,8 +267,60 @@ const useGridRows = (apiRef, props) => {
267
267
  ids: updatedRows
268
268
  })
269
269
  }));
270
- apiRef.current.applySorting();
270
+ apiRef.current.publishEvent('rowsSet');
271
271
  }, [apiRef, logger]);
272
+ const replaceRows = React.useCallback((firstRowToRender, newRows) => {
273
+ if (props.signature === _useGridApiEventHandler.GridSignature.DataGrid && newRows.length > 1) {
274
+ 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'));
275
+ }
276
+
277
+ if (newRows.length === 0) {
278
+ return;
279
+ }
280
+
281
+ const allRows = (0, _gridRowsSelector.gridRowIdsSelector)(apiRef);
282
+ const updatedRows = [...allRows];
283
+ const idRowsLookup = (0, _gridRowsSelector.gridRowsLookupSelector)(apiRef);
284
+ const idToIdLookup = (0, _gridRowsSelector.gridRowsIdToIdLookupSelector)(apiRef);
285
+ const tree = (0, _gridRowsSelector.gridRowTreeSelector)(apiRef);
286
+ const updatedIdRowsLookup = (0, _extends2.default)({}, idRowsLookup);
287
+ const updatedIdToIdLookup = (0, _extends2.default)({}, idToIdLookup);
288
+ const updatedTree = (0, _extends2.default)({}, tree);
289
+ const newRowEntries = newRows.map(newRowModel => {
290
+ const rowId = (0, _gridRowsUtils.getRowIdFromRowModel)(newRowModel, props.getRowId, 'A row was provided without id when calling replaceRows().');
291
+ return {
292
+ id: rowId,
293
+ model: newRowModel
294
+ };
295
+ });
296
+ newRowEntries.forEach((row, index) => {
297
+ const [replacedRowId] = updatedRows.splice(firstRowToRender + index, 1, row.id);
298
+ delete updatedIdRowsLookup[replacedRowId];
299
+ delete updatedIdToIdLookup[replacedRowId];
300
+ delete updatedTree[replacedRowId];
301
+ });
302
+ newRowEntries.forEach(row => {
303
+ const rowTreeNodeConfig = {
304
+ id: row.id,
305
+ parent: null,
306
+ depth: 0,
307
+ groupingKey: null,
308
+ groupingField: null
309
+ };
310
+ updatedIdRowsLookup[row.id] = row.model;
311
+ updatedIdToIdLookup[row.id] = row.id;
312
+ updatedTree[row.id] = rowTreeNodeConfig;
313
+ });
314
+ apiRef.current.setState(state => (0, _extends2.default)({}, state, {
315
+ rows: (0, _extends2.default)({}, state.rows, {
316
+ idRowsLookup: updatedIdRowsLookup,
317
+ idToIdLookup: updatedIdToIdLookup,
318
+ tree: updatedTree,
319
+ ids: updatedRows
320
+ })
321
+ }));
322
+ apiRef.current.publishEvent('rowsSet');
323
+ }, [apiRef, props.signature, props.getRowId]);
272
324
  const rowApi = {
273
325
  getRow,
274
326
  getRowModels,
@@ -280,7 +332,8 @@ const useGridRows = (apiRef, props) => {
280
332
  setRowChildrenExpansion,
281
333
  getRowNode,
282
334
  getRowIndexRelativeToVisibleRows,
283
- getRowGroupChildren
335
+ getRowGroupChildren,
336
+ unstable_replaceRows: replaceRows
284
337
  };
285
338
  /**
286
339
  * EVENTS
@@ -75,7 +75,7 @@ const useGridRowsMeta = (apiRef, props) => {
75
75
  if (!rowsHeightLookup.current[row.id]) {
76
76
  rowsHeightLookup.current[row.id] = {
77
77
  sizes: {
78
- base: rowHeightFromDensity
78
+ baseCenter: rowHeightFromDensity
79
79
  },
80
80
  isResized: false,
81
81
  autoHeight: false,
@@ -90,7 +90,7 @@ const useGridRowsMeta = (apiRef, props) => {
90
90
  sizes
91
91
  } = rowsHeightLookup.current[row.id];
92
92
  let baseRowHeight = rowHeightFromDensity;
93
- const existingBaseRowHeight = sizes.base;
93
+ const existingBaseRowHeight = sizes.baseCenter;
94
94
 
95
95
  if (isResized) {
96
96
  // Do not recalculate resized row height and use the value from the lookup
@@ -121,12 +121,19 @@ const useGridRowsMeta = (apiRef, props) => {
121
121
  }
122
122
  } else {
123
123
  rowsHeightLookup.current[row.id].needsFirstMeasurement = false;
124
- } // We use an object to make simple to check if a height is already added or not
124
+ }
125
125
 
126
+ const existingBaseSizes = Object.entries(sizes).reduce((acc, [key, size]) => {
127
+ if (/^base[A-Z]/.test(key)) {
128
+ acc[key] = size;
129
+ }
126
130
 
127
- const initialHeights = {
128
- base: baseRowHeight
129
- };
131
+ return acc;
132
+ }, {}); // We use an object to make simple to check if a height is already added or not
133
+
134
+ const initialHeights = (0, _extends2.default)({}, existingBaseSizes, {
135
+ baseCenter: baseRowHeight
136
+ });
130
137
 
131
138
  if (getRowSpacing) {
132
139
  var _spacing$top, _spacing$bottom;
@@ -149,9 +156,17 @@ const useGridRowsMeta = (apiRef, props) => {
149
156
  const positions = [];
150
157
  const currentPageTotalHeight = currentPage.rows.reduce((acc, row) => {
151
158
  positions.push(acc);
159
+ let maximumBaseSize = 0;
160
+ let otherSizes = 0;
152
161
  const processedSizes = calculateRowProcessedSizes(row);
153
- const finalRowHeight = Object.values(processedSizes).reduce((acc2, value) => acc2 + value, 0);
154
- return acc + finalRowHeight;
162
+ Object.entries(processedSizes).forEach(([size, value]) => {
163
+ if (/^base[A-Z]/.test(size)) {
164
+ maximumBaseSize = value > maximumBaseSize ? value : maximumBaseSize;
165
+ } else {
166
+ otherSizes += value;
167
+ }
168
+ });
169
+ return acc + maximumBaseSize + otherSizes;
155
170
  }, 0);
156
171
  pinnedRows == null ? void 0 : (_pinnedRows$top = pinnedRows.top) == null ? void 0 : _pinnedRows$top.forEach(row => {
157
172
  calculateRowProcessedSizes(row);
@@ -177,7 +192,7 @@ const useGridRowsMeta = (apiRef, props) => {
177
192
  }, [apiRef, currentPage.rows, rowHeightFromDensity, getRowHeightProp, getRowSpacing, getEstimatedRowHeight, pinnedRows]);
178
193
  const getRowHeight = React.useCallback(rowId => {
179
194
  const height = rowsHeightLookup.current[rowId];
180
- return height ? height.sizes.base : rowHeightFromDensity;
195
+ return height ? height.sizes.baseCenter : rowHeightFromDensity;
181
196
  }, [rowHeightFromDensity]);
182
197
 
183
198
  const getRowInternalSizes = rowId => {
@@ -187,21 +202,21 @@ const useGridRowsMeta = (apiRef, props) => {
187
202
  };
188
203
 
189
204
  const setRowHeight = React.useCallback((id, height) => {
190
- rowsHeightLookup.current[id].sizes.base = height;
205
+ rowsHeightLookup.current[id].sizes.baseCenter = height;
191
206
  rowsHeightLookup.current[id].isResized = true;
192
207
  rowsHeightLookup.current[id].needsFirstMeasurement = false;
193
208
  hydrateRowsMeta();
194
209
  }, [hydrateRowsMeta]);
195
210
  const debouncedHydrateRowsMeta = React.useMemo(() => (0, _utils.debounce)(hydrateRowsMeta), [hydrateRowsMeta]);
196
- const storeMeasuredRowHeight = React.useCallback((id, height) => {
211
+ const storeMeasuredRowHeight = React.useCallback((id, height, position) => {
197
212
  if (!rowsHeightLookup.current[id] || !rowsHeightLookup.current[id].autoHeight) {
198
213
  return;
199
214
  } // Only trigger hydration if the value is different, otherwise we trigger a loop
200
215
 
201
216
 
202
- const needsHydration = rowsHeightLookup.current[id].sizes.base !== height;
217
+ const needsHydration = rowsHeightLookup.current[id].sizes[`base${(0, _utils.capitalize)(position)}`] !== height;
203
218
  rowsHeightLookup.current[id].needsFirstMeasurement = false;
204
- rowsHeightLookup.current[id].sizes.base = height;
219
+ rowsHeightLookup.current[id].sizes[`base${(0, _utils.capitalize)(position)}`] = height;
205
220
 
206
221
  if (needsHydration) {
207
222
  debouncedHydrateRowsMeta();
@@ -219,7 +234,11 @@ const useGridRowsMeta = (apiRef, props) => {
219
234
  if (hasRowWithAutoHeight.current && index > lastMeasuredRowIndex.current) {
220
235
  lastMeasuredRowIndex.current = index;
221
236
  }
222
- }, []); // The effect is used to build the rows meta data - currentPageTotalHeight and positions.
237
+ }, []);
238
+ const resetRowHeights = React.useCallback(() => {
239
+ rowsHeightLookup.current = {};
240
+ hydrateRowsMeta();
241
+ }, [hydrateRowsMeta]); // The effect is used to build the rows meta data - currentPageTotalHeight and positions.
223
242
  // Because of variable row height this is needed for the virtualization
224
243
 
225
244
  React.useEffect(() => {
@@ -233,7 +252,8 @@ const useGridRowsMeta = (apiRef, props) => {
233
252
  unstable_getRowHeight: getRowHeight,
234
253
  unstable_getRowInternalSizes: getRowInternalSizes,
235
254
  unstable_setRowHeight: setRowHeight,
236
- unstable_storeRowHeightMeasurement: storeMeasuredRowHeight
255
+ unstable_storeRowHeightMeasurement: storeMeasuredRowHeight,
256
+ resetRowHeights
237
257
  };
238
258
  (0, _useGridApiMethod.useGridApiMethod)(apiRef, rowsMetaApi, 'GridRowsMetaApi');
239
259
  };
@@ -252,8 +252,19 @@ const useGridVirtualScroller = props => {
252
252
  }, [renderContext, updateRenderZonePosition]);
253
253
  const updateRenderContext = React.useCallback(nextRenderContext => {
254
254
  setRenderContext(nextRenderContext);
255
+ const [firstRowToRender, lastRowToRender] = getRenderableIndexes({
256
+ firstIndex: nextRenderContext.firstRowIndex,
257
+ lastIndex: nextRenderContext.lastRowIndex,
258
+ minFirstIndex: 0,
259
+ maxLastIndex: currentPage.rows.length,
260
+ buffer: rootProps.rowBuffer
261
+ });
262
+ apiRef.current.publishEvent('renderedRowsIntervalChange', {
263
+ firstRowToRender,
264
+ lastRowToRender
265
+ });
255
266
  prevRenderContext.current = nextRenderContext;
256
- }, [setRenderContext, prevRenderContext]);
267
+ }, [apiRef, setRenderContext, prevRenderContext, currentPage.rows.length, rootProps.rowBuffer]);
257
268
  React.useEffect(() => {
258
269
  if (containerWidth == null) {
259
270
  return;
@@ -324,8 +335,8 @@ const useGridVirtualScroller = props => {
324
335
  minFirstColumn = renderZoneMinColumnIndex,
325
336
  maxLastColumn = renderZoneMaxColumnIndex,
326
337
  availableSpace = containerWidth,
327
- ignoreAutoHeight,
328
- rowIndexOffset = 0
338
+ rowIndexOffset = 0,
339
+ position = 'center'
329
340
  } = params;
330
341
 
331
342
  if (!nextRenderContext || availableSpace == null) {
@@ -395,7 +406,7 @@ const useGridVirtualScroller = props => {
395
406
  model
396
407
  } = renderedRows[i];
397
408
  const lastVisibleRowIndex = firstRowToRender + i === currentPage.rows.length - 1;
398
- const baseRowHeight = !apiRef.current.unstable_rowHasAutoHeight(id) || ignoreAutoHeight ? apiRef.current.unstable_getRowHeight(id) : 'auto';
409
+ const baseRowHeight = !apiRef.current.unstable_rowHasAutoHeight(id) ? apiRef.current.unstable_getRowHeight(id) : 'auto';
399
410
  let isSelected;
400
411
 
401
412
  if (selectedRowsLookup[id] == null) {
@@ -421,7 +432,8 @@ const useGridVirtualScroller = props => {
421
432
  selected: isSelected,
422
433
  index: rowIndexOffset + ((currentPage == null ? void 0 : (_currentPage$range5 = currentPage.range) == null ? void 0 : _currentPage$range5.firstRowIndex) || 0) + firstRowToRender + i,
423
434
  containerWidth: availableSpace,
424
- isLastVisible: lastVisibleRowIndex
435
+ isLastVisible: lastVisibleRowIndex,
436
+ position: position
425
437
  }, typeof getRowProps === 'function' ? getRowProps(id, model) : {}, (_rootProps$components = rootProps.componentsProps) == null ? void 0 : _rootProps$components.row), id));
426
438
  }
427
439
 
package/node/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.
@@ -135,6 +135,12 @@ Object.defineProperty(exports, "getColumnsToExport", {
135
135
  return _utils.getColumnsToExport;
136
136
  }
137
137
  });
138
+ Object.defineProperty(exports, "getRenderableIndexes", {
139
+ enumerable: true,
140
+ get: function () {
141
+ return _useGridVirtualScroller.getRenderableIndexes;
142
+ }
143
+ });
138
144
  Object.defineProperty(exports, "getRowIdFromRowModel", {
139
145
  enumerable: true,
140
146
  get: function () {
@@ -92,4 +92,6 @@ exports.GridEvents = GridEvents;
92
92
  GridEvents["preferencePanelOpen"] = "preferencePanelOpen";
93
93
  GridEvents["menuOpen"] = "menuOpen";
94
94
  GridEvents["menuClose"] = "menuClose";
95
+ GridEvents["renderedRowsIntervalChange"] = "renderedRowsIntervalChange";
96
+ GridEvents["fetchRows"] = "fetchRows";
95
97
  })(GridEvents || (exports.GridEvents = GridEvents = {}));
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -184,4 +184,17 @@ Object.keys(_gridMenuParams).forEach(function (key) {
184
184
  return _gridMenuParams[key];
185
185
  }
186
186
  });
187
+ });
188
+
189
+ var _gridRenderedRowsIntervalChangeParams = require("./gridRenderedRowsIntervalChangeParams");
190
+
191
+ Object.keys(_gridRenderedRowsIntervalChangeParams).forEach(function (key) {
192
+ if (key === "default" || key === "__esModule") return;
193
+ if (key in exports && exports[key] === _gridRenderedRowsIntervalChangeParams[key]) return;
194
+ Object.defineProperty(exports, key, {
195
+ enumerable: true,
196
+ get: function () {
197
+ return _gridRenderedRowsIntervalChangeParams[key];
198
+ }
199
+ });
187
200
  });
@@ -4,12 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.clamp = void 0;
7
+ exports.deepClone = deepClone;
7
8
  exports.escapeRegExp = escapeRegExp;
8
9
  exports.isDeepEqual = isDeepEqual;
9
10
  exports.isFunction = isFunction;
10
11
  exports.isNumber = isNumber;
11
12
  exports.isObject = isObject;
12
13
  exports.localStorageAvailable = localStorageAvailable;
14
+ exports.randomNumberBetween = randomNumberBetween;
13
15
 
14
16
  function isNumber(value) {
15
17
  return typeof value === 'number';
@@ -198,4 +200,29 @@ function isDeepEqual(a, b) {
198
200
 
199
201
 
200
202
  return a !== a && b !== b;
203
+ } // Pseudo random number. See https://stackoverflow.com/a/47593316
204
+
205
+
206
+ function mulberry32(a) {
207
+ return () => {
208
+ /* eslint-disable */
209
+ let t = a += 0x6d2b79f5;
210
+ t = Math.imul(t ^ t >>> 15, t | 1);
211
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
212
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
213
+ /* eslint-enable */
214
+ };
215
+ }
216
+
217
+ function randomNumberBetween(seed, min, max) {
218
+ const random = mulberry32(seed);
219
+ return () => min + (max - min) * random();
220
+ }
221
+
222
+ function deepClone(obj) {
223
+ if (typeof structuredClone === 'function') {
224
+ return structuredClone(obj);
225
+ }
226
+
227
+ return JSON.parse(JSON.stringify(obj));
201
228
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-data-grid",
3
- "version": "5.16.0",
3
+ "version": "5.17.2",
4
4
  "description": "The community edition of the data grid component (MUI X).",
5
5
  "author": "MUI Team",
6
6
  "main": "./node/index.js",
package/utils/utils.d.ts CHANGED
@@ -35,3 +35,5 @@ export declare const clamp: (value: number, min: number, max: number) => number;
35
35
  * We only type the public interface to avoid dozens of `as` in the function.
36
36
  */
37
37
  export declare function isDeepEqual<T>(actual: any, expected: T): actual is T;
38
+ export declare function randomNumberBetween(seed: number, min: number, max: number): () => number;
39
+ export declare function deepClone(obj: Record<string, any>): any;