import React, { useRef } from 'react'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; import { ClickOutsideMode, useListenClickOutside, } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; const ModalDiv = styled(motion.div)` display: flex; flex-direction: column; background: ${({ theme }) => theme.background.primary}; border-radius: ${({ theme }) => theme.border.radius.md}; overflow: hidden; max-height: 90vh; z-index: 10000; // should be higher than Backdrop's z-index `; const StyledHeader = styled.div` align-items: center; display: flex; flex-direction: row; height: 60px; overflow: hidden; padding: ${({ theme }) => theme.spacing(5)}; `; const StyledContent = styled.div` display: flex; flex: 1; flex-direction: column; overflow-y: auto; padding: ${({ theme }) => theme.spacing(10)}; `; const StyledFooter = styled.div` align-items: center; display: flex; flex-direction: row; height: 60px; overflow: hidden; padding: ${({ theme }) => theme.spacing(5)}; `; const BackDrop = styled(motion.div)` align-items: center; background: ${({ theme }) => theme.background.overlay}; display: flex; height: 100%; justify-content: center; left: 0; position: fixed; top: 0; width: 100%; z-index: 9999; `; /** * Modal components */ type ModalHeaderProps = React.PropsWithChildren & React.ComponentProps<'div'>; function ModalHeader({ children, ...restProps }: ModalHeaderProps) { return {children}; } type ModalContentProps = React.PropsWithChildren & React.ComponentProps<'div'>; function ModalContent({ children, ...restProps }: ModalContentProps) { return {children}; } type ModalFooterProps = React.PropsWithChildren & React.ComponentProps<'div'>; function ModalFooter({ children, ...restProps }: ModalFooterProps) { return {children}; } /** * Modal */ type ModalProps = React.PropsWithChildren & React.ComponentProps<'div'> & { isOpen?: boolean; onOutsideClick?: () => void; }; const modalVariants = { hidden: { opacity: 0 }, visible: { opacity: 1 }, exit: { opacity: 0 }, }; export function Modal({ isOpen = false, children, onOutsideClick, ...restProps }: ModalProps) { const modalRef = useRef(null); useListenClickOutside({ refs: [modalRef], callback: () => onOutsideClick?.(), mode: ClickOutsideMode.absolute, }); if (!isOpen) { return null; } return ( {children} ); } Modal.Header = ModalHeader; Modal.Content = ModalContent; Modal.Footer = ModalFooter;