import React, { MouseEvent, ReactNode, useRef } from 'react'; import ReactDOM from 'react-dom'; import Button, { ButtonType } from '../Button'; import { useTransition, animated } from 'react-spring'; import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll'; import LoadingSpinner from '../LoadingSpinner'; import useClickOutside from '../../../hooks/useClickOutside'; interface ModalProps extends React.HTMLAttributes { title?: string; onCancel?: (e?: MouseEvent) => void; onOk?: (e?: MouseEvent) => void; onSecondary?: (e?: MouseEvent) => void; onTertiary?: (e?: MouseEvent) => void; cancelText?: string; okText?: string; secondaryText?: string; tertiaryText?: string; okDisabled?: boolean; cancelButtonType?: ButtonType; okButtonType?: ButtonType; secondaryButtonType?: ButtonType; secondaryDisabled?: boolean; tertiaryDisabled?: boolean; tertiaryButtonType?: ButtonType; disableScrollLock?: boolean; backgroundClickable?: boolean; iconSvg?: ReactNode; loading?: boolean; } const Modal: React.FC = ({ title, onCancel, onOk, cancelText, okText, okDisabled = false, cancelButtonType = 'default', okButtonType = 'primary', children, disableScrollLock, backgroundClickable = true, iconSvg, loading = false, secondaryButtonType = 'default', secondaryDisabled = false, onSecondary, secondaryText, tertiaryButtonType = 'default', tertiaryDisabled = false, tertiaryText, onTertiary, ...props }) => { const modalRef = useRef(null); useClickOutside(modalRef, () => { typeof onCancel === 'function' && backgroundClickable ? onCancel() : undefined; }); useLockBodyScroll(true, disableScrollLock); const containerTransitions = useTransition(!loading, null, { from: { opacity: 0, transform: 'scale(0.5)' }, enter: { opacity: 1, transform: 'scale(1)' }, leave: { opacity: 0, transform: 'scale(0.5)' }, config: { tension: 500, velocity: 40, friction: 60 }, }); const loadingTransitions = useTransition(loading, null, { from: { opacity: 0, transform: 'scale(0.5)' }, enter: { opacity: 1, transform: 'scale(1)' }, leave: { opacity: 0, transform: 'scale(0.5)' }, config: { tension: 500, velocity: 40, friction: 60 }, }); return ( <> {ReactDOM.createPortal( { if (e.key === 'Escape') { typeof onCancel === 'function' && backgroundClickable ? onCancel() : undefined; } }} > {loadingTransitions.map( ({ props, item, key }) => item && ( ) )} {containerTransitions.map( ({ props, item, key }) => item && (
{iconSvg && (
{iconSvg}
)}
{title && ( )}
{children && (
{children}
)} {(onCancel || onOk || onSecondary || onTertiary) && (
{typeof onOk === 'function' && ( )} {typeof onSecondary === 'function' && secondaryText && ( )} {typeof onTertiary === 'function' && tertiaryText && ( )} {typeof onCancel === 'function' && ( )}
)}
) )}
, document.body )} ); }; export default Modal;