@mui/x-data-grid 5.15.1 → 5.15.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 (43) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/DataGrid/DataGrid.js +1 -1
  3. package/hooks/features/editRows/useGridCellEditing.new.js +15 -7
  4. package/hooks/features/editRows/useGridRowEditing.new.js +9 -2
  5. package/hooks/features/filter/gridFilterState.d.ts +12 -1
  6. package/hooks/features/filter/gridFilterUtils.d.ts +8 -5
  7. package/hooks/features/filter/gridFilterUtils.js +74 -43
  8. package/hooks/features/filter/useGridFilter.js +16 -3
  9. package/hooks/features/focus/useGridFocus.js +11 -6
  10. package/hooks/features/rows/useGridRows.js +5 -2
  11. package/hooks/features/statePersistence/gridStatePersistenceInterface.d.ts +3 -0
  12. package/index.js +1 -1
  13. package/internals/index.d.ts +1 -0
  14. package/internals/index.js +1 -0
  15. package/legacy/DataGrid/DataGrid.js +1 -1
  16. package/legacy/hooks/features/editRows/useGridCellEditing.new.js +16 -8
  17. package/legacy/hooks/features/editRows/useGridRowEditing.new.js +9 -2
  18. package/legacy/hooks/features/filter/gridFilterUtils.js +84 -55
  19. package/legacy/hooks/features/filter/useGridFilter.js +16 -3
  20. package/legacy/hooks/features/focus/useGridFocus.js +11 -6
  21. package/legacy/hooks/features/rows/useGridRows.js +5 -2
  22. package/legacy/index.js +1 -1
  23. package/legacy/internals/index.js +1 -0
  24. package/models/props/DataGridProps.d.ts +3 -3
  25. package/modern/DataGrid/DataGrid.js +1 -1
  26. package/modern/hooks/features/editRows/useGridCellEditing.new.js +15 -7
  27. package/modern/hooks/features/editRows/useGridRowEditing.new.js +9 -2
  28. package/modern/hooks/features/filter/gridFilterUtils.js +73 -42
  29. package/modern/hooks/features/filter/useGridFilter.js +16 -3
  30. package/modern/hooks/features/focus/useGridFocus.js +11 -6
  31. package/modern/hooks/features/rows/useGridRows.js +5 -2
  32. package/modern/index.js +1 -1
  33. package/modern/internals/index.js +1 -0
  34. package/node/DataGrid/DataGrid.js +1 -1
  35. package/node/hooks/features/editRows/useGridCellEditing.new.js +15 -7
  36. package/node/hooks/features/editRows/useGridRowEditing.new.js +9 -2
  37. package/node/hooks/features/filter/gridFilterUtils.js +81 -47
  38. package/node/hooks/features/filter/useGridFilter.js +15 -2
  39. package/node/hooks/features/focus/useGridFocus.js +11 -6
  40. package/node/hooks/features/rows/useGridRows.js +5 -2
  41. package/node/index.js +1 -1
  42. package/node/internals/index.js +8 -0
  43. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,50 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 5.15.2
