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