MUI anchorEl prop provided is invalid - reactjs

I am trying to code a mobile menu, where when the user clicks on the menu icon, the menu is displayed.
I have the following code:
const StyledMenu = withStyles({
paper: {
border: '1px solid #d3d4d5',
},
})((props, ref) => (
<Menu
elevation={0}
getContentAnchorEl={null}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
{...props}
/>
))`
and the component:
export default function Header(props) {
const [state, setState] = useState({ mobileView: true, drawerOpen: false, anchorEl: null, openItem: null })
const { mobileView, drawerOpen, anchorEl } = state
const classes = useStyles()
useEffect(() => {
const setResponsiveness = () => {
return window.innerWidth < 900
? setState((prevState) => ({ ...prevState, mobileView: true }))
: setState((prevState) => ({ ...prevState, mobileView: false }));
};
setResponsiveness();
window.addEventListener("resize", () => setResponsiveness());
return () => {
window.removeEventListener("resize", () => setResponsiveness());
}
}, []);
const MobileMenu = (props) => {
const handleClick = (id) => {
if (state.openItem === id) {
setState((prevState) => ({ ...prevState, openItem: null }))
} else {
setState((prevState) => ({ ...prevState, openItem: id }))
}
}
const handleDrawerOpen = (event) =>
setState((prevState) => ({ ...prevState, drawerOpen: true, anchorEl: event.currentTarget }));
const handleDrawerClose = () =>
setState((prevState) => ({ ...prevState, drawerOpen: false }));
return (
<Toolbar>
<IconButton
{...{
edge: "start",
color: "inherit",
"aria-label": "menu",
"aria-haspopup": "true",
variant: "contained",
onClick: handleDrawerOpen,
}}
>
<MenuIcon className={classes.menuIcon} fontSize='40px' />
</IconButton>
<StyledMenu
{...{
id: 'custom-menu',
anchor: "left",
open: drawerOpen,
onClose: handleDrawerClose,
anchorEl: anchorEl
}}
>
<List component='nav' className={classes.appMenu} disablePadding>
{menuItems.map((item, index) => {
const hasSubMenus = item.hasOwnProperty('subMenus')
const ListItemLink = () => {
return (
<ListItem key={index} button component={Link} to={item.link} className={classes.menuItem}>
<ListItemText>{item.label}</ListItemText>
</ListItem>
)
}
const ListItemToggle = () => (
<ListItem key={index} button onClick={() => handleClick(index)} className={classes.menuItem}>
<ListItemText>{item.label}</ListItemText>
{index === state.openItem ? <IconExpandLess /> : <IconExpandMore />}
</ListItem>
)
return (
<React.Fragment key={index}>
{!hasSubMenus ? <ListItemLink /> :
<>
<ListItemToggle />
<Collapse in={index === state.openItem} timeout='auto' className={classes.collapseWrapper}>
<div className={classes.collapseDiv}>
<Divider />
<List component='div' disablePadding>
{item.subMenus.map((el, key) => (
<ListItem key={key} button component={Link} to={el.link} className={classes.menuItem}>
<ListItemText inset>{el.label}</ListItemText>
</ListItem>
))}
</List>
</div>
</Collapse>
</>
}
</React.Fragment>
)
})}
</List>
</StyledMenu>
<Logo />
</Toolbar>
)
}
When the clicking on the button, I get the following error:
React does not recognize the getContentAnchorEl prop on a DOM element.
MUI: The anchorEl prop provided to the component is invalid.
The anchor element should be part of the document layout.
Make sure the element is present in the document or that it's not display none.

I solved the problem by moving the anchorEl state from parent (Header) component state to local (MobileMenu) component.

I had the same error message and took the hint, "Make sure the element is present in the document or that it's not display none."
First I was looking on SO when I found this question. I've a similar, but different use case with the #mui/system to show/hide different navigation using <Box sx={{. I'm sharing the way I got rid of the same error you report. I was using display: none, so that in changing from lg to md the anchorEl was nested within a parent element that was indeed set to display none (like the error message suggests).
To get rid of display: none I used visibility along with width to collapse like so:
return (
<List id="id-nav" component="nav" className={classes.root}>
<Box sx={{
display: {
lg: 'inherit'
},
visibility: {
sm: 'hidden',
md: 'hidden',
lg: 'visible'
},
width: {
sm: 0,
md: 0,
lg: 'auto'
},
}}
>
{largeNav}
</Box>
<Box sx={{
display: {
sm: 'inherit',
md: 'inherit'
},
visibility: {
sm: 'visible',
md: 'visible',
lg: 'hidden'
},
width: {
sm: 'auto',
md: 'auto',
lg: 0
}
}}
>
{mediumNav}
</Box>
</List>
);

For future people, if you're wrapping your AppBar in a HideOnScroll/Slide component, that can be the source of the issue (and it was for me). Getting rid of that makes the anchorEl work as expected.
See related question/solution here: Material Ui popover is not on right position

Related

Styling selected LIstItemButton MUI not working

According to the documentation, I can override the style of the selected class by passing a new class under .MuiSelected. something like below:
const useStyles = makeStyles(() => ({
selectedLink: {
"&.Mui-selected": {
backgroundColor: "red",
},
},
}));
Then, I use it:
const MainDrawerMenu: React.FC = () => {
const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
const [selectedIndex, setSelectedIndex] = React.useState(0);
const classes = useStyles();
// Responsive swipe on mobile
const iOS =
typeof navigator !== "undefined" &&
/iPad|iPhone|iPod/.test(navigator.userAgent);
const handleSelected = (
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
selectedIndex: number
) => {
setSelectedIndex(selectedIndex);
};
return (
<React.Fragment>
<SwipeableDrawer
classes={{ paper: classes.drawerMenuHolder }}
disableBackdropTransition={!iOS}
disableDiscovery={iOS}
open={isDrawerOpen}
onClose={() => {
setIsDrawerOpen(false);
}}
onOpen={() => {
setIsDrawerOpen(true);
}}>
<List disablePadding>
<ListItemButton
component={Link}
classes={{ selected: classes.selectedLink }}
to='/'
onClick={(event) => {
setIsDrawerOpen(false);
handleSelected(event, 0);
}}
selected={selectedIndex === 0}>
<ListItemText disableTypography className={classes.drawerItem}>
Home
</ListItemText>
</ListItemButton>
</List>
</SwipeableDrawer>
<IconButton
className={classes.iconMenuBtn}
onClick={() => {
setIsDrawerOpen(!isDrawerOpen);
}}>
<MenuIcon fontSize='large' className={classes.menuIcon} />
</IconButton>
</React.Fragment>
);
};
Yet, it doesn't work. I can see it in the dev tools, but for some reason it gets overridden by another class. See screenshot. I have tried also creating a new class with the css naming convention but no luck...
Solution below:
<ListItemButton sx={{
'&.Mui-selected': {
backgroundColor: 'rgba(220, 0, 50, 0.1)'
}
}} selected={0}>
<ListItemText primary={'label in item selected'} />
</ListItemButton>

Mui dropdown menu is not close in onMouseLeave

I have a menu. in some MenuItems must appear submenu while hovering.
onMouseOver is working correctly but when i leave mouse from menuitem it is not closing
here is my functions
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
if (anchorEl !== event.currentTarget) {
setAnchorEl(event.currentTarget);
}
};
const handleClose = () => {
setAnchorEl(null);
};
const navConf = NavigateConfig();
here is my Jsx
<MenuList sx={{
display: { xs: 'none', lg: 'block' }, display: 'flex'
}}>
{navConf.map((item) => (
<>
<MenuItem
// id="simple-menu"
onMouseOver={item.child ? (e) => handleClick(e) : () => { }}
aria-owns={anchorEl ? "simple-menu" : undefined}
aria-haspopup="true"
>
{item.title}
{anchorEl &&
<Menu
id="simple-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{ onMouseLeave: handleClose, 'aria-labelledby': 'simple-menu', }}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
>
<div className='topDiv'></div>
{item.child?.map((e) => {
return <MenuItem>{e.title}</MenuItem>
})}
</Menu>}
</MenuItem>
</>
))}
<LanguagePopover />
</MenuList>
submenu is disappearing when i click outside of it
Do you just need to add an onMouseLeave?
<MenuItem
onMouseOver={item.child ? (e) => handleClick(e) : () => { }}
onMouseLeave={item.child ? (e) => handleClose() : () => { }}
onMouseOver runs every time your mouse moves and is overlapping the element, but it wont automatically undo what it does when the mouse leaves again.

ClickAwayListener component not working with DragDropContext

I made a dropdown using Button and a Popper using Material UI components where you can click on the button and get a list of subjects to choose from. To make the popper disappear either we can click on the button again or use a <ClickAwayListener> component which listens to click event and closes the Popper. Now I've to make the list capable of drag and drop feature so I use the react-beautiful-dnd npm package.But the <ClickAwayListener> doesn't seem to work when I include <DragDropContext>, <Droppable> and <Draggable> components.Can anyone help me figure it out?
Here's the code without drag and drop feature. CodeSandbox link https://codesandbox.io/s/gallant-newton-mfmhd?file=/demo.js
const subjectsFromBackend = [
{ name: "Physics", selected: false },
{ name: "Chemistry", selected: false },
{ name: "Biology", selected: false },
{ name: "Mathematics", selected: false },
{ name: "Computer Science", selected: false },
];
const useStyles = makeStyles((theme) => ({
root: {
display: "flex"
},
paper: {
marginRight: theme.spacing(2)
}
}));
export default function MenuListComposition() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const [subjects, setSubjects] = React.useState(subjectsFromBackend);
const handleToggle = () => {
setOpen(!open);
};
const handleClose = () => {
setOpen(false);
};
const ColumnItem = ({ subjectName, selected }) => {
return (
<>
<Grid container>
<Grid item>
<Checkbox checked={selected} />
</Grid>
<Grid item>{subjectName}</Grid>
</Grid>
</>
);
};
return (
<div className={classes.root}>
<div>
<Button
ref={anchorRef}
onClick={handleToggle}
style={{ width: 385, justifyContent: "left", textTransform: "none" }}
>
{`Subjects Selected`}
</Button>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<Paper style={{ maxHeight: 200, overflow: "auto", width: 385 }}>
<ClickAwayListener onClickAway={handleClose}>
<List>
{subjects.map((col, index) => (
<ListItem>
<ColumnItem
subjectName={col.name}
selected={col.selected}
/>
</ListItem>
))}
</List>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div>
);
}
Here's the same code using drag and drop. CodeSandbox Link https://codesandbox.io/s/material-demo-forked-ertti
const subjectsFromBackend = [
{ name: "Physics", selected: false },
{ name: "Chemistry", selected: false },
{ name: "Biology", selected: false },
{ name: "Mathematics", selected: false },
{ name: "Computer Science", selected: false },
];
const useStyles = makeStyles((theme) => ({
root: {
display: "flex"
},
paper: {
marginRight: theme.spacing(2)
}
}));
export default function MenuListComposition() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const [subjects, setSubjects] = React.useState(subjectsFromBackend);
const handleToggle = () => {
setOpen(!open);
};
const handleClose = () => {
setOpen(false);
};
const ColumnItem = ({ subjectName, selected }) => {
return (
<>
<Grid container>
<Grid item>
<Checkbox checked={selected} />
</Grid>
<Grid item>{subjectName}</Grid>
</Grid>
</>
);
};
const onDragEnd = (result, subjects, setSubjects) => {
const { source, destination } = result;
if (!destination) return;
if (source.droppableId !== destination.droppableId) return;
const copiedItems = [...subjects];
const [removed] = copiedItems.splice(source.index, 1);
copiedItems.splice(destination.index, 0, removed);
setSubjects(copiedItems);
};
return (
<div className={classes.root}>
<div>
<Button
ref={anchorRef}
onClick={handleToggle}
style={{ width: 385, justifyContent: "left", textTransform: "none" }}
>
{`Subjects Selected`}
</Button>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<DragDropContext
onDragEnd={(res) => onDragEnd(res, subjects, setSubjects)}
>
<Paper style={{ maxHeight: 200, overflow: "auto", width: 385 }}>
<ClickAwayListener onClickAway={handleClose}>
<Droppable droppableId={"subjectsColumn"}>
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
>
<List>
{subjects.map((col, index) => (
<Draggable
key={col.name}
draggableId={col.name}
index={index}
>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<ListItem>
<ColumnItem
subjectName={col.name}
selected={col.selected}
/>
</ListItem>
</div>
)}
</Draggable>
))}
</List>
{provided.placeholder}
</div>
)}
</Droppable>
</ClickAwayListener>
</Paper>
</DragDropContext>
</Grow>
)}
</Popper>
</div>
</div>
);
}
I found out that the ClickAwayListener's child component should be wrapped around a div so that the click event could be triggered properly.
You need to have your ClickAwayListener at the top when you are using the Drag and Drop.
return (
<ClickAwayListener
onClickAway={() => {
console.log("i got called");
handleClose();
}}
>
.....
</ClickAwayListener>
Here is the working codesandbox - https://codesandbox.io/s/material-demo-forked-h1o1s?file=/demo.js:4877-4897

"TypeError: children.props is undefined" error when adding <div> to NextJS component return statement

React/NextJS newbie issue any help is much appreciated. I have a header component built on React/NextJS and Material. This return statement works like a charm.
return (
<header>
<HideOnScroll {...props}>
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</HideOnScroll>
</header>
);
But as soon as I add a basic div, as shown below, I get "TypeError: children.props is undefined". I'm just trying to add a full width div with a height of 10px to the top of the header for some trim but can't even get a div to render. I've tried adding {...props} to the div but still no luck.
return (
<header>
<HideOnScroll {...props}>
<div>test</div>
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</HideOnScroll>
</header>
);
Full source code below:
import {
AppBar,
Toolbar,
Typography,
makeStyles,
Button,
IconButton,
Drawer,
Link,
MenuItem,
Slide,
useScrollTrigger
} from "#material-ui/core";
import MenuIcon from "#material-ui/icons/Menu";
import React, { useState, useEffect } from "react";
import NextLink from "next/link";
const headersData = [
{
label: "Home",
href: "/",
},
{
label: "Blog",
href: "/blog/ryan-test",
},
];
const useStyles = makeStyles(() => ({
header: {
backgroundColor: "#400CCC",
paddingRight: "79px",
paddingLeft: "118px",
"#media (max-width: 900px)": {
paddingLeft: 0,
},
},
logo: {
fontFamily: "Work Sans, sans-serif",
fontWeight: 600,
color: "#FFFEFE",
textAlign: "left",
},
menuButton: {
fontFamily: "Open Sans, sans-serif",
fontWeight: 700,
size: "18px",
marginLeft: "38px",
},
toolbar: {
display: "flex",
justifyContent: "space-between",
},
drawerContainer: {
padding: "20px 30px",
},
topTrim: {
height: "10px",
width: "100%",
backgroundColor: "red",
}
}));
export default function Header(props) {
const { header, logo, menuButton, toolbar, drawerContainer, topTrim } = useStyles();
const [state, setState] = useState({
mobileView: false,
drawerOpen: false,
});
const { mobileView, drawerOpen } = state;
const TopTrim = () => {
return <div>Hello</div>;
}
useEffect(() => {
const setResponsiveness = () => {
return window.innerWidth < 900
? setState((prevState) => ({ ...prevState, mobileView: true }))
: setState((prevState) => ({ ...prevState, mobileView: false }));
};
setResponsiveness();
window.addEventListener("resize", () => setResponsiveness());
}, []);
const HideOnScroll = (props) => {
const { children } = props;
const trigger = useScrollTrigger();
return (
<Slide appear={false} direction="down" in={!trigger}>
{children}
</Slide>
);
}
const displayDesktop = () => {
return (
<Toolbar className={toolbar}>
{femmecubatorLogo}
<div>{getMenuButtons()}</div>
</Toolbar>
);
};
const displayMobile = () => {
const handleDrawerOpen = () =>
setState((prevState) => ({ ...prevState, drawerOpen: true }));
const handleDrawerClose = () =>
setState((prevState) => ({ ...prevState, drawerOpen: false }));
return (
<Toolbar>
<IconButton
{...{
edge: "start",
color: "inherit",
"aria-label": "menu",
"aria-haspopup": "true",
onClick: handleDrawerOpen
}}
>
<MenuIcon />
</IconButton>
<Drawer
{...{
anchor: "left",
open: drawerOpen,
onClose: handleDrawerClose,
}}
>
<div key="test1" className={drawerContainer}>{getDrawerChoices()}</div>
</Drawer>
<div key="test2">{femmecubatorLogo}</div>
</Toolbar>
);
};
const getDrawerChoices = () => {
return headersData.map(({ label, href }) => {
return (
<NextLink href={href} key={label} passHref>
<MenuItem>{label}</MenuItem>
</NextLink>
);
});
};
const femmecubatorLogo = (
<Typography variant="h6" component="h1" className={logo}>
Femmecubator
</Typography>
);
const getMenuButtons = () => {
return headersData.map(({ label, href }) => {
return (
<NextLink href={href} key={label} passHref>
<Button
{...{
key: label,
color: "inherit",
to: href,
className: menuButton,
}}
>
{label}
</Button>
</NextLink>
);
});
};
return (
<header>
<HideOnScroll {...props}>
<div>test</div>
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</HideOnScroll>
</header>
);
}
Pass it like this :
<HideOnScroll {...props}>
<>
<div>test</div>
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</>
</HideOnScroll>
Ultimately, I ended up in moving the div to inside of the AppBar. I now have to adjust AppBar padding and spacing of anything living inside of AppBar to compensate for the div also living there but it is working.
return (
<header>
<HideOnScroll {...props}>
<AppBar className={header}>
<div className={topTrim}>This is a test</div>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</HideOnScroll>
</header>
);

Open menu on mouseover and Close menu on mouseleave in react

I just started plating around with react. I am currently working on my navBar using material-ui and react. When I hover over the menu, the drop-down appears. But in order to close the drop-down, I have to click on the outside of the drop-down. I want to be able to close the dropdown when I hover out of the drop-down or move to the different menu option (in which case a different drop-down should appear). Something like this one: https://www.palantir.com/
I looked around but I didn't find the solution. This was the closest I got: Material-ui: open menu by event hover
I tried using the same technique and added this to my code but to no avail. Any suggestions? Thanks!
Edits: I recreated my problem here: https://react-xmaiyw.stackblitz.io
The problem can be seen when clicked on 'Why us'.
handleClick = (event) => {
event.preventDefault();
this.setState({
open: true,
anchorEl: event.currentTarget,
});
};
handleRequestClose = () => {
this.setState({
open: false,
});
};
render() {
return (
<FlatButton
onClick={this.handleClick}
onMouseOver={this.handleClick}
onMouseLeave={this.handleRequestClose} //When I add this line of
//code, it keeps flickering very fast almost as if drop-down
//doesn't open
label="Why Us?"
/>
)}
The flickering is caused by the opening of the menu underneath your mouse. When the menu opens, the mouse is no longer over the button, so it prompts a mouseleave event, closing the menu, so that your mouse is now above the button again, prompting a mouseenter event, which opens the menu...and so on and so forth.
You can accomplish what you'd like with some additional logic to track where the mouse is, and a timeout to ensure that the user has time to transition the mouse between the button and the menu.
import React from 'react';
import Button from 'material-ui/Button';
import Menu, { MenuItem } from 'material-ui/Menu';
const timeoutLength = 300;
class SimpleMenu extends React.Component {
state = {
anchorEl: null,
// Keep track of whether the mouse is over the button or menu
mouseOverButton: false,
mouseOverMenu: false,
};
handleClick = event => {
this.setState({ open: true, anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({ mouseOverButton: false, mouseOverMenu: false });
};
enterButton = () => {
this.setState({ mouseOverButton: true });
}
leaveButton = () => {
// Set a timeout so that the menu doesn't close before the user has time to
// move their mouse over it
setTimeout(() => {
this.setState({ mouseOverButton: false });
}, timeoutLength);
}
enterMenu = () => {
this.setState({ mouseOverMenu: true });
}
leaveMenu = () => {
setTimeout(() => {
this.setState({ mouseOverMenu: false });
}, timeoutLength);
}
render() {
// Calculate open state based on mouse location
const open = this.state.mouseOverButton || this.state.mouseOverMenu;
return (
<div>
<Button
aria-owns={this.state.open ? 'simple-menu' : null}
aria-haspopup="true"
onClick={this.handleClick}
onMouseEnter={this.enterButton}
onMouseLeave={this.leaveButton}
>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={this.state.anchorEl}
open={open}
onClose={this.handleClose}
MenuListProps={{
onMouseEnter: this.enterMenu,
onMouseLeave: this.leaveMenu,
}}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>My account</MenuItem>
<MenuItem onClick={this.handleClose}>Logout</MenuItem>
</Menu>
</div>
);
}
}
export default SimpleMenu;
I used the MenuListProps to set the mouseEnter and mouseLeave events directly on the MenuList itself because the Menu component includes a bunch of invisible (disply: none) transition elements that have weird effects on mouse events. The MenuList is the element that's actually displayed so it makes sense to set the mouse events directly on it.
You'll probably need to play around with the timeoutLength and transitions to get everything looking smooth.
I faced same problems.
I solved the issues like this. I gaved LeaveMenu event to total component and menu component seperately, after it, it worked perfectly
import React from 'react';
import {
Menu,
MenuItem as MuiMenuItem,
Avatar,
Divider,
Typography,
Switch,
Fade,
} from '#mui/material';
import { useHistory } from 'react-router-dom';
import { styled } from '#mui/styles';
import { DarkMode as DarkModeIcon } from '#mui/icons-material';
/******************** Styled Components ********************/
const UserAvatarButton = styled('div')(({ active, theme }) => ({
height: 72,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '0px 20px',
cursor: 'pointer',
borderBottom: active ? `3px solid ${theme.palette.primary.main}` : 'none',
borderRadius: 0,
}));
const ProfileMenuNavigation = styled(Menu)(() => ({
'& .MuiList-root': {
paddingTop: 0,
paddingBottom: 0,
minWidth: 220,
maxWidth: 350,
},
}));
const MenuItem = styled(MuiMenuItem)(({ theme }) => ({
padding: 16,
width: '100%',
'&:hover': {
backgroundColor: theme.palette.background.main,
boxShadow: '5px 0px 5px 0px #888888',
transition: 'box-shadow 0.3s ease-in-out',
},
}));
const ProfileMenuText = styled(Typography)(() => ({
fontFamily: 'Poppins',
marginLeft: 16,
marginRight: 16,
fontSize: 16,
fontWeight: 600,
}));
/******************** Main Component ********************/
const ProfileMenu = ({ menus, active }) => {
const history = useHistory();
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
if (anchorEl) {
setAnchorEl(null);
} else {
setAnchorEl(event.currentTarget);
}
};
const handleClose = () => {
setAnchorEl(null);
};
const goPath = (path) => {
setAnchorEl(null);
history.push(path);
};
const leaveMenu = () => {
setTimeout(() => {
setAnchorEl(null);
}, 300);
};
return (
<div onMouseLeave={leaveMenu}>
<UserAvatarButton
id="account-button"
active={active}
aria-controls={open ? 'account-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
onMouseOver={(event) => setAnchorEl(event.currentTarget)}
>
<Avatar
sx={{
width: 38,
height: 38,
}}
alt="Avatar"
src="https://i.pravatar.cc/300"
/>
</UserAvatarButton>
<ProfileMenuNavigation
id="account-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'account-button',
onMouseLeave: leaveMenu,
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
TransitionComponent={Fade}
>
{menus.map((menu, index) => (
<div key={index}>
<MenuItem onClick={() => goPath(menu.path)}>
{menu?.icon}
<ProfileMenuText>{menu.text}</ProfileMenuText>
</MenuItem>
<Divider style={{ margin: 0 }} />
</div>
))}
<MenuItem onClick={() => {}}>
<DarkModeIcon />
<ProfileMenuText>Night Mode</ProfileMenuText>
<div style={{ marginLeft: 16 }}>
<Switch />
</div>
</MenuItem>
</ProfileMenuNavigation>
</div>
);
};
export default ProfileMenu;

Resources