doxa-maps/plugin-designs/regions-dashboard
Doxa Maps 07eb74c33c Move four identical bodies into the library
From the fleet census: 620 function bodies indexed across 29 plugin trees,
16 identical in two or more. These are the four cheapest — none closes over
anything beyond its own parameters, so each is a file move plus an import
rather than a new dependency to thread.

hostElement resolves the custom element a component is mounted inside, one
hop out through the shadow root. It was identical in three plugins, and it
is the piece worth sharing for a reason other than line count: every plugin
ships through defineCustomElement, a composite nests two shadow roots, and
code that forgets the hop operates on the wrong node while looking correct.
A document-level query for a node inside a shadow root returns null on a
working build, which reads as a broken feature rather than a wrong query.
Three copies were three chances to write that.

findScrollportAncestor walks up to the nearest ancestor that actually
scrolls, crossing shadow boundaries on the way — parentElement stops at a
root, so a plugin in a custom element would otherwise find no scrollport and
conclude the page does not scroll.

findNodeInTree and buildFlatLegendMatchExpr join useLegendMapBridge, which
already holds four functions from the same seam. They sit at module level
rather than inside the factory because they close over nothing: a pure
function hidden in a closure can only be reached by constructing the whole
bridge.

Call sites keep their old names through a one-line local binding, so no
call changed and the diff is the declaration plus an import.

Rebuild-and-compare, all five affected bundles, before -> after:
  regions-dashboard   1,098,469 -> 1,098,479   +10
  country-posters     1,484,053 -> 1,484,028   -25
  doxa-research-map   1,354,051 -> 1,354,061   +10
  dashboard-plus-grid   915,660 ->   915,644   -16
  big-picture           366,907 ->   366,719  -188
  net -209, and country-posters gains 25 bytes against the 1.5 MB ceiling.
Every behaviour-bearing token counted, not set-compared, and unchanged in
all three map bundles: regions-fill, peoplePraying, engagementStatus,
adoptionStatus, overflowY, scrollHeight, getRootNode, _flat_filter, religion.

Owners cleared their own files first: regions for regions-list.vue, upg100
for countries-map.vue. check:selection-kinds, check:legend-matches-source,
check:legend-data-contract, check:packet-variants, check:no-dead-library and
check:no-cross-plugin-imports all pass.
2026-09-29 09:19:04 +00:00
..
scripts Keep the engineering reason, drop the speaker: 31 Driver references to 0 2026-09-29 03:46:37 +00:00
src Country posters print their list, deck and packet, with the map drawn at the click 2026-09-29 08:07:36 +00:00
dxlife-tokens.js Port their base line-height (1.5); our 1.1 override was compensating for its absence 2026-09-26 05:33:12 +00:00
index.html Regions element gets the Select View tabs, shared with UPG-100 2026-09-23 19:08:00 +00:00
index.js Keep the engineering reason, drop the speaker: 31 Driver references to 0 2026-09-29 03:46:37 +00:00
region-dashboards.meta.json Regions: the selected page is now an exact clone; the chooser is the one addition 2026-09-24 00:59:10 +00:00
region-dashboards.vue Keep the engineering reason, drop the speaker: 31 Driver references to 0 2026-09-29 03:46:37 +00:00
regions-list.meta.json Regions: the selected page is now an exact clone; the chooser is the one addition 2026-09-24 00:59:10 +00:00
regions-list.vue Move four identical bodies into the library 2026-09-29 09:19:04 +00:00
regions-mfe.meta.json Keep the engineering reason, drop the speaker: 31 Driver references to 0 2026-09-29 03:46:37 +00:00
regions-mfe.vue Keep the engineering reason, drop the speaker: 31 Driver references to 0 2026-09-29 03:46:37 +00:00