The browser's context budget is commonly 8 to 16 and this tree has nineteen
map-bearing profiles, so a reader who visits enough map tabs crosses it. What
the browser does then is the real problem: it kills the OLDEST context silently.
getContext never returns null, nothing fires on the new canvas, and a map that
worked a minute ago is simply blank when you go back to it. The reader who
notices is the one returning to something that used to work.
The pane now says so and offers a reload. That holds under either option on the
Driver's row 107, because it makes the failure visible rather than preventing it.
The listener goes on the canvas itself, not the pane. The map's canvas lives in
the plugin's shadow root and webglcontextlost does not bubble, so a listener on
the pane would never hear it — hence a walk that descends through shadow roots.
It binds after mount and again on every re-activation, because the canvas does
not exist when the element connects and a later one would otherwise go unwatched.
Binding is idempotent and marked per canvas.
Two string defects caught before this went anywhere. I wrote
T('actions.reloadMap'), and the string lives at buttons.reloadMap — it exists in
all eleven locales and my wrong namespace would have rendered English in every
one of them while the correct translation sat unused. And messages.mapContextLost
did not exist at all, which the tr() helper answers with a silent English
fallback. Both now resolve; keys-exist and parity are green.
|
||
|---|---|---|
| .. | ||
| app-wrapper-material | ||
| pane-wrapper | ||
| README.md | ||
| StackLayout.vue | ||
| VerticalTabsLayout.vue | ||
layouts/ — app wrappers
Each folder here is an app wrapper: a host shell that composes doxa-maps plugin-designs (the independently-built custom elements) into one application.
layouts/<wrapper>/ ← the HOST page (not a bundle)
┌──────────┬──────────────────────────────┐
│ sidebar │ mounts an app-profile here │
│ (nav.js) │ ┌──────────────┐ │
│ ├ item │ │ <doxa-map> │ ← a │
│ ├ section│ │ (a bundle) │ micro- │
│ └ folder │ └──────────────┘ frontend │
└──────────┴──────────────────────────────┘
- app-profile = a self-contained custom element (the micro-frontend). app wrapper = the host that mounts them and provides nav/chrome. A wrapper is a host page, not a bundle-in-a-bundle.
- Wrappers today:
app-wrapper-material/,pane-wrapper/. - Icons are inline SVG only (no CDN) — an F-Droid/offline hard requirement.
Sidebar contract, target filtering, sidebar modes, staging: ../documentation/architecture/app-wrappers.md.