UNPKG

eventx-design-system

Version:
132 lines (128 loc) 4.22 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect } from 'react'; import { createPortal } from 'react-dom'; import styled, { css } from 'styled-components'; import { colors, spacing, borderRadius, shadows, transitions, zIndex } from '../tokens/design-tokens'; // Overlay do modal const Overlay = styled.div ` position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: ${zIndex.modal}; opacity: ${({ isOpen }) => (isOpen ? 1 : 0)}; visibility: ${({ isOpen }) => (isOpen ? 'visible' : 'hidden')}; transition: all ${transitions.duration[300]} ${transitions.easing.inOut}; padding: ${spacing[4]}; `; // Container do modal const ModalContainer = styled.div ` background-color: ${colors.neutral[50]}; border-radius: ${borderRadius.xl}; box-shadow: ${shadows['2xl']}; max-width: 90vw; max-height: 90vh; overflow: hidden; transform: ${({ isOpen }) => (isOpen ? 'scale(1)' : 'scale(0.95)')}; transition: all ${transitions.duration[300]} ${transitions.easing.inOut}; display: flex; flex-direction: column; ${({ size }) => { switch (size) { case 'sm': return css `width: 400px;`; case 'lg': return css `width: 600px;`; case 'xl': return css `width: 800px;`; default: return css `width: 500px;`; } }} `; // Header do modal const ModalHeader = styled.div ` display: flex; align-items: center; justify-content: space-between; padding: ${spacing[6]} ${spacing[6]} ${spacing[4]}; border-bottom: 1px solid ${colors.neutral[200]}; `; const ModalTitle = styled.h2 ` margin: 0; font-family: inherit; font-size: 1.25rem; font-weight: 600; color: ${colors.neutral[950]}; `; const CloseButton = styled.button ` background: none; border: none; font-size: 1.5rem; cursor: pointer; color: ${colors.neutral[500]}; padding: ${spacing[1]}; border-radius: ${borderRadius.base}; transition: all ${transitions.duration[200]} ${transitions.easing.inOut}; display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; &:hover { background-color: ${colors.neutral[100]}; color: ${colors.neutral[700]}; } &:focus { outline: 2px solid ${colors.brand.primary[500]}; outline-offset: 2px; } `; // Body do modal const ModalBody = styled.div ` padding: ${spacing[6]}; overflow-y: auto; flex: 1; `; // Footer do modal const ModalFooter = styled.div ` display: flex; align-items: center; justify-content: flex-end; gap: ${spacing[3]}; padding: ${spacing[4]} ${spacing[6]}; border-top: 1px solid ${colors.neutral[200]}; background-color: ${colors.neutral[50]}; `; export const Modal = ({ isOpen, onClose, title, children, size = 'md', closeOnOverlayClick = true, closeOnEscape = true, className, ...props }) => { useEffect(() => { const handleEscape = (event) => { if (event.key === 'Escape' && closeOnEscape) { onClose(); } }; if (isOpen) { document.addEventListener('keydown', handleEscape); document.body.style.overflow = 'hidden'; } return () => { document.removeEventListener('keydown', handleEscape); document.body.style.overflow = 'unset'; }; }, [isOpen, onClose, closeOnEscape]); const handleOverlayClick = (event) => { if (event.target === event.currentTarget && closeOnOverlayClick) { onClose(); } }; if (!isOpen) return null; const modalContent = (_jsx(Overlay, { isOpen: isOpen, onClick: handleOverlayClick, children: _jsxs(ModalContainer, { isOpen: isOpen, size: size, className: className, ...props, children: [(title || closeOnOverlayClick) && (_jsxs(ModalHeader, { children: [title && _jsx(ModalTitle, { children: title }), _jsx(CloseButton, { onClick: onClose, "aria-label": "Fechar modal", children: "\u00D7" })] })), _jsx(ModalBody, { children: children })] }) })); return createPortal(modalContent, document.body); }; Modal.displayName = 'Modal';