@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
@@ -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
@@ -0,0 +1 @@
1
+ export { useTreeViewItems } from './useTreeViewItems';
@@ -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,
@@ -0,0 +1 @@
1
+ export { useTreeViewJSXItems } from './useTreeViewJSXItems';
@@ -7,45 +7,46 @@ import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
7
7
  import { useTreeViewContext } from '../../TreeViewProvider/useTreeViewContext';
8
8
  import { DescendantProvider, useDescendant } from '../../TreeViewProvider/DescendantProvider';
9
9
  import { jsx as _jsx } from "react/jsx-runtime";
10
- export const useTreeViewJSXNodes = ({
10
+ export const useTreeViewJSXItems = ({
11
11
  instance,
12
12
  setState
13
13
  }) => {
14
- const insertJSXNode = useEventCallback(node => {
14
+ instance.preventItemUpdates();
15
+ const insertJSXItem = useEventCallback(item => {
15
16
  setState(prevState => {
16
- if (prevState.nodes.nodeMap[node.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.', `Tow items were provided with the same id in the \`items\` prop: "${node.id}"`].join('\n'));
17
+ if (prevState.items.nodeMap[item.id] != null) {
18
+ 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: "${item.id}"`].join('\n'));
18
19
  }
19
20
  return _extends({}, prevState, {
20
- nodes: _extends({}, prevState.nodes, {
21
- nodeMap: _extends({}, prevState.nodes.nodeMap, {
22
- [node.id]: node
21
+ items: _extends({}, prevState.items, {
22
+ nodeMap: _extends({}, prevState.items.nodeMap, {
23
+ [item.id]: item
23
24
  }),
24
25
  // For `SimpleTreeView`, we don't have a proper `item` object, so we create a very basic one.
25
- itemMap: _extends({}, prevState.nodes.itemMap, {
26
- [node.id]: {
27
- id: node.id,
28
- label: node.label
26
+ itemMap: _extends({}, prevState.items.itemMap, {
27
+ [item.id]: {
28
+ id: item.id,
29
+ label: item.label
29
30
  }
30
31
  })
31
32
  })
32
33
  });
33
34
  });
34
35
  });
35
- const removeJSXNode = useEventCallback(itemId => {
36
+ const removeJSXItem = useEventCallback(itemId => {
36
37
  setState(prevState => {
37
- const newNodeMap = _extends({}, prevState.nodes.nodeMap);
38
- const newItemMap = _extends({}, prevState.nodes.itemMap);
38
+ const newNodeMap = _extends({}, prevState.items.nodeMap);
39
+ const newItemMap = _extends({}, prevState.items.itemMap);
39
40
  delete newNodeMap[itemId];
40
41
  delete newItemMap[itemId];
41
42
  return _extends({}, prevState, {
42
- nodes: _extends({}, prevState.nodes, {
43
+ items: _extends({}, prevState.items, {
43
44
  nodeMap: newNodeMap,
44
45
  itemMap: newItemMap
45
46
  })
46
47
  });
47
48
  });
48
- publishTreeViewEvent(instance, 'removeNode', {
49
+ publishTreeViewEvent(instance, 'removeItem', {
49
50
  id: itemId
50
51
  });
51
52
  });
@@ -63,12 +64,12 @@ export const useTreeViewJSXNodes = ({
63
64
  };
64
65
  });
65
66
  populateInstance(instance, {
66
- insertJSXNode,
67
- removeJSXNode,
67
+ insertJSXItem,
68
+ removeJSXItem,
68
69
  mapFirstCharFromJSX
69
70
  });
70
71
  };
71
- const useTreeViewJSXNodesItemPlugin = ({
72
+ const useTreeViewJSXItemsItemPlugin = ({
72
73
  props,
73
74
  rootRef,
74
75
  contentRef
@@ -103,9 +104,9 @@ const useTreeViewJSXNodesItemPlugin = ({
103
104
  parentId
104
105
  } = useDescendant(descendant);
105
106
  React.useEffect(() => {
106
- // On the first render a node's index will be -1. We want to wait for the real index.
107
+ // On the first render a item's index will be -1. We want to wait for the real index.
107
108
  if (index !== -1) {
108
- instance.insertJSXNode({
109
+ instance.insertJSXItem({
109
110
  id: itemId,
110
111
  idAttribute: id,
111
112
  index,
@@ -113,7 +114,7 @@ const useTreeViewJSXNodesItemPlugin = ({
113
114
  expandable,
114
115
  disabled
115
116
  });
116
- return () => instance.removeJSXNode(itemId);
117
+ return () => instance.removeJSXItem(itemId);
117
118
  }
118
119
  return undefined;
119
120
  }, [instance, parentId, index, itemId, expandable, disabled, id]);
@@ -128,12 +129,12 @@ const useTreeViewJSXNodesItemPlugin = ({
128
129
  rootRef: handleRootRef
129
130
  };
130
131
  };
131
- useTreeViewJSXNodes.itemPlugin = useTreeViewJSXNodesItemPlugin;
132
- useTreeViewJSXNodes.wrapItem = ({
132
+ useTreeViewJSXItems.itemPlugin = useTreeViewJSXItemsItemPlugin;
133
+ useTreeViewJSXItems.wrapItem = ({
133
134
  children,
134
135
  itemId
135
136
  }) => /*#__PURE__*/_jsx(DescendantProvider, {
136
137
  id: itemId,
137
138
  children: children
138
139
  });
139
- useTreeViewJSXNodes.params = {};
140
+ useTreeViewJSXItems.params = {};
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { useTheme } from '@mui/material/styles';
3
3
  import useEventCallback from '@mui/utils/useEventCallback';
4
- import { getFirstNode, getLastNode, getNextNode, getPreviousNode, populateInstance } from '../../useTreeView/useTreeView.utils';
4
+ import { getFirstItem, getLastItem, getNextItem, getPreviousItem, populateInstance } from '../../useTreeView/useTreeView.utils';
5
5
  function isPrintableCharacter(string) {
6
6
  return !!string && string.length === 1 && !!string.match(/\S/);
7
7
  }
@@ -15,30 +15,26 @@ function findNextFirstChar(firstChars, startIndex, char) {
15
15
  }
16
16
  export const useTreeViewKeyboardNavigation = ({
17
17
  instance,
18
- params
18
+ params,
19
+ state
19
20
  }) => {
20
21
  const theme = useTheme();
21
22
  const isRTL = theme.direction === 'rtl';
22
23
  const firstCharMap = React.useRef({});
23
- const hasFirstCharMapBeenUpdatedImperatively = React.useRef(false);
24
24
  const updateFirstCharMap = useEventCallback(callback => {
25
- hasFirstCharMapBeenUpdatedImperatively.current = true;
26
25
  firstCharMap.current = callback(firstCharMap.current);
27
26
  });
28
27
  React.useEffect(() => {
29
- if (hasFirstCharMapBeenUpdatedImperatively.current) {
28
+ if (instance.areItemUpdatesPrevented()) {
30
29
  return;
31
30
  }
32
31
  const newFirstCharMap = {};
33
- const processItem = item => {
34
- const getItemId = params.getItemId;
35
- const itemId = getItemId ? getItemId(item) : item.id;
36
- newFirstCharMap[itemId] = instance.getNode(itemId).label.substring(0, 1).toLowerCase();
37
- item.children?.forEach(processItem);
32
+ const processItem = node => {
33
+ newFirstCharMap[node.id] = node.label.substring(0, 1).toLowerCase();
38
34
  };
39
- params.items.forEach(processItem);
35
+ Object.values(state.items.nodeMap).forEach(processItem);
40
36
  firstCharMap.current = newFirstCharMap;
41
- }, [params.items, params.getItemId, instance]);
37
+ }, [state.items.nodeMap, params.getItemId, instance]);
42
38
  const getFirstMatchingItem = (itemId, firstChar) => {
43
39
  let start;
44
40
  let index;
@@ -48,8 +44,8 @@ export const useTreeViewKeyboardNavigation = ({
48
44
  // This really only works since the ids are strings
49
45
  Object.keys(firstCharMap.current).forEach(mapItemId => {
50
46
  const map = instance.getNode(mapItemId);
51
- const visible = map.parentId ? instance.isNodeExpanded(map.parentId) : true;
52
- const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(mapItemId);
47
+ const visible = map.parentId ? instance.isItemExpanded(map.parentId) : true;
48
+ const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isItemDisabled(mapItemId);
53
49
  if (visible && !shouldBeSkipped) {
54
50
  firstCharIds.push(mapItemId);
55
51
  firstChars.push(firstCharMap.current[mapItemId]);
@@ -76,9 +72,9 @@ export const useTreeViewKeyboardNavigation = ({
76
72
  }
77
73
  return null;
78
74
  };
79
- const canToggleItemSelection = itemId => !params.disableSelection && !instance.isNodeDisabled(itemId);
75
+ const canToggleItemSelection = itemId => !params.disableSelection && !instance.isItemDisabled(itemId);
80
76
  const canToggleItemExpansion = itemId => {
81
- return !instance.isNodeDisabled(itemId) && instance.isNodeExpandable(itemId);
77
+ return !instance.isItemDisabled(itemId) && instance.isItemExpandable(itemId);
82
78
  };
83
79
 
84
80
  // ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
@@ -94,7 +90,7 @@ export const useTreeViewKeyboardNavigation = ({
94
90
 
95
91
  // eslint-disable-next-line default-case
96
92
  switch (true) {
97
- // Select the node when pressing "Space"
93
+ // Select the item when pressing "Space"
98
94
  case key === ' ' && canToggleItemSelection(itemId):
99
95
  {
100
96
  event.preventDefault();
@@ -103,26 +99,26 @@ export const useTreeViewKeyboardNavigation = ({
103
99
  end: itemId
104
100
  });
105
101
  } else if (params.multiSelect) {
106
- instance.selectNode(event, itemId, true);
102
+ instance.selectItem(event, itemId, true);
107
103
  } else {
108
- instance.selectNode(event, itemId);
104
+ instance.selectItem(event, itemId);
109
105
  }
110
106
  break;
111
107
  }
112
108
 
113
- // If the focused node has children, we expand it.
114
- // If the focused node has no children, we select it.
109
+ // If the focused item has children, we expand it.
110
+ // If the focused item has no children, we select it.
115
111
  case key === 'Enter':
116
112
  {
117
113
  if (canToggleItemExpansion(itemId)) {
118
- instance.toggleNodeExpansion(event, itemId);
114
+ instance.toggleItemExpansion(event, itemId);
119
115
  event.preventDefault();
120
116
  } else if (canToggleItemSelection(itemId)) {
121
117
  if (params.multiSelect) {
122
118
  event.preventDefault();
123
- instance.selectNode(event, itemId, true);
124
- } else if (!instance.isNodeSelected(itemId)) {
125
- instance.selectNode(event, itemId);
119
+ instance.selectItem(event, itemId, true);
120
+ } else if (!instance.isItemSelected(itemId)) {
121
+ instance.selectItem(event, itemId);
126
122
  event.preventDefault();
127
123
  }
128
124
  }
@@ -132,7 +128,7 @@ export const useTreeViewKeyboardNavigation = ({
132
128
  // Focus the next focusable item
133
129
  case key === 'ArrowDown':
134
130
  {
135
- const nextItem = getNextNode(instance, itemId);
131
+ const nextItem = getNextItem(instance, itemId);
136
132
  if (nextItem) {
137
133
  event.preventDefault();
138
134
  instance.focusItem(event, nextItem);
@@ -152,7 +148,7 @@ export const useTreeViewKeyboardNavigation = ({
152
148
  // Focuses the previous focusable item
153
149
  case key === 'ArrowUp':
154
150
  {
155
- const previousItem = getPreviousNode(instance, itemId);
151
+ const previousItem = getPreviousItem(instance, itemId);
156
152
  if (previousItem) {
157
153
  event.preventDefault();
158
154
  instance.focusItem(event, previousItem);
@@ -173,14 +169,14 @@ export const useTreeViewKeyboardNavigation = ({
173
169
  // If the focused item is collapsed and has children, we expand it
174
170
  case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
175
171
  {
176
- if (instance.isNodeExpanded(itemId)) {
177
- const nextNodeId = getNextNode(instance, itemId);
178
- if (nextNodeId) {
179
- instance.focusItem(event, nextNodeId);
172
+ if (instance.isItemExpanded(itemId)) {
173
+ const nextItemId = getNextItem(instance, itemId);
174
+ if (nextItemId) {
175
+ instance.focusItem(event, nextItemId);
180
176
  event.preventDefault();
181
177
  }
182
178
  } else if (canToggleItemExpansion(itemId)) {
183
- instance.toggleNodeExpansion(event, itemId);
179
+ instance.toggleItemExpansion(event, itemId);
184
180
  event.preventDefault();
185
181
  }
186
182
  break;
@@ -190,8 +186,8 @@ export const useTreeViewKeyboardNavigation = ({
190
186
  // If the focused item is collapsed and has a parent, we move the focus to this parent
191
187
  case key === 'ArrowLeft' && !isRTL || key === 'ArrowRight' && isRTL:
192
188
  {
193
- if (canToggleItemExpansion(itemId) && instance.isNodeExpanded(itemId)) {
194
- instance.toggleNodeExpansion(event, itemId);
189
+ if (canToggleItemExpansion(itemId) && instance.isItemExpanded(itemId)) {
190
+ instance.toggleItemExpansion(event, itemId);
195
191
  event.preventDefault();
196
192
  } else {
197
193
  const parent = instance.getNode(itemId).parentId;
@@ -203,13 +199,13 @@ export const useTreeViewKeyboardNavigation = ({
203
199
  break;
204
200
  }
205
201
 
206
- // Focuses the first node in the tree
202
+ // Focuses the first item in the tree
207
203
  case key === 'Home':
208
204
  {
209
- instance.focusItem(event, getFirstNode(instance));
205
+ instance.focusItem(event, getFirstItem(instance));
210
206
 
211
207
  // Multi select behavior when pressing Ctrl + Shift + Home
212
- // Selects the focused node and all nodes up to the first node.
208
+ // Selects the focused item and all items up to the first item.
213
209
  if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
214
210
  instance.rangeSelectToFirst(event, itemId);
215
211
  }
@@ -220,7 +216,7 @@ export const useTreeViewKeyboardNavigation = ({
220
216
  // Focuses the last item in the tree
221
217
  case key === 'End':
222
218
  {
223
- instance.focusItem(event, getLastNode(instance));
219
+ instance.focusItem(event, getLastItem(instance));
224
220
 
225
221
  // Multi select behavior when pressing Ctrl + Shirt + End
226
222
  // Selects the focused item and all the items down to the last item.
@@ -240,12 +236,12 @@ export const useTreeViewKeyboardNavigation = ({
240
236
  }
241
237
 
242
238
  // Multi select behavior when pressing Ctrl + a
243
- // Selects all the nodes
239
+ // Selects all the items
244
240
  case key === 'a' && ctrlPressed && params.multiSelect && !params.disableSelection:
245
241
  {
246
242
  instance.selectRange(event, {
247
- start: getFirstNode(instance),
248
- end: getLastNode(instance)
243
+ start: getFirstItem(instance),
244
+ end: getLastItem(instance)
249
245
  });
250
246
  event.preventDefault();
251
247
  break;
@@ -255,9 +251,9 @@ export const useTreeViewKeyboardNavigation = ({
255
251
  // TODO: Support typing multiple characters
256
252
  case !ctrlPressed && !event.shiftKey && isPrintableCharacter(key):
257
253
  {
258
- const matchingNode = getFirstMatchingItem(itemId, key);
259
- if (matchingNode != null) {
260
- instance.focusItem(event, matchingNode);
254
+ const matchingItem = getFirstMatchingItem(itemId, key);
255
+ if (matchingItem != null) {
256
+ instance.focusItem(event, matchingItem);
261
257
  event.preventDefault();
262
258
  }
263
259
  break;