diff options
author | crupest <crupest@outlook.com> | 2021-07-01 20:38:28 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-01 20:38:28 +0800 |
commit | eb306e98fb94fdfbced7b7e91ffb3d85ecb28c2c (patch) | |
tree | 5afe2d654a51c8712aa30a419f6edfa19fe1a234 /FrontEnd/src/views/common/menu/PopupMenu.tsx | |
parent | 825aac426d87180e62530321320fbb012efbd897 (diff) | |
parent | b456334cedad566bf2c4c66481ec928dc59eda7d (diff) | |
download | timeline-eb306e98fb94fdfbced7b7e91ffb3d85ecb28c2c.tar.gz timeline-eb306e98fb94fdfbced7b7e91ffb3d85ecb28c2c.tar.bz2 timeline-eb306e98fb94fdfbced7b7e91ffb3d85ecb28c2c.zip |
Merge pull request #649 from crupest/drop-bootstrap
Drop bootstrap!!!
Diffstat (limited to 'FrontEnd/src/views/common/menu/PopupMenu.tsx')
-rw-r--r-- | FrontEnd/src/views/common/menu/PopupMenu.tsx | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/FrontEnd/src/views/common/menu/PopupMenu.tsx b/FrontEnd/src/views/common/menu/PopupMenu.tsx new file mode 100644 index 00000000..d7b81f49 --- /dev/null +++ b/FrontEnd/src/views/common/menu/PopupMenu.tsx @@ -0,0 +1,84 @@ +import classNames from "classnames"; +import React from "react"; +import { createPortal } from "react-dom"; +import { usePopper } from "react-popper"; + +import Menu, { MenuItems } from "./Menu"; + +import "./PopupMenu.css"; + +export interface PopupMenuProps { + items: MenuItems; + children?: React.ReactNode; + containerClassName?: string; + containerStyle?: React.CSSProperties; +} + +const PopupMenu: React.FC<PopupMenuProps> = ({ + items, + children, + containerClassName, + containerStyle, +}) => { + const [show, setShow] = React.useState<boolean>(false); + + const [referenceElement, setReferenceElement] = + React.useState<HTMLDivElement | null>(null); + const [popperElement, setPopperElement] = + React.useState<HTMLDivElement | null>(null); + const { styles, attributes } = usePopper(referenceElement, popperElement); + + React.useEffect(() => { + const handler = (event: MouseEvent): void => { + let element: HTMLElement | null = event.target as HTMLElement; + while (element) { + if (element == referenceElement || element == popperElement) { + return; + } + element = element.parentElement; + } + setShow(false); + }; + document.addEventListener("click", handler); + return () => { + document.removeEventListener("click", handler); + }; + }, [referenceElement, popperElement]); + + return ( + <> + <div + ref={setReferenceElement} + className={classNames( + "cru-popup-menu-trigger-container", + containerClassName + )} + style={containerStyle} + onClick={() => setShow(true)} + > + {children} + </div> + {show + ? createPortal( + <div + ref={setPopperElement} + className="cru-popup-menu-menu-container" + 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")! + ) + : null} + </> + ); +}; + +export default PopupMenu; |