@mui/x-tree-view 8.11.2 → 8.12.0

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +231 -0
  2. package/TreeItem/TreeItem.js +3 -1
  3. package/TreeItemIcon/TreeItemIcon.js +12 -3
  4. package/TreeItemIcon/TreeItemIcon.types.d.ts +4 -4
  5. package/esm/TreeItem/TreeItem.js +3 -1
  6. package/esm/TreeItemIcon/TreeItemIcon.js +12 -3
  7. package/esm/TreeItemIcon/TreeItemIcon.types.d.ts +4 -4
  8. package/esm/index.js +1 -1
  9. package/esm/internals/TreeViewProvider/TreeViewStyleContext.d.ts +3 -3
  10. package/esm/internals/components/RichTreeViewItems.js +12 -5
  11. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +1 -1
  12. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +5 -3
  13. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +19 -3
  14. package/esm/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +15 -6
  15. package/esm/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +2 -2
  16. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.js +2 -19
  17. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +10 -0
  18. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +8 -0
  19. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +8 -11
  20. package/esm/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +0 -4
  21. package/index.js +1 -1
  22. package/internals/TreeViewProvider/TreeViewStyleContext.d.ts +3 -3
  23. package/internals/components/RichTreeViewItems.js +12 -5
  24. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +1 -1
  25. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +5 -3
  26. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +19 -3
  27. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +15 -6
  28. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +2 -2
  29. package/internals/plugins/useTreeViewItems/useTreeViewItems.js +2 -19
  30. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +10 -0
  31. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +8 -0
  32. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +8 -11
  33. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +0 -4
  34. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,237 @@
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.12.0
9
+
10
+ _Sep 25, 2025_
11
+
12
+ We'd like to extend a big thank you to the 15 contributors who made this release possible. Here are some highlights ✨:
13
+
14
+ - 🤝 Grid-Charts integration
15
+
16
+ ![Grid x Charts](https://github.com/user-attachments/assets/0817c36f-f87f-4688-8f30-fa0db638ca8c)
17
+
18
+ 👉 [🎥 Watch the full video](https://github.com/user-attachments/assets/28f1848e-dc85-4077-8756-a3e88afd4e54)
19
+
20
+ - ⌨️ Charts keyboard navigation
21
+ - ⚡️ Charts: Add new `renderer="svg-batch"` prop to Scatter charts that provides improved performance for large datasets
22
+ - 🐞 Bugfixes
23
+ - 📚 Documentation improvements
24
+ - 🧰 Codemod requires Node >=20.19
25
+
26
+ `@mui/x-codemod` minimum supported Node version is `20.19`.
27
+ This was only the case due to using the v18 `yargs` package; this now explicitly aligns with it. (#18979)
28
+
29
+ Special thanks go out to the community members for their valuable contributions:
30
+ @deade1e, @sai6855, @thomas-mcdonald
31
+
32
+ The following are all team members who have contributed to this release:
33
+ @alexfauquette, @bernardobelchior, @flaviendelangle, @Janpot, @JCQuintas, @LukasTy, @michelengelen, @prakhargupta1, @rita-codes, @siriwatknp, @arminmeh, @romgrk
34
+
35
+ ### Data Grid
36
+
37
+ #### `@mui/x-data-grid@8.12.0`
38
+
39
+ - [DataGrid] Fix flex column width diff calculation while resizing (#19667) @arminmeh
40
+
41
+ #### `@mui/x-data-grid-pro@8.12.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
42
+
43
+ Same changes as in `@mui/x-data-grid@8.12.0`.
44
+
45
+ #### `@mui/x-data-grid-premium@8.12.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
46
+
47
+ Same changes as in `@mui/x-data-grid-pro@8.12.0`, plus:
48
+
49
+ - [DataGridPremium] Grid-Charts integration (#18021) @arminmeh
50
+ - [DataGridPremium] Fix sorting and filtering of the tree group columns with aggregation (#19607) @arminmeh
51
+ - [DataGridPremium] Disable aggregation on the grouping column by default (#19692) @arminmeh
52
+ - [DataGridPremium] Do not rely on the group separation constant to retrieve the column name for the charts panel (#19677) @arminmeh
53
+ - [DataGridPremium] Fix stale aggregation state (#19690) @arminmeh
54
+ - [DataGridPremium] Fix pivot column being hidden on autosizing (#19699) @cherniavskii
55
+
56
+ ### Date and Time Pickers
57
+
58
+ #### `@mui/x-date-pickers@8.12.0`
59
+
60
+ - [pickers] Ensure reference value is not updated for invalid values (#19635) @michelengelen
61
+ - [pickers] Fix `slotProps.textField.slotProps.htmlInput` resolution (#19713) @LukasTy
62
+ - [pickers] Preserve time format when using single column layout on Time Range Picker (#19626) @sai6855
63
+ - [pickers] Preserve time format when using single column layout on Date Time Picker and Date Time Range Picker (#19608) @sai6855
64
+
65
+ #### `@mui/x-date-pickers-pro@8.12.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
66
+
67
+ Same changes as in `@mui/x-date-pickers@8.12.0`.
68
+
69
+ ### Charts
70
+
71
+ #### `@mui/x-charts@8.12.0`
72
+
73
+ - [charts] Add batch renderer for scatter chart (#19075) @bernardobelchior
74
+ - [charts] Add renderer suffix to performance benchmarks (#19620) @bernardobelchior
75
+ - [charts] Document how plugins can be used (#19343) @alexfauquette
76
+ - [charts] Export chart plugins per series type (#19337) @alexfauquette
77
+ - [charts] Export plugins (#19335) @alexfauquette
78
+ - [charts] Fix horizontal layout and toolbar (#19655) @alexfauquette
79
+ - [charts] Fix performance issue with JS animations (#19606) @bernardobelchior
80
+ - [charts] Fix piecewise scale causing wrong colors in axis with min/max (#19610) @bernardobelchior
81
+ - [charts] Fix zoom discard inconsistency (#19535) @bernardobelchior
82
+ - [charts] Introduce keyboard navigation (#19155) @alexfauquette
83
+ - [charts] Refactor `getAxisExtremum` (#19627) @bernardobelchior
84
+ - [charts] Remove unused code path from `getAxisScale` (#19673) @bernardobelchior
85
+ - [charts] Make new hideLegend prop on ChartWrapper optional (#19694) @thomas-mcdonald
86
+ - [charts] Fix chart crash in test environment (#19711) @JCQuintas
87
+
88
+ #### `@mui/x-charts-pro@8.12.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
89
+
90
+ Same changes as in `@mui/x-charts@8.12.0`, plus:
91
+
92
+ - [charts-pro] Add `valueFormatter` to sankey (#19636) @JCQuintas
93
+ - [charts-pro] Allow `source/target` keywords in sankey link color (#19634) @JCQuintas
94
+ - [charts-pro] Allow exporting `SankeyChart` (#19659) @JCQuintas
95
+ - [charts-pro] Fix axis inversion when using axis `max` and `filterMode: 'discard'` (#19200) @bernardobelchior
96
+
97
+ #### `@mui/x-charts-premium@8.12.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
98
+
99
+ Same changes as in `@mui/x-charts-pro@8.12.0`, plus:
100
+
101
+ - [charts-premium] Grid-Charts integration (#18021) @arminmeh
102
+
103
+ ### Tree View
104
+
105
+ #### `@mui/x-tree-view@8.12.0`
106
+
107
+ - [tree view] Allow to pass `null` to the icon slots (#19569) @flaviendelangle
108
+ - [tree view] Fix `apiRef.current.isItemExpanded()` method (#19619) @flaviendelangle
109
+
110
+ #### `@mui/x-tree-view-pro@8.12.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
111
+
112
+ Same changes as in `@mui/x-tree-view@8.12.0`.
113
+
114
+ ### Codemod
115
+
116
+ #### `@mui/x-codemod@8.12.0`
117
+
118
+ - [codemod] Bump `engines.node` to `>=20.19` to align with `yargs` package (#18979) @LukasTy
119
+
120
+ ### Docs
121
+
122
+ - [docs] Add missing label to Charts example (#19616) @prakhargupta1
123
+ - [docs] Replace axis type and axis data with a table (#19618) @prakhargupta1
124
+ - [docs] Add Charts example collection page (#18353) @prakhargupta1
125
+ - [docs] Add a Charts demo showcasing bar and scatter composition (#19605) @prakhargupta1
126
+ - [docs] Add composition Charts demo for legends and tooltip (#19602) @prakhargupta1
127
+ - [docs] Add recipe about server-side data export (#19617) @siriwatknp
128
+ - [docs] Clarify DataGrid layout requirements (#19413) @romgrk
129
+ - [docs] Fix `ExportServerSideData` demo layout shift (#19669) @siriwatknp
130
+ - [docs] Improve server-side `updateRow()` description (#19554) @deade1e
131
+ - [docs] Show how to customize drawing area background (#19682) @alexfauquette
132
+ - [docs] Add hook documentation pages (#19334) @Copilot
133
+
134
+ ### Core
135
+
136
+ - [code-infra] Add copilot instructions specific to x repo (#19623) @JCQuintas
137
+ - [code-infra] Load `tsx` files in visual regression (#19595) @JCQuintas
138
+ - [code-infra] Remove renovate automerge (#19501) @Janpot
139
+ - [code-infra] Update `DEFAULT_TIMESTAMP` format to ISO 8601 (#19624) @Janpot
140
+ - [code-infra] Update `findLatestTaggedVersion` to filter tags based on major version (#19693) @michelengelen
141
+ - [code-infra] Fix changelog generation for charts premium (#19701) @JCQuintas
142
+ - [code-infra] Run prettier on `createReleasePR.mjs` (#19702) @bernardobelchior
143
+ - [code-infra] Make `x-charts-premium` releasable (#18959) @JCQuintas
144
+ - [docs-infra] Ensure `create-playground` script only runs if target file is absent (#19603) @michelengelen
145
+ - [docs-infra] Add @prakhargupta1 as a codeowner of the docs (#19679) @alexfauquette
146
+
147
+ ### Miscellaneous
148
+
149
+ - [test] Reduce time for wheel zoom test (#19571) @alexfauquette
150
+ - Change `matchPackageNames` to `matchDepNames` for date-fns-v2 @Janpot
151
+ - Remove groupName for date-fns-v2 in renovate.json @Janpot
152
+
153
+ ## 8.11.3
154
+
155
+ _Sep 16, 2025_
156
+
157
+ We'd like to extend a big thank you to the 11 contributors who made this release possible. Here are some highlights ✨:
158
+
159
+ - 🐞 Bugfixes
160
+ - 📚 Documentation improvements
161
+
162
+ Special thanks go out to the community members for their valuable contributions:
163
+ @sai6855
164
+
165
+ The following are all team members who have contributed to this release:
166
+ @alexfauquette, @bernardobelchior, @brijeshb42, @cherniavskii, @flaviendelangle, @Janpot, @JCQuintas, @LukasTy, @rita-codes, @siriwatknp
167
+
168
+ ### Data Grid
169
+
170
+ #### `@mui/x-data-grid@8.11.3`
171
+
172
+ - [DataGrid] Fix numeric font size not being applied (#19552) @cherniavskii
173
+ - [DataGrid] Improve `operator` types to display literal values (#19529) @siriwatknp
174
+
175
+ #### `@mui/x-data-grid-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
176
+
177
+ Same changes as in `@mui/x-data-grid@8.11.3`.
178
+
179
+ #### `@mui/x-data-grid-premium@8.11.3` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
180
+
181
+ Same changes as in `@mui/x-data-grid-pro@8.11.3`.
182
+
183
+ ### Date and Time Pickers
184
+
185
+ #### `@mui/x-date-pickers@8.11.3`
186
+
187
+ - [pickers] Refactor `slots` and `slotProps` propagation strategy (#18867) @LukasTy
188
+
189
+ #### `@mui/x-date-pickers-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
190
+
191
+ Same changes as in `@mui/x-date-pickers@8.11.3`.
192
+
193
+ ### Charts
194
+
195
+ #### `@mui/x-charts@8.11.3`
196
+
197
+ - [charts] Add `inline-` piecewise legend options (#19382) @JCQuintas
198
+ - [charts] Add bar gradient example (#19174) @bernardobelchior
199
+ - [charts] Ignore empty tick labels in label overlap computation (#19547) @alexfauquette
200
+ - [charts] Rename `isBandScale` to `isDiscreteScale` (#19514) @bernardobelchior
201
+ - [charts] Fix legend position affecting toolbar's position (#19257) @sai6855
202
+
203
+ #### `@mui/x-charts-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
204
+
205
+ Same changes as in `@mui/x-charts@8.11.3`, plus:
206
+
207
+ - [charts-pro] Add chart title and caption to export demo (#19524) @bernardobelchior
208
+
209
+ ### Tree View
210
+
211
+ #### `@mui/x-tree-view@8.11.3`
212
+
213
+ - [tree view] Stop looping through all items to publish the `removeItem` event (#19500) @flaviendelangle
214
+ - [tree view] Support flat DOM structure (#19350) @flaviendelangle
215
+ - [tree view] Update cursor styles for disabled TreeItem (#19548) @sai6855
216
+
217
+ #### `@mui/x-tree-view-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
218
+
219
+ Same changes as in `@mui/x-tree-view@8.11.3`.
220
+
221
+ ### Codemod
222
+
223
+ #### `@mui/x-codemod@8.11.3`
224
+
225
+ Internal changes.
226
+
227
+ ### Docs
228
+
229
+ - [docs] Add styling row group recipe (#19349) @siriwatknp
230
+ - [docs] Group demos data into the dataset folder (#19549) @alexfauquette
231
+ - [docs] Add `shiny` bar chart example at the top (#19416) @JCQuintas
232
+
233
+ ### Core
234
+
235
+ - [code-infra] Axios update (#19577) @Janpot
236
+ - [code-infra] Remove usage of copy-files command from code-infra (#19518) @brijeshb42
237
+ - [internal] Fix naming to match convention @oliviertassinari
238
+
8
239
  ## 8.11.2
9
240
 
10
241
  _Sep 10, 2025_
@@ -69,7 +69,8 @@ const TreeItemContent = exports.TreeItemContent = (0, _zeroStyled.styled)('div',
69
69
  },
70
70
  '&[data-disabled]': {
71
71
  opacity: (theme.vars || theme).palette.action.disabledOpacity,
72
- backgroundColor: 'transparent'
72
+ backgroundColor: 'transparent',
73
+ cursor: 'auto'
73
74
  },
74
75
  '&[data-focused]': {
75
76
  backgroundColor: (theme.vars || theme).palette.action.focus
@@ -121,6 +122,7 @@ const TreeItemIconContainer = exports.TreeItemIconContainer = (0, _zeroStyled.st
121
122
  flexShrink: 0,
122
123
  justifyContent: 'center',
123
124
  position: 'relative',
125
+ cursor: 'inherit',
124
126
  '& svg': {
125
127
  fontSize: 18
126
128
  }
@@ -15,6 +15,15 @@ var _useSlotProps = _interopRequireDefault(require("@mui/utils/useSlotProps"));
15
15
  var _TreeViewStyleContext = require("../internals/TreeViewProvider/TreeViewStyleContext");
16
16
  var _icons = require("../icons");
17
17
  var _jsxRuntime = require("react/jsx-runtime");
18
+ function pickIcon(treeItemIcon, treeViewIcon, fallback) {
19
+ if (treeItemIcon !== undefined) {
20
+ return treeItemIcon;
21
+ }
22
+ if (treeViewIcon !== undefined) {
23
+ return treeViewIcon;
24
+ }
25
+ return fallback;
26
+ }
18
27
  function TreeItemIcon(props) {
19
28
  const {
20
29
  slots: slotsFromTreeItem,
@@ -26,9 +35,9 @@ function TreeItemIcon(props) {
26
35
  slotProps: slotPropsFromTreeView
27
36
  } = (0, _TreeViewStyleContext.useTreeViewStyleContext)();
28
37
  const slots = {
29
- collapseIcon: slotsFromTreeItem?.collapseIcon ?? slotsFromTreeView.collapseIcon ?? _icons.TreeViewCollapseIcon,
30
- expandIcon: slotsFromTreeItem?.expandIcon ?? slotsFromTreeView.expandIcon ?? _icons.TreeViewExpandIcon,
31
- endIcon: slotsFromTreeItem?.endIcon ?? slotsFromTreeView.endIcon,
38
+ collapseIcon: pickIcon(slotsFromTreeItem?.collapseIcon, slotsFromTreeView.collapseIcon, _icons.TreeViewCollapseIcon),
39
+ expandIcon: pickIcon(slotsFromTreeItem?.expandIcon, slotsFromTreeView.expandIcon, _icons.TreeViewExpandIcon),
40
+ endIcon: pickIcon(slotsFromTreeItem?.endIcon, slotsFromTreeView.endIcon),
32
41
  icon: slotsFromTreeItem?.icon
33
42
  };
34
43
  let iconName;
@@ -5,19 +5,19 @@ export interface TreeItemIconSlots {
5
5
  /**
6
6
  * The icon used to collapse the item.
7
7
  */
8
- collapseIcon?: React.ElementType;
8
+ collapseIcon?: React.ElementType | null;
9
9
  /**
10
10
  * The icon used to expand the item.
11
11
  */
12
- expandIcon?: React.ElementType;
12
+ expandIcon?: React.ElementType | null;
13
13
  /**
14
14
  * The icon displayed next to an end item.
15
15
  */
16
- endIcon?: React.ElementType;
16
+ endIcon?: React.ElementType | null;
17
17
  /**
18
18
  * The icon to display next to the Tree Item's label.
19
19
  */
20
- icon?: React.ElementType;
20
+ icon?: React.ElementType | null;
21
21
  }
22
22
  export interface TreeItemIconSlotProps {
23
23
  collapseIcon?: SlotComponentProps<'svg', {}, {}>;
@@ -62,7 +62,8 @@ export const TreeItemContent = styled('div', {
62
62
  },
63
63
  '&[data-disabled]': {
64
64
  opacity: (theme.vars || theme).palette.action.disabledOpacity,
65
- backgroundColor: 'transparent'
65
+ backgroundColor: 'transparent',
66
+ cursor: 'auto'
66
67
  },
67
68
  '&[data-focused]': {
68
69
  backgroundColor: (theme.vars || theme).palette.action.focus
@@ -114,6 +115,7 @@ export const TreeItemIconContainer = styled('div', {
114
115
  flexShrink: 0,
115
116
  justifyContent: 'center',
116
117
  position: 'relative',
118
+ cursor: 'inherit',
117
119
  '& svg': {
118
120
  fontSize: 18
119
121
  }
@@ -8,6 +8,15 @@ import useSlotProps from '@mui/utils/useSlotProps';
8
8
  import { useTreeViewStyleContext } from "../internals/TreeViewProvider/TreeViewStyleContext.js";
9
9
  import { TreeViewCollapseIcon, TreeViewExpandIcon } from "../icons/index.js";
10
10
  import { jsx as _jsx } from "react/jsx-runtime";
11
+ function pickIcon(treeItemIcon, treeViewIcon, fallback) {
12
+ if (treeItemIcon !== undefined) {
13
+ return treeItemIcon;
14
+ }
15
+ if (treeViewIcon !== undefined) {
16
+ return treeViewIcon;
17
+ }
18
+ return fallback;
19
+ }
11
20
  function TreeItemIcon(props) {
12
21
  const {
13
22
  slots: slotsFromTreeItem,
@@ -19,9 +28,9 @@ function TreeItemIcon(props) {
19
28
  slotProps: slotPropsFromTreeView
20
29
  } = useTreeViewStyleContext();
21
30
  const slots = {
22
- collapseIcon: slotsFromTreeItem?.collapseIcon ?? slotsFromTreeView.collapseIcon ?? TreeViewCollapseIcon,
23
- expandIcon: slotsFromTreeItem?.expandIcon ?? slotsFromTreeView.expandIcon ?? TreeViewExpandIcon,
24
- endIcon: slotsFromTreeItem?.endIcon ?? slotsFromTreeView.endIcon,
31
+ collapseIcon: pickIcon(slotsFromTreeItem?.collapseIcon, slotsFromTreeView.collapseIcon, TreeViewCollapseIcon),
32
+ expandIcon: pickIcon(slotsFromTreeItem?.expandIcon, slotsFromTreeView.expandIcon, TreeViewExpandIcon),
33
+ endIcon: pickIcon(slotsFromTreeItem?.endIcon, slotsFromTreeView.endIcon),
25
34
  icon: slotsFromTreeItem?.icon
26
35
  };
27
36
  let iconName;
@@ -5,19 +5,19 @@ export interface TreeItemIconSlots {
5
5
  /**
6
6
  * The icon used to collapse the item.
7
7
  */
8
- collapseIcon?: React.ElementType;
8
+ collapseIcon?: React.ElementType | null;
9
9
  /**
10
10
  * The icon used to expand the item.
11
11
  */
12
- expandIcon?: React.ElementType;
12
+ expandIcon?: React.ElementType | null;
13
13
  /**
14
14
  * The icon displayed next to an end item.
15
15
  */
16
- endIcon?: React.ElementType;
16
+ endIcon?: React.ElementType | null;
17
17
  /**
18
18
  * The icon to display next to the Tree Item's label.
19
19
  */
20
- icon?: React.ElementType;
20
+ icon?: React.ElementType | null;
21
21
  }
22
22
  export interface TreeItemIconSlotProps {
23
23
  collapseIcon?: SlotComponentProps<'svg', {}, {}>;
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v8.11.2
2
+ * @mui/x-tree-view v8.12.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -28,16 +28,16 @@ export interface TreeViewSlots {
28
28
  /**
29
29
  * The default icon used to collapse the item.
30
30
  */
31
- collapseIcon?: React.ElementType;
31
+ collapseIcon?: React.ElementType | null;
32
32
  /**
33
33
  * The default icon used to expand the item.
34
34
  */
35
- expandIcon?: React.ElementType;
35
+ expandIcon?: React.ElementType | null;
36
36
  /**
37
37
  * The default icon displayed next to an end item.
38
38
  * This is applied to all Tree Items and can be overridden by the TreeItem `icon` slot prop.
39
39
  */
40
- endIcon?: React.ElementType;
40
+ endIcon?: React.ElementType | null;
41
41
  }
42
42
  export interface TreeViewSlotProps {
43
43
  collapseIcon?: SlotComponentProps<'svg', {}, {}>;
@@ -10,20 +10,24 @@ import { fastObjectShallowCompare } from '@mui/x-internals/fastObjectShallowComp
10
10
  import { TreeItem } from "../../TreeItem/index.js";
11
11
  import { itemsSelectors } from "../plugins/useTreeViewItems/index.js";
12
12
  import { useTreeViewContext } from "../TreeViewProvider/index.js";
13
+ import { expansionSelectors } from "../plugins/useTreeViewExpansion/index.js";
13
14
  import { jsx as _jsx } from "react/jsx-runtime";
14
15
  const RichTreeViewItemsContext = /*#__PURE__*/React.createContext(null);
15
16
  if (process.env.NODE_ENV !== "production") RichTreeViewItemsContext.displayName = "RichTreeViewItemsContext";
17
+ const EMPTY_ARRAY = [];
18
+ const selectorNoChildren = () => EMPTY_ARRAY;
16
19
  const WrappedTreeItem = /*#__PURE__*/React.memo(function WrappedTreeItem({
17
20
  itemSlot,
18
21
  itemSlotProps,
19
- itemId
22
+ itemId,
23
+ skipChildren
20
24
  }) {
21
25
  const renderItemForRichTreeView = React.useContext(RichTreeViewItemsContext);
22
26
  const {
23
27
  store
24
28
  } = useTreeViewContext();
25
29
  const itemMeta = useStore(store, itemsSelectors.itemMeta, itemId);
26
- const children = useStore(store, itemsSelectors.itemOrderedChildrenIds, itemId);
30
+ const children = useStore(store, skipChildren ? selectorNoChildren : itemsSelectors.itemOrderedChildrenIds, itemId);
27
31
  const Item = itemSlot ?? TreeItem;
28
32
  const _useSlotProps = useSlotProps({
29
33
  elementType: Item,
@@ -54,14 +58,17 @@ export function RichTreeViewItems(props) {
54
58
  } = useTreeViewContext();
55
59
  const itemSlot = slots?.item;
56
60
  const itemSlotProps = slotProps?.item;
57
- const items = useStore(store, itemsSelectors.itemOrderedChildrenIds, null);
61
+ const domStructure = useStore(store, itemsSelectors.domStructure);
62
+ const items = useStore(store, domStructure === 'flat' ? state => expansionSelectors.flatList(state) : state => itemsSelectors.itemOrderedChildrenIds(state, null));
63
+ const skipChildren = domStructure === 'flat';
58
64
  const renderItem = React.useCallback(itemId => {
59
65
  return /*#__PURE__*/_jsx(WrappedTreeItem, {
60
66
  itemSlot: itemSlot,
61
67
  itemSlotProps: itemSlotProps,
62
- itemId: itemId
68
+ itemId: itemId,
69
+ skipChildren: skipChildren
63
70
  }, itemId);
64
- }, [itemSlot, itemSlotProps]);
71
+ }, [itemSlot, itemSlotProps, skipChildren]);
65
72
  return /*#__PURE__*/_jsx(RichTreeViewItemsContext.Provider, {
66
73
  value: renderItem,
67
74
  children: items.map(renderItem)
@@ -84,7 +84,7 @@ export const useTreeViewExpansion = ({
84
84
  });
85
85
  });
86
86
  const isItemExpanded = useEventCallback(itemId => {
87
- return expansionSelectors.isItemExpandable(store.state, itemId);
87
+ return expansionSelectors.isItemExpanded(store.state, itemId);
88
88
  });
89
89
  const expandAllSiblings = (event, itemId) => {
90
90
  const itemMeta = itemsSelectors.itemMeta(store.state, itemId);
@@ -6,11 +6,13 @@ export declare const expansionSelectors: {
6
6
  */
7
7
  expandedItemsRaw: (state: TreeViewState<[UseTreeViewExpansionSignature]>) => string[];
8
8
  /**
9
- * Get the expanded items as a Map.
10
- * @param {TreeViewState<[UseTreeViewExpansionSignature]>} state The state of the tree view.
11
- * @returns {TreeViewExpansionValue} The expanded items as a Map.
9
+ * Gets the expanded items as a Map.
12
10
  */
13
11
  expandedItemsMap: (args_0: import("../../corePlugins/useTreeViewId/useTreeViewId.types.js").UseTreeViewIdState & import("./useTreeViewExpansion.types.js").UseTreeViewExpansionState & Partial<{}>) => Map<string, true>;
12
+ /**
13
+ * Gets the items to render as a flat list (the descendants of an expanded item are listed as siblings of the item).
14
+ */
15
+ flatList: (args_0: import("../../corePlugins/useTreeViewId/useTreeViewId.types.js").UseTreeViewIdState & import("./useTreeViewExpansion.types.js").UseTreeViewExpansionState & Partial<{}>) => string[];
14
16
  /**
15
17
  * Gets the slot that triggers the item's expansion when clicked.
16
18
  */
@@ -1,5 +1,6 @@
1
1
  import { createSelector, createSelectorMemoized } from '@mui/x-internals/store';
2
2
  import { itemsSelectors } from "../useTreeViewItems/useTreeViewItems.selectors.js";
3
+ import { TREE_VIEW_ROOT_PARENT_ID } from "../useTreeViewItems/index.js";
3
4
  const expandedItemMapSelector = createSelectorMemoized(state => state.expansion.expandedItems, expandedItems => {
4
5
  const expandedItemsMap = new Map();
5
6
  expandedItems.forEach(id => {
@@ -13,11 +14,26 @@ export const expansionSelectors = {
13
14
  */
14
15
  expandedItemsRaw: createSelector(state => state.expansion.expandedItems),
15
16
  /**
16
- * Get the expanded items as a Map.
17
- * @param {TreeViewState<[UseTreeViewExpansionSignature]>} state The state of the tree view.
18
- * @returns {TreeViewExpansionValue} The expanded items as a Map.
17
+ * Gets the expanded items as a Map.
19
18
  */
20
19
  expandedItemsMap: expandedItemMapSelector,
20
+ /**
21
+ * Gets the items to render as a flat list (the descendants of an expanded item are listed as siblings of the item).
22
+ */
23
+ flatList: createSelectorMemoized(itemsSelectors.itemOrderedChildrenIdsLookup, expandedItemMapSelector, (itemOrderedChildrenIds, expandedItemsMap) => {
24
+ function appendChildren(itemId) {
25
+ if (!expandedItemsMap.has(itemId)) {
26
+ return [itemId];
27
+ }
28
+ const itemsWithDescendants = [itemId];
29
+ const children = itemOrderedChildrenIds[itemId] || [];
30
+ for (const childId of children) {
31
+ itemsWithDescendants.push(...appendChildren(childId));
32
+ }
33
+ return itemsWithDescendants;
34
+ }
35
+ return (itemOrderedChildrenIds[TREE_VIEW_ROOT_PARENT_ID] ?? []).flatMap(appendChildren);
36
+ }),
21
37
  /**
22
38
  * Gets the slot that triggers the item's expansion when clicked.
23
39
  */
@@ -1,6 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import useEventCallback from '@mui/utils/useEventCallback';
3
- import { useInstanceEventHandler } from "../../hooks/useInstanceEventHandler.js";
3
+ import { useStoreEffect } from '@mui/x-internals/store';
4
4
  import { focusSelectors } from "./useTreeViewFocus.selectors.js";
5
5
  import { expansionSelectors } from "../useTreeViewExpansion/useTreeViewExpansion.selectors.js";
6
6
  import { itemsSelectors } from "../useTreeViewItems/useTreeViewItems.selectors.js";
@@ -52,14 +52,23 @@ export const useTreeViewFocus = ({
52
52
  }
53
53
  setFocusedItemId(null);
54
54
  });
55
- useInstanceEventHandler(instance, 'removeItem', ({
56
- id
57
- }) => {
55
+
56
+ // Whenever the items change, we need to ensure the focused item is still present.
57
+ useStoreEffect(store, itemsSelectors.itemMetaLookup, () => {
58
58
  const focusedItemId = focusSelectors.focusedItemId(store.state);
59
+ if (focusedItemId == null) {
60
+ return;
61
+ }
62
+ const hasItemBeenRemoved = !itemsSelectors.itemMeta(store.state, focusedItemId);
63
+ if (!hasItemBeenRemoved) {
64
+ return;
65
+ }
59
66
  const defaultFocusableItemId = focusSelectors.defaultFocusableItemId(store.state);
60
- if (focusedItemId === id && defaultFocusableItemId != null) {
61
- innerFocusItem(null, defaultFocusableItemId);
67
+ if (defaultFocusableItemId == null) {
68
+ setFocusedItemId(null);
69
+ return;
62
70
  }
71
+ innerFocusItem(null, defaultFocusableItemId);
63
72
  });
64
73
  const createRootHandleFocus = otherHandlers => event => {
65
74
  otherHandlers.onFocus?.(event);
@@ -9,10 +9,10 @@ export interface UseTreeViewFocusPublicAPI {
9
9
  *
10
10
  * If the item is the child of a collapsed item, then this method will do nothing.
11
11
  * Make sure to expand the ancestors of the item before calling this method if needed.
12
- * @param {React.SyntheticEvent} event The DOM event that triggered the change.
12
+ * @param {React.SyntheticEvent | null} event The DOM event that triggered the change.
13
13
  * @param {TreeViewItemId} itemId The id of the item to focus.
14
14
  */
15
- focusItem: (event: React.SyntheticEvent, itemId: string) => void;
15
+ focusItem: (event: React.SyntheticEvent | null, itemId: string) => void;
16
16
  }
17
17
  export interface UseTreeViewFocusInstance extends UseTreeViewFocusPublicAPI {
18
18
  /**
@@ -3,7 +3,6 @@
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
5
  import useEventCallback from '@mui/utils/useEventCallback';
6
- import { publishTreeViewEvent } from "../../utils/publishTreeViewEvent.js";
7
6
  import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "./useTreeViewItems.utils.js";
8
7
  import { TreeViewItemDepthContext } from "../../TreeViewItemDepthContext/index.js";
9
8
  import { itemsSelectors } from "./useTreeViewItems.selectors.js";
@@ -179,13 +178,6 @@ export const useTreeViewItems = ({
179
178
  itemChildrenIndexesLookup: newState.itemChildrenIndexesLookup
180
179
  };
181
180
  }
182
- Object.values(store.state.items.itemMetaLookup).forEach(item => {
183
- if (!newItems.itemMetaLookup[item.id]) {
184
- publishTreeViewEvent(instance, 'removeItem', {
185
- id: item.id
186
- });
187
- }
188
- });
189
181
  store.set('items', _extends({}, store.state.items, newItems));
190
182
  }
191
183
  };
@@ -200,9 +192,6 @@ export const useTreeViewItems = ({
200
192
  const newMetaMap = Object.keys(store.state.items.itemMetaLookup).reduce((acc, key) => {
201
193
  const item = store.state.items.itemMetaLookup[key];
202
194
  if (item.parentId === parentId) {
203
- publishTreeViewEvent(instance, 'removeItem', {
204
- id: item.id
205
- });
206
195
  return acc;
207
196
  }
208
197
  return _extends({}, acc, {
@@ -232,13 +221,6 @@ export const useTreeViewItems = ({
232
221
  getItemLabel: params.getItemLabel,
233
222
  getItemChildren: params.getItemChildren
234
223
  });
235
- Object.values(store.state.items.itemMetaLookup).forEach(item => {
236
- if (!newState.itemMetaLookup[item.id]) {
237
- publishTreeViewEvent(instance, 'removeItem', {
238
- id: item.id
239
- });
240
- }
241
- });
242
224
  store.set('items', _extends({}, store.state.items, newState));
243
225
  }, [instance, store, params.items, params.disabledItemsFocusable, params.isItemDisabled, params.getItemId, params.getItemLabel, params.getItemChildren]);
244
226
 
@@ -284,7 +266,8 @@ useTreeViewItems.getInitialState = params => ({
284
266
  getItemChildren: params.getItemChildren
285
267
  }), {
286
268
  loading: false,
287
- error: null
269
+ error: null,
270
+ domStructure: 'nested'
288
271
  })
289
272
  });
290
273
  useTreeViewItems.applyDefaultValuesToParams = ({
@@ -9,6 +9,10 @@ export declare const itemsSelectors: {
9
9
  * Gets the error state for the Tree View.
10
10
  */
11
11
  error: (state: TreeViewState<[UseTreeViewItemsSignature]>) => Error | null;
12
+ /**
13
+ * Gets the DOM structure of the Tree View.
14
+ */
15
+ domStructure: (state: TreeViewState<[UseTreeViewItemsSignature]>) => "flat" | "nested";
12
16
  /**
13
17
  * Checks whether the disabled items are focusable.
14
18
  */
@@ -19,6 +23,12 @@ export declare const itemsSelectors: {
19
23
  itemMetaLookup: (state: TreeViewState<[UseTreeViewItemsSignature]>) => {
20
24
  [itemId: string]: TreeViewItemMeta;
21
25
  };
26
+ /**
27
+ * Gets the ordered children ids of all items.
28
+ */
29
+ itemOrderedChildrenIdsLookup: (state: TreeViewState<[UseTreeViewItemsSignature]>) => {
30
+ [parentItemId: string]: string[];
31
+ };
22
32
  /**
23
33
  * Gets the meta-information of an item.
24
34
  */
@@ -10,6 +10,10 @@ export const itemsSelectors = {
10
10
  * Gets the error state for the Tree View.
11
11
  */
12
12
  error: createSelector(state => state.items.error),
13
+ /**
14
+ * Gets the DOM structure of the Tree View.
15
+ */
16
+ domStructure: createSelector(state => state.items.domStructure),
13
17
  /**
14
18
  * Checks whether the disabled items are focusable.
15
19
  */
@@ -18,6 +22,10 @@ export const itemsSelectors = {
18
22
  * Gets the meta-information of all items.
19
23
  */
20
24
  itemMetaLookup: createSelector(state => state.items.itemMetaLookup),
25
+ /**
26
+ * Gets the ordered children ids of all items.
27
+ */
28
+ itemOrderedChildrenIdsLookup: createSelector(state => state.items.itemOrderedChildrenIdsLookup),
21
29
  /**
22
30
  * Gets the meta-information of an item.
23
31
  */
@@ -149,13 +149,6 @@ export interface UseTreeViewItemsParameters<R extends {
149
149
  export type UseTreeViewItemsParametersWithDefaults<R extends {
150
150
  children?: R[];
151
151
  }> = DefaultizedProps<UseTreeViewItemsParameters<R>, 'disabledItemsFocusable' | 'itemChildrenIndentation'>;
152
- interface UseTreeViewItemsEventLookup {
153
- removeItem: {
154
- params: {
155
- id: string;
156
- };
157
- };
158
- }
159
152
  export interface UseTreeViewItemsState<R extends {}> {
160
153
  items: {
161
154
  /**
@@ -183,7 +176,7 @@ export interface UseTreeViewItemsState<R extends {}> {
183
176
  * Ordered children ids of each item.
184
177
  */
185
178
  itemOrderedChildrenIdsLookup: {
186
- [parentItemId: string]: string[];
179
+ [parentItemId: string]: TreeViewItemId[];
187
180
  };
188
181
  /**
189
182
  * Index of each child in the ordered children ids of its parent.
@@ -201,6 +194,12 @@ export interface UseTreeViewItemsState<R extends {}> {
201
194
  * The error state of the tree.
202
195
  */
203
196
  error: Error | null;
197
+ /**
198
+ * When equal to 'flat', the tree is rendered as a flat list (children are rendered as siblings of their parents).
199
+ * When equal to 'nested', the tree is rendered with nested children (children are rendered inside the groupTransition slot of their children).
200
+ * Nested DOM structure is not compatible with collapse / expansion animations.
201
+ */
202
+ domStructure: 'flat' | 'nested';
204
203
  };
205
204
  }
206
205
  export type UseTreeViewItemsSignature = TreeViewPluginSignature<{
@@ -208,7 +207,5 @@ export type UseTreeViewItemsSignature = TreeViewPluginSignature<{
208
207
  paramsWithDefaults: UseTreeViewItemsParametersWithDefaults<any>;
209
208
  instance: UseTreeViewItemsInstance<any>;
210
209
  publicAPI: UseTreeViewItemsPublicAPI<any>;
211
- events: UseTreeViewItemsEventLookup;
212
210
  state: UseTreeViewItemsState<TreeViewDefaultItemModelProperties>;
213
- }>;
214
- export {};
211
+ }>;
@@ -6,7 +6,6 @@ import { useStore } from '@mui/x-internals/store';
6
6
  import useEventCallback from '@mui/utils/useEventCallback';
7
7
  import useForkRef from '@mui/utils/useForkRef';
8
8
  import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
9
- import { publishTreeViewEvent } from "../../utils/publishTreeViewEvent.js";
10
9
  import { useTreeViewContext } from "../../TreeViewProvider/index.js";
11
10
  import { TreeViewChildrenItemContext, TreeViewChildrenItemProvider } from "../../TreeViewProvider/TreeViewChildrenItemProvider.js";
12
11
  import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "../useTreeViewItems/useTreeViewItems.utils.js";
@@ -45,9 +44,6 @@ export const useTreeViewJSXItems = ({
45
44
  itemMetaLookup: newItemMetaLookup,
46
45
  itemModelLookup: newItemModelLookup
47
46
  }));
48
- publishTreeViewEvent(instance, 'removeItem', {
49
- id: item.id
50
- });
51
47
  };
52
48
  });
53
49
  const setJSXItemsOrderedChildrenIds = (parentId, orderedChildrenIds) => {
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v8.11.2
2
+ * @mui/x-tree-view v8.12.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -28,16 +28,16 @@ export interface TreeViewSlots {
28
28
  /**
29
29
  * The default icon used to collapse the item.
30
30
  */
31
- collapseIcon?: React.ElementType;
31
+ collapseIcon?: React.ElementType | null;
32
32
  /**
33
33
  * The default icon used to expand the item.
34
34
  */
35
- expandIcon?: React.ElementType;
35
+ expandIcon?: React.ElementType | null;
36
36
  /**
37
37
  * The default icon displayed next to an end item.
38
38
  * This is applied to all Tree Items and can be overridden by the TreeItem `icon` slot prop.
39
39
  */
40
- endIcon?: React.ElementType;
40
+ endIcon?: React.ElementType | null;
41
41
  }
42
42
  export interface TreeViewSlotProps {
43
43
  collapseIcon?: SlotComponentProps<'svg', {}, {}>;
@@ -16,21 +16,25 @@ var _fastObjectShallowCompare = require("@mui/x-internals/fastObjectShallowCompa
16
16
  var _TreeItem = require("../../TreeItem");
17
17
  var _useTreeViewItems = require("../plugins/useTreeViewItems");
18
18
  var _TreeViewProvider = require("../TreeViewProvider");
19
+ var _useTreeViewExpansion = require("../plugins/useTreeViewExpansion");
19
20
  var _jsxRuntime = require("react/jsx-runtime");
20
21
  const _excluded = ["ownerState"];
21
22
  const RichTreeViewItemsContext = /*#__PURE__*/React.createContext(null);
22
23
  if (process.env.NODE_ENV !== "production") RichTreeViewItemsContext.displayName = "RichTreeViewItemsContext";
24
+ const EMPTY_ARRAY = [];
25
+ const selectorNoChildren = () => EMPTY_ARRAY;
23
26
  const WrappedTreeItem = /*#__PURE__*/React.memo(function WrappedTreeItem({
24
27
  itemSlot,
25
28
  itemSlotProps,
26
- itemId
29
+ itemId,
30
+ skipChildren
27
31
  }) {
28
32
  const renderItemForRichTreeView = React.useContext(RichTreeViewItemsContext);
29
33
  const {
30
34
  store
31
35
  } = (0, _TreeViewProvider.useTreeViewContext)();
32
36
  const itemMeta = (0, _store.useStore)(store, _useTreeViewItems.itemsSelectors.itemMeta, itemId);
33
- const children = (0, _store.useStore)(store, _useTreeViewItems.itemsSelectors.itemOrderedChildrenIds, itemId);
37
+ const children = (0, _store.useStore)(store, skipChildren ? selectorNoChildren : _useTreeViewItems.itemsSelectors.itemOrderedChildrenIds, itemId);
34
38
  const Item = itemSlot ?? _TreeItem.TreeItem;
35
39
  const _useSlotProps = (0, _useSlotProps2.default)({
36
40
  elementType: Item,
@@ -61,14 +65,17 @@ function RichTreeViewItems(props) {
61
65
  } = (0, _TreeViewProvider.useTreeViewContext)();
62
66
  const itemSlot = slots?.item;
63
67
  const itemSlotProps = slotProps?.item;
64
- const items = (0, _store.useStore)(store, _useTreeViewItems.itemsSelectors.itemOrderedChildrenIds, null);
68
+ const domStructure = (0, _store.useStore)(store, _useTreeViewItems.itemsSelectors.domStructure);
69
+ const items = (0, _store.useStore)(store, domStructure === 'flat' ? state => _useTreeViewExpansion.expansionSelectors.flatList(state) : state => _useTreeViewItems.itemsSelectors.itemOrderedChildrenIds(state, null));
70
+ const skipChildren = domStructure === 'flat';
65
71
  const renderItem = React.useCallback(itemId => {
66
72
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(WrappedTreeItem, {
67
73
  itemSlot: itemSlot,
68
74
  itemSlotProps: itemSlotProps,
69
- itemId: itemId
75
+ itemId: itemId,
76
+ skipChildren: skipChildren
70
77
  }, itemId);
71
- }, [itemSlot, itemSlotProps]);
78
+ }, [itemSlot, itemSlotProps, skipChildren]);
72
79
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(RichTreeViewItemsContext.Provider, {
73
80
  value: renderItem,
74
81
  children: items.map(renderItem)
@@ -91,7 +91,7 @@ const useTreeViewExpansion = ({
91
91
  });
92
92
  });
93
93
  const isItemExpanded = (0, _useEventCallback.default)(itemId => {
94
- return _useTreeViewExpansion.expansionSelectors.isItemExpandable(store.state, itemId);
94
+ return _useTreeViewExpansion.expansionSelectors.isItemExpanded(store.state, itemId);
95
95
  });
96
96
  const expandAllSiblings = (event, itemId) => {
97
97
  const itemMeta = _useTreeViewItems.itemsSelectors.itemMeta(store.state, itemId);
@@ -6,11 +6,13 @@ export declare const expansionSelectors: {
6
6
  */
7
7
  expandedItemsRaw: (state: TreeViewState<[UseTreeViewExpansionSignature]>) => string[];
8
8
  /**
9
- * Get the expanded items as a Map.
10
- * @param {TreeViewState<[UseTreeViewExpansionSignature]>} state The state of the tree view.
11
- * @returns {TreeViewExpansionValue} The expanded items as a Map.
9
+ * Gets the expanded items as a Map.
12
10
  */
13
11
  expandedItemsMap: (args_0: import("../../corePlugins/useTreeViewId/useTreeViewId.types.js").UseTreeViewIdState & import("./useTreeViewExpansion.types.js").UseTreeViewExpansionState & Partial<{}>) => Map<string, true>;
12
+ /**
13
+ * Gets the items to render as a flat list (the descendants of an expanded item are listed as siblings of the item).
14
+ */
15
+ flatList: (args_0: import("../../corePlugins/useTreeViewId/useTreeViewId.types.js").UseTreeViewIdState & import("./useTreeViewExpansion.types.js").UseTreeViewExpansionState & Partial<{}>) => string[];
14
16
  /**
15
17
  * Gets the slot that triggers the item's expansion when clicked.
16
18
  */
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.expansionSelectors = void 0;
7
7
  var _store = require("@mui/x-internals/store");
8
8
  var _useTreeViewItems = require("../useTreeViewItems/useTreeViewItems.selectors");
9
+ var _useTreeViewItems2 = require("../useTreeViewItems");
9
10
  const expandedItemMapSelector = (0, _store.createSelectorMemoized)(state => state.expansion.expandedItems, expandedItems => {
10
11
  const expandedItemsMap = new Map();
11
12
  expandedItems.forEach(id => {
@@ -19,11 +20,26 @@ const expansionSelectors = exports.expansionSelectors = {
19
20
  */
20
21
  expandedItemsRaw: (0, _store.createSelector)(state => state.expansion.expandedItems),
21
22
  /**
22
- * Get the expanded items as a Map.
23
- * @param {TreeViewState<[UseTreeViewExpansionSignature]>} state The state of the tree view.
24
- * @returns {TreeViewExpansionValue} The expanded items as a Map.
23
+ * Gets the expanded items as a Map.
25
24
  */
26
25
  expandedItemsMap: expandedItemMapSelector,
26
+ /**
27
+ * Gets the items to render as a flat list (the descendants of an expanded item are listed as siblings of the item).
28
+ */
29
+ flatList: (0, _store.createSelectorMemoized)(_useTreeViewItems.itemsSelectors.itemOrderedChildrenIdsLookup, expandedItemMapSelector, (itemOrderedChildrenIds, expandedItemsMap) => {
30
+ function appendChildren(itemId) {
31
+ if (!expandedItemsMap.has(itemId)) {
32
+ return [itemId];
33
+ }
34
+ const itemsWithDescendants = [itemId];
35
+ const children = itemOrderedChildrenIds[itemId] || [];
36
+ for (const childId of children) {
37
+ itemsWithDescendants.push(...appendChildren(childId));
38
+ }
39
+ return itemsWithDescendants;
40
+ }
41
+ return (itemOrderedChildrenIds[_useTreeViewItems2.TREE_VIEW_ROOT_PARENT_ID] ?? []).flatMap(appendChildren);
42
+ }),
27
43
  /**
28
44
  * Gets the slot that triggers the item's expansion when clicked.
29
45
  */
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.useTreeViewFocus = void 0;
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
  var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
10
- var _useInstanceEventHandler = require("../../hooks/useInstanceEventHandler");
10
+ var _store = require("@mui/x-internals/store");
11
11
  var _useTreeViewFocus = require("./useTreeViewFocus.selectors");
12
12
  var _useTreeViewExpansion = require("../useTreeViewExpansion/useTreeViewExpansion.selectors");
13
13
  var _useTreeViewItems = require("../useTreeViewItems/useTreeViewItems.selectors");
@@ -59,14 +59,23 @@ const useTreeViewFocus = ({
59
59
  }
60
60
  setFocusedItemId(null);
61
61
  });
62
- (0, _useInstanceEventHandler.useInstanceEventHandler)(instance, 'removeItem', ({
63
- id
64
- }) => {
62
+
63
+ // Whenever the items change, we need to ensure the focused item is still present.
64
+ (0, _store.useStoreEffect)(store, _useTreeViewItems.itemsSelectors.itemMetaLookup, () => {
65
65
  const focusedItemId = _useTreeViewFocus.focusSelectors.focusedItemId(store.state);
66
+ if (focusedItemId == null) {
67
+ return;
68
+ }
69
+ const hasItemBeenRemoved = !_useTreeViewItems.itemsSelectors.itemMeta(store.state, focusedItemId);
70
+ if (!hasItemBeenRemoved) {
71
+ return;
72
+ }
66
73
  const defaultFocusableItemId = _useTreeViewFocus.focusSelectors.defaultFocusableItemId(store.state);
67
- if (focusedItemId === id && defaultFocusableItemId != null) {
68
- innerFocusItem(null, defaultFocusableItemId);
74
+ if (defaultFocusableItemId == null) {
75
+ setFocusedItemId(null);
76
+ return;
69
77
  }
78
+ innerFocusItem(null, defaultFocusableItemId);
70
79
  });
71
80
  const createRootHandleFocus = otherHandlers => event => {
72
81
  otherHandlers.onFocus?.(event);
@@ -9,10 +9,10 @@ export interface UseTreeViewFocusPublicAPI {
9
9
  *
10
10
  * If the item is the child of a collapsed item, then this method will do nothing.
11
11
  * Make sure to expand the ancestors of the item before calling this method if needed.
12
- * @param {React.SyntheticEvent} event The DOM event that triggered the change.
12
+ * @param {React.SyntheticEvent | null} event The DOM event that triggered the change.
13
13
  * @param {TreeViewItemId} itemId The id of the item to focus.
14
14
  */
15
- focusItem: (event: React.SyntheticEvent, itemId: string) => void;
15
+ focusItem: (event: React.SyntheticEvent | null, itemId: string) => void;
16
16
  }
17
17
  export interface UseTreeViewFocusInstance extends UseTreeViewFocusPublicAPI {
18
18
  /**
@@ -10,7 +10,6 @@ exports.useTreeViewItems = void 0;
10
10
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
11
  var React = _interopRequireWildcard(require("react"));
12
12
  var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
13
- var _publishTreeViewEvent = require("../../utils/publishTreeViewEvent");
14
13
  var _useTreeViewItems = require("./useTreeViewItems.utils");
15
14
  var _TreeViewItemDepthContext = require("../../TreeViewItemDepthContext");
16
15
  var _useTreeViewItems2 = require("./useTreeViewItems.selectors");
@@ -186,13 +185,6 @@ const useTreeViewItems = ({
186
185
  itemChildrenIndexesLookup: newState.itemChildrenIndexesLookup
187
186
  };
188
187
  }
189
- Object.values(store.state.items.itemMetaLookup).forEach(item => {
190
- if (!newItems.itemMetaLookup[item.id]) {
191
- (0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
192
- id: item.id
193
- });
194
- }
195
- });
196
188
  store.set('items', (0, _extends2.default)({}, store.state.items, newItems));
197
189
  }
198
190
  };
@@ -207,9 +199,6 @@ const useTreeViewItems = ({
207
199
  const newMetaMap = Object.keys(store.state.items.itemMetaLookup).reduce((acc, key) => {
208
200
  const item = store.state.items.itemMetaLookup[key];
209
201
  if (item.parentId === parentId) {
210
- (0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
211
- id: item.id
212
- });
213
202
  return acc;
214
203
  }
215
204
  return (0, _extends2.default)({}, acc, {
@@ -239,13 +228,6 @@ const useTreeViewItems = ({
239
228
  getItemLabel: params.getItemLabel,
240
229
  getItemChildren: params.getItemChildren
241
230
  });
242
- Object.values(store.state.items.itemMetaLookup).forEach(item => {
243
- if (!newState.itemMetaLookup[item.id]) {
244
- (0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
245
- id: item.id
246
- });
247
- }
248
- });
249
231
  store.set('items', (0, _extends2.default)({}, store.state.items, newState));
250
232
  }, [instance, store, params.items, params.disabledItemsFocusable, params.isItemDisabled, params.getItemId, params.getItemLabel, params.getItemChildren]);
251
233
 
@@ -292,7 +274,8 @@ useTreeViewItems.getInitialState = params => ({
292
274
  getItemChildren: params.getItemChildren
293
275
  }), {
294
276
  loading: false,
295
- error: null
277
+ error: null,
278
+ domStructure: 'nested'
296
279
  })
297
280
  });
298
281
  useTreeViewItems.applyDefaultValuesToParams = ({
@@ -9,6 +9,10 @@ export declare const itemsSelectors: {
9
9
  * Gets the error state for the Tree View.
10
10
  */
11
11
  error: (state: TreeViewState<[UseTreeViewItemsSignature]>) => Error | null;
12
+ /**
13
+ * Gets the DOM structure of the Tree View.
14
+ */
15
+ domStructure: (state: TreeViewState<[UseTreeViewItemsSignature]>) => "flat" | "nested";
12
16
  /**
13
17
  * Checks whether the disabled items are focusable.
14
18
  */
@@ -19,6 +23,12 @@ export declare const itemsSelectors: {
19
23
  itemMetaLookup: (state: TreeViewState<[UseTreeViewItemsSignature]>) => {
20
24
  [itemId: string]: TreeViewItemMeta;
21
25
  };
26
+ /**
27
+ * Gets the ordered children ids of all items.
28
+ */
29
+ itemOrderedChildrenIdsLookup: (state: TreeViewState<[UseTreeViewItemsSignature]>) => {
30
+ [parentItemId: string]: string[];
31
+ };
22
32
  /**
23
33
  * Gets the meta-information of an item.
24
34
  */
@@ -16,6 +16,10 @@ const itemsSelectors = exports.itemsSelectors = {
16
16
  * Gets the error state for the Tree View.
17
17
  */
18
18
  error: (0, _store.createSelector)(state => state.items.error),
19
+ /**
20
+ * Gets the DOM structure of the Tree View.
21
+ */
22
+ domStructure: (0, _store.createSelector)(state => state.items.domStructure),
19
23
  /**
20
24
  * Checks whether the disabled items are focusable.
21
25
  */
@@ -24,6 +28,10 @@ const itemsSelectors = exports.itemsSelectors = {
24
28
  * Gets the meta-information of all items.
25
29
  */
26
30
  itemMetaLookup: (0, _store.createSelector)(state => state.items.itemMetaLookup),
31
+ /**
32
+ * Gets the ordered children ids of all items.
33
+ */
34
+ itemOrderedChildrenIdsLookup: (0, _store.createSelector)(state => state.items.itemOrderedChildrenIdsLookup),
27
35
  /**
28
36
  * Gets the meta-information of an item.
29
37
  */
@@ -149,13 +149,6 @@ export interface UseTreeViewItemsParameters<R extends {
149
149
  export type UseTreeViewItemsParametersWithDefaults<R extends {
150
150
  children?: R[];
151
151
  }> = DefaultizedProps<UseTreeViewItemsParameters<R>, 'disabledItemsFocusable' | 'itemChildrenIndentation'>;
152
- interface UseTreeViewItemsEventLookup {
153
- removeItem: {
154
- params: {
155
- id: string;
156
- };
157
- };
158
- }
159
152
  export interface UseTreeViewItemsState<R extends {}> {
160
153
  items: {
161
154
  /**
@@ -183,7 +176,7 @@ export interface UseTreeViewItemsState<R extends {}> {
183
176
  * Ordered children ids of each item.
184
177
  */
185
178
  itemOrderedChildrenIdsLookup: {
186
- [parentItemId: string]: string[];
179
+ [parentItemId: string]: TreeViewItemId[];
187
180
  };
188
181
  /**
189
182
  * Index of each child in the ordered children ids of its parent.
@@ -201,6 +194,12 @@ export interface UseTreeViewItemsState<R extends {}> {
201
194
  * The error state of the tree.
202
195
  */
203
196
  error: Error | null;
197
+ /**
198
+ * When equal to 'flat', the tree is rendered as a flat list (children are rendered as siblings of their parents).
199
+ * When equal to 'nested', the tree is rendered with nested children (children are rendered inside the groupTransition slot of their children).
200
+ * Nested DOM structure is not compatible with collapse / expansion animations.
201
+ */
202
+ domStructure: 'flat' | 'nested';
204
203
  };
205
204
  }
206
205
  export type UseTreeViewItemsSignature = TreeViewPluginSignature<{
@@ -208,7 +207,5 @@ export type UseTreeViewItemsSignature = TreeViewPluginSignature<{
208
207
  paramsWithDefaults: UseTreeViewItemsParametersWithDefaults<any>;
209
208
  instance: UseTreeViewItemsInstance<any>;
210
209
  publicAPI: UseTreeViewItemsPublicAPI<any>;
211
- events: UseTreeViewItemsEventLookup;
212
210
  state: UseTreeViewItemsState<TreeViewDefaultItemModelProperties>;
213
- }>;
214
- export {};
211
+ }>;
@@ -13,7 +13,6 @@ var _store = require("@mui/x-internals/store");
13
13
  var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
14
14
  var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef"));
15
15
  var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
16
- var _publishTreeViewEvent = require("../../utils/publishTreeViewEvent");
17
16
  var _TreeViewProvider = require("../../TreeViewProvider");
18
17
  var _TreeViewChildrenItemProvider = require("../../TreeViewProvider/TreeViewChildrenItemProvider");
19
18
  var _useTreeViewItems = require("../useTreeViewItems/useTreeViewItems.utils");
@@ -52,9 +51,6 @@ const useTreeViewJSXItems = ({
52
51
  itemMetaLookup: newItemMetaLookup,
53
52
  itemModelLookup: newItemModelLookup
54
53
  }));
55
- (0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
56
- id: item.id
57
- });
58
54
  };
59
55
  });
60
56
  const setJSXItemsOrderedChildrenIds = (parentId, orderedChildrenIds) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-tree-view",
3
- "version": "8.11.2",
3
+ "version": "8.12.0",
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": "8.11.2"
41
+ "@mui/x-internals": "8.12.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@emotion/react": "^11.9.0",