Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TreeView] Always apply the indentation on the item content instead of its parent's group #15089

Merged
merged 16 commits into from
Nov 7, 2024
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import * as React from 'react';
import { alpha, styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import {
TreeItem,
TreeItemContent,
TreeItemGroupTransition,
} from '@mui/x-tree-view/TreeItem';

const MUI_X_PRODUCTS = [
{
id: 'grid',
label: 'Data Grid',
children: [
{ id: 'grid-community', label: '@mui/x-data-grid' },
{ id: 'grid-pro', label: '@mui/x-data-grid-pro' },
{ id: 'grid-premium', label: '@mui/x-data-grid-premium' },
],
},
{
id: 'pickers',
label: 'Date and Time Pickers',
children: [
{ id: 'pickers-community', label: '@mui/x-date-pickers' },
{ id: 'pickers-pro', label: '@mui/x-date-pickers-pro' },
],
},
{
id: 'charts',
label: 'Charts',
children: [{ id: 'charts-community', label: '@mui/x-charts' }],
},
{
id: 'tree-view',
label: 'Tree View',
children: [{ id: 'tree-view-community', label: '@mui/x-tree-view' }],
},
];

const CustomTreeItemContent = styled(TreeItemContent)(({ theme }) => ({
// Remove the additional padding of nested elements
padding: theme.spacing(0.5, 1),
borderRadius: theme.shape.borderRadius,
width: '100%',
border: '1px solid',
display: 'flex',
'&:hover': {
backgroundColor: alpha((theme.vars || theme).palette.primary.main, 0.2),
},
variants: [
{
props: ({ status }) => status.disabled,
style: {
opacity: 0.5,
backgroundColor: theme.palette.action.disabledBackground,
},
},
{
props: ({ status }) => status.selected,
style: {
backgroundColor: alpha((theme.vars || theme).palette.primary.main, 0.4),
},
},
],
}));

const CustomTreeItemGroupTransition = styled(TreeItemGroupTransition)({
// Add the padding back on the group transition element
paddingLeft: 'var(--TreeView-itemChildrenIndentation) !important',
});

const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
return (
<TreeItem
{...props}
ref={ref}
slots={{
content: CustomTreeItemContent,
groupTransition: CustomTreeItemGroupTransition,
}}
/>
);
});

