How to fix shadow for menu material-ui - reactjs

When I use a few icon menus than box-shadow looks very dark. How to fix that?
1:
Codesandbox example https://codesandbox.io/embed/flamboyant-tdd-r83u1
<div>
{items.map((item, index) => {
return (
<Fragment key={index}>
<IconButton
aria-owns={open ? "long-menu" : undefined}
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu anchorEl={anchorEl} open={open} onClose={this.handleClose}>
{options.map(option => (
<MenuItem key={option} onClick={this.handleClose}>
{option}
</MenuItem>
))}
</Menu>
</Fragment>
);
})}
</div>

Because, actually you are triggering multiple menus with the same flag at the same time. So shadow is dark because there are multiple menus one after the other.

Below code should fix this, You don't have to render Menu in items loop
render() {
const items = [...Array(10).keys()];
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
return (
<div>
{items.map((item, index) => {
return (
<Fragment key={index}>
<IconButton
aria-owns={open ? "long-menu" : undefined}
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
</Fragment>
);
})}
<Menu anchorEl={anchorEl} open={open} onClose={this.handleClose}>
{options.map(option => (
<MenuItem key={option} onClick={this.handleClose}>
{option}
</MenuItem>
))}
</Menu>
</div>
);
}

Related

Close submenu when clicked on other submenu

I am using antd menu and submenu. and i am unable to close the submenu when other sumbenu is opened. I am using react js for the code.I am able to close main menu on other menu expansion. but have no idea how to close submenu on other submenu expansion. Here is my code
<Menu
style={{ width: 220 }}
mode="inline"
openKeys={openKeys}
onOpenChange={onOpenChange}
selectedKeys={[location.pathname]}
title="Navigation"
className="custom-menu"
>
{navigationConfig.map((menu) => {
return (
<>
{menu.submenu.length > 0 ? (
<SubMenu
icon={menu.icon ? <Icon type={menu?.icon} /> : null}
key={menu.key}
title={menu.title}
>
{menu.submenu.map((submenu) => {
return (
<Menu.Item
key={submenu.key}
onClick={submenu.onclick}
>
{submenu.icon ? (
<Icon type={submenu?.icon} />
) : null}
{submenu.title}
{submenu.path ? (
<Link
to={{
pathname: submenu.path,
state: history.location.state,
}}
onClick={() => {
setHeaderTitle(
menu.hasOwnProperty("aliasTitle")
? menu.aliasTitle
: menu.title
);
}}
/>
) : null}
</Menu.Item>
);
})}
</SubMenu>
</Menu.Item>
)}
</>
);
})}
</Menu>

React Menu is closing on element click

I have a menu which applies filter to my list and when I click on an element inside the menu is closing and I can not set more filters. I should click the stepper or the selection box many times and the menu should close on click on submit or cancel and not on click of stepper or selection box
`
<Menu matchWidth={true} isOpen={isOpen} onOpen={handleOpen} onClose={handleCancel} closeOnBlur={false} closeOnSelect={false} >
<ChakraSelectButton headline={'Who?'} information={information} />
<MenuList p={4} onClick={e => e.stopPropagation()} >
<VStack
alignItems={'flex-start'}
// #ts-ignore
ref={ref}
<Stepper
title={'How many people?'}
handleChange={handleChange}
name={people}
value={numberOfPeople ? numberOfPeople : 0}
boxSize={10}
/>
{numberOfPeople > 0 && (
<VStack w={'100%'} onClick={e => e.preventDefault()}>
<Text
alignSelf={'flex-start'}
Please insert the age!
</Text>
{Array.from(Array(numberOfPeople)).map((a, idx) => {
return (
<Select
key={idx}
userSelect={'none'}>
<option value={24}>24</option>
<option value={25}>25</option>
<option value={26}>26</option>
<option value={27}>27</option>
</Select>
);
})}
</VStack>
)}
<Stepper
title={'Pets'}
handleChange={handleChange}
value={numberOfPets ? numberOfPets : 0}
boxSize={10}
/>
<Divider />
<CtaFilterButtons
size={'sm'}
handleCancel={handleCancel}
handleFilterChange={handleSubmit}
/>
</VStack>
</MenuList>
</Menu>
`
I only want to close the menu when I click on submit.

Expand collapse (material-ui) only one at a time - React

