@mui/x-tree-view 8.12.0 → 8.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/RichTreeView/RichTreeView.js +5 -5
  3. package/RichTreeView/RichTreeView.types.d.ts +2 -3
  4. package/RichTreeView/index.d.ts +1 -1
  5. package/SimpleTreeView/SimpleTreeView.types.d.ts +2 -3
  6. package/SimpleTreeView/index.d.ts +1 -1
  7. package/esm/RichTreeView/RichTreeView.js +5 -5
  8. package/esm/RichTreeView/RichTreeView.types.d.ts +2 -3
  9. package/esm/RichTreeView/index.d.ts +1 -1
  10. package/esm/SimpleTreeView/SimpleTreeView.types.d.ts +2 -3
  11. package/esm/SimpleTreeView/index.d.ts +1 -1
  12. package/esm/hooks/useApplyPropagationToSelectedItemsOnMount.js +2 -2
  13. package/esm/index.js +1 -1
  14. package/esm/internals/index.d.ts +2 -2
  15. package/esm/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +4 -4
  16. package/esm/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -1
  17. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.js +79 -158
  18. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +0 -8
  19. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +0 -8
  20. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +12 -26
  21. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.utils.d.ts +36 -2
  22. package/esm/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +115 -1
  23. package/esm/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +6 -6
  24. package/esm/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +1 -1
  25. package/esm/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +2 -2
  26. package/esm/internals/plugins/useTreeViewLazyLoading/index.d.ts +1 -1
  27. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.d.ts +6 -2
  28. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js +7 -2
  29. package/esm/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.d.ts +8 -9
  30. package/esm/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +12 -3
  31. package/esm/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +2 -2
  32. package/esm/internals/useTreeView/useTreeView.js +2 -2
  33. package/esm/useTreeItem/useTreeItem.js +3 -3
  34. package/hooks/useApplyPropagationToSelectedItemsOnMount.js +2 -3
  35. package/index.js +1 -1
  36. package/internals/index.d.ts +2 -2
  37. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +8 -8
  38. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +4 -4
  39. package/internals/plugins/useTreeViewItems/useTreeViewItems.js +80 -159
  40. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +0 -8
  41. package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +0 -8
  42. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +12 -26
  43. package/internals/plugins/useTreeViewItems/useTreeViewItems.utils.d.ts +36 -2
  44. package/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +119 -2
  45. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +8 -8
  46. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +2 -3
  47. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +2 -2
  48. package/internals/plugins/useTreeViewLazyLoading/index.d.ts +1 -1
  49. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.d.ts +6 -2
  50. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.selectors.js +7 -2
  51. package/internals/plugins/useTreeViewLazyLoading/useTreeViewLazyLoading.types.d.ts +8 -9
  52. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +12 -3
  53. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +2 -2
  54. package/internals/useTreeView/useTreeView.js +2 -2
  55. package/package.json +3 -3
  56. package/useTreeItem/useTreeItem.js +3 -3
  57. package/esm/internals/hooks/useLazyRef.d.ts +0 -1
  58. package/esm/internals/hooks/useLazyRef.js +0 -1
  59. package/esm/internals/hooks/useOnMount.d.ts +0 -1
  60. package/esm/internals/hooks/useOnMount.js +0 -1
  61. package/esm/internals/hooks/useTimeout.d.ts +0 -1
  62. package/esm/internals/hooks/useTimeout.js +0 -1
  63. package/internals/hooks/useLazyRef.d.ts +0 -1
  64. package/internals/hooks/useLazyRef.js +0 -13
  65. package/internals/hooks/useOnMount.d.ts +0 -1
  66. package/internals/hooks/useOnMount.js +0 -13
  67. package/internals/hooks/useTimeout.d.ts +0 -1
  68. package/internals/hooks/useTimeout.js +0 -13
@@ -2,100 +2,29 @@
2
2
 
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
- import useEventCallback from '@mui/utils/useEventCallback';
6
- import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "./useTreeViewItems.utils.js";
5
+ import { useEventCallback } from '@base-ui-components/utils/useEventCallback';
6
+ import { buildItemsLookups, buildItemsState, TREE_VIEW_ROOT_PARENT_ID } from "./useTreeViewItems.utils.js";
7
7
  import { TreeViewItemDepthContext } from "../../TreeViewItemDepthContext/index.js";
8
8
  import { itemsSelectors } from "./useTreeViewItems.selectors.js";
9
9
  import { idSelectors } from "../../corePlugins/useTreeViewId/index.js";
