@mui/x-tree-view 7.5.1 → 7.6.1
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 +112 -1
- package/RichTreeView/RichTreeView.js +14 -0
- package/RichTreeView/RichTreeView.types.d.ts +7 -1
- package/SimpleTreeView/SimpleTreeView.js +14 -0
- package/SimpleTreeView/SimpleTreeView.types.d.ts +7 -1
- package/TreeItem/TreeItem.js +35 -7
- package/TreeItem/TreeItem.types.d.ts +1 -0
- package/TreeItem2/TreeItem2.d.ts +12 -6
- package/TreeItem2/TreeItem2.js +21 -10
- package/TreeItem2Provider/TreeItem2Provider.js +4 -2
- package/TreeView/TreeView.js +14 -0
- package/index.js +1 -1
- package/internals/TreeViewItemDepthContext/TreeViewItemDepthContext.d.ts +3 -0
- package/internals/TreeViewItemDepthContext/TreeViewItemDepthContext.js +5 -0
- package/internals/TreeViewItemDepthContext/index.d.ts +1 -0
- package/internals/TreeViewItemDepthContext/index.js +1 -0
- package/internals/TreeViewProvider/TreeViewContext.d.ts +2 -2
- package/internals/TreeViewProvider/TreeViewProvider.types.d.ts +2 -2
- package/internals/index.d.ts +1 -1
- package/internals/models/helpers.d.ts +1 -0
- package/internals/models/plugin.d.ts +12 -5
- package/internals/models/treeView.d.ts +8 -1
- package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +28 -4
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +11 -26
- package/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.d.ts +20 -5
- package/internals/plugins/useTreeViewId/useTreeViewId.types.d.ts +10 -1
- package/internals/plugins/useTreeViewItems/useTreeViewItems.js +29 -8
- package/internals/plugins/useTreeViewItems/useTreeViewItems.types.d.ts +50 -7
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +34 -25
- package/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.types.d.ts +22 -4
- package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +14 -1
- package/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.d.ts +5 -0
- package/internals/useTreeView/useTreeView.js +8 -3
- package/internals/useTreeView/useTreeView.types.d.ts +2 -1
- package/internals/utils/extractPluginParamsFromProps.d.ts +3 -2
- package/internals/utils/extractPluginParamsFromProps.js +4 -2
- package/internals/utils/tree.js +18 -1
- package/modern/RichTreeView/RichTreeView.js +14 -0
- package/modern/SimpleTreeView/SimpleTreeView.js +14 -0
- package/modern/TreeItem/TreeItem.js +35 -7
- package/modern/TreeItem2/TreeItem2.js +21 -10
- package/modern/TreeItem2Provider/TreeItem2Provider.js +4 -2
- package/modern/TreeView/TreeView.js +14 -0
- package/modern/index.js +1 -1
- package/modern/internals/TreeViewItemDepthContext/TreeViewItemDepthContext.js +5 -0
- package/modern/internals/TreeViewItemDepthContext/index.js +1 -0
- package/modern/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +11 -26
- package/modern/internals/plugins/useTreeViewItems/useTreeViewItems.js +29 -8
- package/modern/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +34 -25
- package/modern/internals/useTreeView/useTreeView.js +8 -3
- package/modern/internals/utils/extractPluginParamsFromProps.js +4 -2
- package/modern/internals/utils/tree.js +18 -1
- package/modern/useTreeItem2/useTreeItem2.js +20 -3
- package/node/RichTreeView/RichTreeView.js +14 -0
- package/node/SimpleTreeView/SimpleTreeView.js +14 -0
- package/node/TreeItem/TreeItem.js +35 -7
- package/node/TreeItem2/TreeItem2.js +20 -9
- package/node/TreeItem2Provider/TreeItem2Provider.js +4 -2
- package/node/TreeView/TreeView.js +14 -0
- package/node/index.js +1 -1
- package/node/internals/TreeViewItemDepthContext/TreeViewItemDepthContext.js +13 -0
- package/node/internals/TreeViewItemDepthContext/index.js +12 -0
- package/node/internals/plugins/useTreeViewFocus/useTreeViewFocus.js +11 -26
- package/node/internals/plugins/useTreeViewItems/useTreeViewItems.js +29 -8
- package/node/internals/plugins/useTreeViewJSXItems/useTreeViewJSXItems.js +34 -25
- package/node/internals/useTreeView/useTreeView.js +8 -3
- package/node/internals/utils/extractPluginParamsFromProps.js +4 -2
- package/node/internals/utils/tree.js +18 -1
- package/node/useTreeItem2/useTreeItem2.js +20 -3
- package/package.json +3 -3
- package/useTreeItem2/useTreeItem2.js +20 -3
- package/useTreeItem2/useTreeItem2.types.d.ts +12 -0
|
@@ -48,6 +48,7 @@ export const useTreeView = inParams => {
|
|
|
48
48
|
params,
|
|
49
49
|
slots: params.slots,
|
|
50
50
|
slotProps: params.slotProps,
|
|
51
|
+
experimentalFeatures: params.experimentalFeatures,
|
|
51
52
|
state,
|
|
52
53
|
setState,
|
|
53
54
|
rootRef: innerRootRef,
|
|
@@ -100,19 +101,23 @@ export const useTreeView = inParams => {
|
|
|
100
101
|
itemWrappers.forEach(itemWrapper => {
|
|
101
102
|
finalChildren = itemWrapper({
|
|
102
103
|
itemId,
|
|
103
|
-
children: finalChildren
|
|
104
|
+
children: finalChildren,
|
|
105
|
+
instance
|
|
104
106
|
});
|
|
105
107
|
});
|
|
106
108
|
return finalChildren;
|
|
107
109
|
};
|
|
108
|
-
const rootWrappers = plugins.map(plugin => plugin.wrapRoot).filter(wrapRoot => !!wrapRoot)
|
|
110
|
+
const rootWrappers = plugins.map(plugin => plugin.wrapRoot).filter(wrapRoot => !!wrapRoot)
|
|
111
|
+
// The wrappers are reversed to ensure that the first wrapper is the outermost one.
|
|
112
|
+
.reverse();
|
|
109
113
|
contextValue.wrapRoot = ({
|
|
110
114
|
children
|
|
111
115
|
}) => {
|
|
112
116
|
let finalChildren = children;
|
|
113
117
|
rootWrappers.forEach(rootWrapper => {
|
|
114
118
|
finalChildren = rootWrapper({
|
|
115
|
-
children: finalChildren
|
|
119
|
+
children: finalChildren,
|
|
120
|
+
instance
|
|
116
121
|
});
|
|
117
122
|
});
|
|
118
123
|
return finalChildren;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { EventHandlers } from '@mui/base/utils';
|
|
3
3
|
import type { TreeViewContextValue } from '../TreeViewProvider';
|
|
4
|
-
import { TreeViewAnyPluginSignature, TreeViewPlugin, ConvertPluginsIntoSignatures, MergePluginsProperty, TreeViewInstance, TreeViewPublicAPI } from '../models';
|
|
4
|
+
import { TreeViewAnyPluginSignature, TreeViewPlugin, ConvertPluginsIntoSignatures, MergePluginsProperty, TreeViewInstance, TreeViewPublicAPI, TreeViewExperimentalFeatures } from '../models';
|
|
5
5
|
export type UseTreeViewParameters<TPlugins extends readonly TreeViewPlugin<TreeViewAnyPluginSignature>[]> = UseTreeViewBaseParameters<TPlugins> & MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'params'>;
|
|
6
6
|
export interface UseTreeViewBaseParameters<TPlugins extends readonly TreeViewPlugin<TreeViewAnyPluginSignature>[]> {
|
|
7
7
|
apiRef: React.MutableRefObject<TreeViewPublicAPI<ConvertPluginsIntoSignatures<TPlugins>>> | undefined;
|
|
@@ -9,6 +9,7 @@ export interface UseTreeViewBaseParameters<TPlugins extends readonly TreeViewPlu
|
|
|
9
9
|
plugins: TPlugins;
|
|
10
10
|
slots: MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'slots'>;
|
|
11
11
|
slotProps: MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'slotProps'>;
|
|
12
|
+
experimentalFeatures: TreeViewExperimentalFeatures<ConvertPluginsIntoSignatures<TPlugins>>;
|
|
12
13
|
}
|
|
13
14
|
export type UseTreeViewDefaultizedParameters<TPlugins extends readonly TreeViewPlugin<TreeViewAnyPluginSignature>[]> = UseTreeViewBaseParameters<TPlugins> & MergePluginsProperty<ConvertPluginsIntoSignatures<TPlugins>, 'defaultizedParams'>;
|
|
14
15
|
export interface UseTreeViewRootSlotProps extends Pick<React.HTMLAttributes<HTMLUListElement>, 'onFocus' | 'onBlur' | 'onKeyDown' | 'id' | 'aria-multiselectable' | 'role' | 'tabIndex'> {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ConvertPluginsIntoSignatures, MergePluginsProperty, TreeViewPlugin, TreeViewPublicAPI } from '../models';
|
|
2
|
+
import { ConvertPluginsIntoSignatures, MergePluginsProperty, TreeViewExperimentalFeatures, TreeViewPlugin, TreeViewPublicAPI } from '../models';
|
|
3
3
|
import { UseTreeViewBaseParameters } from '../useTreeView/useTreeView.types';
|
|
4
4
|
export declare const extractPluginParamsFromProps: <TPlugins extends readonly TreeViewPlugin<any>[], TSlots extends MergePluginsProperty<TPlugins, "slots">, TSlotProps extends MergePluginsProperty<TPlugins, "slotProps">, TProps extends {
|
|
5
5
|
slots?: TSlots | undefined;
|
|
6
6
|
slotProps?: TSlotProps | undefined;
|
|
7
7
|
apiRef?: React.MutableRefObject<TreeViewPublicAPI<ConvertPluginsIntoSignatures<TPlugins>> | undefined> | undefined;
|
|
8
|
-
|
|
8
|
+
experimentalFeatures?: TreeViewExperimentalFeatures<ConvertPluginsIntoSignatures<TPlugins>> | undefined;
|
|
9
|
+
}>({ props: { slots, slotProps, apiRef, experimentalFeatures, ...props }, plugins, rootRef, }: {
|
|
9
10
|
props: TProps;
|
|
10
11
|
plugins: TPlugins;
|
|
11
12
|
rootRef?: React.Ref<HTMLUListElement>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
2
|
-
const _excluded = ["slots", "slotProps", "apiRef"];
|
|
2
|
+
const _excluded = ["slots", "slotProps", "apiRef", "experimentalFeatures"];
|
|
3
3
|
export const extractPluginParamsFromProps = _ref => {
|
|
4
4
|
let {
|
|
5
5
|
props: {
|
|
6
6
|
slots,
|
|
7
7
|
slotProps,
|
|
8
|
-
apiRef
|
|
8
|
+
apiRef,
|
|
9
|
+
experimentalFeatures
|
|
9
10
|
},
|
|
10
11
|
plugins,
|
|
11
12
|
rootRef
|
|
@@ -20,6 +21,7 @@ export const extractPluginParamsFromProps = _ref => {
|
|
|
20
21
|
rootRef,
|
|
21
22
|
slots: slots ?? {},
|
|
22
23
|
slotProps: slotProps ?? {},
|
|
24
|
+
experimentalFeatures: experimentalFeatures ?? {},
|
|
23
25
|
apiRef
|
|
24
26
|
};
|
|
25
27
|
const otherProps = {};
|
package/internals/utils/tree.js
CHANGED
|
@@ -18,7 +18,24 @@ export const getPreviousNavigableItem = (instance, itemId) => {
|
|
|
18
18
|
if (itemIndex === 0) {
|
|
19
19
|
return itemMeta.parentId;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
// Finds the previous navigable sibling.
|
|
23
|
+
let previousNavigableSiblingIndex = itemIndex - 1;
|
|
24
|
+
while (!instance.isItemNavigable(siblings[previousNavigableSiblingIndex]) && previousNavigableSiblingIndex >= 0) {
|
|
25
|
+
previousNavigableSiblingIndex -= 1;
|
|
26
|
+
}
|
|
27
|
+
if (previousNavigableSiblingIndex === -1) {
|
|
28
|
+
// If we are at depth 0, then it means all the items above the current item are not navigable.
|
|
29
|
+
if (itemMeta.parentId == null) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Otherwise, we can try to go up a level and find the previous navigable item.
|
|
34
|
+
return getPreviousNavigableItem(instance, itemMeta.parentId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Finds the last navigable ancestor of the previous navigable sibling.
|
|
38
|
+
let currentItemId = siblings[previousNavigableSiblingIndex];
|
|
22
39
|
let lastNavigableChild = getLastNavigableItemInArray(instance, instance.getItemOrderedChildrenIds(currentItemId));
|
|
23
40
|
while (instance.isItemExpanded(currentItemId) && lastNavigableChild != null) {
|
|
24
41
|
currentItemId = lastNavigableChild;
|
|
@@ -180,6 +180,14 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
180
180
|
* Used when the item's expansion is controlled.
|
|
181
181
|
*/
|
|
182
182
|
expandedItems: PropTypes.arrayOf(PropTypes.string),
|
|
183
|
+
/**
|
|
184
|
+
* Unstable features, breaking changes might be introduced.
|
|
185
|
+
* For each feature, if the flag is not explicitly set to `true`,
|
|
186
|
+
* the feature will be fully disabled and any property / method call will not have any effect.
|
|
187
|
+
*/
|
|
188
|
+
experimentalFeatures: PropTypes.shape({
|
|
189
|
+
indentationAtItemLevel: PropTypes.bool
|
|
190
|
+
}),
|
|
183
191
|
/**
|
|
184
192
|
* Used to determine the id of a given item.
|
|
185
193
|
*
|
|
@@ -210,6 +218,12 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
|
|
|
210
218
|
* @returns {boolean} `true` if the item should be disabled.
|
|
211
219
|
*/
|
|
212
220
|
isItemDisabled: PropTypes.func,
|
|
221
|
+
/**
|
|
222
|
+
* Horizontal indentation between an item and its children.
|
|
223
|
+
* Examples: 24, "24px", "2rem", "2em".
|
|
224
|
+
* @default 12px
|
|
225
|
+
*/
|
|
226
|
+
itemChildrenIndentation: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
213
227
|
items: PropTypes.array.isRequired,
|
|
214
228
|
/**
|
|
215
229
|
* If `true`, `ctrl` and `shift` will trigger multiselect.
|
|
@@ -142,11 +142,25 @@ process.env.NODE_ENV !== "production" ? SimpleTreeView.propTypes = {
|
|
|
142
142
|
* Used when the item's expansion is controlled.
|
|
143
143
|
*/
|
|
144
144
|
expandedItems: PropTypes.arrayOf(PropTypes.string),
|
|
145
|
+
/**
|
|
146
|
+
* Unstable features, breaking changes might be introduced.
|
|
147
|
+
* For each feature, if the flag is not explicitly set to `true`,
|
|
148
|
+
* the feature will be fully disabled and any property / method call will not have any effect.
|
|
149
|
+
*/
|
|
150
|
+
experimentalFeatures: PropTypes.shape({
|
|
151
|
+
indentationAtItemLevel: PropTypes.bool
|
|
152
|
+
}),
|
|
145
153
|
/**
|
|
146
154
|
* This prop is used to help implement the accessibility logic.
|
|
147
155
|
* If you don't provide this prop. It falls back to a randomly generated id.
|
|
148
156
|
*/
|
|
149
157
|
id: PropTypes.string,
|
|
158
|
+
/**
|
|
159
|
+
* Horizontal indentation between an item and its children.
|
|
160
|
+
* Examples: 24, "24px", "2rem", "2em".
|
|
161
|
+
* @default 12px
|
|
162
|
+
*/
|
|
163
|
+
itemChildrenIndentation: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
150
164
|
/**
|
|
151
165
|
* If `true`, `ctrl` and `shift` will trigger multiselect.
|
|
152
166
|
* @default false
|
|
@@ -10,6 +10,7 @@ import clsx from 'clsx';
|
|
|
10
10
|
import Collapse from '@mui/material/Collapse';
|
|
11
11
|
import { resolveComponentProps, useSlotProps } from '@mui/base/utils';
|
|
12
12
|
import useForkRef from '@mui/utils/useForkRef';
|
|
13
|
+
import { shouldForwardProp } from '@mui/system/createStyled';
|
|
13
14
|
import { alpha, styled, useThemeProps } from '@mui/material/styles';
|
|
14
15
|
import unsupportedProp from '@mui/utils/unsupportedProp';
|
|
15
16
|
import elementTypeAcceptingRef from '@mui/utils/elementTypeAcceptingRef';
|
|
@@ -19,6 +20,7 @@ import { treeItemClasses, getTreeItemUtilityClass } from './treeItemClasses';
|
|
|
19
20
|
import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewContext';
|
|
20
21
|
import { TreeViewCollapseIcon, TreeViewExpandIcon } from '../icons';
|
|
21
22
|
import { TreeItem2Provider } from '../TreeItem2Provider';
|
|
23
|
+
import { TreeViewItemDepthContext } from '../internals/TreeViewItemDepthContext';
|
|
22
24
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
25
|
const useUtilityClasses = ownerState => {
|
|
24
26
|
const {
|
|
@@ -57,7 +59,8 @@ const StyledTreeItemContent = styled(TreeItemContent, {
|
|
|
57
59
|
}, styles.label && {
|
|
58
60
|
[`& .${treeItemClasses.label}`]: styles.label
|
|
59
61
|
}];
|
|
60
|
-
}
|
|
62
|
+
},
|
|
63
|
+
shouldForwardProp: prop => shouldForwardProp(prop) && prop !== 'indentationAtItemLevel'
|
|
61
64
|
})(({
|
|
62
65
|
theme
|
|
63
66
|
}) => ({
|
|
@@ -117,16 +120,33 @@ const StyledTreeItemContent = styled(TreeItemContent, {
|
|
|
117
120
|
}, theme.typography.body1),
|
|
118
121
|
[`& .${treeItemClasses.checkbox}`]: {
|
|
119
122
|
padding: 0
|
|
120
|
-
}
|
|
123
|
+
},
|
|
124
|
+
variants: [{
|
|
125
|
+
props: {
|
|
126
|
+
indentationAtItemLevel: true
|
|
127
|
+
},
|
|
128
|
+
style: {
|
|
129
|
+
paddingLeft: `calc(${theme.spacing(1)} + var(--TreeView-itemChildrenIndentation) * var(--TreeView-itemDepth))`
|
|
130
|
+
}
|
|
131
|
+
}]
|
|
121
132
|
}));
|
|
122
133
|
const TreeItemGroup = styled(Collapse, {
|
|
123
134
|
name: 'MuiTreeItem',
|
|
124
135
|
slot: 'GroupTransition',
|
|
125
|
-
overridesResolver: (props, styles) => styles.groupTransition
|
|
136
|
+
overridesResolver: (props, styles) => styles.groupTransition,
|
|
137
|
+
shouldForwardProp: prop => shouldForwardProp(prop) && prop !== 'indentationAtItemLevel'
|
|
126
138
|
})({
|
|
127
139
|
margin: 0,
|
|
128
140
|
padding: 0,
|
|
129
|
-
paddingLeft:
|
|
141
|
+
paddingLeft: 'var(--TreeView-itemChildrenIndentation)',
|
|
142
|
+
variants: [{
|
|
143
|
+
props: {
|
|
144
|
+
indentationAtItemLevel: true
|
|
145
|
+
},
|
|
146
|
+
style: {
|
|
147
|
+
paddingLeft: 0
|
|
148
|
+
}
|
|
149
|
+
}]
|
|
130
150
|
});
|
|
131
151
|
|
|
132
152
|
/**
|
|
@@ -147,8 +167,10 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
147
167
|
multiSelect
|
|
148
168
|
},
|
|
149
169
|
disabledItemsFocusable,
|
|
170
|
+
indentationAtItemLevel,
|
|
150
171
|
instance
|
|
151
172
|
} = useTreeViewContext();
|
|
173
|
+
const depthContext = React.useContext(TreeViewItemDepthContext);
|
|
152
174
|
const props = useThemeProps({
|
|
153
175
|
props: inProps,
|
|
154
176
|
name: 'MuiTreeItem'
|
|
@@ -197,7 +219,8 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
197
219
|
expanded,
|
|
198
220
|
focused,
|
|
199
221
|
selected,
|
|
200
|
-
disabled
|
|
222
|
+
disabled,
|
|
223
|
+
indentationAtItemLevel
|
|
201
224
|
});
|
|
202
225
|
const classes = useUtilityClasses(ownerState);
|
|
203
226
|
const GroupTransition = slots.groupTransition ?? undefined;
|
|
@@ -205,12 +228,14 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
205
228
|
elementType: GroupTransition,
|
|
206
229
|
ownerState: {},
|
|
207
230
|
externalSlotProps: inSlotProps?.groupTransition,
|
|
208
|
-
additionalProps: {
|
|
231
|
+
additionalProps: _extends({
|
|
209
232
|
unmountOnExit: true,
|
|
210
233
|
in: expanded,
|
|
211
234
|
component: 'ul',
|
|
212
235
|
role: 'group'
|
|
213
|
-
},
|
|
236
|
+
}, indentationAtItemLevel ? {
|
|
237
|
+
indentationAtItemLevel: true
|
|
238
|
+
} : {}),
|
|
214
239
|
className: classes.groupTransition
|
|
215
240
|
});
|
|
216
241
|
const ExpansionIcon = expanded ? slots.collapseIcon : slots.expandIcon;
|
|
@@ -291,6 +316,9 @@ export const TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(inProps,
|
|
|
291
316
|
onBlur: handleBlur,
|
|
292
317
|
onKeyDown: handleKeyDown,
|
|
293
318
|
ref: handleRootRef,
|
|
319
|
+
style: indentationAtItemLevel ? _extends({}, other.style, {
|
|
320
|
+
'--TreeView-itemDepth': typeof depthContext === 'function' ? depthContext(itemId) : depthContext
|
|
321
|
+
}) : other.style,
|
|
294
322
|
children: [/*#__PURE__*/_jsx(StyledTreeItemContent, _extends({
|
|
295
323
|
as: ContentComponent,
|
|
296
324
|
classes: {
|
|
@@ -10,10 +10,10 @@ import { alpha, styled, useThemeProps } from '@mui/material/styles';
|
|
|
10
10
|
import Collapse from '@mui/material/Collapse';
|
|
11
11
|
import MuiCheckbox from '@mui/material/Checkbox';
|
|
12
12
|
import { useSlotProps } from '@mui/base/utils';
|
|
13
|
-
import { shouldForwardProp } from '@mui/system';
|
|
13
|
+
import { shouldForwardProp } from '@mui/system/createStyled';
|
|
14
14
|
import composeClasses from '@mui/utils/composeClasses';
|
|
15
15
|
import { unstable_useTreeItem2 as useTreeItem2 } from '../useTreeItem2';
|
|
16
|
-
import { getTreeItemUtilityClass
|
|
16
|
+
import { getTreeItemUtilityClass } from '../TreeItem';
|
|
17
17
|
import { TreeItem2Icon } from '../TreeItem2Icon';
|
|
18
18
|
import { TreeItem2Provider } from '../TreeItem2Provider';
|
|
19
19
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -31,7 +31,7 @@ export const TreeItem2Content = styled('div', {
|
|
|
31
31
|
name: 'MuiTreeItem2',
|
|
32
32
|
slot: 'Content',
|
|
33
33
|
overridesResolver: (props, styles) => styles.content,
|
|
34
|
-
shouldForwardProp: prop => shouldForwardProp(prop) && prop !== 'status'
|
|
34
|
+
shouldForwardProp: prop => shouldForwardProp(prop) && prop !== 'status' && prop !== 'indentationAtItemLevel'
|
|
35
35
|
})(({
|
|
36
36
|
theme
|
|
37
37
|
}) => ({
|
|
@@ -52,12 +52,14 @@ export const TreeItem2Content = styled('div', {
|
|
|
52
52
|
backgroundColor: 'transparent'
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
-
[`& .${treeItemClasses.groupTransition}`]: {
|
|
56
|
-
margin: 0,
|
|
57
|
-
padding: 0,
|
|
58
|
-
paddingLeft: 12
|
|
59
|
-
},
|
|
60
55
|
variants: [{
|
|
56
|
+
props: {
|
|
57
|
+
indentationAtItemLevel: true
|
|
58
|
+
},
|
|
59
|
+
style: {
|
|
60
|
+
paddingLeft: `calc(${theme.spacing(1)} + var(--TreeView-itemChildrenIndentation) * var(--TreeView-itemDepth))`
|
|
61
|
+
}
|
|
62
|
+
}, {
|
|
61
63
|
props: ({
|
|
62
64
|
status
|
|
63
65
|
}) => status.disabled,
|
|
@@ -125,11 +127,20 @@ export const TreeItem2IconContainer = styled('div', {
|
|
|
125
127
|
export const TreeItem2GroupTransition = styled(Collapse, {
|
|
126
128
|
name: 'MuiTreeItem2',
|
|
127
129
|
slot: 'GroupTransition',
|
|
128
|
-
overridesResolver: (props, styles) => styles.groupTransition
|
|
130
|
+
overridesResolver: (props, styles) => styles.groupTransition,
|
|
131
|
+
shouldForwardProp: prop => shouldForwardProp(prop) && prop !== 'indentationAtItemLevel'
|
|
129
132
|
})({
|
|
130
133
|
margin: 0,
|
|
131
134
|
padding: 0,
|
|
132
|
-
paddingLeft:
|
|
135
|
+
paddingLeft: 'var(--TreeView-itemChildrenIndentation)',
|
|
136
|
+
variants: [{
|
|
137
|
+
props: {
|
|
138
|
+
indentationAtItemLevel: true
|
|
139
|
+
},
|
|
140
|
+
style: {
|
|
141
|
+
paddingLeft: 0
|
|
142
|
+
}
|
|
143
|
+
}]
|
|
133
144
|
});
|
|
134
145
|
export const TreeItem2Checkbox = styled( /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
135
146
|
const {
|
|
@@ -115,11 +115,25 @@ process.env.NODE_ENV !== "production" ? TreeView.propTypes = {
|
|
|
115
115
|
* Used when the item's expansion is controlled.
|
|
116
116
|
*/
|
|
117
117
|
expandedItems: PropTypes.arrayOf(PropTypes.string),
|
|
118
|
+
/**
|
|
119
|
+
* Unstable features, breaking changes might be introduced.
|
|
120
|
+
* For each feature, if the flag is not explicitly set to `true`,
|
|
121
|
+
* the feature will be fully disabled and any property / method call will not have any effect.
|
|
122
|
+
*/
|
|
123
|
+
experimentalFeatures: PropTypes.shape({
|
|
124
|
+
indentationAtItemLevel: PropTypes.bool
|
|
125
|
+
}),
|
|
118
126
|
/**
|
|
119
127
|
* This prop is used to help implement the accessibility logic.
|
|
120
128
|
* If you don't provide this prop. It falls back to a randomly generated id.
|
|
121
129
|
*/
|
|
122
130
|
id: PropTypes.string,
|
|
131
|
+
/**
|
|
132
|
+
* Horizontal indentation between an item and its children.
|
|
133
|
+
* Examples: 24, "24px", "2rem", "2em".
|
|
134
|
+
* @default 12px
|
|
135
|
+
*/
|
|
136
|
+
itemChildrenIndentation: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
123
137
|
/**
|
|
124
138
|
* If `true`, `ctrl` and `shift` will trigger multiselect.
|
|
125
139
|
* @default false
|
package/modern/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TreeViewItemDepthContext } from './TreeViewItemDepthContext';
|
|
@@ -5,17 +5,15 @@ import ownerDocument from '@mui/utils/ownerDocument';
|
|
|
5
5
|
import { useInstanceEventHandler } from '../../hooks/useInstanceEventHandler';
|
|
6
6
|
import { getActiveElement } from '../../utils/utils';
|
|
7
7
|
import { getFirstNavigableItem } from '../../utils/tree';
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import { convertSelectedItemsToArray } from '../useTreeViewSelection/useTreeViewSelection.utils';
|
|
9
|
+
const useDefaultFocusableItemId = (instance, selectedItems) => {
|
|
10
|
+
let tabbableItemId = convertSelectedItemsToArray(selectedItems).find(itemId => {
|
|
11
|
+
if (!instance.isItemNavigable(itemId)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
10
14
|
const itemMeta = instance.getItemMeta(itemId);
|
|
11
15
|
return itemMeta && (itemMeta.parentId == null || instance.isItemExpanded(itemMeta.parentId));
|
|
12
|
-
};
|
|
13
|
-
let tabbableItemId;
|
|
14
|
-
if (Array.isArray(selectedItems)) {
|
|
15
|
-
tabbableItemId = selectedItems.find(isItemVisible);
|
|
16
|
-
} else if (selectedItems != null && isItemVisible(selectedItems)) {
|
|
17
|
-
tabbableItemId = selectedItems;
|
|
18
|
-
}
|
|
16
|
+
});
|
|
19
17
|
if (tabbableItemId == null) {
|
|
20
18
|
tabbableItemId = getFirstNavigableItem(instance);
|
|
21
19
|
}
|
|
@@ -29,7 +27,7 @@ export const useTreeViewFocus = ({
|
|
|
29
27
|
models,
|
|
30
28
|
rootRef
|
|
31
29
|
}) => {
|
|
32
|
-
const
|
|
30
|
+
const defaultFocusableItemId = useDefaultFocusableItemId(instance, models.selectedItems.value);
|
|
33
31
|
const setFocusedItemId = useEventCallback(itemId => {
|
|
34
32
|
const cleanItemId = typeof itemId === 'function' ? itemId(state.focusedItemId) : itemId;
|
|
35
33
|
if (state.focusedItemId !== cleanItemId) {
|
|
@@ -61,18 +59,6 @@ export const useTreeViewFocus = ({
|
|
|
61
59
|
innerFocusItem(event, itemId);
|
|
62
60
|
}
|
|
63
61
|
});
|
|
64
|
-
const focusDefaultItem = useEventCallback(event => {
|
|
65
|
-
let itemToFocusId;
|
|
66
|
-
if (Array.isArray(models.selectedItems.value)) {
|
|
67
|
-
itemToFocusId = models.selectedItems.value.find(isItemVisible);
|
|
68
|
-
} else if (models.selectedItems.value != null && isItemVisible(models.selectedItems.value)) {
|
|
69
|
-
itemToFocusId = models.selectedItems.value;
|
|
70
|
-
}
|
|
71
|
-
if (itemToFocusId == null) {
|
|
72
|
-
itemToFocusId = getFirstNavigableItem(instance);
|
|
73
|
-
}
|
|
74
|
-
innerFocusItem(event, itemToFocusId);
|
|
75
|
-
});
|
|
76
62
|
const removeFocusedItem = useEventCallback(() => {
|
|
77
63
|
if (state.focusedItemId == null) {
|
|
78
64
|
return;
|
|
@@ -86,12 +72,12 @@ export const useTreeViewFocus = ({
|
|
|
86
72
|
}
|
|
87
73
|
setFocusedItemId(null);
|
|
88
74
|
});
|
|
89
|
-
const canItemBeTabbed = itemId => itemId ===
|
|
75
|
+
const canItemBeTabbed = itemId => itemId === defaultFocusableItemId;
|
|
90
76
|
useInstanceEventHandler(instance, 'removeItem', ({
|
|
91
77
|
id
|
|
92
78
|
}) => {
|
|
93
79
|
if (state.focusedItemId === id) {
|
|
94
|
-
|
|
80
|
+
innerFocusItem(null, defaultFocusableItemId);
|
|
95
81
|
}
|
|
96
82
|
});
|
|
97
83
|
const createRootHandleFocus = otherHandlers => event => {
|
|
@@ -102,7 +88,7 @@ export const useTreeViewFocus = ({
|
|
|
102
88
|
|
|
103
89
|
// if the event bubbled (which is React specific) we don't want to steal focus
|
|
104
90
|
if (event.target === event.currentTarget) {
|
|
105
|
-
|
|
91
|
+
innerFocusItem(event, defaultFocusableItemId);
|
|
106
92
|
}
|
|
107
93
|
};
|
|
108
94
|
return {
|
|
@@ -116,7 +102,6 @@ export const useTreeViewFocus = ({
|
|
|
116
102
|
isItemFocused,
|
|
117
103
|
canItemBeTabbed,
|
|
118
104
|
focusItem,
|
|
119
|
-
focusDefaultItem,
|
|
120
105
|
removeFocusedItem
|
|
121
106
|
}
|
|
122
107
|
};
|
|
@@ -2,6 +2,8 @@ import _extends from "@babel/runtime/helpers/esm/extends";
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { publishTreeViewEvent } from '../../utils/publishTreeViewEvent';
|
|
4
4
|
import { buildSiblingIndexes, TREE_VIEW_ROOT_PARENT_ID } from './useTreeViewItems.utils';
|
|
5
|
+
import { TreeViewItemDepthContext } from '../../TreeViewItemDepthContext';
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
7
|
const updateItemsState = ({
|
|
6
8
|
items,
|
|
7
9
|
isItemDisabled,
|
|
@@ -13,7 +15,7 @@ const updateItemsState = ({
|
|
|
13
15
|
const itemOrderedChildrenIds = {
|
|
14
16
|
[TREE_VIEW_ROOT_PARENT_ID]: []
|
|
15
17
|
};
|
|
16
|
-
const processItem = (item, parentId) => {
|
|
18
|
+
const processItem = (item, depth, parentId) => {
|
|
17
19
|
const id = getItemId ? getItemId(item) : item.id;
|
|
18
20
|
if (id == null) {
|
|
19
21
|
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.', 'An item was provided without id in the `items` prop:', JSON.stringify(item)].join('\n'));
|
|
@@ -31,7 +33,8 @@ const updateItemsState = ({
|
|
|
31
33
|
parentId,
|
|
32
34
|
idAttribute: undefined,
|
|
33
35
|
expandable: !!item.children?.length,
|
|
34
|
-
disabled: isItemDisabled ? isItemDisabled(item) : false
|
|
36
|
+
disabled: isItemDisabled ? isItemDisabled(item) : false,
|
|
37
|
+
depth
|
|
35
38
|
};
|
|
36
39
|
itemMap[id] = item;
|
|
37
40
|
itemOrderedChildrenIds[id] = [];
|
|
@@ -40,9 +43,9 @@ const updateItemsState = ({
|
|
|
40
43
|
itemOrderedChildrenIds[parentIdWithDefault] = [];
|
|
41
44
|
}
|
|
42
45
|
itemOrderedChildrenIds[parentIdWithDefault].push(id);
|
|
43
|
-
item.children?.forEach(child => processItem(child, id));
|
|
46
|
+
item.children?.forEach(child => processItem(child, depth + 1, id));
|
|
44
47
|
};
|
|
45
|
-
items.forEach(item => processItem(item, null));
|
|
48
|
+
items.forEach(item => processItem(item, 0, null));
|
|
46
49
|
const itemChildrenIndexes = {};
|
|
47
50
|
Object.keys(itemOrderedChildrenIds).forEach(parentId => {
|
|
48
51
|
itemChildrenIndexes[parentId] = buildSiblingIndexes(itemOrderedChildrenIds[parentId]);
|
|
@@ -58,7 +61,8 @@ export const useTreeViewItems = ({
|
|
|
58
61
|
instance,
|
|
59
62
|
params,
|
|
60
63
|
state,
|
|
61
|
-
setState
|
|
64
|
+
setState,
|
|
65
|
+
experimentalFeatures
|
|
62
66
|
}) => {
|
|
63
67
|
const getItemMeta = React.useCallback(itemId => state.items.itemMetaMap[itemId], [state.items.itemMetaMap]);
|
|
64
68
|
const getItem = React.useCallback(itemId => state.items.itemMap[itemId], [state.items.itemMap]);
|
|
@@ -135,6 +139,11 @@ export const useTreeViewItems = ({
|
|
|
135
139
|
return state.items.itemOrderedChildrenIds[TREE_VIEW_ROOT_PARENT_ID].map(getPropsFromItemId);
|
|
136
140
|
};
|
|
137
141
|
return {
|
|
142
|
+
getRootProps: () => ({
|
|
143
|
+
style: {
|
|
144
|
+
'--TreeView-itemChildrenIndentation': typeof params.itemChildrenIndentation === 'number' ? `${params.itemChildrenIndentation}px` : params.itemChildrenIndentation
|
|
145
|
+
}
|
|
146
|
+
}),
|
|
138
147
|
publicAPI: {
|
|
139
148
|
getItem
|
|
140
149
|
},
|
|
@@ -150,7 +159,8 @@ export const useTreeViewItems = ({
|
|
|
150
159
|
areItemUpdatesPrevented
|
|
151
160
|
},
|
|
152
161
|
contextValue: {
|
|
153
|
-
disabledItemsFocusable: params.disabledItemsFocusable
|
|
162
|
+
disabledItemsFocusable: params.disabledItemsFocusable,
|
|
163
|
+
indentationAtItemLevel: experimentalFeatures.indentationAtItemLevel ?? false
|
|
154
164
|
}
|
|
155
165
|
};
|
|
156
166
|
};
|
|
@@ -163,12 +173,23 @@ useTreeViewItems.getInitialState = params => ({
|
|
|
163
173
|
})
|
|
164
174
|
});
|
|
165
175
|
useTreeViewItems.getDefaultizedParams = params => _extends({}, params, {
|
|
166
|
-
disabledItemsFocusable: params.disabledItemsFocusable ?? false
|
|
176
|
+
disabledItemsFocusable: params.disabledItemsFocusable ?? false,
|
|
177
|
+
itemChildrenIndentation: params.itemChildrenIndentation ?? '12px'
|
|
167
178
|
});
|
|
179
|
+
useTreeViewItems.wrapRoot = ({
|
|
180
|
+
children,
|
|
181
|
+
instance
|
|
182
|
+
}) => {
|
|
183
|
+
return /*#__PURE__*/_jsx(TreeViewItemDepthContext.Provider, {
|
|
184
|
+
value: itemId => instance.getItemMeta(itemId)?.depth ?? 0,
|
|
185
|
+
children: children
|
|
186
|
+
});
|
|
187
|
+
};
|
|
168
188
|
useTreeViewItems.params = {
|
|
169
189
|
disabledItemsFocusable: true,
|
|
170
190
|
items: true,
|
|
171
191
|
isItemDisabled: true,
|
|
172
192
|
getItemLabel: true,
|
|
173
|
-
getItemId: true
|
|
193
|
+
getItemId: true,
|
|
194
|
+
itemChildrenIndentation: true
|
|
174
195
|
};
|