@mui/x-tree-view 7.0.0-beta.5 → 7.0.0-beta.6
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 +135 -49
- package/RichTreeView/RichTreeView.js +2 -1
- package/SimpleTreeView/SimpleTreeView.js +2 -1
- package/TreeItem/TreeItem.js +24 -28
- package/TreeItem/TreeItem.types.d.ts +7 -11
- package/TreeItem/treeItemClasses.d.ts +1 -1
- package/TreeItem/treeItemClasses.js +1 -1
- package/TreeView/TreeView.js +2 -1
- package/hooks/useTreeViewApiRef.d.ts +2 -2
- package/index.js +1 -1
- package/internals/models/helpers.d.ts +1 -0
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +1 -2
- package/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +20 -6
- package/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +29 -16
- package/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.d.ts +16 -6
- package/modern/RichTreeView/RichTreeView.js +2 -1
- package/modern/SimpleTreeView/SimpleTreeView.js +2 -1
- package/modern/TreeItem/TreeItem.js +23 -27
- package/modern/TreeItem/treeItemClasses.js +1 -1
- package/modern/TreeView/TreeView.js +2 -1
- package/modern/index.js +1 -1
- package/modern/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +20 -6
- package/modern/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +29 -16
- package/node/RichTreeView/RichTreeView.js +2 -1
- package/node/SimpleTreeView/SimpleTreeView.js +2 -1
- package/node/TreeItem/TreeItem.js +23 -27
- package/node/TreeItem/treeItemClasses.js +1 -1
- package/node/TreeView/TreeView.js +2 -1
- package/node/index.js +1 -1
- package/node/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.js +20 -6
- package/node/internals/plugins/useTreeViewNodes/useTreeViewNodes.js +28 -15
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ export interface TreeItemClasses {
|
|
|
2
2
|
/** Styles applied to the root element. */
|
|
3
3
|
root: string;
|
|
4
4
|
/** Styles applied to the transition component. */
|
|
5
|
-
|
|
5
|
+
groupTransition: string;
|
|
6
6
|
/** Styles applied to the content element. */
|
|
7
7
|
content: string;
|
|
8
8
|
/** State class applied to the content element when expanded. */
|
|
@@ -3,4 +3,4 @@ import generateUtilityClasses from '@mui/utils/generateUtilityClasses';
|
|
|
3
3
|
export function getTreeItemUtilityClass(slot) {
|
|
4
4
|
return generateUtilityClass('MuiTreeItem', slot);
|
|
5
5
|
}
|
|
6
|
-
export const treeItemClasses = generateUtilityClasses('MuiTreeItem', ['root', '
|
|
6
|
+
export const treeItemClasses = generateUtilityClasses('MuiTreeItem', ['root', 'groupTransition', 'content', 'expanded', 'selected', 'focused', 'disabled', 'iconContainer', 'label']);
|
package/TreeView/TreeView.js
CHANGED
|
@@ -69,7 +69,8 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
|
|
|
69
69
|
*/
|
|
70
70
|
apiRef: PropTypes.shape({
|
|
71
71
|
current: PropTypes.shape({
|
|
72
|
-
focusNode: PropTypes.func.isRequired
|
|
72
|
+
focusNode: PropTypes.func.isRequired,
|
|
73
|
+
getItem: PropTypes.func.isRequired
|
|
73
74
|
})
|
|
74
75
|
}),
|
|
75
76
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { TreeViewAnyPluginSignature,
|
|
2
|
+
import { TreeViewAnyPluginSignature, TreeViewPublicAPI } from '../internals/models';
|
|
3
3
|
/**
|
|
4
4
|
* Hook that instantiates a [[TreeViewApiRef]].
|
|
5
5
|
*/
|
|
6
|
-
export declare const useTreeViewApiRef: <
|
|
6
|
+
export declare const useTreeViewApiRef: <TPlugins extends readonly TreeViewAnyPluginSignature[] = [import("../internals").UseTreeViewIdSignature, import("../internals").UseTreeViewNodesSignature, import("../internals").UseTreeViewExpansionSignature, import("../internals").UseTreeViewSelectionSignature, import("../internals").UseTreeViewFocusSignature, import("../internals").UseTreeViewKeyboardNavigationSignature, import("../internals").UseTreeViewIconsSignature]>() => React.MutableRefObject<TreeViewPublicAPI<TPlugins> | undefined>;
|
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TreeViewAnyPluginSignature, TreeViewPlugin } from './plugin';
|
|
2
2
|
export type DefaultizedProps<P extends {}, RequiredProps extends keyof P, AdditionalProps extends {} = {}> = Omit<P, RequiredProps | keyof AdditionalProps> & Required<Pick<P, RequiredProps>> & AdditionalProps;
|
|
3
|
+
export type SlotComponentPropsFromProps<TProps extends {}, TOverrides extends {}, TOwnerState extends {}> = (Partial<TProps> & TOverrides) | ((ownerState: TOwnerState) => Partial<TProps> & TOverrides);
|
|
3
4
|
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
4
5
|
export type OptionalIfEmpty<A extends string, B> = keyof B extends never ? Partial<Record<A, B>> : IsAny<B> extends true ? Partial<Record<A, B>> : Record<A, B>;
|
|
5
6
|
export type MergePluginsProperty<TPlugins extends readonly any[], TProperty extends keyof TreeViewAnyPluginSignature> = TPlugins extends readonly [plugin: infer P, ...otherPlugin: infer R] ? P extends TreeViewAnyPluginSignature ? P[TProperty] & MergePluginsProperty<R, TProperty> : {} : {};
|
|
@@ -10,8 +10,7 @@ export interface UseTreeViewFocusInstance {
|
|
|
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, 'focusNode'> {
|
|
15
14
|
}
|
|
16
15
|
export interface UseTreeViewFocusParameters {
|
|
17
16
|
/**
|
|
@@ -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', {
|
|
@@ -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,20 +86,22 @@ 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
107
|
const getNodesToRender = useEventCallback(() => {
|
|
@@ -102,7 +109,7 @@ export const useTreeViewNodes = ({
|
|
|
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);
|
|
120
|
+
return state.nodes.nodeTree.map(getPropsFromNodeId);
|
|
114
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 {};
|
|
@@ -137,7 +137,8 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
137
137
|
*/
|
|
138
138
|
apiRef: PropTypes.shape({
|
|
139
139
|
current: PropTypes.shape({
|
|
140
|
-
focusNode: PropTypes.func.isRequired
|
|
140
|
+
focusNode: PropTypes.func.isRequired,
|
|
141
|
+
getItem: PropTypes.func.isRequired
|
|
141
142
|
})
|
|
142
143
|
}),
|
|
143
144
|
/**
|
|
@@ -95,7 +95,8 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
|
|
|
95
95
|
*/
|
|
96
96
|
apiRef: PropTypes.shape({
|
|
97
97
|
current: PropTypes.shape({
|
|
98
|
-
focusNode: PropTypes.func.isRequired
|
|
98
|
+
focusNode: PropTypes.func.isRequired,
|
|
99
|
+
getItem: PropTypes.func.isRequired
|
|
99
100
|
})
|
|
100
101
|
}),
|
|
101
102
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
2
2
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
3
|
-
const _excluded = ["children", "className", "slots", "slotProps", "ContentComponent", "ContentProps", "nodeId", "id", "label", "onClick", "onMouseDown"
|
|
3
|
+
const _excluded = ["children", "className", "slots", "slotProps", "ContentComponent", "ContentProps", "nodeId", "id", "label", "onClick", "onMouseDown"],
|
|
4
4
|
_excluded2 = ["ownerState"],
|
|
5
5
|
_excluded3 = ["ownerState"],
|
|
6
6
|
_excluded4 = ["ownerState"];
|
|
@@ -32,7 +32,7 @@ const useUtilityClasses = ownerState => {
|
|
|
32
32
|
disabled: ['disabled'],
|
|
33
33
|
iconContainer: ['iconContainer'],
|
|
34
34
|
label: ['label'],
|
|
35
|
-
|
|
35
|
+
groupTransition: ['groupTransition']
|
|
36
36
|
};
|
|
37
37
|
return composeClasses(slots, getTreeItemUtilityClass, classes);
|
|
38
38
|
};
|
|
@@ -116,8 +116,8 @@ const StyledTreeItemContent = styled(TreeItemContent, {
|
|
|
116
116
|
}));
|
|
117
117
|
const TreeItemGroup = styled(Collapse, {
|
|
118
118
|
name: 'MuiTreeItem',
|
|
119
|
-
slot: '
|
|
120
|
-
overridesResolver: (props, styles) => styles.
|
|
119
|
+
slot: 'GroupTransition',
|
|
120
|
+
overridesResolver: (props, styles) => styles.groupTransition
|
|
121
121
|
})({
|
|
122
122
|
margin: 0,
|
|
123
123
|
padding: 0,
|
|
@@ -167,16 +167,15 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
167
167
|
id,
|
|
168
168
|
label,
|
|
169
169
|
onClick,
|
|
170
|
-
onMouseDown
|
|
171
|
-
TransitionComponent = Collapse,
|
|
172
|
-
TransitionProps
|
|
170
|
+
onMouseDown
|
|
173
171
|
} = props,
|
|
174
172
|
other = _objectWithoutPropertiesLoose(props, _excluded);
|
|
175
173
|
const slots = {
|
|
176
174
|
expandIcon: inSlots?.expandIcon ?? contextIcons.slots.expandIcon ?? TreeViewExpandIcon,
|
|
177
175
|
collapseIcon: inSlots?.collapseIcon ?? contextIcons.slots.collapseIcon ?? TreeViewCollapseIcon,
|
|
178
176
|
endIcon: inSlots?.endIcon ?? contextIcons.slots.endIcon,
|
|
179
|
-
icon: inSlots?.icon
|
|
177
|
+
icon: inSlots?.icon,
|
|
178
|
+
groupTransition: inSlots?.groupTransition
|
|
180
179
|
};
|
|
181
180
|
const isExpandable = reactChildren => {
|
|
182
181
|
if (Array.isArray(reactChildren)) {
|
|
@@ -196,6 +195,19 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
196
195
|
disabled
|
|
197
196
|
});
|
|
198
197
|
const classes = useUtilityClasses(ownerState);
|
|
198
|
+
const GroupTransition = slots.groupTransition ?? undefined;
|
|
199
|
+
const groupTransitionProps = useSlotProps({
|
|
200
|
+
elementType: GroupTransition,
|
|
201
|
+
ownerState: {},
|
|
202
|
+
externalSlotProps: inSlotProps?.groupTransition,
|
|
203
|
+
additionalProps: {
|
|
204
|
+
unmountOnExit: true,
|
|
205
|
+
in: expanded,
|
|
206
|
+
component: 'ul',
|
|
207
|
+
role: 'group'
|
|
208
|
+
},
|
|
209
|
+
className: classes.groupTransition
|
|
210
|
+
});
|
|
199
211
|
const ExpansionIcon = expanded ? slots.collapseIcon : slots.expandIcon;
|
|
200
212
|
const _useSlotProps = useSlotProps({
|
|
201
213
|
elementType: ExpansionIcon,
|
|
@@ -285,13 +297,8 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
285
297
|
displayIcon: displayIcon,
|
|
286
298
|
ownerState: ownerState
|
|
287
299
|
}, ContentProps)), children && /*#__PURE__*/_jsx(TreeItemGroup, _extends({
|
|
288
|
-
as:
|
|
289
|
-
|
|
290
|
-
className: classes.group,
|
|
291
|
-
in: expanded,
|
|
292
|
-
component: "ul",
|
|
293
|
-
role: "group"
|
|
294
|
-
}, TransitionProps, {
|
|
300
|
+
as: GroupTransition
|
|
301
|
+
}, groupTransitionProps, {
|
|
295
302
|
children: children
|
|
296
303
|
}))]
|
|
297
304
|
}));
|
|
@@ -351,16 +358,5 @@ TreeItem.propTypes = {
|
|
|
351
358
|
/**
|
|
352
359
|
* The system prop that allows defining system overrides as well as additional CSS styles.
|
|
353
360
|
*/
|
|
354
|
-
sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object])
|
|
355
|
-
/**
|
|
356
|
-
* The component used for the transition.
|
|
357
|
-
* [Follow this guide](/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
|
|
358
|
-
* @default Collapse
|
|
359
|
-
*/
|
|
360
|
-
TransitionComponent: PropTypes.elementType,
|
|
361
|
-
/**
|
|
362
|
-
* Props applied to the transition element.
|
|
363
|
-
* By default, the element is based on this [`Transition`](https://reactcommunity.org/react-transition-group/transition/) component.
|
|
364
|
-
*/
|
|
365
|
-
TransitionProps: PropTypes.object
|
|
361
|
+
sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object])
|
|
366
362
|
};
|
|
@@ -3,4 +3,4 @@ import generateUtilityClasses from '@mui/utils/generateUtilityClasses';
|
|
|
3
3
|
export function getTreeItemUtilityClass(slot) {
|
|
4
4
|
return generateUtilityClass('MuiTreeItem', slot);
|
|
5
5
|
}
|
|
6
|
-
export const treeItemClasses = generateUtilityClasses('MuiTreeItem', ['root', '
|
|
6
|
+
export const treeItemClasses = generateUtilityClasses('MuiTreeItem', ['root', 'groupTransition', 'content', 'expanded', 'selected', 'focused', 'disabled', 'iconContainer', 'label']);
|
|
@@ -69,7 +69,8 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
|
|
|
69
69
|
*/
|
|
70
70
|
apiRef: PropTypes.shape({
|
|
71
71
|
current: PropTypes.shape({
|
|
72
|
-
focusNode: PropTypes.func.isRequired
|
|
72
|
+
focusNode: PropTypes.func.isRequired,
|
|
73
|
+
getItem: PropTypes.func.isRequired
|
|
73
74
|
})
|
|
74
75
|
}),
|
|
75
76
|
/**
|
package/modern/index.js
CHANGED
|
@@ -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', {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import useEventCallback from '@mui/utils/useEventCallback';
|
|
4
|
-
import { populateInstance } from '../../useTreeView/useTreeView.utils';
|
|
4
|
+
import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
|
|
5
5
|
import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
|
|
6
|
-
const
|
|
6
|
+
const updateNodesState = ({
|
|
7
7
|
items,
|
|
8
8
|
isItemDisabled,
|
|
9
9
|
getItemLabel,
|
|
10
10
|
getItemId
|
|
11
11
|
}) => {
|
|
12
12
|
const nodeMap = {};
|
|
13
|
+
const itemMap = {};
|
|
13
14
|
const processItem = (item, index, parentId) => {
|
|
14
15
|
const id = getItemId ? getItemId(item) : item.id;
|
|
15
16
|
if (id == null) {
|
|
@@ -27,10 +28,11 @@ const updateState = ({
|
|
|
27
28
|
label,
|
|
28
29
|
index,
|
|
29
30
|
parentId,
|
|
30
|
-
idAttribute:
|
|
31
|
+
idAttribute: undefined,
|
|
31
32
|
expandable: !!item.children?.length,
|
|
32
33
|
disabled: isItemDisabled ? isItemDisabled(item) : false
|
|
33
34
|
};
|
|
35
|
+
itemMap[id] = item;
|
|
34
36
|
return {
|
|
35
37
|
id,
|
|
36
38
|
children: item.children?.map((child, childIndex) => processItem(child, childIndex, id))
|
|
@@ -39,16 +41,19 @@ const updateState = ({
|
|
|
39
41
|
const nodeTree = items.map((item, itemIndex) => processItem(item, itemIndex, null));
|
|
40
42
|
return {
|
|
41
43
|
nodeMap,
|
|
42
|
-
nodeTree
|
|
44
|
+
nodeTree,
|
|
45
|
+
itemMap
|
|
43
46
|
};
|
|
44
47
|
};
|
|
45
48
|
export const useTreeViewNodes = ({
|
|
46
49
|
instance,
|
|
50
|
+
publicAPI,
|
|
47
51
|
params,
|
|
48
52
|
state,
|
|
49
53
|
setState
|
|
50
54
|
}) => {
|
|
51
|
-
const getNode = React.useCallback(nodeId => state.nodeMap[nodeId], [state.nodeMap]);
|
|
55
|
+
const getNode = React.useCallback(nodeId => state.nodes.nodeMap[nodeId], [state.nodes.nodeMap]);
|
|
56
|
+
const getItem = React.useCallback(nodeId => state.nodes.itemMap[nodeId], [state.nodes.itemMap]);
|
|
52
57
|
const isNodeDisabled = React.useCallback(nodeId => {
|
|
53
58
|
if (nodeId == null) {
|
|
54
59
|
return false;
|
|
@@ -70,7 +75,7 @@ export const useTreeViewNodes = ({
|
|
|
70
75
|
}
|
|
71
76
|
return false;
|
|
72
77
|
}, [instance]);
|
|
73
|
-
const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
|
|
78
|
+
const getChildrenIds = useEventCallback(nodeId => Object.values(state.nodes.nodeMap).filter(node => node.parentId === nodeId).sort((a, b) => a.index - b.index).map(child => child.id));
|
|
74
79
|
const getNavigableChildrenIds = nodeId => {
|
|
75
80
|
let childrenIds = instance.getChildrenIds(nodeId);
|
|
76
81
|
if (!params.disabledItemsFocusable) {
|
|
@@ -80,20 +85,22 @@ export const useTreeViewNodes = ({
|
|
|
80
85
|
};
|
|
81
86
|
React.useEffect(() => {
|
|
82
87
|
setState(prevState => {
|
|
83
|
-
const newState =
|
|
88
|
+
const newState = updateNodesState({
|
|
84
89
|
items: params.items,
|
|
85
90
|
isItemDisabled: params.isItemDisabled,
|
|
86
91
|
getItemId: params.getItemId,
|
|
87
92
|
getItemLabel: params.getItemLabel
|
|
88
93
|
});
|
|
89
|
-
Object.values(prevState.nodeMap).forEach(node => {
|
|
94
|
+
Object.values(prevState.nodes.nodeMap).forEach(node => {
|
|
90
95
|
if (!newState.nodeMap[node.id]) {
|
|
91
96
|
publishTreeViewEvent(instance, 'removeNode', {
|
|
92
97
|
id: node.id
|
|
93
98
|
});
|
|
94
99
|
}
|
|
95
100
|
});
|
|
96
|
-
return _extends({}, prevState,
|
|
101
|
+
return _extends({}, prevState, {
|
|
102
|
+
nodes: newState
|
|
103
|
+
});
|
|
97
104
|
});
|
|
98
105
|
}, [instance, setState, params.items, params.isItemDisabled, params.getItemId, params.getItemLabel]);
|
|
99
106
|
const getNodesToRender = useEventCallback(() => {
|
|
@@ -101,7 +108,7 @@ export const useTreeViewNodes = ({
|
|
|
101
108
|
id,
|
|
102
109
|
children
|
|
103
110
|
}) => {
|
|
104
|
-
const node = state.nodeMap[id];
|
|
111
|
+
const node = state.nodes.nodeMap[id];
|
|
105
112
|
return {
|
|
106
113
|
label: node.label,
|
|
107
114
|
nodeId: node.id,
|
|
@@ -109,26 +116,32 @@ export const useTreeViewNodes = ({
|
|
|
109
116
|
children: children?.map(getPropsFromNodeId)
|
|
110
117
|
};
|
|
111
118
|
};
|
|
112
|
-
return state.nodeTree.map(getPropsFromNodeId);
|
|
119
|
+
return state.nodes.nodeTree.map(getPropsFromNodeId);
|
|
113
120
|
});
|
|
114
121
|
populateInstance(instance, {
|
|
115
122
|
getNode,
|
|
123
|
+
getItem,
|
|
116
124
|
getNodesToRender,
|
|
117
125
|
getChildrenIds,
|
|
118
126
|
getNavigableChildrenIds,
|
|
119
127
|
isNodeDisabled
|
|
120
128
|
});
|
|
129
|
+
populatePublicAPI(publicAPI, {
|
|
130
|
+
getItem
|
|
131
|
+
});
|
|
121
132
|
return {
|
|
122
133
|
contextValue: {
|
|
123
134
|
disabledItemsFocusable: params.disabledItemsFocusable
|
|
124
135
|
}
|
|
125
136
|
};
|
|
126
137
|
};
|
|
127
|
-
useTreeViewNodes.getInitialState = params =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
useTreeViewNodes.getInitialState = params => ({
|
|
139
|
+
nodes: updateNodesState({
|
|
140
|
+
items: params.items,
|
|
141
|
+
isItemDisabled: params.isItemDisabled,
|
|
142
|
+
getItemId: params.getItemId,
|
|
143
|
+
getItemLabel: params.getItemLabel
|
|
144
|
+
})
|
|
132
145
|
});
|
|
133
146
|
useTreeViewNodes.getDefaultizedParams = params => _extends({}, params, {
|
|
134
147
|
disabledItemsFocusable: params.disabledItemsFocusable ?? false
|
|
@@ -146,7 +146,8 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
146
146
|
*/
|
|
147
147
|
apiRef: _propTypes.default.shape({
|
|
148
148
|
current: _propTypes.default.shape({
|
|
149
|
-
focusNode: _propTypes.default.func.isRequired
|
|
149
|
+
focusNode: _propTypes.default.func.isRequired,
|
|
150
|
+
getItem: _propTypes.default.func.isRequired
|
|
150
151
|
})
|
|
151
152
|
}),
|
|
152
153
|
/**
|
|
@@ -104,7 +104,8 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
|
|
|
104
104
|
*/
|
|
105
105
|
apiRef: _propTypes.default.shape({
|
|
106
106
|
current: _propTypes.default.shape({
|
|
107
|
-
focusNode: _propTypes.default.func.isRequired
|
|
107
|
+
focusNode: _propTypes.default.func.isRequired,
|
|
108
|
+
getItem: _propTypes.default.func.isRequired
|
|
108
109
|
})
|
|
109
110
|
}),
|
|
110
111
|
/**
|