@mui/x-tree-view 8.0.0-alpha.0 → 8.0.0-alpha.2
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 +651 -6
- package/README.md +2 -2
- package/RichTreeView/RichTreeView.js +2 -4
- package/RichTreeView/RichTreeView.types.d.ts +5 -18
- package/SimpleTreeView/SimpleTreeView.types.d.ts +2 -2
- package/TreeItem/TreeItem.js +4 -4
- package/TreeItem/TreeItem.types.d.ts +4 -2
- package/TreeItemDragAndDropOverlay/TreeItemDragAndDropOverlay.js +1 -1
- package/TreeItemIcon/TreeItemIcon.types.d.ts +1 -1
- package/TreeItemProvider/TreeItemProvider.d.ts +2 -4
- package/TreeItemProvider/TreeItemProvider.js +26 -11
- package/TreeItemProvider/TreeItemProvider.types.d.ts +1 -0
- package/hooks/index.d.ts +1 -0
- package/hooks/index.js +2 -1
- package/hooks/useTreeItemModel.d.ts +2 -0
- package/hooks/useTreeItemModel.js +11 -0
- package/hooks/useTreeItemUtils/useTreeItemUtils.d.ts +2 -1
- package/hooks/useTreeItemUtils/useTreeItemUtils.js +31 -15
- package/hooks/useTreeViewApiRef.d.ts +1 -0
- package/index.js +1 -1
- package/internals/TreeViewItemDepthContext/TreeViewItemDepthContext.d.ts +3 -1
- package/internals/TreeViewProvider/TreeViewChildrenItemProvider.d.ts +2 -1
- package/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +6 -22
- package/internals/TreeViewProvider/TreeViewProvider.js +1 -2
- package/internals/TreeViewProvider/TreeViewProvider.types.d.ts +4 -2
- package/internals/components/RichTreeViewItems.d.ts +3 -5
- package/internals/components/RichTreeViewItems.js +42 -30
- package/internals/corePlugins/useTreeViewId/useTreeViewId.js +10 -11
- package/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.d.ts +36 -0
- package/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js +9 -0
- package/internals/corePlugins/useTreeViewId/useTreeViewId.types.d.ts +1 -5
- package/internals/hooks/useSelector.d.ts +4 -0
- package/internals/hooks/useSelector.js +6 -0
- package/internals/index.d.ts +6 -1
- package/internals/index.js +5 -1
- package/internals/models/itemPlugin.d.ts +5 -5
- package/internals/models/plugin.d.ts +20 -8
- package/internals/models/treeView.d.ts +6 -0
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +36 -24
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.d.ts +124 -0
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +17 -0
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +6 -14
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.d.ts +1 -0
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.js +7 -0
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +62 -40
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.d.ts +182 -0
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js +34 -0
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +4 -16
- package/internals/plugins/useTreeViewIcons/useTreeViewIcons.js +15 -13
- package/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.d.ts +1 -1
- package/internals/plugins/useTreeViewItems/index.d.ts +1 -1
- package/internals/plugins/useTreeViewItems/useTreeViewItems.js +58 -98
- package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.d.ts +718 -0
- package/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +103 -0
- package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +15 -52
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +29 -26
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +27 -18
- package/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +13 -5
- package/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +19 -30
- package/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.d.ts +74 -0
- package/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js +26 -0
- package/internals/plugins/useTreeViewLabel/useTreeViewLabel.types.d.ts +7 -24
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +8 -6
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +45 -34
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.d.ts +32 -0
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js +9 -0
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +6 -6
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.d.ts +6 -6
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +23 -13
- package/internals/useTreeView/useTreeView.js +30 -17
- package/internals/useTreeView/useTreeView.types.d.ts +2 -3
- package/internals/useTreeView/useTreeViewBuildContext.d.ts +3 -1
- package/internals/useTreeView/useTreeViewBuildContext.js +24 -18
- package/internals/utils/TreeViewStore.d.ts +12 -0
- package/internals/utils/TreeViewStore.js +24 -0
- package/internals/utils/selectors.d.ts +9 -0
- package/internals/utils/selectors.js +37 -0
- package/internals/utils/tree.d.ts +8 -8
- package/internals/utils/tree.js +51 -43
- package/models/items.d.ts +3 -2
- package/modern/RichTreeView/RichTreeView.js +2 -4
- package/modern/TreeItem/TreeItem.js +4 -4
- package/modern/TreeItemDragAndDropOverlay/TreeItemDragAndDropOverlay.js +1 -1
- package/modern/TreeItemProvider/TreeItemProvider.js +26 -11
- package/modern/hooks/index.js +2 -1
- package/modern/hooks/useTreeItemModel.js +11 -0
- package/modern/hooks/useTreeItemUtils/useTreeItemUtils.js +31 -15
- package/modern/index.js +1 -1
- package/modern/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +6 -22
- package/modern/internals/TreeViewProvider/TreeViewProvider.js +1 -2
- package/modern/internals/components/RichTreeViewItems.js +42 -30
- package/modern/internals/corePlugins/useTreeViewId/useTreeViewId.js +10 -11
- package/modern/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js +9 -0
- package/modern/internals/hooks/useSelector.js +6 -0
- package/modern/internals/index.js +5 -1
- package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +36 -24
- package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +17 -0
- package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.js +7 -0
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +62 -40
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js +34 -0
- package/modern/internals/plugins/useTreeViewIcons/useTreeViewIcons.js +15 -13
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +58 -98
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +103 -0
- package/modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +29 -26
- package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +27 -18
- package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +13 -5
- package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +19 -30
- package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js +26 -0
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +8 -6
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +45 -34
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js +9 -0
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +23 -13
- package/modern/internals/useTreeView/useTreeView.js +30 -17
- package/modern/internals/useTreeView/useTreeViewBuildContext.js +24 -18
- package/modern/internals/utils/TreeViewStore.js +24 -0
- package/modern/internals/utils/selectors.js +37 -0
- package/modern/internals/utils/tree.js +51 -43
- package/modern/useTreeItem/useTreeItem.js +26 -11
- package/node/RichTreeView/RichTreeView.js +2 -4
- package/node/TreeItem/TreeItem.js +4 -4
- package/node/TreeItemDragAndDropOverlay/TreeItemDragAndDropOverlay.js +2 -2
- package/node/TreeItemProvider/TreeItemProvider.js +26 -10
- package/node/hooks/index.js +8 -1
- package/node/hooks/useTreeItemModel.js +17 -0
- package/node/hooks/useTreeItemUtils/useTreeItemUtils.js +32 -15
- package/node/index.js +1 -1
- package/node/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +6 -22
- package/node/internals/TreeViewProvider/TreeViewProvider.js +1 -2
- package/node/internals/components/RichTreeViewItems.js +42 -30
- package/node/internals/corePlugins/useTreeViewId/useTreeViewId.js +12 -13
- package/node/internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js +15 -0
- package/node/internals/hooks/useSelector.js +13 -0
- package/node/internals/index.js +47 -1
- package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +36 -24
- package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js +23 -0
- package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.utils.js +14 -0
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +62 -40
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js +40 -0
- package/node/internals/plugins/useTreeViewIcons/useTreeViewIcons.js +16 -13
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +60 -100
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js +109 -0
- package/node/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +30 -27
- package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +27 -18
- package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +13 -5
- package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +19 -30
- package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js +32 -0
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.itemPlugin.js +8 -6
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +46 -35
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js +15 -0
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +24 -14
- package/node/internals/useTreeView/useTreeView.js +30 -17
- package/node/internals/useTreeView/useTreeViewBuildContext.js +25 -18
- package/node/internals/utils/TreeViewStore.js +31 -0
- package/node/internals/utils/selectors.js +44 -0
- package/node/internals/utils/tree.js +51 -43
- package/node/useTreeItem/useTreeItem.js +26 -11
- package/package.json +6 -4
- package/useTreeItem/useTreeItem.js +26 -11
- package/useTreeItem/useTreeItem.types.d.ts +9 -0
|
@@ -9,42 +9,45 @@ import { TreeViewChildrenItemContext, TreeViewChildrenItemProvider } from "../..
|
|
|
9
9
|
import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "../useTreeViewItems/useTreeViewItems.utils.js";
|
|
10
10
|
import { TreeViewItemDepthContext } from "../../TreeViewItemDepthContext/index.js";
|
|
11
11
|
import { generateTreeItemIdAttribute } from "../../corePlugins/useTreeViewId/useTreeViewId.utils.js";
|
|
12
|
+
import { isItemExpandable } from "../../../hooks/useTreeItemUtils/useTreeItemUtils.js";
|
|
13
|
+
import { useSelector } from "../../hooks/useSelector.js";
|
|
14
|
+
import { selectorTreeViewId } from "../../corePlugins/useTreeViewId/useTreeViewId.selectors.js";
|
|
12
15
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
16
|
export const useTreeViewJSXItems = ({
|
|
14
17
|
instance,
|
|
15
|
-
|
|
18
|
+
store
|
|
16
19
|
}) => {
|
|
17
20
|
instance.preventItemUpdates();
|
|
18
21
|
const insertJSXItem = useEventCallback(item => {
|
|
19
|
-
|
|
20
|
-
if (prevState.items.
|
|
22
|
+
store.update(prevState => {
|
|
23
|
+
if (prevState.items.itemMetaLookup[item.id] != null) {
|
|
21
24
|
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.', `Two items were provided with the same id in the \`items\` prop: "${item.id}"`].join('\n'));
|
|
22
25
|
}
|
|
23
26
|
return _extends({}, prevState, {
|
|
24
27
|
items: _extends({}, prevState.items, {
|
|
25
|
-
|
|
28
|
+
itemMetaLookup: _extends({}, prevState.items.itemMetaLookup, {
|
|
26
29
|
[item.id]: item
|
|
27
30
|
}),
|
|
28
31
|
// For Simple Tree View, we don't have a proper `item` object, so we create a very basic one.
|
|
29
|
-
|
|
32
|
+
itemModelLookup: _extends({}, prevState.items.itemModelLookup, {
|
|
30
33
|
[item.id]: {
|
|
31
34
|
id: item.id,
|
|
32
|
-
label: item.label
|
|
35
|
+
label: item.label ?? ''
|
|
33
36
|
}
|
|
34
37
|
})
|
|
35
38
|
})
|
|
36
39
|
});
|
|
37
40
|
});
|
|
38
41
|
return () => {
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
delete
|
|
43
|
-
delete
|
|
42
|
+
store.update(prevState => {
|
|
43
|
+
const newItemMetaLookup = _extends({}, prevState.items.itemMetaLookup);
|
|
44
|
+
const newItemModelLookup = _extends({}, prevState.items.itemModelLookup);
|
|
45
|
+
delete newItemMetaLookup[item.id];
|
|
46
|
+
delete newItemModelLookup[item.id];
|
|
44
47
|
return _extends({}, prevState, {
|
|
45
48
|
items: _extends({}, prevState.items, {
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
itemMetaLookup: newItemMetaLookup,
|
|
50
|
+
itemModelLookup: newItemModelLookup
|
|
48
51
|
})
|
|
49
52
|
});
|
|
50
53
|
});
|
|
@@ -55,12 +58,12 @@ export const useTreeViewJSXItems = ({
|
|
|
55
58
|
});
|
|
56
59
|
const setJSXItemsOrderedChildrenIds = (parentId, orderedChildrenIds) => {
|
|
57
60
|
const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID;
|
|
58
|
-
|
|
61
|
+
store.update(prevState => _extends({}, prevState, {
|
|
59
62
|
items: _extends({}, prevState.items, {
|
|
60
|
-
|
|
63
|
+
itemOrderedChildrenIdsLookup: _extends({}, prevState.items.itemOrderedChildrenIdsLookup, {
|
|
61
64
|
[parentIdWithDefault]: orderedChildrenIds
|
|
62
65
|
}),
|
|
63
|
-
|
|
66
|
+
itemChildrenIndexesLookup: _extends({}, prevState.items.itemChildrenIndexesLookup, {
|
|
64
67
|
[parentIdWithDefault]: buildSiblingIndexes(orderedChildrenIds)
|
|
65
68
|
})
|
|
66
69
|
})
|
|
@@ -87,12 +90,6 @@ export const useTreeViewJSXItems = ({
|
|
|
87
90
|
}
|
|
88
91
|
};
|
|
89
92
|
};
|
|
90
|
-
const isItemExpandable = reactChildren => {
|
|
91
|
-
if (Array.isArray(reactChildren)) {
|
|
92
|
-
return reactChildren.length > 0 && reactChildren.some(isItemExpandable);
|
|
93
|
-
}
|
|
94
|
-
return Boolean(reactChildren);
|
|
95
|
-
};
|
|
96
93
|
const useTreeViewJSXItemsItemPlugin = ({
|
|
97
94
|
props,
|
|
98
95
|
rootRef,
|
|
@@ -100,7 +97,7 @@ const useTreeViewJSXItemsItemPlugin = ({
|
|
|
100
97
|
}) => {
|
|
101
98
|
const {
|
|
102
99
|
instance,
|
|
103
|
-
|
|
100
|
+
store
|
|
104
101
|
} = useTreeViewContext();
|
|
105
102
|
const {
|
|
106
103
|
children,
|
|
@@ -121,6 +118,7 @@ const useTreeViewJSXItemsItemPlugin = ({
|
|
|
121
118
|
const expandable = isItemExpandable(children);
|
|
122
119
|
const pluginContentRef = React.useRef(null);
|
|
123
120
|
const handleContentRef = useForkRef(pluginContentRef, contentRef);
|
|
121
|
+
const treeId = useSelector(store, selectorTreeViewId);
|
|
124
122
|
|
|
125
123
|
// Prevent any flashing
|
|
126
124
|
useEnhancedEffect(() => {
|
|
@@ -132,9 +130,10 @@ const useTreeViewJSXItemsItemPlugin = ({
|
|
|
132
130
|
registerChild(idAttribute, itemId);
|
|
133
131
|
return () => {
|
|
134
132
|
unregisterChild(idAttribute);
|
|
133
|
+
unregisterChild(idAttribute);
|
|
135
134
|
};
|
|
136
|
-
}, [registerChild, unregisterChild, itemId, id, treeId]);
|
|
137
|
-
|
|
135
|
+
}, [store, instance, registerChild, unregisterChild, itemId, id, treeId]);
|
|
136
|
+
useEnhancedEffect(() => {
|
|
138
137
|
return instance.insertJSXItem({
|
|
139
138
|
id: itemId,
|
|
140
139
|
idAttribute: id,
|
|
@@ -157,12 +156,14 @@ const useTreeViewJSXItemsItemPlugin = ({
|
|
|
157
156
|
useTreeViewJSXItems.itemPlugin = useTreeViewJSXItemsItemPlugin;
|
|
158
157
|
useTreeViewJSXItems.wrapItem = ({
|
|
159
158
|
children,
|
|
160
|
-
itemId
|
|
159
|
+
itemId,
|
|
160
|
+
idAttribute
|
|
161
161
|
}) => {
|
|
162
162
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
163
163
|
const depthContext = React.useContext(TreeViewItemDepthContext);
|
|
164
164
|
return /*#__PURE__*/_jsx(TreeViewChildrenItemProvider, {
|
|
165
165
|
itemId: itemId,
|
|
166
|
+
idAttribute: idAttribute,
|
|
166
167
|
children: /*#__PURE__*/_jsx(TreeViewItemDepthContext.Provider, {
|
|
167
168
|
value: depthContext + 1,
|
|
168
169
|
children: children
|
|
@@ -172,6 +173,8 @@ useTreeViewJSXItems.wrapItem = ({
|
|
|
172
173
|
useTreeViewJSXItems.wrapRoot = ({
|
|
173
174
|
children
|
|
174
175
|
}) => /*#__PURE__*/_jsx(TreeViewChildrenItemProvider, {
|
|
176
|
+
itemId: null,
|
|
177
|
+
idAttribute: null,
|
|
175
178
|
children: /*#__PURE__*/_jsx(TreeViewItemDepthContext.Provider, {
|
|
176
179
|
value: 0,
|
|
177
180
|
children: children
|
package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js
CHANGED
|
@@ -4,19 +4,25 @@ import useEventCallback from '@mui/utils/useEventCallback';
|
|
|
4
4
|
import { getFirstNavigableItem, getLastNavigableItem, getNextNavigableItem, getPreviousNavigableItem, isTargetInDescendants } from "../../utils/tree.js";
|
|
5
5
|
import { hasPlugin } from "../../utils/plugins.js";
|
|
6
6
|
import { useTreeViewLabel } from "../useTreeViewLabel/index.js";
|
|
7
|
+
import { useSelector } from "../../hooks/useSelector.js";
|
|
8
|
+
import { selectorItemMetaLookup, selectorIsItemDisabled, selectorItemParentId } from "../useTreeViewItems/useTreeViewItems.selectors.js";
|
|
9
|
+
import { selectorIsItemBeingEdited, selectorIsItemEditable } from "../useTreeViewLabel/useTreeViewLabel.selectors.js";
|
|
10
|
+
import { selectorIsItemSelected } from "../useTreeViewSelection/useTreeViewSelection.selectors.js";
|
|
11
|
+
import { selectorIsItemExpandable, selectorIsItemExpanded } from "../useTreeViewExpansion/useTreeViewExpansion.selectors.js";
|
|
7
12
|
function isPrintableKey(string) {
|
|
8
13
|
return !!string && string.length === 1 && !!string.match(/\S/);
|
|
9
14
|
}
|
|
10
15
|
export const useTreeViewKeyboardNavigation = ({
|
|
11
16
|
instance,
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
store,
|
|
18
|
+
params
|
|
14
19
|
}) => {
|
|
15
20
|
const isRtl = useRtl();
|
|
16
21
|
const firstCharMap = React.useRef({});
|
|
17
22
|
const updateFirstCharMap = useEventCallback(callback => {
|
|
18
23
|
firstCharMap.current = callback(firstCharMap.current);
|
|
19
24
|
});
|
|
25
|
+
const itemMetaLookup = useSelector(store, selectorItemMetaLookup);
|
|
20
26
|
React.useEffect(() => {
|
|
21
27
|
if (instance.areItemUpdatesPrevented()) {
|
|
22
28
|
return;
|
|
@@ -25,16 +31,16 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
25
31
|
const processItem = item => {
|
|
26
32
|
newFirstCharMap[item.id] = item.label.substring(0, 1).toLowerCase();
|
|
27
33
|
};
|
|
28
|
-
Object.values(
|
|
34
|
+
Object.values(itemMetaLookup).forEach(processItem);
|
|
29
35
|
firstCharMap.current = newFirstCharMap;
|
|
30
|
-
}, [
|
|
36
|
+
}, [itemMetaLookup, params.getItemId, instance]);
|
|
31
37
|
const getFirstMatchingItem = (itemId, query) => {
|
|
32
38
|
const cleanQuery = query.toLowerCase();
|
|
33
39
|
const getNextItem = itemIdToCheck => {
|
|
34
|
-
const nextItemId = getNextNavigableItem(
|
|
40
|
+
const nextItemId = getNextNavigableItem(store.value, itemIdToCheck);
|
|
35
41
|
// We reached the end of the tree, check from the beginning
|
|
36
42
|
if (nextItemId === null) {
|
|
37
|
-
return getFirstNavigableItem(
|
|
43
|
+
return getFirstNavigableItem(store.value);
|
|
38
44
|
}
|
|
39
45
|
return nextItemId;
|
|
40
46
|
};
|
|
@@ -52,9 +58,9 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
52
58
|
}
|
|
53
59
|
return matchingItemId;
|
|
54
60
|
};
|
|
55
|
-
const canToggleItemSelection = itemId => !params.disableSelection && !
|
|
61
|
+
const canToggleItemSelection = itemId => !params.disableSelection && !selectorIsItemDisabled(store.value, itemId);
|
|
56
62
|
const canToggleItemExpansion = itemId => {
|
|
57
|
-
return !
|
|
63
|
+
return !selectorIsItemDisabled(store.value, itemId) && selectorIsItemExpandable(store.value, itemId);
|
|
58
64
|
};
|
|
59
65
|
|
|
60
66
|
// ARIA specification: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/#keyboardinteraction
|
|
@@ -91,7 +97,10 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
91
97
|
// If the focused item has no children, we select it.
|
|
92
98
|
case key === 'Enter':
|
|
93
99
|
{
|
|
94
|
-
if (hasPlugin(instance, useTreeViewLabel) &&
|
|
100
|
+
if (hasPlugin(instance, useTreeViewLabel) && selectorIsItemEditable(store.value, {
|
|
101
|
+
itemId,
|
|
102
|
+
isItemEditable: params.isItemEditable
|
|
103
|
+
}) && !selectorIsItemBeingEdited(store.value, itemId)) {
|
|
95
104
|
instance.setEditedItemId(itemId);
|
|
96
105
|
} else if (canToggleItemExpansion(itemId)) {
|
|
97
106
|
instance.toggleItemExpansion(event, itemId);
|
|
@@ -104,7 +113,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
104
113
|
itemId,
|
|
105
114
|
keepExistingSelection: true
|
|
106
115
|
});
|
|
107
|
-
} else if (!
|
|
116
|
+
} else if (!selectorIsItemSelected(store.value, itemId)) {
|
|
108
117
|
instance.selectItem({
|
|
109
118
|
event,
|
|
110
119
|
itemId
|
|
@@ -118,7 +127,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
118
127
|
// Focus the next focusable item
|
|
119
128
|
case key === 'ArrowDown':
|
|
120
129
|
{
|
|
121
|
-
const nextItem = getNextNavigableItem(
|
|
130
|
+
const nextItem = getNextNavigableItem(store.value, itemId);
|
|
122
131
|
if (nextItem) {
|
|
123
132
|
event.preventDefault();
|
|
124
133
|
instance.focusItem(event, nextItem);
|
|
@@ -135,7 +144,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
135
144
|
// Focuses the previous focusable item
|
|
136
145
|
case key === 'ArrowUp':
|
|
137
146
|
{
|
|
138
|
-
const previousItem = getPreviousNavigableItem(
|
|
147
|
+
const previousItem = getPreviousNavigableItem(store.value, itemId);
|
|
139
148
|
if (previousItem) {
|
|
140
149
|
event.preventDefault();
|
|
141
150
|
instance.focusItem(event, previousItem);
|
|
@@ -156,8 +165,8 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
156
165
|
if (ctrlPressed) {
|
|
157
166
|
return;
|
|
158
167
|
}
|
|
159
|
-
if (
|
|
160
|
-
const nextItemId = getNextNavigableItem(
|
|
168
|
+
if (selectorIsItemExpanded(store.value, itemId)) {
|
|
169
|
+
const nextItemId = getNextNavigableItem(store.value, itemId);
|
|
161
170
|
if (nextItemId) {
|
|
162
171
|
instance.focusItem(event, nextItemId);
|
|
163
172
|
event.preventDefault();
|
|
@@ -176,11 +185,11 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
176
185
|
if (ctrlPressed) {
|
|
177
186
|
return;
|
|
178
187
|
}
|
|
179
|
-
if (canToggleItemExpansion(itemId) &&
|
|
188
|
+
if (canToggleItemExpansion(itemId) && selectorIsItemExpanded(store.value, itemId)) {
|
|
180
189
|
instance.toggleItemExpansion(event, itemId);
|
|
181
190
|
event.preventDefault();
|
|
182
191
|
} else {
|
|
183
|
-
const parent =
|
|
192
|
+
const parent = selectorItemParentId(store.value, itemId);
|
|
184
193
|
if (parent) {
|
|
185
194
|
instance.focusItem(event, parent);
|
|
186
195
|
event.preventDefault();
|
|
@@ -197,7 +206,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
197
206
|
if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
|
|
198
207
|
instance.selectRangeFromStartToItem(event, itemId);
|
|
199
208
|
} else {
|
|
200
|
-
instance.focusItem(event, getFirstNavigableItem(
|
|
209
|
+
instance.focusItem(event, getFirstNavigableItem(store.value));
|
|
201
210
|
}
|
|
202
211
|
event.preventDefault();
|
|
203
212
|
break;
|
|
@@ -211,7 +220,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
211
220
|
if (canToggleItemSelection(itemId) && params.multiSelect && ctrlPressed && event.shiftKey) {
|
|
212
221
|
instance.selectRangeFromItemToEnd(event, itemId);
|
|
213
222
|
} else {
|
|
214
|
-
instance.focusItem(event, getLastNavigableItem(
|
|
223
|
+
instance.focusItem(event, getLastNavigableItem(store.value));
|
|
215
224
|
}
|
|
216
225
|
event.preventDefault();
|
|
217
226
|
break;
|
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useTreeViewContext } from "../../TreeViewProvider/index.js";
|
|
3
|
+
import { useSelector } from "../../hooks/useSelector.js";
|
|
4
|
+
import { selectorIsItemBeingEdited, selectorIsItemEditable } from "./useTreeViewLabel.selectors.js";
|
|
3
5
|
export const useTreeViewLabelItemPlugin = ({
|
|
4
6
|
props
|
|
5
7
|
}) => {
|
|
6
8
|
const {
|
|
7
|
-
|
|
9
|
+
store,
|
|
10
|
+
label: {
|
|
11
|
+
isItemEditable
|
|
12
|
+
}
|
|
8
13
|
} = useTreeViewContext();
|
|
9
14
|
const {
|
|
10
15
|
label,
|
|
11
16
|
itemId
|
|
12
17
|
} = props;
|
|
13
18
|
const [labelInputValue, setLabelInputValue] = React.useState(label);
|
|
14
|
-
const
|
|
19
|
+
const editable = useSelector(store, selectorIsItemEditable, {
|
|
20
|
+
itemId,
|
|
21
|
+
isItemEditable
|
|
22
|
+
});
|
|
23
|
+
const editing = useSelector(store, selectorIsItemBeingEdited, itemId);
|
|
15
24
|
React.useEffect(() => {
|
|
16
|
-
if (!
|
|
25
|
+
if (!editing) {
|
|
17
26
|
setLabelInputValue(label);
|
|
18
27
|
}
|
|
19
|
-
}, [
|
|
28
|
+
}, [editing, label]);
|
|
20
29
|
return {
|
|
21
30
|
propsEnhancers: {
|
|
22
31
|
labelInput: ({
|
|
23
32
|
externalEventHandlers,
|
|
24
33
|
interactions
|
|
25
34
|
}) => {
|
|
26
|
-
const editable = instance.isItemEditable(itemId);
|
|
27
35
|
if (!editable) {
|
|
28
36
|
return {};
|
|
29
37
|
}
|
|
@@ -3,41 +3,26 @@ import * as React from 'react';
|
|
|
3
3
|
import { warnOnce } from '@mui/x-internals/warning';
|
|
4
4
|
import { useTreeViewLabelItemPlugin } from "./useTreeViewLabel.itemPlugin.js";
|
|
5
5
|
export const useTreeViewLabel = ({
|
|
6
|
-
|
|
7
|
-
state,
|
|
8
|
-
setState,
|
|
6
|
+
store,
|
|
9
7
|
params
|
|
10
8
|
}) => {
|
|
11
|
-
const editedItemRef = React.useRef(state.editedItemId);
|
|
12
|
-
const isItemBeingEditedRef = itemId => editedItemRef.current === itemId;
|
|
13
9
|
const setEditedItemId = editedItemId => {
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
store.update(prevState => _extends({}, prevState, {
|
|
11
|
+
label: {
|
|
12
|
+
editedItemId
|
|
13
|
+
}
|
|
16
14
|
}));
|
|
17
|
-
editedItemRef.current = editedItemId;
|
|
18
|
-
};
|
|
19
|
-
const isItemBeingEdited = itemId => itemId === state.editedItemId;
|
|
20
|
-
const isTreeViewEditable = Boolean(params.isItemEditable);
|
|
21
|
-
const isItemEditable = itemId => {
|
|
22
|
-
if (itemId == null || !isTreeViewEditable) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
const item = instance.getItem(itemId);
|
|
26
|
-
if (!item) {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
return typeof params.isItemEditable === 'function' ? params.isItemEditable(item) : Boolean(params.isItemEditable);
|
|
30
15
|
};
|
|
31
16
|
const updateItemLabel = (itemId, label) => {
|
|
32
17
|
if (!label) {
|
|
33
18
|
throw new Error(['MUI X: The Tree View component requires all items to have a `label` property.', 'The label of an item cannot be empty.', itemId].join('\n'));
|
|
34
19
|
}
|
|
35
|
-
|
|
36
|
-
const item = prevState.items.
|
|
20
|
+
store.update(prevState => {
|
|
21
|
+
const item = prevState.items.itemMetaLookup[itemId];
|
|
37
22
|
if (item.label !== label) {
|
|
38
23
|
return _extends({}, prevState, {
|
|
39
24
|
items: _extends({}, prevState.items, {
|
|
40
|
-
|
|
25
|
+
itemMetaLookup: _extends({}, prevState.items.itemMetaLookup, {
|
|
41
26
|
[itemId]: _extends({}, item, {
|
|
42
27
|
label
|
|
43
28
|
})
|
|
@@ -51,18 +36,20 @@ export const useTreeViewLabel = ({
|
|
|
51
36
|
params.onItemLabelChange(itemId, label);
|
|
52
37
|
}
|
|
53
38
|
};
|
|
39
|
+
const pluginContextValue = React.useMemo(() => ({
|
|
40
|
+
label: {
|
|
41
|
+
isItemEditable: params.isItemEditable
|
|
42
|
+
}
|
|
43
|
+
}), [params.isItemEditable]);
|
|
54
44
|
return {
|
|
55
45
|
instance: {
|
|
56
46
|
setEditedItemId,
|
|
57
|
-
|
|
58
|
-
updateItemLabel,
|
|
59
|
-
isItemEditable,
|
|
60
|
-
isTreeViewEditable,
|
|
61
|
-
isItemBeingEditedRef
|
|
47
|
+
updateItemLabel
|
|
62
48
|
},
|
|
63
49
|
publicAPI: {
|
|
64
50
|
updateItemLabel
|
|
65
|
-
}
|
|
51
|
+
},
|
|
52
|
+
contextValue: pluginContextValue
|
|
66
53
|
};
|
|
67
54
|
};
|
|
68
55
|
useTreeViewLabel.itemPlugin = useTreeViewLabelItemPlugin;
|
|
@@ -81,7 +68,9 @@ useTreeViewLabel.getDefaultizedParams = ({
|
|
|
81
68
|
});
|
|
82
69
|
};
|
|
83
70
|
useTreeViewLabel.getInitialState = () => ({
|
|
84
|
-
|
|
71
|
+
label: {
|
|
72
|
+
editedItemId: null
|
|
73
|
+
}
|
|
85
74
|
});
|
|
86
75
|
useTreeViewLabel.params = {
|
|
87
76
|
onItemLabelChange: true,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createSelector } from "../../utils/selectors.js";
|
|
2
|
+
import { selectorItemModel } from "../useTreeViewItems/useTreeViewItems.selectors.js";
|
|
3
|
+
const selectorTreeViewLabelState = state => state.label;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if an item is editable.
|
|
7
|
+
* @param {TreeViewState<[UseTreeViewItemsSignature]>} state The state of the tree view.
|
|
8
|
+
* @param {object} params The parameters.
|
|
9
|
+
* @param {TreeViewItemId} params.itemId The id of the item to check.
|
|
10
|
+
* @param {((item: any) => boolean) | boolean} params.isItemEditable The function to determine if an item is editable.
|
|
11
|
+
* @returns {boolean} `true` if the item is editable, `false` otherwise.
|
|
12
|
+
*/
|
|
13
|
+
export const selectorIsItemEditable = createSelector([(_, args) => args, (state, args) => selectorItemModel(state, args.itemId)], (args, itemModel) => {
|
|
14
|
+
if (!itemModel || !args.isItemEditable) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return typeof args.isItemEditable === 'function' ? args.isItemEditable(itemModel) : true;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if an item is being edited.
|
|
22
|
+
* @param {TreeViewState<[UseTreeViewLabelSignature]>} state The state of the tree view.
|
|
23
|
+
* @param {TreeViewItemId} itemId The id of the item to check.
|
|
24
|
+
* @returns {boolean} `true` if the item is being edited, `false` otherwise.
|
|
25
|
+
*/
|
|
26
|
+
export const selectorIsItemBeingEdited = createSelector([selectorTreeViewLabelState, (_, itemId) => itemId], (labelState, itemId) => labelState.editedItemId === itemId);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import { useTreeViewContext } from "../../TreeViewProvider/index.js";
|
|
3
|
+
import { selectorItemOrderedChildrenIds } from "../useTreeViewItems/useTreeViewItems.selectors.js";
|
|
4
|
+
import { selectorIsItemSelected } from "./useTreeViewSelection.selectors.js";
|
|
3
5
|
function getCheckboxStatus({
|
|
4
6
|
itemId,
|
|
5
|
-
|
|
7
|
+
store,
|
|
6
8
|
selectionPropagation,
|
|
7
9
|
selected
|
|
8
10
|
}) {
|
|
@@ -12,7 +14,7 @@ function getCheckboxStatus({
|
|
|
12
14
|
checked: true
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
|
-
const children =
|
|
17
|
+
const children = selectorItemOrderedChildrenIds(store.value, itemId);
|
|
16
18
|
if (children.length === 0) {
|
|
17
19
|
return {
|
|
18
20
|
indeterminate: false,
|
|
@@ -23,13 +25,13 @@ function getCheckboxStatus({
|
|
|
23
25
|
let hasUnSelectedDescendant = false;
|
|
24
26
|
const traverseDescendants = itemToTraverseId => {
|
|
25
27
|
if (itemToTraverseId !== itemId) {
|
|
26
|
-
if (
|
|
28
|
+
if (selectorIsItemSelected(store.value, itemToTraverseId)) {
|
|
27
29
|
hasSelectedDescendant = true;
|
|
28
30
|
} else {
|
|
29
31
|
hasUnSelectedDescendant = true;
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
|
-
|
|
34
|
+
selectorItemOrderedChildrenIds(store.value, itemToTraverseId).forEach(traverseDescendants);
|
|
33
35
|
};
|
|
34
36
|
traverseDescendants(itemId);
|
|
35
37
|
return {
|
|
@@ -44,7 +46,7 @@ export const useTreeViewSelectionItemPlugin = ({
|
|
|
44
46
|
itemId
|
|
45
47
|
} = props;
|
|
46
48
|
const {
|
|
47
|
-
|
|
49
|
+
store,
|
|
48
50
|
selection: {
|
|
49
51
|
disableSelection,
|
|
50
52
|
checkboxSelection,
|
|
@@ -69,7 +71,7 @@ export const useTreeViewSelectionItemPlugin = ({
|
|
|
69
71
|
interactions.handleCheckboxSelection(event);
|
|
70
72
|
};
|
|
71
73
|
const checkboxStatus = getCheckboxStatus({
|
|
72
|
-
|
|
74
|
+
store,
|
|
73
75
|
itemId,
|
|
74
76
|
selectionPropagation,
|
|
75
77
|
selected: status.selected
|