7
+
8
+ _Aug 11, 2022_
9
+
10
+ We'd like to offer a big thanks to the 7 contributors who made this release possible. Here are some highlights ✨:
11
+
12
+ - ✨ Improve quick filtering with row grouping (#5701) @alexfauquette
13
+ - 📚 Documentation improvements
14
+ - 🐞 Bugfixes
15
+
16
+ ### `@mui/x-data-grid@5.15.2` / `@mui/x-data-grid-pro@5.15.2` / `@mui/x-data-grid-premium@5.15.2`
17
+
18
+ #### Changes
19
+
20
+ - [DataGrid] Catch errors if rows freezing is not supported (#5711) @cherniavskii
21
+ - [DataGrid] Preserve cell mode when entering edit mode while commiting (#5686) @m4theushw
22
+ - [DataGridPremium] Let quick filter search in row grouping children (#5701) @alexfauquette
23
+
24
+ ### `@mui/x-date-pickers@v5.0.0-beta.5` / `@mui/x-date-picker-pro@5.0.0-beta.5`
25
+
26
+ #### Changes
27
+
28
+ - [pickers] Add `react-dom` to peerDependencies (#5752) @cherniavskii
29
+ - [TimePicker] Set clock focus outline to `none` (#5758) @LukasTy
30
+ - [pickers] Fix theme augmentation with TypeScript (#5596) @alexfauquette
31
+ - [pickers] Reset input value when locale is modified (#5310) @alexfauquette
32
+ - [pickers] Support `disableHighlightToday` on `MonthPicker` and `YearPicker` (#5562) @flaviendelangle
33
+ - [pickers] Fallback to desktop mode when `matchMedia` is unavailable (#5684) @LukasTy
34
+ - [pickers] Trigger `onChange` when clearing or accepting `Invalid date` (#5740) @LukasTy
35
+
36
+ ### Docs
37
+
38
+ - [docs] Add RFC GH issue template (#5739) @bytasv
39
+ - [docs] Add description to the `GridExportStateParams` page (#5654) @oliviertassinari
40
+ - [docs] Improve the Events page (#5413) @flaviendelangle
41
+ - [docs] Use new editing API in the introduction demos (#5728) @oliviertassinari
42
+
43
+ ### Core
44
+
45
+ - [core] Remove duplicated `FUNDING.yml` file (#5656) @oliviertassinari
46
+ - [core] Remove outdated Next.js options (#5727) @oliviertassinari
47
+ - [core] Update tooling to run with React 18 (#4155) @m4theushw
48
+ - [test] Fix failing dynamic row height tests on Edge (#5707) @m4theushw
49
+
6
50
  ## 5.15.1
7
51
 
8
52
  _Aug 4, 2022_
@@ -645,7 +645,7 @@ DataGridRaw.propTypes = {
645
645
  * @param {GridState} state The new state.
646
646
  * @param {MuiEvent<{}>} event The event object.
647
647
  * @param {GridCallbackDetails} details Additional details for this callback.
648
- * @internal
648
+ * @ignore - do not document.
649
649
  */
650
650
  onStateChange: PropTypes.func,
651
651
 
@@ -15,6 +15,7 @@ import { GridCellEditStartReasons, GridCellEditStopReasons } from '../../../mode
15
15
  const missingOnProcessRowUpdateErrorWarning = buildWarning(['MUI: A call to `processRowUpdate` threw an error which was not handled because `onProcessRowUpdateError` is missing.', 'To handle the error pass a callback to the `onProcessRowUpdateError` prop, e.g. `<DataGrid onProcessRowUpdateError={(error) => ...} />`.', 'For more detail, see http://mui.com/components/data-grid/editing/#persistence.'], 'error');
16
16
  export const useGridCellEditing = (apiRef, props) => {
17
17
  const [cellModesModel, setCellModesModel] = React.useState({});
18
+ const cellModesModelRef = React.useRef(cellModesModel);
18
19
  const prevCellModesModel = React.useRef({});
19
20
  const {
20
21
  processRowUpdate,
@@ -62,6 +63,10 @@ export const useGridCellEditing = (apiRef, props) => {
62
63
  return;
63
64
  }
64
65
 
66
+ if (apiRef.current.getCellMode(params.id, params.field) === GridCellModes.View) {
67
+ return;
68
+ }
69
+
65
70
  const newParams = _extends({}, params, {
66
71
  reason: GridCellEditStopReasons.cellFocusOut
67
72
  });
@@ -194,18 +199,21 @@ export const useGridCellEditing = (apiRef, props) => {
194
199
  }
195
200
 
196
201
  setCellModesModel(newModel);
202
+ cellModesModelRef.current = newModel;
197
203
  apiRef.current.publishEvent('cellModesModelChange', newModel);
198
204
  }, [apiRef, onCellModesModelChange, props.cellModesModel, signature]);
199
205
  const updateFieldInCellModesModel = React.useCallback((id, field, newProps) => {
200
- const newModel = _extends({}, cellModesModel);
206
+ // We use the ref because it always contain the up-to-date value, different from the state
207
+ // that needs a rerender to reflect the new value
208
+ const newModel = _extends({}, cellModesModelRef.current);
201
209
 
202
210
  if (newProps !== null) {
203
211
  newModel[id] = _extends({}, newModel[id], {
204
212
  [field]: _extends({}, newProps)
205
213
  });
206
214
  } else {
207
- const _cellModesModel$id = cellModesModel[id],
208
- otherFields = _objectWithoutPropertiesLoose(_cellModesModel$id, [field].map(_toPropertyKey)); // Ensure that we have a new object, not a reference
215
+ const _newModel$id = newModel[id],
216
+ otherFields = _objectWithoutPropertiesLoose(_newModel$id, [field].map(_toPropertyKey)); // Ensure that we have a new object, not a reference
209
217
 
210
218
 
211
219
  newModel[id] = otherFields;
@@ -216,7 +224,7 @@ export const useGridCellEditing = (apiRef, props) => {
216
224
  }
217
225
 
218
226
  updateCellModesModel(newModel);
219
- }, [cellModesModel, updateCellModesModel]);
227
+ }, [updateCellModesModel]);
220
228
  const updateOrDeleteFieldState = React.useCallback((id, field, newProps) => {
221
229
  apiRef.current.setState(state => {
222
230
  const newEditingState = _extends({}, state.editRows);
@@ -289,12 +297,12 @@ export const useGridCellEditing = (apiRef, props) => {
289
297
  apiRef.current.unstable_runPendingEditCellValueMutation(id, field);
290
298
 
291
299
  const finishCellEditMode = () => {
300
+ updateOrDeleteFieldState(id, field, null);
301
+ updateFieldInCellModesModel(id, field, null);
302
+
292
303
  if (cellToFocusAfter !== 'none') {
293
304
  apiRef.current.unstable_moveFocusToRelativeCell(id, field, cellToFocusAfter);
294
305
  }
295
-
296
- updateOrDeleteFieldState(id, field, null);
297
- updateFieldInCellModesModel(id, field, null);
298
306
  };
299
307
 
300
308
  if (ignoreModifications) {
@@ -16,6 +16,7 @@ import { GridRowEditStopReasons, GridRowEditStartReasons } from '../../../models
16
16
  const missingOnProcessRowUpdateErrorWarning = buildWarning(['MUI: A call to `processRowUpdate` threw an error which was not handled because `onProcessRowUpdateError` is missing.', 'To handle the error pass a callback to the `onProcessRowUpdateError` prop, e.g. `<DataGrid onProcessRowUpdateError={(error) => ...} />`.', 'For more detail, see http://mui.com/components/data-grid/editing/#persistence.'], 'error');
17
17
  export const useGridRowEditing = (apiRef, props) => {
18
18
  const [rowModesModel, setRowModesModel] = React.useState({});
19
+ const rowModesModelRef = React.useRef(rowModesModel);
19
20
  const prevRowModesModel = React.useRef({});
20
21
  const focusTimeout = React.useRef(null);
21
22
  const nextFocusedCell = React.useRef(null);
@@ -90,6 +91,11 @@ export const useGridRowEditing = (apiRef, props) => {
90
91
  // The row might have been deleted during the click
91
92
  if (!apiRef.current.getRow(params.id)) {
92
93
  return;
94
+ } // The row may already changed its mode
95
+
96
+
97
+ if (apiRef.current.getRowMode(params.id) === GridRowModes.View) {
98
+ return;
93
99
  }
94
100
 
95
101
  const rowParams = apiRef.current.getRowParams(params.id);
@@ -260,10 +266,11 @@ export const useGridRowEditing = (apiRef, props) => {
260
266
  }
261
267
 
262
268
  setRowModesModel(newModel);
269
+ rowModesModelRef.current = newModel;
263
270
  apiRef.current.publishEvent('rowModesModelChange', newModel);
264
271
  }, [apiRef, onRowModesModelChange, props.rowModesModel, signature]);
265
272
  const updateRowInRowModesModel = React.useCallback((id, newProps) => {
266
- const newModel = _extends({}, rowModesModel);
273
+ const newModel = _extends({}, rowModesModelRef.current);
267
274
 
268
275
  if (newProps !== null) {
269
276
  newModel[id] = _extends({}, newProps);
@@ -272,7 +279,7 @@ export const useGridRowEditing = (apiRef, props) => {
272
279
  }
273
280
 
274
281
  updateRowModesModel(newModel);
275
- }, [rowModesModel, updateRowModesModel]);
282
+ }, [updateRowModesModel]);
276
283
  const updateOrDeleteRowState = React.useCallback((id, newProps) => {
277
284
  apiRef.current.setState(state => {
278
285
  const newEditingState = _extends({}, state.editRows);
@@ -1,5 +1,12 @@
1
+ import { GridFilterItem } from '../../../models/gridFilterItem';
1
2
  import { GridFilterModel } from '../../../models/gridFilterModel';
2
3
  import { GridRowId } from '../../../models/gridRows';
4
+ export declare type GridFilterItemResult = {
5
+ [key: Required<GridFilterItem>['id']]: boolean;
6
+ };
7
+ export declare type GridQuickFilterValueResult = {
8
+ [key: string]: boolean;
9
+ };
3
10
  export declare const getDefaultGridFilterModel: () => GridFilterModel;
4
11
  export interface GridFilterState {
5
12
  filterModel: GridFilterModel;
@@ -31,8 +38,12 @@ export interface GridFilterInitialState {
31
38
  * @param {GridRowId} rowId The id of the row we want to filter.
32
39
  * @param {(filterItem: GridFilterItem) => boolean} shouldApplyItem An optional callback to allow the filtering engine to only apply some items.
33
40
  */
34
- export declare type GridAggregatedFilterItemApplier = (rowId: GridRowId, shouldApplyItem?: (columnField: string) => boolean) => boolean;
41
+ export declare type GridAggregatedFilterItemApplier = (rowId: GridRowId, shouldApplyItem?: (columnField: string) => boolean) => {
42
+ passingFilterItems: null | GridFilterItemResult;
43
+ passingQuickFilterValues: null | GridQuickFilterValueResult;
44
+ };
35
45
  export interface GridFilteringMethodParams {
36
46
  isRowMatchingFilters: GridAggregatedFilterItemApplier | null;
47
+ filterModel: GridFilterModel;
37
48
  }
38
49
  export declare type GridFilteringMethodValue = Omit<GridFilterState, 'filterModel'>;
@@ -1,8 +1,9 @@
1
1
  import * as React from 'react';
2
- import { GridFilterItem, GridFilterModel } from '../../../models';
2
+ import { GridFilterItem, GridFilterModel, GridRowId } from '../../../models';
3
3
  import { GridApiCommunity } from '../../../models/api/gridApiCommunity';
4
4
  import { GridStateCommunity } from '../../../models/gridStateCommunity';
5
- import { GridAggregatedFilterItemApplier } from './gridFilterState';
5
+ import { GridAggregatedFilterItemApplier, GridFilterItemResult, GridQuickFilterValueResult } from './gridFilterState';
6
+ declare type GridFilterItemApplierNotAggregated = (rowId: GridRowId, shouldApplyItem?: (columnField: string) => boolean) => GridFilterItemResult;
6
7
  /**
7
8
  * Adds default values to the optional fields of a filter items.
8
9
  * @param {GridFilterItem} item The raw filter item.
@@ -19,12 +20,14 @@ export declare const mergeStateWithFilterModel: (filterModel: GridFilterModel, d
19
20
  * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
20
21
  * @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.
21
22
  */
22
- export declare const buildAggregatedFilterItemsApplier: (filterModel: GridFilterModel, apiRef: React.MutableRefObject<GridApiCommunity>) => GridAggregatedFilterItemApplier | null;
23
+ export declare const buildAggregatedFilterItemsApplier: (filterModel: GridFilterModel, apiRef: React.MutableRefObject<GridApiCommunity>) => GridFilterItemApplierNotAggregated | null;
23
24
  /**
24
25
  * Generates a method to easily check if a row is matching the current quick filter.
25
26
  * @param {any[]} values The model with which we want to filter the rows.
26
27
  * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
27
28
  * @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.
28
29
  */
29
- export declare const buildAggregatedQuickFilterApplier: (filterModel: GridFilterModel, apiRef: React.MutableRefObject<GridApiCommunity>) => GridAggregatedFilterItemApplier | null;
30
- export declare const buildAggregatedFilterApplier: (filterModel: GridFilterModel, apiRef: React.MutableRefObject<GridApiCommunity>) => GridAggregatedFilterItemApplier | null;
30
+ export declare const buildAggregatedQuickFilterApplier: (filterModel: GridFilterModel, apiRef: React.MutableRefObject<GridApiCommunity>) => GridFilterItemApplierNotAggregated | null;
31
+ export declare const buildAggregatedFilterApplier: (filterModel: GridFilterModel, apiRef: React.MutableRefObject<GridApiCommunity>) => GridAggregatedFilterItemApplier;
32
+ export declare const passFilterLogic: (allFilterItemResults: (null | GridFilterItemResult)[], allQuickFilterResults: (null | GridQuickFilterValueResult)[], filterModel: GridFilterModel) => boolean;
33
+ export {};
@@ -1,8 +1,8 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { GridLinkOperator } from '../../../models';
3
+ import { getDefaultGridFilterModel } from './gridFilterState';
3
4
  import { buildWarning } from '../../../utils/warning';
4
5
  import { gridColumnFieldsSelector, gridColumnLookupSelector } from '../columns';
5
- import { gridRowTreeSelector } from '../rows/gridRowsSelector';
6
6
 
7
7
  /**
8
8
  * Adds default values to the optional fields of a filter items.
@@ -78,10 +78,8 @@ export const mergeStateWithFilterModel = (filterModel, disableMultipleColumnsFil
78
78
 
79
79
  export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
80
80
  const {
81
- items,
82
- linkOperator = GridLinkOperator.And
81
+ items
83
82
  } = filterModel;
84
- const tree = gridRowTreeSelector(apiRef);
85
83
 
86
84
  const getFilterCallbackFromItem = filterItem => {
87
85
  if (!filterItem.columnField || !filterItem.operatorValue) {
@@ -145,18 +143,12 @@ export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
145
143
  }
146
144
 
147
145
  return (rowId, shouldApplyFilter) => {
148
- if (tree[rowId].position === 'footer') {
149
- return true;
150
- }
151
-
152
- const filteredAppliers = shouldApplyFilter ? appliers.filter(applier => shouldApplyFilter(applier.item.columnField)) : appliers; // Return `false` as soon as we have a failing filter
153
-
154
- if (linkOperator === GridLinkOperator.And) {
155
- return filteredAppliers.every(applier => applier.fn(rowId));
156
- } // Return `true` as soon as we have a passing filter
157
-
158
-
159
- return filteredAppliers.some(applier => applier.fn(rowId));
146
+ const resultPerItemId = {};
147
+ const filteredAppliers = shouldApplyFilter ? appliers.filter(applier => shouldApplyFilter(applier.item.columnField)) : appliers;
148
+ filteredAppliers.forEach(applier => {
149
+ resultPerItemId[applier.item.id] = applier.fn(rowId);
150
+ });
151
+ return resultPerItemId;
160
152
  };
161
153
  };
162
154
  /**
@@ -168,8 +160,7 @@ export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
168
160
 
169
161
  export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
170
162
  const {
171
- quickFilterValues = [],
172
- quickFilterLogicOperator = GridLinkOperator.And
163
+ quickFilterValues = []
173
164
  } = filterModel;
174
165
 
175
166
  if (quickFilterValues.length === 0) {
@@ -190,6 +181,11 @@ export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
190
181
  }); // If some value does not have an applier we ignore them
191
182
 
192
183
  const sanitizedQuickFilterValues = quickFilterValues.filter((value, index) => Object.keys(appliersPerColumnField).some(field => appliersPerColumnField[field][index] != null));
184
+
185
+ if (sanitizedQuickFilterValues.length === 0) {
186
+ return null;
187
+ }
188
+
193
189
  return (rowId, shouldApplyFilter) => {
194
190
  const usedCellParams = {};
195
191
  const columnsFieldsToFilter = [];
@@ -198,10 +194,10 @@ export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
198
194
  usedCellParams[columnField] = apiRef.current.getCellParams(rowId, columnField);
199
195
  columnsFieldsToFilter.push(columnField);
200
196
  }
201
- }); // Return `false` as soon as we have a quick filter value that does not match any column
202
-
203
- if (quickFilterLogicOperator === GridLinkOperator.And) {
204
- return sanitizedQuickFilterValues.every((value, index) => columnsFieldsToFilter.some(field => {
197
+ });
198
+ const quickFilterValueResult = {};
199
+ sanitizedQuickFilterValues.forEach((value, index) => {
200
+ const isPassing = columnsFieldsToFilter.some(field => {
205
201
  var _appliersPerColumnFie, _appliersPerColumnFie2;
206
202
 
207
203
  if (appliersPerColumnField[field][index] == null) {
@@ -209,36 +205,71 @@ export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
209
205
  }
210
206
 
211
207
  return (_appliersPerColumnFie = (_appliersPerColumnFie2 = appliersPerColumnField[field])[index]) == null ? void 0 : _appliersPerColumnFie.call(_appliersPerColumnFie2, usedCellParams[field]);
212
- }));
213
- } // Return `true` as soon as we have have a quick filter value that match any column
208
+ });
209
+ quickFilterValueResult[value] = isPassing;
210
+ });
211
+ return quickFilterValueResult;
212
+ };
213
+ };
214
+ export const buildAggregatedFilterApplier = (filterModel, apiRef) => {
215
+ const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(filterModel, apiRef);
216
+ const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(filterModel, apiRef);
217
+ return (rowId, shouldApplyFilter) => ({
218
+ passingFilterItems: isRowMatchingFilterItems && isRowMatchingFilterItems(rowId, shouldApplyFilter),
219
+ passingQuickFilterValues: isRowMatchingQuickFilter && isRowMatchingQuickFilter(rowId, shouldApplyFilter)
220
+ });
221
+ };
222
+ export const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel) => {
223
+ var _filterModel$quickFil, _filterModel$linkOper;
214
224
 
225
+ const cleanedAllFilterItemResults = allFilterItemResults.filter(result => result != null);
226
+ const cleanedAllQuickFilterResults = allQuickFilterResults.filter(result => result != null); // Defaultize operators
215
227
 
216
- return sanitizedQuickFilterValues.some((value, index) => columnsFieldsToFilter.some(field => {
217
- var _appliersPerColumnFie3, _appliersPerColumnFie4;
228
+ const quickFilterLogicOperator = (_filterModel$quickFil = filterModel.quickFilterLogicOperator) != null ? _filterModel$quickFil : getDefaultGridFilterModel().quickFilterLogicOperator;
229
+ const linkOperator = (_filterModel$linkOper = filterModel.linkOperator) != null ? _filterModel$linkOper : getDefaultGridFilterModel().linkOperator; // get result for filter items model
218
230
 
219
- if (appliersPerColumnField[field][index] == null) {
231
+ if (cleanedAllFilterItemResults.length > 0) {
232
+ // Return true if the item pass with one of the rows
233
+ const filterItemPredicate = item => {
234
+ return cleanedAllFilterItemResults.some(filterItemResult => filterItemResult[item.id]);
235
+ };
236
+
237
+ if (linkOperator === GridLinkOperator.And) {
238
+ const passesAllFilters = filterModel.items.every(filterItemPredicate);
239
+
240
+ if (!passesAllFilters) {
220
241
  return false;
221
242
  }
243
+ } else {
244
+ const passesSomeFilters = filterModel.items.some(filterItemPredicate);
222
245
 
223
- return (_appliersPerColumnFie3 = (_appliersPerColumnFie4 = appliersPerColumnField[field])[index]) == null ? void 0 : _appliersPerColumnFie3.call(_appliersPerColumnFie4, usedCellParams[field]);
224
- }));
225
- };
226
- };
227
- export const buildAggregatedFilterApplier = (filterModel, apiRef) => {
228
- const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(filterModel, apiRef);
229
- const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(filterModel, apiRef);
246
+ if (!passesSomeFilters) {
247
+ return false;
248
+ }
249
+ }
250
+ } // get result for quick filter model
230
251
 
231
- if (isRowMatchingFilterItems == null && isRowMatchingQuickFilter == null) {
232
- return null;
233
- }
234
252
 
235
- if (isRowMatchingFilterItems == null) {
236
- return isRowMatchingQuickFilter;
237
- }
253
+ if (cleanedAllQuickFilterResults.length > 0 && filterModel.quickFilterValues != null) {
254
+ // Return true if the item pass with one of the rows
255
+ const quickFilterValuePredicate = value => {
256
+ return cleanedAllQuickFilterResults.some(quickFilterValueResult => quickFilterValueResult[value]);
257
+ };
258
+
259
+ if (quickFilterLogicOperator === GridLinkOperator.And) {
260
+ const passesAllQuickFilterValues = filterModel.quickFilterValues.every(quickFilterValuePredicate);
238
261
 
239
- if (isRowMatchingQuickFilter == null) {
240
- return isRowMatchingFilterItems;
262
+ if (!passesAllQuickFilterValues) {
263
+ return false;
264
+ }
265
+ } else {
266
+ const passesSomeQuickFilterValues = filterModel.quickFilterValues.some(quickFilterValuePredicate);
267
+
268
+ if (!passesSomeQuickFilterValues) {
269
+ return false;
270
+ }
271
+ }
241
272
  }
242
273
 
243
- return (rowId, shouldApplyFilter) => isRowMatchingFilterItems(rowId, shouldApplyFilter) && isRowMatchingQuickFilter(rowId, shouldApplyFilter);
274
+ return true;
244
275
  };
@@ -12,7 +12,7 @@ import { useFirstRender } from '../../utils/useFirstRender';
12
12
  import { gridRowIdsSelector } from '../rows';
13
13
  import { useGridRegisterPipeProcessor } from '../../core/pipeProcessing';
14
14
  import { GRID_DEFAULT_STRATEGY, useGridRegisterStrategyProcessor } from '../../core/strategyProcessing';
15
- import { buildAggregatedFilterApplier, sanitizeFilterModel, mergeStateWithFilterModel, cleanFilterItem } from './gridFilterUtils';
15
+ import { buildAggregatedFilterApplier, sanitizeFilterModel, mergeStateWithFilterModel, cleanFilterItem, passFilterLogic } from './gridFilterUtils';
16
16
  import { isDeepEqual } from '../../../utils/utils';
17
17
  import { jsx as _jsx } from "react/jsx-runtime";
18
18
  export const filterStateInitializer = (state, props, apiRef) => {
@@ -49,7 +49,8 @@ export const useGridFilter = (apiRef, props) => {
49
49
  const filterModel = gridFilterModelSelector(state, apiRef.current.instanceId);
50
50
  const isRowMatchingFilters = props.filterMode === GridFeatureModeConstant.client ? buildAggregatedFilterApplier(filterModel, apiRef) : null;
51
51
  const filteringResult = apiRef.current.unstable_applyStrategyProcessor('filtering', {
52
- isRowMatchingFilters
52
+ isRowMatchingFilters,
53
+ filterModel: filterModel != null ? filterModel : getDefaultGridFilterModel()
53
54
  });
54
55
  return _extends({}, state, {
55
56
  filter: _extends({}, state.filter, filteringResult)
@@ -261,7 +262,19 @@ export const useGridFilter = (apiRef, props) => {
261
262
 
262
263
  for (let i = 0; i < rowIds.length; i += 1) {
263
264
  const rowId = rowIds[i];
264
- filteredRowsLookup[rowId] = params.isRowMatchingFilters(rowId);
265
+ let isRowPassing;
266
+
267
+ if (typeof rowId === 'string' && rowId.startsWith('auto-generated-group-footer')) {
268
+ isRowPassing = true;
269
+ } else {
270
+ const {
271
+ passingFilterItems,
272
+ passingQuickFilterValues
273
+ } = params.isRowMatchingFilters(rowId);
274
+ isRowPassing = passFilterLogic([passingFilterItems], [passingQuickFilterValues], params.filterModel);
275
+ }
276
+
277
+ filteredRowsLookup[rowId] = isRowPassing;
265
278
  }
266
279
 
267
280
  return {
@@ -60,6 +60,12 @@ export const useGridFocus = (apiRef, props) => {
60
60
  return;
61
61
  }
62
62
 
63
+ if (focusedCell) {
64
+ // There's a focused cell but another cell was clicked
65
+ // Publishes an event to notify that the focus was lost
66
+ apiRef.current.publishEvent('cellFocusOut', apiRef.current.getCellParams(focusedCell.id, focusedCell.field));
67
+ }
68
+
63
69
  apiRef.current.publishEvent('cellFocusIn', apiRef.current.getCellParams(id, field));
64
70
  }, [apiRef, logger]);
65
71
  const setColumnHeaderFocus = React.useCallback((field, event = {}) => {
@@ -191,11 +197,7 @@ export const useGridFocus = (apiRef, props) => {
191
197
 
192
198
  if (!apiRef.current.getRow(focusedCell.id)) {
193
199
  return;
194
- } // There's a focused cell but another cell was clicked
195
- // Publishes an event to notify that the focus was lost
196
-
197
-
198
- apiRef.current.publishEvent('cellFocusOut', apiRef.current.getCellParams(focusedCell.id, focusedCell.field), event);
200
+ }
199
201
 
200
202
  if (cellParams) {
201
203
  apiRef.current.setCellFocus(cellParams.id, cellParams.field);
@@ -206,7 +208,10 @@ export const useGridFocus = (apiRef, props) => {
206
208
  columnHeader: null
207
209
  }
208
210
  }));
209
- apiRef.current.forceUpdate();
211
+ apiRef.current.forceUpdate(); // There's a focused cell but another element (not a cell) was clicked
212
+ // Publishes an event to notify that the focus was lost
213
+
214
+ apiRef.current.publishEvent('cellFocusOut', apiRef.current.getCellParams(focusedCell.id, focusedCell.field), event);
210
215
  }
211
216
  }, [apiRef]);
212
217
  const handleCellModeChange = React.useCallback(params => {
@@ -26,8 +26,11 @@ export const rowsStateInitializer = (state, props, apiRef) => {
26
26
  };
27
27
  export const useGridRows = (apiRef, props) => {
28
28
  if (process.env.NODE_ENV !== 'production') {
29
- // Freeze rows for immutability
30
- Object.freeze(props.rows);
29
+ try {
30
+ // Freeze the `rows` prop so developers have a fast failure if they try to use Array.prototype.push().
31
+ Object.freeze(props.rows);
32
+ } catch (error) {// Sometimes, it's impossible to freeze, so we give up on it.
33
+ }
31
34
  }
32
35
 
33
36
  const logger = useGridLogger(apiRef, 'useGridRows');
@@ -20,6 +20,9 @@ export interface GridRestoreStatePreProcessingValue {
20
20
  */
21
21
  callbacks: (() => void)[];
22
22
  }
23
+ /**
24
+ * Object passed as parameter in the `exportState()` grid API method.
25
+ */
23
26
  export interface GridExportStateParams {
24
27
  /**
25
28
  * By default, the grid exports all the models.
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license MUI v5.15.1
1
+ /** @license MUI v5.15.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.
@@ -18,6 +18,7 @@ export { useGridDensity, densityStateInitializer } from '../hooks/features/densi
18
18
  export { useGridCsvExport } from '../hooks/features/export/useGridCsvExport';
19
19
  export { useGridPrintExport } from '../hooks/features/export/useGridPrintExport';
20
20
  export { useGridFilter, filterStateInitializer } from '../hooks/features/filter/useGridFilter';
21
+ export { passFilterLogic } from '../hooks/features/filter/gridFilterUtils';
21
22
  export type { GridAggregatedFilterItemApplier } from '../hooks/features/filter/gridFilterState';
22
23
  export { useGridFocus, focusStateInitializer } from '../hooks/features/focus/useGridFocus';
23
24
  export { useGridKeyboardNavigation } from '../hooks/features/keyboardNavigation/useGridKeyboardNavigation';
@@ -15,6 +15,7 @@ export { useGridDensity, densityStateInitializer } from '../hooks/features/densi
15
15
  export { useGridCsvExport } from '../hooks/features/export/useGridCsvExport';
16
16
  export { useGridPrintExport } from '../hooks/features/export/useGridPrintExport';
17
17
  export { useGridFilter, filterStateInitializer } from '../hooks/features/filter/useGridFilter';
18
+ export { passFilterLogic } from '../hooks/features/filter/gridFilterUtils';
18
19
  export { useGridFocus, focusStateInitializer } from '../hooks/features/focus/useGridFocus';
19
20
  export { useGridKeyboardNavigation } from '../hooks/features/keyboardNavigation/useGridKeyboardNavigation';
20
21
  export { useGridPagination, paginationStateInitializer } from '../hooks/features/pagination/useGridPagination';
@@ -647,7 +647,7 @@ DataGridRaw.propTypes = {
647
647
  * @param {GridState} state The new state.
648
648
  * @param {MuiEvent<{}>} event The event object.
649
649
  * @param {GridCallbackDetails} details Additional details for this callback.
650
- * @internal
650
+ * @ignore - do not document.
651
651
  */
652
652
  onStateChange: PropTypes.func,
653
653
 
@@ -23,6 +23,7 @@ export var useGridCellEditing = function useGridCellEditing(apiRef, props) {
23
23
  cellModesModel = _React$useState2[0],
24
24
  setCellModesModel = _React$useState2[1];
25
25
 
26
+ var cellModesModelRef = React.useRef(cellModesModel);
26
27
  var prevCellModesModel = React.useRef({});
27
28
  var processRowUpdate = props.processRowUpdate,
28
29
  onProcessRowUpdateError = props.onProcessRowUpdateError,
@@ -70,6 +71,10 @@ export var useGridCellEditing = function useGridCellEditing(apiRef, props) {
70
71
  return;
71
72
  }
72
73
 
74
+ if (apiRef.current.getCellMode(params.id, params.field) === GridCellModes.View) {
75
+ return;
76
+ }
77
+
73
78
  var newParams = _extends({}, params, {
74
79
  reason: GridCellEditStopReasons.cellFocusOut
75
80
  });
@@ -198,17 +203,20 @@ export var useGridCellEditing = function useGridCellEditing(apiRef, props) {
198
203
  }
199
204
 
200
205
  setCellModesModel(newModel);
206
+ cellModesModelRef.current = newModel;
201
207
  apiRef.current.publishEvent('cellModesModelChange', newModel);
202
208
  }, [apiRef, onCellModesModelChange, props.cellModesModel, signature]);
203
209
  var updateFieldInCellModesModel = React.useCallback(function (id, field, newProps) {
204
- var newModel = _extends({}, cellModesModel);
210
+ // We use the ref because it always contain the up-to-date value, different from the state
211
+ // that needs a rerender to reflect the new value
212
+ var newModel = _extends({}, cellModesModelRef.current);
205
213
 
206
214
  if (newProps !== null) {
207
215
  newModel[id] = _extends({}, newModel[id], _defineProperty({}, field, _extends({}, newProps)));
208
216
  } else {
209
- var _cellModesModel$id = cellModesModel[id],
210
- fieldToRemove = _cellModesModel$id[field],
211
- otherFields = _objectWithoutProperties(_cellModesModel$id, [field].map(_toPropertyKey)); // Ensure that we have a new object, not a reference
217
+ var _newModel$id = newModel[id],
218
+ fieldToRemove = _newModel$id[field],
219
+ otherFields = _objectWithoutProperties(_newModel$id, [field].map(_toPropertyKey)); // Ensure that we have a new object, not a reference
212
220
 
213
221
 
214
222
  newModel[id] = otherFields;
@@ -219,7 +227,7 @@ export var useGridCellEditing = function useGridCellEditing(apiRef, props) {
219
227
  }
220
228
 
221
229
  updateCellModesModel(newModel);
222
- }, [cellModesModel, updateCellModesModel]);
230
+ }, [updateCellModesModel]);
223
231
  var updateOrDeleteFieldState = React.useCallback(function (id, field, newProps) {
224
232
  apiRef.current.setState(function (state) {
225
233
  var newEditingState = _extends({}, state.editRows);
@@ -286,12 +294,12 @@ export var useGridCellEditing = function useGridCellEditing(apiRef, props) {
286
294
  apiRef.current.unstable_runPendingEditCellValueMutation(id, field);
287
295
 
288
296
  finishCellEditMode = function finishCellEditMode() {
297
+ updateOrDeleteFieldState(id, field, null);
298
+ updateFieldInCellModesModel(id, field, null);
299
+
289
300
  if (cellToFocusAfter !== 'none') {
290
301
  apiRef.current.unstable_moveFocusToRelativeCell(id, field, cellToFocusAfter);
291
302
  }
292
-
293
- updateOrDeleteFieldState(id, field, null);
294
- updateFieldInCellModesModel(id, field, null);
295
303
  };
296
304
 
297
305
  if (!ignoreModifications) {