10
10
  import { generateTreeItemIdAttribute } from "../../corePlugins/useTreeViewId/useTreeViewId.utils.js";
11
11
  import { jsx as _jsx } from "react/jsx-runtime";
12
- const checkId = (id, item, itemMetaLookup) => {
13
- if (id == null) {
14
- throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', 'An item was provided without id in the `items` prop:', JSON.stringify(item)].join('\n'));
15
- }
16
- if (itemMetaLookup[id] != null) {
17
- throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', `Two items were provided with the same id in the \`items\` prop: "${id}"`].join('\n'));
18
- }
19
- };
20
- const processItemsLookups = ({
21
- disabledItemsFocusable,
22
- items,
23
- isItemDisabled,
24
- getItemLabel,
25
- getItemChildren,
26
- getItemId,
27
- initialDepth = 0,
28
- initialParentId = null,
29
- getChildrenCount,
30
- ignoreChildren = false
31
- }) => {
32
- const itemMetaLookup = {};
33
- const itemModelLookup = {};
34
- const itemOrderedChildrenIdsLookup = {
35
- [TREE_VIEW_ROOT_PARENT_ID]: []
36
- };
37
- const processItem = (item, depth, parentId) => {
38
- const id = getItemId ? getItemId(item) : item.id;
39
- checkId(id, item, itemMetaLookup);
40
- const label = getItemLabel ? getItemLabel(item) : item.label;
41
- if (label == null) {
42
- throw new Error(['MUI X: The Tree View component requires all items to have a `label` property.', 'Alternatively, you can use the `getItemLabel` prop to specify a custom label for each item.', 'An item was provided without label in the `items` prop:', JSON.stringify(item)].join('\n'));
43
- }
44
- const children = getItemChildren ? getItemChildren(item) : item.children;
45
- itemMetaLookup[id] = {
46
- id,
47
- label,
48
- parentId,
49
- idAttribute: undefined,
50
- expandable: getChildrenCount ? getChildrenCount(item) > 0 : !!children?.length,
51
- disabled: isItemDisabled ? isItemDisabled(item) : false,
52
- depth
53
- };
54
- itemModelLookup[id] = item;
55
- const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
56
- if (!itemOrderedChildrenIdsLookup[parentIdWithDefault]) {
57
- itemOrderedChildrenIdsLookup[parentIdWithDefault] = [];
58
- }
59
- itemOrderedChildrenIdsLookup[parentIdWithDefault].push(id);
60
-
61
- // if lazy loading is enabled, we don't want to process children passed through the `items` prop
62
- if (!ignoreChildren) {
63
- children?.forEach(child => processItem(child, depth + 1, id));
64
- }
65
- };
66
- items?.forEach(item => processItem(item, initialDepth, initialParentId));
67
- const itemChildrenIndexesLookup = {};
68
- Object.keys(itemOrderedChildrenIdsLookup).forEach(parentId => {
69
- itemChildrenIndexesLookup[parentId] = buildSiblingIndexes(itemOrderedChildrenIdsLookup[parentId]);
70
- });
71
- return {
72
- disabledItemsFocusable,
73
- itemMetaLookup,
74
- itemModelLookup,
75
- itemOrderedChildrenIdsLookup,
76
- itemChildrenIndexesLookup
77
- };
78
- };
79
12
  export const useTreeViewItems = ({
80
13
  instance,
81
14
  params,
82
15
  store
83
16
  }) => {
17
+ const itemsConfig = React.useMemo(() => ({
18
+ isItemDisabled: params.isItemDisabled,
19
+ getItemLabel: params.getItemLabel,
20
+ getItemChildren: params.getItemChildren,
21
+ getItemId: params.getItemId
22
+ }), [params.isItemDisabled, params.getItemLabel, params.getItemChildren, params.getItemId]);
84
23
  const getItem = React.useCallback(itemId => itemsSelectors.itemModel(store.state, itemId), [store]);
85
24
  const getParentId = React.useCallback(itemId => {
86
25
  const itemMeta = itemsSelectors.itemMeta(store.state, itemId);
87
26
  return itemMeta?.parentId || null;
88
27
  }, [store]);
89
- const setTreeViewLoading = useEventCallback(isLoading => {
90
- store.set('items', _extends({}, store.state.items, {
91
- loading: isLoading
92
- }));
93
- });
94
- const setTreeViewError = useEventCallback(error => {
95
- store.set('items', _extends({}, store.state.items, {
96
- error
97
- }));
98
- });
99
28
  const setIsItemDisabled = useEventCallback(({
100
29
  itemId,
101
30
  shouldBeDisabled
@@ -143,86 +72,81 @@ export const useTreeViewItems = ({
143
72
  areItemUpdatesPreventedRef.current = true;
144
73
  }, []);
145
74
  const areItemUpdatesPrevented = React.useCallback(() => areItemUpdatesPreventedRef.current, []);
146
- const addItems = ({
75
+ const setItemChildren = ({
147
76
  items,
148
77
  parentId,
149
- depth,
150
78
  getChildrenCount
151
79
  }) => {
152
- if (items) {
153
- const newState = processItemsLookups({
154
- disabledItemsFocusable: params.disabledItemsFocusable,
155
- items,
156
- isItemDisabled: params.isItemDisabled,
157
- getItemId: params.getItemId,
158
- getItemLabel: params.getItemLabel,
159
- getItemChildren: params.getItemChildren,
160
- getChildrenCount,
161
- initialDepth: depth,
162
- initialParentId: parentId,
163
- ignoreChildren: true
164
- });
165
- let newItems;
166
- if (parentId) {
167
- newItems = {
168
- itemModelLookup: _extends({}, store.state.items.itemModelLookup, newState.itemModelLookup),
169
- itemMetaLookup: _extends({}, store.state.items.itemMetaLookup, newState.itemMetaLookup),
170
- itemOrderedChildrenIdsLookup: _extends({}, newState.itemOrderedChildrenIdsLookup, store.state.items.itemOrderedChildrenIdsLookup),
171
- itemChildrenIndexesLookup: _extends({}, newState.itemChildrenIndexesLookup, store.state.items.itemChildrenIndexesLookup)
172
- };
173
- } else {
174
- newItems = {
175
- itemModelLookup: newState.itemModelLookup,
176
- itemMetaLookup: newState.itemMetaLookup,
177
- itemOrderedChildrenIdsLookup: newState.itemOrderedChildrenIdsLookup,
178
- itemChildrenIndexesLookup: newState.itemChildrenIndexesLookup
179
- };
180
- }
181
- store.set('items', _extends({}, store.state.items, newItems));
182
- }
80
+ const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
81
+ const parentDepth = parentId == null ? -1 : itemsSelectors.itemDepth(store.state, parentId);
82
+ const {
83
+ metaLookup,
84
+ modelLookup,
85
+ orderedChildrenIds,
86
+ childrenIndexes
87
+ } = buildItemsLookups({
88
+ config: itemsConfig,
89
+ items,
90
+ parentId,
91
+ depth: parentDepth + 1,
92
+ isItemExpandable: getChildrenCount ? item => getChildrenCount(item) > 0 : () => false,
93
+ otherItemsMetaLookup: itemsSelectors.itemMetaLookup(store.state)
94
+ });
95
+ const lookups = {
96
+ itemModelLookup: _extends({}, store.state.items.itemModelLookup, modelLookup),
97
+ itemMetaLookup: _extends({}, store.state.items.itemMetaLookup, metaLookup),
98
+ itemOrderedChildrenIdsLookup: _extends({}, store.state.items.itemOrderedChildrenIdsLookup, {
99
+ [parentIdWithDefault]: orderedChildrenIds
100
+ }),
101
+ itemChildrenIndexesLookup: _extends({}, store.state.items.itemChildrenIndexesLookup, {
102
+ [parentIdWithDefault]: childrenIndexes
103
+ })
104
+ };
105
+ store.set('items', _extends({}, store.state.items, lookups));
183
106
  };
184
- const removeChildren = parentId => {
185
- if (parentId == null) {
186
- store.set('items', _extends({}, store.state.items, {
187
- itemMetaLookup: {},
188
- itemOrderedChildrenIdsLookup: {},
189
- itemChildrenIndexesLookup: {}
190
- }));
191
- } else {
192
- const newMetaMap = Object.keys(store.state.items.itemMetaLookup).reduce((acc, key) => {
193
- const item = store.state.items.itemMetaLookup[key];
194
- if (item.parentId === parentId) {
195
- return acc;
196
- }
197
- return _extends({}, acc, {
198
- [item.id]: item
199
- });
200
- }, {});
201
- const newItemOrderedChildrenIdsLookup = _extends({}, store.state.items.itemOrderedChildrenIdsLookup);
202
- const newItemChildrenIndexesLookup = _extends({}, store.state.items.itemChildrenIndexesLookup);
203
- delete newItemChildrenIndexesLookup[parentId];
204
- delete newItemOrderedChildrenIdsLookup[parentId];
205
- store.set('items', _extends({}, store.state.items, {
206
- itemMetaLookup: newMetaMap,
207
- itemOrderedChildrenIdsLookup: newItemOrderedChildrenIdsLookup,
208
- itemChildrenIndexesLookup: newItemChildrenIndexesLookup
209
- }));
107
+ const removeChildren = useEventCallback(parentId => {
108
+ const newMetaMap = Object.keys(store.state.items.itemMetaLookup).reduce((acc, key) => {
109
+ const item = store.state.items.itemMetaLookup[key];
110
+ if (item.parentId === parentId) {
111
+ return acc;
112
+ }
113
+ return _extends({}, acc, {
114
+ [item.id]: item
115
+ });
116
+ }, {});
117
+ const newItemOrderedChildrenIdsLookup = _extends({}, store.state.items.itemOrderedChildrenIdsLookup);
118
+ const newItemChildrenIndexesLookup = _extends({}, store.state.items.itemChildrenIndexesLookup);
119
+ const cleanId = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
120
+ delete newItemChildrenIndexesLookup[cleanId];
121
+ delete newItemOrderedChildrenIdsLookup[cleanId];
122
+ store.set('items', _extends({}, store.state.items, {
123
+ itemMetaLookup: newMetaMap,
124
+ itemOrderedChildrenIdsLookup: newItemOrderedChildrenIdsLookup,
125
+ itemChildrenIndexesLookup: newItemChildrenIndexesLookup
126
+ }));
127
+ });
128
+ const addExpandableItems = useEventCallback(items => {
129
+ const newItemMetaLookup = _extends({}, store.state.items.itemMetaLookup);
130
+ for (const itemId of items) {
131
+ newItemMetaLookup[itemId] = _extends({}, newItemMetaLookup[itemId], {
132
+ expandable: true
133
+ });
210
134
  }
211
- };
135
+ store.set('items', _extends({}, store.state.items, {
136
+ itemMetaLookup: newItemMetaLookup
137
+ }));
138
+ });
212
139
  React.useEffect(() => {
213
140
  if (instance.areItemUpdatesPrevented()) {
214
141
  return;
215
142
  }
216
- const newState = processItemsLookups({
143
+ const newState = buildItemsState({
217
144
  disabledItemsFocusable: params.disabledItemsFocusable,
218
145
  items: params.items,
219
- isItemDisabled: params.isItemDisabled,
220
- getItemId: params.getItemId,
221
- getItemLabel: params.getItemLabel,
222
- getItemChildren: params.getItemChildren
146
+ config: itemsConfig
223
147
  });
224
148
  store.set('items', _extends({}, store.state.items, newState));
225
- }, [instance, store, params.items, params.disabledItemsFocusable, params.isItemDisabled, params.getItemId, params.getItemLabel, params.getItemChildren]);
149
+ }, [instance, store, params.items, params.disabledItemsFocusable, itemsConfig]);
226
150
 
227
151
  // Wrap `props.onItemClick` with `useEventCallback` to prevent unneeded context updates.
228
152
  const handleItemClick = useEventCallback((event, itemId) => {
@@ -248,26 +172,23 @@ export const useTreeViewItems = ({
248
172
  getItemDOMElement,
249
173
  preventItemUpdates,
250
174
  areItemUpdatesPrevented,
251
- addItems,
252
- setTreeViewLoading,
253
- setTreeViewError,
175
+ setItemChildren,
254
176
  removeChildren,
177
+ addExpandableItems,
255
178
  handleItemClick
256
179
  }
257
180
  };
258
181
  };
259
182
  useTreeViewItems.getInitialState = params => ({
260
- items: _extends({}, processItemsLookups({
261
- disabledItemsFocusable: params.disabledItemsFocusable,
183
+ items: buildItemsState({
262
184
  items: params.items,
263
- isItemDisabled: params.isItemDisabled,
264
- getItemId: params.getItemId,
265
- getItemLabel: params.getItemLabel,
266
- getItemChildren: params.getItemChildren
267
- }), {
268
- loading: false,
269
- error: null,
270
- domStructure: 'nested'
185
+ disabledItemsFocusable: params.disabledItemsFocusable,
186
+ config: {
187
+ isItemDisabled: params.isItemDisabled,
188
+ getItemId: params.getItemId,
189
+ getItemLabel: params.getItemLabel,
190
+ getItemChildren: params.getItemChildren
191
+ }
271
192
  })
272
193
  });
273
194
  useTreeViewItems.applyDefaultValuesToParams = ({
@@ -1,14 +1,6 @@
1
1
  import { TreeViewItemMeta, TreeViewState } from "../../models/index.js";
2
2
  import { UseTreeViewItemsSignature } from "./useTreeViewItems.types.js";
3
3
  export declare const itemsSelectors: {
4
- /**
5
- * Gets the loading state for the Tree View.
6
- */
7
- isLoading: (state: TreeViewState<[UseTreeViewItemsSignature]>) => boolean;
8
- /**
9
- * Gets the error state for the Tree View.
10
- */
11
- error: (state: TreeViewState<[UseTreeViewItemsSignature]>) => Error | null;
12
4
  /**
13
5
  * Gets the DOM structure of the Tree View.
14
6
  */
@@ -2,14 +2,6 @@ import { createSelector } from '@mui/x-internals/store';
2
2
  import { isItemDisabled, TREE_VIEW_ROOT_PARENT_ID } from "./useTreeViewItems.utils.js";
3
3
  const EMPTY_CHILDREN = [];
4
4
  export const itemsSelectors = {
5
- /**
6
- * Gets the loading state for the Tree View.
7
- */
8
- isLoading: createSelector(state => state.items.loading),
9
- /**
10
- * Gets the error state for the Tree View.
11
- */
12
- error: createSelector(state => state.items.error),
13
5
  /**
14
6
  * Gets the DOM structure of the Tree View.
15
7
  */
@@ -2,11 +2,10 @@ import * as React from 'react';
2
2
  import { DefaultizedProps } from '@mui/x-internals/types';
3
3
  import { TreeViewItemMeta, TreeViewPluginSignature } from "../../models/index.js";
4
4
  import { TreeViewBaseItem, TreeViewDefaultItemModelProperties, TreeViewItemId } from "../../../models/index.js";
5
- export type AddItemsParameters<R> = {
5
+ export type SetItemChildrenParameters<R> = {
6
6
  items: readonly R[];
7
- parentId?: TreeViewItemId;
8
- depth: number;
9
- getChildrenCount?: (item: R) => number;
7
+ parentId: TreeViewItemId | null;
8
+ getChildrenCount: (item: R) => number;
10
9
  };
11
10
  export interface UseTreeViewItemsPublicAPI<R extends {}> {
12
11
  /**
@@ -65,30 +64,25 @@ export interface UseTreeViewItemsInstance<R extends {}> extends Pick<UseTreeView
65
64
  areItemUpdatesPrevented: () => boolean;
66
65
  /**
67
66
  * Add an array of items to the tree.
68
- * @param {AddItemsParameters<R>} args The items to add to the tree and information about their ancestors.
67
+ * @param {SetItemChildrenParameters<R>} args The items to add to the tree and information about their ancestors.
69
68
  */
70
- addItems: (args: AddItemsParameters<R>) => void;
69
+ setItemChildren: (args: SetItemChildrenParameters<R>) => void;
71
70
  /**
72
71
  * Remove the children of an item.
73
- * @param {TreeViewItemId} parentId The id of the item to remove the children of.
72
+ * @param {TreeViewItemId | null} parentId The id of the item to remove the children of.
74
73
  */
75
- removeChildren: (parentId?: TreeViewItemId) => void;
76
- /**
77
- * Set the loading state of the tree.
78
- * @param {boolean} loading True if the tree view is loading.
79
- */
80
- setTreeViewLoading: (loading: boolean) => void;
81
- /**
82
- * Set the error state of the tree.
83
- * @param {Error | null} error The error on the tree view.
84
- */
85
- setTreeViewError: (error: Error | null) => void;
74
+ removeChildren: (parentId: TreeViewItemId | null) => void;
86
75
  /**
87
76
  * Event handler to fire when the `content` slot of a given Tree Item is clicked.
88
77
  * @param {React.MouseEvent} event The DOM event that triggered the change.
89
78
  * @param {TreeViewItemId} itemId The id of the item being clicked.
90
79
  */
91
80
  handleItemClick: (event: React.MouseEvent, itemId: TreeViewItemId) => void;
81
+ /**
82
+ * Mark a list of items as expandable.
83
+ * @param {TreeViewItemId[]} items The ids of the items to mark as expandable.
84
+ */
85
+ addExpandableItems: (items: TreeViewItemId[]) => void;
92
86
  }
93
87
  export interface UseTreeViewItemsParameters<R extends {
94
88
  children?: R[];
@@ -186,14 +180,6 @@ export interface UseTreeViewItemsState<R extends {}> {
186
180
  [itemId: string]: number;
187
181
  };
188
182
  };
189
- /**
190
- * The loading state of the tree.
191
- */
192
- loading: boolean;
193
- /**
194
- * The error state of the tree.
195
- */
196
- error: Error | null;
197
183
  /**
198
184
  * When equal to 'flat', the tree is rendered as a flat list (children are rendered as siblings of their parents).
199
185
  * When equal to 'nested', the tree is rendered with nested children (children are rendered inside the groupTransition slot of their children).
@@ -1,5 +1,6 @@
1
- import { TreeViewItemId } from "../../../models/index.js";
1
+ import { TreeViewBaseItem, TreeViewItemId } from "../../../models/index.js";
2
2
  import { TreeViewItemMeta } from "../../models/index.js";
3
+ import { UseTreeViewItemsParametersWithDefaults, UseTreeViewItemsState } from "./useTreeViewItems.types.js";
3
4
  export declare const TREE_VIEW_ROOT_PARENT_ID = "__TREE_VIEW_ROOT_PARENT_ID__";
4
5
  export declare const buildSiblingIndexes: (siblings: string[]) => {
5
6
  [itemId: string]: number;
@@ -12,4 +13,37 @@ export declare const buildSiblingIndexes: (siblings: string[]) => {
12
13
  */
13
14
  export declare const isItemDisabled: (itemMetaLookup: {
14
15
  [itemId: string]: TreeViewItemMeta;
15
- }, itemId: TreeViewItemId) => boolean;
16
+ }, itemId: TreeViewItemId) => boolean;
17
+ type State = UseTreeViewItemsState<any>['items'];
18
+ export declare function buildItemsState(parameters: BuildItemsStateParameters): State;
19
+ interface BuildItemsStateParameters extends Pick<BuildItemsLookupsParameters, 'items' | 'config'> {
20
+ disabledItemsFocusable: boolean;
21
+ }
22
+ export declare function buildItemsLookups(parameters: BuildItemsLookupsParameters): {
23
+ metaLookup: {
24
+ [itemId: string]: TreeViewItemMeta;
25
+ };
26
+ modelLookup: {
27
+ [itemId: string]: any;
28
+ };
29
+ orderedChildrenIds: string[];
30
+ childrenIndexes: {
31
+ [itemId: string]: number;
32
+ };
33
+ itemsChildren: {
34
+ id: string | null;
35
+ children: TreeViewBaseItem[];
36
+ }[];
37
+ };
38
+ interface BuildItemsLookupsParameters {
39
+ items: readonly TreeViewBaseItem[];
40
+ config: BuildItemsLookupConfig;
41
+ parentId: string | null;
42
+ depth: number;
43
+ isItemExpandable: (item: TreeViewBaseItem, children: TreeViewBaseItem[] | undefined) => boolean;
44
+ otherItemsMetaLookup: {
45
+ [itemId: string]: TreeViewItemMeta;
46
+ };
47
+ }
48
+ export interface BuildItemsLookupConfig extends Pick<UseTreeViewItemsParametersWithDefaults<TreeViewBaseItem>, 'isItemDisabled' | 'getItemLabel' | 'getItemChildren' | 'getItemId'> {}
49
+ export {};
@@ -36,4 +36,118 @@ export const isItemDisabled = (itemMetaLookup, itemId) => {
36
36
  }
37
37
  }
38
38
  return false;
39
- };
39
+ };
40
+ export function buildItemsState(parameters) {
41
+ const {
42
+ config,
43
+ items: itemsParam,
44
+ disabledItemsFocusable
45
+ } = parameters;
46
+ const itemMetaLookup = {};
47
+ const itemModelLookup = {};
48
+ const itemOrderedChildrenIdsLookup = {};
49
+ const itemChildrenIndexesLookup = {};
50
+ function processSiblings(items, parentId, depth) {
51
+ const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
52
+ const {
53
+ metaLookup,
54
+ modelLookup,
55
+ orderedChildrenIds,
56
+ childrenIndexes,
57
+ itemsChildren
58
+ } = buildItemsLookups({
59
+ config,
60
+ items,
61
+ parentId,
62
+ depth,
63
+ isItemExpandable: (item, children) => !!children && children.length > 0,
64
+ otherItemsMetaLookup: itemMetaLookup
65
+ });
66
+ Object.assign(itemMetaLookup, metaLookup);
67
+ Object.assign(itemModelLookup, modelLookup);
68
+ itemOrderedChildrenIdsLookup[parentIdWithDefault] = orderedChildrenIds;
69
+ itemChildrenIndexesLookup[parentIdWithDefault] = childrenIndexes;
70
+ for (const item of itemsChildren) {
71
+ processSiblings(item.children || [], item.id, depth + 1);
72
+ }
73
+ }
74
+ processSiblings(itemsParam, null, 0);
75
+ return {
76
+ disabledItemsFocusable,
77
+ itemMetaLookup,
78
+ itemModelLookup,
79
+ itemOrderedChildrenIdsLookup,
80
+ itemChildrenIndexesLookup,
81
+ domStructure: 'nested'
82
+ };
83
+ }
84
+ export function buildItemsLookups(parameters) {
85
+ const {
86
+ config,
87
+ items,
88
+ parentId,
89
+ depth,
90
+ isItemExpandable,
91
+ otherItemsMetaLookup
92
+ } = parameters;
93
+ const metaLookup = {};
94
+ const modelLookup = {};
95
+ const orderedChildrenIds = [];
96
+ const itemsChildren = [];
97
+ const processItem = item => {
98
+ const id = config.getItemId ? config.getItemId(item) : item.id;
99
+ checkId({
100
+ id,
101
+ parentId,
102
+ item,
103
+ itemMetaLookup: otherItemsMetaLookup,
104
+ siblingsMetaLookup: metaLookup
105
+ });
106
+ const label = config.getItemLabel ? config.getItemLabel(item) : item.label;
107
+ if (label == null) {
108
+ throw new Error(['MUI X: The Tree View component requires all items to have a `label` property.', 'Alternatively, you can use the `getItemLabel` prop to specify a custom label for each item.', 'An item was provided without label in the `items` prop:', JSON.stringify(item)].join('\n'));
109
+ }
110
+ const children = (config.getItemChildren ? config.getItemChildren(item) : item.children) || [];
111
+ itemsChildren.push({
112
+ id,
113
+ children
114
+ });
115
+ modelLookup[id] = item;
116
+ metaLookup[id] = {
117
+ id,
118
+ label,
119
+ parentId,
120
+ idAttribute: undefined,
121
+ expandable: isItemExpandable(item, children),
122
+ disabled: config.isItemDisabled ? config.isItemDisabled(item) : false,
123
+ depth
124
+ };
125
+ orderedChildrenIds.push(id);
126
+ };
127
+ for (const item of items) {
128
+ processItem(item);
129
+ }
130
+ return {
131
+ metaLookup,
132
+ modelLookup,
133
+ orderedChildrenIds,
134
+ childrenIndexes: buildSiblingIndexes(orderedChildrenIds),
135
+ itemsChildren
136
+ };
137
+ }
138
+ function checkId({
139
+ id,
140
+ parentId,
141
+ item,
142
+ itemMetaLookup,
143
+ siblingsMetaLookup
144
+ }) {
145
+ if (id == null) {
146
+ throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', 'An item was provided without id in the `items` prop:', JSON.stringify(item)].join('\n'));
147
+ }
148
+ if (siblingsMetaLookup[id] != null ||
149
+ // Ignore items with the same parent id, because it's the same item from the previous generation.
150
+ itemMetaLookup[id] != null && itemMetaLookup[id].parentId !== parentId) {
151
+ throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', `Two items were provided with the same id in the \`items\` prop: "${id}"`].join('\n'));
152
+ }
153
+ }
@@ -3,9 +3,9 @@
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
5
  import { useStore } from '@mui/x-internals/store';
6
- import useEventCallback from '@mui/utils/useEventCallback';
7
- import useForkRef from '@mui/utils/useForkRef';
8
- import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
6
+ import { useEventCallback } from '@base-ui-components/utils/useEventCallback';
7
+ import { useMergedRefs } from '@base-ui-components/utils/useMergedRefs';
8
+ import { useIsoLayoutEffect } from '@base-ui-components/utils/useIsoLayoutEffect';
9
9
  import { useTreeViewContext } from "../../TreeViewProvider/index.js";
10
10
  import { TreeViewChildrenItemContext, TreeViewChildrenItemProvider } from "../../TreeViewProvider/TreeViewChildrenItemProvider.js";
11
11
  import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "../useTreeViewItems/useTreeViewItems.utils.js";
@@ -105,11 +105,11 @@ const useTreeViewJSXItemsItemPlugin = ({
105
105
  } = parentContext;
106
106
  const expandable = itemHasChildren(children);
107
107
  const pluginContentRef = React.useRef(null);
108
- const handleContentRef = useForkRef(pluginContentRef, contentRef);
108
+ const handleContentRef = useMergedRefs(pluginContentRef, contentRef);
109
109
  const treeId = useStore(store, idSelectors.treeId);
110
110
 
111
111
  // Prevent any flashing
112
- useEnhancedEffect(() => {
112
+ useIsoLayoutEffect(() => {
113
113
  const idAttribute = generateTreeItemIdAttribute({
114
114
  itemId,
115
115
  treeId,
@@ -121,7 +121,7 @@ const useTreeViewJSXItemsItemPlugin = ({
121
121
  unregisterChild(idAttribute);
122
122
  };
123
123
  }, [store, instance, registerChild, unregisterChild, itemId, id, treeId]);
124
- useEnhancedEffect(() => {
124
+ useIsoLayoutEffect(() => {
125
125
  return instance.insertJSXItem({
126
126
  id: itemId,
127
127
  idAttribute: id,
@@ -3,7 +3,7 @@
3
3
  import * as React from 'react';
4
4
  import { useStore } from '@mui/x-internals/store';
5
5
  import { useRtl } from '@mui/system/RtlProvider';
6
- import useEventCallback from '@mui/utils/useEventCallback';
6
+ import { useEventCallback } from '@base-ui-components/utils/useEventCallback';
7
7
  import { getFirstNavigableItem, getLastNavigableItem, getNextNavigableItem, getPreviousNavigableItem, isTargetInDescendants } from "../../utils/tree.js";
8
8
  import { hasPlugin } from "../../utils/plugins.js";
9
9
  import { useTreeViewLabel } from "../useTreeViewLabel/index.js";
@@ -1,5 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
- import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
2
+ import { useIsoLayoutEffect } from '@base-ui-components/utils/useIsoLayoutEffect';
3
3
  import { useTreeViewLabelItemPlugin } from "./useTreeViewLabel.itemPlugin.js";
4
4
  import { labelSelectors } from "./useTreeViewLabel.selectors.js";
5
5
  export const useTreeViewLabel = ({
@@ -36,7 +36,7 @@ export const useTreeViewLabel = ({
36
36
  params.onItemLabelChange(itemId, label);
37
37
  }
38
38
  };
39
- useEnhancedEffect(() => {
39
+ useIsoLayoutEffect(() => {
40
40
  store.set('label', _extends({}, store.state.items, {
41
41
  isItemEditable: params.isItemEditable
42
42
  }));
@@ -1,2 +1,2 @@
1
- export type { UseTreeViewLazyLoadingSignature, UseTreeViewLazyLoadingParameters, UseTreeViewLazyLoadingInstance } from "./useTreeViewLazyLoading.types.js";
1
+ export type { UseTreeViewLazyLoadingSignature, UseTreeViewLazyLoadingParameters, UseTreeViewLazyLoadingInstance, DataSource } from "./useTreeViewLazyLoading.types.js";
2
2
  export { lazyLoadingSelectors } from "./useTreeViewLazyLoading.selectors.js";
@@ -12,9 +12,13 @@ export declare const lazyLoadingSelectors: {
12
12
  /**
13
13
  * Checks whether an item is loading.
14
14
  */
15
- isItemLoading: (state: TreeViewState<[], [UseTreeViewLazyLoadingSignature]>, itemId: string) => boolean;
15
+ isItemLoading: (state: TreeViewState<[], [UseTreeViewLazyLoadingSignature]>, itemId: string | null) => boolean;
16
16
  /**
17
17
  * Checks whether an item has errors.
18
18
  */
19
- itemHasError: (state: TreeViewState<[], [UseTreeViewLazyLoadingSignature]>, itemId: string) => boolean;
19
+ itemHasError: (state: TreeViewState<[], [UseTreeViewLazyLoadingSignature]>, itemId: string | null) => boolean;
20
+ /**
21
+ * Get an item error.
22
+ */
23
+ itemError: (state: TreeViewState<[], [UseTreeViewLazyLoadingSignature]>, itemId: string | null) => Error | null | undefined;
20
24
  };