@mui/x-data-grid 6.17.0 → 6.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +124 -5
  2. package/DataGrid/DataGrid.js +6 -0
  3. package/DataGrid/useDataGridProps.js +1 -0
  4. package/colDef/gridStringOperators.js +5 -1
  5. package/components/cell/GridActionsCell.js +19 -12
  6. package/components/cell/GridCell.js +4 -4
  7. package/components/containers/GridRootStyles.js +2 -1
  8. package/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
  9. package/hooks/core/useGridInitialization.d.ts +1 -1
  10. package/hooks/core/useGridInitialization.js +3 -0
  11. package/hooks/features/filter/gridFilterUtils.d.ts +9 -25
  12. package/hooks/features/filter/gridFilterUtils.js +61 -27
  13. package/hooks/features/filter/useGridFilter.d.ts +1 -1
  14. package/hooks/features/filter/useGridFilter.js +4 -3
  15. package/index.js +1 -1
  16. package/internals/index.d.ts +1 -0
  17. package/internals/index.js +1 -0
  18. package/internals/utils/computeSlots.js +8 -1
  19. package/legacy/DataGrid/DataGrid.js +6 -0
  20. package/legacy/DataGrid/useDataGridProps.js +1 -0
  21. package/legacy/colDef/gridStringOperators.js +4 -0
  22. package/legacy/components/cell/GridActionsCell.js +21 -12
  23. package/legacy/components/cell/GridCell.js +6 -4
  24. package/legacy/components/containers/GridRootStyles.js +2 -1
  25. package/legacy/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
  26. package/legacy/hooks/core/useGridInitialization.js +3 -0
  27. package/legacy/hooks/features/filter/gridFilterUtils.js +47 -21
  28. package/legacy/hooks/features/filter/useGridFilter.js +4 -3
  29. package/legacy/index.js +1 -1
  30. package/legacy/internals/index.js +1 -0
  31. package/legacy/internals/utils/computeSlots.js +8 -1
  32. package/legacy/utils/getPublicApiRef.js +5 -0
  33. package/models/api/gridApiCommon.d.ts +3 -2
  34. package/models/api/gridApiCommunity.d.ts +2 -1
  35. package/models/api/gridCoreApi.d.ts +7 -1
  36. package/models/api/gridFilterApi.d.ts +6 -1
  37. package/models/api/gridLocaleTextApi.d.ts +3 -2
  38. package/models/props/DataGridProps.d.ts +6 -0
  39. package/modern/DataGrid/DataGrid.js +6 -0
  40. package/modern/DataGrid/useDataGridProps.js +1 -0
  41. package/modern/colDef/gridStringOperators.js +5 -1
  42. package/modern/components/cell/GridActionsCell.js +18 -12
  43. package/modern/components/cell/GridCell.js +3 -3
  44. package/modern/components/containers/GridRootStyles.js +2 -1
  45. package/modern/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
  46. package/modern/hooks/core/useGridInitialization.js +3 -0
  47. package/modern/hooks/features/filter/gridFilterUtils.js +61 -27
  48. package/modern/hooks/features/filter/useGridFilter.js +4 -3
  49. package/modern/index.js +1 -1
  50. package/modern/internals/index.js +1 -0
  51. package/modern/internals/utils/computeSlots.js +8 -1
  52. package/modern/utils/getPublicApiRef.js +5 -0
  53. package/node/DataGrid/DataGrid.js +6 -0
  54. package/node/DataGrid/useDataGridProps.js +1 -0
  55. package/node/colDef/gridStringOperators.js +5 -1
  56. package/node/components/cell/GridActionsCell.js +18 -12
  57. package/node/components/cell/GridCell.js +3 -3
  58. package/node/components/containers/GridRootStyles.js +2 -1
  59. package/node/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
  60. package/node/hooks/core/useGridInitialization.js +3 -0
  61. package/node/hooks/features/filter/gridFilterUtils.js +63 -30
  62. package/node/hooks/features/filter/useGridFilter.js +4 -3
  63. package/node/index.js +1 -1
  64. package/node/internals/index.js +12 -0
  65. package/node/internals/utils/computeSlots.js +8 -1
  66. package/node/utils/getPublicApiRef.js +11 -0
  67. package/package.json +2 -2
  68. package/utils/getPublicApiRef.d.ts +3 -0
  69. package/utils/getPublicApiRef.js +5 -0
