@mui/x-data-grid 7.22.0 → 7.22.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.
- package/CHANGELOG.md +126 -0
- package/colDef/gridBooleanOperators.js +4 -6
- package/components/GridRow.js +1 -1
- package/components/cell/GridBooleanCell.js +2 -1
- package/components/panel/filterPanel/GridFilterInputBoolean.d.ts +1 -0
- package/components/panel/filterPanel/GridFilterInputBoolean.js +14 -5
- package/components/virtualization/GridVirtualScrollbar.js +7 -1
- package/hooks/features/columnHeaders/useGridColumnHeaders.js +1 -2
- package/hooks/features/editing/useGridCellEditing.js +23 -4
- package/hooks/features/editing/useGridRowEditing.js +23 -2
- package/hooks/features/focus/useGridFocus.js +1 -1
- package/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +3 -4
- package/hooks/features/listView/useGridListView.d.ts +1 -1
- package/hooks/features/listView/useGridListView.js +8 -2
- package/hooks/features/rowSelection/useGridRowSelection.d.ts +1 -1
- package/hooks/features/rowSelection/useGridRowSelection.js +31 -17
- package/hooks/features/rows/useGridRowSpanning.js +3 -1
- package/hooks/features/scroll/useGridScroll.js +3 -7
- package/hooks/features/virtualization/useGridVirtualScroller.js +1 -1
- package/index.js +1 -1
- package/internals/constants.d.ts +3 -0
- package/internals/constants.js +3 -0
- package/internals/index.d.ts +1 -0
- package/internals/index.js +2 -1
- package/internals/utils/gridRowGroupingUtils.d.ts +2 -0
- package/internals/utils/gridRowGroupingUtils.js +9 -0
- package/internals/utils/index.d.ts +1 -0
- package/internals/utils/index.js +2 -1
- package/modern/colDef/gridBooleanOperators.js +4 -6
- package/modern/components/GridRow.js +1 -1
- package/modern/components/cell/GridBooleanCell.js +2 -1
- package/modern/components/panel/filterPanel/GridFilterInputBoolean.js +14 -5
- package/modern/components/virtualization/GridVirtualScrollbar.js +7 -1
- package/modern/hooks/features/columnHeaders/useGridColumnHeaders.js +1 -2
- package/modern/hooks/features/editing/useGridCellEditing.js +23 -4
- package/modern/hooks/features/editing/useGridRowEditing.js +23 -2
- package/modern/hooks/features/focus/useGridFocus.js +1 -1
- package/modern/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +3 -4
- package/modern/hooks/features/listView/useGridListView.js +8 -2
- package/modern/hooks/features/rowSelection/useGridRowSelection.js +31 -17
- package/modern/hooks/features/rows/useGridRowSpanning.js +3 -1
- package/modern/hooks/features/scroll/useGridScroll.js +3 -7
- package/modern/hooks/features/virtualization/useGridVirtualScroller.js +1 -1
- package/modern/index.js +1 -1
- package/modern/internals/constants.js +3 -0
- package/modern/internals/index.js +2 -1
- package/modern/internals/utils/gridRowGroupingUtils.js +9 -0
- package/modern/internals/utils/index.js +2 -1
- package/node/colDef/gridBooleanOperators.js +3 -5
- package/node/components/GridRow.js +2 -2
- package/node/components/cell/GridBooleanCell.js +2 -1
- package/node/components/panel/filterPanel/GridFilterInputBoolean.js +16 -5
- package/node/components/virtualization/GridVirtualScrollbar.js +7 -1
- package/node/hooks/features/columnHeaders/useGridColumnHeaders.js +1 -2
- package/node/hooks/features/editing/useGridCellEditing.js +23 -4
- package/node/hooks/features/editing/useGridRowEditing.js +23 -2
- package/node/hooks/features/focus/useGridFocus.js +1 -1
- package/node/hooks/features/keyboardNavigation/useGridKeyboardNavigation.js +4 -5
- package/node/hooks/features/listView/useGridListView.js +8 -2
- package/node/hooks/features/rowSelection/useGridRowSelection.js +31 -17
- package/node/hooks/features/rows/useGridRowSpanning.js +3 -1
- package/node/hooks/features/scroll/useGridScroll.js +3 -7
- package/node/hooks/features/virtualization/useGridVirtualScroller.js +1 -1
- package/node/index.js +1 -1
- package/node/internals/constants.js +9 -0
- package/node/internals/index.js +12 -0
- package/node/internals/utils/gridRowGroupingUtils.js +17 -0
- package/node/internals/utils/index.js +11 -0
- package/package.json +1 -1
- package/constants/gridDetailPanelToggleField.d.ts +0 -1
- package/constants/gridDetailPanelToggleField.js +0 -2
- package/modern/constants/gridDetailPanelToggleField.js +0 -2
- package/node/constants/gridDetailPanelToggleField.js +0 -8
|
@@ -382,7 +382,7 @@ export const useGridVirtualScroller = () => {
|
|
|
382
382
|
flexShrink: 0
|
|
383
383
|
};
|
|
384
384
|
if (rootProps.autoHeight && currentPage.rows.length === 0) {
|
|
385
|
-
size.
|
|
385
|
+
size.flexBasis = getMinimalContentHeight(apiRef); // Give room to show the overlay when there no rows.
|
|
386
386
|
}
|
|
387
387
|
return size;
|
|
388
388
|
}, [apiRef, columnsTotalWidth, contentHeight, needsHorizontalScrollbar, rootProps.autoHeight, currentPage.rows.length]);
|
package/index.js
CHANGED
package/internals/index.d.ts
CHANGED
|
@@ -92,4 +92,5 @@ export type { GridApiCommunity } from '../models/api/gridApiCommunity';
|
|
|
92
92
|
export type { GridApiCaches } from '../models/gridApiCaches';
|
|
93
93
|
export { serializeCellValue } from '../hooks/features/export/serializers/csvSerializer';
|
|
94
94
|
export * from './utils';
|
|
95
|
+
export * from './constants';
|
|
95
96
|
export type { Localization } from '../utils/getGridLocalization';
|
package/internals/index.js
CHANGED
|
@@ -72,4 +72,5 @@ export * from "../utils/cellBorderUtils.js";
|
|
|
72
72
|
export { useGridPrivateApiContext } from "../hooks/utils/useGridPrivateApiContext.js";
|
|
73
73
|
export * from "../hooks/utils/index.js";
|
|
74
74
|
export { serializeCellValue } from "../hooks/features/export/serializers/csvSerializer.js";
|
|
75
|
-
export * from "./utils/index.js";
|
|
75
|
+
export * from "./utils/index.js";
|
|
76
|
+
export * from "./constants.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD } from "../constants.js";
|
|
2
|
+
export const getRowGroupingCriteriaFromGroupingField = groupingColDefField => {
|
|
3
|
+
const match = groupingColDefField.match(/^__row_group_by_columns_group_(.*)__$/);
|
|
4
|
+
if (!match) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return match[1];
|
|
8
|
+
};
|
|
9
|
+
export const isGroupingColumn = field => field === GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD || getRowGroupingCriteriaFromGroupingField(field) !== null;
|
package/internals/utils/index.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { GridFilterInputBoolean } from "../components/panel/filterPanel/GridFilterInputBoolean.js";
|
|
1
|
+
import { GridFilterInputBoolean, sanitizeFilterItemValue } from "../components/panel/filterPanel/GridFilterInputBoolean.js";
|
|
2
2
|
export const getGridBooleanOperators = () => [{
|
|
3
3
|
value: 'is',
|
|
4
4
|
getApplyFilterFn: filterItem => {
|
|
5
|
-
|
|
5
|
+
const sanitizedValue = sanitizeFilterItemValue(filterItem.value);
|
|
6
|
+
if (sanitizedValue === undefined) {
|
|
6
7
|
return null;
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
-
return value => {
|
|
10
|
-
return Boolean(value) === valueAsBoolean;
|
|
11
|
-
};
|
|
9
|
+
return value => Boolean(value) === sanitizedValue;
|
|
12
10
|
},
|
|
13
11
|
InputComponent: GridFilterInputBoolean
|
|
14
12
|
}];
|
|
@@ -16,7 +16,7 @@ import { useGridVisibleRows } from "../hooks/utils/useGridVisibleRows.js";
|
|
|
16
16
|
import { findParentElementFromClassName, isEventTargetInPortal } from "../utils/domUtils.js";
|
|
17
17
|
import { GRID_CHECKBOX_SELECTION_COL_DEF } from "../colDef/gridCheckboxSelectionColDef.js";
|
|
18
18
|
import { GRID_ACTIONS_COLUMN_TYPE } from "../colDef/gridActionsColDef.js";
|
|
19
|
-
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../constants
|
|
19
|
+
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../internals/constants.js";
|
|
20
20
|
import { gridSortModelSelector } from "../hooks/features/sorting/gridSortingSelector.js";
|
|
21
21
|
import { gridRowMaximumTreeDepthSelector } from "../hooks/features/rows/gridRowsSelector.js";
|
|
22
22
|
import { gridEditRowsStateSelector } from "../hooks/features/editing/gridEditingSelectors.js";
|
|
@@ -10,6 +10,7 @@ import { getDataGridUtilityClass } from "../../constants/gridClasses.js";
|
|
|
10
10
|
import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js";
|
|
11
11
|
import { useGridApiContext } from "../../hooks/utils/useGridApiContext.js";
|
|
12
12
|
import { isAutogeneratedRowNode } from "../../hooks/features/rows/gridRowsUtils.js";
|
|
13
|
+
import { GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD } from "../../internals/constants.js";
|
|
13
14
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
15
|
const useUtilityClasses = ownerState => {
|
|
15
16
|
const {
|
|
@@ -116,7 +117,7 @@ process.env.NODE_ENV !== "production" ? GridBooleanCellRaw.propTypes = {
|
|
|
116
117
|
const GridBooleanCell = /*#__PURE__*/React.memo(GridBooleanCellRaw);
|
|
117
118
|
export { GridBooleanCell };
|
|
118
119
|
export const renderBooleanCell = params => {
|
|
119
|
-
if (params.field !==
|
|
120
|
+
if (params.field !== GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD && isAutogeneratedRowNode(params.rowNode)) {
|
|
120
121
|
return '';
|
|
121
122
|
}
|
|
122
123
|
return /*#__PURE__*/_jsx(GridBooleanCell, _extends({}, params));
|
|
@@ -7,6 +7,15 @@ import { refType, unstable_useId as useId } from '@mui/utils';
|
|
|
7
7
|
import { styled } from '@mui/material/styles';
|
|
8
8
|
import { useGridRootProps } from "../../../hooks/utils/useGridRootProps.js";
|
|
9
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
export const sanitizeFilterItemValue = value => {
|
|
11
|
+
if (String(value).toLowerCase() === 'true') {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (String(value).toLowerCase() === 'false') {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
};
|
|
10
19
|
const BooleanOperatorContainer = styled('div')({
|
|
11
20
|
display: 'flex',
|
|
12
21
|
alignItems: 'center',
|
|
@@ -27,7 +36,7 @@ function GridFilterInputBoolean(props) {
|
|
|
27
36
|
variant = 'standard'
|
|
28
37
|
} = props,
|
|
29
38
|
others = _objectWithoutPropertiesLoose(props, _excluded);
|
|
30
|
-
const [filterValueState, setFilterValueState] = React.useState(item.value
|
|
39
|
+
const [filterValueState, setFilterValueState] = React.useState(sanitizeFilterItemValue(item.value));
|
|
31
40
|
const rootProps = useGridRootProps();
|
|
32
41
|
const labelId = useId();
|
|
33
42
|
const selectId = useId();
|
|
@@ -35,14 +44,14 @@ function GridFilterInputBoolean(props) {
|
|
|
35
44
|
const isSelectNative = baseSelectProps.native ?? false;
|
|
36
45
|
const baseSelectOptionProps = rootProps.slotProps?.baseSelectOption || {};
|
|
37
46
|
const onFilterChange = React.useCallback(event => {
|
|
38
|
-
const value = event.target.value;
|
|
47
|
+
const value = sanitizeFilterItemValue(event.target.value);
|
|
39
48
|
setFilterValueState(value);
|
|
40
49
|
applyValue(_extends({}, item, {
|
|
41
|
-
value
|
|
50
|
+
value
|
|
42
51
|
}));
|
|
43
52
|
}, [applyValue, item]);
|
|
44
53
|
React.useEffect(() => {
|
|
45
|
-
setFilterValueState(item.value
|
|
54
|
+
setFilterValueState(sanitizeFilterItemValue(item.value));
|
|
46
55
|
}, [item.value]);
|
|
47
56
|
const label = labelProp ?? apiRef.current.getLocaleText('filterPanelInputLabel');
|
|
48
57
|
return /*#__PURE__*/_jsxs(BooleanOperatorContainer, {
|
|
@@ -57,7 +66,7 @@ function GridFilterInputBoolean(props) {
|
|
|
57
66
|
labelId: labelId,
|
|
58
67
|
id: selectId,
|
|
59
68
|
label: label,
|
|
60
|
-
value: filterValueState,
|
|
69
|
+
value: filterValueState === undefined ? '' : String(filterValueState),
|
|
61
70
|
onChange: onFilterChange,
|
|
62
71
|
variant: variant,
|
|
63
72
|
notched: variant === 'outlined' ? true : undefined,
|
|
@@ -70,9 +70,13 @@ const GridVirtualScrollbar = /*#__PURE__*/React.forwardRef(function GridVirtualS
|
|
|
70
70
|
const onScrollerScroll = useEventCallback(() => {
|
|
71
71
|
const scroller = apiRef.current.virtualScrollerRef.current;
|
|
72
72
|
const scrollbar = scrollbarRef.current;
|
|
73
|
+
if (!scrollbar) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
73
76
|
if (scroller[propertyScroll] === lastPosition.current) {
|
|
74
77
|
return;
|
|
75
78
|
}
|
|
79
|
+
lastPosition.current = scroller[propertyScroll];
|
|
76
80
|
if (isLocked.current) {
|
|
77
81
|
isLocked.current = false;
|
|
78
82
|
return;
|
|
@@ -80,11 +84,13 @@ const GridVirtualScrollbar = /*#__PURE__*/React.forwardRef(function GridVirtualS
|
|
|
80
84
|
isLocked.current = true;
|
|
81
85
|
const value = scroller[propertyScroll] / contentSize;
|
|
82
86
|
scrollbar[propertyScroll] = value * scrollbarInnerSize;
|
|
83
|
-
lastPosition.current = scroller[propertyScroll];
|
|
84
87
|
});
|
|
85
88
|
const onScrollbarScroll = useEventCallback(() => {
|
|
86
89
|
const scroller = apiRef.current.virtualScrollerRef.current;
|
|
87
90
|
const scrollbar = scrollbarRef.current;
|
|
91
|
+
if (!scrollbar) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
88
94
|
if (isLocked.current) {
|
|
89
95
|
isLocked.current = false;
|
|
90
96
|
return;
|
|
@@ -223,7 +223,6 @@ export const useGridColumnHeaders = props => {
|
|
|
223
223
|
return null;
|
|
224
224
|
}
|
|
225
225
|
const {
|
|
226
|
-
renderedColumns,
|
|
227
226
|
firstColumnToRender,
|
|
228
227
|
lastColumnToRender
|
|
229
228
|
} = columnsToRender;
|
|
@@ -292,7 +291,7 @@ export const useGridColumnHeaders = props => {
|
|
|
292
291
|
pinnedPosition: pinnedPosition,
|
|
293
292
|
style: style,
|
|
294
293
|
indexInSection: indexInSection,
|
|
295
|
-
sectionLength:
|
|
294
|
+
sectionLength: rowStructure.length,
|
|
296
295
|
gridHasFiller: gridHasFiller
|
|
297
296
|
}, index);
|
|
298
297
|
});
|
|
@@ -241,26 +241,45 @@ export const useGridCellEditing = (apiRef, props) => {
|
|
|
241
241
|
mode: GridCellModes.Edit
|
|
242
242
|
}, other));
|
|
243
243
|
}, [throwIfNotEditable, throwIfNotInMode, updateFieldInCellModesModel]);
|
|
244
|
-
const updateStateToStartCellEditMode = useEventCallback(params => {
|
|
244
|
+
const updateStateToStartCellEditMode = useEventCallback(async params => {
|
|
245
245
|
const {
|
|
246
246
|
id,
|
|
247
247
|
field,
|
|
248
248
|
deleteValue,
|
|
249
249
|
initialValue
|
|
250
250
|
} = params;
|
|
251
|
-
|
|
251
|
+
const value = apiRef.current.getCellValue(id, field);
|
|
252
|
+
let newValue = value;
|
|
252
253
|
if (deleteValue) {
|
|
253
254
|
newValue = getDefaultCellValue(apiRef.current.getColumn(field));
|
|
254
255
|
} else if (initialValue) {
|
|
255
256
|
newValue = initialValue;
|
|
256
257
|
}
|
|
257
|
-
const
|
|
258
|
+
const column = apiRef.current.getColumn(field);
|
|
259
|
+
const shouldProcessEditCellProps = !!column.preProcessEditCellProps && deleteValue;
|
|
260
|
+
let newProps = {
|
|
258
261
|
value: newValue,
|
|
259
262
|
error: false,
|
|
260
|
-
isProcessingProps:
|
|
263
|
+
isProcessingProps: shouldProcessEditCellProps
|
|
261
264
|
};
|
|
262
265
|
updateOrDeleteFieldState(id, field, newProps);
|
|
263
266
|
apiRef.current.setCellFocus(id, field);
|
|
267
|
+
if (shouldProcessEditCellProps) {
|
|
268
|
+
newProps = await Promise.resolve(column.preProcessEditCellProps({
|
|
269
|
+
id,
|
|
270
|
+
row: apiRef.current.getRow(id),
|
|
271
|
+
props: newProps,
|
|
272
|
+
hasChanged: newValue !== value
|
|
273
|
+
}));
|
|
274
|
+
// Check if still in edit mode before updating
|
|
275
|
+
if (apiRef.current.getCellMode(id, field) === GridCellModes.Edit) {
|
|
276
|
+
const editingState = gridEditRowsStateSelector(apiRef.current.state);
|
|
277
|
+
updateOrDeleteFieldState(id, field, _extends({}, newProps, {
|
|
278
|
+
value: editingState[id][field].value,
|
|
279
|
+
isProcessingProps: false
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
264
283
|
});
|
|
265
284
|
const stopCellEditMode = React.useCallback(params => {
|
|
266
285
|
const {
|
|
@@ -318,10 +318,11 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
318
318
|
if (!cellParams.isEditable) {
|
|
319
319
|
return acc;
|
|
320
320
|
}
|
|
321
|
+
const column = apiRef.current.getColumn(field);
|
|
321
322
|
let newValue = apiRef.current.getCellValue(id, field);
|
|
322
323
|
if (fieldToFocus === field && (deleteValue || initialValue)) {
|
|
323
324
|
if (deleteValue) {
|
|
324
|
-
newValue = getDefaultCellValue(
|
|
325
|
+
newValue = getDefaultCellValue(column);
|
|
325
326
|
} else if (initialValue) {
|
|
326
327
|
newValue = initialValue;
|
|
327
328
|
}
|
|
@@ -329,7 +330,7 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
329
330
|
acc[field] = {
|
|
330
331
|
value: newValue,
|
|
331
332
|
error: false,
|
|
332
|
-
isProcessingProps:
|
|
333
|
+
isProcessingProps: !!column.preProcessEditCellProps && deleteValue
|
|
333
334
|
};
|
|
334
335
|
return acc;
|
|
335
336
|
}, {});
|
|
@@ -337,6 +338,26 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
337
338
|
if (fieldToFocus) {
|
|
338
339
|
apiRef.current.setCellFocus(id, fieldToFocus);
|
|
339
340
|
}
|
|
341
|
+
columnFields.filter(field => !!apiRef.current.getColumn(field).preProcessEditCellProps && deleteValue).forEach(field => {
|
|
342
|
+
const column = apiRef.current.getColumn(field);
|
|
343
|
+
const value = apiRef.current.getCellValue(id, field);
|
|
344
|
+
const newValue = deleteValue ? getDefaultCellValue(column) : initialValue ?? value;
|
|
345
|
+
Promise.resolve(column.preProcessEditCellProps({
|
|
346
|
+
id,
|
|
347
|
+
row: apiRef.current.getRow(id),
|
|
348
|
+
props: newProps[field],
|
|
349
|
+
hasChanged: newValue !== value
|
|
350
|
+
})).then(processedProps => {
|
|
351
|
+
// Check if still in edit mode before updating
|
|
352
|
+
if (apiRef.current.getRowMode(id) === GridRowModes.Edit) {
|
|
353
|
+
const editingState = gridEditRowsStateSelector(apiRef.current.state);
|
|
354
|
+
updateOrDeleteFieldState(id, field, _extends({}, processedProps, {
|
|
355
|
+
value: editingState[id][field].value,
|
|
356
|
+
isProcessingProps: false
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
});
|
|
340
361
|
});
|
|
341
362
|
const stopRowEditMode = React.useCallback(params => {
|
|
342
363
|
const {
|
|
@@ -335,7 +335,7 @@ export const useGridFocus = (apiRef, props) => {
|
|
|
335
335
|
paginationMode: props.paginationMode
|
|
336
336
|
});
|
|
337
337
|
const nextRow = currentPage.rows[clamp(lastFocusedRowIndex, 0, currentPage.rows.length - 1)];
|
|
338
|
-
nextRowId = nextRow
|
|
338
|
+
nextRowId = nextRow?.id ?? null;
|
|
339
339
|
}
|
|
340
340
|
apiRef.current.setState(state => _extends({}, state, {
|
|
341
341
|
focus: {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useRtl } from '@mui/system/RtlProvider';
|
|
3
|
+
import { GRID_TREE_DATA_GROUPING_FIELD, GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../../../internals/constants.js";
|
|
4
|
+
import { isGroupingColumn } from "../../../internals/utils/gridRowGroupingUtils.js";
|
|
3
5
|
import { gridVisibleColumnDefinitionsSelector, gridVisibleColumnFieldsSelector } from "../columns/gridColumnsSelector.js";
|
|
4
6
|
import { useGridLogger } from "../../utils/useGridLogger.js";
|
|
5
7
|
import { useGridApiEventHandler } from "../../utils/useGridApiEventHandler.js";
|
|
@@ -9,7 +11,6 @@ import { GRID_CHECKBOX_SELECTION_COL_DEF } from "../../../colDef/gridCheckboxSel
|
|
|
9
11
|
import { gridClasses } from "../../../constants/gridClasses.js";
|
|
10
12
|
import { GridCellModes } from "../../../models/gridEditRowModel.js";
|
|
11
13
|
import { isNavigationKey } from "../../../utils/keyboardUtils.js";
|
|
12
|
-
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../../../constants/gridDetailPanelToggleField.js";
|
|
13
14
|
import { gridFocusColumnGroupHeaderSelector } from "../focus/index.js";
|
|
14
15
|
import { gridColumnGroupsHeaderMaxDepthSelector } from "../columnGrouping/gridColumnGroupsSelector.js";
|
|
15
16
|
import { gridHeaderFilteringEditFieldSelector, gridHeaderFilteringMenuSelector } from "../headerFiltering/gridHeaderFilteringSelectors.js";
|
|
@@ -458,9 +459,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
|
|
|
458
459
|
break;
|
|
459
460
|
}
|
|
460
461
|
const colDef = params.colDef;
|
|
461
|
-
if (colDef &&
|
|
462
|
-
// `GRID_TREE_DATA_GROUPING_FIELD` from the Pro package
|
|
463
|
-
colDef.field === '__tree_data_group__') {
|
|
462
|
+
if (colDef && (colDef.field === GRID_TREE_DATA_GROUPING_FIELD || isGroupingColumn(colDef.field))) {
|
|
464
463
|
break;
|
|
465
464
|
}
|
|
466
465
|
if (!event.shiftKey && rowIndexBefore < lastRowIndexInPage) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
+
import { warnOnce } from '@mui/x-internals/warning';
|
|
3
4
|
import { gridDimensionsSelector } from "../dimensions/index.js";
|
|
4
5
|
import { useGridApiEventHandler } from "../../utils/useGridApiEventHandler.js";
|
|
5
6
|
export const listViewStateInitializer = (state, props, apiRef) => _extends({}, state, {
|
|
6
|
-
listViewColumn: _extends({}, props.unstable_listColumn, {
|
|
7
|
+
listViewColumn: props.unstable_listColumn ? _extends({}, props.unstable_listColumn, {
|
|
7
8
|
computedWidth: getListColumnWidth(apiRef)
|
|
8
|
-
})
|
|
9
|
+
}) : undefined
|
|
9
10
|
});
|
|
10
11
|
export function useGridListView(apiRef, props) {
|
|
11
12
|
/*
|
|
@@ -48,6 +49,11 @@ export function useGridListView(apiRef, props) {
|
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
}, [apiRef, props.unstable_listColumn]);
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
if (props.unstable_listView && !props.unstable_listColumn) {
|
|
54
|
+
warnOnce(['MUI X: The `unstable_listColumn` prop must be set if `unstable_listView` is enabled.', 'To fix, pass a column definition to the `unstable_listColumn` prop, e.g. `{ field: "example", renderCell: (params) => <div>{params.row.id}</div> }`.', 'For more details, see https://mui.com/x/react-data-grid/list-view/']);
|
|
55
|
+
}
|
|
56
|
+
}, [props.unstable_listView, props.unstable_listColumn]);
|
|
51
57
|
}
|
|
52
58
|
function getListColumnWidth(apiRef) {
|
|
53
59
|
return gridDimensionsSelector(apiRef.current.state).viewportInnerSize.width;
|
|
@@ -4,7 +4,7 @@ import { GridSignature, useGridApiEventHandler } from "../../utils/useGridApiEve
|
|
|
4
4
|
import { useGridApiMethod } from "../../utils/useGridApiMethod.js";
|
|
5
5
|
import { useGridLogger } from "../../utils/useGridLogger.js";
|
|
6
6
|
import { useGridSelector } from "../../utils/useGridSelector.js";
|
|
7
|
-
import { gridRowMaximumTreeDepthSelector, gridRowTreeSelector } from "../rows/gridRowsSelector.js";
|
|
7
|
+
import { gridRowsLookupSelector, gridRowMaximumTreeDepthSelector, gridRowTreeSelector } from "../rows/gridRowsSelector.js";
|
|
8
8
|
import { gridRowSelectionStateSelector, selectedGridRowsSelector, selectedIdsLookupSelector } from "./gridRowSelectionSelector.js";
|
|
9
9
|
import { gridPaginatedVisibleSortedGridRowIdsSelector } from "../pagination/index.js";
|
|
10
10
|
import { gridFocusCellSelector } from "../focus/gridFocusStateSelector.js";
|
|
@@ -13,7 +13,7 @@ import { GRID_CHECKBOX_SELECTION_COL_DEF, GRID_ACTIONS_COLUMN_TYPE } from "../..
|
|
|
13
13
|
import { GridCellModes } from "../../../models/gridEditRowModel.js";
|
|
14
14
|
import { isKeyboardEvent, isNavigationKey } from "../../../utils/keyboardUtils.js";
|
|
15
15
|
import { useGridVisibleRows } from "../../utils/useGridVisibleRows.js";
|
|
16
|
-
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../../../constants
|
|
16
|
+
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../../../internals/constants.js";
|
|
17
17
|
import { gridClasses } from "../../../constants/gridClasses.js";
|
|
18
18
|
import { isEventTargetInPortal } from "../../../utils/domUtils.js";
|
|
19
19
|
import { isMultipleRowSelectionEnabled, findRowsToSelect, findRowsToDeselect } from "./utils.js";
|
|
@@ -171,30 +171,33 @@ export const useGridRowSelection = (apiRef, props) => {
|
|
|
171
171
|
let newSelection;
|
|
172
172
|
if (resetSelection) {
|
|
173
173
|
if (isSelected) {
|
|
174
|
-
newSelection = selectableIds;
|
|
174
|
+
newSelection = new Set(selectableIds);
|
|
175
175
|
if (applyAutoSelection) {
|
|
176
176
|
const addRow = rowId => {
|
|
177
|
-
newSelection.
|
|
177
|
+
newSelection.add(rowId);
|
|
178
178
|
};
|
|
179
179
|
selectableIds.forEach(id => {
|
|
180
180
|
findRowsToSelect(apiRef, tree, id, props.rowSelectionPropagation?.descendants ?? false, props.rowSelectionPropagation?.parents ?? false, addRow);
|
|
181
181
|
});
|
|
182
182
|
}
|
|
183
183
|
} else {
|
|
184
|
-
newSelection =
|
|
184
|
+
newSelection = new Set();
|
|
185
|
+
}
|
|
186
|
+
const currentLookup = selectedIdsLookupSelector(apiRef);
|
|
187
|
+
if (newSelection.size === Object.keys(currentLookup).length && Array.from(newSelection).every(id => currentLookup[id] === id)) {
|
|
188
|
+
return;
|
|
185
189
|
}
|
|
186
190
|
} else {
|
|
187
|
-
|
|
188
|
-
const selectionLookup = _extends({}, selectedIdsLookupSelector(apiRef));
|
|
191
|
+
newSelection = new Set(Object.values(selectedIdsLookupSelector(apiRef)));
|
|
189
192
|
const addRow = rowId => {
|
|
190
|
-
|
|
193
|
+
newSelection.add(rowId);
|
|
191
194
|
};
|
|
192
195
|
const removeRow = rowId => {
|
|
193
|
-
delete
|
|
196
|
+
newSelection.delete(rowId);
|
|
194
197
|
};
|
|
195
198
|
selectableIds.forEach(id => {
|
|
196
199
|
if (isSelected) {
|
|
197
|
-
|
|
200
|
+
newSelection.add(id);
|
|
198
201
|
if (applyAutoSelection) {
|
|
199
202
|
findRowsToSelect(apiRef, tree, id, props.rowSelectionPropagation?.descendants ?? false, props.rowSelectionPropagation?.parents ?? false, addRow);
|
|
200
203
|
}
|
|
@@ -205,11 +208,10 @@ export const useGridRowSelection = (apiRef, props) => {
|
|
|
205
208
|
}
|
|
206
209
|
}
|
|
207
210
|
});
|
|
208
|
-
newSelection = Object.values(selectionLookup);
|
|
209
211
|
}
|
|
210
|
-
const isSelectionValid = newSelection.
|
|
212
|
+
const isSelectionValid = newSelection.size < 2 || canHaveMultipleSelection;
|
|
211
213
|
if (isSelectionValid) {
|
|
212
|
-
apiRef.current.setRowSelectionModel(newSelection);
|
|
214
|
+
apiRef.current.setRowSelectionModel(Array.from(newSelection));
|
|
213
215
|
}
|
|
214
216
|
}, [logger, applyAutoSelection, canHaveMultipleSelection, apiRef, tree, props.rowSelectionPropagation?.descendants, props.rowSelectionPropagation?.parents]);
|
|
215
217
|
const selectRowRange = React.useCallback(({
|
|
@@ -252,13 +254,20 @@ export const useGridRowSelection = (apiRef, props) => {
|
|
|
252
254
|
return;
|
|
253
255
|
}
|
|
254
256
|
const currentSelection = gridRowSelectionStateSelector(apiRef.current.state);
|
|
257
|
+
const rowsLookup = gridRowsLookupSelector(apiRef);
|
|
255
258
|
const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef);
|
|
256
259
|
|
|
257
260
|
// We clone the existing object to avoid mutating the same object returned by the selector to others part of the project
|
|
258
261
|
const selectionLookup = _extends({}, selectedIdsLookupSelector(apiRef));
|
|
262
|
+
const isNonExistent = id => {
|
|
263
|
+
if (props.filterMode === 'server') {
|
|
264
|
+
return !rowsLookup[id];
|
|
265
|
+
}
|
|
266
|
+
return filteredRowsLookup[id] !== true;
|
|
267
|
+
};
|
|
259
268
|
let hasChanged = false;
|
|
260
269
|
currentSelection.forEach(id => {
|
|
261
|
-
if (
|
|
270
|
+
if (isNonExistent(id)) {
|
|
262
271
|
if (props.keepNonExistentRowsSelected) {
|
|
263
272
|
return;
|
|
264
273
|
}
|
|
@@ -284,15 +293,20 @@ export const useGridRowSelection = (apiRef, props) => {
|
|
|
284
293
|
}
|
|
285
294
|
}
|
|
286
295
|
});
|
|
287
|
-
|
|
296
|
+
|
|
297
|
+
// For nested data, on row tree updation (filtering, adding rows, etc.) when the selection is
|
|
298
|
+
// not empty, we need to re-run scanning of the tree to propagate the selection changes
|
|
299
|
+
// Example: A parent whose de-selected children are filtered out should now be selected
|
|
300
|
+
const shouldReapplyPropagation = isNestedData && props.rowSelectionPropagation?.parents && Object.keys(selectionLookup).length > 0;
|
|
301
|
+
if (hasChanged || shouldReapplyPropagation && !sortModelUpdated) {
|
|
288
302
|
const newSelection = Object.values(selectionLookup);
|
|
289
|
-
if (
|
|
303
|
+
if (shouldReapplyPropagation) {
|
|
290
304
|
apiRef.current.selectRows(newSelection, true, true);
|
|
291
305
|
} else {
|
|
292
306
|
apiRef.current.setRowSelectionModel(newSelection);
|
|
293
307
|
}
|
|
294
308
|
}
|
|
295
|
-
}, [apiRef, isNestedData, props.rowSelectionPropagation?.parents, props.keepNonExistentRowsSelected, tree]);
|
|
309
|
+
}, [apiRef, isNestedData, props.rowSelectionPropagation?.parents, props.keepNonExistentRowsSelected, props.filterMode, tree]);
|
|
296
310
|
const handleSingleRowSelection = React.useCallback((id, event) => {
|
|
297
311
|
const hasCtrlKey = event.metaKey || event.ctrlKey;
|
|
298
312
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import useLazyRef from '@mui/utils/useLazyRef';
|
|
4
|
+
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../../../internals/constants.js";
|
|
4
5
|
import { gridVisibleColumnDefinitionsSelector } from "../columns/gridColumnsSelector.js";
|
|
5
6
|
import { useGridVisibleRows } from "../../utils/useGridVisibleRows.js";
|
|
6
7
|
import { gridRenderContextSelector } from "../virtualization/gridVirtualizationSelectors.js";
|
|
7
8
|
import { useGridSelector } from "../../utils/useGridSelector.js";
|
|
8
9
|
import { getUnprocessedRange, isRowRangeUpdated, isRowContextInitialized, getCellValue } from "./gridRowSpanningUtils.js";
|
|
10
|
+
import { GRID_CHECKBOX_SELECTION_FIELD } from "../../../colDef/gridCheckboxSelectionColDef.js";
|
|
9
11
|
const EMPTY_STATE = {
|
|
10
12
|
spannedCells: {},
|
|
11
13
|
hiddenCells: {},
|
|
@@ -15,7 +17,7 @@ const EMPTY_RANGE = {
|
|
|
15
17
|
firstRowIndex: 0,
|
|
16
18
|
lastRowIndex: 0
|
|
17
19
|
};
|
|
18
|
-
const skippedFields = new Set([
|
|
20
|
+
const skippedFields = new Set([GRID_CHECKBOX_SELECTION_FIELD, '__reorder__', GRID_DETAIL_PANEL_TOGGLE_FIELD]);
|
|
19
21
|
/**
|
|
20
22
|
* Default number of rows to process during state initialization to avoid flickering.
|
|
21
23
|
* Number `20` is arbitrarily chosen to be large enough to cover most of the cases without
|
|
@@ -48,8 +48,6 @@ export const useGridScroll = (apiRef, props) => {
|
|
|
48
48
|
const logger = useGridLogger(apiRef, 'useGridScroll');
|
|
49
49
|
const colRef = apiRef.current.columnHeadersContainerRef;
|
|
50
50
|
const virtualScrollerRef = apiRef.current.virtualScrollerRef;
|
|
51
|
-
const virtualScrollbarHorizontalRef = apiRef.current.virtualScrollbarHorizontalRef;
|
|
52
|
-
const virtualScrollbarVerticalRef = apiRef.current.virtualScrollbarVerticalRef;
|
|
53
51
|
const visibleSortedRows = useGridSelector(apiRef, gridExpandedSortedRowEntriesSelector);
|
|
54
52
|
const scrollToIndexes = React.useCallback(params => {
|
|
55
53
|
const dimensions = gridDimensionsSelector(apiRef.current.state);
|
|
@@ -103,20 +101,18 @@ export const useGridScroll = (apiRef, props) => {
|
|
|
103
101
|
return false;
|
|
104
102
|
}, [logger, apiRef, virtualScrollerRef, props.pagination, visibleSortedRows, props.unstable_listView]);
|
|
105
103
|
const scroll = React.useCallback(params => {
|
|
106
|
-
if (virtualScrollerRef.current &&
|
|
104
|
+
if (virtualScrollerRef.current && params.left !== undefined && colRef.current) {
|
|
107
105
|
const direction = isRtl ? -1 : 1;
|
|
108
106
|
colRef.current.scrollLeft = params.left;
|
|
109
107
|
virtualScrollerRef.current.scrollLeft = direction * params.left;
|
|
110
|
-
virtualScrollbarHorizontalRef.current.scrollLeft = direction * params.left;
|
|
111
108
|
logger.debug(`Scrolling left: ${params.left}`);
|
|
112
109
|
}
|
|
113
|
-
if (virtualScrollerRef.current &&
|
|
110
|
+
if (virtualScrollerRef.current && params.top !== undefined) {
|
|
114
111
|
virtualScrollerRef.current.scrollTop = params.top;
|
|
115
|
-
virtualScrollbarVerticalRef.current.scrollTop = params.top;
|
|
116
112
|
logger.debug(`Scrolling top: ${params.top}`);
|
|
117
113
|
}
|
|
118
114
|
logger.debug(`Scrolling, updating container, and viewport`);
|
|
119
|
-
}, [virtualScrollerRef,
|
|
115
|
+
}, [virtualScrollerRef, isRtl, colRef, logger]);
|
|
120
116
|
const getScrollPosition = React.useCallback(() => {
|
|
121
117
|
if (!virtualScrollerRef?.current) {
|
|
122
118
|
return {
|
|
@@ -382,7 +382,7 @@ export const useGridVirtualScroller = () => {
|
|
|
382
382
|
flexShrink: 0
|
|
383
383
|
};
|
|
384
384
|
if (rootProps.autoHeight && currentPage.rows.length === 0) {
|
|
385
|
-
size.
|
|
385
|
+
size.flexBasis = getMinimalContentHeight(apiRef); // Give room to show the overlay when there no rows.
|
|
386
386
|
}
|
|
387
387
|
return size;
|
|
388
388
|
}, [apiRef, columnsTotalWidth, contentHeight, needsHorizontalScrollbar, rootProps.autoHeight, currentPage.rows.length]);
|
package/modern/index.js
CHANGED
|
@@ -72,4 +72,5 @@ export * from "../utils/cellBorderUtils.js";
|
|
|
72
72
|
export { useGridPrivateApiContext } from "../hooks/utils/useGridPrivateApiContext.js";
|
|
73
73
|
export * from "../hooks/utils/index.js";
|
|
74
74
|
export { serializeCellValue } from "../hooks/features/export/serializers/csvSerializer.js";
|
|
75
|
-
export * from "./utils/index.js";
|
|
75
|
+
export * from "./utils/index.js";
|
|
76
|
+
export * from "./constants.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD } from "../constants.js";
|
|
2
|
+
export const getRowGroupingCriteriaFromGroupingField = groupingColDefField => {
|
|
3
|
+
const match = groupingColDefField.match(/^__row_group_by_columns_group_(.*)__$/);
|
|
4
|
+
if (!match) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return match[1];
|
|
8
|
+
};
|
|
9
|
+
export const isGroupingColumn = field => field === GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD || getRowGroupingCriteriaFromGroupingField(field) !== null;
|
|
@@ -8,13 +8,11 @@ var _GridFilterInputBoolean = require("../components/panel/filterPanel/GridFilte
|
|
|
8
8
|
const getGridBooleanOperators = () => [{
|
|
9
9
|
value: 'is',
|
|
10
10
|
getApplyFilterFn: filterItem => {
|
|
11
|
-
|
|
11
|
+
const sanitizedValue = (0, _GridFilterInputBoolean.sanitizeFilterItemValue)(filterItem.value);
|
|
12
|
+
if (sanitizedValue === undefined) {
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
return value => {
|
|
16
|
-
return Boolean(value) === valueAsBoolean;
|
|
17
|
-
};
|
|
15
|
+
return value => Boolean(value) === sanitizedValue;
|
|
18
16
|
},
|
|
19
17
|
InputComponent: _GridFilterInputBoolean.GridFilterInputBoolean
|
|
20
18
|
}];
|