creacion de componentes dinamicos

This commit is contained in:
Miguel Ortega committed 2026-08-26 15:56:14 -05:00
1 parent ae415fef4e
commit d74aa50845
13 files changed
+1448

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
import React, { useEffect } from 'react';
import { FiX } from 'react-icons/fi';
export interface ModalProps {
isOpen: boolean;
onClose: () => void;
title?: React.ReactNode;
description?: React.ReactNode;
size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
children: React.ReactNode;
footer?: React.ReactNode;
closeOnOverlayClick?: boolean;
showCloseButton?: boolean;
className?: string;
}
const sizeStyles = {
sm: 'max-w-md',
md: 'max-w-lg',
lg: 'max-w-2xl',
xl: 'max-w-4xl',
'2xl': 'max-w-6xl',
full: 'max-w-[95vw] h-[90vh]',
};
export const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
title,
description,
size = 'md',
children,
footer,
closeOnOverlayClick = true,
showCloseButton = true,
className = '',
}) => {
// ESC key handler and body scroll lock
useEffect(() => {
if (!isOpen) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
};
const originalOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
window.addEventListener('keydown', handleKeyDown);
return () => {
document.body.style.overflow = originalOverflow;
window.removeEventListener('keydown', handleKeyDown);
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
role="dialog"
aria-modal="true"
className="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6 overflow-y-auto"
>
{/* Backdrop */}
<div
onClick={() => {
if (closeOnOverlayClick) onClose();
}}
className="fixed inset-0 bg-slate-950/70 backdrop-blur-md transition-opacity animate-fadeIn"
/>
{/* Modal Dialog Card */}
<div
className={`
relative w-full rounded-3xl overflow-hidden shadow-2xl z-10
bg-white text-slate-900 border border-slate-200
dark:bg-slate-900/95 dark:text-slate-100 dark:border-slate-800
transition-all transform animate-scaleUp
${sizeStyles[size]}
${className}
`}
>
{/* Header */}
{(title || description || showCloseButton) && (
<div className="flex items-start justify-between p-6 pb-4 border-b border-slate-100 dark:border-slate-800/80">
<div className="space-y-1 pr-6">
{title && (
<h2 className="text-xl font-bold text-slate-900 dark:text-white tracking-tight">
{title}
</h2>
)}
{description && (
<p className="text-xs sm:text-sm text-slate-500 dark:text-slate-400">
{description}
</p>
)}
</div>
{showCloseButton && (
<button
type="button"
onClick={onClose}
aria-label="Cerrar modal"
className="p-2 rounded-xl text-slate-400 hover:text-slate-700 hover:bg-slate-100 dark:hover:text-slate-200 dark:hover:bg-slate-800 transition-colors"
>
<FiX className="text-lg" />
</button>
)}
</div>
)}
{/* Body Content */}
<div className="p-6 overflow-y-auto max-h-[calc(85vh-160px)]">
{children}
</div>
{/* Footer */}
{footer && (
<div className="p-6 pt-4 border-t border-slate-100 dark:border-slate-800/80 bg-slate-50/50 dark:bg-slate-950/40 flex items-center justify-end gap-3">
{footer}
</div>
)}
</div>
</div>
);
};