Files
react-test/docs/data/material/getting-started/templates/dashboard/components/CustomizedTreeView.js
how2ice 005cf56baf
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
init project
2025-12-12 14:26:25 +09:00

228 lines
5.9 KiB
JavaScript

import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { animated, useSpring } from '@react-spring/web';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Collapse from '@mui/material/Collapse';
import Typography from '@mui/material/Typography';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import { useTreeItem } from '@mui/x-tree-view/useTreeItem';
import {
TreeItemContent,
TreeItemIconContainer,
TreeItemLabel,
TreeItemRoot,
} from '@mui/x-tree-view/TreeItem';
import { TreeItemIcon } from '@mui/x-tree-view/TreeItemIcon';
import { TreeItemProvider } from '@mui/x-tree-view/TreeItemProvider';
import { useTheme } from '@mui/material/styles';
const ITEMS = [
{
id: '1',
label: 'Website',
children: [
{ id: '1.1', label: 'Home', color: 'green' },
{ id: '1.2', label: 'Pricing', color: 'green' },
{ id: '1.3', label: 'About us', color: 'green' },
{
id: '1.4',
label: 'Blog',
children: [
{ id: '1.1.1', label: 'Announcements', color: 'blue' },
{ id: '1.1.2', label: 'April lookahead', color: 'blue' },
{ id: '1.1.3', label: "What's new", color: 'blue' },
{ id: '1.1.4', label: 'Meet the team', color: 'blue' },
],
},
],
},
{
id: '2',
label: 'Store',
children: [
{ id: '2.1', label: 'All products', color: 'green' },
{
id: '2.2',
label: 'Categories',
children: [
{ id: '2.2.1', label: 'Gadgets', color: 'blue' },
{ id: '2.2.2', label: 'Phones', color: 'blue' },
{ id: '2.2.3', label: 'Wearables', color: 'blue' },
],
},
{ id: '2.3', label: 'Bestsellers', color: 'green' },
{ id: '2.4', label: 'Sales', color: 'green' },
],
},
{ id: '4', label: 'Contact', color: 'blue' },
{ id: '5', label: 'Help', color: 'blue' },
];
function DotIcon({ color }) {
return (
<Box sx={{ marginRight: 1, display: 'flex', alignItems: 'center' }}>
<svg width={6} height={6}>
<circle cx={3} cy={3} r={3} fill={color} />
</svg>
</Box>
);
}
DotIcon.propTypes = {
color: PropTypes.string.isRequired,
};
const AnimatedCollapse = animated(Collapse);
function TransitionComponent(props) {
const style = useSpring({
to: {
opacity: props.in ? 1 : 0,
transform: `translate3d(0,${props.in ? 0 : 20}px,0)`,
},
});
return <AnimatedCollapse style={style} {...props} />;
}
TransitionComponent.propTypes = {
/**
* Show the component; triggers the enter or exit states
*/
in: PropTypes.bool,
};
function CustomLabel({ color, expandable, children, ...other }) {
const theme = useTheme();
const colors = {
blue: (theme.vars || theme).palette.primary.main,
green: (theme.vars || theme).palette.success.main,
};
const iconColor = color ? colors[color] : null;
return (
<TreeItemLabel {...other} sx={{ display: 'flex', alignItems: 'center' }}>
{iconColor && <DotIcon color={iconColor} />}
<Typography
className="labelText"
variant="body2"
sx={{ color: 'text.primary' }}
>
{children}
</Typography>
</TreeItemLabel>
);
}
CustomLabel.propTypes = {
children: PropTypes.node,
color: PropTypes.oneOf(['blue', 'green']),
expandable: PropTypes.bool,
};
const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) {
const { id, itemId, label, disabled, children, ...other } = props;
const {
getRootProps,
getContentProps,
getIconContainerProps,
getLabelProps,
getGroupTransitionProps,
status,
publicAPI,
} = useTreeItem({ id, itemId, children, label, disabled, rootRef: ref });
const item = publicAPI.getItem(itemId);
const color = item?.color;
return (
<TreeItemProvider id={id} itemId={itemId}>
<TreeItemRoot {...getRootProps(other)}>
<TreeItemContent
{...getContentProps({
className: clsx('content', {
expanded: status.expanded,
selected: status.selected,
focused: status.focused,
disabled: status.disabled,
}),
})}
>
{status.expandable && (
<TreeItemIconContainer {...getIconContainerProps()}>
<TreeItemIcon status={status} />
</TreeItemIconContainer>
)}
<CustomLabel {...getLabelProps({ color })} />
</TreeItemContent>
{children && (
<TransitionComponent
{...getGroupTransitionProps({ className: 'groupTransition' })}
/>
)}
</TreeItemRoot>
</TreeItemProvider>
);
});
CustomTreeItem.propTypes = {
/**
* The content of the component.
*/
children: PropTypes.node,
/**
* If `true`, the item is disabled.
* @default false
*/
disabled: PropTypes.bool,
/**
* The id attribute of the item. If not provided, it will be generated.
*/
id: PropTypes.string,
/**
* The id of the item.
* Must be unique.
*/
itemId: PropTypes.string.isRequired,
/**
* The label of the item.
*/
label: PropTypes.node,
};
export default function CustomizedTreeView() {
return (
<Card
variant="outlined"
sx={{ display: 'flex', flexDirection: 'column', gap: '8px', flexGrow: 1 }}
>
<CardContent>
<Typography component="h2" variant="subtitle2">
Product tree
</Typography>
<RichTreeView
items={ITEMS}
aria-label="pages"
multiSelect
defaultExpandedItems={['1', '1.1']}
defaultSelectedItems={['1.1', '1.1.1']}
sx={{
m: '0 -8px',
pb: '8px',
height: 'fit-content',
flexGrow: 1,
overflowY: 'auto',
}}
slots={{ item: CustomTreeItem }}
/>
</CardContent>
</Card>
);
}