@@ -72,10 +72,12 @@ function GridActionsCell(props) {
72
72
  focus() {
73
73
  // If ignoreCallToFocus is true, then one of the buttons was clicked and the focus is already set
74
74
  if (!ignoreCallToFocus.current) {
75
- setFocusedButtonIndex(0);
75
+ // find the first focusable button and pass the index to the state
76
+ const focusableButtonIndex = options.findIndex(o => !o.props.disabled);
77
+ setFocusedButtonIndex(focusableButtonIndex);
76
78
  }
77
79
  }
78
- }), []);
80
+ }), [options]);
79
81
  React.useEffect(() => {
80
82
  if (focusedButtonIndex >= numberOfButtons) {
81
83
  setFocusedButtonIndex(numberOfButtons - 1);
@@ -103,19 +105,23 @@ function GridActionsCell(props) {
103
105
  if (numberOfButtons <= 1) {
104
106
  return;
105
107
  }
108
+ const getNewIndex = (index, direction) => {
109
+ if (index < 0 || index > options.length) {
110
+ return index;
111
+ }
112
+
113
+ // for rtl mode we need to reverse the direction
114
+ const rtlMod = theme.direction === 'rtl' ? -1 : 1;
115
+ const indexMod = (direction === 'left' ? -1 : 1) * rtlMod;
116
+
117
+ // if the button that should receive focus is disabled go one more step
118
+ return options[index + indexMod]?.props.disabled ? getNewIndex(index + indexMod, direction) : index + indexMod;
119
+ };
106
120
  let newIndex = focusedButtonIndex;
107
121
  if (event.key === 'ArrowRight') {
108
- if (theme.direction === 'rtl') {
109
- newIndex -= 1;
110
- } else {
111
- newIndex += 1;
112
- }
122
+ newIndex = getNewIndex(focusedButtonIndex, 'right');
113
123
  } else if (event.key === 'ArrowLeft') {
114
- if (theme.direction === 'rtl') {
115
- newIndex += 1;
116
- } else {
117
- newIndex -= 1;
118
- }
124
+ newIndex = getNewIndex(focusedButtonIndex, 'left');
119
125
  }
120
126
  if (newIndex < 0 || newIndex >= numberOfButtons) {
121
127
  return; // We're already in the first or last item = do nothing and let the grid listen the event
@@ -439,8 +439,8 @@ const GridCellV7 = /*#__PURE__*/React.forwardRef((props, ref) => {
439
439
  value,
440
440
  formattedValue
441
441
  } = cellParamsWithAPI;
442
- const managesOwnFocus = column.type === 'actions';
443
- const tabIndex = (cellMode === 'view' || !isEditable) && !managesOwnFocus ? cellParamsWithAPI.tabIndex : -1;
442
+ const canManageOwnFocus = column.type === 'actions' && column.getActions?.(apiRef.current.getRowParams(rowId)).some(action => !action.props.disabled);
443
+ const tabIndex = (cellMode === 'view' || !isEditable) && !canManageOwnFocus ? cellParamsWithAPI.tabIndex : -1;
444
444
  const {
445
445
  classes: rootClasses,
446
446
  getCellClassName
@@ -578,7 +578,7 @@ const GridCellV7 = /*#__PURE__*/React.forwardRef((props, ref) => {
578
578
  children: valueString
579
579
  });
580
580
  }
581
- if ( /*#__PURE__*/React.isValidElement(children) && managesOwnFocus) {
581
+ if ( /*#__PURE__*/React.isValidElement(children) && canManageOwnFocus) {
582
582
  children = /*#__PURE__*/React.cloneElement(children, {
583
583
  focusElementRef
584
584
  });
@@ -191,7 +191,8 @@ export const GridRootStyles = styled('div', {
191
191
  overflow: 'visible !important'
192
192
  },
193
193
  [`& .${gridClasses.cell} > *`]: {
194
- overflow: 'visible !important'
194
+ overflow: 'visible !important',
195
+ whiteSpace: 'nowrap'
195
196
  }
196
197
  },
197
198
  [`& .${gridClasses['virtualScrollerContent--overflowed']} .${gridClasses['row--lastVisible']} .${gridClasses.cell}`]: {
@@ -33,6 +33,10 @@ function GridColumnMenuSortItem(props) {
33
33
  if (!colDef || !colDef.sortable || !sortingOrder.some(item => !!item)) {
34
34
  return null;
35
35
  }
36
+ const getLabel = key => {
37
+ const label = apiRef.current.getLocaleText(key);
38
+ return typeof label === 'function' ? label(colDef) : label;
39
+ };
36
40
  return /*#__PURE__*/_jsxs(React.Fragment, {
37
41
  children: [sortingOrder.includes('asc') && sortDirection !== 'asc' ? /*#__PURE__*/_jsxs(MenuItem, {
38
42
  onClick: onSortMenuItemClick,
@@ -42,7 +46,7 @@ function GridColumnMenuSortItem(props) {
42
46
  fontSize: "small"
43
47
  })
44
48
  }), /*#__PURE__*/_jsx(ListItemText, {
45
- children: apiRef.current.getLocaleText('columnMenuSortAsc')
49
+ children: getLabel('columnMenuSortAsc')
46
50
  })]
47
51
  }) : null, sortingOrder.includes('desc') && sortDirection !== 'desc' ? /*#__PURE__*/_jsxs(MenuItem, {
48
52
  onClick: onSortMenuItemClick,
@@ -52,7 +56,7 @@ function GridColumnMenuSortItem(props) {
52
56
  fontSize: "small"
53
57
  })
54
58
  }), /*#__PURE__*/_jsx(ListItemText, {
55
- children: apiRef.current.getLocaleText('columnMenuSortDesc')
59
+ children: getLabel('columnMenuSortDesc')
56
60
  })]
57
61
  }) : null, sortingOrder.includes(null) && sortDirection != null ? /*#__PURE__*/_jsxs(MenuItem, {
58
62
  onClick: onSortMenuItemClick,
@@ -15,5 +15,8 @@ export const useGridInitialization = (inputApiRef, props) => {
15
15
  useGridPipeProcessing(privateApiRef);
16
16
  useGridStrategyProcessing(privateApiRef);
17
17
  useGridLocaleText(privateApiRef, props);
18
+ privateApiRef.current.register('private', {
19
+ rootProps: props
20
+ });
18
21
  return privateApiRef;
19
22
  };
@@ -3,6 +3,7 @@ import { GridLogicOperator } from '../../../models';
3
3
  import { GLOBAL_API_REF, isInternalFilter } from '../../../colDef/utils';
4
4
  import { getDefaultGridFilterModel } from './gridFilterState';
5
5
  import { buildWarning } from '../../../utils/warning';
6
+ import { getPublicApiRef } from '../../../utils/getPublicApiRef';
6
7
  import { gridColumnFieldsSelector, gridColumnLookupSelector, gridVisibleColumnFieldsSelector } from '../columns';
7
8
 
8
9
  // Fixes https://github.com/mui/mui-x/issues/10056
@@ -17,7 +18,7 @@ try {
17
18
  /**
18
19
  * Adds default values to the optional fields of a filter items.
19
20
  * @param {GridFilterItem} item The raw filter item.
20
- * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
21
+ * @param {React.MutableRefObject<GridPrivateApiCommunity>} apiRef The API of the grid.
21
22
  * @return {GridFilterItem} The clean filter item with an uniq ID and an always-defined operator.
22
23
  * TODO: Make the typing reflect the different between GridFilterInputItem and GridFilterItem.
23
24
  */
@@ -69,6 +70,12 @@ export const sanitizeFilterModel = (model, disableMultipleColumnsFiltering, apiR
69
70
  export const mergeStateWithFilterModel = (filterModel, disableMultipleColumnsFiltering, apiRef) => filteringState => _extends({}, filteringState, {
70
71
  filterModel: sanitizeFilterModel(filterModel, disableMultipleColumnsFiltering, apiRef)
71
72
  });
73
+ export const removeDiacritics = value => {
74
+ if (typeof value === 'string') {
75
+ return value.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
76
+ }
77
+ return value;
78
+ };
72
79
  const getFilterCallbackFromItem = (filterItem, apiRef) => {
73
80
  if (!filterItem.field || !filterItem.operator) {
74
81
  return null;
@@ -84,6 +91,12 @@ const getFilterCallbackFromItem = (filterItem, apiRef) => {
84
91
  } else {
85
92
  parsedValue = filterItem.value;
86
93
  }
94
+ const {
95
+ ignoreDiacritics
96
+ } = apiRef.current.rootProps;
97
+ if (ignoreDiacritics) {
98
+ parsedValue = removeDiacritics(parsedValue);
99
+ }
87
100
  const newFilterItem = _extends({}, filterItem, {
88
101
  value: parsedValue
89
102
  });
@@ -97,6 +110,7 @@ const getFilterCallbackFromItem = (filterItem, apiRef) => {
97
110
  }
98
111
  const hasUserFunctionLegacy = !isInternalFilter(filterOperator.getApplyFilterFn);
99
112
  const hasUserFunctionV7 = !isInternalFilter(filterOperator.getApplyFilterFnV7);
113
+ const publicApiRef = getPublicApiRef(apiRef);
100
114
  if (filterOperator.getApplyFilterFnV7 && !(hasUserFunctionLegacy && !hasUserFunctionV7)) {
101
115
  const applyFilterOnRow = filterOperator.getApplyFilterFnV7(newFilterItem, column);
102
116
  if (typeof applyFilterOnRow !== 'function') {
@@ -106,8 +120,11 @@ const getFilterCallbackFromItem = (filterItem, apiRef) => {
106
120
  v7: true,
107
121
  item: newFilterItem,
108
122
  fn: row => {
109
- const value = apiRef.current.getRowValue(row, column);
110
- return applyFilterOnRow(value, row, column, apiRef);
123
+ let value = apiRef.current.getRowValue(row, column);
124
+ if (ignoreDiacritics) {
125
+ value = removeDiacritics(value);
126
+ }
127
+ return applyFilterOnRow(value, row, column, publicApiRef);
111
128
  }
112
129
  };
113
130
  }
@@ -120,7 +137,10 @@ const getFilterCallbackFromItem = (filterItem, apiRef) => {
120
137
  item: newFilterItem,
121
138
  fn: rowId => {
122
139
  const params = apiRef.current.getCellParams(rowId, newFilterItem.field);
123
- GLOBAL_API_REF.current = apiRef;
140
+ GLOBAL_API_REF.current = publicApiRef;
141
+ if (ignoreDiacritics) {
142
+ params.value = removeDiacritics(params.value);
143
+ }
124
144
  const result = applyFilterOnRow(params);
125
145
  GLOBAL_API_REF.current = null;
126
146
  return result;
@@ -131,12 +151,11 @@ let filterItemsApplierId = 1;
131
151
 
132
152
  /**
133
153
  * Generates a method to easily check if a row is matching the current filter model.
134
- * @param {GridRowIdGetter | undefined} getRowId The getter for row's id.
135
154
  * @param {GridFilterModel} filterModel The model with which we want to filter the rows.
136
- * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
155
+ * @param {React.MutableRefObject<GridPrivateApiCommunity>} apiRef The API of the grid.
137
156
  * @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.
138
157
  */
139
- export const buildAggregatedFilterItemsApplier = (getRowId, filterModel, apiRef, disableEval) => {
158
+ const buildAggregatedFilterItemsApplier = (filterModel, apiRef, disableEval) => {
140
159
  const {
141
160
  items
142
161
  } = filterModel;
@@ -151,7 +170,7 @@ export const buildAggregatedFilterItemsApplier = (getRowId, filterModel, apiRef,
151
170
  for (let i = 0; i < appliers.length; i += 1) {
152
171
  const applier = appliers[i];
153
172
  if (!shouldApplyFilter || shouldApplyFilter(applier.item.field)) {
154
- resultPerItemId[applier.item.id] = applier.v7 ? applier.fn(row) : applier.fn(getRowId ? getRowId(row) : row.id);
173
+ resultPerItemId[applier.item.id] = applier.v7 ? applier.fn(row) : applier.fn(apiRef.current.getRowId(row));
155
174
  }
156
175
  }
157
176
  return resultPerItemId;
@@ -167,14 +186,14 @@ export const buildAggregatedFilterItemsApplier = (getRowId, filterModel, apiRef,
167
186
  ${appliers.map((applier, i) => `${JSON.stringify(String(applier.item.id))}:
168
187
  !shouldApply${i} ?
169
188
  false :
170
- ${applier.v7 ? `appliers[${i}].fn(row)` : `appliers[${i}].fn(${getRowId ? 'getRowId(row)' : 'row.id'})`},
189
+ ${applier.v7 ? `appliers[${i}].fn(row)` : `appliers[${i}].fn(getRowId(row))`},
171
190
  `).join('\n')}};
172
191
 
173
192
  return result$$;
174
193
  })`;
175
194
  const filterItemCore = evalCode(filterItemTemplate.replaceAll('$$', String(filterItemsApplierId)));
176
195
  const filterItem = (row, shouldApplyItem) => {
177
- return filterItemCore(getRowId, appliers, row, shouldApplyItem);
196
+ return filterItemCore(apiRef.current.getRowId, appliers, row, shouldApplyItem);
178
197
  };
179
198
  filterItemsApplierId += 1;
180
199
  return filterItem;
@@ -182,12 +201,11 @@ export const buildAggregatedFilterItemsApplier = (getRowId, filterModel, apiRef,
182
201
 
183
202
  /**
184
203
  * Generates a method to easily check if a row is matching the current quick filter.
185
- * @param {GridRowIdGetter | undefined} getRowId The getter for row's id.
186
204
  * @param {any[]} filterModel The model with which we want to filter the rows.
187
- * @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
205
+ * @param {React.MutableRefObject<GridPrivateApiCommunity>} apiRef The API of the grid.
188
206
  * @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.
189
207
  */
190
- export const buildAggregatedQuickFilterApplier = (getRowId, filterModel, apiRef) => {
208
+ const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
191
209
  const quickFilterValues = filterModel.quickFilterValues?.filter(Boolean) ?? [];
192
210
  if (quickFilterValues.length === 0) {
193
211
  return null;
@@ -195,6 +213,10 @@ export const buildAggregatedQuickFilterApplier = (getRowId, filterModel, apiRef)
195
213
  const quickFilterExcludeHiddenColumns = filterModel.quickFilterExcludeHiddenColumns ?? false;
196
214
  const columnFields = quickFilterExcludeHiddenColumns ? gridVisibleColumnFieldsSelector(apiRef) : gridColumnFieldsSelector(apiRef);
197
215
  const appliersPerField = [];
216
+ const {
217
+ ignoreDiacritics
218
+ } = apiRef.current.rootProps;
219
+ const publicApiRef = getPublicApiRef(apiRef);
198
220
  columnFields.forEach(field => {
199
221
  const column = apiRef.current.getColumn(field);
200
222
  const getApplyQuickFilterFn = column?.getApplyQuickFilterFn;
@@ -204,18 +226,24 @@ export const buildAggregatedQuickFilterApplier = (getRowId, filterModel, apiRef)
204
226
  if (getApplyQuickFilterFnV7 && !(hasUserFunctionLegacy && !hasUserFunctionV7)) {
205
227
  appliersPerField.push({
206
228
  column,
207
- appliers: quickFilterValues.map(value => ({
208
- v7: true,
209
- fn: getApplyQuickFilterFnV7(value, column, apiRef)
210
- }))
229
+ appliers: quickFilterValues.map(quickFilterValue => {
230
+ const value = ignoreDiacritics ? removeDiacritics(quickFilterValue) : quickFilterValue;
231
+ return {
232
+ v7: true,
233
+ fn: getApplyQuickFilterFnV7(value, column, publicApiRef)
234
+ };
235
+ })
211
236
  });
212
237
  } else if (getApplyQuickFilterFn) {
213
238
  appliersPerField.push({
214
239
  column,
215
- appliers: quickFilterValues.map(value => ({
216
- v7: false,
217
- fn: getApplyQuickFilterFn(value, column, apiRef)
218
- }))
240
+ appliers: quickFilterValues.map(quickFilterValue => {
241
+ const value = ignoreDiacritics ? removeDiacritics(quickFilterValue) : quickFilterValue;
242
+ return {
243
+ v7: false,
244
+ fn: getApplyQuickFilterFn(value, column, publicApiRef)
245
+ };
246
+ })
219
247
  });
220
248
  }
221
249
  });
@@ -238,18 +266,24 @@ export const buildAggregatedQuickFilterApplier = (getRowId, filterModel, apiRef)
238
266
  continue;
239
267
  }
240
268
  const applier = appliers[v];
241
- const value = apiRef.current.getRowValue(row, column);
269
+ let value = apiRef.current.getRowValue(row, column);
242
270
  if (applier.fn === null) {
243
271
  continue;
244
272
  }
245
273
  if (applier.v7) {
246
- const isMatching = applier.fn(value, row, column, apiRef);
274
+ if (ignoreDiacritics) {
275
+ value = removeDiacritics(value);
276
+ }
277
+ const isMatching = applier.fn(value, row, column, publicApiRef);
247
278
  if (isMatching) {
248
279
  result[filterValue] = true;
249
280
  continue outer;
250
281
  }
251
282
  } else {
252
- const cellParams = usedCellParams[field] ?? apiRef.current.getCellParams(getRowId ? getRowId(row) : row.id, field);
283
+ const cellParams = usedCellParams[field] ?? apiRef.current.getCellParams(apiRef.current.getRowId(row), field);
284
+ if (ignoreDiacritics) {
285
+ cellParams.value = removeDiacritics(cellParams.value);
286
+ }
253
287
  usedCellParams[field] = cellParams;
254
288
  const isMatching = applier.fn(cellParams);
255
289
  if (isMatching) {
@@ -265,9 +299,9 @@ export const buildAggregatedQuickFilterApplier = (getRowId, filterModel, apiRef)
265
299
  return result;
266
300
  };
267
301
  };
268
- export const buildAggregatedFilterApplier = (getRowId, filterModel, apiRef, disableEval) => {
269
- const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(getRowId, filterModel, apiRef, disableEval);
270
- const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(getRowId, filterModel, apiRef);
302
+ export const buildAggregatedFilterApplier = (filterModel, apiRef, disableEval) => {
303
+ const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(filterModel, apiRef, disableEval);
304
+ const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(filterModel, apiRef);
271
305
  return function isRowMatchingFilters(row, shouldApplyFilter, result) {
272
306
  result.passingFilterItems = isRowMatchingFilterItems?.(row, shouldApplyFilter) ?? null;
273
307
  result.passingQuickFilterValues = isRowMatchingQuickFilter?.(row, shouldApplyFilter) ?? null;
@@ -59,7 +59,7 @@ export const useGridFilter = (apiRef, props) => {
59
59
  const updateFilteredRows = React.useCallback(() => {
60
60
  apiRef.current.setState(state => {
61
61
  const filterModel = gridFilterModelSelector(state, apiRef.current.instanceId);
62
- const isRowMatchingFilters = props.filterMode === 'client' ? buildAggregatedFilterApplier(props.getRowId, filterModel, apiRef, props.disableEval) : null;
62
+ const isRowMatchingFilters = props.filterMode === 'client' ? buildAggregatedFilterApplier(filterModel, apiRef, props.disableEval) : null;
63
63
  const filteringResult = apiRef.current.applyStrategyProcessor('filtering', {
64
64
  isRowMatchingFilters,
65
65
  filterModel: filterModel ?? getDefaultGridFilterModel()
@@ -73,7 +73,7 @@ export const useGridFilter = (apiRef, props) => {
73
73
  });
74
74
  });
75
75
  apiRef.current.publishEvent('filteredRowsSet');
76
- }, [apiRef, props.filterMode, props.getRowId, props.disableEval]);
76
+ }, [apiRef, props.filterMode, props.disableEval]);
77
77
  const addColumnMenuItem = React.useCallback((columnMenuItems, colDef) => {
78
78
  if (colDef == null || colDef.filterable === false || props.disableColumnFilter) {
79
79
  return columnMenuItems;
@@ -212,7 +212,8 @@ export const useGridFilter = (apiRef, props) => {
212
212
  setFilterModel,
213
213
  showFilterPanel,
214
214
  hideFilterPanel,
215
- setQuickFilterValues
215
+ setQuickFilterValues,
216
+ ignoreDiacritics: props.ignoreDiacritics
216
217
  };
217
218
  useGridApiMethod(apiRef, filterApi, 'public');
218
219
 
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v6.17.0
2
+ * @mui/x-data-grid v6.18.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -59,6 +59,7 @@ export { isNavigationKey } from '../utils/keyboardUtils';
59
59
  export { clamp, isDeepEqual, isNumber, isFunction, isObject } from '../utils/utils';
60
60
  export { buildWarning } from '../utils/warning';
61
61
  export { exportAs } from '../utils/exportAs';
62
+ export * from '../utils/getPublicApiRef';
62
63
  export { useGridPrivateApiContext } from '../hooks/utils/useGridPrivateApiContext';
63
64
  export * from '../hooks/utils/useOnMount';
64
65
  export { serializeCellValue } from '../hooks/features/export/serializers/csvSerializer';
@@ -13,5 +13,12 @@ export function computeSlots({
13
13
  if (!overrides || Object.keys(overrides).length === 0) {
14
14
  return defaultSlots;
15
15
  }
16
- return _extends({}, defaultSlots, overrides);
16
+ const result = _extends({}, defaultSlots);
17
+ Object.keys(overrides).forEach(key => {
18
+ const k = key;
19
+ if (overrides[k] !== undefined) {
20
+ result[k] = overrides[k];
21
+ }
22
+ });
23
+ return result;
17
24
  }
@@ -0,0 +1,5 @@
1
+ export function getPublicApiRef(apiRef) {
2
+ return {
3
+ current: apiRef.current.getPublicApi()
4
+ };
5
+ }
@@ -286,6 +286,12 @@ DataGridRaw.propTypes = {
286
286
  * @default false
287
287
  */
288
288
  hideFooterSelectedRowCount: _propTypes.default.bool,
289
+ /**
290
+ * If `true`, the diacritics (accents) are ignored when filtering or quick filtering.
291
+ * E.g. when filter value is `cafe`, the rows with `café` will be visible.
292
+ * @default false
293
+ */
294
+ ignoreDiacritics: _propTypes.default.bool,
289
295
  /**
290
296
  * The initial state of the DataGrid.
291
297
  * The data in it will be set in the state on initialization but will not be controlled.
@@ -60,6 +60,7 @@ const DATA_GRID_PROPS_DEFAULT_VALUES = exports.DATA_GRID_PROPS_DEFAULT_VALUES =
60
60
  hideFooterPagination: false,
61
61
  hideFooterRowCount: false,
62
62
  hideFooterSelectedRowCount: false,
63
+ ignoreDiacritics: false,
63
64
  logger: console,
64
65
  logLevel: process.env.NODE_ENV === 'production' ? 'error' : 'warn',
65
66
  pagination: false,
@@ -8,13 +8,17 @@ var _GridFilterInputValue = require("../components/panel/filterPanel/GridFilterI
8
8
  var _utils = require("../utils/utils");
9
9
  var _GridFilterInputMultipleValue = require("../components/panel/filterPanel/GridFilterInputMultipleValue");
10
10
  var _utils2 = require("./utils");
11
+ var _gridFilterUtils = require("../hooks/features/filter/gridFilterUtils");
11
12
  const getGridStringQuickFilterFn = exports.getGridStringQuickFilterFn = (0, _utils2.tagInternalFilter)(value => {
12
13
  if (!value) {
13
14
  return null;
14
15
  }
15
16
  const filterRegex = new RegExp((0, _utils.escapeRegExp)(value), 'i');
16
17
  return (_, row, column, apiRef) => {
17
- const columnValue = apiRef.current.getRowFormattedValue(row, column);
18
+ let columnValue = apiRef.current.getRowFormattedValue(row, column);
19
+ if (apiRef.current.ignoreDiacritics) {
20
+ columnValue = (0, _gridFilterUtils.removeDiacritics)(columnValue);
21
+ }
18
22
  return columnValue != null ? filterRegex.test(columnValue.toString()) : false;
19
23
  };
20
24
  });
@@ -81,10 +81,12 @@ function GridActionsCell(props) {
81
81
  focus() {
82
82
  // If ignoreCallToFocus is true, then one of the buttons was clicked and the focus is already set
83
83
  if (!ignoreCallToFocus.current) {
84
- setFocusedButtonIndex(0);
84
+ // find the first focusable button and pass the index to the state
85
+ const focusableButtonIndex = options.findIndex(o => !o.props.disabled);
86
+ setFocusedButtonIndex(focusableButtonIndex);
85
87
  }
86
88
  }
87
- }), []);
89
+ }), [options]);
88
90
  React.useEffect(() => {
89
91
  if (focusedButtonIndex >= numberOfButtons) {
90
92
  setFocusedButtonIndex(numberOfButtons - 1);
@@ -112,19 +114,23 @@ function GridActionsCell(props) {
112
114
  if (numberOfButtons <= 1) {
113
115
  return;
114
116
  }
117
+ const getNewIndex = (index, direction) => {
118
+ if (index < 0 || index > options.length) {
119
+ return index;
120
+ }
121
+
122
+ // for rtl mode we need to reverse the direction
123
+ const rtlMod = theme.direction === 'rtl' ? -1 : 1;
124
+ const indexMod = (direction === 'left' ? -1 : 1) * rtlMod;
125
+
126
+ // if the button that should receive focus is disabled go one more step
127
+ return options[index + indexMod]?.props.disabled ? getNewIndex(index + indexMod, direction) : index + indexMod;
128
+ };
115
129
  let newIndex = focusedButtonIndex;
116
130
  if (event.key === 'ArrowRight') {
117
- if (theme.direction === 'rtl') {
118
- newIndex -= 1;
119
- } else {
120
- newIndex += 1;
121
- }
131
+ newIndex = getNewIndex(focusedButtonIndex, 'right');
122
132
  } else if (event.key === 'ArrowLeft') {
123
- if (theme.direction === 'rtl') {
124
- newIndex += 1;
125
- } else {
126
- newIndex -= 1;
127
- }
133
+ newIndex = getNewIndex(focusedButtonIndex, 'left');
128
134
  }
129
135
  if (newIndex < 0 || newIndex >= numberOfButtons) {
130
136
  return; // We're already in the first or last item = do nothing and let the grid listen the event
@@ -447,8 +447,8 @@ const GridCellV7 = /*#__PURE__*/React.forwardRef((props, ref) => {
447
447
  value,
448
448
  formattedValue
449
449
  } = cellParamsWithAPI;
450
- const managesOwnFocus = column.type === 'actions';
451
- const tabIndex = (cellMode === 'view' || !isEditable) && !managesOwnFocus ? cellParamsWithAPI.tabIndex : -1;
450
+ const canManageOwnFocus = column.type === 'actions' && column.getActions?.(apiRef.current.getRowParams(rowId)).some(action => !action.props.disabled);
451
+ const tabIndex = (cellMode === 'view' || !isEditable) && !canManageOwnFocus ? cellParamsWithAPI.tabIndex : -1;
452
452
  const {
453
453
  classes: rootClasses,
454
454
  getCellClassName
@@ -586,7 +586,7 @@ const GridCellV7 = /*#__PURE__*/React.forwardRef((props, ref) => {
586
586
  children: valueString
587
587
  });
588
588
  }
589
- if ( /*#__PURE__*/React.isValidElement(children) && managesOwnFocus) {
589
+ if ( /*#__PURE__*/React.isValidElement(children) && canManageOwnFocus) {
590
590
  children = /*#__PURE__*/React.cloneElement(children, {
591
591
  focusElementRef
592
592
  });
@@ -198,7 +198,8 @@ const GridRootStyles = exports.GridRootStyles = (0, _styles.styled)('div', {
198
198
  overflow: 'visible !important'
199
199
  },
200
200
  [`& .${_gridClasses.gridClasses.cell} > *`]: {
201
- overflow: 'visible !important'
201
+ overflow: 'visible !important',
202
+ whiteSpace: 'nowrap'
202
203
  }
203
204
  },
204
205
  [`& .${_gridClasses.gridClasses['virtualScrollerContent--overflowed']} .${_gridClasses.gridClasses['row--lastVisible']} .${_gridClasses.gridClasses.cell}`]: {
@@ -41,6 +41,10 @@ function GridColumnMenuSortItem(props) {
41
41
  if (!colDef || !colDef.sortable || !sortingOrder.some(item => !!item)) {
42
42
  return null;
43
43
  }
44
+ const getLabel = key => {
45
+ const label = apiRef.current.getLocaleText(key);
46
+ return typeof label === 'function' ? label(colDef) : label;
47
+ };
44
48
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, {
45
49
  children: [sortingOrder.includes('asc') && sortDirection !== 'asc' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_MenuItem.default, {
46
50
  onClick: onSortMenuItemClick,
@@ -50,7 +54,7 @@ function GridColumnMenuSortItem(props) {
50
54
  fontSize: "small"
51
55
  })
52
56
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ListItemText.default, {
53
- children: apiRef.current.getLocaleText('columnMenuSortAsc')
57
+ children: getLabel('columnMenuSortAsc')
54
58
  })]
55
59
  }) : null, sortingOrder.includes('desc') && sortDirection !== 'desc' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_MenuItem.default, {
56
60
  onClick: onSortMenuItemClick,
@@ -60,7 +64,7 @@ function GridColumnMenuSortItem(props) {
60
64
  fontSize: "small"
61
65
  })
62
66
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ListItemText.default, {
63
- children: apiRef.current.getLocaleText('columnMenuSortDesc')
67
+ children: getLabel('columnMenuSortDesc')
64
68
  })]
65
69
  }) : null, sortingOrder.includes(null) && sortDirection != null ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_MenuItem.default, {
66
70
  onClick: onSortMenuItemClick,
@@ -20,6 +20,9 @@ const useGridInitialization = (inputApiRef, props) => {
20
20
  (0, _pipeProcessing.useGridPipeProcessing)(privateApiRef);
21
21
  (0, _strategyProcessing.useGridStrategyProcessing)(privateApiRef);
22
22
  (0, _useGridLocaleText.useGridLocaleText)(privateApiRef, props);
23
+ privateApiRef.current.register('private', {
24
+ rootProps: props
25
+ });
23
26
  return privateApiRef;
24
27
  };
25
28
  exports.useGridInitialization = useGridInitialization;