diff options
Diffstat (limited to 'FrontEnd/src/components/dialog/Dialog.tsx')
-rw-r--r-- | FrontEnd/src/components/dialog/Dialog.tsx | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/FrontEnd/src/components/dialog/Dialog.tsx b/FrontEnd/src/components/dialog/Dialog.tsx new file mode 100644 index 00000000..043a8eec --- /dev/null +++ b/FrontEnd/src/components/dialog/Dialog.tsx @@ -0,0 +1,55 @@ +import { ReactNode, useRef } from "react"; +import ReactDOM from "react-dom"; +import classNames from "classnames"; + +import { ThemeColor, UiLogicError } from "../common"; + +import { useCloseDialog } from "./DialogProvider"; + +import "./Dialog.css"; + +const optionalPortalElement = document.getElementById("portal"); +if (optionalPortalElement == null) { + throw new UiLogicError(); +} +const portalElement = optionalPortalElement; + +interface DialogProps { + color?: ThemeColor; + children?: ReactNode; + disableCloseOnClickOnOverlay?: boolean; +} + +export default function Dialog({ + color, + children, + disableCloseOnClickOnOverlay, +}: DialogProps) { + const closeDialog = useCloseDialog(); + + const lastPointerDownIdRef = useRef<number | null>(null); + + return ReactDOM.createPortal( + <div + className={classNames( + `cru-theme-${color ?? "primary"}`, + "cru-dialog-overlay", + )} + > + <div + className="cru-dialog-background" + onPointerDown={(e) => { + lastPointerDownIdRef.current = e.pointerId; + }} + onPointerUp={(e) => { + if (lastPointerDownIdRef.current === e.pointerId) { + if (!disableCloseOnClickOnOverlay) closeDialog(); + } + lastPointerDownIdRef.current = null; + }} + /> + <div className="cru-dialog-container">{children}</div> + </div>, + portalElement, + ); +} |