/** * useMapInstance.js — Map Initialization Composable * * Manages a single Mapbox GL map instance lifecycle. * Scoped by mapId — safe to use multiple times on the same page. * * SHADOW DOM NOTES: * * 1. Container ID: Mapbox's `new mapboxgl.Map({ container: 'id' })` uses * document.getElementById() which CANNOT cross shadow boundaries. * Always pass the actual DOM element via a Vue template ref. * * 2. CSS timing: The Mapbox GL CSS loads asynchronously. If Mapbox * initializes before the CSS is applied, _detectMissingCSS fires and the * canvas is sized to 0. This composable injects the CSS into the shadow * root and waits for it to load before creating the Map instance. * * 3. Canvas resize: Even with correct CSS, the canvas may init at the wrong * size if the container layout settles after initialization. map.resize() * is called on the load event to correct this. * * Usage: * const containerRef = ref(null) * const { map, isMapReady, initializeMap, destroy } = useMapInstance({ containerRef, accessToken, ... }) * onMounted(() => initializeMap()) */ import { ref, shallowRef, inject, watch } from 'vue' import { useEdgeScrollAffordance } from './useEdgeScrollAffordance.js' // ─── Engine registry (provider → CDN script + css + global) ────────────────── // The map engine is loaded as a page global (CDN