I have table that I can expand Collapse material-ui. Everything is worked perfectly.
But there is one thing I want to update that when I click to expand there is only one expand collapse opened at a time.
const InvoiceInfo = ({el}) => {
const [open, setOpen] = React.useState(false)
}
function handleExpand() {
setOpen(!open)
}
return (
<>
<TableRow key={el.id}>
<TableCell>
{el.name}
</TableCell>
<TableCell>
<IconButton onClick={handleExpand}>
{open ? (
<KeyboardArrowUp fontSize="large" />
) : (
<KeyboardArrowDown fontSize="large" />
)}
</IconButton>
</TableCell>
</TableRow>
{
<TableRow>
<Collapse in={open} timeout="auto" unmountOnExit>
<div>
EXPAND ROW
</div>
</Collapse>
</TableRow>
}
</>
)
Above is my code looks like.
Any advice is very meaningful to me. Thank you so much.
You can use a simple state based on the index of an array or a given number / value:
const [isOpenCollapse, setIsOpenCollapse] = useState(null);
const handleOpen = (clickedIndex) => {
if (isOpenCollapse === clickedIndex) {
setIsOpenCollapse(null);
} else {
setIsOpenCollapse(clickedIndex);
}
};
[...]
return (
<List>
{arr.map((elm, index) => {
return (
<>
<ListItem key={elm.ID} onClick={() => handleOpen(index)} id="listItem">
{isOpenCollapse === index ? <ExpandLess /> : <ExpandMore />}
<Box>
<Typography>{elm.label}</Typography>
</Box>
</ListItem>
<Collapse in={isOpenCollapse === index} timeout="auto" unmountOnExit>
<p>PUT SOMETHING HERE</p>
</Collapse>
</>
);
})}
</List>;
)

How to get the key on click event

I have the following react component:
type MobileNavProp = RouteTableProp
export default function MobileNav({routes}: MobileNavProp) {
const classes = useStyles()
const [drawerOpen, setDrawerOpen] = useState<boolean>(false)
const handleOnClickItem = (event: React.MouseEvent<HTMLDivElement>): void => console.log(event.target)
return (
<React.Fragment>
<IconButton
className={classes.icon}
color="inherit"
aria-label="Open navigation"
edge="end"
onClick={() => setDrawerOpen(true)}
>
<MenuRoundedIcon fontSize="large"/>
</IconButton>
<SwipeableDrawer open={drawerOpen}
onClose={() => setDrawerOpen(false)}
onOpen={() => console.log("Drawer is open")}
disableBackdropTransition={!iOS}
anchor="top"
disableDiscovery={iOS}
>
<List subheader={
<ListSubheader component="div" id="logo" className={classes.company}>
<img className={classes.logo} src={logo} alt="databaker-logo"/>
<Typography variant="h6" className={classes.title}>
DATABAKER
</Typography>
</ListSubheader>
}>
{
routes.map((rt, index) => (
<ListItem
divider
key={index}
button
onClick={handleOnClickItem}
>
<ListItemText primary={rt.name}/>
</ListItem>
))
}
</List>
</SwipeableDrawer>
</React.Fragment>
)
}
When the user click on ListItem(the handler function is handleOnClickItem), then it shows me:
<span class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock">ABOUT US</span>
However, I would like to get the clicked index that I have provided:
<ListItem
divider
key={index}...
How to get it?
You can make handleOnClickItem a higher-order function that takes the index as a parameter, and call it:
const makeHandleOnClickItem = (i: number) => (event: React.MouseEvent<HTMLDivElement>) => {
console.log(event.target);
console.log(i);
};
and change
onClick={handleOnClickItem}
to
onClick={makeHandleOnClickItem(index)}

Cannot read property map of undefined react

I'm trying to render a component that uses an array of filters to make a list. I pass the array as an argument to the function but it returns an error. The array is not null or undefined because it shows the itens if I log to the console.
Console.log returns:
Here is my code:
const List = (filtrosPorTipo) => {
let filtros = filtrosPorTipo[0]
let valoresDosFiltros = filtrosPorTipo[1]
let lista = (
<List>
{filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
})}
</List>
)
return lista
}
Error:
Perhaps the component it's trying to render before "filtros" is assigned. It's a common and logical behavior in React.
Try adding a conditional before the .map() call:
{filtros ? filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
}) : null}
You can map over the values when they are present like so. If you are not planning on displaying a Loading screen in the process of waiting for the data then this would work. Otherwise use a ternary operator like the other answer.
{filtros && filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
})}
While rendering the component you have to check data in filtrosPorTipo. It has an array value or not. Like below:
const List = (filtrosPorTipo) => {
if (filtrosPorTipo && filtrosPorTipo.length > 0) {
let filtros = filtrosPorTipo[0]
let valoresDosFiltros = filtrosPorTipo[1]
let lista = (
<List>
{filtros.map((item, index) => {
return (
<>
<ListItem
button
onClick={() => setOpen({ [item]: !open[item] })}
key={item}
>
<ListItemText primary={item} />
{open[item] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open[item]} timeout='auto'>
<List component='div' disablePadding>
{valoresDosFiltros[index].map((filtro) => {
return (
<>
<ListItem key={filtro}>
<p>{`${filtro}\n`}</p>
<ListItemSecondaryAction>
<Checkbox
label={filtro}
key={filtro.toString()}
color='primary'
onChange={() => handleChecked(filtro)}
checked={checked[filtro]}
/>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</>
)
})}
</List>
</Collapse>
</>
)
})}
</List>
)
return lista
}
return 'No data available!'
}

Resources