@mui/x-tree-view 7.0.0-beta.5 → 7.0.0-beta.7
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 +252 -50
- package/RichTreeView/RichTreeView.js +23 -22
- package/RichTreeView/RichTreeView.types.d.ts +2 -1
- package/SimpleTreeView/SimpleTreeView.js +23 -22
- package/TreeItem/TreeItem.js +79 -79
- package/TreeItem/TreeItem.types.d.ts +17 -19
- package/TreeItem/treeItemClasses.d.ts +1 -1
- package/TreeItem/treeItemClasses.js +1 -1
- package/TreeItem/useTreeItemState.js +2 -2
- package/TreeItem2/TreeItem2.d.ts +18 -0
- package/TreeItem2/TreeItem2.js +301 -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 +68 -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.js +23 -22
- 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/hooks/useTreeViewApiRef.d.ts +2 -2
- 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/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/helpers.d.ts +1 -0
- package/internals/models/plugin.d.ts +19 -16
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +25 -25
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +11 -11
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +12 -12
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +5 -6
- package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +37 -23
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +11 -9
- package/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +31 -18
- package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +16 -6
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +34 -34
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +11 -11
- package/internals/useTreeView/useTreeView.js +27 -25
- package/modern/RichTreeView/RichTreeView.js +23 -22
- package/modern/SimpleTreeView/SimpleTreeView.js +23 -22
- package/modern/TreeItem/TreeItem.js +78 -78
- package/modern/TreeItem/treeItemClasses.js +1 -1
- package/modern/TreeItem/useTreeItemState.js +2 -2
- 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 -22
- 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 +24 -24
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +12 -12
- package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +36 -22
- package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +11 -9
- package/modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +31 -18
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +34 -34
- package/modern/internals/useTreeView/useTreeView.js +27 -25
- package/modern/useTreeItem2/index.js +1 -0
- package/modern/useTreeItem2/useTreeItem2.js +135 -0
- package/modern/useTreeItem2/useTreeItem2.types.js +1 -0
- package/node/RichTreeView/RichTreeView.js +23 -22
- package/node/SimpleTreeView/SimpleTreeView.js +23 -22
- package/node/TreeItem/TreeItem.js +78 -78
- package/node/TreeItem/treeItemClasses.js +1 -1
- package/node/TreeItem/useTreeItemState.js +2 -2
- 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 -22
- 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 +24 -24
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +12 -12
- package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +36 -22
- package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +11 -9
- package/node/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +30 -17
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +34 -34
- package/node/internals/useTreeView/useTreeView.js +27 -25
- package/node/useTreeItem2/index.js +12 -0
- package/node/useTreeItem2/useTreeItem2.js +143 -0
- package/node/useTreeItem2/useTreeItem2.types.js +5 -0
- package/package.json +2 -2
- 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 +138 -0
- package/useTreeItem2/useTreeItem2.types.d.ts +113 -0
- package/useTreeItem2/useTreeItem2.types.js +1 -0
|
@@ -7,42 +7,42 @@ export const useTreeViewExpansion = ({
|
|
|
7
7
|
params,
|
|
8
8
|
models
|
|
9
9
|
}) => {
|
|
10
|
-
const
|
|
11
|
-
params.
|
|
12
|
-
models.
|
|
10
|
+
const setExpandedItems = (event, value) => {
|
|
11
|
+
params.onExpandedItemsChange?.(event, value);
|
|
12
|
+
models.expandedItems.setControlledValue(value);
|
|
13
13
|
};
|
|
14
14
|
const isNodeExpanded = React.useCallback(nodeId => {
|
|
15
|
-
return Array.isArray(models.
|
|
16
|
-
}, [models.
|
|
15
|
+
return Array.isArray(models.expandedItems.value) ? models.expandedItems.value.indexOf(nodeId) !== -1 : false;
|
|
16
|
+
}, [models.expandedItems.value]);
|
|
17
17
|
const isNodeExpandable = React.useCallback(nodeId => !!instance.getNode(nodeId)?.expandable, [instance]);
|
|
18
|
-
const toggleNodeExpansion = useEventCallback((event,
|
|
19
|
-
if (
|
|
18
|
+
const toggleNodeExpansion = useEventCallback((event, itemId) => {
|
|
19
|
+
if (itemId == null) {
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
const isExpandedBefore = models.
|
|
22
|
+
const isExpandedBefore = models.expandedItems.value.indexOf(itemId) !== -1;
|
|
23
23
|
let newExpanded;
|
|
24
24
|
if (isExpandedBefore) {
|
|
25
|
-
newExpanded = models.
|
|
25
|
+
newExpanded = models.expandedItems.value.filter(id => id !== itemId);
|
|
26
26
|
} else {
|
|
27
|
-
newExpanded = [
|
|
27
|
+
newExpanded = [itemId].concat(models.expandedItems.value);
|
|
28
28
|
}
|
|
29
|
-
if (params.
|
|
30
|
-
params.
|
|
29
|
+
if (params.onItemExpansionToggle) {
|
|
30
|
+
params.onItemExpansionToggle(event, itemId, !isExpandedBefore);
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
setExpandedItems(event, newExpanded);
|
|
33
33
|
});
|
|
34
34
|
const expandAllSiblings = (event, nodeId) => {
|
|
35
35
|
const node = instance.getNode(nodeId);
|
|
36
36
|
const siblings = instance.getChildrenIds(node.parentId);
|
|
37
37
|
const diff = siblings.filter(child => instance.isNodeExpandable(child) && !instance.isNodeExpanded(child));
|
|
38
|
-
const newExpanded = models.
|
|
38
|
+
const newExpanded = models.expandedItems.value.concat(diff);
|
|
39
39
|
if (diff.length > 0) {
|
|
40
|
-
if (params.
|
|
40
|
+
if (params.onItemExpansionToggle) {
|
|
41
41
|
diff.forEach(newlyExpandedNodeId => {
|
|
42
|
-
params.
|
|
42
|
+
params.onItemExpansionToggle(event, newlyExpandedNodeId, true);
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
setExpandedItems(event, newExpanded);
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
populateInstance(instance, {
|
|
@@ -53,17 +53,17 @@ export const useTreeViewExpansion = ({
|
|
|
53
53
|
});
|
|
54
54
|
};
|
|
55
55
|
useTreeViewExpansion.models = {
|
|
56
|
-
|
|
57
|
-
getDefaultValue: params => params.
|
|
56
|
+
expandedItems: {
|
|
57
|
+
getDefaultValue: params => params.defaultExpandedItems
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
const DEFAULT_EXPANDED_NODES = [];
|
|
61
61
|
useTreeViewExpansion.getDefaultizedParams = params => _extends({}, params, {
|
|
62
|
-
|
|
62
|
+
defaultExpandedItems: params.defaultExpandedItems ?? DEFAULT_EXPANDED_NODES
|
|
63
63
|
});
|
|
64
64
|
useTreeViewExpansion.params = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
expandedItems: true,
|
|
66
|
+
defaultExpandedItems: true,
|
|
67
|
+
onExpandedItemsChange: true,
|
|
68
|
+
onItemExpansionToggle: true
|
|
69
69
|
};
|
|
@@ -28,31 +28,31 @@ export const useTreeViewFocus = ({
|
|
|
28
28
|
const node = instance.getNode(nodeId);
|
|
29
29
|
return node && (node.parentId == null || instance.isNodeExpanded(node.parentId));
|
|
30
30
|
};
|
|
31
|
-
const
|
|
31
|
+
const focusItem = useEventCallback((event, nodeId) => {
|
|
32
32
|
// if we receive a nodeId, and it is visible, the focus will be set to it
|
|
33
33
|
if (nodeId && isNodeVisible(nodeId)) {
|
|
34
34
|
if (!isTreeViewFocused()) {
|
|
35
35
|
instance.focusRoot();
|
|
36
36
|
}
|
|
37
37
|
setFocusedNodeId(nodeId);
|
|
38
|
-
if (params.
|
|
39
|
-
params.
|
|
38
|
+
if (params.onItemFocus) {
|
|
39
|
+
params.onItemFocus(event, nodeId);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
const focusDefaultNode = useEventCallback(event => {
|
|
44
44
|
let nodeToFocusId;
|
|
45
|
-
if (Array.isArray(models.
|
|
46
|
-
nodeToFocusId = models.
|
|
47
|
-
} else if (models.
|
|
48
|
-
nodeToFocusId = models.
|
|
45
|
+
if (Array.isArray(models.selectedItems.value)) {
|
|
46
|
+
nodeToFocusId = models.selectedItems.value.find(isNodeVisible);
|
|
47
|
+
} else if (models.selectedItems.value != null && isNodeVisible(models.selectedItems.value)) {
|
|
48
|
+
nodeToFocusId = models.selectedItems.value;
|
|
49
49
|
}
|
|
50
50
|
if (nodeToFocusId == null) {
|
|
51
51
|
nodeToFocusId = instance.getNavigableChildrenIds(null)[0];
|
|
52
52
|
}
|
|
53
53
|
setFocusedNodeId(nodeToFocusId);
|
|
54
|
-
if (params.
|
|
55
|
-
params.
|
|
54
|
+
if (params.onItemFocus) {
|
|
55
|
+
params.onItemFocus(event, nodeToFocusId);
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
const focusRoot = useEventCallback(() => {
|
|
@@ -62,12 +62,12 @@ export const useTreeViewFocus = ({
|
|
|
62
62
|
});
|
|
63
63
|
populateInstance(instance, {
|
|
64
64
|
isNodeFocused,
|
|
65
|
-
|
|
65
|
+
focusItem,
|
|
66
66
|
focusRoot,
|
|
67
67
|
focusDefaultNode
|
|
68
68
|
});
|
|
69
69
|
populatePublicAPI(publicAPI, {
|
|
70
|
-
|
|
70
|
+
focusItem
|
|
71
71
|
});
|
|
72
72
|
useInstanceEventHandler(instance, 'removeNode', ({
|
|
73
73
|
id
|
|
@@ -104,5 +104,5 @@ useTreeViewFocus.getInitialState = () => ({
|
|
|
104
104
|
focusedNodeId: null
|
|
105
105
|
});
|
|
106
106
|
useTreeViewFocus.params = {
|
|
107
|
-
|
|
107
|
+
onItemFocus: true
|
|
108
108
|
};
|
|
@@ -13,22 +13,36 @@ export const useTreeViewJSXNodes = ({
|
|
|
13
13
|
}) => {
|
|
14
14
|
const insertJSXNode = useEventCallback(node => {
|
|
15
15
|
setState(prevState => {
|
|
16
|
-
if (prevState.nodeMap[node.id] != null) {
|
|
16
|
+
if (prevState.nodes.nodeMap[node.id] != null) {
|
|
17
17
|
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.', `Tow items were provided with the same id in the \`items\` prop: "${node.id}"`].join('\n'));
|
|
18
18
|
}
|
|
19
19
|
return _extends({}, prevState, {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
nodes: _extends({}, prevState.nodes, {
|
|
21
|
+
nodeMap: _extends({}, prevState.nodes.nodeMap, {
|
|
22
|
+
[node.id]: node
|
|
23
|
+
}),
|
|
24
|
+
// For `SimpleTreeView`, we don't have a proper `item` object, so we create a very basic one.
|
|
25
|
+
itemMap: _extends({}, prevState.nodes.itemMap, {
|
|
26
|
+
[node.id]: {
|
|
27
|
+
id: node.id,
|
|
28
|
+
label: node.label
|
|
29
|
+
}
|
|
30
|
+
})
|
|
22
31
|
})
|
|
23
32
|
});
|
|
24
33
|
});
|
|
25
34
|
});
|
|
26
35
|
const removeJSXNode = useEventCallback(nodeId => {
|
|
27
36
|
setState(prevState => {
|
|
28
|
-
const
|
|
29
|
-
|
|
37
|
+
const newNodeMap = _extends({}, prevState.nodes.nodeMap);
|
|
38
|
+
const newItemMap = _extends({}, prevState.nodes.itemMap);
|
|
39
|
+
delete newNodeMap[nodeId];
|
|
40
|
+
delete newItemMap[nodeId];
|
|
30
41
|
return _extends({}, prevState, {
|
|
31
|
-
|
|
42
|
+
nodes: _extends({}, prevState.nodes, {
|
|
43
|
+
nodeMap: newNodeMap,
|
|
44
|
+
itemMap: newItemMap
|
|
45
|
+
})
|
|
32
46
|
});
|
|
33
47
|
});
|
|
34
48
|
publishTreeViewEvent(instance, 'removeNode', {
|
|
@@ -56,15 +70,15 @@ export const useTreeViewJSXNodes = ({
|
|
|
56
70
|
};
|
|
57
71
|
const useTreeViewJSXNodesItemPlugin = ({
|
|
58
72
|
props,
|
|
59
|
-
|
|
73
|
+
rootRef,
|
|
74
|
+
contentRef
|
|
60
75
|
}) => {
|
|
61
76
|
const {
|
|
62
77
|
children,
|
|
63
78
|
disabled = false,
|
|
64
79
|
label,
|
|
65
80
|
nodeId,
|
|
66
|
-
id
|
|
67
|
-
ContentProps: inContentProps
|
|
81
|
+
id
|
|
68
82
|
} = props;
|
|
69
83
|
const {
|
|
70
84
|
instance
|
|
@@ -77,8 +91,9 @@ const useTreeViewJSXNodesItemPlugin = ({
|
|
|
77
91
|
};
|
|
78
92
|
const expandable = isExpandable(children);
|
|
79
93
|
const [treeItemElement, setTreeItemElement] = React.useState(null);
|
|
80
|
-
const
|
|
81
|
-
const
|
|
94
|
+
const pluginContentRef = React.useRef(null);
|
|
95
|
+
const handleRootRef = useForkRef(setTreeItemElement, rootRef);
|
|
96
|
+
const handleContentRef = useForkRef(pluginContentRef, contentRef);
|
|
82
97
|
const descendant = React.useMemo(() => ({
|
|
83
98
|
element: treeItemElement,
|
|
84
99
|
id: nodeId
|
|
@@ -104,22 +119,21 @@ const useTreeViewJSXNodesItemPlugin = ({
|
|
|
104
119
|
}, [instance, parentId, index, nodeId, expandable, disabled, id]);
|
|
105
120
|
React.useEffect(() => {
|
|
106
121
|
if (label) {
|
|
107
|
-
return instance.mapFirstCharFromJSX(nodeId, (
|
|
122
|
+
return instance.mapFirstCharFromJSX(nodeId, (pluginContentRef.current?.textContent ?? '').substring(0, 1).toLowerCase());
|
|
108
123
|
}
|
|
109
124
|
return undefined;
|
|
110
125
|
}, [instance, nodeId, label]);
|
|
111
126
|
return {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
ref: contentRef
|
|
115
|
-
})
|
|
116
|
-
}),
|
|
117
|
-
ref: handleRef,
|
|
118
|
-
wrapItem: item => /*#__PURE__*/_jsx(DescendantProvider, {
|
|
119
|
-
id: nodeId,
|
|
120
|
-
children: item
|
|
121
|
-
})
|
|
127
|
+
contentRef: handleContentRef,
|
|
128
|
+
rootRef: handleRootRef
|
|
122
129
|
};
|
|
123
130
|
};
|
|
124
131
|
useTreeViewJSXNodes.itemPlugin = useTreeViewJSXNodesItemPlugin;
|
|
132
|
+
useTreeViewJSXNodes.wrapItem = ({
|
|
133
|
+
children,
|
|
134
|
+
nodeId
|
|
135
|
+
}) => /*#__PURE__*/_jsx(DescendantProvider, {
|
|
136
|
+
id: nodeId,
|
|
137
|
+
children: children
|
|
138
|
+
});
|
|
125
139
|
useTreeViewJSXNodes.params = {};
|
package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js
CHANGED
|
@@ -81,7 +81,9 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
81
81
|
return null;
|
|
82
82
|
};
|
|
83
83
|
const canToggleNodeSelection = nodeId => !params.disableSelection && !instance.isNodeDisabled(nodeId);
|
|
84
|
-
const canToggleNodeExpansion = nodeId =>
|
|
84
|
+
const canToggleNodeExpansion = nodeId => {
|
|
85
|
+
return !instance.isNodeDisabled(nodeId) && instance.isNodeExpandable(nodeId);
|
|
86
|
+
};
|
|
85
87
|
|
|
86
88
|
// ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
|
|
87
89
|
const createHandleKeyDown = otherHandlers => event => {
|
|
@@ -90,7 +92,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
90
92
|
return;
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
// If the tree is empty there will be no focused node
|
|
95
|
+
// If the tree is empty, there will be no focused node
|
|
94
96
|
if (event.altKey || event.currentTarget !== event.target || state.focusedNodeId == null) {
|
|
95
97
|
return;
|
|
96
98
|
}
|
|
@@ -140,7 +142,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
140
142
|
const nextNode = getNextNode(instance, state.focusedNodeId);
|
|
141
143
|
if (nextNode) {
|
|
142
144
|
event.preventDefault();
|
|
143
|
-
instance.
|
|
145
|
+
instance.focusItem(event, nextNode);
|
|
144
146
|
|
|
145
147
|
// Multi select behavior when pressing Shift + ArrowDown
|
|
146
148
|
// Toggles the selection state of the next node
|
|
@@ -160,7 +162,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
160
162
|
const previousNode = getPreviousNode(instance, state.focusedNodeId);
|
|
161
163
|
if (previousNode) {
|
|
162
164
|
event.preventDefault();
|
|
163
|
-
instance.
|
|
165
|
+
instance.focusItem(event, previousNode);
|
|
164
166
|
|
|
165
167
|
// Multi select behavior when pressing Shift + ArrowUp
|
|
166
168
|
// Toggles the selection state of the previous node
|
|
@@ -179,7 +181,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
179
181
|
case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
|
|
180
182
|
{
|
|
181
183
|
if (instance.isNodeExpanded(state.focusedNodeId)) {
|
|
182
|
-
instance.
|
|
184
|
+
instance.focusItem(event, getNextNode(instance, state.focusedNodeId));
|
|
183
185
|
event.preventDefault();
|
|
184
186
|
} else if (canToggleNodeExpansion(state.focusedNodeId)) {
|
|
185
187
|
instance.toggleNodeExpansion(event, state.focusedNodeId);
|
|
@@ -198,7 +200,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
198
200
|
} else {
|
|
199
201
|
const parent = instance.getNode(state.focusedNodeId).parentId;
|
|
200
202
|
if (parent) {
|
|
201
|
-
instance.
|
|
203
|
+
instance.focusItem(event, parent);
|
|
202
204
|
event.preventDefault();
|
|
203
205
|
}
|
|
204
206
|
}
|
|
@@ -208,7 +210,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
208
210
|
// Focuses the first node in the tree
|
|
209
211
|
case key === 'Home':
|
|
210
212
|
{
|
|
211
|
-
instance.
|
|
213
|
+
instance.focusItem(event, getFirstNode(instance));
|
|
212
214
|
|
|
213
215
|
// Multi select behavior when pressing Ctrl + Shift + Home
|
|
214
216
|
// Selects the focused node and all nodes up to the first node.
|
|
@@ -222,7 +224,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
222
224
|
// Focuses the last node in the tree
|
|
223
225
|
case key === 'End':
|
|
224
226
|
{
|
|
225
|
-
instance.
|
|
227
|
+
instance.focusItem(event, getLastNode(instance));
|
|
226
228
|
|
|
227
229
|
// Multi select behavior when pressing Ctrl + Shirt + End
|
|
228
230
|
// Selects the focused node and all the nodes down to the last node.
|
|
@@ -259,7 +261,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
259
261
|
{
|
|
260
262
|
const matchingNode = getFirstMatchingNode(state.focusedNodeId, key);
|
|
261
263
|
if (matchingNode != null) {
|
|
262
|
-
instance.
|
|
264
|
+
instance.focusItem(event, matchingNode);
|
|
263
265
|
event.preventDefault();
|
|
264
266
|
}
|
|
265
267
|
break;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import useEventCallback from '@mui/utils/useEventCallback';
|
|
4
|
-
import { populateInstance } from '../../useTreeView/useTreeView.utils';
|
|
4
|
+
import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
|
|
5
5
|
import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
|
|
6
|
-
const
|
|
6
|
+
const updateNodesState = ({
|
|
7
7
|
items,
|
|
8
8
|
isItemDisabled,
|
|
9
9
|
getItemLabel,
|
|
10
10
|
getItemId
|
|
11
11
|
}) => {
|
|
12
12
|
const nodeMap = {};
|
|
13
|
+
const itemMap = {};
|
|
13
14
|
const processItem = (item, index, parentId) => {
|
|
14
15
|
const id = getItemId ? getItemId(item) : item.id;
|
|
15
16
|
if (id == null) {
|
|
@@ -27,10 +28,11 @@ const updateState = ({
|
|
|
27
28
|
label,
|
|
28
29
|
index,
|
|
29
30
|
parentId,
|
|
30
|
-
idAttribute:
|
|
31
|
+
idAttribute: undefined,
|
|
31
32
|
expandable: !!item.children?.length,
|
|
32
33
|
disabled: isItemDisabled ? isItemDisabled(item) : false
|
|
33
34
|
};
|
|
35
|
+
itemMap[id] = item;
|
|
34
36
|
return {
|
|
35
37
|
id,
|
|
36
38
|
children: item.children?.map((child, childIndex) => processItem(child, childIndex, id))
|
|
@@ -39,16 +41,19 @@ const updateState = ({
|
|
|
39
41
|
const nodeTree = items.map((item, itemIndex) => processItem(item, itemIndex, null));
|
|
40
42
|
return {
|
|
41
43
|
nodeMap,
|
|
42
|
-
nodeTree
|
|
44
|
+
nodeTree,
|
|
45
|
+
itemMap
|
|
43
46
|
};
|
|
44
47
|
};
|
|
45
48
|
export const useTreeViewNodes = ({
|
|
46
49
|
instance,
|
|
50
|
+
publicAPI,
|
|
47
51
|
params,
|
|
48
52
|
state,
|
|
49
53
|
setState
|
|
50
54
|
}) => {
|
|
51
|
-
const getNode = React.useCallback(nodeId => state.nodeMap[nodeId], [state.nodeMap]);
|
|
55
|
+
const getNode = React.useCallback(nodeId => state.nodes.nodeMap[nodeId], [state.nodes.nodeMap]);
|
|
56
|
+
const getItem = React.useCallback(nodeId => state.nodes.itemMap[nodeId], [state.nodes.itemMap]);
|
|
52
57
|
const isNodeDisabled = React.useCallback(nodeId => {
|
|
53
58
|
if (nodeId == null) {
|
|
54
59
|
return false;
|
|
@@ -70,7 +75,7 @@ export const useTreeViewNodes = ({
|
|
|
70
75
|
}
|
|
71
76
|
return false;
|
|
72
77
|
}, [instance]);
|
|
73
|
-
const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
|
|
78
|
+
const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodes.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
|
|
74
79
|
const getNavigableChildrenIds = nodeId => {
|
|
75
80
|
let childrenIds = instance.getChildrenIds(nodeId);
|
|
76
81
|
if (!params.disabledItemsFocusable) {
|
|
@@ -80,28 +85,30 @@ export const useTreeViewNodes = ({
|
|
|
80
85
|
};
|
|
81
86
|
React.useEffect(() => {
|
|
82
87
|
setState(prevState => {
|
|
83
|
-
const newState =
|
|
88
|
+
const newState = updateNodesState({
|
|
84
89
|
items: params.items,
|
|
85
90
|
isItemDisabled: params.isItemDisabled,
|
|
86
91
|
getItemId: params.getItemId,
|
|
87
92
|
getItemLabel: params.getItemLabel
|
|
88
93
|
});
|
|
89
|
-
Object.values(prevState.nodeMap).forEach(node => {
|
|
94
|
+
Object.values(prevState.nodes.nodeMap).forEach(node => {
|
|
90
95
|
if (!newState.nodeMap[node.id]) {
|
|
91
96
|
publishTreeViewEvent(instance, 'removeNode', {
|
|
92
97
|
id: node.id
|
|
93
98
|
});
|
|
94
99
|
}
|
|
95
100
|
});
|
|
96
|
-
return _extends({}, prevState,
|
|
101
|
+
return _extends({}, prevState, {
|
|
102
|
+
nodes: newState
|
|
103
|
+
});
|
|
97
104
|
});
|
|
98
105
|
}, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
|
|
99
|
-
const getNodesToRender =
|
|
106
|
+
const getNodesToRender = () => {
|
|
100
107
|
const getPropsFromNodeId = ({
|
|
101
108
|
id,
|
|
102
109
|
children
|
|
103
110
|
}) => {
|
|
104
|
-
const node = state.nodeMap[id];
|
|
111
|
+
const node = state.nodes.nodeMap[id];
|
|
105
112
|
return {
|
|
106
113
|
label: node.label,
|
|
107
114
|
nodeId: node.id,
|
|
@@ -109,26 +116,32 @@ export const useTreeViewNodes = ({
|
|
|
109
116
|
children: children?.map(getPropsFromNodeId)
|
|
110
117
|
};
|
|
111
118
|
};
|
|
112
|
-
return state.nodeTree.map(getPropsFromNodeId);
|
|
113
|
-
}
|
|
119
|
+
return state.nodes.nodeTree.map(getPropsFromNodeId);
|
|
120
|
+
};
|
|
114
121
|
populateInstance(instance, {
|
|
115
122
|
getNode,
|
|
123
|
+
getItem,
|
|
116
124
|
getNodesToRender,
|
|
117
125
|
getChildrenIds,
|
|
118
126
|
getNavigableChildrenIds,
|
|
119
127
|
isNodeDisabled
|
|
120
128
|
});
|
|
129
|
+
populatePublicAPI(publicAPI, {
|
|
130
|
+
getItem
|
|
131
|
+
});
|
|
121
132
|
return {
|
|
122
133
|
contextValue: {
|
|
123
134
|
disabledItemsFocusable: params.disabledItemsFocusable
|
|
124
135
|
}
|
|
125
136
|
};
|
|
126
137
|
};
|
|
127
|
-
useTreeViewNodes.getInitialState = params =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
useTreeViewNodes.getInitialState = params => ({
|
|
139
|
+
nodes: updateNodesState({
|
|
140
|
+
items: params.items,
|
|
141
|
+
isItemDisabled: params.isItemDisabled,
|
|
142
|
+
getItemId: params.getItemId,
|
|
143
|
+
getItemLabel: params.getItemLabel
|
|
144
|
+
})
|
|
132
145
|
});
|
|
133
146
|
useTreeViewNodes.getDefaultizedParams = params => _extends({}, params, {
|
|
134
147
|
disabledItemsFocusable: params.disabledItemsFocusable ?? false
|
|
@@ -10,49 +10,49 @@ 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 = nodeId => Array.isArray(models.
|
|
38
|
+
const isNodeSelected = nodeId => Array.isArray(models.selectedItems.value) ? models.selectedItems.value.indexOf(nodeId) !== -1 : models.selectedItems.value === nodeId;
|
|
39
39
|
const selectNode = (event, nodeId, 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(nodeId) !== -1) {
|
|
47
|
+
newSelected = models.selectedItems.value.filter(id => id !== nodeId);
|
|
48
48
|
} else {
|
|
49
|
-
newSelected = [nodeId].concat(models.
|
|
49
|
+
newSelected = [nodeId].concat(models.selectedItems.value);
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
setSelectedItems(event, newSelected);
|
|
52
52
|
}
|
|
53
53
|
} else {
|
|
54
54
|
const newSelected = params.multiSelect ? [nodeId] : nodeId;
|
|
55
|
-
|
|
55
|
+
setSelectedItems(event, newSelected);
|
|
56
56
|
}
|
|
57
57
|
lastSelectedNode.current = nodeId;
|
|
58
58
|
lastSelectionWasRange.current = false;
|
|
@@ -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) {
|
|
@@ -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
|
};
|