Cesar Mendivil e43686e36d feat(modal-parts): add modular components for modal UI
- Introduced ModalDestinationButton for destination selection with customizable icons and labels.
- Added ModalInput for text input with optional character counter.
- Implemented ModalLink for reusable links styled as underlined text.
- Created ModalPlatformCard for platform selection with badges.
- Developed ModalRadioGroup for radio button groups with custom styling.
- Added ModalSection for grouping modal content with optional labels.
- Implemented ModalSelect for dropdown selections with custom styling.
- Created ModalShareButtons for sharing options via Gmail, Email, and Messenger.
- Developed ModalTextarea for multi-line text input with character counter.
- Introduced ModalToggle for toggle switches with optional help text and links.
- Updated README.md with component descriptions, usage examples, and design guidelines.
- Added index.ts for centralized exports of modal components.
2025-11-06 00:32:08 -07:00

77 lines
1.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useRef } from 'react'
import styles from './Modal.module.css'
export interface ModalProps {
open: boolean
onClose: () => void
title?: string
children: React.ReactNode
footer?: React.ReactNode
width?: 'sm' | 'md' | 'lg' | 'xl'
closeOnOverlayClick?: boolean
}
export const Modal: React.FC<ModalProps> = ({
open,
onClose,
title,
children,
footer,
width = 'md',
closeOnOverlayClick = true
}) => {
const dialogRef = useRef<HTMLDialogElement>(null)
useEffect(() => {
const dialog = dialogRef.current
if (!dialog) return
if (open) {
dialog.showModal()
} else {
dialog.close()
}
}, [open])
const handleOverlayClick = (e: React.MouseEvent<HTMLDialogElement>) => {
if (closeOnOverlayClick && e.target === dialogRef.current) {
onClose()
}
}
if (!open) return null
return (
<dialog
ref={dialogRef}
className={`${styles.modal} ${styles[`modal-${width}`]}`}
onClick={handleOverlayClick}
>
<div className={styles.modalContent}>
{/* Header */}
{title && (
<div className={styles.modalHeader}>
<h3 className={styles.modalTitle}>{title}</h3>
<button
type="button"
className={styles.closeButton}
onClick={onClose}
aria-label="Cerrar"
>
×
</button>
</div>
)}
{/* Body */}
<div className={styles.modalBody}>{children}</div>
{/* Footer */}
{footer && <div className={styles.modalFooter}>{footer}</div>}
</div>
</dialog>
)
}
export default Modal