@mui/x-tree-view 7.0.0 → 7.1.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 (111) hide show
  1. package/CHANGELOG.md +246 -4
  2. package/README.md +1 -1
  3. package/RichTreeView/RichTreeView.d.ts +2 -2
  4. package/RichTreeView/RichTreeView.js +11 -9
  5. package/SimpleTreeView/SimpleTreeView.js +4 -2
  6. package/SimpleTreeView/SimpleTreeView.plugins.d.ts +1 -1
  7. package/SimpleTreeView/SimpleTreeView.plugins.js +2 -2
  8. package/TreeItem/TreeItem.js +4 -4
  9. package/TreeItem/treeItemClasses.d.ts +1 -1
  10. package/TreeItem/useTreeItemState.js +9 -9
  11. package/TreeItem2Icon/TreeItem2Icon.types.d.ts +4 -4
  12. package/TreeView/TreeView.js +2 -1
  13. package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +8 -8
  14. package/hooks/useTreeViewApiRef.d.ts +1 -1
  15. package/index.js +1 -1
  16. package/internals/TreeViewProvider/DescendantProvider.d.ts +1 -1
  17. package/internals/TreeViewProvider/DescendantProvider.js +1 -1
  18. package/internals/index.d.ts +18 -8
  19. package/internals/index.js +11 -0
  20. package/internals/models/plugin.d.ts +1 -1
  21. package/internals/plugins/defaultPlugins.d.ts +3 -3
  22. package/internals/plugins/defaultPlugins.js +2 -2
  23. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +32 -18
  24. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +16 -6
  25. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +35 -33
  26. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +17 -9
  27. package/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.d.ts +6 -6
  28. package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +1 -1
  29. package/internals/plugins/useTreeViewItems/index.d.ts +2 -0
  30. package/internals/plugins/useTreeViewItems/index.js +1 -0
  31. package/internals/plugins/useTreeViewItems/useTreeViewItems.d.ts +3 -0
  32. package/internals/plugins/{useTreeViewNodes/useTreeViewNodes.js → useTreeViewItems/useTreeViewItems.js} +43 -33
  33. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +104 -0
  34. package/internals/plugins/useTreeViewJSXItems/index.d.ts +2 -0
  35. package/internals/plugins/useTreeViewJSXItems/index.js +1 -0
  36. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.d.ts +3 -0
  37. package/{modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js → internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js} +26 -25
  38. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.d.ts +18 -0
  39. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +40 -44
  40. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +2 -2
  41. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +34 -34
  42. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +6 -6
  43. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.d.ts +7 -7
  44. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +5 -5
  45. package/internals/useTreeView/useTreeView.utils.d.ts +5 -5
  46. package/internals/useTreeView/useTreeView.utils.js +15 -15
  47. package/internals/useTreeView/useTreeViewModels.js +2 -2
  48. package/modern/RichTreeView/RichTreeView.js +11 -9
  49. package/modern/SimpleTreeView/SimpleTreeView.js +4 -2
  50. package/modern/SimpleTreeView/SimpleTreeView.plugins.js +2 -2
  51. package/modern/TreeItem/TreeItem.js +4 -4
  52. package/modern/TreeItem/useTreeItemState.js +9 -9
  53. package/modern/TreeView/TreeView.js +2 -1
  54. package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +8 -8
  55. package/modern/index.js +1 -1
  56. package/modern/internals/TreeViewProvider/DescendantProvider.js +1 -1
  57. package/modern/internals/index.js +11 -0
  58. package/modern/internals/plugins/defaultPlugins.js +2 -2
  59. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +32 -18
  60. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +35 -33
  61. package/modern/internals/plugins/useTreeViewItems/index.js +1 -0
  62. package/modern/internals/plugins/{useTreeViewNodes/useTreeViewNodes.js → useTreeViewItems/useTreeViewItems.js} +43 -33
  63. package/modern/internals/plugins/useTreeViewJSXItems/index.js +1 -0
  64. package/{internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js → modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js} +26 -25
  65. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +40 -44
  66. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +34 -34
  67. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +5 -5
  68. package/modern/internals/useTreeView/useTreeView.utils.js +15 -15
  69. package/modern/internals/useTreeView/useTreeViewModels.js +2 -2
  70. package/node/RichTreeView/RichTreeView.js +11 -9
  71. package/node/SimpleTreeView/SimpleTreeView.js +4 -2
  72. package/node/SimpleTreeView/SimpleTreeView.plugins.js +2 -2
  73. package/node/TreeItem/TreeItem.js +4 -4
  74. package/node/TreeItem/useTreeItemState.js +9 -9
  75. package/node/TreeView/TreeView.js +2 -1
  76. package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +8 -8
  77. package/node/index.js +1 -1
  78. package/node/internals/TreeViewProvider/DescendantProvider.js +1 -1
  79. package/node/internals/index.js +70 -0
  80. package/node/internals/plugins/defaultPlugins.js +2 -2
  81. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +31 -17
  82. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +35 -33
  83. package/node/internals/plugins/useTreeViewItems/index.js +12 -0
  84. package/node/internals/plugins/{useTreeViewNodes/useTreeViewNodes.js → useTreeViewItems/useTreeViewItems.js} +45 -35
  85. package/node/internals/plugins/useTreeViewJSXItems/index.js +12 -0
  86. package/node/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.js → useTreeViewJSXItems/useTreeViewJSXItems.js} +28 -27
  87. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +39 -43
  88. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +33 -33
  89. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +5 -5
  90. package/node/internals/useTreeView/useTreeView.utils.js +20 -20
  91. package/node/internals/useTreeView/useTreeViewModels.js +2 -2
  92. package/package.json +2 -2
  93. package/useTreeItem2/useTreeItem2.d.ts +1 -1
  94. package/internals/plugins/useTreeViewJSXNodes/index.d.ts +0 -2
  95. package/internals/plugins/useTreeViewJSXNodes/index.js +0 -1
  96. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.d.ts +0 -3
  97. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.d.ts +0 -18
  98. package/internals/plugins/useTreeViewNodes/index.d.ts +0 -2
  99. package/internals/plugins/useTreeViewNodes/index.js +0 -1
  100. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.d.ts +0 -3
  101. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +0 -88
  102. package/modern/internals/plugins/useTreeViewJSXNodes/index.js +0 -1
  103. package/modern/internals/plugins/useTreeViewNodes/index.js +0 -1
  104. package/node/internals/plugins/useTreeViewJSXNodes/index.js +0 -12
  105. package/node/internals/plugins/useTreeViewNodes/index.js +0 -12
  106. /package/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.types.js → useTreeViewItems/useTreeViewItems.types.js} +0 -0
  107. /package/internals/plugins/{useTreeViewNodes/useTreeViewNodes.types.js → useTreeViewJSXItems/useTreeViewJSXItems.types.js} +0 -0
  108. /package/modern/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.types.js → useTreeViewItems/useTreeViewItems.types.js} +0 -0
  109. /package/modern/internals/plugins/{useTreeViewNodes/useTreeViewNodes.types.js → useTreeViewJSXItems/useTreeViewJSXItems.types.js} +0 -0
  110. /package/node/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.types.js → useTreeViewItems/useTreeViewItems.types.js} +0 -0
  111. /package/node/internals/plugins/{useTreeViewNodes/useTreeViewNodes.types.js → useTreeViewJSXItems/useTreeViewJSXItems.types.js} +0 -0
