import markerIconRetinaURL from 'leaflet/dist/images/marker-icon-2x.png'; import markerIconURL from 'leaflet/dist/images/marker-icon.png'; import markerShadowURL from 'leaflet/dist/images/marker-shadow.png'; import 'leaflet/dist/leaflet.css'; import type { Map } from 'leaflet'; interface MapNodeProps { latitude: number; longitude: number; zoom: number; mapboxAccessToken: string; markerMarkup?: string; } async function updateMap( mapElement: HTMLElement, { latitude, longitude, zoom, mapboxAccessToken, markerMarkup = '' }: MapNodeProps ) { const { icon: leafletIcon, map: leafletMap, marker: leafletMarker, tileLayer } = await import('leaflet'); const markerIcon = leafletIcon({ iconSize: [25, 41], iconAnchor: [10, 41], popupAnchor: [2, -40], iconUrl: markerIconURL, iconRetinaUrl: markerIconRetinaURL, shadowUrl: markerShadowURL }); const map = leafletMap(mapElement).setView([latitude, longitude], zoom); tileLayer( 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}{r}?access_token={accessToken}', { attribution: 'Map data © OpenStreetMap contributors, Imagery © Mapbox', maxZoom: 19, id: 'mapbox/streets-v11', tileSize: 512, zoomOffset: -1, accessToken: mapboxAccessToken, detectRetina: true } ).addTo(map); if (markerMarkup !== '') { leafletMarker([latitude, longitude], { icon: markerIcon }).bindPopup(markerMarkup).addTo(map); } else { leafletMarker([latitude, longitude], { icon: markerIcon }).addTo(map); } return map; } export function setMap(mapElement: HTMLElement, mapProps: MapNodeProps) { let map: Map | null = null; (async () => (map = await updateMap(mapElement, mapProps)))(); return { // return update function to be called when props change async update({ latitude, longitude, zoom }: MapNodeProps) { map?.flyTo([latitude, longitude], zoom); } }; }