import React, { useState, useContext, MouseEvent } from "react"; import MaterialMenu, { MenuProps } from "@material-ui/core/Menu"; import MenuContext from "./context"; import ClickAwayListener from "@material-ui/core/ClickAwayListener"; type ButtonEventFn = ( event: MouseEvent ) => void; interface Props { buttonElement: (onClick: { onClick: ButtonEventFn; onKeyDown: ButtonEventFn; }) => React.ReactNode; // TODO can we specify the MenuItem[] component type as children? children: React.ReactNode; anchorOrigin?: MenuProps["anchorOrigin"]; transformOrigin?: MenuProps["transformOrigin"]; className?: string; onOpen?: () => void; onClose?: () => void; header?: React.ReactElement; } function Menu({ children, className, buttonElement, anchorOrigin = { vertical: "bottom", horizontal: "left" }, transformOrigin = { vertical: "top", horizontal: "left" }, onOpen = () => {}, onClose = () => {}, header }: Props) { const [anchorEl, setAnchorEl] = useState(null); const [shouldAutoFocus, setShouldAutoFocus] = useState(false); const menuContext = useContext(MenuContext); function handleClick(event) { if (event.type === "click") { openWithFocus(false); } if ( event.type === "keydown" && (event.key === "Enter" || event.key === "ArrowDown") ) { openWithFocus(true); } function openWithFocus(withFocus) { setShouldAutoFocus(withFocus); setAnchorEl(event.currentTarget); onOpen(); } } function handleClose() { setAnchorEl(null); onClose(); } menuContext.registerCloseMenuCallback(handleClose); return (
{buttonElement({ onClick: handleClick, onKeyDown: handleClick })} {children}
); } export default function MenuWithProvider({ ...props }: Props) { const callbacks = []; return ( { callbacks.push(callback); }, closeMenu: () => { callbacks.forEach(callback => callback()); } }} > ); }