@mui/x-tree-view 9.10.0 → 9.10.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
@@ -1,5 +1,111 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.10.1
4
+
5
+ _Jul 23, 2026_
6
+
7
+ We'd like to extend a big thank you to the 11 contributors who made this release possible. Here are some highlights ✨:
8
+
9
+ - 🦮 Improve accessibility of the Charts and Pickers components.
10
+ - 🐞 Bugfixes
11
+ - 📚 Documentation improvements
12
+
13
+ Special thanks go out to these community members for their valuable contributions:
14
+ @kevincorizi-sbt, @mustafajw07, @SamanPandey-in
15
+
16
+ The following team members contributed to this release:
17
+ @brijeshb42, @hasdfa, @JCQuintas, @LukasTy, @michelengelen, @noraleonte, @rita-codes, @silviuaavram
18
+
19
+ ### Data Grid
20
+
21
+ #### `@mui/x-data-grid@9.10.1`
22
+
23
+ - [data grid] Fix `getColumn` return type not reflecting that it can return undefined (#23165) @JCQuintas
24
+
25
+ #### `@mui/x-data-grid-pro@9.10.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
26
+
27
+ Same changes as in `@mui/x-data-grid@9.10.1`.
28
+
29
+ #### `@mui/x-data-grid-premium@9.10.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
30
+
31
+ Same changes as in `@mui/x-data-grid-pro@9.10.1`.
32
+
33
+ ### Date and Time Pickers
34
+
35
+ #### `@mui/x-date-pickers@9.10.1`
36
+
37
+ - [pickers] Fix format placeholder brightness with a start adornment (#23189) @LukasTy
38
+
39
+ #### `@mui/x-date-pickers-pro@9.10.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
40
+
41
+ Same changes as in `@mui/x-date-pickers@9.10.1`, plus:
42
+
43
+ - [DateRangePicker] Fix broken active range position underline in single input range fields (#23166) @LukasTy
44
+
45
+ ### Charts
46
+
47
+ #### `@mui/x-charts@9.10.1`
48
+
49
+ - [charts] Fix pie chart disappearing when an arc spans almost the full circle (#23145) @JCQuintas
50
+ - [charts] Set `aria-hidden` on accessibility proxy divs at initialization (#23186) @kevincorizi-sbt
51
+ - [charts] Fix keyboard navigation on series with different lengths (#23182) @JCQuintas
52
+ - [charts] Fix out of bounds keyboard navigation (#23180) @silviuaavram
53
+
54
+ #### `@mui/x-charts-pro@9.10.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
55
+
56
+ Same changes as in `@mui/x-charts@9.10.1`, plus:
57
+
58
+ - [charts-pro] Fix highlight shifting on sampled bar charts (#23190) @noraleonte
59
+ - [charts-pro] Sampled band highlight falls back to single-band width for Date/object values (#23024) @SamanPandey-in
60
+
61
+ #### `@mui/x-charts-premium@9.10.1` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
62
+
63
+ Same changes as in `@mui/x-charts-pro@9.10.1`.
64
+
65
+ ### Tree View
66
+
67
+ #### `@mui/x-tree-view@9.10.1`
68
+
69
+ - [TreeView] Fix selection propagation to exclude disabled items (#23012) @michelengelen
70
+
71
+ #### `@mui/x-tree-view-pro@9.10.1` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
72
+
73
+ Same changes as in `@mui/x-tree-view@9.10.1`.
74
+
75
+ ### Scheduler
76
+
77
+ #### `@mui/x-scheduler@9.0.0-beta.7`
78
+
79
+ - [scheduler] Polish `EventCalendar` rendering for multi-resource events (#23161) @mustafajw07
80
+ - [scheduler] Responsive header (#22954) @noraleonte
81
+
82
+ #### `@mui/x-scheduler-premium@9.0.0-beta.7` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
83
+
84
+ Same changes as in `@mui/x-scheduler@9.0.0-beta.7`, plus:
85
+
86
+ - [scheduler-premium] Add the dependencies data model (#23117) @rita-codes
87
+ - [scheduler-premium] Dependencies - Render the FS arrow (#23162) @rita-codes
88
+
89
+ ### Codemod
90
+
91
+ #### `@mui/x-codemod@9.10.1`
92
+
93
+ Internal changes.
94
+
95
+ ### Docs
96
+
97
+ - [docs] Fix clearing, layout shift, and prop leak in Pickers demos (#23191) @LukasTy
98
+
99
+ ### Core
100
+
101
+ - [code-infra] Validate working of specific code-infra canary (#23207) @brijeshb42
102
+
103
+ ### Miscellaneous
104
+
105
+ - [chat] Normalize message part link URLs (#23187) @hasdfa
106
+ - [x-chat] Fix object URL leaks for submitted attachments (#23198) @hasdfa
107
+ - [internals] Make disposable types self-contained without `esnext.disposable` lib (#23164) @JCQuintas
108
+
3
109
  ## 9.10.0
4
110
 
5
111
  _Jul 17, 2026_
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v9.10.0
2
+ * @mui/x-tree-view v9.10.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v9.10.0
2
+ * @mui/x-tree-view v9.10.1
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -1,5 +1,5 @@
1
1
  import { Store } from '@mui/x-internals/store';
2
- import { disposeSymbol } from '@mui/x-internals/disposable';
2
+ import { DisposableStack, disposeSymbol } from '@mui/x-internals/disposable';
3
3
  import type { MinimalTreeViewParameters, TreeViewParametersToStateMapper, MinimalTreeViewState } from "./MinimalTreeViewStore.types.mjs";
4
4
  import type { TreeViewValidItem } from "../../models/index.mjs";
5
5
  import { TimeoutManager } from "./TimeoutManager.mjs";
@@ -1,5 +1,5 @@
1
1
  import { Store } from '@mui/x-internals/store';
2
- import { disposeSymbol } from '@mui/x-internals/disposable';
2
+ import { DisposableStack, disposeSymbol } from '@mui/x-internals/disposable';
3
3
  import type { MinimalTreeViewParameters, TreeViewParametersToStateMapper, MinimalTreeViewState } from "./MinimalTreeViewStore.types.js";
4
4
  import type { TreeViewValidItem } from "../../models/index.js";
5
5
  import { TimeoutManager } from "./TimeoutManager.js";
@@ -250,20 +250,27 @@ function propagateSelection({
250
250
  if (selectionPropagation.descendants) {
251
251
  const selectDescendants = itemId => {
252
252
  if (itemId !== addedItemId) {
253
- shouldRegenerateModel = true;
254
- newModelLookup[itemId] = true;
253
+ if (_selectors.selectionSelectors.canItemBeSelected(store.state, itemId)) {
254
+ shouldRegenerateModel = true;
255
+ newModelLookup[itemId] = true;
256
+ }
255
257
  }
256
258
  _items.itemsSelectors.itemOrderedChildrenIds(store.state, itemId).forEach(selectDescendants);
257
259
  };
258
260
  selectDescendants(addedItemId);
259
261
  }
260
262
  if (selectionPropagation.parents) {
261
- const checkAllDescendantsSelected = itemId => {
263
+ const checkAllSelectableDescendantsSelected = itemId => {
264
+ if (!_selectors.selectionSelectors.canItemBeSelected(store.state, itemId)) {
265
+ // Non-selectable items don't count; still recurse for isItemSelectionDisabled case
266
+ const children = _items.itemsSelectors.itemOrderedChildrenIds(store.state, itemId);
267
+ return children.every(checkAllSelectableDescendantsSelected);
268
+ }
262
269
  if (!newModelLookup[itemId]) {
263
270
  return false;
264
271
  }
265
272
  const children = _items.itemsSelectors.itemOrderedChildrenIds(store.state, itemId);
266
- return children.every(checkAllDescendantsSelected);
273
+ return children.every(checkAllSelectableDescendantsSelected);
267
274
  };
268
275
  const selectParents = itemId => {
269
276
  const parentId = _items.itemsSelectors.itemParentId(store.state, itemId);
@@ -271,9 +278,11 @@ function propagateSelection({
271
278
  return;
272
279
  }
273
280
  const siblings = _items.itemsSelectors.itemOrderedChildrenIds(store.state, parentId);
274
- if (siblings.every(checkAllDescendantsSelected)) {
275
- shouldRegenerateModel = true;
276
- newModelLookup[parentId] = true;
281
+ if (siblings.every(checkAllSelectableDescendantsSelected)) {
282
+ if (_selectors.selectionSelectors.canItemBeSelected(store.state, parentId)) {
283
+ shouldRegenerateModel = true;
284
+ newModelLookup[parentId] = true;
285
+ }
277
286
  selectParents(parentId);
278
287
  }
279
288
  };
@@ -242,20 +242,27 @@ function propagateSelection({
242
242
  if (selectionPropagation.descendants) {
243
243
  const selectDescendants = itemId => {
244
244
  if (itemId !== addedItemId) {
245
- shouldRegenerateModel = true;
246
- newModelLookup[itemId] = true;
245
+ if (selectionSelectors.canItemBeSelected(store.state, itemId)) {
246
+ shouldRegenerateModel = true;
247
+ newModelLookup[itemId] = true;
248
+ }
247
249
  }
248
250
  itemsSelectors.itemOrderedChildrenIds(store.state, itemId).forEach(selectDescendants);
249
251
  };
250
252
  selectDescendants(addedItemId);
251
253
  }
252
254
  if (selectionPropagation.parents) {
253
- const checkAllDescendantsSelected = itemId => {
255
+ const checkAllSelectableDescendantsSelected = itemId => {
256
+ if (!selectionSelectors.canItemBeSelected(store.state, itemId)) {
257
+ // Non-selectable items don't count; still recurse for isItemSelectionDisabled case
258
+ const children = itemsSelectors.itemOrderedChildrenIds(store.state, itemId);
259
+ return children.every(checkAllSelectableDescendantsSelected);
260
+ }
254
261
  if (!newModelLookup[itemId]) {
255
262
  return false;
256
263
  }
257
264
  const children = itemsSelectors.itemOrderedChildrenIds(store.state, itemId);
258
- return children.every(checkAllDescendantsSelected);
265
+ return children.every(checkAllSelectableDescendantsSelected);
259
266
  };
260
267
  const selectParents = itemId => {
261
268
  const parentId = itemsSelectors.itemParentId(store.state, itemId);
@@ -263,9 +270,11 @@ function propagateSelection({
263
270
  return;
264
271
  }
265
272
  const siblings = itemsSelectors.itemOrderedChildrenIds(store.state, parentId);
266
- if (siblings.every(checkAllDescendantsSelected)) {
267
- shouldRegenerateModel = true;
268
- newModelLookup[parentId] = true;
273
+ if (siblings.every(checkAllSelectableDescendantsSelected)) {
274
+ if (selectionSelectors.canItemBeSelected(store.state, parentId)) {
275
+ shouldRegenerateModel = true;
276
+ newModelLookup[parentId] = true;
277
+ }
269
278
  selectParents(parentId);
270
279
  }
271
280
  };
@@ -16,10 +16,12 @@ const selectorCheckboxSelectionStatus = (0, _store.createSelector)((state, itemI
16
16
  let hasUnSelectedDescendant = false;
17
17
  const traverseDescendants = itemToTraverseId => {
18
18
  if (itemToTraverseId !== itemId) {
19
- if (_selectors2.selectionSelectors.isItemSelected(state, itemToTraverseId)) {
20
- hasSelectedDescendant = true;
21
- } else {
22
- hasUnSelectedDescendant = true;
19
+ if (_selectors2.selectionSelectors.canItemBeSelected(state, itemToTraverseId)) {
20
+ if (_selectors2.selectionSelectors.isItemSelected(state, itemToTraverseId)) {
21
+ hasSelectedDescendant = true;
22
+ } else {
23
+ hasUnSelectedDescendant = true;
24
+ }
23
25
  }
24
26
  }
25
27
  _selectors.itemsSelectors.itemOrderedChildrenIds(state, itemToTraverseId).forEach(traverseDescendants);
@@ -52,19 +54,28 @@ const useSelectionItemPlugin = ({
52
54
  const isCheckboxSelectionEnabled = (0, _store.useStore)(store, _selectors2.selectionSelectors.isCheckboxSelectionEnabled);
53
55
  const isFeatureEnabledForItem = (0, _store.useStore)(store, _selectors2.selectionSelectors.isFeatureEnabledForItem, itemId);
54
56
  const canItemBeSelected = (0, _store.useStore)(store, _selectors2.selectionSelectors.canItemBeSelected, itemId);
57
+ const isItemDisabled = (0, _store.useStore)(store, _selectors.itemsSelectors.isItemDisabled, itemId);
58
+ const isItemSelectable = (0, _store.useStore)(store, _selectors2.selectionSelectors.isItemSelectable, itemId);
55
59
  const selectionStatus = (0, _store.useStore)(store, selectorCheckboxSelectionStatus, itemId);
60
+
61
+ // An item is "inherently not selectable" when disabled or excluded via isItemSelectionDisabled,
62
+ // regardless of the global disableSelection flag. Such items must not have aria-checked.
63
+ const isItemInherentlyNotSelectable = isItemDisabled || !isItemSelectable;
56
64
  return {
57
65
  propsEnhancers: {
58
66
  root: () => {
59
67
  // https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
60
68
  let ariaChecked;
61
- if (selectionStatus === 'checked') {
69
+ if (isItemInherentlyNotSelectable) {
70
+ // - if the tree contains nodes that are not selectable, aria-checked is not present on those nodes.
71
+ ariaChecked = undefined;
72
+ } else if (selectionStatus === 'checked') {
62
73
  // - each selected node has aria-checked set to true.
63
74
  ariaChecked = true;
64
75
  } else if (selectionStatus === 'indeterminate') {
65
76
  ariaChecked = 'mixed';
66
77
  } else if (!canItemBeSelected) {
67
- // - if the tree contains nodes that are not selectable, aria-checked is not present on those nodes.
78
+ // disableSelection=true with an unselected item: aria-checked is not present.
68
79
  ariaChecked = undefined;
69
80
  } else {
70
81
  // - all nodes that are selectable but not selected have aria-checked set to false.
@@ -10,10 +10,12 @@ const selectorCheckboxSelectionStatus = createSelector((state, itemId) => {
10
10
  let hasUnSelectedDescendant = false;
11
11
  const traverseDescendants = itemToTraverseId => {
12
12
  if (itemToTraverseId !== itemId) {
13
- if (selectionSelectors.isItemSelected(state, itemToTraverseId)) {
14
- hasSelectedDescendant = true;
15
- } else {
16
- hasUnSelectedDescendant = true;
13
+ if (selectionSelectors.canItemBeSelected(state, itemToTraverseId)) {
14
+ if (selectionSelectors.isItemSelected(state, itemToTraverseId)) {
15
+ hasSelectedDescendant = true;
16
+ } else {
17
+ hasUnSelectedDescendant = true;
18
+ }
17
19
  }
18
20
  }
19
21
  itemsSelectors.itemOrderedChildrenIds(state, itemToTraverseId).forEach(traverseDescendants);
@@ -46,19 +48,28 @@ export const useSelectionItemPlugin = ({
46
48
  const isCheckboxSelectionEnabled = useStore(store, selectionSelectors.isCheckboxSelectionEnabled);
47
49
  const isFeatureEnabledForItem = useStore(store, selectionSelectors.isFeatureEnabledForItem, itemId);
48
50
  const canItemBeSelected = useStore(store, selectionSelectors.canItemBeSelected, itemId);
51
+ const isItemDisabled = useStore(store, itemsSelectors.isItemDisabled, itemId);
52
+ const isItemSelectable = useStore(store, selectionSelectors.isItemSelectable, itemId);
49
53
  const selectionStatus = useStore(store, selectorCheckboxSelectionStatus, itemId);
54
+
55
+ // An item is "inherently not selectable" when disabled or excluded via isItemSelectionDisabled,
56
+ // regardless of the global disableSelection flag. Such items must not have aria-checked.
57
+ const isItemInherentlyNotSelectable = isItemDisabled || !isItemSelectable;
50
58
  return {
51
59
  propsEnhancers: {
52
60
  root: () => {
53
61
  // https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
54
62
  let ariaChecked;
55
- if (selectionStatus === 'checked') {
63
+ if (isItemInherentlyNotSelectable) {
64
+ // - if the tree contains nodes that are not selectable, aria-checked is not present on those nodes.
65
+ ariaChecked = undefined;
66
+ } else if (selectionStatus === 'checked') {
56
67
  // - each selected node has aria-checked set to true.
57
68
  ariaChecked = true;
58
69
  } else if (selectionStatus === 'indeterminate') {
59
70
  ariaChecked = 'mixed';
60
71
  } else if (!canItemBeSelected) {
61
- // - if the tree contains nodes that are not selectable, aria-checked is not present on those nodes.
72
+ // disableSelection=true with an unselected item: aria-checked is not present.
62
73
  ariaChecked = undefined;
63
74
  } else {
64
75
  // - all nodes that are selectable but not selected have aria-checked set to false.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-tree-view",
3
- "version": "9.10.0",
3
+ "version": "9.10.1",
4
4
  "author": "MUI Team",
5
5
  "description": "The community edition of the MUI X Tree View components.",
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "clsx": "^2.1.1",
39
39
  "prop-types": "^15.8.1",
40
40
  "react-transition-group": "^4.4.5",
41
- "@mui/x-internals": "^9.10.0"
41
+ "@mui/x-internals": "^9.10.1"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@emotion/react": "^11.9.0",