@@ -97,7 +97,7 @@ type TreeViewUsedPlugins<TSignature extends TreeViewAnyPluginSignature> = [
97
97
  TreeViewCorePluginsSignature,
98
98
  ...TSignature['dependantPlugins']
99
99
  ];
100
- type TreeViewUsedParams<TSignature extends TreeViewAnyPluginSignature> = TSignature['params'] & MergePluginsProperty<TreeViewUsedPlugins<TSignature>, 'params'>;
100
+ export type TreeViewUsedParams<TSignature extends TreeViewAnyPluginSignature> = TSignature['params'] & MergePluginsProperty<TreeViewUsedPlugins<TSignature>, 'params'>;
101
101
  type TreeViewUsedDefaultizedParams<TSignature extends TreeViewAnyPluginSignature> = TSignature['defaultizedParams'] & MergePluginsProperty<TreeViewUsedPlugins<TSignature>, 'defaultizedParams'>;
102
102
  export type TreeViewUsedInstance<TSignature extends TreeViewAnyPluginSignature> = TSignature['instance'] & MergePluginsProperty<TreeViewUsedPlugins<TSignature>, 'instance'> & {
103
103
  /**
@@ -1,13 +1,13 @@
1
1
  import { UseTreeViewIdParameters } from './useTreeViewId';
2
- import { UseTreeViewNodesParameters } from './useTreeViewNodes';
2
+ import { UseTreeViewItemsParameters } from './useTreeViewItems';
3
3
  import { UseTreeViewExpansionParameters } from './useTreeViewExpansion';
4
4
  import { UseTreeViewSelectionParameters } from './useTreeViewSelection';
5
5
  import { UseTreeViewFocusParameters } from './useTreeViewFocus';
6
6
  import { UseTreeViewIconsParameters } from './useTreeViewIcons';
7
7
  import { ConvertPluginsIntoSignatures, MergePluginsProperty } from '../models';
8
- export declare const DEFAULT_TREE_VIEW_PLUGINS: readonly [import("../models").TreeViewPlugin<import("./useTreeViewId").UseTreeViewIdSignature>, import("../models").TreeViewPlugin<import("./useTreeViewNodes").UseTreeViewNodesSignature>, import("../models").TreeViewPlugin<import("./useTreeViewExpansion").UseTreeViewExpansionSignature>, import("../models").TreeViewPlugin<import("./useTreeViewSelection").UseTreeViewSelectionSignature>, import("../models").TreeViewPlugin<import("./useTreeViewFocus").UseTreeViewFocusSignature>, import("../models").TreeViewPlugin<import("./useTreeViewKeyboardNavigation").UseTreeViewKeyboardNavigationSignature>, import("../models").TreeViewPlugin<import("./useTreeViewIcons").UseTreeViewIconsSignature>];
8
+ export declare const DEFAULT_TREE_VIEW_PLUGINS: readonly [import("../models").TreeViewPlugin<import("./useTreeViewId").UseTreeViewIdSignature>, import("../models").TreeViewPlugin<import("./useTreeViewItems").UseTreeViewItemsSignature>, import("../models").TreeViewPlugin<import("./useTreeViewExpansion").UseTreeViewExpansionSignature>, import("../models").TreeViewPlugin<import("./useTreeViewSelection").UseTreeViewSelectionSignature>, import("../models").TreeViewPlugin<import("./useTreeViewFocus").UseTreeViewFocusSignature>, import("../models").TreeViewPlugin<import("./useTreeViewKeyboardNavigation").UseTreeViewKeyboardNavigationSignature>, import("../models").TreeViewPlugin<import("./useTreeViewIcons").UseTreeViewIconsSignature>];
9
9
  export type DefaultTreeViewPlugins = ConvertPluginsIntoSignatures<typeof DEFAULT_TREE_VIEW_PLUGINS>;
10
10
  export type DefaultTreeViewPluginSlots = MergePluginsProperty<DefaultTreeViewPlugins, 'slots'>;
11
11
  export type DefaultTreeViewPluginSlotProps = MergePluginsProperty<DefaultTreeViewPlugins, 'slotProps'>;
12
- export interface DefaultTreeViewPluginParameters<R extends {}, Multiple extends boolean | undefined> extends UseTreeViewIdParameters, UseTreeViewNodesParameters<R>, UseTreeViewExpansionParameters, UseTreeViewFocusParameters, UseTreeViewSelectionParameters<Multiple>, UseTreeViewIconsParameters {
12
+ export interface DefaultTreeViewPluginParameters<R extends {}, Multiple extends boolean | undefined> extends UseTreeViewIdParameters, UseTreeViewItemsParameters<R>, UseTreeViewExpansionParameters, UseTreeViewFocusParameters, UseTreeViewSelectionParameters<Multiple>, UseTreeViewIconsParameters {
13
13
  }
@@ -1,10 +1,10 @@
1
1
  import { useTreeViewId } from './useTreeViewId';
2
- import { useTreeViewNodes } from './useTreeViewNodes';
2
+ import { useTreeViewItems } from './useTreeViewItems';
3
3
  import { useTreeViewExpansion } from './useTreeViewExpansion';
4
4
  import { useTreeViewSelection } from './useTreeViewSelection';
5
5
  import { useTreeViewFocus } from './useTreeViewFocus';
6
6
  import { useTreeViewKeyboardNavigation } from './useTreeViewKeyboardNavigation';
7
7
  import { useTreeViewIcons } from './useTreeViewIcons';
8
- export const DEFAULT_TREE_VIEW_PLUGINS = [useTreeViewId, useTreeViewNodes, useTreeViewExpansion, useTreeViewSelection, useTreeViewFocus, useTreeViewKeyboardNavigation, useTreeViewIcons];
8
+ export const DEFAULT_TREE_VIEW_PLUGINS = [useTreeViewId, useTreeViewItems, useTreeViewExpansion, useTreeViewSelection, useTreeViewFocus, useTreeViewKeyboardNavigation, useTreeViewIcons];
9
9
 
10
10
  // We can't infer this type from the plugin, otherwise we would lose the generics.
@@ -1,40 +1,50 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import useEventCallback from '@mui/utils/useEventCallback';
4
- import { populateInstance } from '../../useTreeView/useTreeView.utils';
4
+ import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
5
5
  export const useTreeViewExpansion = ({
6
6
  instance,
7
+ publicAPI,
7
8
  params,
8
9
  models
9
10
  }) => {
11
+ const expandedItemsMap = React.useMemo(() => {
12
+ const temp = new Map();
13
+ models.expandedItems.value.forEach(id => {
14
+ temp.set(id, true);
15
+ });
16
+ return temp;
17
+ }, [models.expandedItems.value]);
10
18
  const setExpandedItems = (event, value) => {
11
19
  params.onExpandedItemsChange?.(event, value);
12
20
  models.expandedItems.setControlledValue(value);
13
21
  };
14
- const isNodeExpanded = React.useCallback(itemId => {
15
- return Array.isArray(models.expandedItems.value) ? models.expandedItems.value.indexOf(itemId) !== -1 : false;
16
- }, [models.expandedItems.value]);
17
- const isNodeExpandable = React.useCallback(itemId => !!instance.getNode(itemId)?.expandable, [instance]);
18
- const toggleNodeExpansion = useEventCallback((event, itemId) => {
19
- if (itemId == null) {
22
+ const isItemExpanded = React.useCallback(itemId => expandedItemsMap.has(itemId), [expandedItemsMap]);
23
+ const isItemExpandable = React.useCallback(itemId => !!instance.getNode(itemId)?.expandable, [instance]);
24
+ const toggleItemExpansion = useEventCallback((event, itemId) => {
25
+ const isExpandedBefore = instance.isItemExpanded(itemId);
26
+ instance.setItemExpansion(event, itemId, !isExpandedBefore);
27
+ });
28
+ const setItemExpansion = useEventCallback((event, itemId, isExpanded) => {
29
+ const isExpandedBefore = instance.isItemExpanded(itemId);
30
+ if (isExpandedBefore === isExpanded) {
20
31
  return;
21
32
  }
22
- const isExpandedBefore = models.expandedItems.value.indexOf(itemId) !== -1;
23
33
  let newExpanded;
24
- if (isExpandedBefore) {
25
- newExpanded = models.expandedItems.value.filter(id => id !== itemId);
26
- } else {
34
+ if (isExpanded) {
27
35
  newExpanded = [itemId].concat(models.expandedItems.value);
36
+ } else {
37
+ newExpanded = models.expandedItems.value.filter(id => id !== itemId);
28
38
  }
29
39
  if (params.onItemExpansionToggle) {
30
- params.onItemExpansionToggle(event, itemId, !isExpandedBefore);
40
+ params.onItemExpansionToggle(event, itemId, isExpanded);
31
41
  }
32
42
  setExpandedItems(event, newExpanded);
33
43
  });
34
44
  const expandAllSiblings = (event, itemId) => {
35
45
  const node = instance.getNode(itemId);
36
46
  const siblings = instance.getChildrenIds(node.parentId);
37
- const diff = siblings.filter(child => instance.isNodeExpandable(child) && !instance.isNodeExpanded(child));
47
+ const diff = siblings.filter(child => instance.isItemExpandable(child) && !instance.isItemExpanded(child));
38
48
  const newExpanded = models.expandedItems.value.concat(diff);
39
49
  if (diff.length > 0) {
40
50
  if (params.onItemExpansionToggle) {
@@ -46,20 +56,24 @@ export const useTreeViewExpansion = ({
46
56
  }
47
57
  };
48
58
  populateInstance(instance, {
49
- isNodeExpanded,
50
- isNodeExpandable,
51
- toggleNodeExpansion,
59
+ isItemExpanded,
60
+ isItemExpandable,
61
+ setItemExpansion,
62
+ toggleItemExpansion,
52
63
  expandAllSiblings
53
64
  });
65
+ populatePublicAPI(publicAPI, {
66
+ setItemExpansion
67
+ });
54
68
  };
55
69
  useTreeViewExpansion.models = {
56
70
  expandedItems: {
57
71
  getDefaultValue: params => params.defaultExpandedItems
58
72
  }
59
73
  };
60
- const DEFAULT_EXPANDED_NODES = [];
74
+ const DEFAULT_EXPANDED_ITEMS = [];
61
75
  useTreeViewExpansion.getDefaultizedParams = params => _extends({}, params, {
62
- defaultExpandedItems: params.defaultExpandedItems ?? DEFAULT_EXPANDED_NODES
76
+ defaultExpandedItems: params.defaultExpandedItems ?? DEFAULT_EXPANDED_ITEMS
63
77
  });
64
78
  useTreeViewExpansion.params = {
65
79
  expandedItems: true,
@@ -1,10 +1,19 @@
1
1
  import * as React from 'react';
2
2
  import { DefaultizedProps, TreeViewPluginSignature } from '../../models';
3
- import { UseTreeViewNodesSignature } from '../useTreeViewNodes';
4
- export interface UseTreeViewExpansionInstance {
5
- isNodeExpanded: (itemId: string) => boolean;
6
- isNodeExpandable: (itemId: string) => boolean;
7
- toggleNodeExpansion: (event: React.SyntheticEvent, value: string) => void;
3
+ import { UseTreeViewItemsSignature } from '../useTreeViewItems';
4
+ export interface UseTreeViewExpansionPublicAPI {
5
+ /**
6
+ * Change the expansion status of a given item.
7
+ * @param {React.SyntheticEvent} event The UI event that triggered the change.
8
+ * @param {string} itemId The id of the item to modify.
9
+ * @param {boolean} isExpanded The new expansion status of the given item.
10
+ */
11
+ setItemExpansion: (event: React.SyntheticEvent, itemId: string, isExpanded: boolean) => void;
12
+ }
13
+ export interface UseTreeViewExpansionInstance extends UseTreeViewExpansionPublicAPI {
14
+ isItemExpanded: (itemId: string) => boolean;
15
+ isItemExpandable: (itemId: string) => boolean;
16
+ toggleItemExpansion: (event: React.SyntheticEvent, itemId: string) => void;
8
17
  expandAllSiblings: (event: React.KeyboardEvent, itemId: string) => void;
9
18
  }
