@mui/x-tree-view 7.0.0-beta.6 → 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.
- package/CHANGELOG.md +311 -12
- package/README.md +1 -1
- package/RichTreeView/RichTreeView.js +34 -36
- package/RichTreeView/RichTreeView.types.d.ts +3 -2
- package/SimpleTreeView/SimpleTreeView.js +25 -26
- package/TreeItem/TreeItem.js +94 -82
- package/TreeItem/TreeItem.types.d.ts +13 -11
- package/TreeItem/TreeItemContent.d.ts +7 -7
- package/TreeItem/TreeItemContent.js +10 -10
- package/TreeItem/useTreeItemState.d.ts +1 -1
- package/TreeItem/useTreeItemState.js +13 -13
- package/TreeItem2/TreeItem2.d.ts +18 -0
- package/TreeItem2/TreeItem2.js +300 -0
- package/TreeItem2/TreeItem2.types.d.ts +64 -0
- package/TreeItem2/TreeItem2.types.js +1 -0
- package/TreeItem2/index.d.ts +2 -0
- package/TreeItem2/index.js +1 -0
- package/TreeItem2/package.json +6 -0
- package/TreeItem2Icon/TreeItem2Icon.d.ts +7 -0
- package/TreeItem2Icon/TreeItem2Icon.js +67 -0
- package/TreeItem2Icon/TreeItem2Icon.types.d.ts +40 -0
- package/TreeItem2Icon/TreeItem2Icon.types.js +1 -0
- package/TreeItem2Icon/index.d.ts +2 -0
- package/TreeItem2Icon/index.js +1 -0
- package/TreeItem2Icon/package.json +6 -0
- package/TreeItem2Provider/TreeItem2Provider.d.ts +7 -0
- package/TreeItem2Provider/TreeItem2Provider.js +24 -0
- package/TreeItem2Provider/TreeItem2Provider.types.d.ts +6 -0
- package/TreeItem2Provider/TreeItem2Provider.types.js +1 -0
- package/TreeItem2Provider/index.d.ts +2 -0
- package/TreeItem2Provider/index.js +1 -0
- package/TreeItem2Provider/package.json +6 -0
- package/TreeView/TreeView.d.ts +1 -1
- package/TreeView/TreeView.js +23 -23
- package/hooks/index.d.ts +1 -0
- package/hooks/index.js +2 -1
- package/hooks/useTreeItem2Utils/index.d.ts +1 -0
- package/hooks/useTreeItem2Utils/index.js +1 -0
- package/hooks/useTreeItem2Utils/useTreeItem2Utils.d.ts +15 -0
- package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +61 -0
- package/index.d.ts +5 -1
- package/index.js +9 -2
- package/internals/TreeViewProvider/TreeViewContext.d.ts +3 -1
- package/internals/TreeViewProvider/TreeViewProvider.types.d.ts +4 -2
- package/internals/hooks/useInstanceEventHandler.js +5 -10
- package/internals/hooks/useLazyRef.d.ts +1 -2
- package/internals/hooks/useLazyRef.js +1 -11
- package/internals/hooks/useOnMount.d.ts +1 -2
- package/internals/hooks/useOnMount.js +1 -7
- package/internals/hooks/useTimeout.d.ts +1 -11
- package/internals/hooks/useTimeout.js +1 -36
- package/internals/models/plugin.d.ts +19 -16
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +31 -38
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +14 -14
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +67 -51
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +9 -8
- package/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
- package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +1 -1
- package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +30 -31
- package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.d.ts +2 -2
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +75 -80
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +4 -1
- package/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +26 -31
- package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +11 -11
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +47 -50
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +15 -15
- package/internals/useTreeView/useTreeView.js +28 -27
- package/internals/useTreeView/useTreeView.utils.d.ts +2 -2
- package/internals/useTreeView/useTreeView.utils.js +22 -22
- package/internals/utils/extractPluginParamsFromProps.js +2 -2
- package/internals/utils/utils.js +1 -0
- package/modern/RichTreeView/RichTreeView.js +29 -29
- package/modern/SimpleTreeView/SimpleTreeView.js +23 -23
- package/modern/TreeItem/TreeItem.js +83 -70
- package/modern/TreeItem/TreeItemContent.js +10 -10
- package/modern/TreeItem/useTreeItemState.js +13 -13
- package/modern/TreeItem2/TreeItem2.js +300 -0
- package/modern/TreeItem2/TreeItem2.types.js +1 -0
- package/modern/TreeItem2/index.js +1 -0
- package/modern/TreeItem2Icon/TreeItem2Icon.js +67 -0
- package/modern/TreeItem2Icon/TreeItem2Icon.types.js +1 -0
- package/modern/TreeItem2Icon/index.js +1 -0
- package/modern/TreeItem2Provider/TreeItem2Provider.js +24 -0
- package/modern/TreeItem2Provider/TreeItem2Provider.types.js +1 -0
- package/modern/TreeItem2Provider/index.js +1 -0
- package/modern/TreeView/TreeView.js +23 -23
- package/modern/hooks/index.js +2 -1
- package/modern/hooks/useTreeItem2Utils/index.js +1 -0
- package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +61 -0
- package/modern/index.js +9 -2
- package/modern/internals/hooks/useLazyRef.js +1 -11
- package/modern/internals/hooks/useOnMount.js +1 -7
- package/modern/internals/hooks/useTimeout.js +1 -36
- package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +29 -29
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +65 -46
- package/modern/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
- package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +30 -30
- package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +74 -77
- package/modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +21 -22
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +43 -43
- package/modern/internals/useTreeView/useTreeView.js +28 -27
- package/modern/internals/useTreeView/useTreeView.utils.js +22 -22
- package/modern/internals/utils/utils.js +1 -0
- package/modern/useTreeItem2/index.js +1 -0
- package/modern/useTreeItem2/useTreeItem2.js +146 -0
- package/modern/useTreeItem2/useTreeItem2.types.js +1 -0
- package/node/RichTreeView/RichTreeView.js +29 -29
- package/node/SimpleTreeView/SimpleTreeView.js +23 -23
- package/node/TreeItem/TreeItem.js +83 -70
- package/node/TreeItem/TreeItemContent.js +10 -10
- package/node/TreeItem/useTreeItemState.js +13 -13
- package/node/TreeItem2/TreeItem2.js +308 -0
- package/node/TreeItem2/TreeItem2.types.js +5 -0
- package/node/TreeItem2/index.js +42 -0
- package/node/TreeItem2Icon/TreeItem2Icon.js +75 -0
- package/node/TreeItem2Icon/TreeItem2Icon.types.js +5 -0
- package/node/TreeItem2Icon/index.js +12 -0
- package/node/TreeItem2Provider/TreeItem2Provider.js +30 -0
- package/node/TreeItem2Provider/TreeItem2Provider.types.js +5 -0
- package/node/TreeItem2Provider/index.js +12 -0
- package/node/TreeView/TreeView.js +23 -23
- package/node/hooks/index.js +8 -1
- package/node/hooks/useTreeItem2Utils/index.js +12 -0
- package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +68 -0
- package/node/index.js +61 -13
- package/node/internals/hooks/useLazyRef.js +7 -13
- package/node/internals/hooks/useOnMount.js +8 -10
- package/node/internals/hooks/useTimeout.js +7 -37
- package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +29 -29
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +65 -46
- package/node/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
- package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +30 -30
- package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +74 -77
- package/node/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +21 -22
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +43 -43
- package/node/internals/useTreeView/useTreeView.js +28 -27
- package/node/internals/useTreeView/useTreeView.utils.js +22 -22
- package/node/internals/utils/utils.js +1 -0
- package/node/useTreeItem2/index.js +12 -0
- package/node/useTreeItem2/useTreeItem2.js +154 -0
- package/node/useTreeItem2/useTreeItem2.types.js +5 -0
- package/package.json +5 -5
- package/themeAugmentation/components.d.ts +5 -0
- package/themeAugmentation/overrides.d.ts +1 -0
- package/themeAugmentation/props.d.ts +2 -0
- package/useTreeItem2/index.d.ts +2 -0
- package/useTreeItem2/index.js +1 -0
- package/useTreeItem2/package.json +6 -0
- package/useTreeItem2/useTreeItem2.d.ts +2 -0
- package/useTreeItem2/useTreeItem2.js +146 -0
- package/useTreeItem2/useTreeItem2.types.d.ts +115 -0
- package/useTreeItem2/useTreeItem2.types.js +1 -0
package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js
CHANGED
|
@@ -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
|
|
37
|
-
newFirstCharMap[
|
|
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
|
-
|
|
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(
|
|
54
|
-
const map = instance.getNode(
|
|
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(
|
|
52
|
+
const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(mapItemId);
|
|
57
53
|
if (visible && !shouldBeSkipped) {
|
|
58
|
-
firstCharIds.push(
|
|
59
|
-
firstChars.push(firstCharMap.current[
|
|
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(
|
|
60
|
+
start = firstCharIds.indexOf(itemId) + 1;
|
|
65
61
|
if (start >= firstCharIds.length) {
|
|
66
62
|
start = 0;
|
|
67
63
|
}
|
|
@@ -80,18 +76,17 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
80
76
|
}
|
|
81
77
|
return null;
|
|
82
78
|
};
|
|
83
|
-
const
|
|
84
|
-
const
|
|
79
|
+
const canToggleItemSelection = itemId => !params.disableSelection && !instance.isNodeDisabled(itemId);
|
|
80
|
+
const canToggleItemExpansion = itemId => {
|
|
81
|
+
return !instance.isNodeDisabled(itemId) && instance.isNodeExpandable(itemId);
|
|
82
|
+
};
|
|
85
83
|
|
|
86
84
|
// ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
|
|
87
|
-
const
|
|
88
|
-
otherHandlers.onKeyDown?.(event);
|
|
85
|
+
const handleItemKeyDown = (event, itemId) => {
|
|
89
86
|
if (event.defaultMuiPrevented) {
|
|
90
87
|
return;
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
// If the tree is empty there will be no focused node
|
|
94
|
-
if (event.altKey || event.currentTarget !== event.target || state.focusedNodeId == null) {
|
|
89
|
+
if (event.altKey || event.currentTarget !== event.target) {
|
|
95
90
|
return;
|
|
96
91
|
}
|
|
97
92
|
const ctrlPressed = event.ctrlKey || event.metaKey;
|
|
@@ -100,17 +95,17 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
100
95
|
// eslint-disable-next-line default-case
|
|
101
96
|
switch (true) {
|
|
102
97
|
// Select the node when pressing "Space"
|
|
103
|
-
case key === ' ' &&
|
|
98
|
+
case key === ' ' && canToggleItemSelection(itemId):
|
|
104
99
|
{
|
|
105
100
|
event.preventDefault();
|
|
106
101
|
if (params.multiSelect && event.shiftKey) {
|
|
107
102
|
instance.selectRange(event, {
|
|
108
|
-
end:
|
|
103
|
+
end: itemId
|
|
109
104
|
});
|
|
110
105
|
} else if (params.multiSelect) {
|
|
111
|
-
instance.selectNode(event,
|
|
106
|
+
instance.selectNode(event, itemId, true);
|
|
112
107
|
} else {
|
|
113
|
-
instance.selectNode(event,
|
|
108
|
+
instance.selectNode(event, itemId);
|
|
114
109
|
}
|
|
115
110
|
break;
|
|
116
111
|
}
|
|
@@ -119,86 +114,89 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
119
114
|
// If the focused node has no children, we select it.
|
|
120
115
|
case key === 'Enter':
|
|
121
116
|
{
|
|
122
|
-
if (
|
|
123
|
-
instance.toggleNodeExpansion(event,
|
|
117
|
+
if (canToggleItemExpansion(itemId)) {
|
|
118
|
+
instance.toggleNodeExpansion(event, itemId);
|
|
124
119
|
event.preventDefault();
|
|
125
|
-
} else if (
|
|
120
|
+
} else if (canToggleItemSelection(itemId)) {
|
|
126
121
|
if (params.multiSelect) {
|
|
127
122
|
event.preventDefault();
|
|
128
|
-
instance.selectNode(event,
|
|
129
|
-
} else if (!instance.isNodeSelected(
|
|
130
|
-
instance.selectNode(event,
|
|
123
|
+
instance.selectNode(event, itemId, true);
|
|
124
|
+
} else if (!instance.isNodeSelected(itemId)) {
|
|
125
|
+
instance.selectNode(event, itemId);
|
|
131
126
|
event.preventDefault();
|
|
132
127
|
}
|
|
133
128
|
}
|
|
134
129
|
break;
|
|
135
130
|
}
|
|
136
131
|
|
|
137
|
-
// Focus the next focusable
|
|
132
|
+
// Focus the next focusable item
|
|
138
133
|
case key === 'ArrowDown':
|
|
139
134
|
{
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
135
|
+
const nextItem = getNextNode(instance, itemId);
|
|
136
|
+
if (nextItem) {
|
|
142
137
|
event.preventDefault();
|
|
143
|
-
instance.
|
|
138
|
+
instance.focusItem(event, nextItem);
|
|
144
139
|
|
|
145
140
|
// Multi select behavior when pressing Shift + ArrowDown
|
|
146
|
-
// Toggles the selection state of the next
|
|
147
|
-
if (params.multiSelect && event.shiftKey &&
|
|
141
|
+
// Toggles the selection state of the next item
|
|
142
|
+
if (params.multiSelect && event.shiftKey && canToggleItemSelection(nextItem)) {
|
|
148
143
|
instance.selectRange(event, {
|
|
149
|
-
end:
|
|
150
|
-
current:
|
|
144
|
+
end: nextItem,
|
|
145
|
+
current: itemId
|
|
151
146
|
}, true);
|
|
152
147
|
}
|
|
153
148
|
}
|
|
154
149
|
break;
|
|
155
150
|
}
|
|
156
151
|
|
|
157
|
-
// Focuses the previous focusable
|
|
152
|
+
// Focuses the previous focusable item
|
|
158
153
|
case key === 'ArrowUp':
|
|
159
154
|
{
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
155
|
+
const previousItem = getPreviousNode(instance, itemId);
|
|
156
|
+
if (previousItem) {
|
|
162
157
|
event.preventDefault();
|
|
163
|
-
instance.
|
|
158
|
+
instance.focusItem(event, previousItem);
|
|
164
159
|
|
|
165
160
|
// Multi select behavior when pressing Shift + ArrowUp
|
|
166
|
-
// Toggles the selection state of the previous
|
|
167
|
-
if (params.multiSelect && event.shiftKey &&
|
|
161
|
+
// Toggles the selection state of the previous item
|
|
162
|
+
if (params.multiSelect && event.shiftKey && canToggleItemSelection(previousItem)) {
|
|
168
163
|
instance.selectRange(event, {
|
|
169
|
-
end:
|
|
170
|
-
current:
|
|
164
|
+
end: previousItem,
|
|
165
|
+
current: itemId
|
|
171
166
|
}, true);
|
|
172
167
|
}
|
|
173
168
|
}
|
|
174
169
|
break;
|
|
175
170
|
}
|
|
176
171
|
|
|
177
|
-
// If the focused
|
|
178
|
-
// If the focused
|
|
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
|
|
179
174
|
case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
|
|
180
175
|
{
|
|
181
|
-
if (instance.isNodeExpanded(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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);
|
|
186
184
|
event.preventDefault();
|
|
187
185
|
}
|
|
188
186
|
break;
|
|
189
187
|
}
|
|
190
188
|
|
|
191
|
-
// If the focused
|
|
192
|
-
// If the focused
|
|
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
|
|
193
191
|
case key === 'ArrowLeft' && !isRTL || key === 'ArrowRight' && isRTL:
|
|
194
192
|
{
|
|
195
|
-
if (
|
|
196
|
-
instance.toggleNodeExpansion(event,
|
|
193
|
+
if (canToggleItemExpansion(itemId) && instance.isNodeExpanded(itemId)) {
|
|
194
|
+
instance.toggleNodeExpansion(event, itemId);
|
|
197
195
|
event.preventDefault();
|
|
198
196
|
} else {
|
|
199
|
-
const parent = instance.getNode(
|
|
197
|
+
const parent = instance.getNode(itemId).parentId;
|
|
200
198
|
if (parent) {
|
|
201
|
-
instance.
|
|
199
|
+
instance.focusItem(event, parent);
|
|
202
200
|
event.preventDefault();
|
|
203
201
|
}
|
|
204
202
|
}
|
|
@@ -208,35 +206,35 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
208
206
|
// Focuses the first node in the tree
|
|
209
207
|
case key === 'Home':
|
|
210
208
|
{
|
|
211
|
-
instance.
|
|
209
|
+
instance.focusItem(event, getFirstNode(instance));
|
|
212
210
|
|
|
213
211
|
// Multi select behavior when pressing Ctrl + Shift + Home
|
|
214
212
|
// Selects the focused node and all nodes up to the first node.
|
|
215
|
-
if (
|
|
216
|
-
instance.rangeSelectToFirst(event,
|
|
213
|
+
if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
|
|
214
|
+
instance.rangeSelectToFirst(event, itemId);
|
|
217
215
|
}
|
|
218
216
|
event.preventDefault();
|
|
219
217
|
break;
|
|
220
218
|
}
|
|
221
219
|
|
|
222
|
-
// Focuses the last
|
|
220
|
+
// Focuses the last item in the tree
|
|
223
221
|
case key === 'End':
|
|
224
222
|
{
|
|
225
|
-
instance.
|
|
223
|
+
instance.focusItem(event, getLastNode(instance));
|
|
226
224
|
|
|
227
225
|
// Multi select behavior when pressing Ctrl + Shirt + End
|
|
228
|
-
// Selects the focused
|
|
229
|
-
if (
|
|
230
|
-
instance.rangeSelectToLast(event,
|
|
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);
|
|
231
229
|
}
|
|
232
230
|
event.preventDefault();
|
|
233
231
|
break;
|
|
234
232
|
}
|
|
235
233
|
|
|
236
|
-
// Expand all siblings that are at the same level as the focused
|
|
234
|
+
// Expand all siblings that are at the same level as the focused item
|
|
237
235
|
case key === '*':
|
|
238
236
|
{
|
|
239
|
-
instance.expandAllSiblings(event,
|
|
237
|
+
instance.expandAllSiblings(event, itemId);
|
|
240
238
|
event.preventDefault();
|
|
241
239
|
break;
|
|
242
240
|
}
|
|
@@ -257,19 +255,18 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
257
255
|
// TODO: Support typing multiple characters
|
|
258
256
|
case !ctrlPressed && !event.shiftKey && isPrintableCharacter(key):
|
|
259
257
|
{
|
|
260
|
-
const matchingNode =
|
|
258
|
+
const matchingNode = getFirstMatchingItem(itemId, key);
|
|
261
259
|
if (matchingNode != null) {
|
|
262
|
-
instance.
|
|
260
|
+
instance.focusItem(event, matchingNode);
|
|
263
261
|
event.preventDefault();
|
|
264
262
|
}
|
|
265
263
|
break;
|
|
266
264
|
}
|
|
267
265
|
}
|
|
268
266
|
};
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
};
|
|
267
|
+
populateInstance(instance, {
|
|
268
|
+
updateFirstCharMap,
|
|
269
|
+
handleItemKeyDown
|
|
270
|
+
});
|
|
274
271
|
};
|
|
275
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(
|
|
56
|
-
const getItem = React.useCallback(
|
|
57
|
-
const isNodeDisabled = React.useCallback(
|
|
58
|
-
if (
|
|
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
|
|
60
|
+
let item = instance.getNode(itemId);
|
|
62
61
|
|
|
63
|
-
// This can be called before the
|
|
64
|
-
if (!
|
|
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 (
|
|
66
|
+
if (item.disabled) {
|
|
68
67
|
return true;
|
|
69
68
|
}
|
|
70
|
-
while (
|
|
71
|
-
|
|
72
|
-
if (
|
|
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 =
|
|
79
|
-
const getNavigableChildrenIds =
|
|
80
|
-
let childrenIds = instance.getChildrenIds(
|
|
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(
|
|
81
|
+
childrenIds = childrenIds.filter(item => !instance.isNodeDisabled(item));
|
|
83
82
|
}
|
|
84
83
|
return childrenIds;
|
|
85
84
|
};
|
|
@@ -103,21 +102,21 @@ export const useTreeViewNodes = ({
|
|
|
103
102
|
});
|
|
104
103
|
});
|
|
105
104
|
}, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
|
|
106
|
-
const getNodesToRender =
|
|
107
|
-
const
|
|
105
|
+
const getNodesToRender = () => {
|
|
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
|
-
|
|
113
|
+
itemId: node.id,
|
|
115
114
|
id: node.idAttribute,
|
|
116
|
-
children: children?.map(
|
|
115
|
+
children: children?.map(getPropsFromItemId)
|
|
117
116
|
};
|
|
118
117
|
};
|
|
119
|
-
return state.nodes.nodeTree.map(
|
|
120
|
-
}
|
|
118
|
+
return state.nodes.nodeTree.map(getPropsFromItemId);
|
|
119
|
+
};
|
|
121
120
|
populateInstance(instance, {
|
|
122
121
|
getNode,
|
|
123
122
|
getItem,
|
|
@@ -10,51 +10,51 @@ export const useTreeViewSelection = ({
|
|
|
10
10
|
const lastSelectedNode = React.useRef(null);
|
|
11
11
|
const lastSelectionWasRange = React.useRef(false);
|
|
12
12
|
const currentRangeSelection = React.useRef([]);
|
|
13
|
-
const
|
|
14
|
-
if (params.
|
|
13
|
+
const setSelectedItems = (event, newSelectedItems) => {
|
|
14
|
+
if (params.onItemSelectionToggle) {
|
|
15
15
|
if (params.multiSelect) {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
params.
|
|
16
|
+
const addedItems = newSelectedItems.filter(itemId => !instance.isNodeSelected(itemId));
|
|
17
|
+
const removedItems = models.selectedItems.value.filter(itemId => !newSelectedItems.includes(itemId));
|
|
18
|
+
addedItems.forEach(itemId => {
|
|
19
|
+
params.onItemSelectionToggle(event, itemId, true);
|
|
20
20
|
});
|
|
21
|
-
|
|
22
|
-
params.
|
|
21
|
+
removedItems.forEach(itemId => {
|
|
22
|
+
params.onItemSelectionToggle(event, itemId, false);
|
|
23
23
|
});
|
|
24
|
-
} else if (
|
|
25
|
-
if (models.
|
|
26
|
-
params.
|
|
24
|
+
} else if (newSelectedItems !== models.selectedItems.value) {
|
|
25
|
+
if (models.selectedItems.value != null) {
|
|
26
|
+
params.onItemSelectionToggle(event, models.selectedItems.value, false);
|
|
27
27
|
}
|
|
28
|
-
if (
|
|
29
|
-
params.
|
|
28
|
+
if (newSelectedItems != null) {
|
|
29
|
+
params.onItemSelectionToggle(event, newSelectedItems, true);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
if (params.
|
|
34
|
-
params.
|
|
33
|
+
if (params.onSelectedItemsChange) {
|
|
34
|
+
params.onSelectedItemsChange(event, newSelectedItems);
|
|
35
35
|
}
|
|
36
|
-
models.
|
|
36
|
+
models.selectedItems.setControlledValue(newSelectedItems);
|
|
37
37
|
};
|
|
38
|
-
const isNodeSelected =
|
|
39
|
-
const selectNode = (event,
|
|
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
|
-
if (Array.isArray(models.
|
|
44
|
+
if (Array.isArray(models.selectedItems.value)) {
|
|
45
45
|
let newSelected;
|
|
46
|
-
if (models.
|
|
47
|
-
newSelected = models.
|
|
46
|
+
if (models.selectedItems.value.indexOf(itemId) !== -1) {
|
|
47
|
+
newSelected = models.selectedItems.value.filter(id => id !== itemId);
|
|
48
48
|
} else {
|
|
49
|
-
newSelected = [
|
|
49
|
+
newSelected = [itemId].concat(models.selectedItems.value);
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
setSelectedItems(event, newSelected);
|
|
52
52
|
}
|
|
53
53
|
} else {
|
|
54
|
-
const newSelected = params.multiSelect ? [
|
|
55
|
-
|
|
54
|
+
const newSelected = params.multiSelect ? [itemId] : itemId;
|
|
55
|
+
setSelectedItems(event, newSelected);
|
|
56
56
|
}
|
|
57
|
-
lastSelectedNode.current =
|
|
57
|
+
lastSelectedNode.current = itemId;
|
|
58
58
|
lastSelectionWasRange.current = false;
|
|
59
59
|
currentRangeSelection.current = [];
|
|
60
60
|
};
|
|
@@ -69,7 +69,7 @@ export const useTreeViewSelection = ({
|
|
|
69
69
|
return nodes;
|
|
70
70
|
};
|
|
71
71
|
const handleRangeArrowSelect = (event, nodes) => {
|
|
72
|
-
let base = models.
|
|
72
|
+
let base = models.selectedItems.value.slice();
|
|
73
73
|
const {
|
|
74
74
|
start,
|
|
75
75
|
next,
|
|
@@ -93,10 +93,10 @@ export const useTreeViewSelection = ({
|
|
|
93
93
|
base.push(next);
|
|
94
94
|
currentRangeSelection.current.push(current, next);
|
|
95
95
|
}
|
|
96
|
-
|
|
96
|
+
setSelectedItems(event, base);
|
|
97
97
|
};
|
|
98
98
|
const handleRangeSelect = (event, nodes) => {
|
|
99
|
-
let base = models.
|
|
99
|
+
let base = models.selectedItems.value.slice();
|
|
100
100
|
const {
|
|
101
101
|
start,
|
|
102
102
|
end
|
|
@@ -110,7 +110,7 @@ export const useTreeViewSelection = ({
|
|
|
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
115
|
const selectRange = (event, nodes, stacked = false) => {
|
|
116
116
|
if (params.disableSelection) {
|
|
@@ -135,21 +135,21 @@ export const useTreeViewSelection = ({
|
|
|
135
135
|
}
|
|
136
136
|
lastSelectionWasRange.current = true;
|
|
137
137
|
};
|
|
138
|
-
const rangeSelectToFirst = (event,
|
|
138
|
+
const rangeSelectToFirst = (event, itemId) => {
|
|
139
139
|
if (!lastSelectedNode.current) {
|
|
140
|
-
lastSelectedNode.current =
|
|
140
|
+
lastSelectedNode.current = itemId;
|
|
141
141
|
}
|
|
142
|
-
const start = lastSelectionWasRange.current ? lastSelectedNode.current :
|
|
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,
|
|
148
|
+
const rangeSelectToLast = (event, itemId) => {
|
|
149
149
|
if (!lastSelectedNode.current) {
|
|
150
|
-
lastSelectedNode.current =
|
|
150
|
+
lastSelectedNode.current = itemId;
|
|
151
151
|
}
|
|
152
|
-
const start = lastSelectionWasRange.current ? lastSelectedNode.current :
|
|
152
|
+
const start = lastSelectionWasRange.current ? lastSelectedNode.current : itemId;
|
|
153
153
|
instance.selectRange(event, {
|
|
154
154
|
start,
|
|
155
155
|
end: getLastNode(instance)
|
|
@@ -174,21 +174,21 @@ export const useTreeViewSelection = ({
|
|
|
174
174
|
};
|
|
175
175
|
};
|
|
176
176
|
useTreeViewSelection.models = {
|
|
177
|
-
|
|
178
|
-
getDefaultValue: params => params.
|
|
177
|
+
selectedItems: {
|
|
178
|
+
getDefaultValue: params => params.defaultSelectedItems
|
|
179
179
|
}
|
|
180
180
|
};
|
|
181
181
|
const DEFAULT_SELECTED_NODES = [];
|
|
182
182
|
useTreeViewSelection.getDefaultizedParams = params => _extends({}, params, {
|
|
183
183
|
disableSelection: params.disableSelection ?? false,
|
|
184
184
|
multiSelect: params.multiSelect ?? false,
|
|
185
|
-
|
|
185
|
+
defaultSelectedItems: params.defaultSelectedItems ?? (params.multiSelect ? DEFAULT_SELECTED_NODES : null)
|
|
186
186
|
});
|
|
187
187
|
useTreeViewSelection.params = {
|
|
188
188
|
disableSelection: true,
|
|
189
189
|
multiSelect: true,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
defaultSelectedItems: true,
|
|
191
|
+
selectedItems: true,
|
|
192
|
+
onSelectedItemsChange: true,
|
|
193
|
+
onItemSelectionToggle: true
|
|
194
194
|
};
|
|
@@ -38,6 +38,7 @@ export const useTreeView = inParams => {
|
|
|
38
38
|
});
|
|
39
39
|
const rootPropsGetters = [];
|
|
40
40
|
const contextValue = {
|
|
41
|
+
publicAPI,
|
|
41
42
|
instance: instance
|
|
42
43
|
};
|
|
43
44
|
const runPlugin = plugin => {
|
|
@@ -60,47 +61,47 @@ export const useTreeView = inParams => {
|
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
63
|
plugins.forEach(runPlugin);
|
|
63
|
-
contextValue.runItemPlugins =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}) => {
|
|
67
|
-
let finalProps = props;
|
|
68
|
-
let finalRef = ref;
|
|
69
|
-
const itemWrappers = [];
|
|
64
|
+
contextValue.runItemPlugins = itemPluginProps => {
|
|
65
|
+
let finalRootRef = null;
|
|
66
|
+
let finalContentRef = null;
|
|
70
67
|
plugins.forEach(plugin => {
|
|
71
68
|
if (!plugin.itemPlugin) {
|
|
72
69
|
return;
|
|
73
70
|
}
|
|
74
71
|
const itemPluginResponse = plugin.itemPlugin({
|
|
75
|
-
props:
|
|
76
|
-
|
|
72
|
+
props: itemPluginProps,
|
|
73
|
+
rootRef: finalRootRef,
|
|
74
|
+
contentRef: finalContentRef
|
|
77
75
|
});
|
|
78
|
-
if (itemPluginResponse?.
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
if (itemPluginResponse?.ref) {
|
|
82
|
-
finalRef = itemPluginResponse.ref;
|
|
76
|
+
if (itemPluginResponse?.rootRef) {
|
|
77
|
+
finalRootRef = itemPluginResponse.rootRef;
|
|
83
78
|
}
|
|
84
|
-
if (itemPluginResponse?.
|
|
85
|
-
|
|
79
|
+
if (itemPluginResponse?.contentRef) {
|
|
80
|
+
finalContentRef = itemPluginResponse.contentRef;
|
|
86
81
|
}
|
|
87
82
|
});
|
|
88
83
|
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
wrapItem: children => {
|
|
92
|
-
let finalChildren = children;
|
|
93
|
-
itemWrappers.forEach(itemWrapper => {
|
|
94
|
-
finalChildren = itemWrapper(finalChildren);
|
|
95
|
-
});
|
|
96
|
-
return finalChildren;
|
|
97
|
-
}
|
|
84
|
+
contentRef: finalContentRef,
|
|
85
|
+
rootRef: finalRootRef
|
|
98
86
|
};
|
|
99
87
|
};
|
|
88
|
+
const itemWrappers = plugins.map(plugin => plugin.wrapItem).filter(wrapItem => !!wrapItem);
|
|
89
|
+
contextValue.wrapItem = ({
|
|
90
|
+
itemId,
|
|
91
|
+
children
|
|
92
|
+
}) => {
|
|
93
|
+
let finalChildren = children;
|
|
94
|
+
itemWrappers.forEach(itemWrapper => {
|
|
95
|
+
finalChildren = itemWrapper({
|
|
96
|
+
itemId,
|
|
97
|
+
children: finalChildren
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
return finalChildren;
|
|
101
|
+
};
|
|
100
102
|
const getRootProps = (otherHandlers = {}) => {
|
|
101
103
|
const rootProps = _extends({
|
|
102
|
-
role: 'tree'
|
|
103
|
-
tabIndex: 0
|
|
104
|
+
role: 'tree'
|
|
104
105
|
}, otherHandlers, {
|
|
105
106
|
ref: handleRootRef
|
|
106
107
|
});
|