diff --git a/plugin-designs/doxa-research-map/research-map.vue b/plugin-designs/doxa-research-map/research-map.vue index 74bd0eff8..e593682e4 100644 --- a/plugin-designs/doxa-research-map/research-map.vue +++ b/plugin-designs/doxa-research-map/research-map.vue @@ -3035,14 +3035,23 @@ onMounted(async () => { console.error('[research-map] data load failed:', err) return { normalizedPeopleGroups: [] } }) + // ★ A PANE RELEASED WHILE ITS MAP IS STILL STARTING IS A CANCEL, NOT A FAILURE. When the reader + // switches tab, the gallery releases this element. initializeMap then returns SILENTLY (see + // useMapInstance's liveness checks) and leaves map.value null. This handler reported that as "Map + // failed to initialize — check token and container", so a console ERROR landed in whichever tab was + // open by then and blamed the token for a tab switch (measured 2026-09-29, a phone in Arabic, + // 2 runs in 3). The pane is gone, so nobody is waiting for a map: return quietly. + const released = () => !mapContainer.value || !mapContainer.value.isConnected try { await initializeMap() } catch (err) { + if (released()) return // `new mapboxgl.Map()` throws outright when the device has no WebGL context. console.error('[research-map] Map failed to initialize —', err) mapError.value = String(err?.message || err) return } + if (released()) return // Keep the Mapbox Map OUT of Vue's reactive Proxy. useMapInstance holds it in a plain // ref() (deep-reactive): every internal read/write inside Mapbox then pays the Proxy // get/set trap, and a render scheduled through the Proxy (any map.value.* call →