@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
|
@@ -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';
|
|
@@ -32,37 +31,33 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
32
31
|
}
|
|
33
32
|
const newFirstCharMap = {};
|
|
34
33
|
const processItem = item => {
|
|
35
|
-
var _item$children;
|
|
36
34
|
const getItemId = params.getItemId;
|
|
37
|
-
const
|
|
38
|
-
newFirstCharMap[
|
|
39
|
-
|
|
35
|
+
const itemId = getItemId ? getItemId(item) : item.id;
|
|
36
|
+
newFirstCharMap[itemId] = instance.getNode(itemId).label.substring(0, 1).toLowerCase();
|
|
37
|
+
item.children?.forEach(processItem);
|
|
40
38
|
};
|
|
41
39
|
params.items.forEach(processItem);
|
|
42
40
|
firstCharMap.current = newFirstCharMap;
|
|
43
41
|
}, [params.items, params.getItemId, instance]);
|
|
44
|
-
|
|
45
|
-
updateFirstCharMap
|
|
46
|
-
});
|
|
47
|
-
const getFirstMatchingNode = (nodeId, firstChar) => {
|
|
42
|
+
const getFirstMatchingItem = (itemId, firstChar) => {
|
|
48
43
|
let start;
|
|
49
44
|
let index;
|
|
50
45
|
const lowercaseChar = firstChar.toLowerCase();
|
|
51
46
|
const firstCharIds = [];
|
|
52
47
|
const firstChars = [];
|
|
53
48
|
// This really only works since the ids are strings
|
|
54
|
-
Object.keys(firstCharMap.current).forEach(
|
|
55
|
-
const map = instance.getNode(
|
|
49
|
+
Object.keys(firstCharMap.current).forEach(mapItemId => {
|
|
50
|
+
const map = instance.getNode(mapItemId);
|
|
56
51
|
const visible = map.parentId ? instance.isNodeExpanded(map.parentId) : true;
|
|
57
|
-
const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(
|
|
52
|
+
const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isNodeDisabled(mapItemId);
|
|
58
53
|
if (visible && !shouldBeSkipped) {
|
|
59
|
-
firstCharIds.push(
|
|
60
|
-
firstChars.push(firstCharMap.current[
|
|
54
|
+
firstCharIds.push(mapItemId);
|
|
55
|
+
firstChars.push(firstCharMap.current[mapItemId]);
|
|
61
56
|
}
|
|
62
57
|
});
|
|
63
58
|
|
|
64
59
|
// Get start index for search based on position of currentItem
|
|
65
|
-
start = firstCharIds.indexOf(
|
|
60
|
+
start = firstCharIds.indexOf(itemId) + 1;
|
|
66
61
|
if (start >= firstCharIds.length) {
|
|
67
62
|
start = 0;
|
|
68
63
|
}
|
|
@@ -81,19 +76,17 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
81
76
|
}
|
|
82
77
|
return null;
|
|
83
78
|
};
|
|
84
|
-
const
|
|
85
|
-
const
|
|
79
|
+
const canToggleItemSelection = itemId => !params.disableSelection && !instance.isNodeDisabled(itemId);
|
|
80
|
+
const canToggleItemExpansion = itemId => {
|
|
81
|
+
return !instance.isNodeDisabled(itemId) && instance.isNodeExpandable(itemId);
|
|
82
|
+
};
|
|
86
83
|
|
|
87
84
|
// ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
|
|
88
|
-
const
|
|
89
|
-
var _otherHandlers$onKeyD;
|
|
90
|
-
(_otherHandlers$onKeyD = otherHandlers.onKeyDown) == null || _otherHandlers$onKeyD.call(otherHandlers, event);
|
|
85
|
+
const handleItemKeyDown = (event, itemId) => {
|
|
91
86
|
if (event.defaultMuiPrevented) {
|
|
92
87
|
return;
|
|
93
88
|
}
|
|
94
|
-
|
|
95
|
-
// If the tree is empty there will be no focused node
|
|
96
|
-
if (event.altKey || event.currentTarget !== event.target || state.focusedNodeId == null) {
|
|
89
|
+
if (event.altKey || event.currentTarget !== event.target) {
|
|
97
90
|
return;
|
|
98
91
|
}
|
|
99
92
|
const ctrlPressed = event.ctrlKey || event.metaKey;
|
|
@@ -102,17 +95,17 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
102
95
|
// eslint-disable-next-line default-case
|
|
103
96
|
switch (true) {
|
|
104
97
|
// Select the node when pressing "Space"
|
|
105
|
-
case key === ' ' &&
|
|
98
|
+
case key === ' ' && canToggleItemSelection(itemId):
|
|
106
99
|
{
|
|
107
100
|
event.preventDefault();
|
|
108
101
|
if (params.multiSelect && event.shiftKey) {
|
|
109
102
|
instance.selectRange(event, {
|
|
110
|
-
end:
|
|
103
|
+
end: itemId
|
|
111
104
|
});
|
|
112
105
|
} else if (params.multiSelect) {
|
|
113
|
-
instance.selectNode(event,
|
|
106
|
+
instance.selectNode(event, itemId, true);
|
|
114
107
|
} else {
|
|
115
|
-
instance.selectNode(event,
|
|
108
|
+
instance.selectNode(event, itemId);
|
|
116
109
|
}
|
|
117
110
|
break;
|
|
118
111
|
}
|
|
@@ -121,86 +114,89 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
121
114
|
// If the focused node has no children, we select it.
|
|
122
115
|
case key === 'Enter':
|
|
123
116
|
{
|
|
124
|
-
if (
|
|
125
|
-
instance.toggleNodeExpansion(event,
|
|
117
|
+
if (canToggleItemExpansion(itemId)) {
|
|
118
|
+
instance.toggleNodeExpansion(event, itemId);
|
|
126
119
|
event.preventDefault();
|
|
127
|
-
} else if (
|
|
120
|
+
} else if (canToggleItemSelection(itemId)) {
|
|
128
121
|
if (params.multiSelect) {
|
|
129
122
|
event.preventDefault();
|
|
130
|
-
instance.selectNode(event,
|
|
131
|
-
} else if (!instance.isNodeSelected(
|
|
132
|
-
instance.selectNode(event,
|
|
123
|
+
instance.selectNode(event, itemId, true);
|
|
124
|
+
} else if (!instance.isNodeSelected(itemId)) {
|
|
125
|
+
instance.selectNode(event, itemId);
|
|
133
126
|
event.preventDefault();
|
|
134
127
|
}
|
|
135
128
|
}
|
|
136
129
|
break;
|
|
137
130
|
}
|
|
138
131
|
|
|
139
|
-
// Focus the next focusable
|
|
132
|
+
// Focus the next focusable item
|
|
140
133
|
case key === 'ArrowDown':
|
|
141
134
|
{
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
135
|
+
const nextItem = getNextNode(instance, itemId);
|
|
136
|
+
if (nextItem) {
|
|
144
137
|
event.preventDefault();
|
|
145
|
-
instance.
|
|
138
|
+
instance.focusItem(event, nextItem);
|
|
146
139
|
|
|
147
140
|
// Multi select behavior when pressing Shift + ArrowDown
|
|
148
|
-
// Toggles the selection state of the next
|
|
149
|
-
if (params.multiSelect && event.shiftKey &&
|
|
141
|
+
// Toggles the selection state of the next item
|
|
142
|
+
if (params.multiSelect && event.shiftKey && canToggleItemSelection(nextItem)) {
|
|
150
143
|
instance.selectRange(event, {
|
|
151
|
-
end:
|
|
152
|
-
current:
|
|
144
|
+
end: nextItem,
|
|
145
|
+
current: itemId
|
|
153
146
|
}, true);
|
|
154
147
|
}
|
|
155
148
|
}
|
|
156
149
|
break;
|
|
157
150
|
}
|
|
158
151
|
|
|
159
|
-
// Focuses the previous focusable
|
|
152
|
+
// Focuses the previous focusable item
|
|
160
153
|
case key === 'ArrowUp':
|
|
161
154
|
{
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
155
|
+
const previousItem = getPreviousNode(instance, itemId);
|
|
156
|
+
if (previousItem) {
|
|
164
157
|
event.preventDefault();
|
|
165
|
-
instance.
|
|
158
|
+
instance.focusItem(event, previousItem);
|
|
166
159
|
|
|
167
160
|
// Multi select behavior when pressing Shift + ArrowUp
|
|
168
|
-
// Toggles the selection state of the previous
|
|
169
|
-
if (params.multiSelect && event.shiftKey &&
|
|
161
|
+
// Toggles the selection state of the previous item
|
|
162
|
+
if (params.multiSelect && event.shiftKey && canToggleItemSelection(previousItem)) {
|
|
170
163
|
instance.selectRange(event, {
|
|
171
|
-
end:
|
|
172
|
-
current:
|
|
164
|
+
end: previousItem,
|
|
165
|
+
current: itemId
|
|
173
166
|
}, true);
|
|
174
167
|
}
|
|
175
168
|
}
|
|
176
169
|
break;
|
|
177
170
|
}
|
|
178
171
|
|
|
179
|
-
// If the focused
|
|
180
|
-
// 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
|
|
181
174
|
case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
|
|
182
175
|
{
|
|
183
|
-
if (instance.isNodeExpanded(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
176
|
+
if (instance.isNodeExpanded(itemId)) {
|
|
177
|
+
const nextNodeId = getNextNode(instance, itemId);
|
|
178
|
+
if (nextNodeId) {
|
|
179
|
+
instance.focusItem(event, nextNodeId);
|
|
180
|
+
event.preventDefault();
|
|
181
|
+
}
|
|
182
|
+
} else if (canToggleItemExpansion(itemId)) {
|
|
183
|
+
instance.toggleNodeExpansion(event, itemId);
|
|
188
184
|
event.preventDefault();
|
|
189
185
|
}
|
|
190
186
|
break;
|
|
191
187
|
}
|
|
192
188
|
|
|
193
|
-
// If the focused
|
|
194
|
-
// 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
|
|
195
191
|
case key === 'ArrowLeft' && !isRTL || key === 'ArrowRight' && isRTL:
|
|
196
192
|
{
|
|
197
|
-
if (
|
|
198
|
-
instance.toggleNodeExpansion(event,
|
|
193
|
+
if (canToggleItemExpansion(itemId) && instance.isNodeExpanded(itemId)) {
|
|
194
|
+
instance.toggleNodeExpansion(event, itemId);
|
|
199
195
|
event.preventDefault();
|
|
200
196
|
} else {
|
|
201
|
-
const parent = instance.getNode(
|
|
197
|
+
const parent = instance.getNode(itemId).parentId;
|
|
202
198
|
if (parent) {
|
|
203
|
-
instance.
|
|
199
|
+
instance.focusItem(event, parent);
|
|
204
200
|
event.preventDefault();
|
|
205
201
|
}
|
|
206
202
|
}
|
|
@@ -210,35 +206,35 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
210
206
|
// Focuses the first node in the tree
|
|
211
207
|
case key === 'Home':
|
|
212
208
|
{
|
|
213
|
-
instance.
|
|
209
|
+
instance.focusItem(event, getFirstNode(instance));
|
|
214
210
|
|
|
215
211
|
// Multi select behavior when pressing Ctrl + Shift + Home
|
|
216
212
|
// Selects the focused node and all nodes up to the first node.
|
|
217
|
-
if (
|
|
218
|
-
instance.rangeSelectToFirst(event,
|
|
213
|
+
if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
|
|
214
|
+
instance.rangeSelectToFirst(event, itemId);
|
|
219
215
|
}
|
|
220
216
|
event.preventDefault();
|
|
221
217
|
break;
|
|
222
218
|
}
|
|
223
219
|
|
|
224
|
-
// Focuses the last
|
|
220
|
+
// Focuses the last item in the tree
|
|
225
221
|
case key === 'End':
|
|
226
222
|
{
|
|
227
|
-
instance.
|
|
223
|
+
instance.focusItem(event, getLastNode(instance));
|
|
228
224
|
|
|
229
225
|
// Multi select behavior when pressing Ctrl + Shirt + End
|
|
230
|
-
// Selects the focused
|
|
231
|
-
if (
|
|
232
|
-
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);
|
|
233
229
|
}
|
|
234
230
|
event.preventDefault();
|
|
235
231
|
break;
|
|
236
232
|
}
|
|
237
233
|
|
|
238
|
-
// Expand all siblings that are at the same level as the focused
|
|
234
|
+
// Expand all siblings that are at the same level as the focused item
|
|
239
235
|
case key === '*':
|
|
240
236
|
{
|
|
241
|
-
instance.expandAllSiblings(event,
|
|
237
|
+
instance.expandAllSiblings(event, itemId);
|
|
242
238
|
event.preventDefault();
|
|
243
239
|
break;
|
|
244
240
|
}
|
|
@@ -259,19 +255,18 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
259
255
|
// TODO: Support typing multiple characters
|
|
260
256
|
case !ctrlPressed && !event.shiftKey && isPrintableCharacter(key):
|
|
261
257
|
{
|
|
262
|
-
const matchingNode =
|
|
258
|
+
const matchingNode = getFirstMatchingItem(itemId, key);
|
|
263
259
|
if (matchingNode != null) {
|
|
264
|
-
instance.
|
|
260
|
+
instance.focusItem(event, matchingNode);
|
|
265
261
|
event.preventDefault();
|
|
266
262
|
}
|
|
267
263
|
break;
|
|
268
264
|
}
|
|
269
265
|
}
|
|
270
266
|
};
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
};
|
|
267
|
+
populateInstance(instance, {
|
|
268
|
+
updateFirstCharMap,
|
|
269
|
+
handleItemKeyDown
|
|
270
|
+
});
|
|
276
271
|
};
|
|
277
272
|
useTreeViewKeyboardNavigation.params = {};
|
package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
1
2
|
import { TreeViewPluginSignature } from '../../models';
|
|
2
3
|
import { UseTreeViewNodesSignature } from '../useTreeViewNodes';
|
|
3
4
|
import { UseTreeViewSelectionSignature } from '../useTreeViewSelection';
|
|
4
5
|
import { UseTreeViewFocusSignature } from '../useTreeViewFocus';
|
|
5
6
|
import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
|
|
7
|
+
import { MuiCancellableEvent } from '../../models/MuiCancellableEvent';
|
|
6
8
|
export interface UseTreeViewKeyboardNavigationInstance {
|
|
7
9
|
updateFirstCharMap: (updater: (map: TreeViewFirstCharMap) => TreeViewFirstCharMap) => void;
|
|
10
|
+
handleItemKeyDown: (event: React.KeyboardEvent<HTMLElement> & MuiCancellableEvent, itemId: string) => void;
|
|
8
11
|
}
|
|
9
12
|
export type UseTreeViewKeyboardNavigationSignature = TreeViewPluginSignature<{
|
|
10
13
|
instance: UseTreeViewKeyboardNavigationInstance;
|
|
@@ -16,5 +19,5 @@ export type UseTreeViewKeyboardNavigationSignature = TreeViewPluginSignature<{
|
|
|
16
19
|
];
|
|
17
20
|
}>;
|
|
18
21
|
export type TreeViewFirstCharMap = {
|
|
19
|
-
[
|
|
22
|
+
[itemId: string]: string;
|
|
20
23
|
};
|
|
@@ -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 = ({
|
|
@@ -12,7 +11,6 @@ const updateNodesState = ({
|
|
|
12
11
|
const nodeMap = {};
|
|
13
12
|
const itemMap = {};
|
|
14
13
|
const processItem = (item, index, parentId) => {
|
|
15
|
-
var _item$children, _item$children2;
|
|
16
14
|
const id = getItemId ? getItemId(item) : item.id;
|
|
17
15
|
if (id == null) {
|
|
18
16
|
throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', 'An item was provided without id in the `items` prop:', JSON.stringify(item)].join('\n'));
|
|
@@ -30,13 +28,13 @@ const updateNodesState = ({
|
|
|
30
28
|
index,
|
|
31
29
|
parentId,
|
|
32
30
|
idAttribute: undefined,
|
|
33
|
-
expandable: !!
|
|
31
|
+
expandable: !!item.children?.length,
|
|
34
32
|
disabled: isItemDisabled ? isItemDisabled(item) : false
|
|
35
33
|
};
|
|
36
34
|
itemMap[id] = item;
|
|
37
35
|
return {
|
|
38
36
|
id,
|
|
39
|
-
children:
|
|
37
|
+
children: item.children?.map((child, childIndex) => processItem(child, childIndex, id))
|
|
40
38
|
};
|
|
41
39
|
};
|
|
42
40
|
const nodeTree = items.map((item, itemIndex) => processItem(item, itemIndex, null));
|
|
@@ -53,34 +51,34 @@ export const useTreeViewNodes = ({
|
|
|
53
51
|
state,
|
|
54
52
|
setState
|
|
55
53
|
}) => {
|
|
56
|
-
const getNode = React.useCallback(
|
|
57
|
-
const getItem = React.useCallback(
|
|
58
|
-
const isNodeDisabled = React.useCallback(
|
|
59
|
-
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) {
|
|
60
58
|
return false;
|
|
61
59
|
}
|
|
62
|
-
let
|
|
60
|
+
let item = instance.getNode(itemId);
|
|
63
61
|
|
|
64
|
-
// This can be called before the
|
|
65
|
-
if (!
|
|
62
|
+
// This can be called before the item has been added to the node map.
|
|
63
|
+
if (!item) {
|
|
66
64
|
return false;
|
|
67
65
|
}
|
|
68
|
-
if (
|
|
66
|
+
if (item.disabled) {
|
|
69
67
|
return true;
|
|
70
68
|
}
|
|
71
|
-
while (
|
|
72
|
-
|
|
73
|
-
if (
|
|
69
|
+
while (item.parentId != null) {
|
|
70
|
+
item = instance.getNode(item.parentId);
|
|
71
|
+
if (item.disabled) {
|
|
74
72
|
return true;
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
return false;
|
|
78
76
|
}, [instance]);
|
|
79
|
-
const getChildrenIds =
|
|
80
|
-
const getNavigableChildrenIds =
|
|
81
|
-
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);
|
|
82
80
|
if (!params.disabledItemsFocusable) {
|
|
83
|
-
childrenIds = childrenIds.filter(
|
|
81
|
+
childrenIds = childrenIds.filter(item => !instance.isNodeDisabled(item));
|
|
84
82
|
}
|
|
85
83
|
return childrenIds;
|
|
86
84
|
};
|
|
@@ -104,21 +102,21 @@ export const useTreeViewNodes = ({
|
|
|
104
102
|
});
|
|
105
103
|
});
|
|
106
104
|
}, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
|
|
107
|
-
const getNodesToRender =
|
|
108
|
-
const
|
|
105
|
+
const getNodesToRender = () => {
|
|
106
|
+
const getPropsFromItemId = ({
|
|
109
107
|
id,
|
|
110
108
|
children
|
|
111
109
|
}) => {
|
|
112
110
|
const node = state.nodes.nodeMap[id];
|
|
113
111
|
return {
|
|
114
112
|
label: node.label,
|
|
115
|
-
|
|
113
|
+
itemId: node.id,
|
|
116
114
|
id: node.idAttribute,
|
|
117
|
-
children: children
|
|
115
|
+
children: children?.map(getPropsFromItemId)
|
|
118
116
|
};
|
|
119
117
|
};
|
|
120
|
-
return state.nodes.nodeTree.map(
|
|
121
|
-
}
|
|
118
|
+
return state.nodes.nodeTree.map(getPropsFromItemId);
|
|
119
|
+
};
|
|
122
120
|
populateInstance(instance, {
|
|
123
121
|
getNode,
|
|
124
122
|
getItem,
|
|
@@ -144,12 +142,9 @@ useTreeViewNodes.getInitialState = params => ({
|
|
|
144
142
|
getItemLabel: params.getItemLabel
|
|
145
143
|
})
|
|
146
144
|
});
|
|
147
|
-
useTreeViewNodes.getDefaultizedParams = params => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
disabledItemsFocusable: (_params$disabledItems = params.disabledItemsFocusable) != null ? _params$disabledItems : false
|
|
151
|
-
});
|
|
152
|
-
};
|
|
145
|
+
useTreeViewNodes.getDefaultizedParams = params => _extends({}, params, {
|
|
146
|
+
disabledItemsFocusable: params.disabledItemsFocusable ?? false
|
|
147
|
+
});
|
|
153
148
|
useTreeViewNodes.params = {
|
|
154
149
|
disabledItemsFocusable: true,
|
|
155
150
|
items: true,
|
|
@@ -2,17 +2,17 @@ import { TreeViewNode, DefaultizedProps, TreeViewPluginSignature } from '../../m
|
|
|
2
2
|
import { TreeViewItemId } from '../../../models';
|
|
3
3
|
interface TreeViewNodeProps {
|
|
4
4
|
label: string;
|
|
5
|
-
|
|
5
|
+
itemId: string;
|
|
6
6
|
id: string | undefined;
|
|
7
7
|
children?: TreeViewNodeProps[];
|
|
8
8
|
}
|
|
9
9
|
export interface UseTreeViewNodesInstance<R extends {}> {
|
|
10
|
-
getNode: (
|
|
11
|
-
getItem: (
|
|
10
|
+
getNode: (itemId: string) => TreeViewNode;
|
|
11
|
+
getItem: (itemId: string) => R;
|
|
12
12
|
getNodesToRender: () => TreeViewNodeProps[];
|
|
13
|
-
getChildrenIds: (
|
|
14
|
-
getNavigableChildrenIds: (
|
|
15
|
-
isNodeDisabled: (
|
|
13
|
+
getChildrenIds: (itemId: string | null) => string[];
|
|
14
|
+
getNavigableChildrenIds: (itemId: string | null) => string[];
|
|
15
|
+
isNodeDisabled: (itemId: string | null) => itemId is string;
|
|
16
16
|
}
|
|
17
17
|
export interface UseTreeViewNodesPublicAPI<R extends {}> extends Pick<UseTreeViewNodesInstance<R>, 'getItem'> {
|
|
18
18
|
}
|
|
@@ -57,13 +57,13 @@ interface UseTreeViewNodesEventLookup {
|
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
export interface
|
|
60
|
+
export interface TreeViewItemIdAndChildren {
|
|
61
61
|
id: TreeViewItemId;
|
|
62
|
-
children?:
|
|
62
|
+
children?: TreeViewItemIdAndChildren[];
|
|
63
63
|
}
|
|
64
64
|
export interface UseTreeViewNodesState<R extends {}> {
|
|
65
65
|
nodes: {
|
|
66
|
-
nodeTree:
|
|
66
|
+
nodeTree: TreeViewItemIdAndChildren[];
|
|
67
67
|
nodeMap: TreeViewNodeMap;
|
|
68
68
|
itemMap: TreeViewItemMap<R>;
|
|
69
69
|
};
|
|
@@ -80,9 +80,9 @@ export type UseTreeViewNodesSignature = TreeViewPluginSignature<{
|
|
|
80
80
|
contextValue: UseTreeViewNodesContextValue;
|
|
81
81
|
}>;
|
|
82
82
|
export type TreeViewNodeMap = {
|
|
83
|
-
[
|
|
83
|
+
[itemId: string]: TreeViewNode;
|
|
84
84
|
};
|
|
85
85
|
export type TreeViewItemMap<R extends {}> = {
|
|
86
|
-
[
|
|
86
|
+
[itemId: string]: R;
|
|
87
87
|
};
|
|
88
88
|
export {};
|