@mui/x-tree-view 7.0.0-beta.7 → 7.1.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 (136) hide show
  1. package/CHANGELOG.md +266 -12
  2. package/README.md +1 -1
  3. package/RichTreeView/RichTreeView.js +15 -17
  4. package/RichTreeView/RichTreeView.types.d.ts +1 -1
  5. package/SimpleTreeView/SimpleTreeView.js +3 -4
  6. package/SimpleTreeView/SimpleTreeView.plugins.d.ts +1 -1
  7. package/SimpleTreeView/SimpleTreeView.plugins.js +2 -2
  8. package/TreeItem/TreeItem.js +43 -35
  9. package/TreeItem/TreeItem.types.d.ts +3 -3
  10. package/TreeItem/TreeItemContent.d.ts +7 -7
  11. package/TreeItem/TreeItemContent.js +10 -10
  12. package/TreeItem/treeItemClasses.d.ts +1 -1
  13. package/TreeItem/useTreeItemState.d.ts +1 -1
  14. package/TreeItem/useTreeItemState.js +13 -13
  15. package/TreeItem2/TreeItem2.js +16 -17
  16. package/TreeItem2Icon/TreeItem2Icon.js +5 -6
  17. package/TreeItem2Icon/TreeItem2Icon.types.d.ts +4 -4
  18. package/TreeItem2Provider/TreeItem2Provider.js +3 -3
  19. package/TreeItem2Provider/TreeItem2Provider.types.d.ts +1 -1
  20. package/TreeView/TreeView.d.ts +1 -1
  21. package/TreeView/TreeView.js +1 -1
  22. package/hooks/useTreeItem2Utils/useTreeItem2Utils.d.ts +2 -2
  23. package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +12 -12
  24. package/hooks/useTreeViewApiRef.d.ts +1 -1
  25. package/index.js +1 -1
  26. package/internals/TreeViewProvider/DescendantProvider.d.ts +1 -1
  27. package/internals/TreeViewProvider/DescendantProvider.js +1 -1
  28. package/internals/hooks/useInstanceEventHandler.js +5 -10
  29. package/internals/index.d.ts +2 -2
  30. package/internals/models/plugin.d.ts +1 -1
  31. package/internals/plugins/defaultPlugins.d.ts +3 -3
  32. package/internals/plugins/defaultPlugins.js +2 -2
  33. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +17 -24
  34. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +6 -6
  35. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +76 -58
  36. package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +9 -8
  37. package/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.d.ts +6 -6
  38. package/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
  39. package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +2 -2
  40. package/internals/plugins/useTreeViewItems/index.d.ts +2 -0
  41. package/internals/plugins/useTreeViewItems/index.js +1 -0
  42. package/internals/plugins/useTreeViewItems/useTreeViewItems.d.ts +3 -0
  43. package/{modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js → internals/plugins/useTreeViewItems/useTreeViewItems.js} +42 -33
  44. package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +99 -0
  45. package/internals/plugins/useTreeViewJSXItems/index.d.ts +2 -0
  46. package/internals/plugins/useTreeViewJSXItems/index.js +1 -0
  47. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.d.ts +3 -0
  48. package/{modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js → internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js} +41 -40
  49. package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.d.ts +18 -0
  50. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +85 -96
  51. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +6 -3
  52. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +44 -47
  53. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +8 -8
  54. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.d.ts +7 -7
  55. package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +5 -5
  56. package/internals/useTreeView/useTreeView.js +5 -6
  57. package/internals/useTreeView/useTreeView.utils.d.ts +5 -5
  58. package/internals/useTreeView/useTreeView.utils.js +18 -18
  59. package/internals/utils/extractPluginParamsFromProps.js +2 -2
  60. package/internals/utils/utils.js +1 -0
  61. package/modern/RichTreeView/RichTreeView.js +11 -11
  62. package/modern/SimpleTreeView/SimpleTreeView.js +1 -1
  63. package/modern/SimpleTreeView/SimpleTreeView.plugins.js +2 -2
  64. package/modern/TreeItem/TreeItem.js +31 -22
  65. package/modern/TreeItem/TreeItemContent.js +10 -10
  66. package/modern/TreeItem/useTreeItemState.js +13 -13
  67. package/modern/TreeItem2/TreeItem2.js +11 -11
  68. package/modern/TreeItem2Provider/TreeItem2Provider.js +3 -3
  69. package/modern/TreeView/TreeView.js +1 -1
  70. package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +12 -12
  71. package/modern/index.js +1 -1
  72. package/modern/internals/TreeViewProvider/DescendantProvider.js +1 -1
  73. package/modern/internals/plugins/defaultPlugins.js +2 -2
  74. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +14 -14
  75. package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +74 -53
  76. package/modern/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
  77. package/modern/internals/plugins/useTreeViewItems/index.js +1 -0
  78. package/{internals/plugins/useTreeViewNodes/useTreeViewNodes.js → modern/internals/plugins/useTreeViewItems/useTreeViewItems.js} +46 -41
  79. package/modern/internals/plugins/useTreeViewJSXItems/index.js +1 -0
  80. package/{internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js → modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js} +41 -41
  81. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +85 -94
  82. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +40 -40
  83. package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +5 -5
  84. package/modern/internals/useTreeView/useTreeView.js +3 -4
  85. package/modern/internals/useTreeView/useTreeView.utils.js +18 -18
  86. package/modern/internals/utils/utils.js +1 -0
  87. package/modern/useTreeItem2/useTreeItem2.js +23 -12
  88. package/node/RichTreeView/RichTreeView.js +11 -11
  89. package/node/SimpleTreeView/SimpleTreeView.js +1 -1
  90. package/node/SimpleTreeView/SimpleTreeView.plugins.js +2 -2
  91. package/node/TreeItem/TreeItem.js +31 -22
  92. package/node/TreeItem/TreeItemContent.js +10 -10
  93. package/node/TreeItem/useTreeItemState.js +13 -13
  94. package/node/TreeItem2/TreeItem2.js +11 -11
  95. package/node/TreeItem2Provider/TreeItem2Provider.js +3 -3
  96. package/node/TreeView/TreeView.js +1 -1
  97. package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +12 -12
  98. package/node/index.js +1 -1
  99. package/node/internals/TreeViewProvider/DescendantProvider.js +1 -1
  100. package/node/internals/plugins/defaultPlugins.js +2 -2
  101. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +14 -14
  102. package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +74 -53
  103. package/node/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
  104. package/node/internals/plugins/useTreeViewItems/index.js +12 -0
  105. package/node/internals/plugins/{useTreeViewNodes/useTreeViewNodes.js → useTreeViewItems/useTreeViewItems.js} +44 -35
  106. package/node/internals/plugins/useTreeViewJSXItems/index.js +12 -0
  107. package/node/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.js → useTreeViewJSXItems/useTreeViewJSXItems.js} +43 -42
  108. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +84 -93
  109. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +39 -39
  110. package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +5 -5
  111. package/node/internals/useTreeView/useTreeView.js +3 -4
  112. package/node/internals/useTreeView/useTreeView.utils.js +23 -23
  113. package/node/internals/utils/utils.js +1 -0
  114. package/node/useTreeItem2/useTreeItem2.js +23 -12
  115. package/package.json +5 -5
  116. package/useTreeItem2/useTreeItem2.d.ts +1 -1
  117. package/useTreeItem2/useTreeItem2.js +26 -18
  118. package/useTreeItem2/useTreeItem2.types.d.ts +9 -7
  119. package/internals/plugins/useTreeViewJSXNodes/index.d.ts +0 -2
  120. package/internals/plugins/useTreeViewJSXNodes/index.js +0 -1
  121. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.d.ts +0 -3
  122. package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.d.ts +0 -18
  123. package/internals/plugins/useTreeViewNodes/index.d.ts +0 -2
  124. package/internals/plugins/useTreeViewNodes/index.js +0 -1
  125. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.d.ts +0 -3
  126. package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +0 -88
  127. package/modern/internals/plugins/useTreeViewJSXNodes/index.js +0 -1
  128. package/modern/internals/plugins/useTreeViewNodes/index.js +0 -1
  129. package/node/internals/plugins/useTreeViewJSXNodes/index.js +0 -12
  130. package/node/internals/plugins/useTreeViewNodes/index.js +0 -12
  131. /package/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.types.js → useTreeViewItems/useTreeViewItems.types.js} +0 -0
  132. /package/internals/plugins/{useTreeViewNodes/useTreeViewNodes.types.js → useTreeViewJSXItems/useTreeViewJSXItems.types.js} +0 -0
  133. /package/modern/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.types.js → useTreeViewItems/useTreeViewItems.types.js} +0 -0
  134. /package/modern/internals/plugins/{useTreeViewNodes/useTreeViewNodes.types.js → useTreeViewJSXItems/useTreeViewJSXItems.types.js} +0 -0
  135. /package/node/internals/plugins/{useTreeViewJSXNodes/useTreeViewJSXNodes.types.js → useTreeViewItems/useTreeViewItems.types.js} +0 -0
  136. /package/node/internals/plugins/{useTreeViewNodes/useTreeViewNodes.types.js → useTreeViewJSXItems/useTreeViewJSXItems.types.js} +0 -0
