import clsx from 'clsx'; import { ReactNode, useEffect, useState, MouseEvent, useCallback, ReactPortal } from 'react'; import { createPortal } from 'react-dom'; import { Button } from '../Button/Button'; import { ReactComponent as xSVG } from './images/x.svg'; import styles from './Modal.module.scss'; type Props = { heading: string; close: () => void; children?: ReactNode; footer?: ReactNode; className?: string; size?: 'normal' | 'large'; }; function useHeight() { const [height, setHeight] = useState(0); const ref = useCallback((node: HTMLDivElement | null) => { if (node) setHeight(node.getBoundingClientRect().height); }, []); return [height, ref] as const; } function useMaxHeight() { const [headerHeight, headerRef] = useHeight(); const [footerHeight, footerRef] = useHeight(); const padding = 32; const bodyStyle = { maxHeight: `calc(100vh - ${headerHeight + footerHeight + 2 * padding}px)` }; return { bodyStyle, headerRef, footerRef }; } const Modal = ({ heading, close, children, footer, className, size = 'normal' }: Props): ReactPortal | null => { const [root, setRoot] = useState(); const { bodyStyle, headerRef, footerRef } = useMaxHeight(); const modalClassName = clsx(styles.modal, styles[size]); const bodyClassName = clsx(styles.body, className, !footer && styles.withoutFooter); const handleOverlayClick = ({ target, currentTarget }: MouseEvent) => { if (target === currentTarget) close(); }; useEffect(() => { const div = document.createElement('div'); div.id = 'modal-root'; document.body.appendChild(div); setRoot(div); return () => { document.body.removeChild(div); }; }, []); const component = (

{heading}

{children && (
{children}
)} {footer && ( )}
); return root ? createPortal(component, root) : null; }; export { Modal, styles as modalStyles }; export type { Props as ModalProps };