useLegendMapBridge took the idle paint helper as an injected dependency and called it five times, while each consuming map defined its own copy of the one-line body and handed it over. The library owned the paint logic and not the expression it painted with, so the copies could drift apart silently and the two maps would render the same idle state differently. Export it from the composable instead, and take it from there in this map. The injected parameter is deliberately KEPT for one round: inside the composable the parameter shadows the module export, so what the bridge paints with is still exactly what its callers pass, and this change cannot move behaviour. It is a deletion in the plugin and an addition in the library, nothing more. The parameter goes when the second map has adopted the export too. This map held a THIRD copy under a different name -- a function-scoped helper in the paint prewarm, byte-identical body, used once. It now refers to the library helper. Verified rather than assumed: the library version and both original plugin versions produce identical output for every value the maps actually pass, including the dynamic one. check:region-paint-single-source is green for this map and stays red for the other until it adopts the export, which is the state the gate is meant to report. The second map is the other plugin's file and is not touched here; its owner takes that half. |
||
|---|---|---|
| .. | ||
| api | ||
| charts/whiteboard | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| dashboards | ||
| data | ||
| elements | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| packets | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| vendor/cldr | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.