export default function ItemIndentationWithBorder() {
return (
<Stack sx={{ minHeight: 200, minWidth: 350 }} spacing={2}>
<RichTreeView
defaultExpandedItems={['pickers']}
items={MUI_X_PRODUCTS}
slots={{
item: CustomTreeItem,
}}
/>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import * as React from 'react';
import { alpha, styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import {
TreeItem,
TreeItemContent,
TreeItemGroupTransition,
TreeItemProps,
} from '@mui/x-tree-view/TreeItem';
import { UseTreeItemContentSlotOwnProps } from '@mui/x-tree-view/useTreeItem';

const MUI_X_PRODUCTS = [
{
id: 'grid',
label: 'Data Grid',
children: [
{ id: 'grid-community', label: '@mui/x-data-grid' },
{ id: 'grid-pro', label: '@mui/x-data-grid-pro' },
{ id: 'grid-premium', label: '@mui/x-data-grid-premium' },
],
},
{
id: 'pickers',
label: 'Date and Time Pickers',
children: [
{ id: 'pickers-community', label: '@mui/x-date-pickers' },
{ id: 'pickers-pro', label: '@mui/x-date-pickers-pro' },
],
},
{
id: 'charts',
label: 'Charts',
children: [{ id: 'charts-community', label: '@mui/x-charts' }],
},
{
id: 'tree-view',
label: 'Tree View',
children: [{ id: 'tree-view-community', label: '@mui/x-tree-view' }],
},
];

const CustomTreeItemContent = styled(TreeItemContent)(({ theme }) => ({
// Remove the additional padding of nested elements
padding: theme.spacing(0.5, 1),
borderRadius: theme.shape.borderRadius,
width: '100%',
border: '1px solid',
display: 'flex',
'&:hover': {
backgroundColor: alpha((theme.vars || theme).palette.primary.main, 0.2),
},
variants: [
{
props: ({ status }: UseTreeItemContentSlotOwnProps) => status.disabled,
style: {
opacity: 0.5,
backgroundColor: theme.palette.action.disabledBackground,
},
},
{
props: ({ status }: UseTreeItemContentSlotOwnProps) => status.selected,
style: {
backgroundColor: alpha((theme.vars || theme).palette.primary.main, 0.4),
},
},
],
}));

const CustomTreeItemGroupTransition = styled(TreeItemGroupTransition)({
// Add the padding back on the group transition element
paddingLeft: 'var(--TreeView-itemChildrenIndentation) !important',
});

const CustomTreeItem = React.forwardRef(function CustomTreeItem(
props: TreeItemProps,
ref: React.Ref<HTMLLIElement>,
) {
return (
<TreeItem
{...props}
ref={ref}
slots={{
content: CustomTreeItemContent,
groupTransition: CustomTreeItemGroupTransition,
}}
/>
);
});

export default function ItemIndentationWithBorder() {
return (
<Stack sx={{ minHeight: 200, minWidth: 350 }} spacing={2}>
<RichTreeView
defaultExpandedItems={['pickers']}
items={MUI_X_PRODUCTS}
slots={{
item: CustomTreeItem,
}}
/>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<RichTreeView
defaultExpandedItems={['pickers']}
items={MUI_X_PRODUCTS}
slots={{
item: CustomTreeItem,
}}
/>
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,30 @@ All the new Tree Item-related components and utils (introduced in the previous m
- } from '@mui/x-tree-view/TreeItem2LabelInput';
+ } from '@mui/x-tree-view/TreeItemLabelInput';
```

## Apply the indentation on the item content instead of it's parent's group

The indentation of nested Tree Items is now applied on the content of the element.
This is required to support features like the drag and drop re-ordering which requires every Tree Item to go to the far left of the Tree View.

### Apply custom indentation

If you used to set custom indentation in your Tree Item, you can use the new `itemChildrenIndentation` prop to do it while supporting the new DOM structure:

```tsx
<RichTreeView
items={MUI_X_PRODUCTS}
itemChildrenIndentation={24}
defaultExpandedItems={['grid']}
/>
```

:::info
See [Tree Item Customization—Change nested item's indentation](/x/react-tree-view/tree-item-customization/#change-nested-items-indentation) for more details.
:::

### Fallback to the old behavior

If you used to style your content element (for example to add a border to it) and you don't use the drag and drop re-ordering, you can manually put the padding on the group transition element to restore the previous behavior:

{{"demo": "ItemIndentationWithBorder.js"}}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Avatar from '@mui/material/Avatar';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
Expand Down Expand Up @@ -37,10 +36,6 @@ const ITEMS = [
},
];

const CustomTreeItemContent = styled(TreeItemContent)(({ theme }) => ({
padding: theme.spacing(0.5, 1),
}));

const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
const { id, itemId, label, disabled, children, ...other } = props;

Expand All @@ -58,7 +53,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
return (
<TreeItemProvider itemId={itemId}>
<TreeItemRoot {...getRootProps(other)}>
<CustomTreeItemContent {...getContentProps()}>
<TreeItemContent {...getContentProps()}>
<TreeItemIconContainer {...getIconContainerProps()}>
<TreeItemIcon status={status} />
</TreeItemIconContainer>
Expand All @@ -77,7 +72,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
<TreeItemLabel {...getLabelProps()} />
</Box>
<TreeItemDragAndDropOverlay {...getDragAndDropOverlayProps()} />
</CustomTreeItemContent>
</TreeItemContent>
{children && <TreeItemGroupTransition {...getGroupTransitionProps()} />}
</TreeItemRoot>
</TreeItemProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Avatar from '@mui/material/Avatar';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
Expand Down Expand Up @@ -37,10 +36,6 @@ const ITEMS: TreeViewBaseItem[] = [
},
];

const CustomTreeItemContent = styled(TreeItemContent)(({ theme }) => ({
padding: theme.spacing(0.5, 1),
}));

interface CustomTreeItemProps
extends Omit<UseTreeItemParameters, 'rootRef'>,
Omit<React.HTMLAttributes<HTMLLIElement>, 'onFocus'> {}
Expand All @@ -65,7 +60,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(
return (
<TreeItemProvider itemId={itemId}>
<TreeItemRoot {...getRootProps(other)}>
<CustomTreeItemContent {...getContentProps()}>
<TreeItemContent {...getContentProps()}>
<TreeItemIconContainer {...getIconContainerProps()}>
<TreeItemIcon status={status} />
</TreeItemIconContainer>
Expand All @@ -84,7 +79,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(
<TreeItemLabel {...getLabelProps()} />
</Box>
<TreeItemDragAndDropOverlay {...getDragAndDropOverlayProps()} />
</CustomTreeItemContent>
</TreeItemContent>
{children && <TreeItemGroupTransition {...getGroupTransitionProps()} />}
</TreeItemRoot>
</TreeItemProvider>
Expand Down
1 change: 0 additions & 1 deletion docs/data/tree-view/rich-tree-view/ordering/DragAndDrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export default function DragAndDrop() {
itemsReordering
defaultExpandedItems={['grid', 'pickers']}
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export default function DragAndDrop() {
itemsReordering
defaultExpandedItems={['grid', 'pickers']}
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
itemsReordering
defaultExpandedItems={['grid', 'pickers']}
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
/>
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ export default function FileExplorer() {
defaultExpandedItems={['1', '1.1']}
sx={{ height: 'fit-content', flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
slots={{ item: CustomTreeItem }}
experimentalFeatures={{ indentationAtItemLevel: true, itemsReordering: true }}
experimentalFeatures={{ itemsReordering: true }}
itemsReordering
canMoveItemToNewPosition={(params) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export default function FileExplorer() {
defaultExpandedItems={['1', '1.1']}
sx={{ height: 'fit-content', flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
slots={{ item: CustomTreeItem }}
experimentalFeatures={{ indentationAtItemLevel: true, itemsReordering: true }}
experimentalFeatures={{ itemsReordering: true }}
itemsReordering
canMoveItemToNewPosition={(params) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export default function OnItemPositionChange() {
items={MUI_X_PRODUCTS}
itemsReordering
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
defaultExpandedItems={['grid', 'pickers']}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ export default function OnItemPositionChange() {
items={MUI_X_PRODUCTS}
itemsReordering
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
defaultExpandedItems={['grid', 'pickers']}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ export default function OnlyReorderFromDragHandle() {
items={MUI_X_PRODUCTS}
defaultExpandedItems={['grid', 'pickers']}
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
itemsReordering
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ export default function OnlyReorderFromDragHandle() {
items={MUI_X_PRODUCTS}
defaultExpandedItems={['grid', 'pickers']}
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
itemsReordering
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
items={MUI_X_PRODUCTS}
defaultExpandedItems={['grid', 'pickers']}
experimentalFeatures={{
indentationAtItemLevel: true,
itemsReordering: true,
}}
itemsReordering
Expand Down
Loading