@mui/x-tree-view 7.1.1 → 7.3.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 +211 -0
- package/RichTreeView/RichTreeView.types.d.ts +3 -3
- package/TreeItem/TreeItem.js +1 -1
- package/TreeItem2/TreeItem2.d.ts +5 -1
- package/TreeItem2/TreeItem2.js +0 -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/models/plugin.d.ts +13 -5
- package/internals/models/treeView.d.ts +1 -2
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +15 -15
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +31 -28
- package/internals/plugins/useTreeViewId/useTreeViewId.js +5 -7
- package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +1 -1
- package/internals/plugins/useTreeViewItems/useTreeViewItems.js +60 -50
- package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +19 -15
- package/internals/plugins/useTreeViewItems/useTreeViewItems.utils.d.ts +4 -0
- package/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +8 -0
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +73 -48
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.d.ts +3 -2
- 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/utils/tree.d.ts +8 -0
- package/internals/utils/tree.js +137 -0
- package/modern/TreeItem/TreeItem.js +1 -1
- package/modern/TreeItem2/TreeItem2.js +0 -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/plugins/useTreeViewExpansion/useTreeViewExpansion.js +15 -15
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +31 -28
- package/modern/internals/plugins/useTreeViewId/useTreeViewId.js +5 -7
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +60 -50
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +8 -0
- package/modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +73 -48
- 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/utils/tree.js +137 -0
- package/modern/useTreeItem2/useTreeItem2.js +1 -1
- package/node/TreeItem/TreeItem.js +1 -1
- package/node/TreeItem2/TreeItem2.js +0 -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/plugins/useTreeViewExpansion/useTreeViewExpansion.js +15 -15
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +31 -28
- package/node/internals/plugins/useTreeViewId/useTreeViewId.js +5 -7
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +60 -50
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.utils.js +15 -0
- package/node/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +73 -48
- 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/utils/tree.js +148 -0
- package/node/useTreeItem2/useTreeItem2.js +1 -1
- package/package.json +1 -1
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useTheme } from '@mui/material/styles';
|
|
3
3
|
import useEventCallback from '@mui/utils/useEventCallback';
|
|
4
|
-
import {
|
|
4
|
+
import { getFirstNavigableItem, getLastNavigableItem, getNextNavigableItem, getPreviousNavigableItem } from '../../utils/tree';
|
|
5
5
|
function isPrintableCharacter(string) {
|
|
6
6
|
return !!string && string.length === 1 && !!string.match(/\S/);
|
|
7
7
|
}
|
|
@@ -29,12 +29,12 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
const newFirstCharMap = {};
|
|
32
|
-
const processItem =
|
|
33
|
-
newFirstCharMap[
|
|
32
|
+
const processItem = item => {
|
|
33
|
+
newFirstCharMap[item.id] = item.label.substring(0, 1).toLowerCase();
|
|
34
34
|
};
|
|
35
|
-
Object.values(state.items.
|
|
35
|
+
Object.values(state.items.itemMetaMap).forEach(processItem);
|
|
36
36
|
firstCharMap.current = newFirstCharMap;
|
|
37
|
-
}, [state.items.
|
|
37
|
+
}, [state.items.itemMetaMap, params.getItemId, instance]);
|
|
38
38
|
const getFirstMatchingItem = (itemId, firstChar) => {
|
|
39
39
|
let start;
|
|
40
40
|
let index;
|
|
@@ -43,7 +43,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
43
43
|
const firstChars = [];
|
|
44
44
|
// This really only works since the ids are strings
|
|
45
45
|
Object.keys(firstCharMap.current).forEach(mapItemId => {
|
|
46
|
-
const map = instance.
|
|
46
|
+
const map = instance.getItemMeta(mapItemId);
|
|
47
47
|
const visible = map.parentId ? instance.isItemExpanded(map.parentId) : true;
|
|
48
48
|
const shouldBeSkipped = params.disabledItemsFocusable ? false : instance.isItemDisabled(mapItemId);
|
|
49
49
|
if (visible && !shouldBeSkipped) {
|
|
@@ -128,7 +128,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
128
128
|
// Focus the next focusable item
|
|
129
129
|
case key === 'ArrowDown':
|
|
130
130
|
{
|
|
131
|
-
const nextItem =
|
|
131
|
+
const nextItem = getNextNavigableItem(instance, itemId);
|
|
132
132
|
if (nextItem) {
|
|
133
133
|
event.preventDefault();
|
|
134
134
|
instance.focusItem(event, nextItem);
|
|
@@ -148,7 +148,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
148
148
|
// Focuses the previous focusable item
|
|
149
149
|
case key === 'ArrowUp':
|
|
150
150
|
{
|
|
151
|
-
const previousItem =
|
|
151
|
+
const previousItem = getPreviousNavigableItem(instance, itemId);
|
|
152
152
|
if (previousItem) {
|
|
153
153
|
event.preventDefault();
|
|
154
154
|
instance.focusItem(event, previousItem);
|
|
@@ -170,7 +170,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
170
170
|
case key === 'ArrowRight' && !isRTL || key === 'ArrowLeft' && isRTL:
|
|
171
171
|
{
|
|
172
172
|
if (instance.isItemExpanded(itemId)) {
|
|
173
|
-
const nextItemId =
|
|
173
|
+
const nextItemId = getNextNavigableItem(instance, itemId);
|
|
174
174
|
if (nextItemId) {
|
|
175
175
|
instance.focusItem(event, nextItemId);
|
|
176
176
|
event.preventDefault();
|
|
@@ -190,7 +190,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
190
190
|
instance.toggleItemExpansion(event, itemId);
|
|
191
191
|
event.preventDefault();
|
|
192
192
|
} else {
|
|
193
|
-
const parent = instance.
|
|
193
|
+
const parent = instance.getItemMeta(itemId).parentId;
|
|
194
194
|
if (parent) {
|
|
195
195
|
instance.focusItem(event, parent);
|
|
196
196
|
event.preventDefault();
|
|
@@ -202,7 +202,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
202
202
|
// Focuses the first item in the tree
|
|
203
203
|
case key === 'Home':
|
|
204
204
|
{
|
|
205
|
-
instance.focusItem(event,
|
|
205
|
+
instance.focusItem(event, getFirstNavigableItem(instance));
|
|
206
206
|
|
|
207
207
|
// Multi select behavior when pressing Ctrl + Shift + Home
|
|
208
208
|
// Selects the focused item and all items up to the first item.
|
|
@@ -216,7 +216,7 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
216
216
|
// Focuses the last item in the tree
|
|
217
217
|
case key === 'End':
|
|
218
218
|
{
|
|
219
|
-
instance.focusItem(event,
|
|
219
|
+
instance.focusItem(event, getLastNavigableItem(instance));
|
|
220
220
|
|
|
221
221
|
// Multi select behavior when pressing Ctrl + Shirt + End
|
|
222
222
|
// Selects the focused item and all the items down to the last item.
|
|
@@ -240,8 +240,8 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
240
240
|
case key === 'a' && ctrlPressed && params.multiSelect && !params.disableSelection:
|
|
241
241
|
{
|
|
242
242
|
instance.selectRange(event, {
|
|
243
|
-
start:
|
|
244
|
-
end:
|
|
243
|
+
start: getFirstNavigableItem(instance),
|
|
244
|
+
end: getLastNavigableItem(instance)
|
|
245
245
|
});
|
|
246
246
|
event.preventDefault();
|
|
247
247
|
break;
|
|
@@ -260,9 +260,11 @@ export const useTreeViewKeyboardNavigation = ({
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
};
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
return {
|
|
264
|
+
instance: {
|
|
265
|
+
updateFirstCharMap,
|
|
266
|
+
handleItemKeyDown
|
|
267
|
+
}
|
|
268
|
+
};
|
|
267
269
|
};
|
|
268
270
|
useTreeViewKeyboardNavigation.params = {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import { findOrderInTremauxTree } from './useTreeViewSelection.utils';
|
|
3
|
+
import { getFirstNavigableItem, getLastNavigableItem, getNavigableItemsInRange } from '../../utils/tree';
|
|
5
4
|
export const useTreeViewSelection = ({
|
|
6
5
|
instance,
|
|
7
6
|
params,
|
|
@@ -58,16 +57,6 @@ export const useTreeViewSelection = ({
|
|
|
58
57
|
lastSelectionWasRange.current = false;
|
|
59
58
|
currentRangeSelection.current = [];
|
|
60
59
|
};
|
|
61
|
-
const getItemsInRange = (itemAId, itemBId) => {
|
|
62
|
-
const [first, last] = findOrderInTremauxTree(instance, itemAId, itemBId);
|
|
63
|
-
const items = [first];
|
|
64
|
-
let current = first;
|
|
65
|
-
while (current !== last) {
|
|
66
|
-
current = getNextItem(instance, current);
|
|
67
|
-
items.push(current);
|
|
68
|
-
}
|
|
69
|
-
return items;
|
|
70
|
-
};
|
|
71
60
|
const handleRangeArrowSelect = (event, items) => {
|
|
72
61
|
let base = models.selectedItems.value.slice();
|
|
73
62
|
const {
|
|
@@ -105,7 +94,7 @@ export const useTreeViewSelection = ({
|
|
|
105
94
|
if (lastSelectionWasRange.current) {
|
|
106
95
|
base = base.filter(id => currentRangeSelection.current.indexOf(id) === -1);
|
|
107
96
|
}
|
|
108
|
-
let range =
|
|
97
|
+
let range = getNavigableItemsInRange(instance, start, end);
|
|
109
98
|
range = range.filter(item => !instance.isItemDisabled(item));
|
|
110
99
|
currentRangeSelection.current = range;
|
|
111
100
|
let newSelected = base.concat(range);
|
|
@@ -142,7 +131,7 @@ export const useTreeViewSelection = ({
|
|
|
142
131
|
const start = lastSelectionWasRange.current ? lastSelectedItem.current : itemId;
|
|
143
132
|
instance.selectRange(event, {
|
|
144
133
|
start,
|
|
145
|
-
end:
|
|
134
|
+
end: getFirstNavigableItem(instance)
|
|
146
135
|
});
|
|
147
136
|
};
|
|
148
137
|
const rangeSelectToLast = (event, itemId) => {
|
|
@@ -152,20 +141,20 @@ export const useTreeViewSelection = ({
|
|
|
152
141
|
const start = lastSelectionWasRange.current ? lastSelectedItem.current : itemId;
|
|
153
142
|
instance.selectRange(event, {
|
|
154
143
|
start,
|
|
155
|
-
end:
|
|
144
|
+
end: getLastNavigableItem(instance)
|
|
156
145
|
});
|
|
157
146
|
};
|
|
158
|
-
populateInstance(instance, {
|
|
159
|
-
isItemSelected,
|
|
160
|
-
selectItem,
|
|
161
|
-
selectRange,
|
|
162
|
-
rangeSelectToLast,
|
|
163
|
-
rangeSelectToFirst
|
|
164
|
-
});
|
|
165
147
|
return {
|
|
166
148
|
getRootProps: () => ({
|
|
167
149
|
'aria-multiselectable': params.multiSelect
|
|
168
150
|
}),
|
|
151
|
+
instance: {
|
|
152
|
+
isItemSelected,
|
|
153
|
+
selectItem,
|
|
154
|
+
selectRange,
|
|
155
|
+
rangeSelectToLast,
|
|
156
|
+
rangeSelectToFirst
|
|
157
|
+
},
|
|
169
158
|
contextValue: {
|
|
170
159
|
selection: {
|
|
171
160
|
multiSelect: params.multiSelect
|
|
@@ -39,12 +39,12 @@ export const useTreeView = inParams => {
|
|
|
39
39
|
const rootPropsGetters = [];
|
|
40
40
|
const contextValue = {
|
|
41
41
|
publicAPI,
|
|
42
|
-
instance: instance
|
|
42
|
+
instance: instance,
|
|
43
|
+
rootRef: innerRootRef
|
|
43
44
|
};
|
|
44
45
|
const runPlugin = plugin => {
|
|
45
46
|
const pluginResponse = plugin({
|
|
46
47
|
instance,
|
|
47
|
-
publicAPI,
|
|
48
48
|
params,
|
|
49
49
|
slots: params.slots,
|
|
50
50
|
slotProps: params.slotProps,
|
|
@@ -52,10 +52,16 @@ export const useTreeView = inParams => {
|
|
|
52
52
|
setState,
|
|
53
53
|
rootRef: innerRootRef,
|
|
54
54
|
models
|
|
55
|
-
})
|
|
55
|
+
});
|
|
56
56
|
if (pluginResponse.getRootProps) {
|
|
57
57
|
rootPropsGetters.push(pluginResponse.getRootProps);
|
|
58
58
|
}
|
|
59
|
+
if (pluginResponse.publicAPI) {
|
|
60
|
+
Object.assign(publicAPI, pluginResponse.publicAPI);
|
|
61
|
+
}
|
|
62
|
+
if (pluginResponse.instance) {
|
|
63
|
+
Object.assign(instance, pluginResponse.instance);
|
|
64
|
+
}
|
|
59
65
|
if (pluginResponse.contextValue) {
|
|
60
66
|
Object.assign(contextValue, pluginResponse.contextValue);
|
|
61
67
|
}
|
|
@@ -99,6 +105,18 @@ export const useTreeView = inParams => {
|
|
|
99
105
|
});
|
|
100
106
|
return finalChildren;
|
|
101
107
|
};
|
|
108
|
+
const rootWrappers = plugins.map(plugin => plugin.wrapRoot).filter(wrapRoot => !!wrapRoot);
|
|
109
|
+
contextValue.wrapRoot = ({
|
|
110
|
+
children
|
|
111
|
+
}) => {
|
|
112
|
+
let finalChildren = children;
|
|
113
|
+
rootWrappers.forEach(rootWrapper => {
|
|
114
|
+
finalChildren = rootWrapper({
|
|
115
|
+
children: finalChildren
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
return finalChildren;
|
|
119
|
+
};
|
|
102
120
|
const getRootProps = (otherHandlers = {}) => {
|
|
103
121
|
const rootProps = _extends({
|
|
104
122
|
role: 'tree'
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TreeViewInstance } from '../models';
|
|
2
|
+
import type { UseTreeViewExpansionSignature } from '../plugins/useTreeViewExpansion';
|
|
3
|
+
import type { UseTreeViewItemsSignature } from '../plugins/useTreeViewItems';
|
|
4
|
+
export declare const getPreviousNavigableItem: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemId: string) => string | null;
|
|
5
|
+
export declare const getNextNavigableItem: (instance: TreeViewInstance<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>, itemId: string) => string | null;
|
|
6
|
+
export declare const getLastNavigableItem: (instance: TreeViewInstance<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>) => string;
|
|
7
|
+
export declare const getFirstNavigableItem: (instance: TreeViewInstance<[UseTreeViewItemsSignature]>) => string;
|
|
8
|
+
export declare const getNavigableItemsInRange: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemAId: string, itemBId: string) => string[];
|
|
@@ -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
|
+
};
|
|
@@ -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,
|
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,10 +1,8 @@
|
|
|
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, populatePublicAPI } from '../../useTreeView/useTreeView.utils';
|
|
5
4
|
export const useTreeViewExpansion = ({
|
|
6
5
|
instance,
|
|
7
|
-
publicAPI,
|
|
8
6
|
params,
|
|
9
7
|
models
|
|
10
8
|
}) => {
|
|
@@ -20,7 +18,7 @@ export const useTreeViewExpansion = ({
|
|
|
20
18
|
models.expandedItems.setControlledValue(value);
|
|
21
19
|
};
|
|
22
20
|
const isItemExpanded = React.useCallback(itemId => expandedItemsMap.has(itemId), [expandedItemsMap]);
|
|
23
|
-
const isItemExpandable = React.useCallback(itemId => !!instance.
|
|
21
|
+
const isItemExpandable = React.useCallback(itemId => !!instance.getItemMeta(itemId)?.expandable, [instance]);
|
|
24
22
|
const toggleItemExpansion = useEventCallback((event, itemId) => {
|
|
25
23
|
const isExpandedBefore = instance.isItemExpanded(itemId);
|
|
26
24
|
instance.setItemExpansion(event, itemId, !isExpandedBefore);
|
|
@@ -42,8 +40,8 @@ export const useTreeViewExpansion = ({
|
|
|
42
40
|
setExpandedItems(event, newExpanded);
|
|
43
41
|
});
|
|
44
42
|
const expandAllSiblings = (event, itemId) => {
|
|
45
|
-
const
|
|
46
|
-
const siblings = instance.
|
|
43
|
+
const itemMeta = instance.getItemMeta(itemId);
|
|
44
|
+
const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
|
|
47
45
|
const diff = siblings.filter(child => instance.isItemExpandable(child) && !instance.isItemExpanded(child));
|
|
48
46
|
const newExpanded = models.expandedItems.value.concat(diff);
|
|
49
47
|
if (diff.length > 0) {
|
|
@@ -55,16 +53,18 @@ export const useTreeViewExpansion = ({
|
|
|
55
53
|
setExpandedItems(event, newExpanded);
|
|
56
54
|
}
|
|
57
55
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
return {
|
|
57
|
+
publicAPI: {
|
|
58
|
+
setItemExpansion
|
|
59
|
+
},
|
|
60
|
+
instance: {
|
|
61
|
+
isItemExpanded,
|
|
62
|
+
isItemExpandable,
|
|
63
|
+
setItemExpansion,
|
|
64
|
+
toggleItemExpansion,
|
|
65
|
+
expandAllSiblings
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
68
|
};
|
|
69
69
|
useTreeViewExpansion.models = {
|
|
70
70
|
expandedItems: {
|