import React, { PropsWithChildren, useEffect } from "react"; import classNames from "classnames"; import { createPortal } from "react-dom"; import { Button } from ":/components/Button"; export type ModalHandle = {}; export enum ModalSize { SMALL = "small", MEDIUM = "medium", LARGE = "large", FULL = "full", } export const useModal = ({ isOpenDefault, }: { isOpenDefault?: boolean } = {}) => { const [isOpen, setIsOpen] = React.useState(!!isOpenDefault); const onClose = () => { setIsOpen(false); }; const open = () => { setIsOpen(true); }; const close = () => { onClose(); }; return { isOpen, onClose, open, close, }; }; export interface ModalProps extends PropsWithChildren<{ size: ModalSize; isOpen: boolean; onClose: () => void; leftActions?: React.ReactNode; rightActions?: React.ReactNode; actions?: React.ReactNode; title?: string; titleIcon?: React.ReactNode; hideCloseButton?: boolean; closeOnClickOutside?: boolean; preventClose?: boolean; }> {} export const Modal = (props: ModalProps) => { const ref = React.useRef(null); useEffect(() => { if (props.isOpen) { ref.current?.showModal(); } else { ref.current?.close(); } }, [props.isOpen]); useEffect(() => { ref.current?.addEventListener("close", () => props.onClose(), { once: true, }); const onClick = (event: MouseEvent) => { const rect = ref.current!.getBoundingClientRect(); const isInDialog = rect.top <= event.clientY && event.clientY <= rect.top + rect.height && rect.left <= event.clientX && event.clientX <= rect.left + rect.width; if (!isInDialog) { props.onClose(); } }; if (props.closeOnClickOutside) { ref.current?.addEventListener("click", onClick); } const preventClose = (event: Event) => { event.preventDefault(); }; if (props.preventClose) { ref.current?.addEventListener("cancel", preventClose); } return () => { ref.current?.removeEventListener("click", onClick); ref.current?.removeEventListener("click", preventClose); }; }, [props.isOpen]); if (!props.isOpen) { return null; } return ( <> {createPortal( <>
{!props.hideCloseButton && !props.preventClose && (
)} {props.titleIcon && (
{props.titleIcon}
)} {props.title && (
{props.title}
)} {/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}
{props.children}
, document.getElementById("c__modals-portal")!, )} ); }; const ModalFooter = ({ leftActions, rightActions, actions }: ModalProps) => { if ((leftActions || rightActions) && actions) { throw new Error("Cannot use leftActions or rightActions with actions"); } if (!leftActions && !rightActions && !actions) { return null; } return (
{actions || ( <>
{leftActions}
{rightActions}
)}
); };