To create the functionality where users can navigate to other menus while keeping a submenu open and retaining the state of parent or previous menus when interacting with submenus, you need to update the way state is managed and events are handled in your RecursiveMenu and RecursiveMenuItem components. Follow these steps to adjust your code:
Managing Open Menus State:
Use an array to monitor which menu levels are open. When a submenu is opened, add its ID to the array; when it's closed, remove the ID.
Handling Submenu Events:
Treat clicks on menu items differently depending on whether they have submenus. For items without submenus, toggle the checkbox state as usual. For items with submenus, update the openMenus array to reflect the current menu hierarchy.
Here is how you can update your code to implement these changes:
import React, { useState } from 'react';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import IconButton from '@mui/material/IconButton';
import MenuIcon from '@mui/icons-material/Menu';
import Checkbox from '@mui/material/Checkbox';
const RecursiveMenu = ({ menuItems }) => {
const [openMenus, setOpenMenus] = useState([]);
const handleClick = (event, menuId) => {
setOpenMenus((prevOpenMenus) => [...prevOpenMenus, menuId]);
};
const handleClose = () => {
setOpenMenus((prevOpenMenus) => prevOpenMenus.slice(0, -1));
};
return (
<div>
<IconButton
aria-controls="simple-menu"
aria-haspopup="true"
onClick={(event) => handleClick(event, 'root')}
>
<MenuIcon />
</IconButton>
<Menu
id="simple-menu"
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
anchorEl={document.getElementById('simple-menu')}
keepMounted
open={openMenus.length > 0}
onClose={handleClose}
>
{Object.values(menuItems)
.filter((menuItem) => menuItem.showing !== false)
.map((menuItem) => (
<RecursiveMenuItem key={menuItem.id} menuItem={menuItem} handleClick={handleClick} />
))}
</Menu>
</div>
);
};
const RecursiveMenuItem = ({ menuItem, handleClick }) => {
const hasSubMenu = menuItem.options;
const [showingState, setShowingState] = useState(menuItem.showing);
const handleItemClick = (event, menuId) => {
if (hasSubMenu) {
handleClick(event, menuId);
} else {
setShowingState((prevState) => (prevState + 1) % 3);
}
};
return (
<>
<MenuItem
style={{ display: 'flex', justifyContent: 'space-between' }}
onClick={(event) => handleItemClick(event, menuItem.id)}
>
<span>{menuItem.name}</span>
{!hasSubMenu && (
<Checkbox
checked={showingState === 0}
indeterminate={showingState === 1}
onChange={(event) => handleItemClick(event, menuItem.id)}
inputProps={{ 'aria-label': 'indeterminate-checkbox' }}
/>
)}
</MenuItem>
{hasSubMenu && (
<Menu
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
anchorEl={document.getElementById(menuItem.id)}
keepMounted
open={true}
onClose={() => {}}
>
{Object.values(menuItem.options)
.filter((subMenuItem) => subMenuItem.showing !== false)
.map((subMenuItem) => (
<RecursiveMenuItem key={subMenuItem.id} menuItem={subMenuItem} handleClick={handleClick} />
))}
</Menu>
)}
</>
);
};
const App = () => {
const menuItems = {
A: { id: "A", name: "A", enabled: false, showing: 0 },
B: { id: "B", name: "B", enabled: false, showing: 2 },
C: {
id: "c",
name: "C",
options: {
C1: { id: "C1", name: "C1", enabled: false, showing: 1 },
C2: {
id: "C2", name: "C2", options:
{
C21: { id: "C21", name: "C2.1", enabled: false, showing: 0 },
C22: { id: "C22", name: "C2.2", enabled: false, showing: 2 },
}
},
},
},
Shaun: { id: "D", name: "D", enabled: false, showing: 2 },
};
return <RecursiveMenu menuItems={menuItems} />;
};
export default App;