import { MoreVert } from "@mui/icons-material"; import { IconButton, Menu as MuiMenu } from "@mui/material"; import { PropsWithChildren, ReactNode, useCallback, useEffect, useMemo, useState } from "react"; import { POSITION } from "@dreipol/t3-ui"; import { PopoverOrigin } from "@mui/material/Popover/Popover"; export type MenuProps = PropsWithChildren<{ /** * Custom icon */ icon?: ReactNode; /** * Custom trigger. WHen this is set, you are responsible to control the state of the menu */ trigger?: ReactNode; /** * Set menu open/close */ open?: boolean; /** * Handle close event */ onClose?: () => void; /** * Custom anchor element */ anchor?: HTMLElement | null; /** * Custom css class name */ className?: string; anchorPosition?: POSITION }>; /** * Simple wrapper for the MUI Menu component adding some basic logic to avoid repetition */ export const Menu = ({ children, icon, trigger, onClose, anchor = null, className, open = false, anchorPosition }: MenuProps) => { const [ isOpen, setOpen ] = useState(open); const [ anchorRef, setAnchorRef ] = useState(anchor); const onCloseTriggered = useCallback(() => { onClose?.(); setOpen(false) }, [ onClose ]); useEffect(() => { setOpen(open); }, [ open ]) useEffect(() => { setAnchorRef(anchorRef) }, [ anchor ]) const anchorOrigin: PopoverOrigin = useMemo(() => { switch (anchorPosition) { case POSITION.TOP_LEFT : return { vertical: 'top', horizontal: 'left' } case POSITION.TOP_CENTER : return { vertical: 'top', horizontal: 'center' } case POSITION.TOP_RIGHT : return { vertical: 'top', horizontal: 'right' } case POSITION.CENTER_LEFT : return { vertical: 'center', horizontal: 'left' } case POSITION.CENTER_CENTER : return { vertical: 'center', horizontal: 'center' } case POSITION.CENTER_RIGHT : return { vertical: 'center', horizontal: 'right' } case POSITION.BOTTOM_LEFT : return { vertical: 'bottom', horizontal: 'left' } case POSITION.BOTTOM_CENTER: return { vertical: 'bottom', horizontal: 'center' } case POSITION.BOTTOM_RIGHT: return { vertical: 'bottom', horizontal: 'right' } default: return { vertical: 'top', horizontal: 'left' } } }, [ anchorPosition ]) return ( <> { trigger ? trigger : setOpen(true) } > { icon ? icon : } } { children } ); }