@mui/x-tree-view-pro 9.0.0-beta.0 → 9.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,271 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.0.0
4
+
5
+ <!-- generated comparing v9.0.0-rc.0..master -->
6
+
7
+ _Apr 8, 2026_
8
+
9
+ 🥳 We're excited to announce the stable release of MUI X v9!
10
+ This major release includes many new features and improvements. Here are some highlights ✨:
11
+
12
+ - Data Grid – [Charts integration](https://mui.com/x/react-data-grid/charts-integration/) [Premium]
13
+ - Data Grid – [AI Assistant](https://mui.com/x/react-data-grid/ai-assistant/) [Premium]
14
+ - Data Grid – [Undo and redo](https://mui.com/x/react-data-grid/undo-redo/) [Premium]
15
+ - Data Grid – [Drag fill](https://mui.com/x/react-data-grid/clipboard/#drag-to-fill) [Premium]
16
+ - Data Grid – [longText column type](https://mui.com/x/react-data-grid/column-definition/#column-types)
17
+ - Charts – [Interaction and accessibility](https://mui.com/x/react-charts/accessibility/)
18
+ - Charts – [Candlestick](https://mui.com/x/react-charts/candlestick/) [Premium]
19
+ - Charts – [Range bar charts](https://mui.com/x/react-charts/range-bar/) [Premium]
20
+ - Charts – [WebGL Heatmap renderer](https://mui.com/x/react-charts/heatmap/#webgl-renderer) [Premium]
21
+ - Tree View – [Virtualization](https://mui.com/x/react-tree-view/rich-tree-view/virtualization/) [Pro]
22
+ - New [Scheduler](https://mui.com/x/react-scheduler/) packages [Alpha]
23
+
24
+ We'd like to extend a big thank you to the 5 contributors who made this release possible.
25
+ The following team members contributed to this release:
26
+ @DanailH, @LukasTy, @MBilalShafi, @oliviertassinari, @siriwatknp
27
+
28
+ ### Data Grid
29
+
30
+ #### `@mui/x-data-grid@9.0.0`
31
+
32
+ Internal changes.
33
+
34
+ #### `@mui/x-data-grid-pro@9.0.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
35
+
36
+ Same changes as in `@mui/x-data-grid@9.0.0`, plus:
37
+
38
+ - [DataGridPro] Preserve parent selection for non-selectable children (#21132) @MBilalShafi
39
+
40
+ #### `@mui/x-data-grid-premium@9.0.0` [![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@9.0.0`, plus:
43
+
44
+ - [DataGridPremium] Drag fill (#21717) @MBilalShafi
45
+
46
+ ### Date and Time Pickers
47
+
48
+ #### Breaking changes
49
+
50
+ - Removed the legacy Pickers and Field TextField props (for example: `InputProps`) in favor of the nested `slotProps`. [Read more](https://mui.com/x/migration/migration-pickers-v8/#drop-deprecated-pickerstextfield-props)
51
+ - The `utils` field in `PickersAdapterContextValue` has been removed in favor of the `adapter` field.
52
+ This should no longer affect you, as the context export has also been removed.
53
+ - `MuiPickersAdapterContext` export has been removed.
54
+ Prefer using the `usePickerAdapter` hook. [Read more](https://mui.com/x/migration/migration-pickers-v8/#localizationprovider-breaking-changes).
55
+
56
+ #### `@mui/x-date-pickers@9.0.0`
57
+
58
+ - [pickers] Refactor `PickersTextField` to use `slotProps` approach (#22002) @LukasTy
59
+ - [pickers] Remove deprecated LocalizationProvider legacy API (#22010) @LukasTy
60
+
61
+ #### `@mui/x-date-pickers-pro@9.0.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
62
+
63
+ Same changes as in `@mui/x-date-pickers@9.0.0`.
64
+
65
+ ### Charts
66
+
67
+ #### `@mui/x-charts@9.0.0`
68
+
69
+ Internal changes.
70
+
71
+ #### `@mui/x-charts-pro@9.0.0` [![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-charts@9.0.0`.
74
+
75
+ #### `@mui/x-charts-premium@9.0.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
76
+
77
+ Same changes as in `@mui/x-charts-pro@9.0.0`.
78
+
79
+ ### Tree View
80
+
81
+ #### `@mui/x-tree-view@9.0.0`
82
+
83
+ Internal changes.
84
+
85
+ #### `@mui/x-tree-view-pro@9.0.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
86
+
87
+ Same changes as in `@mui/x-tree-view@9.0.0`.
88
+
89
+ ### Scheduler
90
+
91
+ #### `@mui/x-scheduler@9.0.0-alpha.0`
92
+
93
+ Internal changes.
94
+
95
+ #### `@mui/x-scheduler-premium@9.0.0-alpha.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
96
+
97
+ Same changes as in `@mui/x-scheduler-pro@9.0.0-alpha.0`.
98
+
99
+ ### Codemod
100
+
101
+ #### `@mui/x-codemod@9.0.0`
102
+
103
+ Internal changes.
104
+
105
+ ### Docs
106
+
107
+ - [docs] Add explanation for v8 -> v9 license migration (#22004) @DanailH
108
+
109
+ ### Core
110
+
111
+ - [code-infra] Optimize dependency definition (#22006) @LukasTy
112
+ - [internal] Prepare v9 stable (#22018) @siriwatknp
113
+ - [internal] Remove 'conf' from codebase (#21989) @oliviertassinari
114
+
115
+ ## 9.0.0-rc.0
116
+
117
+ <!-- generated comparing v9.0.0-beta.0..master -->
118
+
119
+ _Apr 7, 2026_
120
+
121
+ We'd like to extend a big thank you to the 18 contributors who made this release possible.
122
+
123
+ Special thanks go out to these community members for their valuable contributions:
124
+ @mixelburg, @sibananda485, @youjin-hong
125
+
126
+ The following team members contributed to this release:
127
+ @aemartos, @alexfauquette, @arminmeh, @brijeshb42, @flaviendelangle, @JCQuintas, @LukasTy, @mapache-salvaje, @MBilalShafi, @michelengelen, @noraleonte, @rita-codes, @romgrk, @siriwatknp, @ZeeshanTamboli
128
+
129
+ ### Data Grid
130
+
131
+ #### `@mui/x-data-grid@9.0.0-rc.0`
132
+
133
+ - [DataGrid] Rename filter panel `Columns` label to singular `Column` (#21935) @youjin-hong
134
+ - [DataGrid] Export `GridColumnUnsortedIconProps` for custom column icon slots (#21658) @mixelburg
135
+ - [DataGrid] Remove `x-virtualizer`'s `virtualScroller` from public API (#21936) @romgrk
136
+ - [DataGrid][virtualizer] Scrolling without render gaps (#21616) @romgrk
137
+
138
+ #### `@mui/x-data-grid-pro@9.0.0-rc.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
139
+
140
+ Same changes as in `@mui/x-data-grid@9.0.0-rc.0`, plus:
141
+
142
+ - [DataGridPro] Improve trigger for nested row reordering (#21642) @MBilalShafi
143
+ - [DataGridPro] Undeprecate `onRowsScrollEnd` prop (#21912) @MBilalShafi
144
+
145
+ #### `@mui/x-data-grid-premium@9.0.0-rc.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
146
+
147
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-rc.0`, plus:
148
+
149
+ - [DataGridPremium] Fix clipboard paste issue in portal (#21931) @sibananda485
150
+
151
+ ### Date and Time Pickers
152
+
153
+ #### Breaking changes
154
+
155
+ - Accessible DOM structure is now the only default. [Read more](https://mui.com/x/migration/migration-pickers-v8/#accessible-dom-structure-is-now-the-default)
156
+ - The `PickerDay2` and `DateRangePickerDay2` components were propagated to stable while removing the previous defaults. [Read more](https://mui.com/x/migration/migration-pickers-v8/#day-slot)
157
+
158
+ #### `@mui/x-date-pickers@9.0.0-rc.0`
159
+
160
+ - [pickers] Remove `PickersDay` and `DateRangePickerDay` and promote their `2` versions as replacements (#21739) @michelengelen
161
+
162
+ #### `@mui/x-date-pickers-pro@9.0.0-rc.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
163
+
164
+ Same changes as in `@mui/x-date-pickers@9.0.0-rc.0`.
165
+
166
+ ### Charts
167
+
168
+ #### `@mui/x-charts@9.0.0-rc.0.0`
169
+
170
+ - [charts] Make line visibility toggle start from the baseline (#21893) @alexfauquette
171
+ - [charts] Remove the container overflow (#21955) @alexfauquette
172
+ - [charts] Revert `theme.alpha` for non-channel token (#21965) @siriwatknp
173
+
174
+ #### `@mui/x-charts-pro@9.0.0-rc.0.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
175
+
176
+ Same changes as in `@mui/x-charts@9.0.0-rc.0.0`, plus:
177
+
178
+ - [charts-pro] Zoom slider touch improvements (#21832) @JCQuintas
179
+ - [charts-pro] Add `seriesIds` filter to zoom slider preview (#21933) @JCQuintas
180
+ - [charts-pro] Fix zoom slider preview with discard filter mode (#21883) @JCQuintas
181
+
182
+ #### `@mui/x-charts-premium@9.0.0-rc.0.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
183
+
184
+ Same changes as in `@mui/x-charts-pro@9.0.0-rc.0.0`, plus:
185
+
186
+ - [charts-premium] Add series `valueFormatter` to candlestick chart (#21905) @JCQuintas
187
+ - [charts-premium] Add zoom slider preview support for candlestick charts (#21914) @JCQuintas
188
+ - [charts-premium] Allow color customization in `Candlestick` chart (#21838) @JCQuintas
189
+ - [charts-premium] Support hide/show for OHLC (candlestick) series (#21807) @Copilot
190
+ - [charts-premium] Add `dataset` support to `Candlestick` chart (#21872) @JCQuintas
191
+ - [charts-premium] Add candlestick page to sidebar navigation (#21834) @JCQuintas
192
+
193
+ ### Tree View
194
+
195
+ #### `@mui/x-tree-view@9.0.0-rc.0`
196
+
197
+ Internal changes.
198
+
199
+ #### `@mui/x-tree-view-pro@9.0.0-rc.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
200
+
201
+ Same changes as in `@mui/x-tree-view@9.0.0-rc.0`, plus:
202
+
203
+ - [RichTreeViewPro] Allow to auto-expand lazy loaded items (#21759) @flaviendelangle
204
+
205
+ ### Scheduler
206
+
207
+ #### `@mui/x-scheduler@9.0.0-alpha.0`
208
+
209
+ - [scheduler] Add locale files, adapt l10n scripts, and add localization table to docs (#21870) @rita-codes
210
+ - [scheduler] Add planned features to the docs (#21705) @rita-codes
211
+ - [scheduler] Add scheduler to docs introduction (#21845) @rita-codes
212
+ - [scheduler] Add wide docs to scheduler (#21860) @noraleonte
213
+ - [scheduler] All day event bugfixes (#21884) @noraleonte
214
+ - [scheduler] Autofocus title field (#21947) @noraleonte
215
+ - [scheduler] Change default event creation trigger to single click (#21979) @rita-codes
216
+ - [scheduler] Change order of the views on the view selector (#21904) @rita-codes
217
+ - [scheduler] Disabled border color for the repeat day picker in dark mode (#21987) @rita-codes
218
+ - [scheduler] Drop unused dependency (#21956) @flaviendelangle
219
+ - [scheduler] Fix all-day event shifting to previous day in negative UTC offsets (#21994) @rita-codes
220
+ - [scheduler] Fix dark theme localization demos (#21992) @noraleonte
221
+ - [scheduler] Fix licensing confusion in docs (#21939) @rita-codes
222
+ - [scheduler] Fix preferences menu width shift when toggling options + Improve preferences menu accessibility (#21902) @rita-codes
223
+ - [scheduler] Prepare for the alpha launch (#21859) @rita-codes
224
+ - [scheduler] Sync Base UI internals and apply good practices (#21946) @flaviendelangle
225
+ - [scheduler] Update close modal aria label translation (#21940) @rita-codes
226
+ - [scheduler] Add Spanish (es-ES) locale (#21900) @rita-codes
227
+ - [scheduler] Improve French (fr-FR) locale (#21941) @rita-codes
228
+ - [scheduler] Improve Romanian (ro-RO) locale (#21942) @rita-codes
229
+
230
+ #### `@mui/x-scheduler-premium@9.0.0-alpha.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
231
+
232
+ Same changes as in `@mui/x-scheduler@9.0.0-alpha.0`.
233
+
234
+ ### Codemod
235
+
236
+ #### `@mui/x-codemod@9.0.0-rc.0`
237
+
238
+ Internal changes.
239
+
240
+ ### Docs
241
+
242
+ - [docs] Fix JSDOM → jsdom casing (#21907) @JCQuintas
243
+ - [docs] Remove Joy UI references and dependency (#21937) @siriwatknp
244
+ - [docs] Remove none generated files (#21886) @alexfauquette
245
+ - [docs] Remove unused interactive demo code (#21945) @LukasTy
246
+ - [docs] Revise the Funnel doc (#21677) @mapache-salvaje
247
+ - [docs] Revise the Line chart docs (#21554) @mapache-salvaje
248
+ - [docs] Revise the Radar doc (#21674) @mapache-salvaje
249
+ - [docs] Revise the Sankey doc (#21678) @mapache-salvaje
250
+ - [docs] Revise the Scatter chart docs (#21564) @mapache-salvaje
251
+
252
+ ### Core
253
+
254
+ - [docs-infra] Update to the latest monorepo (#21971) @brijeshb42
255
+ - [internal] Remove checks for `materialVersion >= 6` (#21975) @LukasTy
256
+
257
+ ### Miscellaneous
258
+
259
+ - [core] Bump @mui/material to v9.0.0-beta.1 (#21858) @siriwatknp
260
+ - [core] Update browserslistrc (#21974) @siriwatknp
261
+ - [deps] Bump minimum core packages to 7.3.0 to adopt theme color manipulator (#21892) @siriwatknp
262
+ - [telemetry] Prefer upstream remote over origin for `projectId` (#21882) @aemartos
263
+ - [telemetry] Send `repoHash`, `[x]packageNameHash`, and `rootPathHash` alongside `projectId` (#21896) @aemartos
264
+ - [test] Exclude flaky `DataGrid` argos test (#21977) @MBilalShafi
265
+ - [test] Fix flaky `DataGrid` test (#22000) @arminmeh
266
+ - [test] Remove `componentsProp` test from `describeConformance` (#21897) @ZeeshanTamboli
267
+ - [x-license] Change `orderId` type from `number` to `string` (#21885) @aemartos
268
+
3
269
  ## 9.0.0-beta.0
4
270
 
5
271
  <!-- generated comparing v9.0.0-alpha.4..master -->
@@ -313,7 +579,7 @@ Same changes as in `@mui/x-charts-pro@9.0.0-alpha.3`, plus:
313
579
  - Remove deprecated CSS state classes from `treeItemClasses`: `expanded`, `selected`, `focused`, `disabled`, `editable`, `editing` (use `[data-expanded]`, `[data-selected]`, etc.)
314
580
  - The `<RichTreeViewPro />` component has now virtualization enabled by default.
315
581
  - The items used inside the `<RichTreeViewPro />` now have a default height of `32px`.
316
- - The events of the `<RichTreeViewPro />` are now rendered as a flat list instead of a nested tree.
582
+ - The items of the `<RichTreeViewPro />` are now rendered as a flat list instead of a nested tree.
317
583
 
318
584
  #### `@mui/x-tree-view@9.0.0-alpha.3`
319
585
 
@@ -59,8 +59,8 @@ const RichTreeViewProRoot = exports.RichTreeViewProRoot = (0, _zeroStyled.styled
59
59
  }
60
60
  });
61
61
  const packageInfo = {
62
- releaseDate: "MTc3NDU2OTYwMDAwMA==",
63
- version: "9.0.0-beta.0",
62
+ releaseDate: "MTc3NTYwNjQwMDAwMA==",
63
+ version: "9.0.0",
64
64
  name: 'x-tree-view-pro'
65
65
  };
66
66
 
@@ -369,6 +369,15 @@ process.env.NODE_ENV !== "production" ? RichTreeViewPro.propTypes = {
369
369
  * @param {boolean} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
370
370
  */
371
371
  onItemSelectionToggle: _propTypes.default.func,
372
+ /**
373
+ * Callback fired when the children of an item are loaded from the data source.
374
+ * Only relevant for lazy-loaded tree views.
375
+ * @param {object} parameters The parameters of the callback.
376
+ * @param {R[]} parameters.items The items that were loaded.
377
+ * @param {TreeViewItemId | null} parameters.parentId The id of the parent item whose children were loaded. `null` if the root items were loaded.
378
+ * @param {boolean} parameters.isCacheHit `true` if the items were loaded from the cache, `false` if they were fetched from the data source.
379
+ */
380
+ onItemsLazyLoaded: _propTypes.default.func,
372
381
  /**
373
382
  * Callback fired when Tree Items are selected/deselected.
374
383
  * @param {React.SyntheticEvent} event The DOM event that triggered the change. Can be null when the change is caused by the `publicAPI.setItemSelection()` method.
@@ -52,8 +52,8 @@ export const RichTreeViewProRoot = styled('ul', {
52
52
  }
53
53
  });
54
54
  const packageInfo = {
55
- releaseDate: "MTc3NDU2OTYwMDAwMA==",
56
- version: "9.0.0-beta.0",
55
+ releaseDate: "MTc3NTYwNjQwMDAwMA==",
56
+ version: "9.0.0",
57
57
  name: 'x-tree-view-pro'
58
58
  };
59
59
 
@@ -362,6 +362,15 @@ process.env.NODE_ENV !== "production" ? RichTreeViewPro.propTypes = {
362
362
  * @param {boolean} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
363
363
  */
364
364
  onItemSelectionToggle: PropTypes.func,
365
+ /**
366
+ * Callback fired when the children of an item are loaded from the data source.
367
+ * Only relevant for lazy-loaded tree views.
368
+ * @param {object} parameters The parameters of the callback.
369
+ * @param {R[]} parameters.items The items that were loaded.
370
+ * @param {TreeViewItemId | null} parameters.parentId The id of the parent item whose children were loaded. `null` if the root items were loaded.
371
+ * @param {boolean} parameters.isCacheHit `true` if the items were loaded from the cache, `false` if they were fetched from the data source.
372
+ */
373
+ onItemsLazyLoaded: PropTypes.func,
365
374
  /**
366
375
  * Callback fired when Tree Items are selected/deselected.
367
376
  * @param {React.SyntheticEvent} event The DOM event that triggered the change. Can be null when the change is caused by the `publicAPI.setItemSelection()` method.
@@ -138,18 +138,18 @@ export declare function useExtractRichTreeViewProParameters<R extends TreeViewVa
138
138
  onFocusCapture?: React.FocusEventHandler<HTMLUListElement> | undefined;
139
139
  onBlur?: React.FocusEventHandler<HTMLUListElement> | undefined;
140
140
  onBlurCapture?: React.FocusEventHandler<HTMLUListElement> | undefined;
141
- onChange?: React.FormEventHandler<HTMLUListElement> | undefined;
142
- onChangeCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
141
+ onChange?: React.ChangeEventHandler<HTMLUListElement, Element> | undefined;
142
+ onChangeCapture?: React.ChangeEventHandler<HTMLUListElement, Element> | undefined;
143
143
  onBeforeInput?: React.InputEventHandler<HTMLUListElement> | undefined;
144
- onBeforeInputCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
145
- onInput?: React.FormEventHandler<HTMLUListElement> | undefined;
146
- onInputCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
147
- onReset?: React.FormEventHandler<HTMLUListElement> | undefined;
148
- onResetCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
149
- onSubmit?: React.FormEventHandler<HTMLUListElement> | undefined;
150
- onSubmitCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
151
- onInvalid?: React.FormEventHandler<HTMLUListElement> | undefined;
152
- onInvalidCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
144
+ onBeforeInputCapture?: React.InputEventHandler<HTMLUListElement> | undefined;
145
+ onInput?: React.InputEventHandler<HTMLUListElement> | undefined;
146
+ onInputCapture?: React.InputEventHandler<HTMLUListElement> | undefined;
147
+ onReset?: React.ReactEventHandler<HTMLUListElement> | undefined;
148
+ onResetCapture?: React.ReactEventHandler<HTMLUListElement> | undefined;
149
+ onSubmit?: React.SubmitEventHandler<HTMLUListElement> | undefined;
150
+ onSubmitCapture?: React.SubmitEventHandler<HTMLUListElement> | undefined;
151
+ onInvalid?: React.ReactEventHandler<HTMLUListElement> | undefined;
152
+ onInvalidCapture?: React.ReactEventHandler<HTMLUListElement> | undefined;
153
153
  onLoad?: React.ReactEventHandler<HTMLUListElement> | undefined;
154
154
  onLoadCapture?: React.ReactEventHandler<HTMLUListElement> | undefined;
155
155
  onError?: React.ReactEventHandler<HTMLUListElement> | undefined;
@@ -138,18 +138,18 @@ export declare function useExtractRichTreeViewProParameters<R extends TreeViewVa
138
138
  onFocusCapture?: React.FocusEventHandler<HTMLUListElement> | undefined;
139
139
  onBlur?: React.FocusEventHandler<HTMLUListElement> | undefined;
140
140
  onBlurCapture?: React.FocusEventHandler<HTMLUListElement> | undefined;
141
- onChange?: React.FormEventHandler<HTMLUListElement> | undefined;
142
- onChangeCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
141
+ onChange?: React.ChangeEventHandler<HTMLUListElement, Element> | undefined;
142
+ onChangeCapture?: React.ChangeEventHandler<HTMLUListElement, Element> | undefined;
143
143
  onBeforeInput?: React.InputEventHandler<HTMLUListElement> | undefined;
144
- onBeforeInputCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
145
- onInput?: React.FormEventHandler<HTMLUListElement> | undefined;
146
- onInputCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
147
- onReset?: React.FormEventHandler<HTMLUListElement> | undefined;
148
- onResetCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
149
- onSubmit?: React.FormEventHandler<HTMLUListElement> | undefined;
150
- onSubmitCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
151
- onInvalid?: React.FormEventHandler<HTMLUListElement> | undefined;
152
- onInvalidCapture?: React.FormEventHandler<HTMLUListElement> | undefined;
144
+ onBeforeInputCapture?: React.InputEventHandler<HTMLUListElement> | undefined;
145
+ onInput?: React.InputEventHandler<HTMLUListElement> | undefined;
146
+ onInputCapture?: React.InputEventHandler<HTMLUListElement> | undefined;
147
+ onReset?: React.ReactEventHandler<HTMLUListElement> | undefined;
148
+ onResetCapture?: React.ReactEventHandler<HTMLUListElement> | undefined;
149
+ onSubmit?: React.SubmitEventHandler<HTMLUListElement> | undefined;
150
+ onSubmitCapture?: React.SubmitEventHandler<HTMLUListElement> | undefined;
151
+ onInvalid?: React.ReactEventHandler<HTMLUListElement> | undefined;
152
+ onInvalidCapture?: React.ReactEventHandler<HTMLUListElement> | undefined;
153
153
  onLoad?: React.ReactEventHandler<HTMLUListElement> | undefined;
154
154
  onLoadCapture?: React.ReactEventHandler<HTMLUListElement> | undefined;
155
155
  onError?: React.ReactEventHandler<HTMLUListElement> | undefined;
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "__esModule", {
8
8
  exports.useExtractRichTreeViewProParameters = useExtractRichTreeViewProParameters;
9
9
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
10
10
  var React = _interopRequireWildcard(require("react"));
11
- const _excluded = ["apiRef", "slots", "slotProps", "disabledItemsFocusable", "items", "isItemDisabled", "isItemSelectionDisabled", "getItemLabel", "getItemChildren", "getItemId", "onItemClick", "itemChildrenIndentation", "id", "expandedItems", "defaultExpandedItems", "onExpandedItemsChange", "onItemExpansionToggle", "expansionTrigger", "disableSelection", "selectedItems", "defaultSelectedItems", "multiSelect", "checkboxSelection", "selectionPropagation", "onSelectedItemsChange", "onItemSelectionToggle", "onItemFocus", "itemHeight", "onItemLabelChange", "isItemEditable", "domStructure", "dataSource", "dataSourceCache", "itemsReordering", "isItemReorderable", "canMoveItemToNewPosition", "onItemPositionChange", "disableVirtualization"];
11
+ const _excluded = ["apiRef", "slots", "slotProps", "disabledItemsFocusable", "items", "isItemDisabled", "isItemSelectionDisabled", "getItemLabel", "getItemChildren", "getItemId", "onItemClick", "itemChildrenIndentation", "id", "expandedItems", "defaultExpandedItems", "onExpandedItemsChange", "onItemExpansionToggle", "expansionTrigger", "disableSelection", "selectedItems", "defaultSelectedItems", "multiSelect", "checkboxSelection", "selectionPropagation", "onSelectedItemsChange", "onItemSelectionToggle", "onItemFocus", "itemHeight", "onItemLabelChange", "isItemEditable", "domStructure", "dataSource", "dataSourceCache", "onItemsLazyLoaded", "itemsReordering", "isItemReorderable", "canMoveItemToNewPosition", "onItemPositionChange", "disableVirtualization"];
12
12
  function useExtractRichTreeViewProParameters(props) {
13
13
  const {
14
14
  // Props for Provider
@@ -48,6 +48,7 @@ function useExtractRichTreeViewProParameters(props) {
48
48
  // RichTreeViewProStore parameters
49
49
  dataSource,
50
50
  dataSourceCache,
51
+ onItemsLazyLoaded,
51
52
  itemsReordering,
52
53
  isItemReorderable,
53
54
  canMoveItemToNewPosition,
@@ -91,6 +92,7 @@ function useExtractRichTreeViewProParameters(props) {
91
92
  // RichTreeViewProStore parameters
92
93
  dataSource,
93
94
  dataSourceCache,
95
+ onItemsLazyLoaded,
94
96
  itemsReordering,
95
97
  isItemReorderable,
96
98
  canMoveItemToNewPosition,
@@ -102,7 +104,7 @@ function useExtractRichTreeViewProParameters(props) {
102
104
  // RichTreeViewStore parameters
103
105
  onItemLabelChange, isItemEditable, domStructure,
104
106
  // RichTreeViewProStore parameters
105
- dataSource, dataSourceCache, itemsReordering, isItemReorderable, canMoveItemToNewPosition, onItemPositionChange, disableVirtualization]);
107
+ dataSource, dataSourceCache, onItemsLazyLoaded, itemsReordering, isItemReorderable, canMoveItemToNewPosition, onItemPositionChange, disableVirtualization]);
106
108
  return {
107
109
  apiRef,
108
110
  slots,
@@ -1,5 +1,5 @@
1
1
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2
- const _excluded = ["apiRef", "slots", "slotProps", "disabledItemsFocusable", "items", "isItemDisabled", "isItemSelectionDisabled", "getItemLabel", "getItemChildren", "getItemId", "onItemClick", "itemChildrenIndentation", "id", "expandedItems", "defaultExpandedItems", "onExpandedItemsChange", "onItemExpansionToggle", "expansionTrigger", "disableSelection", "selectedItems", "defaultSelectedItems", "multiSelect", "checkboxSelection", "selectionPropagation", "onSelectedItemsChange", "onItemSelectionToggle", "onItemFocus", "itemHeight", "onItemLabelChange", "isItemEditable", "domStructure", "dataSource", "dataSourceCache", "itemsReordering", "isItemReorderable", "canMoveItemToNewPosition", "onItemPositionChange", "disableVirtualization"];
2
+ const _excluded = ["apiRef", "slots", "slotProps", "disabledItemsFocusable", "items", "isItemDisabled", "isItemSelectionDisabled", "getItemLabel", "getItemChildren", "getItemId", "onItemClick", "itemChildrenIndentation", "id", "expandedItems", "defaultExpandedItems", "onExpandedItemsChange", "onItemExpansionToggle", "expansionTrigger", "disableSelection", "selectedItems", "defaultSelectedItems", "multiSelect", "checkboxSelection", "selectionPropagation", "onSelectedItemsChange", "onItemSelectionToggle", "onItemFocus", "itemHeight", "onItemLabelChange", "isItemEditable", "domStructure", "dataSource", "dataSourceCache", "onItemsLazyLoaded", "itemsReordering", "isItemReorderable", "canMoveItemToNewPosition", "onItemPositionChange", "disableVirtualization"];
3
3
  import * as React from 'react';
4
4
  export function useExtractRichTreeViewProParameters(props) {
5
5
  const {
@@ -40,6 +40,7 @@ export function useExtractRichTreeViewProParameters(props) {
40
40
  // RichTreeViewProStore parameters
41
41
  dataSource,
42
42
  dataSourceCache,
43
+ onItemsLazyLoaded,
43
44
  itemsReordering,
44
45
  isItemReorderable,
45
46
  canMoveItemToNewPosition,
@@ -83,6 +84,7 @@ export function useExtractRichTreeViewProParameters(props) {
83
84
  // RichTreeViewProStore parameters
84
85
  dataSource,
85
86
  dataSourceCache,
87
+ onItemsLazyLoaded,
86
88
  itemsReordering,
87
89
  isItemReorderable,
88
90
  canMoveItemToNewPosition,
@@ -94,7 +96,7 @@ export function useExtractRichTreeViewProParameters(props) {
94
96
  // RichTreeViewStore parameters
95
97
  onItemLabelChange, isItemEditable, domStructure,
96
98
  // RichTreeViewProStore parameters
97
- dataSource, dataSourceCache, itemsReordering, isItemReorderable, canMoveItemToNewPosition, onItemPositionChange, disableVirtualization]);
99
+ dataSource, dataSourceCache, onItemsLazyLoaded, itemsReordering, isItemReorderable, canMoveItemToNewPosition, onItemPositionChange, disableVirtualization]);
98
100
  return {
99
101
  apiRef,
100
102
  slots,
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view-pro v9.0.0-beta.0
2
+ * @mui/x-tree-view-pro v9.0.0
3
3
  *
4
4
  * @license SEE LICENSE IN LICENSE
5
5
  * This source code is licensed under the SEE LICENSE IN LICENSE license found in the
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view-pro v9.0.0-beta.0
2
+ * @mui/x-tree-view-pro v9.0.0
3
3
  *
4
4
  * @license SEE LICENSE IN LICENSE
5
5
  * This source code is licensed under the SEE LICENSE IN LICENSE license found in the
@@ -4,8 +4,9 @@ import { RichTreeViewProStoreParameters, RichTreeViewProState } from "./RichTree
4
4
  import { TreeViewLazyLoadingPlugin } from "../plugins/lazyLoading/index.mjs";
5
5
  import { TreeViewItemsReorderingPlugin } from "../plugins/itemsReordering/index.mjs";
6
6
  export declare class RichTreeViewProStore<R extends TreeViewValidItem<R>, Multiple extends boolean | undefined> extends ExtendableRichTreeViewStore<R, Multiple, RichTreeViewProState<R, Multiple>, RichTreeViewProStoreParameters<R, Multiple>> {
7
- lazyLoading: TreeViewLazyLoadingPlugin;
7
+ lazyLoading: TreeViewLazyLoadingPlugin<R>;
8
8
  itemsReordering: TreeViewItemsReorderingPlugin;
9
+ disposeEffect: () => () => void;
9
10
  constructor(parameters: RichTreeViewProStoreParameters<R, Multiple>);
10
11
  buildPublicAPI(): {
11
12
  updateItemChildren: (itemId: import("@mui/x-tree-view").TreeViewItemId | null) => Promise<void>;
@@ -4,8 +4,9 @@ import { RichTreeViewProStoreParameters, RichTreeViewProState } from "./RichTree
4
4
  import { TreeViewLazyLoadingPlugin } from "../plugins/lazyLoading/index.js";
5
5
  import { TreeViewItemsReorderingPlugin } from "../plugins/itemsReordering/index.js";
6
6
  export declare class RichTreeViewProStore<R extends TreeViewValidItem<R>, Multiple extends boolean | undefined> extends ExtendableRichTreeViewStore<R, Multiple, RichTreeViewProState<R, Multiple>, RichTreeViewProStoreParameters<R, Multiple>> {
7
- lazyLoading: TreeViewLazyLoadingPlugin;
7
+ lazyLoading: TreeViewLazyLoadingPlugin<R>;
8
8
  itemsReordering: TreeViewItemsReorderingPlugin;
9
+ disposeEffect: () => () => void;
9
10
  constructor(parameters: RichTreeViewProStoreParameters<R, Multiple>);
10
11
  buildPublicAPI(): {
11
12
  updateItemChildren: (itemId: import("@mui/x-tree-view").TreeViewItemId | null) => Promise<void>;
@@ -12,6 +12,10 @@ var _itemsReordering = require("../plugins/itemsReordering");
12
12
  var _RichTreeViewProStore = require("./RichTreeViewProStore.utils");
13
13
  class RichTreeViewProStore extends _internals.ExtendableRichTreeViewStore {
14
14
  itemsReordering = new _itemsReordering.TreeViewItemsReorderingPlugin(this);
15
+ disposeEffect = () => {
16
+ this.lazyLoading.initEffect();
17
+ return this.timeoutManager.clearAll;
18
+ };
15
19
  constructor(parameters) {
16
20
  super(parameters, 'RichTreeViewPro', _RichTreeViewProStore.parametersToStateMapper);
17
21
  this.lazyLoading = new _lazyLoading.TreeViewLazyLoadingPlugin(this);
@@ -4,7 +4,11 @@ import { TreeViewLazyLoadingPlugin } from "../plugins/lazyLoading/index.mjs";
4
4
  import { TreeViewItemsReorderingPlugin } from "../plugins/itemsReordering/index.mjs";
5
5
  import { parametersToStateMapper } from "./RichTreeViewProStore.utils.mjs";
6
6
  export class RichTreeViewProStore extends ExtendableRichTreeViewStore {
7
- itemsReordering = (() => new TreeViewItemsReorderingPlugin(this))();
7
+ itemsReordering = new TreeViewItemsReorderingPlugin(this);
8
+ disposeEffect = () => {
9
+ this.lazyLoading.initEffect();
10
+ return this.timeoutManager.clearAll;
11
+ };
8
12
  constructor(parameters) {
9
13
  super(parameters, 'RichTreeViewPro', parametersToStateMapper);
10
14
  this.lazyLoading = new TreeViewLazyLoadingPlugin(this);
@@ -32,7 +32,7 @@ export interface RichTreeViewProStoreParameters<R extends TreeViewValidItem<R>,
32
32
  /**
33
33
  * The data source cache object.
34
34
  */
35
- dataSourceCache?: DataSourceCache;
35
+ dataSourceCache?: DataSourceCache<R>;
36
36
  /**
37
37
  * If `true`, the reordering of items is enabled.
38
38
  * @default false
@@ -58,6 +58,19 @@ export interface RichTreeViewProStoreParameters<R extends TreeViewValidItem<R>,
58
58
  oldPosition: TreeViewItemReorderPosition;
59
59
  newPosition: TreeViewItemReorderPosition;
60
60
  }) => boolean;
61
+ /**
62
+ * Callback fired when the children of an item are loaded from the data source.
63
+ * Only relevant for lazy-loaded tree views.
64
+ * @param {object} parameters The parameters of the callback.
65
+ * @param {R[]} parameters.items The items that were loaded.
66
+ * @param {TreeViewItemId | null} parameters.parentId The id of the parent item whose children were loaded. `null` if the root items were loaded.
67
+ * @param {boolean} parameters.isCacheHit `true` if the items were loaded from the cache, `false` if they were fetched from the data source.
68
+ */
69
+ onItemsLazyLoaded?: (parameters: {
70
+ items: R[];
71
+ parentId: TreeViewItemId | null;
72
+ isCacheHit: boolean;
73
+ }) => void;
61
74
  /**
62
75
  * Callback fired when a Tree Item is moved in the tree.
63
76
  * @param {object} parameters The params describing the item re-ordering.
@@ -32,7 +32,7 @@ export interface RichTreeViewProStoreParameters<R extends TreeViewValidItem<R>,
32
32
  /**
33
33
  * The data source cache object.
34
34
  */
35
- dataSourceCache?: DataSourceCache;
35
+ dataSourceCache?: DataSourceCache<R>;
36
36
  /**
37
37
  * If `true`, the reordering of items is enabled.
38
38
  * @default false
@@ -58,6 +58,19 @@ export interface RichTreeViewProStoreParameters<R extends TreeViewValidItem<R>,
58
58
  oldPosition: TreeViewItemReorderPosition;
59
59
  newPosition: TreeViewItemReorderPosition;
60
60
  }) => boolean;
61
+ /**
62
+ * Callback fired when the children of an item are loaded from the data source.
63
+ * Only relevant for lazy-loaded tree views.
64
+ * @param {object} parameters The parameters of the callback.
65
+ * @param {R[]} parameters.items The items that were loaded.
66
+ * @param {TreeViewItemId | null} parameters.parentId The id of the parent item whose children were loaded. `null` if the root items were loaded.
67
+ * @param {boolean} parameters.isCacheHit `true` if the items were loaded from the cache, `false` if they were fetched from the data source.
68
+ */
69
+ onItemsLazyLoaded?: (parameters: {
70
+ items: R[];
71
+ parentId: TreeViewItemId | null;
72
+ isCacheHit: boolean;
73
+ }) => void;
61
74
  /**
62
75
  * Callback fired when a Tree Item is moved in the tree.
63
76
  * @param {object} parameters The params describing the item re-ordering.
@@ -1,18 +1,27 @@
1
- import { TreeViewItemId } from '@mui/x-tree-view/models';
1
+ import { TreeViewItemId, TreeViewValidItem } from '@mui/x-tree-view/models';
2
2
  import { RichTreeViewProStore } from "../../RichTreeViewProStore/RichTreeViewProStore.mjs";
3
3
  export declare const TREE_VIEW_LAZY_LOADED_ITEMS_INITIAL_STATE: {
4
4
  loading: {};
5
5
  errors: {};
6
6
  };
7
- export declare class TreeViewLazyLoadingPlugin {
7
+ export declare class TreeViewLazyLoadingPlugin<R extends TreeViewValidItem<R>> {
8
8
  private store;
9
9
  private nestedDataManager;
10
10
  private cache;
11
- constructor(store: RichTreeViewProStore<any, any>);
11
+ private isInsideOnItemsLazyLoaded;
12
+ private initStarted;
13
+ constructor(store: RichTreeViewProStore<R, any>);
14
+ /**
15
+ * Initialize lazy loading.
16
+ * Called from the store's disposeEffect (inside a useEffect) to avoid side effects during render.
17
+ * Uses a flag to ensure initialization only happens once (handles React 18 StrictMode double-firing effects).
18
+ */
19
+ initEffect: () => void;
12
20
  private init;
13
21
  private handleBeforeItemToggleExpansion;
14
22
  private setItemLoading;
15
23
  private setItemError;
24
+ private callOnItemsLazyLoaded;
16
25
  buildPublicAPI: () => {
17
26
  updateItemChildren: (itemId: TreeViewItemId | null) => Promise<void>;
18
27
  };
@@ -41,6 +50,9 @@ export declare class TreeViewLazyLoadingPlugin {
41
50
  * @param {boolean} [parameters.forceRefresh] Whether to force a refresh of the children when the cache already contains some data.
42
51
  * @returns {Promise<void>} The promise resolved when the items are fetched.
43
52
  */
53
+ private getItemId;
54
+ private getInlineChildren;
55
+ private processNestedItemChildren;
44
56
  fetchItemChildren: ({
45
57
  itemId,
46
58
  forceRefresh
@@ -1,18 +1,27 @@
1
- import { TreeViewItemId } from '@mui/x-tree-view/models';
1
+ import { TreeViewItemId, TreeViewValidItem } from '@mui/x-tree-view/models';
2
2
  import { RichTreeViewProStore } from "../../RichTreeViewProStore/RichTreeViewProStore.js";
3
3
  export declare const TREE_VIEW_LAZY_LOADED_ITEMS_INITIAL_STATE: {
4
4
  loading: {};
5
5
  errors: {};
6
6
  };
7
- export declare class TreeViewLazyLoadingPlugin {
7
+ export declare class TreeViewLazyLoadingPlugin<R extends TreeViewValidItem<R>> {
8
8
  private store;
9
9
  private nestedDataManager;
10
10
  private cache;
11
- constructor(store: RichTreeViewProStore<any, any>);
11
+ private isInsideOnItemsLazyLoaded;
12
+ private initStarted;
13
+ constructor(store: RichTreeViewProStore<R, any>);
14
+ /**
15
+ * Initialize lazy loading.
16
+ * Called from the store's disposeEffect (inside a useEffect) to avoid side effects during render.
17
+ * Uses a flag to ensure initialization only happens once (handles React 18 StrictMode double-firing effects).
18
+ */
19
+ initEffect: () => void;
12
20
  private init;
13
21
  private handleBeforeItemToggleExpansion;
14
22
  private setItemLoading;
15
23
  private setItemError;
24
+ private callOnItemsLazyLoaded;
16
25
  buildPublicAPI: () => {
17
26
  updateItemChildren: (itemId: TreeViewItemId | null) => Promise<void>;
18
27
  };
@@ -41,6 +50,9 @@ export declare class TreeViewLazyLoadingPlugin {
41
50
  * @param {boolean} [parameters.forceRefresh] Whether to force a refresh of the children when the cache already contains some data.
42
51
  * @returns {Promise<void>} The promise resolved when the items are fetched.
43
52
  */
53
+ private getItemId;
54
+ private getInlineChildren;
55
+ private processNestedItemChildren;
44
56
  fetchItemChildren: ({
45
57
  itemId,
46
58
  forceRefresh
@@ -15,14 +15,28 @@ const TREE_VIEW_LAZY_LOADED_ITEMS_INITIAL_STATE = exports.TREE_VIEW_LAZY_LOADED_
15
15
  };
16
16
  class TreeViewLazyLoadingPlugin {
17
17
  nestedDataManager = new _utils2.NestedDataManager(this);
18
+ isInsideOnItemsLazyLoaded = false;
19
+ initStarted = false;
18
20
  constructor(store) {
19
21
  this.store = store;
20
22
  this.cache = store.parameters.dataSourceCache ?? new _utils.DataSourceCacheDefault({});
21
23
  if (store.parameters.dataSource != null) {
22
- this.init();
23
24
  store.subscribeEvent('beforeItemToggleExpansion', this.handleBeforeItemToggleExpansion);
24
25
  }
25
26
  }
27
+
28
+ /**
29
+ * Initialize lazy loading.
30
+ * Called from the store's disposeEffect (inside a useEffect) to avoid side effects during render.
31
+ * Uses a flag to ensure initialization only happens once (handles React 18 StrictMode double-firing effects).
32
+ */
33
+ initEffect = () => {
34
+ if (this.store.parameters.dataSource == null || this.initStarted) {
35
+ return;
36
+ }
37
+ this.initStarted = true;
38
+ this.init();
39
+ };
26
40
  init = () => {
27
41
  const store = this.store;
28
42
  // eslint-disable-next-line consistent-this
@@ -115,6 +129,21 @@ class TreeViewLazyLoadingPlugin {
115
129
  errors
116
130
  }));
117
131
  };
132
+ callOnItemsLazyLoaded(items, parentId, isCacheHit) {
133
+ if (this.isInsideOnItemsLazyLoaded) {
134
+ return;
135
+ }
136
+ this.isInsideOnItemsLazyLoaded = true;
137
+ try {
138
+ this.store.parameters.onItemsLazyLoaded?.({
139
+ items,
140
+ parentId,
141
+ isCacheHit
142
+ });
143
+ } finally {
144
+ this.isInsideOnItemsLazyLoaded = false;
145
+ }
146
+ }
118
147
  buildPublicAPI = () => {
119
148
  return {
120
149
  updateItemChildren: this.updateItemChildren
@@ -151,6 +180,27 @@ class TreeViewLazyLoadingPlugin {
151
180
  * @param {boolean} [parameters.forceRefresh] Whether to force a refresh of the children when the cache already contains some data.
152
181
  * @returns {Promise<void>} The promise resolved when the items are fetched.
153
182
  */
183
+ getItemId = item => this.store.parameters.getItemId ? this.store.parameters.getItemId(item) : item.id;
184
+ getInlineChildren = item => (this.store.parameters.getItemChildren ? this.store.parameters.getItemChildren(item) : item.children) ?? [];
185
+ processNestedItemChildren = items => {
186
+ const {
187
+ getChildrenCount
188
+ } = this.store.parameters.dataSource;
189
+ for (const item of items) {
190
+ const children = this.getInlineChildren(item);
191
+ if (children.length === 0) {
192
+ continue;
193
+ }
194
+ const itemId = this.getItemId(item);
195
+ this.cache.set(itemId, children);
196
+ this.store.items.setItemChildren({
197
+ items: children,
198
+ parentId: itemId,
199
+ getChildrenCount
200
+ });
201
+ this.processNestedItemChildren(children);
202
+ }
203
+ };
154
204
  fetchItemChildren = async ({
155
205
  itemId,
156
206
  forceRefresh
@@ -186,6 +236,7 @@ class TreeViewLazyLoadingPlugin {
186
236
  getChildrenCount
187
237
  });
188
238
  this.setItemLoading(itemId, false);
239
+ this.callOnItemsLazyLoaded(cachedData, itemId, true);
189
240
  return;
190
241
  }
191
242
 
@@ -216,6 +267,10 @@ class TreeViewLazyLoadingPlugin {
216
267
  parentId: itemId,
217
268
  getChildrenCount
218
269
  });
270
+ // pre-cache any inline nested children so expanding them requires no extra network call
271
+ this.processNestedItemChildren(response);
272
+ // notify the user that new items have been loaded
273
+ this.callOnItemsLazyLoaded(response, itemId, false);
219
274
  } catch (error) {
220
275
  const childrenFetchError = error;
221
276
  // set the item error in the state
@@ -7,15 +7,29 @@ export const TREE_VIEW_LAZY_LOADED_ITEMS_INITIAL_STATE = {
7
7
  errors: {}
8
8
  };
9
9
  export class TreeViewLazyLoadingPlugin {
10
- nestedDataManager = (() => new NestedDataManager(this))();
10
+ nestedDataManager = new NestedDataManager(this);
11
+ isInsideOnItemsLazyLoaded = false;
12
+ initStarted = false;
11
13
  constructor(store) {
12
14
  this.store = store;
13
15
  this.cache = store.parameters.dataSourceCache ?? new DataSourceCacheDefault({});
14
16
  if (store.parameters.dataSource != null) {
15
- this.init();
16
17
  store.subscribeEvent('beforeItemToggleExpansion', this.handleBeforeItemToggleExpansion);
17
18
  }
18
19
  }
20
+
21
+ /**
22
+ * Initialize lazy loading.
23
+ * Called from the store's disposeEffect (inside a useEffect) to avoid side effects during render.
24
+ * Uses a flag to ensure initialization only happens once (handles React 18 StrictMode double-firing effects).
25
+ */
26
+ initEffect = () => {
27
+ if (this.store.parameters.dataSource == null || this.initStarted) {
28
+ return;
29
+ }
30
+ this.initStarted = true;
31
+ this.init();
32
+ };
19
33
  init = () => {
20
34
  const store = this.store;
21
35
  // eslint-disable-next-line consistent-this
@@ -108,6 +122,21 @@ export class TreeViewLazyLoadingPlugin {
108
122
  errors
109
123
  }));
110
124
  };
125
+ callOnItemsLazyLoaded(items, parentId, isCacheHit) {
126
+ if (this.isInsideOnItemsLazyLoaded) {
127
+ return;
128
+ }
129
+ this.isInsideOnItemsLazyLoaded = true;
130
+ try {
131
+ this.store.parameters.onItemsLazyLoaded?.({
132
+ items,
133
+ parentId,
134
+ isCacheHit
135
+ });
136
+ } finally {
137
+ this.isInsideOnItemsLazyLoaded = false;
138
+ }
139
+ }
111
140
  buildPublicAPI = () => {
112
141
  return {
113
142
  updateItemChildren: this.updateItemChildren
@@ -144,6 +173,27 @@ export class TreeViewLazyLoadingPlugin {
144
173
  * @param {boolean} [parameters.forceRefresh] Whether to force a refresh of the children when the cache already contains some data.
145
174
  * @returns {Promise<void>} The promise resolved when the items are fetched.
146
175
  */
176
+ getItemId = item => this.store.parameters.getItemId ? this.store.parameters.getItemId(item) : item.id;
177
+ getInlineChildren = item => (this.store.parameters.getItemChildren ? this.store.parameters.getItemChildren(item) : item.children) ?? [];
178
+ processNestedItemChildren = items => {
179
+ const {
180
+ getChildrenCount
181
+ } = this.store.parameters.dataSource;
182
+ for (const item of items) {
183
+ const children = this.getInlineChildren(item);
184
+ if (children.length === 0) {
185
+ continue;
186
+ }
187
+ const itemId = this.getItemId(item);
188
+ this.cache.set(itemId, children);
189
+ this.store.items.setItemChildren({
190
+ items: children,
191
+ parentId: itemId,
192
+ getChildrenCount
193
+ });
194
+ this.processNestedItemChildren(children);
195
+ }
196
+ };
147
197
  fetchItemChildren = async ({
148
198
  itemId,
149
199
  forceRefresh
@@ -179,6 +229,7 @@ export class TreeViewLazyLoadingPlugin {
179
229
  getChildrenCount
180
230
  });
181
231
  this.setItemLoading(itemId, false);
232
+ this.callOnItemsLazyLoaded(cachedData, itemId, true);
182
233
  return;
183
234
  }
184
235
 
@@ -209,6 +260,10 @@ export class TreeViewLazyLoadingPlugin {
209
260
  parentId: itemId,
210
261
  getChildrenCount
211
262
  });
263
+ // pre-cache any inline nested children so expanding them requires no extra network call
264
+ this.processNestedItemChildren(response);
265
+ // notify the user that new items have been loaded
266
+ this.callOnItemsLazyLoaded(response, itemId, false);
212
267
  } catch (error) {
213
268
  const childrenFetchError = error;
214
269
  // set the item error in the state
@@ -1,4 +1,4 @@
1
- import { TreeViewItemId } from '@mui/x-tree-view/models';
1
+ import { TreeViewItemId, TreeViewValidItem } from '@mui/x-tree-view/models';
2
2
  import { TreeViewLazyLoadingPlugin } from "./TreeViewLazyLoadingPlugin.mjs";
3
3
  export declare enum RequestStatus {
4
4
  QUEUED = 0,
@@ -17,7 +17,7 @@ export declare class NestedDataManager {
17
17
  private settledRequests;
18
18
  private lazyLoadingPlugin;
19
19
  private maxConcurrentRequests;
20
- constructor(lazyLoadingPlugin: TreeViewLazyLoadingPlugin, maxConcurrentRequests?: number);
20
+ constructor(lazyLoadingPlugin: TreeViewLazyLoadingPlugin<TreeViewValidItem<any>>, maxConcurrentRequests?: number);
21
21
  private processQueue;
22
22
  queue: (ids: TreeViewItemId[]) => Promise<void>;
23
23
  setRequestSettled: (id: TreeViewItemId) => Promise<void>;
@@ -1,4 +1,4 @@
1
- import { TreeViewItemId } from '@mui/x-tree-view/models';
1
+ import { TreeViewItemId, TreeViewValidItem } from '@mui/x-tree-view/models';
2
2
  import { TreeViewLazyLoadingPlugin } from "./TreeViewLazyLoadingPlugin.js";
3
3
  export declare enum RequestStatus {
4
4
  QUEUED = 0,
@@ -17,7 +17,7 @@ export declare class NestedDataManager {
17
17
  private settledRequests;
18
18
  private lazyLoadingPlugin;
19
19
  private maxConcurrentRequests;
20
- constructor(lazyLoadingPlugin: TreeViewLazyLoadingPlugin, maxConcurrentRequests?: number);
20
+ constructor(lazyLoadingPlugin: TreeViewLazyLoadingPlugin<TreeViewValidItem<any>>, maxConcurrentRequests?: number);
21
21
  private processQueue;
22
22
  queue: (ids: TreeViewItemId[]) => Promise<void>;
23
23
  setRequestSettled: (id: TreeViewItemId) => Promise<void>;
@@ -13,9 +13,9 @@ export let RequestStatus = /*#__PURE__*/function (RequestStatus) {
13
13
  * Uses `ParentId` to uniquely identify a request
14
14
  */
15
15
  export class NestedDataManager {
16
- pendingRequests = (() => new Set())();
17
- queuedRequests = (() => new Set())();
18
- settledRequests = (() => new Set())();
16
+ pendingRequests = new Set();
17
+ queuedRequests = new Set();
18
+ settledRequests = new Set();
19
19
  constructor(lazyLoadingPlugin, maxConcurrentRequests = MAX_CONCURRENT_REQUESTS) {
20
20
  this.lazyLoadingPlugin = lazyLoadingPlugin;
21
21
  this.maxConcurrentRequests = maxConcurrentRequests;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-tree-view-pro",
3
- "version": "9.0.0-beta.0",
3
+ "version": "9.0.0",
4
4
  "author": "MUI Team",
5
5
  "description": "The Pro plan edition of the MUI X Tree View components.",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -32,24 +32,24 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@babel/runtime": "^7.28.6",
35
- "@base-ui/utils": "^0.2.3",
36
- "@mui/utils": "^7.3.7",
35
+ "@base-ui/utils": "^0.2.6",
36
+ "@mui/utils": "9.0.0",
37
37
  "@types/react-transition-group": "^4.4.12",
38
38
  "clsx": "^2.1.1",
39
39
  "prop-types": "^15.8.1",
40
40
  "react-transition-group": "^4.4.5",
41
41
  "reselect": "^5.1.1",
42
42
  "use-sync-external-store": "^1.6.0",
43
- "@mui/x-internals": "9.0.0-alpha.4",
44
- "@mui/x-tree-view": "9.0.0-alpha.4",
45
- "@mui/x-license": "9.0.0-beta.0",
46
- "@mui/x-virtualizer": "1.0.0-beta.1"
43
+ "@mui/x-internals": "^9.0.0",
44
+ "@mui/x-license": "^9.0.0",
45
+ "@mui/x-virtualizer": "9.0.0-alpha.0",
46
+ "@mui/x-tree-view": "^9.0.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@emotion/react": "^11.9.0",
50
50
  "@emotion/styled": "^11.8.1",
51
- "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0",
52
- "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0",
51
+ "@mui/material": "^7.3.0 || ^9.0.0",
52
+ "@mui/system": "^7.3.0 || ^9.0.0",
53
53
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
54
54
  "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
55
55
  },