@mui/x-tree-view 7.1.0 → 7.2.0
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 +261 -4
- package/README.md +1 -1
- package/RichTreeView/RichTreeView.d.ts +2 -2
- package/RichTreeView/RichTreeView.js +7 -5
- package/RichTreeView/RichTreeView.types.d.ts +3 -3
- package/SimpleTreeView/SimpleTreeView.js +4 -2
- package/TreeItem/TreeItem.js +1 -1
- package/TreeItem2/TreeItem2.d.ts +5 -1
- package/TreeItem2/TreeItem2.js +0 -1
- package/TreeView/TreeView.js +2 -1
- package/index.js +1 -1
- package/internals/TreeViewProvider/TreeViewChildrenItemProvider.d.ts +16 -0
- package/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +57 -0
- package/internals/TreeViewProvider/TreeViewContext.d.ts +2 -0
- package/internals/TreeViewProvider/TreeViewProvider.js +2 -3
- package/internals/TreeViewProvider/TreeViewProvider.types.d.ts +3 -1
- package/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +7 -8
- package/internals/index.d.ts +18 -8
- package/internals/index.js +11 -0
- package/internals/models/plugin.d.ts +14 -6
- package/internals/models/treeView.d.ts +1 -2
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +33 -19
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +12 -2
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +25 -26
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +12 -4
- package/internals/plugins/useTreeViewId/useTreeViewId.js +5 -7
- package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +1 -1
- package/internals/plugins/useTreeViewItems/useTreeViewItems.js +61 -51
- package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +30 -21
- package/internals/plugins/useTreeViewItems/useTreeViewItems.utils.d.ts +4 -0
- package/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +8 -0
- package/internals/plugins/useTreeViewJSXItems/index.d.ts +1 -1
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +67 -42
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.d.ts +5 -4
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +20 -18
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +11 -22
- package/internals/useTreeView/useTreeView.js +21 -3
- package/internals/useTreeView/useTreeViewModels.js +2 -2
- package/internals/utils/tree.d.ts +8 -0
- package/internals/utils/tree.js +137 -0
- package/modern/RichTreeView/RichTreeView.js +7 -5
- package/modern/SimpleTreeView/SimpleTreeView.js +4 -2
- package/modern/TreeItem/TreeItem.js +1 -1
- package/modern/TreeItem2/TreeItem2.js +0 -1
- package/modern/TreeView/TreeView.js +2 -1
- package/modern/index.js +1 -1
- package/modern/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +57 -0
- package/modern/internals/TreeViewProvider/TreeViewProvider.js +2 -3
- package/modern/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +7 -8
- package/modern/internals/index.js +11 -0
- package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +33 -19
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +25 -26
- package/modern/internals/plugins/useTreeViewId/useTreeViewId.js +5 -7
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +61 -51
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +8 -0
- package/modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +67 -42
- package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +20 -18
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +11 -22
- package/modern/internals/useTreeView/useTreeView.js +21 -3
- package/modern/internals/useTreeView/useTreeViewModels.js +2 -2
- package/modern/internals/utils/tree.js +137 -0
- package/modern/useTreeItem2/useTreeItem2.js +1 -1
- package/node/RichTreeView/RichTreeView.js +7 -5
- package/node/SimpleTreeView/SimpleTreeView.js +4 -2
- package/node/TreeItem/TreeItem.js +1 -1
- package/node/TreeItem2/TreeItem2.js +0 -1
- package/node/TreeView/TreeView.js +2 -1
- package/node/index.js +1 -1
- package/node/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +67 -0
- package/node/internals/TreeViewProvider/TreeViewProvider.js +2 -3
- package/node/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +7 -8
- package/node/internals/index.js +70 -0
- package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +33 -19
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +25 -26
- package/node/internals/plugins/useTreeViewId/useTreeViewId.js +5 -7
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +61 -51
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +15 -0
- package/node/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +67 -42
- package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +20 -18
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +11 -22
- package/node/internals/useTreeView/useTreeView.js +21 -3
- package/node/internals/useTreeView/useTreeViewModels.js +2 -2
- package/node/internals/utils/tree.js +148 -0
- package/node/useTreeItem2/useTreeItem2.js +1 -1
- package/package.json +2 -2
- package/useTreeItem2/useTreeItem2.js +1 -1
- package/internals/TreeViewProvider/DescendantProvider.d.ts +0 -38
- package/internals/TreeViewProvider/DescendantProvider.js +0 -176
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.d.ts +0 -17
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +0 -55
- package/internals/useTreeView/useTreeView.utils.d.ts +0 -9
- package/internals/useTreeView/useTreeView.utils.js +0 -46
- package/modern/internals/TreeViewProvider/DescendantProvider.js +0 -176
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +0 -55
- package/modern/internals/useTreeView/useTreeView.utils.js +0 -46
- package/node/internals/TreeViewProvider/DescendantProvider.js +0 -185
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +0 -62
- package/node/internals/useTreeView/useTreeView.utils.js +0 -58
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const getLastNavigableItemInArray = (instance, items) => {
|
|
2
|
+
// Equivalent to Array.prototype.findLastIndex
|
|
3
|
+
let itemIndex = items.length - 1;
|
|
4
|
+
while (itemIndex >= 0 && !instance.isItemNavigable(items[itemIndex])) {
|
|
5
|
+
itemIndex -= 1;
|
|
6
|
+
}
|
|
7
|
+
if (itemIndex === -1) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return items[itemIndex];
|
|
11
|
+
};
|
|
12
|
+
export const getPreviousNavigableItem = (instance, itemId) => {
|
|
13
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
14
|
+
const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
|
|
15
|
+
const itemIndex = instance.getItemIndex(itemId);
|
|
16
|
+
|
|
17
|
+
// TODO: What should we do if the parent is not navigable?
|
|
18
|
+
if (itemIndex === 0) {
|
|
19
|
+
return itemMeta.parentId;
|
|
20
|
+
}
|
|
21
|
+
let currentItemId = siblings[itemIndex - 1];
|
|
22
|
+
let lastNavigableChild = getLastNavigableItemInArray(instance, instance.getItemOrderedChildrenIds(currentItemId));
|
|
23
|
+
while (instance.isItemExpanded(currentItemId) && lastNavigableChild != null) {
|
|
24
|
+
currentItemId = lastNavigableChild;
|
|
25
|
+
lastNavigableChild = instance.getItemOrderedChildrenIds(currentItemId).find(instance.isItemNavigable);
|
|
26
|
+
}
|
|
27
|
+
return currentItemId;
|
|
28
|
+
};
|
|
29
|
+
export const getNextNavigableItem = (instance, itemId) => {
|
|
30
|
+
// If the item is expanded and has some navigable children, return the first of them.
|
|
31
|
+
if (instance.isItemExpanded(itemId)) {
|
|
32
|
+
const firstNavigableChild = instance.getItemOrderedChildrenIds(itemId).find(instance.isItemNavigable);
|
|
33
|
+
if (firstNavigableChild != null) {
|
|
34
|
+
return firstNavigableChild;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
let itemMeta = instance.getItemMeta(itemId);
|
|
38
|
+
while (itemMeta != null) {
|
|
39
|
+
// Try to find the first navigable sibling after the current item.
|
|
40
|
+
const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
|
|
41
|
+
const currentItemIndex = instance.getItemIndex(itemMeta.id);
|
|
42
|
+
if (currentItemIndex < siblings.length - 1) {
|
|
43
|
+
let nextItemIndex = currentItemIndex + 1;
|
|
44
|
+
while (!instance.isItemNavigable(siblings[nextItemIndex]) && nextItemIndex < siblings.length - 1) {
|
|
45
|
+
nextItemIndex += 1;
|
|
46
|
+
}
|
|
47
|
+
if (instance.isItemNavigable(siblings[nextItemIndex])) {
|
|
48
|
+
return siblings[nextItemIndex];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// If the sibling does not exist, go up a level to the parent and try again.
|
|
53
|
+
itemMeta = instance.getItemMeta(itemMeta.parentId);
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
export const getLastNavigableItem = instance => {
|
|
58
|
+
let itemId = null;
|
|
59
|
+
while (itemId == null || instance.isItemExpanded(itemId)) {
|
|
60
|
+
const children = instance.getItemOrderedChildrenIds(itemId);
|
|
61
|
+
const lastNavigableChild = getLastNavigableItemInArray(instance, children);
|
|
62
|
+
|
|
63
|
+
// The item has no navigable children.
|
|
64
|
+
if (lastNavigableChild == null) {
|
|
65
|
+
return itemId;
|
|
66
|
+
}
|
|
67
|
+
itemId = lastNavigableChild;
|
|
68
|
+
}
|
|
69
|
+
return itemId;
|
|
70
|
+
};
|
|
71
|
+
export const getFirstNavigableItem = instance => instance.getItemOrderedChildrenIds(null).find(instance.isItemNavigable);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* This is used to determine the start and end of a selection range so
|
|
75
|
+
* we can get the items between the two border items.
|
|
76
|
+
*
|
|
77
|
+
* It finds the items' common ancestor using
|
|
78
|
+
* a naive implementation of a lowest common ancestor algorithm
|
|
79
|
+
* (https://en.wikipedia.org/wiki/Lowest_common_ancestor).
|
|
80
|
+
* Then compares the ancestor's 2 children that are ancestors of itemA and ItemB
|
|
81
|
+
* so we can compare their indexes to work out which item comes first in a depth first search.
|
|
82
|
+
* (https://en.wikipedia.org/wiki/Depth-first_search)
|
|
83
|
+
*
|
|
84
|
+
* Another way to put it is which item is shallower in a trémaux tree
|
|
85
|
+
* https://en.wikipedia.org/wiki/Tr%C3%A9maux_tree
|
|
86
|
+
*/
|
|
87
|
+
const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
|
|
88
|
+
if (itemAId === itemBId) {
|
|
89
|
+
return [itemAId, itemBId];
|
|
90
|
+
}
|
|
91
|
+
const itemMetaA = instance.getItemMeta(itemAId);
|
|
92
|
+
const itemMetaB = instance.getItemMeta(itemBId);
|
|
93
|
+
if (itemMetaA.parentId === itemMetaB.id || itemMetaB.parentId === itemMetaA.id) {
|
|
94
|
+
return itemMetaB.parentId === itemMetaA.id ? [itemMetaA.id, itemMetaB.id] : [itemMetaB.id, itemMetaA.id];
|
|
95
|
+
}
|
|
96
|
+
const aFamily = [itemMetaA.id];
|
|
97
|
+
const bFamily = [itemMetaB.id];
|
|
98
|
+
let aAncestor = itemMetaA.parentId;
|
|
99
|
+
let bAncestor = itemMetaB.parentId;
|
|
100
|
+
let aAncestorIsCommon = bFamily.indexOf(aAncestor) !== -1;
|
|
101
|
+
let bAncestorIsCommon = aFamily.indexOf(bAncestor) !== -1;
|
|
102
|
+
let continueA = true;
|
|
103
|
+
let continueB = true;
|
|
104
|
+
while (!bAncestorIsCommon && !aAncestorIsCommon) {
|
|
105
|
+
if (continueA) {
|
|
106
|
+
aFamily.push(aAncestor);
|
|
107
|
+
aAncestorIsCommon = bFamily.indexOf(aAncestor) !== -1;
|
|
108
|
+
continueA = aAncestor !== null;
|
|
109
|
+
if (!aAncestorIsCommon && continueA) {
|
|
110
|
+
aAncestor = instance.getItemMeta(aAncestor).parentId;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (continueB && !aAncestorIsCommon) {
|
|
114
|
+
bFamily.push(bAncestor);
|
|
115
|
+
bAncestorIsCommon = aFamily.indexOf(bAncestor) !== -1;
|
|
116
|
+
continueB = bAncestor !== null;
|
|
117
|
+
if (!bAncestorIsCommon && continueB) {
|
|
118
|
+
bAncestor = instance.getItemMeta(bAncestor).parentId;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const commonAncestor = aAncestorIsCommon ? aAncestor : bAncestor;
|
|
123
|
+
const ancestorFamily = instance.getItemOrderedChildrenIds(commonAncestor);
|
|
124
|
+
const aSide = aFamily[aFamily.indexOf(commonAncestor) - 1];
|
|
125
|
+
const bSide = bFamily[bFamily.indexOf(commonAncestor) - 1];
|
|
126
|
+
return ancestorFamily.indexOf(aSide) < ancestorFamily.indexOf(bSide) ? [itemAId, itemBId] : [itemBId, itemAId];
|
|
127
|
+
};
|
|
128
|
+
export const getNavigableItemsInRange = (instance, itemAId, itemBId) => {
|
|
129
|
+
const [first, last] = findOrderInTremauxTree(instance, itemAId, itemBId);
|
|
130
|
+
const items = [first];
|
|
131
|
+
let current = first;
|
|
132
|
+
while (current !== last) {
|
|
133
|
+
current = getNextNavigableItem(instance, current);
|
|
134
|
+
items.push(current);
|
|
135
|
+
}
|
|
136
|
+
return items;
|
|
137
|
+
};
|
|
@@ -29,7 +29,8 @@ export const RichTreeViewRoot = styled('ul', {
|
|
|
29
29
|
padding: 0,
|
|
30
30
|
margin: 0,
|
|
31
31
|
listStyle: 'none',
|
|
32
|
-
outline: 0
|
|
32
|
+
outline: 0,
|
|
33
|
+
position: 'relative'
|
|
33
34
|
});
|
|
34
35
|
function WrappedTreeItem({
|
|
35
36
|
slots,
|
|
@@ -138,7 +139,8 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
138
139
|
apiRef: PropTypes.shape({
|
|
139
140
|
current: PropTypes.shape({
|
|
140
141
|
focusItem: PropTypes.func.isRequired,
|
|
141
|
-
getItem: PropTypes.func.isRequired
|
|
142
|
+
getItem: PropTypes.func.isRequired,
|
|
143
|
+
setItemExpansion: PropTypes.func.isRequired
|
|
142
144
|
})
|
|
143
145
|
}),
|
|
144
146
|
/**
|
|
@@ -174,12 +176,12 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
174
176
|
*/
|
|
175
177
|
expandedItems: PropTypes.arrayOf(PropTypes.string),
|
|
176
178
|
/**
|
|
177
|
-
* Used to determine the
|
|
179
|
+
* Used to determine the id of a given item.
|
|
178
180
|
*
|
|
179
181
|
* @template R
|
|
180
182
|
* @param {R} item The item to check.
|
|
181
183
|
* @returns {string} The id of the item.
|
|
182
|
-
* @default
|
|
184
|
+
* @default (item) => item.id
|
|
183
185
|
*/
|
|
184
186
|
getItemId: PropTypes.func,
|
|
185
187
|
/**
|
|
@@ -188,7 +190,7 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
188
190
|
* @template R
|
|
189
191
|
* @param {R} item The item to check.
|
|
190
192
|
* @returns {string} The label of the item.
|
|
191
|
-
* @default
|
|
193
|
+
* @default (item) => item.label
|
|
192
194
|
*/
|
|
193
195
|
getItemLabel: PropTypes.func,
|
|
194
196
|
/**
|
|
@@ -28,7 +28,8 @@ export const SimpleTreeViewRoot = styled('ul', {
|
|
|
28
28
|
padding: 0,
|
|
29
29
|
margin: 0,
|
|
30
30
|
listStyle: 'none',
|
|
31
|
-
outline: 0
|
|
31
|
+
outline: 0,
|
|
32
|
+
position: 'relative'
|
|
32
33
|
});
|
|
33
34
|
const EMPTY_ITEMS = [];
|
|
34
35
|
const itemsPropWarning = buildWarning(['MUI X: The `SimpleTreeView` component does not support the `items` prop.', 'If you want to add items, you need to pass them as JSX children.', 'Check the documentation for more details: https://mui.com/x/react-tree-view/simple-tree-view/items/']);
|
|
@@ -96,7 +97,8 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
|
|
|
96
97
|
apiRef: PropTypes.shape({
|
|
97
98
|
current: PropTypes.shape({
|
|
98
99
|
focusItem: PropTypes.func.isRequired,
|
|
99
|
-
getItem: PropTypes.func.isRequired
|
|
100
|
+
getItem: PropTypes.func.isRequired,
|
|
101
|
+
setItemExpansion: PropTypes.func.isRequired
|
|
100
102
|
})
|
|
101
103
|
}),
|
|
102
104
|
/**
|
|
@@ -270,7 +270,7 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
270
270
|
onKeyDown?.(event);
|
|
271
271
|
instance.handleItemKeyDown(event, itemId);
|
|
272
272
|
};
|
|
273
|
-
const idAttribute = instance.
|
|
273
|
+
const idAttribute = instance.getTreeItemIdAttribute(itemId, id);
|
|
274
274
|
const tabIndex = instance.canItemBeTabbed(itemId) ? 0 : -1;
|
|
275
275
|
return /*#__PURE__*/_jsx(TreeItem2Provider, {
|
|
276
276
|
itemId: itemId,
|
|
@@ -70,7 +70,8 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
|
|
|
70
70
|
apiRef: PropTypes.shape({
|
|
71
71
|
current: PropTypes.shape({
|
|
72
72
|
focusItem: PropTypes.func.isRequired,
|
|
73
|
-
getItem: PropTypes.func.isRequired
|
|
73
|
+
getItem: PropTypes.func.isRequired,
|
|
74
|
+
setItemExpansion: PropTypes.func.isRequired
|
|
74
75
|
})
|
|
75
76
|
}),
|
|
76
77
|
/**
|
package/modern/index.js
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useTreeViewContext } from './useTreeViewContext';
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
export const TreeViewChildrenItemContext = /*#__PURE__*/React.createContext(null);
|
|
6
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7
|
+
TreeViewChildrenItemContext.displayName = 'TreeViewChildrenItemContext';
|
|
8
|
+
}
|
|
9
|
+
export function TreeViewChildrenItemProvider(props) {
|
|
10
|
+
const {
|
|
11
|
+
children,
|
|
12
|
+
itemId = null
|
|
13
|
+
} = props;
|
|
14
|
+
const {
|
|
15
|
+
instance,
|
|
16
|
+
rootRef
|
|
17
|
+
} = useTreeViewContext();
|
|
18
|
+
const childrenIdAttrToIdRef = React.useRef(new Map());
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
if (!rootRef.current) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let idAttr = null;
|
|
24
|
+
if (itemId == null) {
|
|
25
|
+
idAttr = rootRef.current.id;
|
|
26
|
+
} else {
|
|
27
|
+
// Undefined during 1st render
|
|
28
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
29
|
+
if (itemMeta !== undefined) {
|
|
30
|
+
idAttr = instance.getTreeItemIdAttribute(itemId, itemMeta.idAttribute);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (idAttr == null) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const previousChildrenIds = instance.getItemOrderedChildrenIds(itemId ?? null) ?? [];
|
|
37
|
+
const childrenElements = rootRef.current.querySelectorAll(`${itemId == null ? '' : `*[id="${idAttr}"] `}[role="treeitem"]:not(*[id="${idAttr}"] [role="treeitem"] [role="treeitem"])`);
|
|
38
|
+
const childrenIds = Array.from(childrenElements).map(child => childrenIdAttrToIdRef.current.get(child.id));
|
|
39
|
+
const hasChanged = childrenIds.length !== previousChildrenIds.length || childrenIds.some((childId, index) => childId !== previousChildrenIds[index]);
|
|
40
|
+
if (hasChanged) {
|
|
41
|
+
instance.setJSXItemsOrderedChildrenIds(itemId ?? null, childrenIds);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const value = React.useMemo(() => ({
|
|
45
|
+
registerChild: (childIdAttribute, childItemId) => childrenIdAttrToIdRef.current.set(childIdAttribute, childItemId),
|
|
46
|
+
unregisterChild: childIdAttribute => childrenIdAttrToIdRef.current.delete(childIdAttribute),
|
|
47
|
+
parentId: itemId
|
|
48
|
+
}), [itemId]);
|
|
49
|
+
return /*#__PURE__*/_jsx(TreeViewChildrenItemContext.Provider, {
|
|
50
|
+
value: value,
|
|
51
|
+
children: children
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
process.env.NODE_ENV !== "production" ? TreeViewChildrenItemProvider.propTypes = {
|
|
55
|
+
children: PropTypes.node,
|
|
56
|
+
id: PropTypes.string
|
|
57
|
+
} : void 0;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { TreeViewContext } from './TreeViewContext';
|
|
3
|
-
import { DescendantProvider } from './DescendantProvider';
|
|
4
3
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
4
|
/**
|
|
6
5
|
* Sets up the contexts for the underlying TreeItem components.
|
|
@@ -14,8 +13,8 @@ export function TreeViewProvider(props) {
|
|
|
14
13
|
} = props;
|
|
15
14
|
return /*#__PURE__*/_jsx(TreeViewContext.Provider, {
|
|
16
15
|
value: value,
|
|
17
|
-
children:
|
|
18
|
-
children
|
|
16
|
+
children: value.wrapRoot({
|
|
17
|
+
children
|
|
19
18
|
})
|
|
20
19
|
});
|
|
21
20
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { EventManager } from '../../utils/EventManager';
|
|
3
|
-
import { populateInstance } from '../../useTreeView/useTreeView.utils';
|
|
4
3
|
const isSyntheticEvent = event => {
|
|
5
4
|
return event.isPropagationStopped !== undefined;
|
|
6
5
|
};
|
|
7
|
-
export const useTreeViewInstanceEvents = ({
|
|
8
|
-
instance
|
|
9
|
-
}) => {
|
|
6
|
+
export const useTreeViewInstanceEvents = () => {
|
|
10
7
|
const [eventManager] = React.useState(() => new EventManager());
|
|
11
8
|
const publishEvent = React.useCallback((...args) => {
|
|
12
9
|
const [name, params, event = {}] = args;
|
|
@@ -22,9 +19,11 @@ export const useTreeViewInstanceEvents = ({
|
|
|
22
19
|
eventManager.removeListener(event, handler);
|
|
23
20
|
};
|
|
24
21
|
}, [eventManager]);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
return {
|
|
23
|
+
instance: {
|
|
24
|
+
$$publishEvent: publishEvent,
|
|
25
|
+
$$subscribeEvent: subscribeEvent
|
|
26
|
+
}
|
|
27
|
+
};
|
|
29
28
|
};
|
|
30
29
|
useTreeViewInstanceEvents.params = {};
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
export { useTreeView } from './useTreeView';
|
|
2
2
|
export { TreeViewProvider } from './TreeViewProvider';
|
|
3
|
+
export { unstable_resetCleanupTracking } from './hooks/useInstanceEventHandler';
|
|
4
|
+
// Plugins
|
|
3
5
|
export { DEFAULT_TREE_VIEW_PLUGINS } from './plugins/defaultPlugins';
|
|
6
|
+
export { useTreeViewExpansion } from './plugins/useTreeViewExpansion';
|
|
7
|
+
export { useTreeViewSelection } from './plugins/useTreeViewSelection';
|
|
8
|
+
export { useTreeViewFocus } from './plugins/useTreeViewFocus';
|
|
9
|
+
export { useTreeViewKeyboardNavigation } from './plugins/useTreeViewKeyboardNavigation';
|
|
10
|
+
export { useTreeViewId } from './plugins/useTreeViewId';
|
|
11
|
+
export { useTreeViewIcons } from './plugins/useTreeViewIcons';
|
|
12
|
+
export { useTreeViewItems } from './plugins/useTreeViewItems';
|
|
13
|
+
export { useTreeViewJSXItems } from './plugins/useTreeViewJSXItems';
|
|
14
|
+
export { buildWarning } from './utils/warning';
|
|
4
15
|
export { extractPluginParamsFromProps } from './utils/extractPluginParamsFromProps';
|
|
@@ -1,39 +1,47 @@
|
|
|
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';
|
|
5
4
|
export const useTreeViewExpansion = ({
|
|
6
5
|
instance,
|
|
7
6
|
params,
|
|
8
7
|
models
|
|
9
8
|
}) => {
|
|
9
|
+
const expandedItemsMap = React.useMemo(() => {
|
|
10
|
+
const temp = new Map();
|
|
11
|
+
models.expandedItems.value.forEach(id => {
|
|
12
|
+
temp.set(id, true);
|
|
13
|
+
});
|
|
14
|
+
return temp;
|
|
15
|
+
}, [models.expandedItems.value]);
|
|
10
16
|
const setExpandedItems = (event, value) => {
|
|
11
17
|
params.onExpandedItemsChange?.(event, value);
|
|
12
18
|
models.expandedItems.setControlledValue(value);
|
|
13
19
|
};
|
|
14
|
-
const isItemExpanded = React.useCallback(itemId =>
|
|
15
|
-
|
|
16
|
-
}, [models.expandedItems.value]);
|
|
17
|
-
const isItemExpandable = React.useCallback(itemId => !!instance.getNode(itemId)?.expandable, [instance]);
|
|
20
|
+
const isItemExpanded = React.useCallback(itemId => expandedItemsMap.has(itemId), [expandedItemsMap]);
|
|
21
|
+
const isItemExpandable = React.useCallback(itemId => !!instance.getItemMeta(itemId)?.expandable, [instance]);
|
|
18
22
|
const toggleItemExpansion = useEventCallback((event, itemId) => {
|
|
19
|
-
|
|
23
|
+
const isExpandedBefore = instance.isItemExpanded(itemId);
|
|
24
|
+
instance.setItemExpansion(event, itemId, !isExpandedBefore);
|
|
25
|
+
});
|
|
26
|
+
const setItemExpansion = useEventCallback((event, itemId, isExpanded) => {
|
|
27
|
+
const isExpandedBefore = instance.isItemExpanded(itemId);
|
|
28
|
+
if (isExpandedBefore === isExpanded) {
|
|
20
29
|
return;
|
|
21
30
|
}
|
|
22
|
-
const isExpandedBefore = models.expandedItems.value.indexOf(itemId) !== -1;
|
|
23
31
|
let newExpanded;
|
|
24
|
-
if (
|
|
25
|
-
newExpanded = models.expandedItems.value.filter(id => id !== itemId);
|
|
26
|
-
} else {
|
|
32
|
+
if (isExpanded) {
|
|
27
33
|
newExpanded = [itemId].concat(models.expandedItems.value);
|
|
34
|
+
} else {
|
|
35
|
+
newExpanded = models.expandedItems.value.filter(id => id !== itemId);
|
|
28
36
|
}
|
|
29
37
|
if (params.onItemExpansionToggle) {
|
|
30
|
-
params.onItemExpansionToggle(event, itemId,
|
|
38
|
+
params.onItemExpansionToggle(event, itemId, isExpanded);
|
|
31
39
|
}
|
|
32
40
|
setExpandedItems(event, newExpanded);
|
|
33
41
|
});
|
|
34
42
|
const expandAllSiblings = (event, itemId) => {
|
|
35
|
-
const
|
|
36
|
-
const siblings = instance.
|
|
43
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
44
|
+
const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
|
|
37
45
|
const diff = siblings.filter(child => instance.isItemExpandable(child) && !instance.isItemExpanded(child));
|
|
38
46
|
const newExpanded = models.expandedItems.value.concat(diff);
|
|
39
47
|
if (diff.length > 0) {
|
|
@@ -45,12 +53,18 @@ export const useTreeViewExpansion = ({
|
|
|
45
53
|
setExpandedItems(event, newExpanded);
|
|
46
54
|
}
|
|
47
55
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
return {
|
|
57
|
+
publicAPI: {
|
|
58
|
+
setItemExpansion
|
|
59
|
+
},
|
|
60
|
+
instance: {
|
|
61
|
+
isItemExpanded,
|
|
62
|
+
isItemExpandable,
|
|
63
|
+
setItemExpansion,
|
|
64
|
+
toggleItemExpansion,
|
|
65
|
+
expandAllSiblings
|
|
66
|
+
}
|
|
67
|
+
};
|
|
54
68
|
};
|
|
55
69
|
useTreeViewExpansion.models = {
|
|
56
70
|
expandedItems: {
|
|
@@ -2,13 +2,13 @@ import _extends from "@babel/runtime/helpers/esm/extends";
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import useEventCallback from '@mui/utils/useEventCallback';
|
|
4
4
|
import ownerDocument from '@mui/utils/ownerDocument';
|
|
5
|
-
import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
|
|
6
5
|
import { useInstanceEventHandler } from '../../hooks/useInstanceEventHandler';
|
|
7
6
|
import { getActiveElement } from '../../utils/utils';
|
|
7
|
+
import { getFirstNavigableItem } from '../../utils/tree';
|
|
8
8
|
const useTabbableItemId = (instance, selectedItems) => {
|
|
9
9
|
const isItemVisible = itemId => {
|
|
10
|
-
const
|
|
11
|
-
return
|
|
10
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
11
|
+
return itemMeta && (itemMeta.parentId == null || instance.isItemExpanded(itemMeta.parentId));
|
|
12
12
|
};
|
|
13
13
|
let tabbableItemId;
|
|
14
14
|
if (Array.isArray(selectedItems)) {
|
|
@@ -17,13 +17,12 @@ const useTabbableItemId = (instance, selectedItems) => {
|
|
|
17
17
|
tabbableItemId = selectedItems;
|
|
18
18
|
}
|
|
19
19
|
if (tabbableItemId == null) {
|
|
20
|
-
tabbableItemId = instance
|
|
20
|
+
tabbableItemId = getFirstNavigableItem(instance);
|
|
21
21
|
}
|
|
22
22
|
return tabbableItemId;
|
|
23
23
|
};
|
|
24
24
|
export const useTreeViewFocus = ({
|
|
25
25
|
instance,
|
|
26
|
-
publicAPI,
|
|
27
26
|
params,
|
|
28
27
|
state,
|
|
29
28
|
setState,
|
|
@@ -42,12 +41,12 @@ export const useTreeViewFocus = ({
|
|
|
42
41
|
const isTreeViewFocused = React.useCallback(() => !!rootRef.current && rootRef.current.contains(getActiveElement(ownerDocument(rootRef.current))), [rootRef]);
|
|
43
42
|
const isItemFocused = React.useCallback(itemId => state.focusedItemId === itemId && isTreeViewFocused(), [state.focusedItemId, isTreeViewFocused]);
|
|
44
43
|
const isItemVisible = itemId => {
|
|
45
|
-
const
|
|
46
|
-
return
|
|
44
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
45
|
+
return itemMeta && (itemMeta.parentId == null || instance.isItemExpanded(itemMeta.parentId));
|
|
47
46
|
};
|
|
48
47
|
const innerFocusItem = (event, itemId) => {
|
|
49
|
-
const
|
|
50
|
-
const itemElement = document.getElementById(instance.
|
|
48
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
49
|
+
const itemElement = document.getElementById(instance.getTreeItemIdAttribute(itemId, itemMeta.idAttribute));
|
|
51
50
|
if (itemElement) {
|
|
52
51
|
itemElement.focus();
|
|
53
52
|
}
|
|
@@ -70,7 +69,7 @@ export const useTreeViewFocus = ({
|
|
|
70
69
|
itemToFocusId = models.selectedItems.value;
|
|
71
70
|
}
|
|
72
71
|
if (itemToFocusId == null) {
|
|
73
|
-
itemToFocusId = instance
|
|
72
|
+
itemToFocusId = getFirstNavigableItem(instance);
|
|
74
73
|
}
|
|
75
74
|
innerFocusItem(event, itemToFocusId);
|
|
76
75
|
});
|
|
@@ -78,9 +77,9 @@ export const useTreeViewFocus = ({
|
|
|
78
77
|
if (state.focusedItemId == null) {
|
|
79
78
|
return;
|
|
80
79
|
}
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
const itemElement = document.getElementById(instance.
|
|
80
|
+
const itemMeta = instance.getItemMeta(state.focusedItemId);
|
|
81
|
+
if (itemMeta) {
|
|
82
|
+
const itemElement = document.getElementById(instance.getTreeItemIdAttribute(state.focusedItemId, itemMeta.idAttribute));
|
|
84
83
|
if (itemElement) {
|
|
85
84
|
itemElement.blur();
|
|
86
85
|
}
|
|
@@ -88,16 +87,6 @@ export const useTreeViewFocus = ({
|
|
|
88
87
|
setFocusedItemId(null);
|
|
89
88
|
});
|
|
90
89
|
const canItemBeTabbed = itemId => itemId === tabbableItemId;
|
|
91
|
-
populateInstance(instance, {
|
|
92
|
-
isItemFocused,
|
|
93
|
-
canItemBeTabbed,
|
|
94
|
-
focusItem,
|
|
95
|
-
focusDefaultItem,
|
|
96
|
-
removeFocusedItem
|
|
97
|
-
});
|
|
98
|
-
populatePublicAPI(publicAPI, {
|
|
99
|
-
focusItem
|
|
100
|
-
});
|
|
101
90
|
useInstanceEventHandler(instance, 'removeItem', ({
|
|
102
91
|
id
|
|
103
92
|
}) => {
|
|
@@ -112,13 +101,23 @@ export const useTreeViewFocus = ({
|
|
|
112
101
|
instance.focusDefaultItem(event);
|
|
113
102
|
}
|
|
114
103
|
};
|
|
115
|
-
const focusedItem = instance.
|
|
116
|
-
const activeDescendant = focusedItem ? instance.
|
|
104
|
+
const focusedItem = instance.getItemMeta(state.focusedItemId);
|
|
105
|
+
const activeDescendant = focusedItem ? instance.getTreeItemIdAttribute(focusedItem.id, focusedItem.idAttribute) : null;
|
|
117
106
|
return {
|
|
118
107
|
getRootProps: otherHandlers => ({
|
|
119
108
|
onFocus: createHandleFocus(otherHandlers),
|
|
120
109
|
'aria-activedescendant': activeDescendant ?? undefined
|
|
121
|
-
})
|
|
110
|
+
}),
|
|
111
|
+
publicAPI: {
|
|
112
|
+
focusItem
|
|
113
|
+
},
|
|
114
|
+
instance: {
|
|
115
|
+
isItemFocused,
|
|
116
|
+
canItemBeTabbed,
|
|
117
|
+
focusItem,
|
|
118
|
+
focusDefaultItem,
|
|
119
|
+
removeFocusedItem
|
|
120
|
+
}
|
|
122
121
|
};
|
|
123
122
|
};
|
|
124
123
|
useTreeViewFocus.getInitialState = () => ({
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import useId from '@mui/utils/useId';
|
|
3
|
-
import { populateInstance } from '../../useTreeView/useTreeView.utils';
|
|
4
3
|
export const useTreeViewId = ({
|
|
5
|
-
instance,
|
|
6
4
|
params
|
|
7
5
|
}) => {
|
|
8
6
|
const treeId = useId(params.id);
|
|
9
|
-
const
|
|
10
|
-
populateInstance(instance, {
|
|
11
|
-
getTreeItemId
|
|
12
|
-
});
|
|
7
|
+
const getTreeItemIdAttribute = React.useCallback((itemId, idAttribute) => idAttribute ?? `${treeId}-${itemId}`, [treeId]);
|
|
13
8
|
return {
|
|
14
9
|
getRootProps: () => ({
|
|
15
10
|
id: treeId
|
|
16
|
-
})
|
|
11
|
+
}),
|
|
12
|
+
instance: {
|
|
13
|
+
getTreeItemIdAttribute
|
|
14
|
+
}
|
|
17
15
|
};
|
|
18
16
|
};
|
|
19
17
|
useTreeViewId.params = {
|