@mui/x-tree-view 7.3.0 → 7.4.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 +220 -7
- package/TreeItem/TreeItem.js +1 -2
- package/TreeItem/TreeItemContent.js +1 -2
- package/TreeItem/useTreeItemState.js +1 -3
- package/TreeItem2/TreeItem2.js +2 -3
- package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +1 -3
- package/index.js +1 -1
- package/internals/TreeViewProvider/useTreeViewContext.d.ts +1 -1
- package/internals/hooks/useInstanceEventHandler.d.ts +2 -2
- package/internals/models/treeView.d.ts +0 -6
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -4
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +31 -63
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +82 -94
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +32 -5
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.d.ts +9 -0
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +21 -0
- package/internals/useTreeView/useTreeView.types.d.ts +1 -1
- package/internals/useTreeView/useTreeViewModels.d.ts +1 -1
- package/internals/utils/extractPluginParamsFromProps.d.ts +1 -1
- package/internals/utils/publishTreeViewEvent.d.ts +1 -1
- package/internals/utils/tree.d.ts +17 -1
- package/internals/utils/tree.js +34 -4
- package/modern/TreeItem/TreeItem.js +1 -2
- package/modern/TreeItem/TreeItemContent.js +1 -2
- package/modern/TreeItem/useTreeItemState.js +1 -3
- package/modern/TreeItem2/TreeItem2.js +2 -3
- package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +1 -3
- package/modern/index.js +1 -1
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +1 -4
- package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +31 -63
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +82 -94
- package/modern/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +21 -0
- package/modern/internals/utils/tree.js +34 -4
- package/modern/useTreeItem2/useTreeItem2.js +3 -3
- package/node/RichTreeView/RichTreeView.js +1 -1
- package/node/SimpleTreeView/SimpleTreeView.js +1 -1
- package/node/TreeItem/TreeItem.js +1 -1
- package/node/TreeItem/TreeItemContent.js +1 -1
- package/node/TreeItem/useTreeItemState.js +1 -3
- package/node/TreeItem2/TreeItem2.js +2 -2
- package/node/TreeItem2Icon/TreeItem2Icon.js +1 -1
- package/node/TreeView/TreeView.js +1 -1
- package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +1 -3
- package/node/hooks/useTreeViewApiRef.js +1 -1
- package/node/icons/icons.js +1 -1
- package/node/index.js +1 -1
- package/node/internals/TreeViewProvider/TreeViewChildrenItemProvider.js +1 -1
- package/node/internals/TreeViewProvider/TreeViewContext.js +1 -1
- package/node/internals/TreeViewProvider/TreeViewProvider.js +1 -1
- package/node/internals/TreeViewProvider/useTreeViewContext.js +1 -1
- package/node/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.js +1 -1
- package/node/internals/hooks/useInstanceEventHandler.js +1 -1
- package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +1 -1
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +2 -5
- package/node/internals/plugins/useTreeViewId/useTreeViewId.js +1 -1
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +1 -1
- package/node/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +1 -1
- package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +32 -64
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.js +82 -94
- package/node/internals/plugins/useTreeViewSelection/useTreeViewSelection.utils.js +29 -0
- package/node/internals/useTreeView/useTreeView.js +1 -1
- package/node/internals/useTreeView/useTreeViewModels.js +1 -1
- package/node/internals/utils/tree.js +37 -5
- package/node/useTreeItem2/useTreeItem2.js +3 -3
- package/package.json +4 -6
- package/useTreeItem2/useTreeItem2.js +3 -3
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { getFirstNavigableItem, getLastNavigableItem,
|
|
3
|
+
import { findOrderInTremauxTree, getAllNavigableItems, getFirstNavigableItem, getLastNavigableItem, getNonDisabledItemsInRange } from '../../utils/tree';
|
|
4
|
+
import { convertSelectedItemsToArray, getLookupFromArray } from './useTreeViewSelection.utils';
|
|
4
5
|
export const useTreeViewSelection = ({
|
|
5
6
|
instance,
|
|
6
7
|
params,
|
|
7
8
|
models
|
|
8
9
|
}) => {
|
|
9
10
|
const lastSelectedItem = React.useRef(null);
|
|
10
|
-
const
|
|
11
|
-
const
|
|
11
|
+
const lastSelectedRange = React.useRef({});
|
|
12
|
+
const selectedItemsMap = React.useMemo(() => {
|
|
13
|
+
const temp = new Map();
|
|
14
|
+
if (Array.isArray(models.selectedItems.value)) {
|
|
15
|
+
models.selectedItems.value.forEach(id => {
|
|
16
|
+
temp.set(id, true);
|
|
17
|
+
});
|
|
18
|
+
} else if (models.selectedItems.value != null) {
|
|
19
|
+
temp.set(models.selectedItems.value, true);
|
|
20
|
+
}
|
|
21
|
+
return temp;
|
|
22
|
+
}, [models.selectedItems.value]);
|
|
12
23
|
const setSelectedItems = (event, newSelectedItems) => {
|
|
13
24
|
if (params.onItemSelectionToggle) {
|
|
14
25
|
if (params.multiSelect) {
|
|
@@ -34,115 +45,90 @@ export const useTreeViewSelection = ({
|
|
|
34
45
|
}
|
|
35
46
|
models.selectedItems.setControlledValue(newSelectedItems);
|
|
36
47
|
};
|
|
37
|
-
const isItemSelected = itemId =>
|
|
48
|
+
const isItemSelected = itemId => selectedItemsMap.has(itemId);
|
|
38
49
|
const selectItem = (event, itemId, multiple = false) => {
|
|
39
50
|
if (params.disableSelection) {
|
|
40
51
|
return;
|
|
41
52
|
}
|
|
53
|
+
let newSelected;
|
|
42
54
|
if (multiple) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
newSelected = [itemId].concat(models.selectedItems.value);
|
|
49
|
-
}
|
|
50
|
-
setSelectedItems(event, newSelected);
|
|
55
|
+
const cleanSelectedItems = convertSelectedItemsToArray(models.selectedItems.value);
|
|
56
|
+
if (instance.isItemSelected(itemId)) {
|
|
57
|
+
newSelected = cleanSelectedItems.filter(id => id !== itemId);
|
|
58
|
+
} else {
|
|
59
|
+
newSelected = [itemId].concat(cleanSelectedItems);
|
|
51
60
|
}
|
|
52
61
|
} else {
|
|
53
|
-
|
|
54
|
-
setSelectedItems(event, newSelected);
|
|
62
|
+
newSelected = params.multiSelect ? [itemId] : itemId;
|
|
55
63
|
}
|
|
64
|
+
setSelectedItems(event, newSelected);
|
|
56
65
|
lastSelectedItem.current = itemId;
|
|
57
|
-
|
|
58
|
-
currentRangeSelection.current = [];
|
|
66
|
+
lastSelectedRange.current = {};
|
|
59
67
|
};
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const {
|
|
63
|
-
start,
|
|
64
|
-
next,
|
|
65
|
-
current
|
|
66
|
-
} = items;
|
|
67
|
-
if (!next || !current) {
|
|
68
|
+
const selectRange = (event, [start, end]) => {
|
|
69
|
+
if (params.disableSelection || !params.multiSelect) {
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
let newSelectedItems = convertSelectedItemsToArray(models.selectedItems.value).slice();
|
|
73
|
+
|
|
74
|
+
// If the last selection was a range selection,
|
|
75
|
+
// remove the items that were part of the last range from the model
|
|
76
|
+
if (Object.keys(lastSelectedRange.current).length > 0) {
|
|
77
|
+
newSelectedItems = newSelectedItems.filter(id => !lastSelectedRange.current[id]);
|
|
72
78
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
} else {
|
|
82
|
-
base.push(next);
|
|
83
|
-
currentRangeSelection.current.push(current, next);
|
|
84
|
-
}
|
|
85
|
-
setSelectedItems(event, base);
|
|
79
|
+
|
|
80
|
+
// Add to the model the items that are part of the new range and not already part of the model.
|
|
81
|
+
const selectedItemsLookup = getLookupFromArray(newSelectedItems);
|
|
82
|
+
const range = getNonDisabledItemsInRange(instance, start, end);
|
|
83
|
+
const itemsToAddToModel = range.filter(id => !selectedItemsLookup[id]);
|
|
84
|
+
newSelectedItems = newSelectedItems.concat(itemsToAddToModel);
|
|
85
|
+
setSelectedItems(event, newSelectedItems);
|
|
86
|
+
lastSelectedRange.current = getLookupFromArray(range);
|
|
86
87
|
};
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
start,
|
|
91
|
-
end
|
|
92
|
-
} = items;
|
|
93
|
-
// If last selection was a range selection ignore items that were selected.
|
|
94
|
-
if (lastSelectionWasRange.current) {
|
|
95
|
-
base = base.filter(id => currentRangeSelection.current.indexOf(id) === -1);
|
|
88
|
+
const expandSelectionRange = (event, itemId) => {
|
|
89
|
+
if (lastSelectedItem.current != null) {
|
|
90
|
+
const [start, end] = findOrderInTremauxTree(instance, itemId, lastSelectedItem.current);
|
|
91
|
+
selectRange(event, [start, end]);
|
|
96
92
|
}
|
|
97
|
-
let range = getNavigableItemsInRange(instance, start, end);
|
|
98
|
-
range = range.filter(item => !instance.isItemDisabled(item));
|
|
99
|
-
currentRangeSelection.current = range;
|
|
100
|
-
let newSelected = base.concat(range);
|
|
101
|
-
newSelected = newSelected.filter((id, i) => newSelected.indexOf(id) === i);
|
|
102
|
-
setSelectedItems(event, newSelected);
|
|
103
93
|
};
|
|
104
|
-
const
|
|
105
|
-
|
|
94
|
+
const selectRangeFromStartToItem = (event, itemId) => {
|
|
95
|
+
selectRange(event, [getFirstNavigableItem(instance), itemId]);
|
|
96
|
+
};
|
|
97
|
+
const selectRangeFromItemToEnd = (event, itemId) => {
|
|
98
|
+
selectRange(event, [itemId, getLastNavigableItem(instance)]);
|
|
99
|
+
};
|
|
100
|
+
const selectAllNavigableItems = event => {
|
|
101
|
+
if (params.disableSelection || !params.multiSelect) {
|
|
106
102
|
return;
|
|
107
103
|
}
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
current
|
|
112
|
-
} = items;
|
|
113
|
-
if (stacked) {
|
|
114
|
-
handleRangeArrowSelect(event, {
|
|
115
|
-
start,
|
|
116
|
-
next: end,
|
|
117
|
-
current
|
|
118
|
-
});
|
|
119
|
-
} else if (start != null && end != null) {
|
|
120
|
-
handleRangeSelect(event, {
|
|
121
|
-
start,
|
|
122
|
-
end
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
lastSelectionWasRange.current = true;
|
|
104
|
+
const navigableItems = getAllNavigableItems(instance);
|
|
105
|
+
setSelectedItems(event, navigableItems);
|
|
106
|
+
lastSelectedRange.current = getLookupFromArray(navigableItems);
|
|
126
107
|
};
|
|
127
|
-
const
|
|
128
|
-
if (!
|
|
129
|
-
|
|
108
|
+
const selectItemFromArrowNavigation = (event, currentItem, nextItem) => {
|
|
109
|
+
if (params.disableSelection || !params.multiSelect) {
|
|
110
|
+
return;
|
|
130
111
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
112
|
+
let newSelectedItems = convertSelectedItemsToArray(models.selectedItems.value).slice();
|
|
113
|
+
if (Object.keys(lastSelectedRange.current).length === 0) {
|
|
114
|
+
newSelectedItems.push(nextItem);
|
|
115
|
+
lastSelectedRange.current = {
|
|
116
|
+
[currentItem]: true,
|
|
117
|
+
[nextItem]: true
|
|
118
|
+
};
|
|
119
|
+
} else {
|
|
120
|
+
if (!lastSelectedRange.current[currentItem]) {
|
|
121
|
+
lastSelectedRange.current = {};
|
|
122
|
+
}
|
|
123
|
+
if (lastSelectedRange.current[nextItem]) {
|
|
124
|
+
newSelectedItems = newSelectedItems.filter(id => id !== currentItem);
|
|
125
|
+
delete lastSelectedRange.current[currentItem];
|
|
126
|
+
} else {
|
|
127
|
+
newSelectedItems.push(nextItem);
|
|
128
|
+
lastSelectedRange.current[nextItem] = true;
|
|
129
|
+
}
|
|
140
130
|
}
|
|
141
|
-
|
|
142
|
-
instance.selectRange(event, {
|
|
143
|
-
start,
|
|
144
|
-
end: getLastNavigableItem(instance)
|
|
145
|
-
});
|
|
131
|
+
setSelectedItems(event, newSelectedItems);
|
|
146
132
|
};
|
|
147
133
|
return {
|
|
148
134
|
getRootProps: () => ({
|
|
@@ -151,9 +137,11 @@ export const useTreeViewSelection = ({
|
|
|
151
137
|
instance: {
|
|
152
138
|
isItemSelected,
|
|
153
139
|
selectItem,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
140
|
+
selectAllNavigableItems,
|
|
141
|
+
expandSelectionRange,
|
|
142
|
+
selectRangeFromStartToItem,
|
|
143
|
+
selectRangeFromItemToEnd,
|
|
144
|
+
selectItemFromArrowNavigation
|
|
157
145
|
},
|
|
158
146
|
contextValue: {
|
|
159
147
|
selection: {
|
|
@@ -1,13 +1,40 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { DefaultizedProps,
|
|
2
|
+
import type { DefaultizedProps, TreeViewPluginSignature } from '../../models';
|
|
3
3
|
import { UseTreeViewItemsSignature } from '../useTreeViewItems';
|
|
4
4
|
import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion';
|
|
5
5
|
export interface UseTreeViewSelectionInstance {
|
|
6
6
|
isItemSelected: (itemId: string) => boolean;
|
|
7
|
-
selectItem: (event: React.SyntheticEvent, itemId: string,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
selectItem: (event: React.SyntheticEvent, itemId: string, keepExistingSelection?: boolean) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Select all the navigable items in the tree.
|
|
10
|
+
* @param {React.SyntheticEvent} event The event source of the callback.
|
|
11
|
+
*/
|
|
12
|
+
selectAllNavigableItems: (event: React.SyntheticEvent) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Expand the current selection range up to the given item.
|
|
15
|
+
* @param {React.SyntheticEvent} event The event source of the callback.
|
|
16
|
+
* @param {string} itemId The id of the item to expand the selection to.
|
|
17
|
+
*/
|
|
18
|
+
expandSelectionRange: (event: React.SyntheticEvent, itemId: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Expand the current selection range from the first navigable item to the given item.
|
|
21
|
+
* @param {React.SyntheticEvent} event The event source of the callback.
|
|
22
|
+
* @param {string} itemId The id of the item up to which the selection range should be expanded.
|
|
23
|
+
*/
|
|
24
|
+
selectRangeFromStartToItem: (event: React.SyntheticEvent, itemId: string) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Expand the current selection range from the given item to the last navigable item.
|
|
27
|
+
* @param {React.SyntheticEvent} event The event source of the callback.
|
|
28
|
+
* @param {string} itemId The id of the item from which the selection range should be expanded.
|
|
29
|
+
*/
|
|
30
|
+
selectRangeFromItemToEnd: (event: React.SyntheticEvent, itemId: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Update the selection when navigating with ArrowUp / ArrowDown keys.
|
|
33
|
+
* @param {React.SyntheticEvent} event The event source of the callback.
|
|
34
|
+
* @param {string} currentItemId The id of the active item before the keyboard navigation.
|
|
35
|
+
* @param {string} nextItemId The id of the active item after the keyboard navigation.
|
|
36
|
+
*/
|
|
37
|
+
selectItemFromArrowNavigation: (event: React.SyntheticEvent, currentItemId: string, nextItemId: string) => void;
|
|
11
38
|
}
|
|
12
39
|
type TreeViewSelectionValue<Multiple extends boolean | undefined> = Multiple extends true ? string[] : string | null;
|
|
13
40
|
export interface UseTreeViewSelectionParameters<Multiple extends boolean | undefined> {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform the `selectedItems` model to be an array if it was a string or null.
|
|
3
|
+
* @param {string[] | string | null} model The raw model.
|
|
4
|
+
* @returns {string[]} The converted model.
|
|
5
|
+
*/
|
|
6
|
+
export declare const convertSelectedItemsToArray: (model: string[] | string | null) => string[];
|
|
7
|
+
export declare const getLookupFromArray: (array: string[]) => {
|
|
8
|
+
[itemId: string]: boolean;
|
|
9
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform the `selectedItems` model to be an array if it was a string or null.
|
|
3
|
+
* @param {string[] | string | null} model The raw model.
|
|
4
|
+
* @returns {string[]} The converted model.
|
|
5
|
+
*/
|
|
6
|
+
export const convertSelectedItemsToArray = model => {
|
|
7
|
+
if (Array.isArray(model)) {
|
|
8
|
+
return model;
|
|
9
|
+
}
|
|
10
|
+
if (model != null) {
|
|
11
|
+
return [model];
|
|
12
|
+
}
|
|
13
|
+
return [];
|
|
14
|
+
};
|
|
15
|
+
export const getLookupFromArray = array => {
|
|
16
|
+
const lookup = {};
|
|
17
|
+
array.forEach(itemId => {
|
|
18
|
+
lookup[itemId] = true;
|
|
19
|
+
});
|
|
20
|
+
return lookup;
|
|
21
|
+
};
|
|
@@ -11,7 +11,7 @@ export interface UseTreeViewBaseParameters<TPlugins extends readonly TreeViewPlu
|
|
|
11
11
|
slotProps: MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'slotProps'>;
|
|
12
12
|
}
|
|
13
13
|
export type UseTreeViewDefaultizedParameters<TPlugins extends readonly TreeViewPlugin<TreeViewAnyPluginSignature>[]> = UseTreeViewBaseParameters<TPlugins> & MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'defaultizedParams'>;
|
|
14
|
-
export interface UseTreeViewRootSlotProps extends Pick<React.HTMLAttributes<HTMLUListElement>, 'onFocus' | 'onBlur' | 'onKeyDown' | 'id' | 'aria-
|
|
14
|
+
export interface UseTreeViewRootSlotProps extends Pick<React.HTMLAttributes<HTMLUListElement>, 'onFocus' | 'onBlur' | 'onKeyDown' | 'id' | 'aria-multiselectable' | 'role' | 'tabIndex'> {
|
|
15
15
|
ref: React.Ref<HTMLUListElement>;
|
|
16
16
|
}
|
|
17
17
|
export interface UseTreeViewReturnValue<TPlugins extends readonly TreeViewAnyPluginSignature[]> {
|
|
@@ -3,4 +3,4 @@ import { TreeViewAnyPluginSignature, TreeViewPlugin, ConvertPluginsIntoSignature
|
|
|
3
3
|
* Implements the same behavior as `useControlled` but for several models.
|
|
4
4
|
* The controlled models are never stored in the state and the state is only updated if the model is not controlled.
|
|
5
5
|
*/
|
|
6
|
-
export declare const useTreeViewModels: <TPlugins extends readonly TreeViewPlugin<TreeViewAnyPluginSignature>[]>(plugins: TPlugins, props: MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>,
|
|
6
|
+
export declare const useTreeViewModels: <TPlugins extends readonly TreeViewPlugin<TreeViewAnyPluginSignature>[]>(plugins: TPlugins, props: MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'defaultizedParams'>) => MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, "models">;
|
|
@@ -8,7 +8,7 @@ export declare const extractPluginParamsFromProps: <TPlugins extends readonly Tr
|
|
|
8
8
|
}>({ props: { slots, slotProps, apiRef, ...props }, plugins, rootRef, }: {
|
|
9
9
|
props: TProps;
|
|
10
10
|
plugins: TPlugins;
|
|
11
|
-
rootRef?: React.Ref<HTMLUListElement
|
|
11
|
+
rootRef?: React.Ref<HTMLUListElement>;
|
|
12
12
|
}) => {
|
|
13
13
|
pluginParams: UseTreeViewBaseParameters<TPlugins> & MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, "params">;
|
|
14
14
|
slots: TSlots | undefined;
|
|
@@ -2,4 +2,4 @@ import { UseTreeViewInstanceEventsInstance } from '../corePlugins/useTreeViewIns
|
|
|
2
2
|
import { TreeViewAnyPluginSignature, TreeViewUsedEvents } from '../models';
|
|
3
3
|
export declare const publishTreeViewEvent: <Instance extends UseTreeViewInstanceEventsInstance & {
|
|
4
4
|
$$signature: TreeViewAnyPluginSignature;
|
|
5
|
-
}, E extends keyof Instance["$$signature"]["events"] | keyof import("../models").MergePluginsProperty<[import("../corePlugins").TreeViewCorePluginsSignature, ...Instance["$$signature"]["dependantPlugins"]], "events">>(instance: Instance, eventName: E, params: TreeViewUsedEvents<Instance[
|
|
5
|
+
}, E extends keyof Instance["$$signature"]["events"] | keyof import("../models").MergePluginsProperty<[import("../corePlugins").TreeViewCorePluginsSignature, ...Instance["$$signature"]["dependantPlugins"]], "events">>(instance: Instance, eventName: E, params: TreeViewUsedEvents<Instance['$$signature']>[E]['params']) => void;
|
|
@@ -5,4 +5,20 @@ export declare const getPreviousNavigableItem: (instance: TreeViewInstance<[UseT
|
|
|
5
5
|
export declare const getNextNavigableItem: (instance: TreeViewInstance<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>, itemId: string) => string | null;
|
|
6
6
|
export declare const getLastNavigableItem: (instance: TreeViewInstance<[UseTreeViewExpansionSignature, UseTreeViewItemsSignature]>) => string;
|
|
7
7
|
export declare const getFirstNavigableItem: (instance: TreeViewInstance<[UseTreeViewItemsSignature]>) => string;
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* This is used to determine the start and end of a selection range so
|
|
10
|
+
* we can get the items between the two border items.
|
|
11
|
+
*
|
|
12
|
+
* It finds the items' common ancestor using
|
|
13
|
+
* a naive implementation of a lowest common ancestor algorithm
|
|
14
|
+
* (https://en.wikipedia.org/wiki/Lowest_common_ancestor).
|
|
15
|
+
* Then compares the ancestor's 2 children that are ancestors of itemA and ItemB
|
|
16
|
+
* so we can compare their indexes to work out which item comes first in a depth first search.
|
|
17
|
+
* (https://en.wikipedia.org/wiki/Depth-first_search)
|
|
18
|
+
*
|
|
19
|
+
* Another way to put it is which item is shallower in a trémaux tree
|
|
20
|
+
* https://en.wikipedia.org/wiki/Tr%C3%A9maux_tree
|
|
21
|
+
*/
|
|
22
|
+
export declare const findOrderInTremauxTree: (instance: TreeViewInstance<[UseTreeViewItemsSignature]>, itemAId: string, itemBId: string) => string[];
|
|
23
|
+
export declare const getNonDisabledItemsInRange: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>, itemAId: string, itemBId: string) => string[];
|
|
24
|
+
export declare const getAllNavigableItems: (instance: TreeViewInstance<[UseTreeViewItemsSignature, UseTreeViewExpansionSignature]>) => string[];
|
package/internals/utils/tree.js
CHANGED
|
@@ -84,7 +84,7 @@ export const getFirstNavigableItem = instance => instance.getItemOrderedChildren
|
|
|
84
84
|
* Another way to put it is which item is shallower in a trémaux tree
|
|
85
85
|
* https://en.wikipedia.org/wiki/Tr%C3%A9maux_tree
|
|
86
86
|
*/
|
|
87
|
-
const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
|
|
87
|
+
export const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
|
|
88
88
|
if (itemAId === itemBId) {
|
|
89
89
|
return [itemAId, itemBId];
|
|
90
90
|
}
|
|
@@ -125,13 +125,43 @@ const findOrderInTremauxTree = (instance, itemAId, itemBId) => {
|
|
|
125
125
|
const bSide = bFamily[bFamily.indexOf(commonAncestor) - 1];
|
|
126
126
|
return ancestorFamily.indexOf(aSide) < ancestorFamily.indexOf(bSide) ? [itemAId, itemBId] : [itemBId, itemAId];
|
|
127
127
|
};
|
|
128
|
-
export const
|
|
128
|
+
export const getNonDisabledItemsInRange = (instance, itemAId, itemBId) => {
|
|
129
|
+
const getNextItem = itemId => {
|
|
130
|
+
// If the item is expanded and has some children, return the first of them.
|
|
131
|
+
if (instance.isItemExpandable(itemId) && instance.isItemExpanded(itemId)) {
|
|
132
|
+
return instance.getItemOrderedChildrenIds(itemId)[0];
|
|
133
|
+
}
|
|
134
|
+
let itemMeta = instance.getItemMeta(itemId);
|
|
135
|
+
while (itemMeta != null) {
|
|
136
|
+
// Try to find the first navigable sibling after the current item.
|
|
137
|
+
const siblings = instance.getItemOrderedChildrenIds(itemMeta.parentId);
|
|
138
|
+
const currentItemIndex = instance.getItemIndex(itemMeta.id);
|
|
139
|
+
if (currentItemIndex < siblings.length - 1) {
|
|
140
|
+
return siblings[currentItemIndex + 1];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// If the item is the last of its siblings, go up a level to the parent and try again.
|
|
144
|
+
itemMeta = instance.getItemMeta(itemMeta.parentId);
|
|
145
|
+
}
|
|
146
|
+
throw new Error('Invalid range');
|
|
147
|
+
};
|
|
129
148
|
const [first, last] = findOrderInTremauxTree(instance, itemAId, itemBId);
|
|
130
149
|
const items = [first];
|
|
131
150
|
let current = first;
|
|
132
151
|
while (current !== last) {
|
|
133
|
-
current =
|
|
134
|
-
|
|
152
|
+
current = getNextItem(current);
|
|
153
|
+
if (!instance.isItemDisabled(current)) {
|
|
154
|
+
items.push(current);
|
|
155
|
+
}
|
|
135
156
|
}
|
|
136
157
|
return items;
|
|
158
|
+
};
|
|
159
|
+
export const getAllNavigableItems = instance => {
|
|
160
|
+
let item = getFirstNavigableItem(instance);
|
|
161
|
+
const navigableItems = [];
|
|
162
|
+
while (item != null) {
|
|
163
|
+
navigableItems.push(item);
|
|
164
|
+
item = getNextNavigableItem(instance, item);
|
|
165
|
+
}
|
|
166
|
+
return navigableItems;
|
|
137
167
|
};
|
|
@@ -19,8 +19,7 @@ import { treeItemClasses, getTreeItemUtilityClass } from './treeItemClasses';
|
|
|
19
19
|
import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewContext';
|
|
20
20
|
import { TreeViewCollapseIcon, TreeViewExpandIcon } from '../icons';
|
|
21
21
|
import { TreeItem2Provider } from '../TreeItem2Provider';
|
|
22
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
23
|
-
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
23
|
const useUtilityClasses = ownerState => {
|
|
25
24
|
const {
|
|
26
25
|
classes
|
|
@@ -5,8 +5,7 @@ import * as React from 'react';
|
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
import clsx from 'clsx';
|
|
7
7
|
import { useTreeItemState } from './useTreeItemState';
|
|
8
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
-
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
9
|
/**
|
|
11
10
|
* @ignore - internal component.
|
|
12
11
|
*/
|
|
@@ -32,9 +32,7 @@ export function useTreeItemState(itemId) {
|
|
|
32
32
|
const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
|
|
33
33
|
if (multiple) {
|
|
34
34
|
if (event.shiftKey) {
|
|
35
|
-
instance.
|
|
36
|
-
end: itemId
|
|
37
|
-
});
|
|
35
|
+
instance.expandSelectionRange(event, itemId);
|
|
38
36
|
} else {
|
|
39
37
|
instance.selectItem(event, itemId, true);
|
|
40
38
|
}
|
|
@@ -14,8 +14,7 @@ import { unstable_useTreeItem2 as useTreeItem2 } from '../useTreeItem2';
|
|
|
14
14
|
import { getTreeItemUtilityClass, treeItemClasses } from '../TreeItem';
|
|
15
15
|
import { TreeItem2Icon } from '../TreeItem2Icon';
|
|
16
16
|
import { TreeItem2Provider } from '../TreeItem2Provider';
|
|
17
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
-
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
18
|
export const TreeItem2Root = styled('li', {
|
|
20
19
|
name: 'MuiTreeItem2',
|
|
21
20
|
slot: 'Root',
|
|
@@ -122,7 +121,7 @@ export const TreeItem2IconContainer = styled('div', {
|
|
|
122
121
|
}
|
|
123
122
|
});
|
|
124
123
|
export const TreeItem2GroupTransition = styled(Collapse, {
|
|
125
|
-
name: '
|
|
124
|
+
name: 'MuiTreeItem2',
|
|
126
125
|
slot: 'GroupTransition',
|
|
127
126
|
overridesResolver: (props, styles) => styles.groupTransition
|
|
128
127
|
})({
|
|
@@ -40,9 +40,7 @@ export const useTreeItem2Utils = ({
|
|
|
40
40
|
const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
|
|
41
41
|
if (multiple) {
|
|
42
42
|
if (event.shiftKey) {
|
|
43
|
-
instance.
|
|
44
|
-
end: itemId
|
|
45
|
-
});
|
|
43
|
+
instance.expandSelectionRange(event, itemId);
|
|
46
44
|
} else {
|
|
47
45
|
instance.selectItem(event, itemId, true);
|
|
48
46
|
}
|
package/modern/index.js
CHANGED
|
@@ -105,12 +105,9 @@ export const useTreeViewFocus = ({
|
|
|
105
105
|
instance.focusDefaultItem(event);
|
|
106
106
|
}
|
|
107
107
|
};
|
|
108
|
-
const focusedItem = instance.getItemMeta(state.focusedItemId);
|
|
109
|
-
const activeDescendant = focusedItem ? instance.getTreeItemIdAttribute(focusedItem.id, focusedItem.idAttribute) : null;
|
|
110
108
|
return {
|
|
111
109
|
getRootProps: otherHandlers => ({
|
|
112
|
-
onFocus: createRootHandleFocus(otherHandlers)
|
|
113
|
-
'aria-activedescendant': activeDescendant ?? undefined
|
|
110
|
+
onFocus: createRootHandleFocus(otherHandlers)
|
|
114
111
|
}),
|
|
115
112
|
publicAPI: {
|
|
116
113
|
focusItem
|