10
19
  export interface UseTreeViewExpansionParameters {
@@ -38,6 +47,7 @@ export type UseTreeViewExpansionSignature = TreeViewPluginSignature<{
38
47
  params: UseTreeViewExpansionParameters;
39
48
  defaultizedParams: UseTreeViewExpansionDefaultizedParameters;
40
49
  instance: UseTreeViewExpansionInstance;
50
+ publicAPI: UseTreeViewExpansionPublicAPI;
41
51
  modelNames: 'expandedItems';
42
- dependantPlugins: [UseTreeViewNodesSignature];
52
+ dependantPlugins: [UseTreeViewItemsSignature];
43
53
  }>;
@@ -8,7 +8,7 @@ import { getActiveElement } from '../../utils/utils';
8
8
  const useTabbableItemId = (instance, selectedItems) => {
9
9
  const isItemVisible = itemId => {
10
10
  const node = instance.getNode(itemId);
11
- return node && (node.parentId == null || instance.isNodeExpanded(node.parentId));
11
+ return node && (node.parentId == null || instance.isItemExpanded(node.parentId));
12
12
  };
13
13
  let tabbableItemId;
14
14
  if (Array.isArray(selectedItems)) {
@@ -32,18 +32,18 @@ export const useTreeViewFocus = ({
32
32
  }) => {
33
33
  const tabbableItemId = useTabbableItemId(instance, models.selectedItems.value);
34
34
  const setFocusedItemId = useEventCallback(itemId => {
35
- const cleanItemId = typeof itemId === 'function' ? itemId(state.focusedNodeId) : itemId;
36
- if (state.focusedNodeId !== cleanItemId) {
35
+ const cleanItemId = typeof itemId === 'function' ? itemId(state.focusedItemId) : itemId;
36
+ if (state.focusedItemId !== cleanItemId) {
37
37
  setState(prevState => _extends({}, prevState, {
38
- focusedNodeId: cleanItemId
38
+ focusedItemId: cleanItemId
39
39
  }));
40
40
  }
41
41
  });
42
42
  const isTreeViewFocused = React.useCallback(() => !!rootRef.current && rootRef.current.contains(getActiveElement(ownerDocument(rootRef.current))), [rootRef]);
43
- const isNodeFocused = React.useCallback(itemId => state.focusedNodeId === itemId && isTreeViewFocused(), [state.focusedNodeId, isTreeViewFocused]);
44
- const isNodeVisible = itemId => {
43
+ const isItemFocused = React.useCallback(itemId => state.focusedItemId === itemId && isTreeViewFocused(), [state.focusedItemId, isTreeViewFocused]);
44
+ const isItemVisible = itemId => {
45
45
  const node = instance.getNode(itemId);
46
- return node && (node.parentId == null || instance.isNodeExpanded(node.parentId));
46
+ return node && (node.parentId == null || instance.isItemExpanded(node.parentId));
47
47
  };
48
48
  const innerFocusItem = (event, itemId) => {
49
49
  const node = instance.getNode(itemId);
@@ -56,62 +56,64 @@ export const useTreeViewFocus = ({
56
56
  params.onItemFocus(event, itemId);
57
57
  }
58
58
  };
59
- const focusItem = useEventCallback((event, nodeId) => {
60
- // If we receive a nodeId, and it is visible, the focus will be set to it
61
- if (isNodeVisible(nodeId)) {
62
- innerFocusItem(event, nodeId);
59
+ const focusItem = useEventCallback((event, itemId) => {
60
+ // If we receive an itemId, and it is visible, the focus will be set to it
61
+ if (isItemVisible(itemId)) {
62
+ innerFocusItem(event, itemId);
63
63
  }
64
64
  });
65
- const focusDefaultNode = useEventCallback(event => {
66
- let nodeToFocusId;
65
+ const focusDefaultItem = useEventCallback(event => {
66
+ let itemToFocusId;
67
67
  if (Array.isArray(models.selectedItems.value)) {
68
- nodeToFocusId = models.selectedItems.value.find(isNodeVisible);
69
- } else if (models.selectedItems.value != null && isNodeVisible(models.selectedItems.value)) {
70
- nodeToFocusId = models.selectedItems.value;
68
+ itemToFocusId = models.selectedItems.value.find(isItemVisible);
69
+ } else if (models.selectedItems.value != null && isItemVisible(models.selectedItems.value)) {
70
+ itemToFocusId = models.selectedItems.value;
71
71
  }
72
- if (nodeToFocusId == null) {
73
- nodeToFocusId = instance.getNavigableChildrenIds(null)[0];
72
+ if (itemToFocusId == null) {
73
+ itemToFocusId = instance.getNavigableChildrenIds(null)[0];
74
74
  }
75
- innerFocusItem(event, nodeToFocusId);
75
+ innerFocusItem(event, itemToFocusId);
76
76
  });
77
77
  const removeFocusedItem = useEventCallback(() => {
78
- if (state.focusedNodeId == null) {
78
+ if (state.focusedItemId == null) {
79
79
  return;
80
80
  }
81
- const node = instance.getNode(state.focusedNodeId);
82
- const itemElement = document.getElementById(instance.getTreeItemId(state.focusedNodeId, node.idAttribute));
83
- if (itemElement) {
84
- itemElement.blur();
81
+ const node = instance.getNode(state.focusedItemId);
82
+ if (node) {
83
+ const itemElement = document.getElementById(instance.getTreeItemId(state.focusedItemId, node.idAttribute));
84
+ if (itemElement) {
85
+ itemElement.blur();
86
+ }
85
87
  }
86
88
  setFocusedItemId(null);
87
89
  });
88
90
  const canItemBeTabbed = itemId => itemId === tabbableItemId;
89
91
  populateInstance(instance, {
90
- isNodeFocused,
92
+ isItemFocused,
91
93
  canItemBeTabbed,
92
94
  focusItem,
93
- focusDefaultNode,
95
+ focusDefaultItem,
94
96
  removeFocusedItem
95
97
  });
96
98
  populatePublicAPI(publicAPI, {
97
99
  focusItem
98
100
  });
99
- useInstanceEventHandler(instance, 'removeNode', ({
101
+ useInstanceEventHandler(instance, 'removeItem', ({
100
102
  id
101
103
  }) => {
102
- if (state.focusedNodeId === id) {
103
- instance.focusDefaultNode(null);
104
+ if (state.focusedItemId === id) {
105
+ instance.focusDefaultItem(null);
104
106
  }
105
107
  });
106
108
  const createHandleFocus = otherHandlers => event => {
107
109
  otherHandlers.onFocus?.(event);
108
110
  // if the event bubbled (which is React specific) we don't want to steal focus
109
111
  if (event.target === event.currentTarget) {
110
- instance.focusDefaultNode(event);
112
+ instance.focusDefaultItem(event);
111
113
  }
112
114
  };
113
- const focusedNode = instance.getNode(state.focusedNodeId);
114
- const activeDescendant = focusedNode ? instance.getTreeItemId(focusedNode.id, focusedNode.idAttribute) : null;
115
+ const focusedItem = instance.getNode(state.focusedItemId);
116
+ const activeDescendant = focusedItem ? instance.getTreeItemId(focusedItem.id, focusedItem.idAttribute) : null;
115
117
  return {
116
118
  getRootProps: otherHandlers => ({
117
119
  onFocus: createHandleFocus(otherHandlers),
@@ -120,7 +122,7 @@ export const useTreeViewFocus = ({
120
122
  };
121
123
  };
122
124
  useTreeViewFocus.getInitialState = () => ({
123
- focusedNodeId: null
125
+ focusedItemId: null
124
126
  });
125
127
  useTreeViewFocus.params = {
126
128
  onItemFocus: true
@@ -1,18 +1,26 @@
1
1
  import * as React from 'react';
2
2
  import { TreeViewPluginSignature } from '../../models';
3
3
  import { UseTreeViewIdSignature } from '../useTreeViewId/useTreeViewId.types';
4
- import type { UseTreeViewNodesSignature } from '../useTreeViewNodes';
4
+ import type { UseTreeViewItemsSignature } from '../useTreeViewItems';
5
5
  import type { UseTreeViewSelectionSignature } from '../useTreeViewSelection';
6
6
  import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
7
- export interface UseTreeViewFocusInstance {
8
- isNodeFocused: (itemId: string) => boolean;
7
+ export interface UseTreeViewFocusPublicAPI {
8
+ /**
9
+ * Focuses the item with the given id.
10
+ *
11
+ * If the item is the child of a collapsed item, then this method will do nothing.
12
+ * Make sure to expand the ancestors of the item before calling this method if needed.
13
+ * @param {React.SyntheticEvent} event The event source of the action.
14
+ * @param {string} itemId The id of the item to focus.
15
+ */
16
+ focusItem: (event: React.SyntheticEvent, itemId: string) => void;
17
+ }
18
+ export interface UseTreeViewFocusInstance extends UseTreeViewFocusPublicAPI {
19
+ isItemFocused: (itemId: string) => boolean;
9
20
  canItemBeTabbed: (itemId: string) => boolean;
10
- focusItem: (event: React.SyntheticEvent, nodeId: string) => void;
11
- focusDefaultNode: (event: React.SyntheticEvent | null) => void;
21
+ focusDefaultItem: (event: React.SyntheticEvent | null) => void;
12
22
  removeFocusedItem: () => void;
13
23
  }
14
- export interface UseTreeViewFocusPublicAPI extends Pick<UseTreeViewFocusInstance, 'focusItem'> {
15
- }
16
24
  export interface UseTreeViewFocusParameters {
17
25
  /**
18
26
  * Callback fired when tree items are focused.
@@ -24,7 +32,7 @@ export interface UseTreeViewFocusParameters {
24
32
  }
25
33
  export type UseTreeViewFocusDefaultizedParameters = UseTreeViewFocusParameters;
26
34
  export interface UseTreeViewFocusState {
27
- focusedNodeId: string | null;
35
+ focusedItemId: string | null;
28
36
  }
29
37
  export type UseTreeViewFocusSignature = TreeViewPluginSignature<{
30
38
  params: UseTreeViewFocusParameters;
@@ -34,7 +42,7 @@ export type UseTreeViewFocusSignature = TreeViewPluginSignature<{
34
42
  state: UseTreeViewFocusState;
35
43
  dependantPlugins: [
36
44
  UseTreeViewIdSignature,
37
- UseTreeViewNodesSignature,
45
+ UseTreeViewItemsSignature,
38
46
  UseTreeViewSelectionSignature,
39
47
  UseTreeViewExpansionSignature
40
48
  ];
@@ -1,23 +1,23 @@
1
1
  import * as React from 'react';
2
2
  import { SlotComponentProps } from '@mui/base/utils';
3
3
  import { TreeViewPluginSignature } from '../../models';
4
- import { UseTreeViewNodesSignature } from '../useTreeViewNodes';
4
+ import { UseTreeViewItemsSignature } from '../useTreeViewItems';
5
5
  import { UseTreeViewSelectionSignature } from '../useTreeViewSelection';
6
6
  export interface UseTreeViewIconsParameters {
7
7
  }
8
8
  export type UseTreeViewIconsDefaultizedParameters = UseTreeViewIconsParameters;
9
9
  interface UseTreeViewIconsSlots {
10
10
  /**
11
- * The default icon used to collapse the node.
11
+ * The default icon used to collapse the item.
12
12
  */
13
13
  collapseIcon?: React.ElementType;
14
14
  /**
15
- * The default icon used to expand the node.
15
+ * The default icon used to expand the item.
16
16
  */
17
17
  expandIcon?: React.ElementType;
18
18
  /**
19
- * The default icon displayed next to an end node.
20
- * This is applied to all tree nodes and can be overridden by the TreeItem `icon` slot prop.
19
+ * The default icon displayed next to an end item.
20
+ * This is applied to all tree items and can be overridden by the TreeItem `icon` slot prop.
21
21
  */
22
22
  endIcon?: React.ElementType;
23
23
  }
@@ -38,6 +38,6 @@ export type UseTreeViewIconsSignature = TreeViewPluginSignature<{
38
38
  contextValue: UseTreeViewIconsContextValue;
39
39
  slots: UseTreeViewIconsSlots;
40
40
  slotProps: UseTreeViewIconsSlotProps;
41
- dependantPlugins: [UseTreeViewNodesSignature, UseTreeViewSelectionSignature];
41
+ dependantPlugins: [UseTreeViewItemsSignature, UseTreeViewSelectionSignature];
42
42
  }>;
43
43
  export {};
@@ -11,7 +11,7 @@ export interface UseTreeViewIdParameters {
11
11
  }
12
12
  export type UseTreeViewIdDefaultizedParameters = UseTreeViewIdParameters;
13
13
  export interface UseTreeViewIdState {
14
- focusedNodeId: string | null;
14
+ focusedItemId: string | null;
15
15
  }
16
16
  export type UseTreeViewIdSignature = TreeViewPluginSignature<{
17
17
  params: UseTreeViewIdParameters;
@@ -0,0 +1,2 @@
1
+ export { useTreeViewItems } from './useTreeViewItems';
2
+ export type { UseTreeViewItemsSignature, UseTreeViewItemsParameters, UseTreeViewItemsDefaultizedParameters, } from './useTreeViewItems.types';
@@ -0,0 +1 @@
1
+ export { useTreeViewItems } from './useTreeViewItems';
@@ -0,0 +1,3 @@
1
+ import { TreeViewPlugin } from '../../models';
2
+ import { UseTreeViewItemsSignature } from './useTreeViewItems.types';
3
+ export declare const useTreeViewItems: TreeViewPlugin<UseTreeViewItemsSignature>;
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
4
4
  import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
5
- const updateNodesState = ({
5
+ const updateItemsState = ({
6
6
  items,
7
7
  isItemDisabled,
8
8
  getItemLabel,
@@ -16,7 +16,7 @@ const updateNodesState = ({
16
16
  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'));
17
17
  }
18
18
  if (nodeMap[id] != null) {
19
- 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.', `Tow items were provided with the same id in the \`items\` prop: "${id}"`].join('\n'));
19
+ 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'));
20
20
  }
21
21
  const label = getItemLabel ? getItemLabel(item) : item.label;
22
22
  if (label == null) {
@@ -44,86 +44,96 @@ const updateNodesState = ({
44
44
  itemMap
45
45
  };
46
46
  };
47
- export const useTreeViewNodes = ({
47
+ export const useTreeViewItems = ({
48
48
  instance,
49
49
  publicAPI,
50
50
  params,
51
51
  state,
52
52
  setState
53
53
  }) => {
54
- const getNode = React.useCallback(itemId => state.nodes.nodeMap[itemId], [state.nodes.nodeMap]);
55
- const getItem = React.useCallback(itemId => state.nodes.itemMap[itemId], [state.nodes.itemMap]);
56
- const isNodeDisabled = React.useCallback(itemId => {
54
+ const getNode = React.useCallback(itemId => state.items.nodeMap[itemId], [state.items.nodeMap]);
55
+ const getItem = React.useCallback(itemId => state.items.itemMap[itemId], [state.items.itemMap]);
56
+ const isItemDisabled = React.useCallback(itemId => {
57
57
  if (itemId == null) {
58
58
  return false;
59
59
  }
60
- let item = instance.getNode(itemId);
60
+ let node = instance.getNode(itemId);
61
61
 
62
- // This can be called before the item has been added to the node map.
63
- if (!item) {
62
+ // This can be called before the item has been added to the item map.
63
+ if (!node) {
64
64
  return false;
65
65
  }
66
- if (item.disabled) {
66
+ if (node.disabled) {
67
67
  return true;
68
68
  }
69
- while (item.parentId != null) {
70
- item = instance.getNode(item.parentId);
71
- if (item.disabled) {
69
+ while (node.parentId != null) {
70
+ node = instance.getNode(node.parentId);
71
+ if (node.disabled) {
72
72
  return true;
73
73
  }
74
74
  }
75
75
  return false;
76
76
  }, [instance]);
77
- const getChildrenIds = React.useCallback(itemId => Object.values(state.nodes.nodeMap).filter(item => item.parentId === itemId).sort((a, b) => a.index - b.index).map(child => child.id), [state.nodes.nodeMap]);
77
+ const getChildrenIds = React.useCallback(itemId => Object.values(state.items.nodeMap).filter(item => item.parentId === itemId).sort((a, b) => a.index - b.index).map(child => child.id), [state.items.nodeMap]);
78
78
  const getNavigableChildrenIds = itemId => {
79
79
  let childrenIds = instance.getChildrenIds(itemId);
80
80
  if (!params.disabledItemsFocusable) {
81
- childrenIds = childrenIds.filter(item => !instance.isNodeDisabled(item));
81
+ childrenIds = childrenIds.filter(item => !instance.isItemDisabled(item));
82
82
  }
83
83
  return childrenIds;
84
84
  };
85
+ const areItemUpdatesPreventedRef = React.useRef(false);
86
+ const preventItemUpdates = React.useCallback(() => {
87
+ areItemUpdatesPreventedRef.current = true;
88
+ }, []);
89
+ const areItemUpdatesPrevented = React.useCallback(() => areItemUpdatesPreventedRef.current, []);
85
90
  React.useEffect(() => {
91
+ if (instance.areItemUpdatesPrevented()) {
92
+ return;
93
+ }
86
94
  setState(prevState => {
87
- const newState = updateNodesState({
95
+ const newState = updateItemsState({
88
96
  items: params.items,
89
97
  isItemDisabled: params.isItemDisabled,
90
98
  getItemId: params.getItemId,
91
99
  getItemLabel: params.getItemLabel
92
100
  });
93
- Object.values(prevState.nodes.nodeMap).forEach(node => {
94
- if (!newState.nodeMap[node.id]) {
95
- publishTreeViewEvent(instance, 'removeNode', {
96
- id: node.id
101
+ Object.values(prevState.items.nodeMap).forEach(item => {
102
+ if (!newState.nodeMap[item.id]) {
103
+ publishTreeViewEvent(instance, 'removeItem', {
104
+ id: item.id
97
105
  });
98
106
  }
99
107
  });
100
108
  return _extends({}, prevState, {
101
- nodes: newState
109
+ items: newState
102
110
  });
103
111
  });
104
112
  }, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
105
- const getNodesToRender = () => {
113
+ const getItemsToRender = () => {
106
114
  const getPropsFromItemId = ({
107
115
  id,
108
116
  children
109
117
  }) => {
110
- const node = state.nodes.nodeMap[id];
118
+ const item = state.items.nodeMap[id];
111
119
  return {
112
- label: node.label,
113
- itemId: node.id,
114
- id: node.idAttribute,
120
+ label: item.label,
121
+ itemId: item.id,
122
+ id: item.idAttribute,
115
123
  children: children?.map(getPropsFromItemId)
116
124
  };
117
125
  };
118
- return state.nodes.nodeTree.map(getPropsFromItemId);
126
+ return state.items.nodeTree.map(getPropsFromItemId);
119
127
  };
120
128
  populateInstance(instance, {
121
129
  getNode,
122
130
  getItem,
123
- getNodesToRender,
131
+ getItemsToRender,
124
132
  getChildrenIds,
125
133
  getNavigableChildrenIds,
126
- isNodeDisabled
134
+ isItemDisabled,
135
+ preventItemUpdates,
136
+ areItemUpdatesPrevented
127
137
  });
128
138
  populatePublicAPI(publicAPI, {
129
139
  getItem
@@ -134,18 +144,18 @@ export const useTreeViewNodes = ({
134
144
  }
135
145
  };
136
146
  };
137
- useTreeViewNodes.getInitialState = params => ({
138
- nodes: updateNodesState({
147
+ useTreeViewItems.getInitialState = params => ({
148
+ items: updateItemsState({
139
149
  items: params.items,
140
150
  isItemDisabled: params.isItemDisabled,
141
151
  getItemId: params.getItemId,
142
152
  getItemLabel: params.getItemLabel
143
153
  })
144
154
  });
145
- useTreeViewNodes.getDefaultizedParams = params => _extends({}, params, {
155
+ useTreeViewItems.getDefaultizedParams = params => _extends({}, params, {
146
156
  disabledItemsFocusable: params.disabledItemsFocusable ?? false
147
157
  });
148
- useTreeViewNodes.params = {
158
+ useTreeViewItems.params = {
149
159
  disabledItemsFocusable: true,
150
160
  items: true,
151
161
  isItemDisabled: true,