@mui/x-tree-view 7.0.0-beta.7 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +195 -12
  2. package/README.md +1 -1
  3. package/RichTreeView/RichTreeView.js +12 -14
  4. package/RichTreeView/RichTreeView.types.d.ts +1 -1
  5. package/SimpleTreeView/SimpleTreeView.js +3 -4
  6. package/TreeItem/TreeItem.js +43 -35
  7. package/TreeItem/TreeItem.types.d.ts +3 -3
  8. package/TreeItem/TreeItemContent.d.ts +7 -7
  9. package/TreeItem/TreeItemContent.js +10 -10
  10. package/TreeItem/useTreeItemState.d.ts +1 -1
  11. package/TreeItem/useTreeItemState.js +13 -13
  12. package/TreeItem2/TreeItem2.js +16 -17
  13. package/TreeItem2Icon/TreeItem2Icon.js +5 -6
  14. package/TreeItem2Provider/TreeItem2Provider.js +3 -3
  15. package/TreeItem2Provider/TreeItem2Provider.types.d.ts +1 -1
  16. package/TreeView/TreeView.d.ts +1 -1
  17. package/TreeView/TreeView.js +1 -1
  18. package/hooks/useTreeItem2Utils/useTreeItem2Utils.d.ts +2 -2
  19. package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +12 -12
  20. package/index.js +1 -1
  21. package/internals/hooks/useInstanceEventHandler.js +5 -10
  22. package/internals/models/plugin.d.ts +1 -1
  23. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +11 -18
  24. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +3 -3
  25. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +59 -43
  26. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +6 -5
  27. package/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
  28. package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +1 -1
  29. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +17 -18
  30. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.d.ts +2 -2
  31. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +70 -77
  32. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +4 -1
  33. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +24 -29
  34. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +11 -11
  35. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +18 -21
  36. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +4 -4
  37. package/internals/useTreeView/useTreeView.js +5 -6
  38. package/internals/useTreeView/useTreeView.utils.d.ts +2 -2
  39. package/internals/useTreeView/useTreeView.utils.js +22 -22
  40. package/internals/utils/extractPluginParamsFromProps.js +2 -2
  41. package/internals/utils/utils.js +1 -0
  42. package/modern/RichTreeView/RichTreeView.js +7 -7
  43. package/modern/SimpleTreeView/SimpleTreeView.js +1 -1
  44. package/modern/TreeItem/TreeItem.js +31 -22
  45. package/modern/TreeItem/TreeItemContent.js +10 -10
  46. package/modern/TreeItem/useTreeItemState.js +13 -13
  47. package/modern/TreeItem2/TreeItem2.js +11 -11
  48. package/modern/TreeItem2Provider/TreeItem2Provider.js +3 -3
  49. package/modern/TreeView/TreeView.js +1 -1
  50. package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +12 -12
  51. package/modern/index.js +1 -1
  52. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +7 -7
  53. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +57 -38
  54. package/modern/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
  55. package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +17 -17
  56. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +69 -74
  57. package/modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +19 -20
  58. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +13 -13
  59. package/modern/internals/useTreeView/useTreeView.js +3 -4
  60. package/modern/internals/useTreeView/useTreeView.utils.js +22 -22
  61. package/modern/internals/utils/utils.js +1 -0
  62. package/modern/useTreeItem2/useTreeItem2.js +23 -12
  63. package/node/RichTreeView/RichTreeView.js +7 -7
  64. package/node/SimpleTreeView/SimpleTreeView.js +1 -1
  65. package/node/TreeItem/TreeItem.js +31 -22
  66. package/node/TreeItem/TreeItemContent.js +10 -10
  67. package/node/TreeItem/useTreeItemState.js +13 -13
  68. package/node/TreeItem2/TreeItem2.js +11 -11
  69. package/node/TreeItem2Provider/TreeItem2Provider.js +3 -3
  70. package/node/TreeView/TreeView.js +1 -1
  71. package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +12 -12
  72. package/node/index.js +1 -1
  73. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +7 -7
  74. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +57 -38
  75. package/node/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
  76. package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +17 -17
  77. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +69 -74
  78. package/node/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +19 -20
  79. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +13 -13
  80. package/node/internals/useTreeView/useTreeView.js +3 -4
  81. package/node/internals/useTreeView/useTreeView.utils.js +22 -22
  82. package/node/internals/utils/utils.js +1 -0
  83. package/node/useTreeItem2/useTreeItem2.js +23 -12
  84. package/package.json +5 -5
  85. package/useTreeItem2/useTreeItem2.js +26 -18
  86. package/useTreeItem2/useTreeItem2.types.d.ts +9 -7
