diff options
Diffstat (limited to 'FrontEnd/src/components/menu/PopupMenu.tsx')
-rw-r--r-- | FrontEnd/src/components/menu/PopupMenu.tsx | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/FrontEnd/src/components/menu/PopupMenu.tsx b/FrontEnd/src/components/menu/PopupMenu.tsx new file mode 100644 index 00000000..23a67f79 --- /dev/null +++ b/FrontEnd/src/components/menu/PopupMenu.tsx @@ -0,0 +1,73 @@ +import { useState, CSSProperties, ReactNode } from "react"; +import classNames from "classnames"; +import { createPortal } from "react-dom"; +import { usePopper } from "react-popper"; + +import { useClickOutside } from "~src/utilities/hooks"; + +import Menu, { MenuItems } from "./Menu"; + +import { ThemeColor } from "../common"; + +import "./PopupMenu.css"; + +export interface PopupMenuProps { + color?: ThemeColor; + items: MenuItems; + children?: ReactNode; + containerClassName?: string; + containerStyle?: CSSProperties; +} + +export default function PopupMenu({ + color, + items, + children, + containerClassName, + containerStyle, +}: PopupMenuProps) { + const [show, setShow] = useState<boolean>(false); + + const [referenceElement, setReferenceElement] = + useState<HTMLDivElement | null>(null); + const [popperElement, setPopperElement] = useState<HTMLDivElement | null>( + null, + ); + const { styles, attributes } = usePopper(referenceElement, popperElement); + + useClickOutside(popperElement, () => setShow(false), true); + + return ( + <div + ref={setReferenceElement} + className={classNames( + "cru-popup-menu-trigger-container", + containerClassName, + )} + style={containerStyle} + onClick={() => setShow(true)} + > + {children} + {show && + createPortal( + <div + ref={setPopperElement} + className={`cru-popup-menu-menu-container cru-clickable-${ + color ?? "primary" + }`} + style={styles.popper} + {...attributes.popper} + > + <Menu + items={items} + onItemClicked={() => { + setShow(false); + }} + /> + </div>, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + document.getElementById("portal")!, + )} + </div> + ); +} |