import * as maplibregl from 'maplibre-gl' import { useEffect, useState, type MutableRefObject, type ReactNode } from 'react' import { Loader2Icon } from 'lucide-react' import { MdClose, MdFullscreen } from 'react-icons/md' import { useLang } from '../i18n/lang' import type { MapStatus } from './types' type MapViewportProps = { containerRef: MutableRefObject /** نمونه‌ی نقشه — فقط برای هم‌گام‌سازی اندازه؛ مالکیتش با useMapLibre است */ map: maplibregl.Map | null status: MapStatus onRetry: () => void /** برچسب دسترس‌پذیری ناحیه‌ی نقشه */ label: string /** ارتفاع/فاصله‌ها از بیرون — مثل «h-[520px]» */ className?: string /** محتوای شناور روی نقشه (پورتال پاپ‌آپ) */ children?: ReactNode } /** * پوسته‌ی نقشه — قاب شیشه‌ای، حالت تمام‌صفحه، کنترل بزرگ‌نمایی و لایه‌های * بارگذاری/خطا. * * ظرف نقشه در جریان عادی و با ارتفاع ۱۰۰٪ والد می‌نشیند (نه absolute)؛ * استایل خود مپ‌لیبر بعد از تیلویند بار می‌شود و position: relative می‌دهد، * پس کلاس absolute بی‌اثر می‌شد و ظرف صفر می‌ماند. * * در تمام‌صفحه فقط شفافیت و گوشه‌ها انیمیت می‌شوند تا بافر بوم هرگز کشیده * و تار نشود؛ تغییر اندازه در همان فریم اعمال می‌شود. */ export function MapViewport({ containerRef, map, status, onRetry, label, className = '', children, }: MapViewportProps) { const { t } = useLang() const [isFullscreen, setIsFullscreen] = useState(false) /** تمام‌صفحه: Esc برای خروج و قفل اسکرول پس‌زمینه */ useEffect(() => { if (!isFullscreen) return const onKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') setIsFullscreen(false) } window.addEventListener('keydown', onKeyDown) const previousOverflow = document.body.style.overflow document.body.style.overflow = 'hidden' return () => { window.removeEventListener('keydown', onKeyDown) document.body.style.overflow = previousOverflow } }, [isFullscreen]) /** پس از پایان انتقال، بوم را هم‌گام کن (مپ‌لیبر خودش هم ResizeObserver دارد) */ useEffect(() => { if (!isFullscreen) return const timer = window.setTimeout(() => map?.resize(), 340) return () => window.clearTimeout(timer) }, [isFullscreen, map]) const shellClass = isFullscreen ? 'fixed inset-0 z-[75] h-[100dvh] w-screen animate-[luxFadeIn_0.25s_ease-out] rounded-none border-0' : `relative h-full min-h-[280px] w-full rounded-3xl border border-ivory/10 shadow-lift ${className}` return (
{/* ظرف نقشه در جریان عادی و با ارتفاع ۱۰۰٪ والد است؛ کلاس relative صریح است تا هم بستر موقعیت‌یابی فرزندان مپ‌لیبر باشد و هم هشدار «container has a non-static position» و محاسبه‌ی اشتباه آفست اسکرول رخ ندهد — ترتیب بار شدن CSS هیچ‌وقت تعیین‌کننده نباشد */}
{isFullscreen ? ( ) : ( )} {status !== 'ready' && (
{status === 'loading' ? ( <>
)} {children}
) }