@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.
- package/CHANGELOG.md +124 -5
- package/DataGrid/DataGrid.js +6 -0
- package/DataGrid/useDataGridProps.js +1 -0
- package/colDef/gridStringOperators.js +5 -1
- package/components/cell/GridActionsCell.js +19 -12
- package/components/cell/GridCell.js +4 -4
- package/components/containers/GridRootStyles.js +2 -1
- package/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
- package/hooks/core/useGridInitialization.d.ts +1 -1
- package/hooks/core/useGridInitialization.js +3 -0
- package/hooks/features/filter/gridFilterUtils.d.ts +9 -25
- package/hooks/features/filter/gridFilterUtils.js +61 -27
- package/hooks/features/filter/useGridFilter.d.ts +1 -1
- package/hooks/features/filter/useGridFilter.js +4 -3
- package/index.js +1 -1
- package/internals/index.d.ts +1 -0
- package/internals/index.js +1 -0
- package/internals/utils/computeSlots.js +8 -1
- package/legacy/DataGrid/DataGrid.js +6 -0
- package/legacy/DataGrid/useDataGridProps.js +1 -0
- package/legacy/colDef/gridStringOperators.js +4 -0
- package/legacy/components/cell/GridActionsCell.js +21 -12
- package/legacy/components/cell/GridCell.js +6 -4
- package/legacy/components/containers/GridRootStyles.js +2 -1
- package/legacy/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
- package/legacy/hooks/core/useGridInitialization.js +3 -0
- package/legacy/hooks/features/filter/gridFilterUtils.js +47 -21
- package/legacy/hooks/features/filter/useGridFilter.js +4 -3
- package/legacy/index.js +1 -1
- package/legacy/internals/index.js +1 -0
- package/legacy/internals/utils/computeSlots.js +8 -1
- package/legacy/utils/getPublicApiRef.js +5 -0
- package/models/api/gridApiCommon.d.ts +3 -2
- package/models/api/gridApiCommunity.d.ts +2 -1
- package/models/api/gridCoreApi.d.ts +7 -1
- package/models/api/gridFilterApi.d.ts +6 -1
- package/models/api/gridLocaleTextApi.d.ts +3 -2
- package/models/props/DataGridProps.d.ts +6 -0
- package/modern/DataGrid/DataGrid.js +6 -0
- package/modern/DataGrid/useDataGridProps.js +1 -0
- package/modern/colDef/gridStringOperators.js +5 -1
- package/modern/components/cell/GridActionsCell.js +18 -12
- package/modern/components/cell/GridCell.js +3 -3
- package/modern/components/containers/GridRootStyles.js +2 -1
- package/modern/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
- package/modern/hooks/core/useGridInitialization.js +3 -0
- package/modern/hooks/features/filter/gridFilterUtils.js +61 -27
- package/modern/hooks/features/filter/useGridFilter.js +4 -3
- package/modern/index.js +1 -1
- package/modern/internals/index.js +1 -0
- package/modern/internals/utils/computeSlots.js +8 -1
- package/modern/utils/getPublicApiRef.js +5 -0
- package/node/DataGrid/DataGrid.js +6 -0
- package/node/DataGrid/useDataGridProps.js +1 -0
- package/node/colDef/gridStringOperators.js +5 -1
- package/node/components/cell/GridActionsCell.js +18 -12
- package/node/components/cell/GridCell.js +3 -3
- package/node/components/containers/GridRootStyles.js +2 -1
- package/node/components/menu/columnMenu/menuItems/GridColumnMenuSortItem.js +6 -2
- package/node/hooks/core/useGridInitialization.js +3 -0
- package/node/hooks/features/filter/gridFilterUtils.js +63 -30
- package/node/hooks/features/filter/useGridFilter.js +4 -3
- package/node/index.js +1 -1
- package/node/internals/index.js +12 -0
- package/node/internals/utils/computeSlots.js +8 -1
- package/node/utils/getPublicApiRef.js +11 -0
- package/package.json +2 -2
- package/utils/getPublicApiRef.d.ts +3 -0
- 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
|
-
|
|
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
|
-
|
|
109
|
-
newIndex -= 1;
|
|
110
|
-
} else {
|
|
111
|
-
newIndex += 1;
|
|
112
|
-
}
|
|
122
|
+
newIndex = getNewIndex(focusedButtonIndex, 'right');
|
|
113
123
|
} else if (event.key === 'ArrowLeft') {
|
|
114
|
-
|
|
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
|
|
443
|
-
const tabIndex = (cellMode === 'view' || !isEditable) && !
|
|
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) &&
|
|
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:
|
|
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:
|
|
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<
|
|
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
|
-
|
|
110
|
-
|
|
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 =
|
|
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<
|
|
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
|
-
|
|
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
|
|
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(
|
|
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<
|
|
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
|
-
|
|
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(
|
|
208
|
-
|
|
209
|
-
|
|
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(
|
|
216
|
-
|
|
217
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 = (
|
|
269
|
-
const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(
|
|
270
|
-
const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(
|
|
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(
|
|
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.
|
|
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
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
newIndex -= 1;
|
|
119
|
-
} else {
|
|
120
|
-
newIndex += 1;
|
|
121
|
-
}
|
|
131
|
+
newIndex = getNewIndex(focusedButtonIndex, 'right');
|
|
122
132
|
} else if (event.key === 'ArrowLeft') {
|
|
123
|
-
|
|
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
|
|
451
|
-
const tabIndex = (cellMode === 'view' || !isEditable) && !
|
|
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) &&
|
|
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:
|
|
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:
|
|
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;
|