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 ( { if (isOpen) { onOpen?.(); } }} > { 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} {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)', }, }, })} ); } 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 ( setMenuIndex(0)} onLeaveMenu={createHandleLeaveMenu(0)} menu={ setMenuIndex(null)}> Application 1 Application 2 Application 3 } > setMenuIndex(1)} onLeaveMenu={createHandleLeaveMenu(1)} menu={ setMenuIndex(null)}> Setting 1 Setting 2 Setting 3 } > setMenuIndex(2)} onLeaveMenu={createHandleLeaveMenu(2)} menu={ setMenuIndex(null)}> Personal 1 Personal 2 Personal 3 } > ); }