import React, { useCallback, useEffect, useMemo, useRef } from 'react' function hashHtml(value) { let hash = 0 const step = Math.max(1, Math.floor(value.length / 64)) for (let i = 0; i < value.length; i += step) { hash = ((hash << 5) - hash) + value.charCodeAt(i) hash |= 0 } return `${value.length}-${Math.abs(hash)}` } export default function MapFrame({ html }) { const iframeRef = useRef(null) const timersRef = useRef([]) const frameKey = useMemo(() => hashHtml(html || ''), [html]) const clearTimers = useCallback(() => { timersRef.current.forEach((id) => window.clearTimeout(id)) timersRef.current = [] }, []) const recenterFromLayers = useCallback(() => { const iframe = iframeRef.current if (!iframe) return try { const win = iframe.contentWindow const doc = iframe.contentDocument || win?.document if (!win || !doc || !win.L) return const maps = Object.values(win).filter( (item) => item && typeof item.fitBounds === 'function' && typeof item.eachLayer === 'function' && typeof item.invalidateSize === 'function', ) const map = maps[0] if (!map) return map.invalidateSize(true) const bounds = win.L.latLngBounds([]) map.eachLayer((layer) => { try { if (typeof layer.getLatLng === 'function') { const latlng = layer.getLatLng() if (latlng && Number.isFinite(latlng.lat) && Number.isFinite(latlng.lng)) { bounds.extend(latlng) } return } if (typeof layer.getBounds === 'function') { const layerBounds = layer.getBounds() if (layerBounds && typeof layerBounds.isValid === 'function' && layerBounds.isValid()) { bounds.extend(layerBounds) } } } catch { // no-op } }) if (bounds.isValid()) { map.fitBounds(bounds, { padding: [20, 20], maxZoom: 17, animate: false }) } } catch { // no-op } }, []) const scheduleRecenter = useCallback(() => { clearTimers() ;[40, 180, 520, 1100].forEach((delay) => { const timerId = window.setTimeout(() => { recenterFromLayers() }, delay) timersRef.current.push(timerId) }) }, [clearTimers, recenterFromLayers]) useEffect(() => { return () => { clearTimers() } }, [clearTimers]) if (!html) { return