aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/components/menu/PopupMenu.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'FrontEnd/src/components/menu/PopupMenu.tsx')
-rw-r--r--FrontEnd/src/components/menu/PopupMenu.tsx72
1 files changed, 72 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..7ac2abfe
--- /dev/null
+++ b/FrontEnd/src/components/menu/PopupMenu.tsx
@@ -0,0 +1,72 @@
+import { useState, CSSProperties, ReactNode } from "react";
+import classNames from "classnames";
+import { createPortal } from "react-dom";
+import { usePopper } from "react-popper";
+
+import { ThemeColor } from "../common";
+import { useClickOutside } from "../hooks";
+import Menu, { MenuItems } from "./Menu";
+
+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}
+ onItemClick={(e) => {
+ setShow(false);
+ e.stopPropagation();
+ }}
+ />
+ </div>,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ document.getElementById("portal")!,
+ )}
+ </div>
+ );
+}