Map-paint gate: walk nested shadow roots so composites are verified, not false-failed

This commit is contained in:
doxa-maps-88655c70 2026-09-20 03:59:56 +00:00
parent 4c27190641
commit 8ed3bbfcbc

View file

@ -89,10 +89,26 @@ for (const url of urls) {
await page.waitForTimeout(15000)
const r = await page.evaluate(() => {
const host = [...document.querySelectorAll('*')].find((e) => e.tagName.includes('-'))
// ★ SHADOW DOM DOES NOT PIERCE — walk NESTED roots recursively (fixed 2026-09-20).
// A cap-4/cap-5 COMPOSITE mounts child custom elements, each with its OWN shadow root,
// so the map canvas lives one (or more) levels DOWN. A single-level
// `shadowRoot.querySelector('canvas')` can never see it and reports a perfectly working
// map as "no canvas". That false negative cost three wrong diagnoses of upg-100-mfe:
// "the Map tab is unwired", then "the pane has zero height" — while live measurement
// through nested roots showed a 1280x800 canvas with a live GL context the whole time.
// Flat leaves were unaffected, which is exactly why the blind spot survived: the gate
// passed the four single-level leaves and only lied about composites.
const deep = (root, sel, out = []) => {
out.push(...root.querySelectorAll(sel))
for (const el of root.querySelectorAll('*')) if (el.shadowRoot) deep(el.shadowRoot, sel, out)
return out
}
const host = [...document.querySelectorAll('*')].find((e) => e.tagName.includes('-') && e.shadowRoot)
const sr = host && host.shadowRoot
if (!sr) return { shadow: false }
const cv = sr.querySelector('canvas')
// Prefer a canvas that actually HAS a GL context, at any depth.
const canvases = deep(sr, 'canvas')
const cv = canvases.find((c) => c.getContext('webgl2') || c.getContext('webgl')) || canvases[0] || null
// Read ONLY user-visible copy: shadowRoot.textContent includes the injected <style>,
// which has produced false "unavailable"/"error" matches before.
const clone = document.createElement('div')
@ -102,10 +118,12 @@ for (const url of urls) {
return {
shadow: true,
canvas: cv ? cv.width + 'x' + cv.height : null,
depth: canvases.length,
// THE load-bearing assertion: a live GL context, not merely a sized canvas.
glContext: cv ? !!(cv.getContext('webgl2') || cv.getContext('webgl')) : false,
// Mapbox only emits attribution once tiles are actually loading.
attribution: /mapbox|openstreetmap/i.test(text),
// Mapbox only emits attribution once tiles are actually loading. Search nested roots too:
// in a composite the attribution control lives beside the canvas, inside the CHILD's root.
attribution: /mapbox|openstreetmap/i.test(text) || deep(sr, '.mapboxgl-ctrl-attrib').length > 0,
asksForToken: /paste|access token|pk\./i.test(text),
}
})