From f5dfd52f6efece2f4cad227044ecf4dd66301bbc Mon Sep 17 00:00:00 2001
From: crupest <crupest@outlook.com>
Date: Sat, 26 Aug 2023 21:36:58 +0800
Subject: ...

---
 FrontEnd/src/components/menu/PopupMenu.tsx | 73 ++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 FrontEnd/src/components/menu/PopupMenu.tsx

(limited to 'FrontEnd/src/components/menu/PopupMenu.tsx')

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>
+  );
+}
-- 
cgit v1.2.3

