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 dataBounds = win.L.latLngBounds([]) const isBairroLayer = (layer) => { try { const nome = String(layer?.options?.name || layer?.layerName || '').toLowerCase() if (nome.includes('bairro')) return true const featureName = String(layer?.feature?.properties?.NOME || layer?.feature?.properties?.BAIRRO || '').toLowerCase() return featureName.length > 0 } catch { return false } } map.eachLayer((layer) => { try { if (layer instanceof win.L.TileLayer) return if (isBairroLayer(layer)) return if (layer instanceof win.L.CircleMarker || layer instanceof win.L.Marker) { const latlng = layer.getLatLng() if (latlng && Number.isFinite(latlng.lat) && Number.isFinite(latlng.lng)) { dataBounds.extend(latlng) } return } if (layer instanceof win.L.Rectangle) { const rectBounds = layer.getBounds() if (rectBounds && typeof rectBounds.isValid === 'function' && rectBounds.isValid()) { dataBounds.extend(rectBounds) } return } } catch { // no-op } }) if (dataBounds.isValid()) { const size = map.getSize ? map.getSize() : null const basePadding = size ? Math.max(34, Math.min(84, Math.round(Math.min(size.x, size.y) * 0.085))) : 48 map.fitBounds(dataBounds, { padding: [basePadding, basePadding], maxZoom: 18, 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