@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
|
@@ -6,21 +6,20 @@ import type { UseTreeViewSelectionSignature } from '../useTreeViewSelection';
|
|
|
6
6
|
import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
|
|
7
7
|
export interface UseTreeViewFocusInstance {
|
|
8
8
|
isNodeFocused: (nodeId: string) => boolean;
|
|
9
|
-
|
|
9
|
+
focusItem: (event: React.SyntheticEvent, itemId: string | null) => void;
|
|
10
10
|
focusDefaultNode: (event: React.SyntheticEvent) => void;
|
|
11
11
|
focusRoot: () => void;
|
|
12
12
|
}
|
|
13
|
-
export interface UseTreeViewFocusPublicAPI {
|
|
14
|
-
focusNode: (event: React.SyntheticEvent, nodeId: string | null) => void;
|
|
13
|
+
export interface UseTreeViewFocusPublicAPI extends Pick<UseTreeViewFocusInstance, 'focusItem'> {
|
|
15
14
|
}
|
|
16
15
|
export interface UseTreeViewFocusParameters {
|
|
17
16
|
/**
|
|
18
17
|
* Callback fired when tree items are focused.
|
|
19
18
|
* @param {React.SyntheticEvent} event The event source of the callback **Warning**: This is a generic event not a focus event.
|
|
20
|
-
* @param {string}
|
|
21
|
-
* @param {string} value of the focused
|
|
19
|
+
* @param {string} itemId The id of the focused item.
|
|
20
|
+
* @param {string} value of the focused item.
|
|
22
21
|
*/
|
|
23
|
-
|
|
22
|
+
onItemFocus?: (event: React.SyntheticEvent, itemId: string) => void;
|
|
24
23
|
}
|
|
25
24
|
export type UseTreeViewFocusDefaultizedParameters = UseTreeViewFocusParameters;
|
|
26
25
|
export interface UseTreeViewFocusState {
|
|
@@ -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,23 +119,22 @@ const useTreeViewJSXNodesItemPlugin = ({
|
|
|
104
119
|
}, [instance, parentId, index, nodeId, expandable, disabled, id]);
|
|
105
120
|
React.useEffect(() => {
|
|
106
121
|
if (label) {
|
|
107
|
-
var
|
|
108
|
-
return instance.mapFirstCharFromJSX(nodeId, ((
|
|
122
|
+
var _pluginContentRef$cur, _pluginContentRef$cur2;
|
|
123
|
+
return instance.mapFirstCharFromJSX(nodeId, ((_pluginContentRef$cur = (_pluginContentRef$cur2 = pluginContentRef.current) == null ? void 0 : _pluginContentRef$cur2.textContent) != null ? _pluginContentRef$cur : '').substring(0, 1).toLowerCase());
|
|
109
124
|
}
|
|
110
125
|
return undefined;
|
|
111
126
|
}, [instance, nodeId, label]);
|
|
112
127
|
return {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
ref: contentRef
|
|
116
|
-
})
|
|
117
|
-
}),
|
|
118
|
-
ref: handleRef,
|
|
119
|
-
wrapItem: item => /*#__PURE__*/_jsx(DescendantProvider, {
|
|
120
|
-
id: nodeId,
|
|
121
|
-
children: item
|
|
122
|
-
})
|
|
128
|
+
contentRef: handleContentRef,
|
|
129
|
+
rootRef: handleRootRef
|
|
123
130
|
};
|
|
124
131
|
};
|
|
125
132
|
useTreeViewJSXNodes.itemPlugin = useTreeViewJSXNodesItemPlugin;
|
|
133
|
+
useTreeViewJSXNodes.wrapItem = ({
|
|
134
|
+
children,
|
|
135
|
+
nodeId
|
|
136
|
+
}) => /*#__PURE__*/_jsx(DescendantProvider, {
|
|
137
|
+
id: nodeId,
|
|
138
|
+
children: children
|
|
139
|
+
});
|
|
126
140
|
useTreeViewJSXNodes.params = {};
|
|
@@ -82,7 +82,9 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
82
82
|
return null;
|
|
83
83
|
};
|
|
84
84
|
const canToggleNodeSelection = nodeId => !params.disableSelection && !instance.isNodeDisabled(nodeId);
|
|
85
|
-
const canToggleNodeExpansion = nodeId =>
|
|
85
|
+
const canToggleNodeExpansion = nodeId => {
|
|
86
|
+
return !instance.isNodeDisabled(nodeId) && instance.isNodeExpandable(nodeId);
|
|
87
|
+
};
|
|
86
88
|
|
|
87
89
|
// ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
|
|
88
90
|
const createHandleKeyDown = otherHandlers => event => {
|
|
@@ -92,7 +94,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
92
94
|
return;
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
// If the tree is empty there will be no focused node
|
|
97
|
+
// If the tree is empty, there will be no focused node
|
|
96
98
|
if (event.altKey || event.currentTarget !== event.target || state.focusedNodeId == null) {
|
|
97
99
|
return;
|
|
98
100
|
}
|
|
@@ -142,7 +144,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
142
144
|
const nextNode = getNextNode(instance, state.focusedNodeId);
|
|
143
145
|
if (nextNode) {
|
|
144
146
|
event.preventDefault();
|
|
145
|
-
instance.
|
|
147
|
+
instance.focusItem(event, nextNode);
|
|
146
148
|
|
|
147
149
|
// Multi select behavior when pressing Shift + ArrowDown
|
|
148
150
|
// Toggles the selection state of the next node
|
|
@@ -162,7 +164,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
162
164
|
const previousNode = getPreviousNode(instance, state.focusedNodeId);
|
|
163
165
|
if (previousNode) {
|
|
164
166
|
event.preventDefault();
|
|
165
|
-
instance.
|
|
167
|
+
instance.focusItem(event, previousNode);
|
|
166
168
|
|
|
167
169
|
// Multi select behavior when pressing Shift + ArrowUp
|
|
168
170
|
// Toggles the selection state of the previous node
|
|
@@ -181,7 +183,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
181
183
|
case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
|
|
182
184
|
{
|
|
183
185
|
if (instance.isNodeExpanded(state.focusedNodeId)) {
|
|
184
|
-
instance.
|
|
186
|
+
instance.focusItem(event, getNextNode(instance, state.focusedNodeId));
|
|
185
187
|
event.preventDefault();
|
|
186
188
|
} else if (canToggleNodeExpansion(state.focusedNodeId)) {
|
|
187
189
|
instance.toggleNodeExpansion(event, state.focusedNodeId);
|
|
@@ -200,7 +202,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
200
202
|
} else {
|
|
201
203
|
const parent = instance.getNode(state.focusedNodeId).parentId;
|
|
202
204
|
if (parent) {
|
|
203
|
-
instance.
|
|
205
|
+
instance.focusItem(event, parent);
|
|
204
206
|
event.preventDefault();
|
|
205
207
|
}
|
|
206
208
|
}
|
|
@@ -210,7 +212,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
210
212
|
// Focuses the first node in the tree
|
|
211
213
|
case key === 'Home':
|
|
212
214
|
{
|
|
213
|
-
instance.
|
|
215
|
+
instance.focusItem(event, getFirstNode(instance));
|
|
214
216
|
|
|
215
217
|
// Multi select behavior when pressing Ctrl + Shift + Home
|
|
216
218
|
// Selects the focused node and all nodes up to the first node.
|
|
@@ -224,7 +226,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
224
226
|
// Focuses the last node in the tree
|
|
225
227
|
case key === 'End':
|
|
226
228
|
{
|
|
227
|
-
instance.
|
|
229
|
+
instance.focusItem(event, getLastNode(instance));
|
|
228
230
|
|
|
229
231
|
// Multi select behavior when pressing Ctrl + Shirt + End
|
|
230
232
|
// Selects the focused node and all the nodes down to the last node.
|
|
@@ -261,7 +263,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
261
263
|
{
|
|
262
264
|
const matchingNode = getFirstMatchingNode(state.focusedNodeId, key);
|
|
263
265
|
if (matchingNode != null) {
|
|
264
|
-
instance.
|
|
266
|
+
instance.focusItem(event, matchingNode);
|
|
265
267
|
event.preventDefault();
|
|
266
268
|
}
|
|
267
269
|
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
|
var _item$children, _item$children2;
|
|
15
16
|
const id = getItemId ? getItemId(item) : item.id;
|
|
@@ -28,10 +29,11 @@ const updateState = ({
|
|
|
28
29
|
label,
|
|
29
30
|
index,
|
|
30
31
|
parentId,
|
|
31
|
-
idAttribute:
|
|
32
|
+
idAttribute: undefined,
|
|
32
33
|
expandable: !!((_item$children = item.children) != null && _item$children.length),
|
|
33
34
|
disabled: isItemDisabled ? isItemDisabled(item) : false
|
|
34
35
|
};
|
|
36
|
+
itemMap[id] = item;
|
|
35
37
|
return {
|
|
36
38
|
id,
|
|
37
39
|
children: (_item$children2 = item.children) == null ? void 0 : _item$children2.map((child, childIndex) => processItem(child, childIndex, id))
|
|
@@ -40,16 +42,19 @@ const updateState = ({
|
|
|
40
42
|
const nodeTree = items.map((item, itemIndex) => processItem(item, itemIndex, null));
|
|
41
43
|
return {
|
|
42
44
|
nodeMap,
|
|
43
|
-
nodeTree
|
|
45
|
+
nodeTree,
|
|
46
|
+
itemMap
|
|
44
47
|
};
|
|
45
48
|
};
|
|
46
49
|
export const useTreeViewNodes = ({
|
|
47
50
|
instance,
|
|
51
|
+
publicAPI,
|
|
48
52
|
params,
|
|
49
53
|
state,
|
|
50
54
|
setState
|
|
51
55
|
}) => {
|
|
52
|
-
const getNode = React.useCallback(nodeId => state.nodeMap[nodeId], [state.nodeMap]);
|
|
56
|
+
const getNode = React.useCallback(nodeId => state.nodes.nodeMap[nodeId], [state.nodes.nodeMap]);
|
|
57
|
+
const getItem = React.useCallback(nodeId => state.nodes.itemMap[nodeId], [state.nodes.itemMap]);
|
|
53
58
|
const isNodeDisabled = React.useCallback(nodeId => {
|
|
54
59
|
if (nodeId == null) {
|
|
55
60
|
return false;
|
|
@@ -71,7 +76,7 @@ export const useTreeViewNodes = ({
|
|
|
71
76
|
}
|
|
72
77
|
return false;
|
|
73
78
|
}, [instance]);
|
|
74
|
-
const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
|
|
79
|
+
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));
|
|
75
80
|
const getNavigableChildrenIds = nodeId => {
|
|
76
81
|
let childrenIds = instance.getChildrenIds(nodeId);
|
|
77
82
|
if (!params.disabledItemsFocusable) {
|
|
@@ -81,28 +86,30 @@ export const useTreeViewNodes = ({
|
|
|
81
86
|
};
|
|
82
87
|
React.useEffect(() => {
|
|
83
88
|
setState(prevState => {
|
|
84
|
-
const newState =
|
|
89
|
+
const newState = updateNodesState({
|
|
85
90
|
items: params.items,
|
|
86
91
|
isItemDisabled: params.isItemDisabled,
|
|
87
92
|
getItemId: params.getItemId,
|
|
88
93
|
getItemLabel: params.getItemLabel
|
|
89
94
|
});
|
|
90
|
-
Object.values(prevState.nodeMap).forEach(node => {
|
|
95
|
+
Object.values(prevState.nodes.nodeMap).forEach(node => {
|
|
91
96
|
if (!newState.nodeMap[node.id]) {
|
|
92
97
|
publishTreeViewEvent(instance, 'removeNode', {
|
|
93
98
|
id: node.id
|
|
94
99
|
});
|
|
95
100
|
}
|
|
96
101
|
});
|
|
97
|
-
return _extends({}, prevState,
|
|
102
|
+
return _extends({}, prevState, {
|
|
103
|
+
nodes: newState
|
|
104
|
+
});
|
|
98
105
|
});
|
|
99
106
|
}, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
|
|
100
|
-
const getNodesToRender =
|
|
107
|
+
const getNodesToRender = () => {
|
|
101
108
|
const getPropsFromNodeId = ({
|
|
102
109
|
id,
|
|
103
110
|
children
|
|
104
111
|
}) => {
|
|
105
|
-
const node = state.nodeMap[id];
|
|
112
|
+
const node = state.nodes.nodeMap[id];
|
|
106
113
|
return {
|
|
107
114
|
label: node.label,
|
|
108
115
|
nodeId: node.id,
|
|
@@ -110,26 +117,32 @@ export const useTreeViewNodes = ({
|
|
|
110
117
|
children: children == null ? void 0 : children.map(getPropsFromNodeId)
|
|
111
118
|
};
|
|
112
119
|
};
|
|
113
|
-
return state.nodeTree.map(getPropsFromNodeId);
|
|
114
|
-
}
|
|
120
|
+
return state.nodes.nodeTree.map(getPropsFromNodeId);
|
|
121
|
+
};
|
|
115
122
|
populateInstance(instance, {
|
|
116
123
|
getNode,
|
|
124
|
+
getItem,
|
|
117
125
|
getNodesToRender,
|
|
118
126
|
getChildrenIds,
|
|
119
127
|
getNavigableChildrenIds,
|
|
120
128
|
isNodeDisabled
|
|
121
129
|
});
|
|
130
|
+
populatePublicAPI(publicAPI, {
|
|
131
|
+
getItem
|
|
132
|
+
});
|
|
122
133
|
return {
|
|
123
134
|
contextValue: {
|
|
124
135
|
disabledItemsFocusable: params.disabledItemsFocusable
|
|
125
136
|
}
|
|
126
137
|
};
|
|
127
138
|
};
|
|
128
|
-
useTreeViewNodes.getInitialState = params =>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
useTreeViewNodes.getInitialState = params => ({
|
|
140
|
+
nodes: updateNodesState({
|
|
141
|
+
items: params.items,
|
|
142
|
+
isItemDisabled: params.isItemDisabled,
|
|
143
|
+
getItemId: params.getItemId,
|
|
144
|
+
getItemLabel: params.getItemLabel
|
|
145
|
+
})
|
|
133
146
|
});
|
|
134
147
|
useTreeViewNodes.getDefaultizedParams = params => {
|
|
135
148
|
var _params$disabledItems;
|
|
@@ -6,13 +6,16 @@ interface TreeViewNodeProps {
|
|
|
6
6
|
id: string | undefined;
|
|
7
7
|
children?: TreeViewNodeProps[];
|
|
8
8
|
}
|
|
9
|
-
export interface UseTreeViewNodesInstance {
|
|
9
|
+
export interface UseTreeViewNodesInstance<R extends {}> {
|
|
10
10
|
getNode: (nodeId: string) => TreeViewNode;
|
|
11
|
+
getItem: (nodeId: string) => R;
|
|
11
12
|
getNodesToRender: () => TreeViewNodeProps[];
|
|
12
13
|
getChildrenIds: (nodeId: string | null) => string[];
|
|
13
14
|
getNavigableChildrenIds: (nodeId: string | null) => string[];
|
|
14
15
|
isNodeDisabled: (nodeId: string | null) => nodeId is string;
|
|
15
16
|
}
|
|
17
|
+
export interface UseTreeViewNodesPublicAPI<R extends {}> extends Pick<UseTreeViewNodesInstance<R>, 'getItem'> {
|
|
18
|
+
}
|
|
16
19
|
export interface UseTreeViewNodesParameters<R extends {}> {
|
|
17
20
|
/**
|
|
18
21
|
* If `true`, will allow focus on disabled items.
|
|
@@ -58,21 +61,28 @@ export interface TreeViewNodeIdAndChildren {
|
|
|
58
61
|
id: TreeViewItemId;
|
|
59
62
|
children?: TreeViewNodeIdAndChildren[];
|
|
60
63
|
}
|
|
61
|
-
export interface UseTreeViewNodesState {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
export interface UseTreeViewNodesState<R extends {}> {
|
|
65
|
+
nodes: {
|
|
66
|
+
nodeTree: TreeViewNodeIdAndChildren[];
|
|
67
|
+
nodeMap: TreeViewNodeMap;
|
|
68
|
+
itemMap: TreeViewItemMap<R>;
|
|
69
|
+
};
|
|
64
70
|
}
|
|
65
71
|
interface UseTreeViewNodesContextValue extends Pick<UseTreeViewNodesDefaultizedParameters<any>, 'disabledItemsFocusable'> {
|
|
66
72
|
}
|
|
67
73
|
export type UseTreeViewNodesSignature = TreeViewPluginSignature<{
|
|
68
74
|
params: UseTreeViewNodesParameters<any>;
|
|
69
75
|
defaultizedParams: UseTreeViewNodesDefaultizedParameters<any>;
|
|
70
|
-
instance: UseTreeViewNodesInstance
|
|
76
|
+
instance: UseTreeViewNodesInstance<any>;
|
|
77
|
+
publicAPI: UseTreeViewNodesPublicAPI<any>;
|
|
71
78
|
events: UseTreeViewNodesEventLookup;
|
|
72
|
-
state: UseTreeViewNodesState
|
|
79
|
+
state: UseTreeViewNodesState<any>;
|
|
73
80
|
contextValue: UseTreeViewNodesContextValue;
|
|
74
81
|
}>;
|
|
75
82
|
export type TreeViewNodeMap = {
|
|
76
83
|
[nodeId: string]: TreeViewNode;
|
|
77
84
|
};
|
|
85
|
+
export type TreeViewItemMap<R extends {}> = {
|
|
86
|
+
[nodeId: string]: R;
|
|
87
|
+
};
|
|
78
88
|
export {};
|
|
@@ -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,8 +174,8 @@ 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 = [];
|
|
@@ -184,14 +184,14 @@ useTreeViewSelection.getDefaultizedParams = params => {
|
|
|
184
184
|
return _extends({}, params, {
|
|
185
185
|
disableSelection: (_params$disableSelect = params.disableSelection) != null ? _params$disableSelect : false,
|
|
186
186
|
multiSelect: (_params$multiSelect = params.multiSelect) != null ? _params$multiSelect : false,
|
|
187
|
-
|
|
187
|
+
defaultSelectedItems: (_params$defaultSelect = params.defaultSelectedItems) != null ? _params$defaultSelect : params.multiSelect ? DEFAULT_SELECTED_NODES : null
|
|
188
188
|
});
|
|
189
189
|
};
|
|
190
190
|
useTreeViewSelection.params = {
|
|
191
191
|
disableSelection: true,
|
|
192
192
|
multiSelect: true,
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
defaultSelectedItems: true,
|
|
194
|
+
selectedItems: true,
|
|
195
|
+
onSelectedItemsChange: true,
|
|
196
|
+
onItemSelectionToggle: true
|
|
197
197
|
};
|
|
@@ -17,16 +17,16 @@ export interface UseTreeViewSelectionParameters<Multiple extends boolean | undef
|
|
|
17
17
|
*/
|
|
18
18
|
disableSelection?: boolean;
|
|
19
19
|
/**
|
|
20
|
-
* Selected
|
|
20
|
+
* Selected item ids. (Uncontrolled)
|
|
21
21
|
* When `multiSelect` is true this takes an array of strings; when false (default) a string.
|
|
22
22
|
* @default []
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
defaultSelectedItems?: TreeViewSelectionValue<Multiple>;
|
|
25
25
|
/**
|
|
26
|
-
* Selected
|
|
26
|
+
* Selected item ids. (Controlled)
|
|
27
27
|
* When `multiSelect` is true this takes an array of strings; when false (default) a string.
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
selectedItems?: TreeViewSelectionValue<Multiple>;
|
|
30
30
|
/**
|
|
31
31
|
* If true `ctrl` and `shift` will trigger multiselect.
|
|
32
32
|
* @default false
|
|
@@ -35,19 +35,19 @@ export interface UseTreeViewSelectionParameters<Multiple extends boolean | undef
|
|
|
35
35
|
/**
|
|
36
36
|
* Callback fired when tree items are selected/deselected.
|
|
37
37
|
* @param {React.SyntheticEvent} event The event source of the callback
|
|
38
|
-
* @param {string[] | string}
|
|
38
|
+
* @param {string[] | string} itemIds The ids of the selected items.
|
|
39
39
|
* When `multiSelect` is `true`, this is an array of strings; when false (default) a string.
|
|
40
40
|
*/
|
|
41
|
-
|
|
41
|
+
onSelectedItemsChange?: (event: React.SyntheticEvent, itemIds: TreeViewSelectionValue<Multiple>) => void;
|
|
42
42
|
/**
|
|
43
43
|
* Callback fired when a tree item is selected or deselected.
|
|
44
44
|
* @param {React.SyntheticEvent} event The event source of the callback.
|
|
45
|
-
* @param {array}
|
|
46
|
-
* @param {array} isSelected `true` if the
|
|
45
|
+
* @param {array} itemId The itemId of the modified item.
|
|
46
|
+
* @param {array} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
onItemSelectionToggle?: (event: React.SyntheticEvent, itemId: string, isSelected: boolean) => void;
|
|
49
49
|
}
|
|
50
|
-
export type UseTreeViewSelectionDefaultizedParameters<Multiple extends boolean> = DefaultizedProps<UseTreeViewSelectionParameters<Multiple>, 'disableSelection' | '
|
|
50
|
+
export type UseTreeViewSelectionDefaultizedParameters<Multiple extends boolean> = DefaultizedProps<UseTreeViewSelectionParameters<Multiple>, 'disableSelection' | 'defaultSelectedItems' | 'multiSelect'>;
|
|
51
51
|
interface UseTreeViewSelectionContextValue {
|
|
52
52
|
selection: Pick<UseTreeViewSelectionDefaultizedParameters<boolean>, 'multiSelect'>;
|
|
53
53
|
}
|
|
@@ -56,7 +56,7 @@ export type UseTreeViewSelectionSignature = TreeViewPluginSignature<{
|
|
|
56
56
|
defaultizedParams: UseTreeViewSelectionDefaultizedParameters<any>;
|
|
57
57
|
instance: UseTreeViewSelectionInstance;
|
|
58
58
|
contextValue: UseTreeViewSelectionContextValue;
|
|
59
|
-
modelNames: '
|
|
59
|
+
modelNames: 'selectedItems';
|
|
60
60
|
dependantPlugins: [
|
|
61
61
|
UseTreeViewNodesSignature,
|
|
62
62
|
UseTreeViewExpansionSignature,
|