Files
react-test/docs/data/joy/components/menu/MenuIconSideNavExample.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

200 lines
5.3 KiB
JavaScript

import * as React from 'react';
import PropTypes from 'prop-types';
import Menu, { menuClasses } from '@mui/joy/Menu';
import MenuItem from '@mui/joy/MenuItem';
import IconButton from '@mui/joy/IconButton';
import List from '@mui/joy/List';
import ListItem from '@mui/joy/ListItem';
import Sheet from '@mui/joy/Sheet';
import Apps from '@mui/icons-material/Apps';
import Settings from '@mui/icons-material/Settings';
import Person from '@mui/icons-material/Person';
import Dropdown from '@mui/joy/Dropdown';
import MenuButton from '@mui/joy/MenuButton';
// The Menu is built on top of Popper v2, so it accepts `modifiers` prop that will be passed to the Popper.
// https://popper.js.org/docs/v2/modifiers/offset/
const modifiers = [
{
name: 'offset',
options: {
offset: ({ placement }) => {
if (placement.includes('end')) {
return [8, 20];
}
return [-8, 20];
},
},
},
];
function NavMenuButton({
children,
menu,
open,
onOpen,
onLeaveMenu,
label,
...props
}) {
const isOnButton = React.useRef(false);
const internalOpen = React.useRef(open);
const handleButtonKeyDown = (event) => {
internalOpen.current = open;
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
event.preventDefault();
onOpen(event);
}
};
return (
<Dropdown
open={open}
onOpenChange={(_, isOpen) => {
if (isOpen) {
onOpen?.();
}
}}
>
<MenuButton
{...props}
slots={{ root: IconButton }}
slotProps={{ root: { variant: 'plain', color: 'neutral' } }}
onMouseDown={() => {
internalOpen.current = open;
}}
onClick={() => {
if (!internalOpen.current) {
onOpen();
}
}}
onMouseEnter={() => {
onOpen();
isOnButton.current = true;
}}
onMouseLeave={() => {
isOnButton.current = false;
}}
onKeyDown={handleButtonKeyDown}
sx={[
{
'&:focus-visible': {
bgcolor: 'neutral.plainHoverBg',
},
},
open ? { bgcolor: 'neutral.plainHoverBg' } : { bgcolor: null },
]}
>
{children}
</MenuButton>
{React.cloneElement(menu, {
onMouseLeave: () => {
onLeaveMenu(() => isOnButton.current);
},
modifiers,
slotProps: {
listbox: {
id: `nav-example-menu-${label}`,
'aria-label': label,
},
},
placement: 'right-start',
sx: {
width: 288,
[`& .${menuClasses.listbox}`]: {
'--List-padding': 'var(--ListDivider-gap)',
},
},
})}
</Dropdown>
);
}
NavMenuButton.propTypes = {
children: PropTypes.node,
label: PropTypes.string.isRequired,
menu: PropTypes.element.isRequired,
onLeaveMenu: PropTypes.func.isRequired,
onOpen: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired,
};
export default function MenuIconSideNavExample() {
const [menuIndex, setMenuIndex] = React.useState(null);
const itemProps = {
onClick: () => setMenuIndex(null),
};
const createHandleLeaveMenu = (index) => (getIsOnButton) => {
setTimeout(() => {
const isOnButton = getIsOnButton();
if (!isOnButton) {
setMenuIndex((latestIndex) => {
if (index === latestIndex) {
return null;
}
return latestIndex;
});
}
}, 200);
};
return (
<Sheet sx={{ borderRadius: 'sm', py: 1, mr: 20 }}>
<List>
<ListItem>
<NavMenuButton
label="Apps"
open={menuIndex === 0}
onOpen={() => setMenuIndex(0)}
onLeaveMenu={createHandleLeaveMenu(0)}
menu={
<Menu onClose={() => setMenuIndex(null)}>
<MenuItem {...itemProps}>Application 1</MenuItem>
<MenuItem {...itemProps}>Application 2</MenuItem>
<MenuItem {...itemProps}>Application 3</MenuItem>
</Menu>
}
>
<Apps />
</NavMenuButton>
</ListItem>
<ListItem>
<NavMenuButton
label="Settings"
open={menuIndex === 1}
onOpen={() => setMenuIndex(1)}
onLeaveMenu={createHandleLeaveMenu(1)}
menu={
<Menu onClose={() => setMenuIndex(null)}>
<MenuItem {...itemProps}>Setting 1</MenuItem>
<MenuItem {...itemProps}>Setting 2</MenuItem>
<MenuItem {...itemProps}>Setting 3</MenuItem>
</Menu>
}
>
<Settings />
</NavMenuButton>
</ListItem>
<ListItem>
<NavMenuButton
label="Personal"
open={menuIndex === 2}
onOpen={() => setMenuIndex(2)}
onLeaveMenu={createHandleLeaveMenu(2)}
menu={
<Menu onClose={() => setMenuIndex(null)}>
<MenuItem {...itemProps}>Personal 1</MenuItem>
<MenuItem {...itemProps}>Personal 2</MenuItem>
<MenuItem {...itemProps}>Personal 3</MenuItem>
</Menu>
}
>
<Person />
</NavMenuButton>
</ListItem>
</List>
</Sheet>
);
}