@mui/x-data-grid 8.22.0 → 8.22.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 CHANGED
@@ -5,6 +5,107 @@
5
5
  All notable changes to this project will be documented in this file.
6
6
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
7
7
 
8
+ ## 8.22.1
9
+
10
+ _Dec 17, 2025_
11
+
12
+ We'd like to extend a big thank you to the 13 contributors who made this release possible. Here are some highlights ✨:
13
+
14
+ - 🌎 Improve Swedish (sv-SE) locale on the Data Grid
15
+ - 🐞 Bugfixes
16
+
17
+ Special thanks go out to the community members for their valuable contributions:
18
+ @KyeongJooni, @VismaAndreasIvarsson
19
+
20
+ The following team members contributed to this release:
21
+ @alelthomas, @alexfauquette, @arminmeh, @bernardobelchior, @Janpot, @JCQuintas, @mapache-salvaje, @michelengelen, @mj12albert, @prakhargupta1, @romgrk, @siriwatknp
22
+
23
+ ### Data Grid
24
+
25
+ #### `@mui/x-data-grid@8.22.1`
26
+
27
+ - [data grid] Fix column menu keyboard shortcut (#20621) @mj12albert
28
+ - [data grid] Fix row checkbox disabled state on first render and keep cell focusable (ARIA) (#20641) @michelengelen
29
+ - [data grid] Fix tree data selection bug (#20528) @michelengelen
30
+ - [data grid] Prevent clear cell selection on edit mode (#20544) @siriwatknp
31
+ - [data grid] Refactor column merge logic to prioritize defined properties only (#20640) @michelengelen
32
+ - [data grid] Reset row spanning on row expansion change (#20661) @siriwatknp
33
+ - [data grid] Resize newly added rows while resize action is happening (#20676)
34
+ - [l10n] Improve Swedish (sv-SE) locale (#20682) @VismaAndreasIvarsson
35
+
36
+ #### `@mui/x-data-grid-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
37
+
38
+ Same changes as in `@mui/x-data-grid@8.22.1`.
39
+
40
+ #### `@mui/x-data-grid-premium@8.22.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
41
+
42
+ Same changes as in `@mui/x-data-grid-pro@8.22.1`, plus:
43
+
44
+ - [DataGridPremium] Import `useId()` from `@mui/utils` to maintain React 17 compatibility (#20635) @arminmeh
45
+
46
+ ### Date and Time Pickers
47
+
48
+ #### `@mui/x-date-pickers@8.22.1`
49
+
50
+ - [pickers] Add minutesStep validation test (#20672) @KyeongJooni
51
+ - [pickers] Fix `onAccept()` returning wrong year after selecting year then month (#20639) @michelengelen
52
+
53
+ #### `@mui/x-date-pickers-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
54
+
55
+ Same changes as in `@mui/x-date-pickers@8.22.1`.
56
+
57
+ ### Charts
58
+
59
+ #### `@mui/x-charts@8.22.1`
60
+
61
+ - [charts] Extract `FocusedPieArc` from `PieArcPlot` (#20613) @alexfauquette
62
+ - [charts] Fix regression on the highlight control (#20627) @alexfauquette
63
+ - [charts] Refactor: `useSelector()` => `store.use()` (#20681) @romgrk
64
+ - [charts] Remove duplicated types (#20694) @alexfauquette
65
+ - [charts] Remove unused generics from bar charts (#20642) @bernardobelchior
66
+ - [charts] Simplify tooltip position getter for pie chart (#20625) @alexfauquette
67
+
68
+ #### `@mui/x-charts-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
69
+
70
+ Same changes as in `@mui/x-charts@8.22.1`, plus:
71
+
72
+ - [charts-pro] Add heatmap performance benchmark (#20695) @bernardobelchior
73
+
74
+ #### `@mui/x-charts-premium@8.22.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
75
+
76
+ Same changes as in `@mui/x-charts-pro@8.22.1`, plus:
77
+
78
+ - [charts-premium] Create `BarChartPremium` (#20643) @bernardobelchior
79
+
80
+ ### Tree View
81
+
82
+ #### `@mui/x-tree-view@8.22.1`
83
+
84
+ Internal changes.
85
+
86
+ #### `@mui/x-tree-view-pro@8.22.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
87
+
88
+ Same changes as in `@mui/x-tree-view@8.22.1`.
89
+
90
+ ### Codemod
91
+
92
+ #### `@mui/x-codemod@8.22.1`
93
+
94
+ Internal changes.
95
+
96
+ ### Docs
97
+
98
+ - [docs] Add button to GitHub source code for the Data Grid advanced demos (DX-50) (#20633) @alelthomas
99
+ - [docs] Remove `seriesConfig` to prevent future confusion (#20678) @alexfauquette
100
+ - [docs] Revise the Data Grid's API object doc for clarity and style (#20649) @mapache-salvaje
101
+ - [docs] Update list of charts (#20479) @prakhargupta1
102
+
103
+ ### Core
104
+
105
+ - [code-infra] Regression tests improvements (#20441) @Janpot
106
+ - [code-infra] Test utils upgrade (#20592) @Janpot
107
+ - [code-infra] Try to fix the Tree View flacky tests (#20573) @JCQuintas
108
+
8
109
  ## 8.22.0
9
110
 
10
111
  _Dec 11, 2025_
@@ -65,13 +65,13 @@ const GridCellCheckboxForwardRef = exports.GridCellCheckboxForwardRef = (0, _for
65
65
  apiRef.current.publishEvent('rowSelectionCheckboxChange', params, event);
66
66
  };
67
67
  React.useLayoutEffect(() => {
68
- if (tabIndex === 0) {
68
+ if (tabIndex === 0 && !disabled) {
69
69
  const element = apiRef.current.getCellElement(id, field);
70
70
  if (element) {
71
71
  element.tabIndex = -1;
72
72
  }
73
73
  }
74
- }, [apiRef, tabIndex, id, field]);
74
+ }, [apiRef, tabIndex, id, field, disabled]);
75
75
  const handleKeyDown = (0, _useEventCallback.default)(event => {
76
76
  if (event.key === ' ') {
77
77
  // We call event.stopPropagation to avoid selecting the row and also scrolling to bottom
@@ -98,12 +98,13 @@ const GridCellCheckboxForwardRef = exports.GridCellCheckboxForwardRef = (0, _for
98
98
  }
99
99
  const label = apiRef.current.getLocaleText(isChecked && !isIndeterminate ? 'checkboxSelectionUnselectRow' : 'checkboxSelectionSelectRow');
100
100
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(rootProps.slots.baseCheckbox, (0, _extends2.default)({
101
- tabIndex: tabIndex,
101
+ tabIndex: disabled ? -1 : tabIndex,
102
102
  checked: isChecked && !isIndeterminate,
103
103
  onChange: handleChange,
104
104
  onClick: handleClick,
105
105
  onMouseDown: handleMouseDown,
106
106
  className: (0, _clsx.default)(classes.root, disabled && 'Mui-disabled'),
107
+ disabled: disabled,
107
108
  material: {
108
109
  disableRipple: disabled
109
110
  },
@@ -58,13 +58,13 @@ const GridCellCheckboxForwardRef = forwardRef(function GridCellCheckboxRenderer(
58
58
  apiRef.current.publishEvent('rowSelectionCheckboxChange', params, event);
59
59
  };
60
60
  React.useLayoutEffect(() => {
61
- if (tabIndex === 0) {
61
+ if (tabIndex === 0 && !disabled) {
62
62
  const element = apiRef.current.getCellElement(id, field);
63
63
  if (element) {
64
64
  element.tabIndex = -1;
65
65
  }
66
66
  }
67
- }, [apiRef, tabIndex, id, field]);
67
+ }, [apiRef, tabIndex, id, field, disabled]);
68
68
  const handleKeyDown = useEventCallback(event => {
69
69
  if (event.key === ' ') {
70
70
  // We call event.stopPropagation to avoid selecting the row and also scrolling to bottom
@@ -91,12 +91,13 @@ const GridCellCheckboxForwardRef = forwardRef(function GridCellCheckboxRenderer(
91
91
  }
92
92
  const label = apiRef.current.getLocaleText(isChecked && !isIndeterminate ? 'checkboxSelectionUnselectRow' : 'checkboxSelectionSelectRow');
93
93
  return /*#__PURE__*/_jsx(rootProps.slots.baseCheckbox, _extends({
94
- tabIndex: tabIndex,
94
+ tabIndex: disabled ? -1 : tabIndex,
95
95
  checked: isChecked && !isIndeterminate,
96
96
  onChange: handleChange,
97
97
  onClick: handleClick,
98
98
  onMouseDown: handleMouseDown,
99
99
  className: clsx(classes.root, disabled && 'Mui-disabled'),
100
+ disabled: disabled,
100
101
  material: {
101
102
  disableRipple: disabled
102
103
  },
@@ -7,7 +7,8 @@ export const propsStateInitializer = (state, props) => {
7
7
  props: {
8
8
  listView: props.listView,
9
9
  getRowId: props.getRowId,
10
- isCellEditable: props.isCellEditable
10
+ isCellEditable: props.isCellEditable,
11
+ isRowSelectable: props.isRowSelectable
11
12
  }
12
13
  });
13
14
  };
@@ -17,6 +17,7 @@ import { useTimeout } from "../../utils/useTimeout.js";
17
17
  import { GridPinnedColumnPosition } from "../columns/gridColumnsInterfaces.js";
18
18
  import { gridColumnsStateSelector } from "../columns/index.js";
19
19
  import { gridDimensionsSelector } from "../dimensions/index.js";
20
+ import { gridResizingColumnFieldSelector } from "./columnResizeSelector.js";
20
21
  function trackFinger(event, currentTouchId) {
21
22
  if (currentTouchId !== undefined && event.changedTouches) {
22
23
  for (let i = 0; i < event.changedTouches.length; i += 1) {
@@ -320,6 +321,11 @@ export const useGridColumnResize = (apiRef, props) => {
320
321
  apiRef.current.publishEvent('columnResizeStop', null, nativeEvent);
321
322
  });
322
323
  };
324
+ const setCellElementsRef = () => {
325
+ if (refs.columnHeaderElement) {
326
+ refs.cellElements = findGridCellElementsFromCol(refs.columnHeaderElement, apiRef.current);
327
+ }
328
+ };
323
329
  const storeReferences = (colDef, separator, xStart) => {
324
330
  const root = apiRef.current.rootElementRef.current;
325
331
  refs.initialColWidth = colDef.computedWidth;
@@ -331,7 +337,7 @@ export const useGridColumnResize = (apiRef, props) => {
331
337
  refs.headerFilterElement = headerFilterElement;
332
338
  }
333
339
  refs.groupHeaderElements = findGroupHeaderElementsFromField(apiRef.current.columnHeadersContainerRef?.current, colDef.field);
334
- refs.cellElements = findGridCellElementsFromCol(refs.columnHeaderElement, apiRef.current);
340
+ setCellElementsRef();
335
341
  refs.fillerLeft = findGridElement(apiRef.current, isRtl ? 'filler--pinnedRight' : 'filler--pinnedLeft');
336
342
  refs.fillerRight = findGridElement(apiRef.current, isRtl ? 'filler--pinnedLeft' : 'filler--pinnedRight');
337
343
  const pinnedPosition = apiRef.current.unstable_applyPipeProcessors('isColumnPinned', false, refs.colDef.field);
@@ -578,6 +584,15 @@ export const useGridColumnResize = (apiRef, props) => {
578
584
  useGridEvent(apiRef, 'columnResizeStart', handleResizeStart);
579
585
  useGridEvent(apiRef, 'columnSeparatorMouseDown', handleColumnResizeMouseDown);
580
586
  useGridEvent(apiRef, 'columnSeparatorDoubleClick', handleColumnSeparatorDoubleClick);
587
+ useGridEvent(apiRef, 'rowsSet', () => {
588
+ // if the user is still resizing the column, update the cell references included in the resize action
589
+ if (gridResizingColumnFieldSelector(apiRef) !== '') {
590
+ // wait until the rows are in the DOM
591
+ requestAnimationFrame(() => {
592
+ setCellElementsRef();
593
+ });
594
+ }
595
+ });
581
596
  useGridEventPriority(apiRef, 'columnResize', props.onColumnResize);
582
597
  useGridEventPriority(apiRef, 'columnWidthChange', props.onColumnWidthChange);
583
598
  };
@@ -283,9 +283,17 @@ export const createColumnsState = ({
283
283
  }
284
284
  }
285
285
  });
286
- columnsState.lookup[field] = resolveProps(existingState, _extends({}, getDefaultColTypeDef(newColumn.type), newColumn, {
287
- hasBeenResized
288
- }));
286
+ const mergedProps = _extends({}, getDefaultColTypeDef(newColumn.type), {
287
+ hasBeenResized,
288
+ field
289
+ });
290
+ let key;
291
+ for (key in newColumn) {
292
+ if (newColumn[key] !== undefined && key !== 'field') {
293
+ mergedProps[key] = newColumn[key];
294
+ }
295
+ }
296
+ columnsState.lookup[field] = resolveProps(existingState, mergedProps);
289
297
  });
290
298
  if (keepOnlyColumnsToUpsert && !isInsideStateInitializer) {
291
299
  Object.keys(columnsState.lookup).forEach(field => {
@@ -106,7 +106,7 @@ export const useGridKeyboardNavigation = (apiRef, props) => {
106
106
  // There is one exception for the checkBoxHeader
107
107
  return;
108
108
  }
109
- if (!isNavigationKey(event.key) && event.key !== 'Tab') {
109
+ if (!isNavigationKey(event.key) && event.key !== 'Tab' && event.key !== 'Enter') {
110
110
  return;
111
111
  }
112
112
 
@@ -63,10 +63,21 @@ export const checkboxPropsSelector = createSelector(gridColumnDefinitionsSelecto
63
63
  if (node?.type === 'group') {
64
64
  node.children.forEach(traverseDescendants);
65
65
  }
66
- if (rowSelectionManager.has(itemToTraverseId)) {
67
- hasSelectedDescendant = true;
68
- } else {
69
- hasUnSelectedDescendant = true;
66
+ // Check if row is selectable before considering it for parent selection state
67
+ const descendantRowParams = {
68
+ id: itemToTraverseId,
69
+ row: rowsLookup[itemToTraverseId],
70
+ columns
71
+ };
72
+ const rowIsSelectable = typeof isRowSelectable === 'function' ? isRowSelectable(descendantRowParams) : true;
73
+
74
+ // Only consider selectable rows when determining parent selection state
75
+ if (rowIsSelectable) {
76
+ if (rowSelectionManager.has(itemToTraverseId)) {
77
+ hasSelectedDescendant = true;
78
+ } else {
79
+ hasUnSelectedDescendant = true;
80
+ }
70
81
  }
71
82
  };
72
83
  traverseDescendants(groupId);
@@ -126,21 +137,37 @@ export const findRowsToSelect = (apiRef, tree, selectedRow, autoSelectDescendant
126
137
  }
127
138
  if (autoSelectParents) {
128
139
  const checkAllDescendantsSelected = rowId => {
129
- if (!rowSelectionManager.has(rowId) && !selectedDescendants.has(rowId)) {
130
- return false;
131
- }
132
140
  const node = tree[rowId];
133
141
  if (!node) {
134
142
  return false;
135
143
  }
144
+ // For non-group nodes, check if it's selected or if it's non-selectable
136
145
  if (node.type !== 'group') {
146
+ // If the row is selectable, it must be selected
147
+ if (apiRef.current.isRowSelectable(rowId)) {
148
+ return rowSelectionManager.has(rowId) || selectedDescendants.has(rowId);
149
+ }
150
+ // Non-selectable rows don't affect parent selection
137
151
  return true;
138
152
  }
153
+ // For group nodes, check if it's selected or all its children are selected
154
+ if (rowSelectionManager.has(rowId) || selectedDescendants.has(rowId)) {
155
+ return true;
156
+ }
157
+ // Recursively check all children
139
158
  return node.children.every(checkAllDescendantsSelected);
140
159
  };
141
160
  const traverseParents = rowId => {
142
161
  const siblings = getFilteredRowNodeSiblings(tree, filteredRows, rowId);
143
- if (siblings.length === 0 || siblings.every(checkAllDescendantsSelected)) {
162
+ // Check if all selectable siblings are selected
163
+ const allSelectableSiblingsSelected = siblings.every(siblingId => {
164
+ // Non-selectable siblings don't affect parent selection
165
+ if (!apiRef.current.isRowSelectable(siblingId)) {
166
+ return true;
167
+ }
168
+ return checkAllDescendantsSelected(siblingId);
169
+ });
170
+ if (siblings.length === 0 || allSelectableSiblingsSelected) {
144
171
  const rowNode = tree[rowId];
145
172
  const parent = rowNode?.parent;
146
173
  if (parent != null && parent !== GRID_ROOT_GROUP_ID && apiRef.current.isRowSelectable(parent)) {
@@ -191,6 +191,7 @@ export const useGridRowSpanning = (apiRef, props) => {
191
191
  useGridEvent(apiRef, 'paginationModelChange', runIf(props.rowSpanning, resetRowSpanningState));
192
192
  useGridEvent(apiRef, 'filteredRowsSet', runIf(props.rowSpanning, resetRowSpanningState));
193
193
  useGridEvent(apiRef, 'columnsChange', runIf(props.rowSpanning, resetRowSpanningState));
194
+ useGridEvent(apiRef, 'rowExpansionChange', runIf(props.rowSpanning, resetRowSpanningState));
194
195
  React.useEffect(() => {
195
196
  const store = apiRef.current.virtualizer?.store;
196
197
  if (!store) {
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.22.0
2
+ * @mui/x-data-grid v8.22.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -3,8 +3,8 @@ const svSEGrid = {
3
3
  // Root
4
4
  noRowsLabel: 'Inga rader',
5
5
  noResultsOverlayLabel: 'Inga resultat funna.',
6
- // noColumnsOverlayLabel: 'No columns',
7
- // noColumnsOverlayManageColumns: 'Manage columns',
6
+ noColumnsOverlayLabel: 'Inga kolumner',
7
+ noColumnsOverlayManageColumns: 'Hantera kolumner',
8
8
  // emptyPivotOverlayLabel: 'Add fields to rows, columns, and values to create a pivot table',
9
9
 
10
10
  // Density selector toolbar button text
@@ -14,7 +14,8 @@ const propsStateInitializer = (state, props) => {
14
14
  props: {
15
15
  listView: props.listView,
16
16
  getRowId: props.getRowId,
17
- isCellEditable: props.isCellEditable
17
+ isCellEditable: props.isCellEditable,
18
+ isRowSelectable: props.isRowSelectable
18
19
  }
19
20
  });
20
21
  };
@@ -24,6 +24,7 @@ var _useTimeout = require("../../utils/useTimeout");
24
24
  var _gridColumnsInterfaces = require("../columns/gridColumnsInterfaces");
25
25
  var _columns = require("../columns");
26
26
  var _dimensions = require("../dimensions");
27
+ var _columnResizeSelector = require("./columnResizeSelector");
27
28
  function trackFinger(event, currentTouchId) {
28
29
  if (currentTouchId !== undefined && event.changedTouches) {
29
30
  for (let i = 0; i < event.changedTouches.length; i += 1) {
@@ -328,6 +329,11 @@ const useGridColumnResize = (apiRef, props) => {
328
329
  apiRef.current.publishEvent('columnResizeStop', null, nativeEvent);
329
330
  });
330
331
  };
332
+ const setCellElementsRef = () => {
333
+ if (refs.columnHeaderElement) {
334
+ refs.cellElements = (0, _domUtils.findGridCellElementsFromCol)(refs.columnHeaderElement, apiRef.current);
335
+ }
336
+ };
331
337
  const storeReferences = (colDef, separator, xStart) => {
332
338
  const root = apiRef.current.rootElementRef.current;
333
339
  refs.initialColWidth = colDef.computedWidth;
@@ -339,7 +345,7 @@ const useGridColumnResize = (apiRef, props) => {
339
345
  refs.headerFilterElement = headerFilterElement;
340
346
  }
341
347
  refs.groupHeaderElements = (0, _domUtils.findGroupHeaderElementsFromField)(apiRef.current.columnHeadersContainerRef?.current, colDef.field);
342
- refs.cellElements = (0, _domUtils.findGridCellElementsFromCol)(refs.columnHeaderElement, apiRef.current);
348
+ setCellElementsRef();
343
349
  refs.fillerLeft = (0, _domUtils.findGridElement)(apiRef.current, isRtl ? 'filler--pinnedRight' : 'filler--pinnedLeft');
344
350
  refs.fillerRight = (0, _domUtils.findGridElement)(apiRef.current, isRtl ? 'filler--pinnedLeft' : 'filler--pinnedRight');
345
351
  const pinnedPosition = apiRef.current.unstable_applyPipeProcessors('isColumnPinned', false, refs.colDef.field);
@@ -586,6 +592,15 @@ const useGridColumnResize = (apiRef, props) => {
586
592
  (0, _utils.useGridEvent)(apiRef, 'columnResizeStart', handleResizeStart);
587
593
  (0, _utils.useGridEvent)(apiRef, 'columnSeparatorMouseDown', handleColumnResizeMouseDown);
588
594
  (0, _utils.useGridEvent)(apiRef, 'columnSeparatorDoubleClick', handleColumnSeparatorDoubleClick);
595
+ (0, _utils.useGridEvent)(apiRef, 'rowsSet', () => {
596
+ // if the user is still resizing the column, update the cell references included in the resize action
597
+ if ((0, _columnResizeSelector.gridResizingColumnFieldSelector)(apiRef) !== '') {
598
+ // wait until the rows are in the DOM
599
+ requestAnimationFrame(() => {
600
+ setCellElementsRef();
601
+ });
602
+ }
603
+ });
589
604
  (0, _utils.useGridEventPriority)(apiRef, 'columnResize', props.onColumnResize);
590
605
  (0, _utils.useGridEventPriority)(apiRef, 'columnWidthChange', props.onColumnWidthChange);
591
606
  };
@@ -298,9 +298,17 @@ const createColumnsState = ({
298
298
  }
299
299
  }
300
300
  });
301
- columnsState.lookup[field] = (0, _resolveProps.default)(existingState, (0, _extends2.default)({}, getDefaultColTypeDef(newColumn.type), newColumn, {
302
- hasBeenResized
303
- }));
301
+ const mergedProps = (0, _extends2.default)({}, getDefaultColTypeDef(newColumn.type), {
302
+ hasBeenResized,
303
+ field
304
+ });
305
+ let key;
306
+ for (key in newColumn) {
307
+ if (newColumn[key] !== undefined && key !== 'field') {
308
+ mergedProps[key] = newColumn[key];
309
+ }
310
+ }
311
+ columnsState.lookup[field] = (0, _resolveProps.default)(existingState, mergedProps);
304
312
  });
305
313
  if (keepOnlyColumnsToUpsert && !isInsideStateInitializer) {
306
314
  Object.keys(columnsState.lookup).forEach(field => {
@@ -113,7 +113,7 @@ const useGridKeyboardNavigation = (apiRef, props) => {
113
113
  // There is one exception for the checkBoxHeader
114
114
  return;
115
115
  }
116
- if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab') {
116
+ if (!(0, _keyboardUtils.isNavigationKey)(event.key) && event.key !== 'Tab' && event.key !== 'Enter') {
117
117
  return;
118
118
  }
119
119
 
@@ -70,10 +70,21 @@ const checkboxPropsSelector = exports.checkboxPropsSelector = (0, _createSelecto
70
70
  if (node?.type === 'group') {
71
71
  node.children.forEach(traverseDescendants);
72
72
  }
73
- if (rowSelectionManager.has(itemToTraverseId)) {
74
- hasSelectedDescendant = true;
75
- } else {
76
- hasUnSelectedDescendant = true;
73
+ // Check if row is selectable before considering it for parent selection state
74
+ const descendantRowParams = {
75
+ id: itemToTraverseId,
76
+ row: rowsLookup[itemToTraverseId],
77
+ columns
78
+ };
79
+ const rowIsSelectable = typeof isRowSelectable === 'function' ? isRowSelectable(descendantRowParams) : true;
80
+
81
+ // Only consider selectable rows when determining parent selection state
82
+ if (rowIsSelectable) {
83
+ if (rowSelectionManager.has(itemToTraverseId)) {
84
+ hasSelectedDescendant = true;
85
+ } else {
86
+ hasUnSelectedDescendant = true;
87
+ }
77
88
  }
78
89
  };
79
90
  traverseDescendants(groupId);
@@ -133,21 +144,37 @@ const findRowsToSelect = (apiRef, tree, selectedRow, autoSelectDescendants, auto
133
144
  }
134
145
  if (autoSelectParents) {
135
146
  const checkAllDescendantsSelected = rowId => {
136
- if (!rowSelectionManager.has(rowId) && !selectedDescendants.has(rowId)) {
137
- return false;
138
- }
139
147
  const node = tree[rowId];
140
148
  if (!node) {
141
149
  return false;
142
150
  }
151
+ // For non-group nodes, check if it's selected or if it's non-selectable
143
152
  if (node.type !== 'group') {
153
+ // If the row is selectable, it must be selected
154
+ if (apiRef.current.isRowSelectable(rowId)) {
155
+ return rowSelectionManager.has(rowId) || selectedDescendants.has(rowId);
156
+ }
157
+ // Non-selectable rows don't affect parent selection
158
+ return true;
159
+ }
160
+ // For group nodes, check if it's selected or all its children are selected
161
+ if (rowSelectionManager.has(rowId) || selectedDescendants.has(rowId)) {
144
162
  return true;
145
163
  }
164
+ // Recursively check all children
146
165
  return node.children.every(checkAllDescendantsSelected);
147
166
  };
148
167
  const traverseParents = rowId => {
149
168
  const siblings = getFilteredRowNodeSiblings(tree, filteredRows, rowId);
150
- if (siblings.length === 0 || siblings.every(checkAllDescendantsSelected)) {
169
+ // Check if all selectable siblings are selected
170
+ const allSelectableSiblingsSelected = siblings.every(siblingId => {
171
+ // Non-selectable siblings don't affect parent selection
172
+ if (!apiRef.current.isRowSelectable(siblingId)) {
173
+ return true;
174
+ }
175
+ return checkAllDescendantsSelected(siblingId);
176
+ });
177
+ if (siblings.length === 0 || allSelectableSiblingsSelected) {
151
178
  const rowNode = tree[rowId];
152
179
  const parent = rowNode?.parent;
153
180
  if (parent != null && parent !== _gridRowsUtils.GRID_ROOT_GROUP_ID && apiRef.current.isRowSelectable(parent)) {
@@ -199,6 +199,7 @@ const useGridRowSpanning = (apiRef, props) => {
199
199
  (0, _useGridEvent.useGridEvent)(apiRef, 'paginationModelChange', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
200
200
  (0, _useGridEvent.useGridEvent)(apiRef, 'filteredRowsSet', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
201
201
  (0, _useGridEvent.useGridEvent)(apiRef, 'columnsChange', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
202
+ (0, _useGridEvent.useGridEvent)(apiRef, 'rowExpansionChange', (0, _utils.runIf)(props.rowSpanning, resetRowSpanningState));
202
203
  React.useEffect(() => {
203
204
  const store = apiRef.current.virtualizer?.store;
204
205
  if (!store) {
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.22.0
2
+ * @mui/x-data-grid v8.22.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/locales/svSE.js CHANGED
@@ -9,8 +9,8 @@ const svSEGrid = {
9
9
  // Root
10
10
  noRowsLabel: 'Inga rader',
11
11
  noResultsOverlayLabel: 'Inga resultat funna.',
12
- // noColumnsOverlayLabel: 'No columns',
13
- // noColumnsOverlayManageColumns: 'Manage columns',
12
+ noColumnsOverlayLabel: 'Inga kolumner',
13
+ noColumnsOverlayManageColumns: 'Hantera kolumner',
14
14
  // emptyPivotOverlayLabel: 'Add fields to rows, columns, and values to create a pivot table',
15
15
 
16
16
  // Density selector toolbar button text
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-data-grid",
3
- "version": "8.22.0",
3
+ "version": "8.22.1",
4
4
  "author": "MUI Team",
5
5
  "description": "The Community plan edition of the MUI X Data Grid components.",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "prop-types": "^15.8.1",
44
44
  "use-sync-external-store": "^1.6.0",
45
45
  "@mui/x-internals": "8.22.0",
46
- "@mui/x-virtualizer": "0.2.12"
46
+ "@mui/x-virtualizer": "0.2.13"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@emotion/react": "^11.9.0",