@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
|
@@ -1,30 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
1
4
|
import PropTypes from 'prop-types';
|
|
2
5
|
import { useTreeViewContext } from "../internals/TreeViewProvider/index.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
import { generateTreeItemIdAttribute } from "../internals/corePlugins/useTreeViewId/useTreeViewId.utils.js";
|
|
7
|
+
import { useSelector } from "../internals/hooks/useSelector.js";
|
|
8
|
+
import { selectorTreeViewId } from "../internals/corePlugins/useTreeViewId/useTreeViewId.selectors.js";
|
|
9
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
10
|
function TreeItemProvider(props) {
|
|
8
11
|
const {
|
|
9
12
|
children,
|
|
10
|
-
itemId
|
|
13
|
+
itemId,
|
|
14
|
+
id
|
|
11
15
|
} = props;
|
|
12
16
|
const {
|
|
13
17
|
wrapItem,
|
|
14
|
-
instance
|
|
18
|
+
instance,
|
|
19
|
+
store
|
|
15
20
|
} = useTreeViewContext();
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
const treeId = useSelector(store, selectorTreeViewId);
|
|
22
|
+
const idAttribute = generateTreeItemIdAttribute({
|
|
18
23
|
itemId,
|
|
19
|
-
|
|
24
|
+
treeId,
|
|
25
|
+
id
|
|
26
|
+
});
|
|
27
|
+
return /*#__PURE__*/_jsx(React.Fragment, {
|
|
28
|
+
children: wrapItem({
|
|
29
|
+
children,
|
|
30
|
+
itemId,
|
|
31
|
+
instance,
|
|
32
|
+
idAttribute
|
|
33
|
+
})
|
|
20
34
|
});
|
|
21
35
|
}
|
|
22
|
-
TreeItemProvider.propTypes = {
|
|
36
|
+
process.env.NODE_ENV !== "production" ? TreeItemProvider.propTypes = {
|
|
23
37
|
// ----------------------------- Warning --------------------------------
|
|
24
38
|
// | These PropTypes are generated from the TypeScript type definitions |
|
|
25
39
|
// | To update them edit the TypeScript types and run "pnpm proptypes" |
|
|
26
40
|
// ----------------------------------------------------------------------
|
|
27
41
|
children: PropTypes.node,
|
|
42
|
+
id: PropTypes.string,
|
|
28
43
|
itemId: PropTypes.string.isRequired
|
|
29
|
-
};
|
|
44
|
+
} : void 0;
|
|
30
45
|
export { TreeItemProvider };
|
package/modern/hooks/index.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useTreeViewContext } from "../internals/TreeViewProvider/index.js";
|
|
4
|
+
import { useSelector } from "../internals/hooks/useSelector.js";
|
|
5
|
+
import { selectorItemModel } from "../internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js";
|
|
6
|
+
export const useTreeItemModel = itemId => {
|
|
7
|
+
const {
|
|
8
|
+
store
|
|
9
|
+
} = useTreeViewContext();
|
|
10
|
+
return useSelector(store, selectorItemModel, itemId);
|
|
11
|
+
};
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
import { useTreeViewContext } from "../../internals/TreeViewProvider/index.js";
|
|
4
4
|
import { useTreeViewLabel } from "../../internals/plugins/useTreeViewLabel/index.js";
|
|
5
5
|
import { hasPlugin } from "../../internals/utils/plugins.js";
|
|
6
|
+
import { useSelector } from "../../internals/hooks/useSelector.js";
|
|
7
|
+
import { selectorIsItemExpanded } from "../../internals/plugins/useTreeViewExpansion/useTreeViewExpansion.selectors.js";
|
|
8
|
+
import { selectorIsItemFocused } from "../../internals/plugins/useTreeViewFocus/useTreeViewFocus.selectors.js";
|
|
9
|
+
import { selectorIsItemDisabled } from "../../internals/plugins/useTreeViewItems/useTreeViewItems.selectors.js";
|
|
10
|
+
import { selectorIsItemSelected } from "../../internals/plugins/useTreeViewSelection/useTreeViewSelection.selectors.js";
|
|
11
|
+
import { selectorIsItemBeingEdited, selectorIsItemEditable } from "../../internals/plugins/useTreeViewLabel/useTreeViewLabel.selectors.js";
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
14
|
* Plugins that need to be present in the Tree View in order for `useTreeItemUtils` to work correctly.
|
|
@@ -12,7 +18,7 @@ import { hasPlugin } from "../../internals/utils/plugins.js";
|
|
|
12
18
|
* Plugins that `useTreeItemUtils` can use if they are present, but are not required.
|
|
13
19
|
*/
|
|
14
20
|
|
|
15
|
-
const isItemExpandable = reactChildren => {
|
|
21
|
+
export const isItemExpandable = reactChildren => {
|
|
16
22
|
if (Array.isArray(reactChildren)) {
|
|
17
23
|
return reactChildren.length > 0 && reactChildren.some(isItemExpandable);
|
|
18
24
|
}
|
|
@@ -24,19 +30,30 @@ export const useTreeItemUtils = ({
|
|
|
24
30
|
}) => {
|
|
25
31
|
const {
|
|
26
32
|
instance,
|
|
33
|
+
label,
|
|
34
|
+
store,
|
|
27
35
|
selection: {
|
|
28
36
|
multiSelect
|
|
29
37
|
},
|
|
30
38
|
publicAPI
|
|
31
39
|
} = useTreeViewContext();
|
|
40
|
+
const isExpanded = useSelector(store, selectorIsItemExpanded, itemId);
|
|
41
|
+
const isFocused = useSelector(store, selectorIsItemFocused, itemId);
|
|
42
|
+
const isSelected = useSelector(store, selectorIsItemSelected, itemId);
|
|
43
|
+
const isDisabled = useSelector(store, selectorIsItemDisabled, itemId);
|
|
44
|
+
const isEditing = useSelector(store, state => label == null ? false : selectorIsItemBeingEdited(state, itemId));
|
|
45
|
+
const isEditable = useSelector(store, state => label == null ? false : selectorIsItemEditable(state, {
|
|
46
|
+
itemId,
|
|
47
|
+
isItemEditable: label.isItemEditable
|
|
48
|
+
}));
|
|
32
49
|
const status = {
|
|
33
50
|
expandable: isItemExpandable(children),
|
|
34
|
-
expanded:
|
|
35
|
-
focused:
|
|
36
|
-
selected:
|
|
37
|
-
disabled:
|
|
38
|
-
editing:
|
|
39
|
-
editable:
|
|
51
|
+
expanded: isExpanded,
|
|
52
|
+
focused: isFocused,
|
|
53
|
+
selected: isSelected,
|
|
54
|
+
disabled: isDisabled,
|
|
55
|
+
editing: isEditing,
|
|
56
|
+
editable: isEditable
|
|
40
57
|
};
|
|
41
58
|
const handleExpansion = event => {
|
|
42
59
|
if (status.disabled) {
|
|
@@ -48,7 +65,7 @@ export const useTreeItemUtils = ({
|
|
|
48
65
|
const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
|
|
49
66
|
|
|
50
67
|
// If already expanded and trying to toggle selection don't close
|
|
51
|
-
if (status.expandable && !(multiple &&
|
|
68
|
+
if (status.expandable && !(multiple && selectorIsItemExpanded(store.value, itemId))) {
|
|
52
69
|
instance.toggleItemExpansion(event, itemId);
|
|
53
70
|
}
|
|
54
71
|
};
|
|
@@ -95,15 +112,15 @@ export const useTreeItemUtils = ({
|
|
|
95
112
|
if (!hasPlugin(instance, useTreeViewLabel)) {
|
|
96
113
|
return;
|
|
97
114
|
}
|
|
98
|
-
if (
|
|
99
|
-
if (
|
|
115
|
+
if (isEditable) {
|
|
116
|
+
if (isEditing) {
|
|
100
117
|
instance.setEditedItemId(null);
|
|
101
118
|
} else {
|
|
102
119
|
instance.setEditedItemId(itemId);
|
|
103
120
|
}
|
|
104
121
|
}
|
|
105
122
|
};
|
|
106
|
-
const handleSaveItemLabel = (event,
|
|
123
|
+
const handleSaveItemLabel = (event, newLabel) => {
|
|
107
124
|
if (!hasPlugin(instance, useTreeViewLabel)) {
|
|
108
125
|
return;
|
|
109
126
|
}
|
|
@@ -111,9 +128,8 @@ export const useTreeItemUtils = ({
|
|
|
111
128
|
// As a side effect of `instance.focusItem` called here and in `handleCancelItemLabelEditing` the `labelInput` is blurred
|
|
112
129
|
// The `onBlur` event is triggered, which calls `handleSaveItemLabel` again.
|
|
113
130
|
// To avoid creating an unwanted behavior we need to check if the item is being edited before calling `updateItemLabel`
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
instance.updateItemLabel(itemId, label);
|
|
131
|
+
if (selectorIsItemBeingEdited(store.value, itemId)) {
|
|
132
|
+
instance.updateItemLabel(itemId, newLabel);
|
|
117
133
|
toggleItemEditing();
|
|
118
134
|
instance.focusItem(event, itemId);
|
|
119
135
|
}
|
|
@@ -122,7 +138,7 @@ export const useTreeItemUtils = ({
|
|
|
122
138
|
if (!hasPlugin(instance, useTreeViewLabel)) {
|
|
123
139
|
return;
|
|
124
140
|
}
|
|
125
|
-
if (
|
|
141
|
+
if (selectorIsItemBeingEdited(store.value, itemId)) {
|
|
126
142
|
toggleItemEditing();
|
|
127
143
|
instance.focusItem(event, itemId);
|
|
128
144
|
}
|
package/modern/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { useTreeViewContext } from "./useTreeViewContext.js";
|
|
4
4
|
import { escapeOperandAttributeSelector } from "../utils/utils.js";
|
|
5
|
-
import {
|
|
5
|
+
import { selectorItemOrderedChildrenIds } from "../plugins/useTreeViewItems/useTreeViewItems.selectors.js";
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
7
|
export const TreeViewChildrenItemContext = /*#__PURE__*/React.createContext(null);
|
|
8
8
|
if (process.env.NODE_ENV !== 'production') {
|
|
@@ -11,11 +11,12 @@ if (process.env.NODE_ENV !== 'production') {
|
|
|
11
11
|
export function TreeViewChildrenItemProvider(props) {
|
|
12
12
|
const {
|
|
13
13
|
children,
|
|
14
|
-
itemId = null
|
|
14
|
+
itemId = null,
|
|
15
|
+
idAttribute
|
|
15
16
|
} = props;
|
|
16
17
|
const {
|
|
17
18
|
instance,
|
|
18
|
-
|
|
19
|
+
store,
|
|
19
20
|
rootRef
|
|
20
21
|
} = useTreeViewContext();
|
|
21
22
|
const childrenIdAttrToIdRef = React.useRef(new Map());
|
|
@@ -23,25 +24,8 @@ export function TreeViewChildrenItemProvider(props) {
|
|
|
23
24
|
if (!rootRef.current) {
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
idAttr = rootRef.current.id;
|
|
29
|
-
} else {
|
|
30
|
-
// Undefined during 1st render
|
|
31
|
-
const itemMeta = instance.getItemMeta(itemId);
|
|
32
|
-
if (itemMeta !== undefined) {
|
|
33
|
-
idAttr = generateTreeItemIdAttribute({
|
|
34
|
-
itemId,
|
|
35
|
-
treeId,
|
|
36
|
-
id: itemMeta.idAttribute
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (idAttr == null) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const previousChildrenIds = instance.getItemOrderedChildrenIds(itemId ?? null) ?? [];
|
|
44
|
-
const escapedIdAttr = escapeOperandAttributeSelector(idAttr);
|
|
27
|
+
const previousChildrenIds = selectorItemOrderedChildrenIds(store.value, itemId ?? null) ?? [];
|
|
28
|
+
const escapedIdAttr = escapeOperandAttributeSelector(idAttribute ?? rootRef.current.id);
|
|
45
29
|
const childrenElements = rootRef.current.querySelectorAll(`${itemId == null ? '' : `*[id="${escapedIdAttr}"] `}[role="treeitem"]:not(*[id="${escapedIdAttr}"] [role="treeitem"] [role="treeitem"])`);
|
|
46
30
|
const childrenIds = Array.from(childrenElements).map(child => childrenIdAttrToIdRef.current.get(child.id));
|
|
47
31
|
const hasChanged = childrenIds.length !== previousChildrenIds.length || childrenIds.some((childId, index) => childId !== previousChildrenIds[index]);
|
|
@@ -3,54 +3,66 @@ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWith
|
|
|
3
3
|
const _excluded = ["ownerState"];
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import useSlotProps from '@mui/utils/useSlotProps';
|
|
6
|
+
import { fastObjectShallowCompare } from '@mui/x-internals/fastObjectShallowCompare';
|
|
6
7
|
import { TreeItem } from "../../TreeItem/index.js";
|
|
8
|
+
import { useSelector } from "../hooks/useSelector.js";
|
|
9
|
+
import { selectorItemMeta, selectorItemOrderedChildrenIds } from "../plugins/useTreeViewItems/useTreeViewItems.selectors.js";
|
|
10
|
+
import { useTreeViewContext } from "../TreeViewProvider/index.js";
|
|
7
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const RichTreeViewItemsContext = /*#__PURE__*/React.createContext(null);
|
|
13
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
14
|
+
RichTreeViewItemsContext.displayName = 'RichTreeViewItemsProvider';
|
|
15
|
+
}
|
|
16
|
+
const WrappedTreeItem = /*#__PURE__*/React.memo(function WrappedTreeItem({
|
|
17
|
+
itemSlot,
|
|
18
|
+
itemSlotProps,
|
|
19
|
+
itemId
|
|
15
20
|
}) {
|
|
16
|
-
const
|
|
21
|
+
const renderItemForRichTreeView = React.useContext(RichTreeViewItemsContext);
|
|
22
|
+
const {
|
|
23
|
+
store
|
|
24
|
+
} = useTreeViewContext();
|
|
25
|
+
const itemMeta = useSelector(store, selectorItemMeta, itemId);
|
|
26
|
+
const children = useSelector(store, selectorItemOrderedChildrenIds, itemId);
|
|
27
|
+
const Item = itemSlot ?? TreeItem;
|
|
17
28
|
const _useSlotProps = useSlotProps({
|
|
18
29
|
elementType: Item,
|
|
19
|
-
externalSlotProps:
|
|
30
|
+
externalSlotProps: itemSlotProps,
|
|
20
31
|
additionalProps: {
|
|
21
|
-
|
|
22
|
-
id,
|
|
23
|
-
|
|
32
|
+
label: itemMeta?.label,
|
|
33
|
+
id: itemMeta?.idAttribute,
|
|
34
|
+
itemId
|
|
24
35
|
},
|
|
25
36
|
ownerState: {
|
|
26
37
|
itemId,
|
|
27
|
-
label
|
|
38
|
+
label: itemMeta?.label
|
|
28
39
|
}
|
|
29
40
|
}),
|
|
30
41
|
itemProps = _objectWithoutPropertiesLoose(_useSlotProps, _excluded);
|
|
31
|
-
const children = React.useMemo(() => itemsToRender ? /*#__PURE__*/_jsx(RichTreeViewItems, {
|
|
32
|
-
itemsToRender: itemsToRender,
|
|
33
|
-
slots: slots,
|
|
34
|
-
slotProps: slotProps
|
|
35
|
-
}) : null, [itemsToRender, slots, slotProps]);
|
|
36
42
|
return /*#__PURE__*/_jsx(Item, _extends({}, itemProps, {
|
|
37
|
-
children: children
|
|
43
|
+
children: children?.map(renderItemForRichTreeView)
|
|
38
44
|
}));
|
|
39
|
-
}
|
|
45
|
+
}, fastObjectShallowCompare);
|
|
40
46
|
export function RichTreeViewItems(props) {
|
|
41
47
|
const {
|
|
42
|
-
itemsToRender,
|
|
43
48
|
slots,
|
|
44
49
|
slotProps
|
|
45
50
|
} = props;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
const {
|
|
52
|
+
store
|
|
53
|
+
} = useTreeViewContext();
|
|
54
|
+
const itemSlot = slots?.item;
|
|
55
|
+
const itemSlotProps = slotProps?.item;
|
|
56
|
+
const items = useSelector(store, selectorItemOrderedChildrenIds, null);
|
|
57
|
+
const renderItem = React.useCallback(itemId => {
|
|
58
|
+
return /*#__PURE__*/_jsx(WrappedTreeItem, {
|
|
59
|
+
itemSlot: itemSlot,
|
|
60
|
+
itemSlotProps: itemSlotProps,
|
|
61
|
+
itemId: itemId
|
|
62
|
+
}, itemId);
|
|
63
|
+
}, [itemSlot, itemSlotProps]);
|
|
64
|
+
return /*#__PURE__*/_jsx(RichTreeViewItemsContext.Provider, {
|
|
65
|
+
value: renderItem,
|
|
66
|
+
children: items.map(renderItem)
|
|
55
67
|
});
|
|
56
68
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
+
import { useSelector } from "../../hooks/useSelector.js";
|
|
4
|
+
import { selectorTreeViewId } from "./useTreeViewId.selectors.js";
|
|
3
5
|
import { createTreeViewDefaultId } from "./useTreeViewId.utils.js";
|
|
4
6
|
export const useTreeViewId = ({
|
|
5
7
|
params,
|
|
6
|
-
|
|
7
|
-
setState
|
|
8
|
+
store
|
|
8
9
|
}) => {
|
|
9
10
|
React.useEffect(() => {
|
|
10
|
-
|
|
11
|
-
if (
|
|
11
|
+
store.update(prevState => {
|
|
12
|
+
if (params.id === prevState.id.providedTreeId && prevState.id.treeId !== undefined) {
|
|
12
13
|
return prevState;
|
|
13
14
|
}
|
|
14
15
|
return _extends({}, prevState, {
|
|
@@ -17,15 +18,12 @@ export const useTreeViewId = ({
|
|
|
17
18
|
})
|
|
18
19
|
});
|
|
19
20
|
});
|
|
20
|
-
}, [
|
|
21
|
-
const treeId =
|
|
21
|
+
}, [store, params.id]);
|
|
22
|
+
const treeId = useSelector(store, selectorTreeViewId);
|
|
22
23
|
return {
|
|
23
24
|
getRootProps: () => ({
|
|
24
25
|
id: treeId
|
|
25
|
-
})
|
|
26
|
-
contextValue: {
|
|
27
|
-
treeId
|
|
28
|
-
}
|
|
26
|
+
})
|
|
29
27
|
};
|
|
30
28
|
};
|
|
31
29
|
useTreeViewId.params = {
|
|
@@ -35,6 +33,7 @@ useTreeViewId.getInitialState = ({
|
|
|
35
33
|
id
|
|
36
34
|
}) => ({
|
|
37
35
|
id: {
|
|
38
|
-
treeId:
|
|
36
|
+
treeId: undefined,
|
|
37
|
+
providedTreeId: id
|
|
39
38
|
}
|
|
40
39
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createSelector } from "../../utils/selectors.js";
|
|
2
|
+
const selectorTreeViewIdState = state => state.id;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get the id attribute of the tree view.
|
|
6
|
+
* @param {TreeViewState<[UseTreeViewIdSignature]>} state The state of the tree view.
|
|
7
|
+
* @returns {string} The id attribute of the tree view.
|
|
8
|
+
*/
|
|
9
|
+
export const selectorTreeViewId = createSelector(selectorTreeViewIdState, idState => idState.treeId);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
|
|
2
|
+
const defaultCompare = Object.is;
|
|
3
|
+
export const useSelector = (store, selector, args = undefined, equals = defaultCompare) => {
|
|
4
|
+
const selectorWithArgs = state => selector(state, args);
|
|
5
|
+
return useSyncExternalStoreWithSelector(store.subscribe, store.getSnapshot, store.getSnapshot, selectorWithArgs, equals);
|
|
6
|
+
};
|
|
@@ -2,6 +2,7 @@ export { useTreeView } from "./useTreeView/index.js";
|
|
|
2
2
|
export { TreeViewProvider, useTreeViewContext } from "./TreeViewProvider/index.js";
|
|
3
3
|
export { RichTreeViewItems } from "./components/RichTreeViewItems.js";
|
|
4
4
|
export { unstable_resetCleanupTracking } from "./hooks/useInstanceEventHandler.js";
|
|
5
|
+
export { useSelector } from "./hooks/useSelector.js";
|
|
5
6
|
|
|
6
7
|
// Core plugins
|
|
7
8
|
|
|
@@ -12,6 +13,9 @@ export { useTreeViewFocus } from "./plugins/useTreeViewFocus/index.js";
|
|
|
12
13
|
export { useTreeViewKeyboardNavigation } from "./plugins/useTreeViewKeyboardNavigation/index.js";
|
|
13
14
|
export { useTreeViewIcons } from "./plugins/useTreeViewIcons/index.js";
|
|
14
15
|
export { useTreeViewItems, buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from "./plugins/useTreeViewItems/index.js";
|
|
16
|
+
export { selectorItemMetaLookup, selectorItemMeta, selectorItemIndex, selectorItemOrderedChildrenIds } from "./plugins/useTreeViewItems/useTreeViewItems.selectors.js";
|
|
15
17
|
export { useTreeViewLabel } from "./plugins/useTreeViewLabel/index.js";
|
|
16
18
|
export { useTreeViewJSXItems } from "./plugins/useTreeViewJSXItems/index.js";
|
|
17
|
-
export {
|
|
19
|
+
export { createSelector } from "./utils/selectors.js";
|
|
20
|
+
export { isTargetInDescendants } from "./utils/tree.js";
|
|
21
|
+
export { TreeViewStore } from "./utils/TreeViewStore.js";
|
|
@@ -1,30 +1,35 @@
|
|
|
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 useEnhancedEffect from '@mui/utils/useEnhancedEffect';
|
|
5
|
+
import { selectorIsItemExpandable, selectorIsItemExpanded } from "./useTreeViewExpansion.selectors.js";
|
|
6
|
+
import { createExpandedItemsMap } from "./useTreeViewExpansion.utils.js";
|
|
7
|
+
import { selectorItemMeta, selectorItemOrderedChildrenIds } from "../useTreeViewItems/useTreeViewItems.selectors.js";
|
|
4
8
|
export const useTreeViewExpansion = ({
|
|
5
9
|
instance,
|
|
10
|
+
store,
|
|
6
11
|
params,
|
|
7
|
-
models
|
|
12
|
+
models,
|
|
13
|
+
experimentalFeatures
|
|
8
14
|
}) => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
const isTreeViewEditable = Boolean(params.isItemEditable) && !!experimentalFeatures.labelEditing;
|
|
16
|
+
useEnhancedEffect(() => {
|
|
17
|
+
store.update(prevState => _extends({}, prevState, {
|
|
18
|
+
expansion: {
|
|
19
|
+
expandedItemsMap: createExpandedItemsMap(models.expandedItems.value)
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
}, [store, models.expandedItems.value]);
|
|
16
23
|
const setExpandedItems = (event, value) => {
|
|
17
24
|
params.onExpandedItemsChange?.(event, value);
|
|
18
25
|
models.expandedItems.setControlledValue(value);
|
|
19
26
|
};
|
|
20
|
-
const isItemExpanded = React.useCallback(itemId => expandedItemsMap.has(itemId), [expandedItemsMap]);
|
|
21
|
-
const isItemExpandable = React.useCallback(itemId => !!instance.getItemMeta(itemId)?.expandable, [instance]);
|
|
22
27
|
const toggleItemExpansion = useEventCallback((event, itemId) => {
|
|
23
|
-
const isExpandedBefore =
|
|
28
|
+
const isExpandedBefore = selectorIsItemExpanded(store.value, itemId);
|
|
24
29
|
instance.setItemExpansion(event, itemId, !isExpandedBefore);
|
|
25
30
|
});
|
|
26
31
|
const setItemExpansion = useEventCallback((event, itemId, isExpanded) => {
|
|
27
|
-
const isExpandedBefore =
|
|
32
|
+
const isExpandedBefore = selectorIsItemExpanded(store.value, itemId);
|
|
28
33
|
if (isExpandedBefore === isExpanded) {
|
|
29
34
|
return;
|
|
30
35
|
}
|
|
@@ -40,9 +45,12 @@ export const useTreeViewExpansion = ({
|
|
|
40
45
|
setExpandedItems(event, newExpanded);
|
|
41
46
|
});
|
|
42
47
|
const expandAllSiblings = (event, itemId) => {
|
|
43
|
-
const itemMeta =
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
const itemMeta = selectorItemMeta(store.value, itemId);
|
|
49
|
+
if (itemMeta == null) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const siblings = selectorItemOrderedChildrenIds(store.value, itemMeta.parentId);
|
|
53
|
+
const diff = siblings.filter(child => selectorIsItemExpandable(store.value, child) && !selectorIsItemExpanded(store.value, child));
|
|
46
54
|
const newExpanded = models.expandedItems.value.concat(diff);
|
|
47
55
|
if (diff.length > 0) {
|
|
48
56
|
if (params.onItemExpansionToggle) {
|
|
@@ -57,27 +65,26 @@ export const useTreeViewExpansion = ({
|
|
|
57
65
|
if (params.expansionTrigger) {
|
|
58
66
|
return params.expansionTrigger;
|
|
59
67
|
}
|
|
60
|
-
if (
|
|
68
|
+
if (isTreeViewEditable) {
|
|
61
69
|
return 'iconContainer';
|
|
62
70
|
}
|
|
63
71
|
return 'content';
|
|
64
|
-
}, [params.expansionTrigger,
|
|
72
|
+
}, [params.expansionTrigger, isTreeViewEditable]);
|
|
73
|
+
const pluginContextValue = React.useMemo(() => ({
|
|
74
|
+
expansion: {
|
|
75
|
+
expansionTrigger
|
|
76
|
+
}
|
|
77
|
+
}), [expansionTrigger]);
|
|
65
78
|
return {
|
|
66
79
|
publicAPI: {
|
|
67
80
|
setItemExpansion
|
|
68
81
|
},
|
|
69
82
|
instance: {
|
|
70
|
-
isItemExpanded,
|
|
71
|
-
isItemExpandable,
|
|
72
83
|
setItemExpansion,
|
|
73
84
|
toggleItemExpansion,
|
|
74
85
|
expandAllSiblings
|
|
75
86
|
},
|
|
76
|
-
contextValue:
|
|
77
|
-
expansion: {
|
|
78
|
-
expansionTrigger
|
|
79
|
-
}
|
|
80
|
-
}
|
|
87
|
+
contextValue: pluginContextValue
|
|
81
88
|
};
|
|
82
89
|
};
|
|
83
90
|
useTreeViewExpansion.models = {
|
|
@@ -91,6 +98,11 @@ useTreeViewExpansion.getDefaultizedParams = ({
|
|
|
91
98
|
}) => _extends({}, params, {
|
|
92
99
|
defaultExpandedItems: params.defaultExpandedItems ?? DEFAULT_EXPANDED_ITEMS
|
|
93
100
|
});
|
|
101
|
+
useTreeViewExpansion.getInitialState = params => ({
|
|
102
|
+
expansion: {
|
|
103
|
+
expandedItemsMap: createExpandedItemsMap(params.expandedItems === undefined ? params.defaultExpandedItems : params.expandedItems)
|
|
104
|
+
}
|
|
105
|
+
});
|
|
94
106
|
useTreeViewExpansion.params = {
|
|
95
107
|
expandedItems: true,
|
|
96
108
|
defaultExpandedItems: true,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createSelector } from "../../utils/selectors.js";
|
|
2
|
+
import { selectorItemMeta } from "../useTreeViewItems/useTreeViewItems.selectors.js";
|
|
3
|
+
const selectorExpansion = state => state.expansion;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if an item is expanded.
|
|
7
|
+
* @param {TreeViewState<[UseTreeViewExpansionSignature]>} state The state of the tree view.
|
|
8
|
+
* @returns {boolean} `true` if the item is expanded, `false` otherwise.
|
|
9
|
+
*/
|
|
10
|
+
export const selectorIsItemExpanded = createSelector([selectorExpansion, (_, itemId) => itemId], (expansionState, itemId) => expansionState.expandedItemsMap.has(itemId));
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if an item is expandable.
|
|
14
|
+
* @param {TreeViewState<[UseTreeViewItemsSignature]>} state The state of the tree view.
|
|
15
|
+
* @returns {boolean} `true` if the item is expandable, `false` otherwise.
|
|
16
|
+
*/
|
|
17
|
+
export const selectorIsItemExpandable = createSelector([selectorItemMeta], itemMeta => itemMeta?.expandable ?? false);
|