@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 +106 -0
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/internals/MinimalTreeViewStore/MinimalTreeViewStore.d.mts +1 -1
- package/internals/MinimalTreeViewStore/MinimalTreeViewStore.d.ts +1 -1
- package/internals/plugins/selection/TreeViewSelectionPlugin.js +16 -7
- package/internals/plugins/selection/TreeViewSelectionPlugin.mjs +16 -7
- package/internals/plugins/selection/itemPlugin.js +17 -6
- package/internals/plugins/selection/itemPlugin.mjs +17 -6
- package/package.json +2 -2
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` [](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` [](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` [](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` [](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` [](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` [](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` [](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
package/index.mjs
CHANGED
|
@@ -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
|
-
|
|
254
|
-
|
|
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
|
|
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(
|
|
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(
|
|
275
|
-
|
|
276
|
-
|
|
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
|
-
|
|
246
|
-
|
|
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
|
|
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(
|
|
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(
|
|
267
|
-
|
|
268
|
-
|
|
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.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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 (
|
|
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
|
-
//
|
|
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.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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 (
|
|
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
|
-
//
|
|
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.
|
|
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.
|
|
41
|
+
"@mui/x-internals": "^9.10.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@emotion/react": "^11.9.0",
|