import React, { ReactNode, useEffect } from "react"; import { createPortal } from "react-dom"; import { X } from "lucide-react"; import { __ } from "../../lib/i18n"; type ModalSize = "sm" | "md" | "lg" | "xl" | "full"; const sizeClasses: Record = { sm: "max-w-md", md: "max-w-xl", lg: "max-w-2xl", xl: "max-w-4xl", full: "max-w-6xl", }; interface ModalProps { isOpen: boolean; onClose: () => void; title?: ReactNode; description?: ReactNode; children: ReactNode; footer?: ReactNode; size?: ModalSize; maxWidthClassName?: string; panelClassName?: string; bodyClassName?: string; showCloseButton?: boolean; closeOnOverlayClick?: boolean; loading?: boolean; loadingSkeleton?: ReactNode; error?: string | null; errorComponent?: ReactNode; hideHeader?: boolean; hideFooter?: boolean; customZIndex?: number; /** Replaces default `max-h-[70vh] overflow-y-auto custom-scrollbar` on the body wrapper (e.g. full-height previews). */ bodyScrollClassName?: string; } export const Modal: React.FC = ({ isOpen, onClose, title, description, children, footer, size = "xl", maxWidthClassName, panelClassName = "", bodyClassName, showCloseButton = true, closeOnOverlayClick = true, loading = false, loadingSkeleton, error, errorComponent, hideHeader = false, hideFooter = false, customZIndex, bodyScrollClassName, }) => { useEffect(() => { if (!isOpen) { return; } const originalOverflow = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = originalOverflow; }; }, [isOpen]); if (!isOpen) { return null; } const panelWidthClass = maxWidthClassName || sizeClasses[size]; const bodyClasses = bodyClassName ?? "px-6 py-5"; const bodyScrollClasses = bodyScrollClassName ?? "max-h-[70vh] overflow-y-auto custom-scrollbar"; const zIndex = customZIndex || 999999; // Default loading skeleton const defaultLoadingSkeleton = (
); // Default error component const defaultErrorComponent = error ? (

{__("Error", "yatra")}

{error}

) : null; return createPortal(
{ if (closeOnOverlayClick && !loading) { onClose(); } }} />
{!hideHeader && (title || showCloseButton) && (
{title && (

{title}

)} {description && (

{description}

)}
{showCloseButton && ( )}
)}
{loading ? loadingSkeleton || defaultLoadingSkeleton : error ? errorComponent || defaultErrorComponent : children}
{!hideFooter && footer && (
{footer}
)}
, document.body, ); };