aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/views/common/menu/PopupMenu.tsx
blob: d7b81f49ccffa654352ce5b388f0658c4791efab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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;