@@ -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
  }
@@ -21,47 +21,39 @@ export const useTreeViewKeyboardNavigation = ({
21
21
  const theme = useTheme();
22
22
  const isRTL = theme.direction === 'rtl';
23
23
  const firstCharMap = React.useRef({});
24
- const hasFirstCharMapBeenUpdatedImperatively = React.useRef(false);
25
24
  const updateFirstCharMap = useEventCallback(callback => {
26
- hasFirstCharMapBeenUpdatedImperatively.current = true;
27
25
  firstCharMap.current = callback(firstCharMap.current);
28
26
  });
29
27
  React.useEffect(() => {
30
- if (hasFirstCharMapBeenUpdatedImperatively.current) {
28
+ if (instance.areItemUpdatesPrevented()) {
31
29
  return;
32
30
  }
33
31
  const newFirstCharMap = {};
34
- const processItem = item => {
35
- const getItemId = params.getItemId;
36
- const nodeId = getItemId ? getItemId(item) : item.id;
37
- newFirstCharMap[nodeId] = instance.getNode(nodeId).label.substring(0, 1).toLowerCase();
38
- item.children?.forEach(processItem);
32
+ const processItem = node => {
33
+ newFirstCharMap[node.id] = node.label.substring(0, 1).toLowerCase();
39
34
  };
40
- params.items.forEach(processItem);
35
+ Object.values(state.items.nodeMap).forEach(processItem);
41
36
  firstCharMap.current = newFirstCharMap;
42
- }, [params.items, params.getItemId, instance]);
43
- populateInstance(instance, {
44
- updateFirstCharMap
45
- });
46
- const getFirstMatchingNode = (nodeId, firstChar) => {
37
+ }, [state.items.nodeMap, params.getItemId, instance]);
38
+ const getFirstMatchingItem = (itemId, firstChar) => {
47
39
  let start;
48
40
  let index;
49
41
  const lowercaseChar = firstChar.toLowerCase();
50
42
  const firstCharIds = [];
51
43
  const firstChars = [];
52
44
  // This really only works since the ids are strings
53
- Object.keys(firstCharMap.current).forEach(mapNodeId => {
54
- const map = instance.getNode(mapNodeId);
55
- const visible = map.parentId ? instance.isNodeExpanded(map.parentId) : true;
56
- const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(mapNodeId);
45
+ Object.keys(firstCharMap.current).forEach(mapItemId => {
46
+ const map = instance.getNode(mapItemId);
47
+ const visible = map.parentId ? instance.isItemExpanded(map.parentId) : true;
48
+ const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isItemDisabled(mapItemId);
57
49
  if (visible && !shouldBeSkipped) {
58
- firstCharIds.push(mapNodeId);
59
- firstChars.push(firstCharMap.current[mapNodeId]);
50
+ firstCharIds.push(mapItemId);
51
+ firstChars.push(firstCharMap.current[mapItemId]);
60
52
  }
61
53
  });
62
54
 
63
55
  // Get start index for search based on position of currentItem
64
- start = firstCharIds.indexOf(nodeId) + 1;
56
+ start = firstCharIds.indexOf(itemId) + 1;
65
57
  if (start >= firstCharIds.length) {
66
58
  start = 0;
67
59
  }
@@ -80,20 +72,17 @@ export const useTreeViewKeyboardNavigation = ({
80
72
  }
81
73
  return null;
82
74
  };
83
- const canToggleNodeSelection = nodeId => !params.disableSelection && !instance.isNodeDisabled(nodeId);
84
- const canToggleNodeExpansion = nodeId => {
85
- return !instance.isNodeDisabled(nodeId) && instance.isNodeExpandable(nodeId);
75
+ const canToggleItemSelection = itemId => !params.disableSelection && !instance.isItemDisabled(itemId);
76
+ const canToggleItemExpansion = itemId => {
77
+ return !instance.isItemDisabled(itemId) && instance.isItemExpandable(itemId);
86
78
  };
87
79
 
88
80
  // ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
89
- const createHandleKeyDown = otherHandlers => event => {
90
- otherHandlers.onKeyDown?.(event);
81
+ const handleItemKeyDown = (event, itemId) => {
91
82
  if (event.defaultMuiPrevented) {
92
83
  return;
93
84
  }
94
-
95
- // If the tree is empty, there will be no focused node
96
- if (event.altKey || event.currentTarget !== event.target || state.focusedNodeId == null) {
85
+ if (event.altKey || event.currentTarget !== event.target) {
97
86
  return;
98
87
  }
99
88
  const ctrlPressed = event.ctrlKey || event.metaKey;
@@ -101,104 +90,107 @@ export const useTreeViewKeyboardNavigation = ({
101
90
 
102
91
  // eslint-disable-next-line default-case
103
92
  switch (true) {
104
- // Select the node when pressing "Space"
105
- case key === ' ' && canToggleNodeSelection(state.focusedNodeId):
93
+ // Select the item when pressing "Space"
94
+ case key === ' ' && canToggleItemSelection(itemId):
106
95
  {
107
96
  event.preventDefault();
108
97
  if (params.multiSelect && event.shiftKey) {
109
98
  instance.selectRange(event, {
110
- end: state.focusedNodeId
99
+ end: itemId
111
100
  });
112
101
  } else if (params.multiSelect) {
113
- instance.selectNode(event, state.focusedNodeId, true);
102
+ instance.selectItem(event, itemId, true);
114
103
  } else {
115
- instance.selectNode(event, state.focusedNodeId);
104
+ instance.selectItem(event, itemId);
116
105
  }
117
106
  break;
118
107
  }
119
108
 
120
- // If the focused node has children, we expand it.
121
- // 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.
122
111
  case key === 'Enter':
123
112
  {
124
- if (canToggleNodeExpansion(state.focusedNodeId)) {
125
- instance.toggleNodeExpansion(event, state.focusedNodeId);
113
+ if (canToggleItemExpansion(itemId)) {
114
+ instance.toggleItemExpansion(event, itemId);
126
115
  event.preventDefault();
127
- } else if (canToggleNodeSelection(state.focusedNodeId)) {
116
+ } else if (canToggleItemSelection(itemId)) {
128
117
  if (params.multiSelect) {
129
118
  event.preventDefault();
130
- instance.selectNode(event, state.focusedNodeId, true);
131
- } else if (!instance.isNodeSelected(state.focusedNodeId)) {
132
- instance.selectNode(event, state.focusedNodeId);
119
+ instance.selectItem(event, itemId, true);
120
+ } else if (!instance.isItemSelected(itemId)) {
121
+ instance.selectItem(event, itemId);
133
122
  event.preventDefault();
134
123
  }
135
124
  }
136
125
  break;
137
126
  }
138
127
 
139
- // Focus the next focusable node
128
+ // Focus the next focusable item
140
129
  case key === 'ArrowDown':
141
130
  {
142
- const nextNode = getNextNode(instance, state.focusedNodeId);
143
- if (nextNode) {
131
+ const nextItem = getNextItem(instance, itemId);
132
+ if (nextItem) {
144
133
  event.preventDefault();
145
- instance.focusItem(event, nextNode);
134
+ instance.focusItem(event, nextItem);
146
135
 
147
136
  // Multi select behavior when pressing Shift + ArrowDown
148
- // Toggles the selection state of the next node
149
- if (params.multiSelect && event.shiftKey && canToggleNodeSelection(nextNode)) {
137
+ // Toggles the selection state of the next item
138
+ if (params.multiSelect && event.shiftKey && canToggleItemSelection(nextItem)) {
150
139
  instance.selectRange(event, {
151
- end: nextNode,
152
- current: state.focusedNodeId
140
+ end: nextItem,
141
+ current: itemId
153
142
  }, true);
154
143
  }
155
144
  }
156
145
  break;
157
146
  }
158
147
 
159
- // Focuses the previous focusable node
148
+ // Focuses the previous focusable item
160
149
  case key === 'ArrowUp':
161
150
  {
162
- const previousNode = getPreviousNode(instance, state.focusedNodeId);
163
- if (previousNode) {
151
+ const previousItem = getPreviousItem(instance, itemId);
152
+ if (previousItem) {
164
153
  event.preventDefault();
165
- instance.focusItem(event, previousNode);
154
+ instance.focusItem(event, previousItem);
166
155
 
167
156
  // Multi select behavior when pressing Shift + ArrowUp
168
- // Toggles the selection state of the previous node
169
- if (params.multiSelect && event.shiftKey && canToggleNodeSelection(previousNode)) {
157
+ // Toggles the selection state of the previous item
158
+ if (params.multiSelect && event.shiftKey && canToggleItemSelection(previousItem)) {
170
159
  instance.selectRange(event, {
171
- end: previousNode,
172
- current: state.focusedNodeId
160
+ end: previousItem,
161
+ current: itemId
173
162
  }, true);
174
163
  }
175
164
  }
176
165
  break;
177
166
  }
178
167
 
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
168
+ // If the focused item is expanded, we move the focus to its first child
169
+ // If the focused item is collapsed and has children, we expand it
181
170
  case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
182
171
  {
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);
172
+ if (instance.isItemExpanded(itemId)) {
173
+ const nextItemId = getNextItem(instance, itemId);
174
+ if (nextItemId) {
175
+ instance.focusItem(event, nextItemId);
176
+ event.preventDefault();
177
+ }
178
+ } else if (canToggleItemExpansion(itemId)) {
179
+ instance.toggleItemExpansion(event, itemId);
188
180
  event.preventDefault();
189
181
  }
190
182
  break;
191
183
  }
192
184
 
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
185
+ // If the focused item is expanded, we collapse it
186
+ // If the focused item is collapsed and has a parent, we move the focus to this parent
195
187
  case key === 'ArrowLeft' && !isRTL || key === 'ArrowRight' && isRTL:
196
188
  {
197
- if (canToggleNodeExpansion(state.focusedNodeId) && instance.isNodeExpanded(state.focusedNodeId)) {
198
- instance.toggleNodeExpansion(event, state.focusedNodeId);
189
+ if (canToggleItemExpansion(itemId) && instance.isItemExpanded(itemId)) {
190
+ instance.toggleItemExpansion(event, itemId);
199
191
  event.preventDefault();
200
192
  } else {
201
- const parent = instance.getNode(state.focusedNodeId).parentId;
193
+ const parent = instance.getNode(itemId).parentId;
202
194
  if (parent) {
203
195
  instance.focusItem(event, parent);
204
196
  event.preventDefault();
@@ -207,49 +199,49 @@ export const useTreeViewKeyboardNavigation = ({
207
199
  break;
208
200
  }
209
201
 
210
- // Focuses the first node in the tree
202
+ // Focuses the first item in the tree
211
203
  case key === 'Home':
212
204
  {
213
- instance.focusItem(event, getFirstNode(instance));
205
+ instance.focusItem(event, getFirstItem(instance));
214
206
 
215
207
  // Multi select behavior when pressing Ctrl + Shift + Home
216
- // 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);
208
+ // Selects the focused item and all items up to the first item.
209
+ if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
210
+ instance.rangeSelectToFirst(event, itemId);
219
211
  }
220
212
  event.preventDefault();
221
213
  break;
222
214
  }
223
215
 
224
- // Focuses the last node in the tree
216
+ // Focuses the last item in the tree
225
217
  case key === 'End':
226
218
  {
227
- instance.focusItem(event, getLastNode(instance));
219
+ instance.focusItem(event, getLastItem(instance));
228
220
 
229
221
  // 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);
222
+ // Selects the focused item and all the items down to the last item.
223
+ if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
224
+ instance.rangeSelectToLast(event, itemId);
233
225
  }
234
226
  event.preventDefault();
235
227
  break;
236
228
  }
237
229
 
238
- // Expand all siblings that are at the same level as the focused node
230
+ // Expand all siblings that are at the same level as the focused item
239
231
  case key === '*':
240
232
  {
241
- instance.expandAllSiblings(event, state.focusedNodeId);
233
+ instance.expandAllSiblings(event, itemId);
242
234
  event.preventDefault();
243
235
  break;
244
236
  }
245
237
 
246
238
  // Multi select behavior when pressing Ctrl + a
247
- // Selects all the nodes
239
+ // Selects all the items
248
240
  case key === 'a' && ctrlPressed && params.multiSelect && !params.disableSelection:
249
241
  {
250
242
  instance.selectRange(event, {
251
- start: getFirstNode(instance),
252
- end: getLastNode(instance)
243
+ start: getFirstItem(instance),
244
+ end: getLastItem(instance)
253
245
  });
254
246
  event.preventDefault();
255
247
  break;
@@ -259,19 +251,18 @@ export const useTreeViewKeyboardNavigation = ({
259
251
  // TODO: Support typing multiple characters
260
252
  case !ctrlPressed && !event.shiftKey && isPrintableCharacter(key):
261
253
  {
262
- const matchingNode = getFirstMatchingNode(state.focusedNodeId, key);
263
- if (matchingNode != null) {
264
- instance.focusItem(event, matchingNode);
254
+ const matchingItem = getFirstMatchingItem(itemId, key);
255
+ if (matchingItem != null) {
256
+ instance.focusItem(event, matchingItem);
265
257
  event.preventDefault();
266
258
  }
267
259
  break;
268
260
  }
269
261
  }
270
262
  };
271
- return {
272
- getRootProps: otherHandlers => ({
273
- onKeyDown: createHandleKeyDown(otherHandlers)
274
- })
275
- };
263
+ populateInstance(instance, {
264
+ updateFirstCharMap,
265
+ handleItemKeyDown
266
+ });
276
267
  };
277
268
  useTreeViewKeyboardNavigation.params = {};
@@ -1,19 +1,19 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import { populateInstance, getNextNode, getFirstNode, getLastNode } from '../../useTreeView/useTreeView.utils';
3
+ import { populateInstance, getNextItem, getFirstItem, getLastItem } from '../../useTreeView/useTreeView.utils';
4
4
  import { findOrderInTremauxTree } from './useTreeViewSelection.utils';
5
5
  export const useTreeViewSelection = ({
6
6
  instance,
7
7
  params,
8
8
  models
9
9
  }) => {
10
- const lastSelectedNode = React.useRef(null);
10
+ const lastSelectedItem = React.useRef(null);
11
11
  const lastSelectionWasRange = React.useRef(false);
12
12
  const currentRangeSelection = React.useRef([]);
13
13
  const setSelectedItems = (event, newSelectedItems) => {
14
14
  if (params.onItemSelectionToggle) {
15
15
  if (params.multiSelect) {
16
- const addedItems = newSelectedItems.filter(itemId => !instance.isNodeSelected(itemId));
16
+ const addedItems = newSelectedItems.filter(itemId => !instance.isItemSelected(itemId));
17
17
  const removedItems = models.selectedItems.value.filter(itemId => !newSelectedItems.includes(itemId));
18
18
  addedItems.forEach(itemId => {
19
19
  params.onItemSelectionToggle(event, itemId, true);
@@ -35,46 +35,46 @@ 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 isItemSelected = itemId => Array.isArray(models.selectedItems.value) ? models.selectedItems.value.indexOf(itemId) !== -1 : models.selectedItems.value === itemId;
39
+ const selectItem = (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
+ lastSelectedItem.current = itemId;
58
58
  lastSelectionWasRange.current = false;
59
59
  currentRangeSelection.current = [];
60
60
  };
61
- const getNodesInRange = (nodeAId, nodeBId) => {
62
- const [first, last] = findOrderInTremauxTree(instance, nodeAId, nodeBId);
63
- const nodes = [first];
61
+ const getItemsInRange = (itemAId, itemBId) => {
62
+ const [first, last] = findOrderInTremauxTree(instance, itemAId, itemBId);
63
+ const items = [first];
64
64
  let current = first;
65
65
  while (current !== last) {
66
- current = getNextNode(instance, current);
67
- nodes.push(current);
66
+ current = getNextItem(instance, current);
67
+ items.push(current);
68
68
  }
69
- return nodes;
69
+ return items;
70
70
  };
71
- const handleRangeArrowSelect = (event, nodes) => {
71
+ const handleRangeArrowSelect = (event, items) => {
72
72
  let base = models.selectedItems.value.slice();
73
73
  const {
74
74
  start,
75
75
  next,
76
76
  current
77
- } = nodes;
77
+ } = items;
78
78
  if (!next || !current) {
79
79
  return;
80
80
  }
@@ -95,32 +95,32 @@ export const useTreeViewSelection = ({
95
95
  }
96
96
  setSelectedItems(event, base);
97
97
  };
98
- const handleRangeSelect = (event, nodes) => {
98
+ const handleRangeSelect = (event, items) => {
99
99
  let base = models.selectedItems.value.slice();
100
100
  const {
101
101
  start,
102
102
  end
103
- } = nodes;
104
- // If last selection was a range selection ignore nodes that were selected.
103
+ } = items;
104
+ // If last selection was a range selection ignore items that were selected.
105
105
  if (lastSelectionWasRange.current) {
106
106
  base = base.filter(id => currentRangeSelection.current.indexOf(id) === -1);
107
107
  }
108
- let range = getNodesInRange(start, end);
109
- range = range.filter(node => !instance.isNodeDisabled(node));
108
+ let range = getItemsInRange(start, end);
109
+ range = range.filter(item => !instance.isItemDisabled(item));
110
110
  currentRangeSelection.current = range;
111
111
  let newSelected = base.concat(range);
112
112
  newSelected = newSelected.filter((id, i) => newSelected.indexOf(id) === i);
113
113
  setSelectedItems(event, newSelected);
114
114
  };
115
- const selectRange = (event, nodes, stacked = false) => {
115
+ const selectRange = (event, items, stacked = false) => {
116
116
  if (params.disableSelection) {
117
117
  return;
118
118
  }
119
119
  const {
120
- start = lastSelectedNode.current,
120
+ start = lastSelectedItem.current,
121
121
  end,
122
122
  current
123
- } = nodes;
123
+ } = items;
124
124
  if (stacked) {
125
125
  handleRangeArrowSelect(event, {
126
126
  start,
@@ -135,29 +135,29 @@ export const useTreeViewSelection = ({
135
135
  }
136
136
  lastSelectionWasRange.current = true;
137
137
  };
138
- const rangeSelectToFirst = (event, nodeId) => {
139
- if (!lastSelectedNode.current) {
140
- lastSelectedNode.current = nodeId;
138
+ const rangeSelectToFirst = (event, itemId) => {
139
+ if (!lastSelectedItem.current) {
140
+ lastSelectedItem.current = itemId;
141
141
  }
142
- const start = lastSelectionWasRange.current ? lastSelectedNode.current : nodeId;
142
+ const start = lastSelectionWasRange.current ? lastSelectedItem.current : itemId;
143
143
  instance.selectRange(event, {
144
144
  start,
145
- end: getFirstNode(instance)
145
+ end: getFirstItem(instance)
146
146
  });
147
147
  };
148
- const rangeSelectToLast = (event, nodeId) => {
149
- if (!lastSelectedNode.current) {
150
- lastSelectedNode.current = nodeId;
148
+ const rangeSelectToLast = (event, itemId) => {
149
+ if (!lastSelectedItem.current) {
150
+ lastSelectedItem.current = itemId;
151
151
  }
152
- const start = lastSelectionWasRange.current ? lastSelectedNode.current : nodeId;
152
+ const start = lastSelectionWasRange.current ? lastSelectedItem.current : itemId;
153
153
  instance.selectRange(event, {
154
154
  start,
155
- end: getLastNode(instance)
155
+ end: getLastItem(instance)
156
156
  });
157
157
  };
158
158
  populateInstance(instance, {
159
- isNodeSelected,
160
- selectNode,
159
+ isItemSelected,
160
+ selectItem,
161
161
  selectRange,
162
162
  rangeSelectToLast,
163
163
  rangeSelectToFirst
@@ -178,11 +178,11 @@ useTreeViewSelection.models = {
178
178
  getDefaultValue: params => params.defaultSelectedItems
179
179
  }
180
180
  };
181
- const DEFAULT_SELECTED_NODES = [];
181
+ const DEFAULT_SELECTED_ITEMS = [];
182
182
  useTreeViewSelection.getDefaultizedParams = params => _extends({}, params, {
183
183
  disableSelection: params.disableSelection ?? false,
184
184
  multiSelect: params.multiSelect ?? false,
185
- defaultSelectedItems: params.defaultSelectedItems ?? (params.multiSelect ? DEFAULT_SELECTED_NODES : null)
185
+ defaultSelectedItems: params.defaultSelectedItems ?? (params.multiSelect ? DEFAULT_SELECTED_ITEMS : null)
186
186
  });
187
187
  useTreeViewSelection.params = {
188
188
  disableSelection: true,
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * This is used to determine the start and end of a selection range so
3
- * we can get the nodes between the two border nodes.
3
+ * we can get the items between the two border items.
4
4
  *
5
- * It finds the nodes' common ancestor using
5
+ * It finds the items' common ancestor using
6
6
  * a naive implementation of a lowest common ancestor algorithm
7
7
  * (https://en.wikipedia.org/wiki/Lowest_common_ancestor).
8
- * Then compares the ancestor's 2 children that are ancestors of nodeA and NodeB
9
- * so we can compare their indexes to work out which node comes first in a depth first search.
8
+ * Then compares the ancestor's 2 children that are ancestors of itemA and ItemB
9
+ * so we can compare their indexes to work out which item comes first in a depth first search.
10
10
  * (https://en.wikipedia.org/wiki/Depth-first_search)
11
11
  *
12
- * Another way to put it is which node is shallower in a trémaux tree
12
+ * Another way to put it is which item is shallower in a trémaux tree
13
13
  * https://en.wikipedia.org/wiki/Tr%C3%A9maux_tree
14
14
  */
15
15
  export const findOrderInTremauxTree = (instance, nodeAId, nodeBId) => {
@@ -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,22 +1,22 @@
1
- export const getPreviousNode = (instance, nodeId) => {
2
- const node = instance.getNode(nodeId);
1
+ export const getPreviousItem = (instance, itemId) => {
2
+ const node = instance.getNode(itemId);
3
3
  const siblings = instance.getNavigableChildrenIds(node.parentId);
4
- const nodeIndex = siblings.indexOf(nodeId);
5
- if (nodeIndex === 0) {
4
+ const itemIndex = siblings.indexOf(itemId);
5
+ if (itemIndex === 0) {
6
6
  return node.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.isItemExpanded(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 getNextItem = (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.isItemExpanded(itemId) && instance.getNavigableChildrenIds(itemId).length > 0) {
17
+ return instance.getNavigableChildrenIds(itemId)[0];
18
18
  }
19
- let node = instance.getNode(nodeId);
19
+ let node = instance.getNode(itemId);
20
20
  while (node != null) {
21
21
  // Try to get next sibling
22
22
  const siblings = instance.getNavigableChildrenIds(node.parentId);
@@ -30,14 +30,14 @@ export const getNextNode = (instance, nodeId) => {
30
30
  }
31
31
  return null;
32
32
  };
33
- export const getLastNode = instance => {
34
- let lastNode = instance.getNavigableChildrenIds(null).pop();
35
- while (instance.isNodeExpanded(lastNode)) {
36
- lastNode = instance.getNavigableChildrenIds(lastNode).pop();
33
+ export const getLastItem = instance => {
34
+ let lastItem = instance.getNavigableChildrenIds(null).pop();
35
+ while (instance.isItemExpanded(lastItem)) {
36
+ lastItem = instance.getNavigableChildrenIds(lastItem).pop();
37
37
  }
38
- return lastNode;
38
+ return lastItem;
39
39
  };
40
- export const getFirstNode = instance => instance.getNavigableChildrenIds(null)[0];
40
+ export const getFirstItem = instance => instance.getNavigableChildrenIds(null)[0];
41
41
  export const populateInstance = (instance, methods) => {
42
42
  Object.assign(instance, methods);
43
43
  };
@@ -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) {