@@ -15,8 +15,7 @@ function findNextFirstChar(firstChars, startIndex, char) {
15
15
  }
16
16
  export const useTreeViewKeyboardNavigation = ({
17
17
  instance,
18
- params,
19
- state
18
+ params
20
19
  }) => {
21
20
  const theme = useTheme();
22
21
  const isRTL = theme.direction === 'rtl';
@@ -33,35 +32,32 @@ export const useTreeViewKeyboardNavigation = ({
33
32
  const newFirstCharMap = {};
34
33
  const processItem = item => {
35
34
  const getItemId = params.getItemId;
36
- const nodeId = getItemId ? getItemId(item) : item.id;
37
- newFirstCharMap[nodeId] = instance.getNode(nodeId).label.substring(0, 1).toLowerCase();
35
+ const itemId = getItemId ? getItemId(item) : item.id;
36
+ newFirstCharMap[itemId] = instance.getNode(itemId).label.substring(0, 1).toLowerCase();
38
37
  item.children?.forEach(processItem);
39
38
  };
40
39
  params.items.forEach(processItem);
41
40
  firstCharMap.current = newFirstCharMap;
42
41
  }, [params.items, params.getItemId, instance]);
43
- populateInstance(instance, {
44
- updateFirstCharMap
45
- });
46
- const getFirstMatchingNode = (nodeId, firstChar) => {
42
+ const getFirstMatchingItem = (itemId, firstChar) => {
47
43
  let start;
48
44
  let index;
49
45
  const lowercaseChar = firstChar.toLowerCase();
50
46
  const firstCharIds = [];
51
47
  const firstChars = [];
52
48
  // This really only works since the ids are strings
53
- Object.keys(firstCharMap.current).forEach(mapNodeId => {
54
- const map = instance.getNode(mapNodeId);
49
+ Object.keys(firstCharMap.current).forEach(mapItemId => {
50
+ const map = instance.getNode(mapItemId);
55
51
  const visible = map.parentId ? instance.isNodeExpanded(map.parentId) : true;
56
- const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(mapNodeId);
52
+ const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(mapItemId);
57
53
  if (visible && !shouldBeSkipped) {
58
- firstCharIds.push(mapNodeId);
59
- firstChars.push(firstCharMap.current[mapNodeId]);
54
+ firstCharIds.push(mapItemId);
55
+ firstChars.push(firstCharMap.current[mapItemId]);
60
56
  }
61
57
  });
62
58
 
63
59
  // Get start index for search based on position of currentItem
64
- start = firstCharIds.indexOf(nodeId) + 1;
60
+ start = firstCharIds.indexOf(itemId) + 1;
65
61
  if (start >= firstCharIds.length) {
66
62
  start = 0;
67
63
  }
@@ -80,20 +76,17 @@ export const useTreeViewKeyboardNavigation = ({
80
76
  }
81
77
  return null;
82
78
  };
83
- const canToggleNodeSelection = nodeId => !params.disableSelection && !instance.isNodeDisabled(nodeId);
84
- const canToggleNodeExpansion = nodeId => {
85
- return !instance.isNodeDisabled(nodeId) && instance.isNodeExpandable(nodeId);
79
+ const canToggleItemSelection = itemId => !params.disableSelection && !instance.isNodeDisabled(itemId);
80
+ const canToggleItemExpansion = itemId => {
81
+ return !instance.isNodeDisabled(itemId) && instance.isNodeExpandable(itemId);
86
82
  };
87
83
 
88
84
  // ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
89
- const createHandleKeyDown = otherHandlers => event => {
90
- otherHandlers.onKeyDown?.(event);
85
+ const handleItemKeyDown = (event, itemId) => {
91
86
  if (event.defaultMuiPrevented) {
92
87
  return;
93
88
  }
94
-
95
- // If the tree is empty, there will be no focused node
96
- if (event.altKey || event.currentTarget !== event.target || state.focusedNodeId == null) {
89
+ if (event.altKey || event.currentTarget !== event.target) {
97
90
  return;
98
91
  }
99
92
  const ctrlPressed = event.ctrlKey || event.metaKey;
@@ -102,17 +95,17 @@ export const useTreeViewKeyboardNavigation = ({
102
95
  // eslint-disable-next-line default-case
103
96
  switch (true) {
104
97
  // Select the node when pressing "Space"
105
- case key === ' ' && canToggleNodeSelection(state.focusedNodeId):
98
+ case key === ' ' && canToggleItemSelection(itemId):
106
99
  {
107
100
  event.preventDefault();
108
101
  if (params.multiSelect && event.shiftKey) {
109
102
  instance.selectRange(event, {
110
- end: state.focusedNodeId
103
+ end: itemId
111
104
  });
112
105
  } else if (params.multiSelect) {
113
- instance.selectNode(event, state.focusedNodeId, true);
106
+ instance.selectNode(event, itemId, true);
114
107
  } else {
115
- instance.selectNode(event, state.focusedNodeId);
108
+ instance.selectNode(event, itemId);
116
109
  }
117
110
  break;
118
111
  }
@@ -121,84 +114,87 @@ export const useTreeViewKeyboardNavigation = ({
121
114
  // If the focused node has no children, we select it.
122
115
  case key === 'Enter':
123
116
  {
124
- if (canToggleNodeExpansion(state.focusedNodeId)) {
125
- instance.toggleNodeExpansion(event, state.focusedNodeId);
117
+ if (canToggleItemExpansion(itemId)) {
118
+ instance.toggleNodeExpansion(event, itemId);
126
119
  event.preventDefault();
127
- } else if (canToggleNodeSelection(state.focusedNodeId)) {
120
+ } else if (canToggleItemSelection(itemId)) {
128
121
  if (params.multiSelect) {
129
122
  event.preventDefault();
130
- instance.selectNode(event, state.focusedNodeId, true);
131
- } else if (!instance.isNodeSelected(state.focusedNodeId)) {
132
- instance.selectNode(event, state.focusedNodeId);
123
+ instance.selectNode(event, itemId, true);
124
+ } else if (!instance.isNodeSelected(itemId)) {
125
+ instance.selectNode(event, itemId);
133
126
  event.preventDefault();
134
127
  }
135
128
  }
136
129
  break;
137
130
  }
138
131
 
139
- // Focus the next focusable node
132
+ // Focus the next focusable item
140
133
  case key === 'ArrowDown':
141
134
  {
142
- const nextNode = getNextNode(instance, state.focusedNodeId);
143
- if (nextNode) {
135
+ const nextItem = getNextNode(instance, itemId);
136
+ if (nextItem) {
144
137
  event.preventDefault();
145
- instance.focusItem(event, nextNode);
138
+ instance.focusItem(event, nextItem);
146
139
 
147
140
  // Multi select behavior when pressing Shift + ArrowDown
148
- // Toggles the selection state of the next node
149
- if (params.multiSelect && event.shiftKey && canToggleNodeSelection(nextNode)) {
141
+ // Toggles the selection state of the next item
142
+ if (params.multiSelect && event.shiftKey && canToggleItemSelection(nextItem)) {
150
143
  instance.selectRange(event, {
151
- end: nextNode,
152
- current: state.focusedNodeId
144
+ end: nextItem,
145
+ current: itemId
153
146
  }, true);
154
147
  }
155
148
  }
156
149
  break;
157
150
  }
158
151
 
159
- // Focuses the previous focusable node
152
+ // Focuses the previous focusable item
160
153
  case key === 'ArrowUp':
161
154
  {
162
- const previousNode = getPreviousNode(instance, state.focusedNodeId);
163
- if (previousNode) {
155
+ const previousItem = getPreviousNode(instance, itemId);
156
+ if (previousItem) {
164
157
  event.preventDefault();
165
- instance.focusItem(event, previousNode);
158
+ instance.focusItem(event, previousItem);
166
159
 
167
160
  // Multi select behavior when pressing Shift + ArrowUp
168
- // Toggles the selection state of the previous node
169
- if (params.multiSelect && event.shiftKey && canToggleNodeSelection(previousNode)) {
161
+ // Toggles the selection state of the previous item
162
+ if (params.multiSelect && event.shiftKey && canToggleItemSelection(previousItem)) {
170
163
  instance.selectRange(event, {
171
- end: previousNode,
172
- current: state.focusedNodeId
164
+ end: previousItem,
165
+ current: itemId
173
166
  }, true);
174
167
  }
175
168
  }
176
169
  break;
177
170
  }
178
171
 
179
- // If the focused node is expanded, we move the focus to its first child
180
- // If the focused node is collapsed and has children, we expand it
172
+ // If the focused item is expanded, we move the focus to its first child
173
+ // If the focused item is collapsed and has children, we expand it
181
174
  case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
182
175
  {
183
- if (instance.isNodeExpanded(state.focusedNodeId)) {
184
- instance.focusItem(event, getNextNode(instance, state.focusedNodeId));
185
- event.preventDefault();
186
- } else if (canToggleNodeExpansion(state.focusedNodeId)) {
187
- instance.toggleNodeExpansion(event, state.focusedNodeId);
176
+ if (instance.isNodeExpanded(itemId)) {
177
+ const nextNodeId = getNextNode(instance, itemId);
178
+ if (nextNodeId) {
179
+ instance.focusItem(event, nextNodeId);
180
+ event.preventDefault();
181
+ }
182
+ } else if (canToggleItemExpansion(itemId)) {
183
+ instance.toggleNodeExpansion(event, itemId);
188
184
  event.preventDefault();
189
185
  }
190
186
  break;
191
187
  }
192
188
 
193
- // If the focused node is expanded, we collapse it
194
- // If the focused node is collapsed and has a parent, we move the focus to this parent
189
+ // If the focused item is expanded, we collapse it
190
+ // If the focused item is collapsed and has a parent, we move the focus to this parent
195
191
  case key === 'ArrowLeft' && !isRTL || key === 'ArrowRight' && isRTL:
196
192
  {
197
- if (canToggleNodeExpansion(state.focusedNodeId) && instance.isNodeExpanded(state.focusedNodeId)) {
198
- instance.toggleNodeExpansion(event, state.focusedNodeId);
193
+ if (canToggleItemExpansion(itemId) && instance.isNodeExpanded(itemId)) {
194
+ instance.toggleNodeExpansion(event, itemId);
199
195
  event.preventDefault();
200
196
  } else {
201
- const parent = instance.getNode(state.focusedNodeId).parentId;
197
+ const parent = instance.getNode(itemId).parentId;
202
198
  if (parent) {
203
199
  instance.focusItem(event, parent);
204
200
  event.preventDefault();
@@ -214,31 +210,31 @@ export const useTreeViewKeyboardNavigation = ({
214
210
 
215
211
  // Multi select behavior when pressing Ctrl + Shift + Home
216
212
  // Selects the focused node and all nodes up to the first node.
217
- if (canToggleNodeSelection(state.focusedNodeId) && params.multiSelect && ctrlPressed && event.shiftKey) {
218
- instance.rangeSelectToFirst(event, state.focusedNodeId);
213
+ if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
214
+ instance.rangeSelectToFirst(event, itemId);
219
215
  }
220
216
  event.preventDefault();
221
217
  break;
222
218
  }
223
219
 
224
- // Focuses the last node in the tree
220
+ // Focuses the last item in the tree
225
221
  case key === 'End':
226
222
  {
227
223
  instance.focusItem(event, getLastNode(instance));
228
224
 
229
225
  // Multi select behavior when pressing Ctrl + Shirt + End
230
- // Selects the focused node and all the nodes down to the last node.
231
- if (canToggleNodeSelection(state.focusedNodeId) && params.multiSelect && ctrlPressed && event.shiftKey) {
232
- instance.rangeSelectToLast(event, state.focusedNodeId);
226
+ // Selects the focused item and all the items down to the last item.
227
+ if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
228
+ instance.rangeSelectToLast(event, itemId);
233
229
  }
234
230
  event.preventDefault();
235
231
  break;
236
232
  }
237
233
 
238
- // Expand all siblings that are at the same level as the focused node
234
+ // Expand all siblings that are at the same level as the focused item
239
235
  case key === '*':
240
236
  {
241
- instance.expandAllSiblings(event, state.focusedNodeId);
237
+ instance.expandAllSiblings(event, itemId);
242
238
  event.preventDefault();
243
239
  break;
244
240
  }
@@ -259,7 +255,7 @@ export const useTreeViewKeyboardNavigation = ({
259
255
  // TODO: Support typing multiple characters
260
256
  case !ctrlPressed && !event.shiftKey && isPrintableCharacter(key):
261
257
  {
262
- const matchingNode = getFirstMatchingNode(state.focusedNodeId, key);
258
+ const matchingNode = getFirstMatchingItem(itemId, key);
263
259
  if (matchingNode != null) {
264
260
  instance.focusItem(event, matchingNode);
265
261
  event.preventDefault();
@@ -268,10 +264,9 @@ export const useTreeViewKeyboardNavigation = ({
268
264
  }
269
265
  }
270
266
  };
271
- return {
272
- getRootProps: otherHandlers => ({
273
- onKeyDown: createHandleKeyDown(otherHandlers)
274
- })
275
- };
267
+ populateInstance(instance, {
268
+ updateFirstCharMap,
269
+ handleItemKeyDown
270
+ });
276
271
  };
277
272
  useTreeViewKeyboardNavigation.params = {};
@@ -1,6 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import useEventCallback from '@mui/utils/useEventCallback';
4
3
  import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
5
4
  import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
6
5
  const updateNodesState = ({
@@ -52,34 +51,34 @@ export const useTreeViewNodes = ({
52
51
  state,
53
52
  setState
54
53
  }) => {
55
- const getNode = React.useCallback(nodeId => state.nodes.nodeMap[nodeId], [state.nodes.nodeMap]);
56
- const getItem = React.useCallback(nodeId => state.nodes.itemMap[nodeId], [state.nodes.itemMap]);
57
- const isNodeDisabled = React.useCallback(nodeId => {
58
- if (nodeId == null) {
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 => {
57
+ if (itemId == null) {
59
58
  return false;
60
59
  }
61
- let node = instance.getNode(nodeId);
60
+ let item = instance.getNode(itemId);
62
61
 
63
- // This can be called before the node has been added to the node map.
64
- if (!node) {
62
+ // This can be called before the item has been added to the node map.
63
+ if (!item) {
65
64
  return false;
66
65
  }
67
- if (node.disabled) {
66
+ if (item.disabled) {
68
67
  return true;
69
68
  }
70
- while (node.parentId != null) {
71
- node = instance.getNode(node.parentId);
72
- if (node.disabled) {
69
+ while (item.parentId != null) {
70
+ item = instance.getNode(item.parentId);
71
+ if (item.disabled) {
73
72
  return true;
74
73
  }
75
74
  }
76
75
  return false;
77
76
  }, [instance]);
78
- const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodes.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
79
- const getNavigableChildrenIds = nodeId => {
80
- let childrenIds = instance.getChildrenIds(nodeId);
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]);
78
+ const getNavigableChildrenIds = itemId => {
79
+ let childrenIds = instance.getChildrenIds(itemId);
81
80
  if (!params.disabledItemsFocusable) {
82
- childrenIds = childrenIds.filter(node => !instance.isNodeDisabled(node));
81
+ childrenIds = childrenIds.filter(item => !instance.isNodeDisabled(item));
83
82
  }
84
83
  return childrenIds;
85
84
  };
@@ -104,19 +103,19 @@ export const useTreeViewNodes = ({
104
103
  });
105
104
  }, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
106
105
  const getNodesToRender = () => {
107
- const getPropsFromNodeId = ({
106
+ const getPropsFromItemId = ({
108
107
  id,
109
108
  children
110
109
  }) => {
111
110
  const node = state.nodes.nodeMap[id];
112
111
  return {
113
112
  label: node.label,
114
- nodeId: node.id,
113
+ itemId: node.id,
115
114
  id: node.idAttribute,
116
- children: children?.map(getPropsFromNodeId)
115
+ children: children?.map(getPropsFromItemId)
117
116
  };
118
117
  };
119
- return state.nodes.nodeTree.map(getPropsFromNodeId);
118
+ return state.nodes.nodeTree.map(getPropsFromItemId);
120
119
  };
121
120
  populateInstance(instance, {
122
121
  getNode,
@@ -35,26 +35,26 @@ export const useTreeViewSelection = ({
35
35
  }
36
36
  models.selectedItems.setControlledValue(newSelectedItems);
37
37
  };
38
- const isNodeSelected = nodeId => Array.isArray(models.selectedItems.value) ? models.selectedItems.value.indexOf(nodeId) !== -1 : models.selectedItems.value === nodeId;
39
- const selectNode = (event, nodeId, multiple = false) => {
38
+ const isNodeSelected = itemId => Array.isArray(models.selectedItems.value) ? models.selectedItems.value.indexOf(itemId) !== -1 : models.selectedItems.value === itemId;
39
+ const selectNode = (event, itemId, multiple = false) => {
40
40
  if (params.disableSelection) {
41
41
  return;
42
42
  }
43
43
  if (multiple) {
44
44
  if (Array.isArray(models.selectedItems.value)) {
45
45
  let newSelected;
46
- if (models.selectedItems.value.indexOf(nodeId) !== -1) {
47
- newSelected = models.selectedItems.value.filter(id => id !== nodeId);
46
+ if (models.selectedItems.value.indexOf(itemId) !== -1) {
47
+ newSelected = models.selectedItems.value.filter(id => id !== itemId);
48
48
  } else {
49
- newSelected = [nodeId].concat(models.selectedItems.value);
49
+ newSelected = [itemId].concat(models.selectedItems.value);
50
50
  }
51
51
  setSelectedItems(event, newSelected);
52
52
  }
53
53
  } else {
54
- const newSelected = params.multiSelect ? [nodeId] : nodeId;
54
+ const newSelected = params.multiSelect ? [itemId] : itemId;
55
55
  setSelectedItems(event, newSelected);
56
56
  }
57
- lastSelectedNode.current = nodeId;
57
+ lastSelectedNode.current = itemId;
58
58
  lastSelectionWasRange.current = false;
59
59
  currentRangeSelection.current = [];
60
60
  };
@@ -135,21 +135,21 @@ export const useTreeViewSelection = ({
135
135
  }
136
136
  lastSelectionWasRange.current = true;
137
137
  };
138
- const rangeSelectToFirst = (event, nodeId) => {
138
+ const rangeSelectToFirst = (event, itemId) => {
139
139
  if (!lastSelectedNode.current) {
140
- lastSelectedNode.current = nodeId;
140
+ lastSelectedNode.current = itemId;
141
141
  }
142
- const start = lastSelectionWasRange.current ? lastSelectedNode.current : nodeId;
142
+ const start = lastSelectionWasRange.current ? lastSelectedNode.current : itemId;
143
143
  instance.selectRange(event, {
144
144
  start,
145
145
  end: getFirstNode(instance)
146
146
  });
147
147
  };
148
- const rangeSelectToLast = (event, nodeId) => {
148
+ const rangeSelectToLast = (event, itemId) => {
149
149
  if (!lastSelectedNode.current) {
150
- lastSelectedNode.current = nodeId;
150
+ lastSelectedNode.current = itemId;
151
151
  }
152
- const start = lastSelectionWasRange.current ? lastSelectedNode.current : nodeId;
152
+ const start = lastSelectionWasRange.current ? lastSelectedNode.current : itemId;
153
153
  instance.selectRange(event, {
154
154
  start,
155
155
  end: getLastNode(instance)
@@ -87,13 +87,13 @@ export const useTreeView = inParams => {
87
87
  };
88
88
  const itemWrappers = plugins.map(plugin => plugin.wrapItem).filter(wrapItem => !!wrapItem);
89
89
  contextValue.wrapItem = ({
90
- nodeId,
90
+ itemId,
91
91
  children
92
92
  }) => {
93
93
  let finalChildren = children;
94
94
  itemWrappers.forEach(itemWrapper => {
95
95
  finalChildren = itemWrapper({
96
- nodeId,
96
+ itemId,
97
97
  children: finalChildren
98
98
  });
99
99
  });
@@ -101,8 +101,7 @@ export const useTreeView = inParams => {
101
101
  };
102
102
  const getRootProps = (otherHandlers = {}) => {
103
103
  const rootProps = _extends({
104
- role: 'tree',
105
- tabIndex: 0
104
+ role: 'tree'
106
105
  }, otherHandlers, {
107
106
  ref: handleRootRef
108
107
  });
@@ -1,41 +1,41 @@
1
- export const getPreviousNode = (instance, nodeId) => {
2
- const node = instance.getNode(nodeId);
3
- const siblings = instance.getNavigableChildrenIds(node.parentId);
4
- const nodeIndex = siblings.indexOf(nodeId);
5
- if (nodeIndex === 0) {
6
- return node.parentId;
1
+ export const getPreviousNode = (instance, itemId) => {
2
+ const item = instance.getNode(itemId);
3
+ const siblings = instance.getNavigableChildrenIds(item.parentId);
4
+ const itemIndex = siblings.indexOf(itemId);
5
+ if (itemIndex === 0) {
6
+ return item.parentId;
7
7
  }
8
- let currentNode = siblings[nodeIndex - 1];
9
- while (instance.isNodeExpanded(currentNode) && instance.getNavigableChildrenIds(currentNode).length > 0) {
10
- currentNode = instance.getNavigableChildrenIds(currentNode).pop();
8
+ let currentItem = siblings[itemIndex - 1];
9
+ while (instance.isNodeExpanded(currentItem) && instance.getNavigableChildrenIds(currentItem).length > 0) {
10
+ currentItem = instance.getNavigableChildrenIds(currentItem).pop();
11
11
  }
12
- return currentNode;
12
+ return currentItem;
13
13
  };
14
- export const getNextNode = (instance, nodeId) => {
14
+ export const getNextNode = (instance, itemId) => {
15
15
  // If expanded get first child
16
- if (instance.isNodeExpanded(nodeId) && instance.getNavigableChildrenIds(nodeId).length > 0) {
17
- return instance.getNavigableChildrenIds(nodeId)[0];
16
+ if (instance.isNodeExpanded(itemId) && instance.getNavigableChildrenIds(itemId).length > 0) {
17
+ return instance.getNavigableChildrenIds(itemId)[0];
18
18
  }
19
- let node = instance.getNode(nodeId);
20
- while (node != null) {
19
+ let item = instance.getNode(itemId);
20
+ while (item != null) {
21
21
  // Try to get next sibling
22
- const siblings = instance.getNavigableChildrenIds(node.parentId);
23
- const nextSibling = siblings[siblings.indexOf(node.id) + 1];
22
+ const siblings = instance.getNavigableChildrenIds(item.parentId);
23
+ const nextSibling = siblings[siblings.indexOf(item.id) + 1];
24
24
  if (nextSibling) {
25
25
  return nextSibling;
26
26
  }
27
27
 
28
28
  // If the sibling does not exist, go up a level to the parent and try again.
29
- node = instance.getNode(node.parentId);
29
+ item = instance.getNode(item.parentId);
30
30
  }
31
31
  return null;
32
32
  };
33
33
  export const getLastNode = instance => {
34
- let lastNode = instance.getNavigableChildrenIds(null).pop();
35
- while (instance.isNodeExpanded(lastNode)) {
36
- lastNode = instance.getNavigableChildrenIds(lastNode).pop();
34
+ let lastItem = instance.getNavigableChildrenIds(null).pop();
35
+ while (instance.isNodeExpanded(lastItem)) {
36
+ lastItem = instance.getNavigableChildrenIds(lastItem).pop();
37
37
  }
38
- return lastNode;
38
+ return lastItem;
39
39
  };
40
40
  export const getFirstNode = instance => instance.getNavigableChildrenIds(null)[0];
41
41
  export const populateInstance = (instance, methods) => {
@@ -1,3 +1,4 @@
1
+ // https://www.abeautifulsite.net/posts/finding-the-active-element-in-a-shadow-root/
1
2
  export const getActiveElement = (root = document) => {
2
3
  const activeEl = root.activeElement;
3
4
  if (!activeEl) {
@@ -15,7 +15,7 @@ export const useTreeItem2 = parameters => {
15
15
  } = useTreeViewContext();
16
16
  const {
17
17
  id,
18
- nodeId,
18
+ itemId,
19
19
  label,
20
20
  children,
21
21
  rootRef
@@ -28,25 +28,34 @@ export const useTreeItem2 = parameters => {
28
28
  interactions,
29
29
  status
30
30
  } = useTreeItem2Utils({
31
- nodeId,
31
+ itemId,
32
32
  children
33
33
  });
34
- const idAttribute = instance.getTreeItemId(nodeId, id);
34
+ const idAttribute = instance.getTreeItemId(itemId, id);
35
35
  const handleRootRef = useForkRef(rootRef, pluginRootRef);
36
36
  const createRootHandleFocus = otherHandlers => event => {
37
37
  otherHandlers.onFocus?.(event);
38
38
  if (event.defaultMuiPrevented) {
39
39
  return;
40
40
  }
41
-
42
- // DOM focus stays on the tree which manages focus with aria-activedescendant
43
- if (event.target === event.currentTarget) {
44
- instance.focusRoot();
45
- }
46
41
  const canBeFocused = !status.disabled || disabledItemsFocusable;
47
42
  if (!status.focused && canBeFocused && event.currentTarget === event.target) {
48
- instance.focusItem(event, nodeId);
43
+ instance.focusItem(event, itemId);
44
+ }
45
+ };
46
+ const createRootHandleBlur = otherHandlers => event => {
47
+ otherHandlers.onBlur?.(event);
48
+ if (event.defaultMuiPrevented) {
49
+ return;
50
+ }
51
+ instance.removeFocusedItem();
52
+ };
53
+ const createRootHandleKeyDown = otherHandlers => event => {
54
+ otherHandlers.onKeyDown?.(event);
55
+ if (event.defaultMuiPrevented) {
56
+ return;
49
57
  }
58
+ instance.handleItemKeyDown(event, itemId);
50
59
  };
51
60
  const createContentHandleClick = otherHandlers => event => {
52
61
  otherHandlers.onClick?.(event);
@@ -76,7 +85,7 @@ export const useTreeItem2 = parameters => {
76
85
  /* single-selection trees unset aria-selected on un-selected items.
77
86
  *
78
87
  * If the tree does not support multiple selection, aria-selected
79
- * is set to true for the selected node and it is not present on any other node in the tree.
88
+ * is set to true for the selected item and it is not present on any other item in the tree.
80
89
  * Source: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
81
90
  */
82
91
  ariaSelected = true;
@@ -84,13 +93,15 @@ export const useTreeItem2 = parameters => {
84
93
  return _extends({}, externalEventHandlers, {
85
94
  ref: handleRootRef,
86
95
  role: 'treeitem',
87
- tabIndex: -1,
96
+ tabIndex: instance.canItemBeTabbed(itemId) ? 0 : -1,
88
97
  id: idAttribute,
89
98
  'aria-expanded': status.expandable ? status.expanded : undefined,
90
99
  'aria-selected': ariaSelected,
91
100
  'aria-disabled': status.disabled || undefined
92
101
  }, externalProps, {
93
- onFocus: createRootHandleFocus(externalEventHandlers)
102
+ onFocus: createRootHandleFocus(externalEventHandlers),
103
+ onBlur: createRootHandleBlur(externalEventHandlers),
104
+ onKeyDown: createRootHandleKeyDown(externalEventHandlers)
94
105
  });
95
106
  };
96
107
  const getContentProps = (externalProps = {}) => {
@@ -45,7 +45,7 @@ function WrappedTreeItem({
45
45
  slotProps,
46
46
  label,
47
47
  id,
48
- nodeId,
48
+ itemId,
49
49
  children
50
50
  }) {
51
51
  const Item = slots?.item ?? _TreeItem.TreeItem;
@@ -53,12 +53,12 @@ function WrappedTreeItem({
53
53
  elementType: Item,
54
54
  externalSlotProps: slotProps?.item,
55
55
  additionalProps: {
56
- nodeId,
56
+ itemId,
57
57
  id,
58
58
  label
59
59
  },
60
60
  ownerState: {
61
- nodeId,
61
+ itemId,
62
62
  label
63
63
  }
64
64
  });
@@ -66,7 +66,7 @@ function WrappedTreeItem({
66
66
  children: children
67
67
  }));
68
68
  }
69
- const childrenWarning = (0, _warning.buildWarning)(['MUI X: The `RichTreeView` component does not support JSX children.', 'If you want to add items, you need to use the `items` prop', 'Check the documentation for more details: https://next.mui.com/x/react-tree-view/rich-tree-view/items/']);
69
+ const childrenWarning = (0, _warning.buildWarning)(['MUI X: The `RichTreeView` component does not support JSX children.', 'If you want to add items, you need to use the `items` prop', 'Check the documentation for more details: https://mui.com/x/react-tree-view/rich-tree-view/items/']);
70
70
 
71
71
  /**
72
72
  *
@@ -116,7 +116,7 @@ const RichTreeView = exports.RichTreeView = /*#__PURE__*/React.forwardRef(functi
116
116
  const nodesToRender = instance.getNodesToRender();
117
117
  const renderNode = ({
118
118
  label,
119
- nodeId,
119
+ itemId,
120
120
  id,
121
121
  children
122
122
  }) => {
@@ -125,9 +125,9 @@ const RichTreeView = exports.RichTreeView = /*#__PURE__*/React.forwardRef(functi
125
125
  slotProps: slotProps,
126
126
  label: label,
127
127
  id: id,
128
- nodeId: nodeId,
128
+ itemId: itemId,
129
129
  children: children?.map(renderNode)
130
- }, nodeId);
130
+ }, itemId);
131
131
  };
132
132
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeViewProvider.TreeViewProvider, {
133
133
  value: contextValue,