import React, { PropsWithChildren, ReactNode, useEffect } from "react"; import classNames from "classnames"; import ReactModal from "react-modal"; import { Button } from ":/components/Button"; import { NOSCROLL_CLASS, useModals } from ":/components/Modal/ModalProvider"; export type ModalHandle = {}; export const MODAL_CLASS = "c__modal"; export enum ModalSize { SMALL = "small", MEDIUM = "medium", LARGE = "large", EXTRA_LARGE = "extra-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 type ModalProps = PropsWithChildren & { size: ModalSize; isOpen: boolean; onClose: () => void; leftActions?: React.ReactNode; rightActions?: React.ReactNode; actions?: React.ReactNode; title?: ReactNode; titleIcon?: React.ReactNode; hideCloseButton?: boolean; closeOnClickOutside?: boolean; closeOnEsc?: boolean; preventClose?: boolean; "aria-label"?: string; }; export const Modal = (props: ModalProps) => { /** * This is a workaround to prevent the modal from rendering on the first render because if the modal is open on the * first render, it will not be able to resolve document.getElementById() which is not rendered yet. */ const [firstRender, setFirstRender] = React.useState(true); useEffect(() => { setFirstRender(false); }, []); if (firstRender) { return null; } return ; }; export const ModalInner = ({ closeOnEsc = true, ...props }: ModalProps) => { const { modalParentSelector } = useModals(); if (!props.isOpen) { return null; } return ( { if (!props.preventClose) { props.onClose(); } }} parentSelector={modalParentSelector} overlayClassName="c__modal__backdrop" className={classNames(MODAL_CLASS, `${MODAL_CLASS}--${props.size}`)} shouldCloseOnOverlayClick={!!props.closeOnClickOutside} shouldCloseOnEsc={closeOnEsc} bodyOpenClassName={classNames("c__modals--opened", NOSCROLL_CLASS)} contentLabel={props["aria-label"] || props.title?.toString()} >
{!props.hideCloseButton && !props.preventClose && (
)} {props.titleIcon && (
{props.titleIcon}
)} {props.title &&
{props.title}
} {/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}
{props.children}
); }; const ModalFooter = ({ leftActions, rightActions, actions, }: Pick) => { if ((leftActions || rightActions) && actions) { throw new Error("Cannot use leftActions or rightActions with actions"); } if (!leftActions && !rightActions && !actions) { return null; } return (
{actions || ( <>
{leftActions}
{rightActions}
)}
); };