I need to add a Context Menu to my TreeWiew
. I managed to do this with this mui.com's Menu
but I don't know how to get the selected item in the tree where the user did the right click to open the context menu. For example, let's say the user open the context menu and click on "Copy message" i'd like to know which node the user selected (Calendar, OSS, index.js etc) and do the proper action. I've tried looking in the TreeView's thing like onNodeSelect
but it doesn't fire when you open the context menu over the item.
Currently the code look like this:
export default function FileSystemNavigator() {
const [contextMenu, setContextMenu] = React.useState<{
mouseX: number;
mouseY: number;
} | null>(null);
const handleContextMenu = (event: React.MouseEvent) => {
event.preventDefault();
setContextMenu(
contextMenu === null
? {
mouseX: event.clientX + 2,
mouseY: event.clientY - 6
}
: // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu
// Other native context menus might behave different.
// With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus.
null
);
};
const handleClose = () => {
setContextMenu(null);
};
return (
<div onContextMenu={handleContextMenu} style={{ cursor: "context-menu" }}>
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="10" label="OSS" />
<TreeItem nodeId="6" label="MUI">
<TreeItem nodeId="8" label="index.js" />
</TreeItem>
</TreeItem>
</TreeView>
<Menu
open={contextMenu !== null}
onClose={handleClose}
anchorReference="anchorPosition"
anchorPosition={
contextMenu !== null
? { top: contextMenu.mouseY, left: contextMenu.mouseX }
: undefined
}
>
<MenuItem onClick={handleClose}>Copy Ctrl+C</MenuItem>
<MenuItem onClick={handleClose}>Delete</MenuItem>
<MenuItem onClick={handleClose}>Move</MenuItem>
<MenuItem onClick={handleClose}>Email</MenuItem>
</Menu>
</div>
);
}
Here's
a live code example
You can achieve this by a small hack - trigger the click event
on opening the context menu. That will fire an onNodeSelect
callback of the TreeView
component.
export default function FileSystemNavigator() {
// ...
const [selectedNodeId, setSelectedNodeId] = React.useState<string | null>(
null
);
const handleContextMenu = (event: React.MouseEvent) => {
event.target.click();
event.preventDefault();
// ...
};
const handleNodeSelect = (event, nodeId) => {
setSelectedNodeId(nodeId);
};
return (
<div onContextMenu={handleContextMenu} style={{ cursor: "context-menu" }}>
<TreeView
{/* ... */}
onNodeSelect={handleNodeSelect}
></TreeView>
<Menu>
{/* ... */}
<MenuItem onClick={handleClose}>Delete node {selectedNodeId}</MenuItem>
{/* ... */}
</Menu>
</div>
);
}