Commit graph

21 commits

Author SHA1 Message Date
Doxa Maps
7a5d93437f MapInfo hears panel-open on its shadow root when it has no parent element
A MapInfo mounted at the top of a map's own shadow tree has no parentElement, so it attached no listener and a
standalone leaf would have kept the pointer over Share. It now falls back to its root node (the shadow root),
which the panel's event reaches.
2026-10-02 06:14:49 +00:00
Doxa Maps
a143992d0e An opening map panel puts the "What can this map do?" pointer away
On a phone, at first load, the onboarding pointer could sit over the open Share panel and cover its ✕
(cities-with-internet). The pointer can be drawn by the host page, outside the map's shadow root, so no
z-index inside the map can lift a panel above it. Instead, MapControlMenu (Share, and every menu built on it)
announces that it opened with a composed 'dxmaps:panel-open' event, and MapInfo, hearing it on its own
container (so only that map's panels count), hides its pointer; a page-load pointer is then done for this
load, as if its popup had been opened.
2026-10-02 06:08:51 +00:00
Doxa Maps
69cfb5e4d9 The header ⓘ's pointer keeps the measured 1200px rule: in a tab's top strip it covered the view switcher
A control in a map's own column keeps its pointer at every width; a header-form control (the
rounded-square MapControlButton) sits in the strip the rule was measured on, so below 1200px its
pointer hides again. Rebuilt doxa-maps-spa and doxa-simple-map (MapInfo's importers), tree and SRI.
2026-09-30 10:57:02 +00:00
Doxa Maps
c2131fe1c5 The ⓘ panel leads with the map's short description, and the strategy opens on request
At the top of every "What can this map do?" panel: a "Short description" header and the map's
intro, on a pale band with the Rudder blue as its accent bar and the text in a darker shade of that
blue (5.6:1), so the eye finds it first. Below it, the strategy is a collapsed "Strategy ▾" disclosure
(a native details element, collapsed again on every open) instead of a tab; the examples follow
wherever a map has them. The tab machinery goes. New label mapInfo.shortDescription in all 11
locales.
2026-09-30 09:26:58 +00:00
Doxa Maps
7646e222fe The "What can this map do?" button shows a question mark, not an (i)
The map's attribution control is a round (i) as well, and two identical glyphs on one map read as the
same thing. Both copies of the glyph change: MapInfoButton (the map control and the dashboard header
button) and MapInfo's floating fallback button.
2026-09-30 08:21:16 +00:00
Doxa Maps
5fbe2829e1 The ⓘ strategy tabs follow the ARIA tabs pattern: a tabpanel, and arrow keys between the tabs
The panel is role=tabpanel, labelled by the selected tab; each tab names it with aria-controls. Only the
selected tab is in the tab order, and Left/Right switch tabs with focus following.
2026-09-30 08:16:35 +00:00
Doxa Maps
9b39577830 The ⓘ panel shows each map's strategy: an intro, then the strategy, with Examples | Strategy tabs where a map has examples
MapInfo gains a `strategyKey` prop: a catalogue key prefix whose .bottom is the bottom line and .p1, .p2 … the
points, read in order until the first missing one (the catalogue decides how many). The popup shows the intro
(the lead), then:
- a map with examples AND a strategy gets two tabs, Examples first, then Strategy (44px targets, reset to
  Examples on every open);
- a map with only a strategy goes straight to it, under a Strategy heading;
- a map with neither is unchanged.
The takeaway is not shown beside a strategy, which supersedes it. Labels come from mapInfo.tabExamples and
mapInfo.tabStrategy. Prayer Progress's own info (for embeds) names its strategy key too.
2026-09-30 08:04:11 +00:00
Doxa Maps
d03b24e613 Prayer Progress carries its own "What can this map do?", so the ⓘ works wherever the map is embedded
On a partner page or a standalone preset page the ⓘ control rendered nothing, because only the
gallery answered it and the ⓘ's text lived in the gallery's settings. Now the map carries its info
(plugin-designs/doxa-simple-map/src/mapInfo.js) and a host only adds placement:

- MapInfoButton gains an opt-in `standalone` prop. When no host answers and the map carries info, it
  asks the map for a popup of its own (the 'standalone' event). If a real host appears later, the
  map's popup is dropped and the host takes over. Never inside the gallery (its panes carry
  data-doxa-gallery): there the gallery alone decides, its own info:false included.
- MapInfo gains `popupOnly` (with trigger 'control'): no floating button, since the map's control is
  the only button; it answers that control from inside the map, points at it once per page load,
  and opens the same popup (the bottom sheet on phones). It announces itself as local, so the
  control can tell it from a real host.
- Prayer Progress mounts that popup beside its control column, only when asked.

Per preset: the text describes the prayer map, so a map that shows the Prayer tab has info (the full
profile and the prayer preset); the engagement-only and adoption-only presets have none and show no
ⓘ, as before. A host's profile-config info:false removes the ⓘ. Every other MapInfoButton consumer
is unchanged (standalone is off by default).

doxa-simple-map grows by 20,590 bytes raw (5,699 gzipped), for compiling MapInfo. Rebuilt
doxa-simple-map and doxa-maps-spa, then tree + SRI.
2026-09-30 06:15:11 +00:00
Doxa Maps
c3523ae1fc The ⓘ panel on a phone is a bottom sheet over the map, not a full white page
On phones (up to 767px) the "What can this map do?" panel opened as a full-screen page: a few
lines of text at the top of an empty white screen, reading as a new page rather than a panel.
It is now a bottom sheet:

- it sizes to its content, up to 70% of the small viewport (svh, so a collapsing URL bar does not
  resize it), and scrolls inside, with its scroll kept to itself;
- the close button is 44px and stays in view in the sheet's header;
- the dimmed map above it stays visible, and a tap there closes the panel, as Escape does.

Desktop is unchanged. Rebuilt doxa-maps-spa (the only bundle that compiles MapInfo.vue), then
tree + SRI.
2026-09-30 05:35:46 +00:00
Doxa Maps
3d462ec308 The ⓘ control's pointer: once per page load, gone after a click or a tab change, no checkbox
Every map whose ⓘ is its own control (MapInfo trigger 'control') now gets the same pointer:
it shows the first time that control is on screen in a page load, and goes for the rest of the
load once the reader opens the popup or leaves the tab. A full reload shows it again. This is
page-load memory, never storage, so the popup offers no checkbox in control mode: the "Keep
tooltip turned on" box and its string (all 11 locales) are removed, along with the pointerKeep
prop that selected this model per tab. Floating-mode maps keep their stored model and their
"don't point again" box, unchanged.

Leaving the tab is read from the pane (hidden or inert), on the control's intersection change
and the existing 1.5 s measurement tick.

Rebuilt doxa-simple-map (it ships the mapInfo catalogue) and doxa-maps-spa, then tree + SRI.
2026-09-30 04:41:04 +00:00
Doxa Maps
d7b496c6b1 Prayer Progress tells the gallery its ⓘ is coming, so the floating one never flashes on a slow load
Prayer Progress draws its control column only once the style and the people-group data are in,
which on a slow phone can take longer than any fixed wait, and then the gallery's floating ⓘ
appeared and was swapped for the control. Now the map announces at mount that a control is on its
way ('dxmaps:mapinfo-pending'), and MapInfo waits for the map instead of a clock.

- A known failure (the map reports an error) or an unmount before the map is ready withdraws the
  announcement, and the floating ⓘ shows at once.
- While a control is pending, the 30 s wait becomes a 90 s backstop (time on screen), so an
  unreported failure still gets a floating ⓘ.
- A map that never announces anything keeps the 30 s wait, and pages with no MapInfo are unchanged.

Rebuilt doxa-simple-map and doxa-maps-spa, then tree + SRI.
2026-09-30 04:32:55 +00:00
Doxa Maps
3b933aefd4 Prayer Progress: round, spaced controls again, and no floating ⓘ while the map loads
The control column goes back to the library's round, spaced buttons at every width; the square
grouped card read too compact, on phones most of all. The ⓘ stays the top control.

In control mode, MapInfo no longer shows its floating button before the map's control has
announced itself. The map draws its column only once it is ready (style and people-group data),
so the floating ⓘ appeared for a moment and was then replaced by the control. The wait is bounded
at 30 s of time on screen, counted only while the pane is visible and not inert: measured column
arrival times run from 7 to 19 s on a local serve, so a shorter wait expired inside a normal load
and flashed late. If no control arrives, the floating button shows, so there is still always a way
to open the popup. Once a control has announced itself, measurement alone decides, as before.

MapInfo's plain <script> block (the page-load pointer memory) now sits above <script setup>, so
check:setup-order no longer reads it as used before its definition; its explanation moves into
<script setup> so the library index keeps the component's own description. Compiled output is
unchanged by the move.

Rebuilt doxa-simple-map and doxa-maps-spa (the only bundle that compiles MapInfo.vue), then
tree + SRI.
2026-09-30 04:17:28 +00:00
Doxa Maps
fa01a77799 Prayer Progress's pointer: once per page load, and "Keep tooltip turned on"
- pointerKeep maps (Prayer Progress only) point ONCE PER PAGE LOAD: the pointer shows the first time
  the map is on screen in a load. Opening the popup hides it for the rest of that load, and the next
  full load shows it again. The memory is a module-scope Set (pointerDoneThisLoad), because the gallery
  remounts a heavy tab's MapInfo on every switch back. It is marked when the pointer is on screen, not
  on mount. Nothing about it is persisted any more (no seen write in show() or hide()).
- The keep box (still stored, per map) keeps the pointer after the popup closes and on every
  appearance. A page-load pointer ignores the every-map off switch, which is not offered beside it.
- The label is "Keep tooltip turned on" (en), with de retuned to match; the other nine already say
  "keep ... on".
- Rebuilt doxa-simple-map and doxa-maps-spa, then tree and fix:sri.
2026-09-30 03:46:30 +00:00
Doxa Maps
48a1a747ba Prayer Progress: "What can this map do?" is the top of its own control column
- Prayer Progress's column becomes the engine's square grouped card (controls="square"). Its first
  control is MapInfoButton, which opens the gallery's MapInfo for the tab. The gallery's tabInfo
  'prayer-map' entry now uses trigger 'control', so the floating button hides while that control is
  on screen, and shows again (fail-open) whenever it is not.
- MapInfo, control mode: the first-visit pointer now points at the control. Its place is measured
  against the pane (which scrolls) and goes on the control's physical inner side, so an Arabic page,
  whose column mirrors to the left, gets the pointer on the right with the arrow reversed. It shows at
  every width: the under-1200px rule was measured for the floating pointer crossing each tab's top
  strip, and does not apply here.
- MapInfo, pointerKeep (prayer-map only): the popup offers "Keep tooltip activated" instead of the
  every-map "don't point again" box. It is off by default, and opening the popup retires the pointer.
  Checked, the pointer keeps showing on every load. It is stored per map.
- mapInfo.keepPointer in all 11 locales.
- Rebuilt doxa-simple-map and doxa-maps-spa, then tree and fix:sri.
2026-09-30 03:31:15 +00:00
Doxa Maps
b4664aa67e MapInfo can answer a map-control info button (MapInfoButton), fail-open
The "what can this map do for you?" button can now live IN a map's control
column instead of floating over it. This is the bridge only: nothing changes
until a map adds the control and its gallery tab sets trigger: 'control'.

- map-controls/MapInfoButton.vue (new): a MapControlButton with the info
  icon and the localized mapInfo.open label. Clicking it sends a bubbling,
  composed 'dxmaps:mapinfo-open' event out of the plugin's shadow root to
  the gallery pane. On mount it asks 'dxmaps:mapinfo-control' and shows
  ONLY if a MapInfo on the same pane answers (ack), so a standalone leaf or
  a partner page never shows a button that opens nothing. A MapInfo that
  mounts later broadcasts 'dxmaps:mapinfo-host' and the button asks again.
- info/MapInfo.vue: new prop trigger, 'floating' (default, unchanged) |
  'control'. In control mode it listens on its own pane: it acts only on
  events whose composedPath contains the pane, and stops them there. Its own
  floating button and pointer hide ONLY while the announced control is
  MEASURED usable: connected, a non-zero on-screen rect, and in no
  inert/aria-hidden subtree. It is re-measured by IntersectionObserver and
  ResizeObserver plus a 1.5 s fallback timer, never inferred from an unmount
  event. Escape and close return focus to the control when it is on screen,
  else to the floating button. aria-expanded is kept on the control.

Proved on a UPG-100 pilot served locally (gallery page, 1440, MapLibre and
Mapbox, en and ar), exactly one info button on screen at every step:
wall 1 floating; Map 1 control (it wins its hit test and sits inside the
toolbar column); opened from the control, Escape closes it with focus back
on the control; toolbar hidden 1 floating, shown again 1 control; tab away
and back 1; back to the wall 1 floating. 0 page errors. That pilot's wiring
is not in this commit.
2026-09-30 03:11:40 +00:00
Doxa Maps
b86dcc3df2 MapInfo's backdrop sits above every map's own top layer, so no pin hint floats over the dialog
PinHint's first-visit pill sits at z-index 2147482000, so with MapInfo's scrim at 1000 the pill floated
bright and clickable over the dimmed backdrop while the popup was open (gospel; measured on the live
build: the pill's centre hit the pill, not the scrim, on Cities). The scrim goes to 2147483000; the
dialog is its child, inside the scrim's stacking context, so it stays on top of the scrim. The root fix
is the top layer (<dialog>.showModal()), carded.
2026-09-29 23:45:35 +00:00
Doxa Maps
3b0fb958e1 MapInfo: the one-time nudge is desktop-only, at a measured threshold
The "What can this map do?" pointer is anchored beside the ⓘ and extends ~213px
INWARD, across whatever the tab puts in its top strip. Worst overlap per width,
measured on Deep Research on the shared browser, on 99c22caf7:

     390   Regions "Region Dashboards" 1416px^2   UPG-100 1428px^2
     768   Cities legend 6560   Gospel legend 6560 + input 6240   Regions 4200
     900   Cities legend 2432   Gospel legend 2496 + input 2176   Regions 3696
    1024   Cities CLEAN         Gospel CLEAN                      Regions 2100
    1200   CLEAN                CLEAN                             CLEAN
    1440   CLEAN                CLEAN                             CLEAN

★ IT IS NOT A PHONE PROBLEM, which is how it was first reported and how I first
fixed it. It persists to 1024 and only clears near 1200, so the max-width:600px
version I wrote first would have left 768, 900 and 1024 broken on four tabs.
Two things found that: gospel counted PANELS (.gm-legend/.gm-sheet) as well as
controls -- a control-only probe misses a legend entirely -- and upg100 measured
the same shape on their own tab (768 over "Prayer Resources" and "Map", 1024 over
"Map", clear at 1200+), in en and ar.

★ ARABIC IS MEASURED, not argued. My first attempt used ?lang=ar, which does not
switch the locale -- the page stayed dir=ltr and I reported that run as invalid
rather than as an ar pass. Via DX Life's /ar/ route (dir=rtl confirmed) the
pointer is hidden and clean at 390, 768 and 1024, and at 1440 it mirrors to the
start side (x=104) and is clean there too.

★ TWO OTHER SHAPES WERE MEASURED FIRST AND BOTH WERE WORSE. Stacking it below the
button traded one collision for five: Gospel's "Resources found" chip (2010px^2)
plus the zoom +/- of Prayer Progress, Big Picture and Simple Research. Hiding
only its text shrank it to 30px but still left 675px^2 on "Region Dashboards" and
900px^2 on Gospel's search input.

⚠ NOT A PLACEMENT CHANGE, and an earlier draft of this got it wrong. It also
pinned the button's inline side at narrow widths; studio's pos.narrow values have
since landed and the buttons now sit at x=8, 12, 294 and 346 across the seven
tabs at 390. A pinned inset-inline-* here wins by specificity and would have
silently flattened every one of them. The button is placement's business; this
rule is only about the hint. 0 added lines declare --map-info-side; 0 touch
.mi-btn.

Its own block rather than the existing 600px one, which also full-screens the
dialog and has nothing to do with this.

VERIFIED AFTER THE CHANGE, en and ar: pointer hidden and 0 overlaps at 390, 768
and 1024 on Cities, Gospel, Regions and UPG-100; present and clean at 1200 and
1440.

NOT FIXED HERE: at 1440 Big Picture's pointer lies over the Religion filter by
1050px^2. Stacking it below the button there does not clear it -- it relocates it
to "Adopted" 561 + "1%" 425. The only single rule that clears that too is hiding
the pointer at every width, which deletes the affordance where it does fit. So
BP-1440 wants a per-tab placement value or a known-minor ruling; it is
pointer-events:none, so the filter still opens.
2026-09-29 22:45:49 +00:00
Doxa Maps
8b8f1fda79 The info button sits at the END of the line, so Arabic mirrors it
The button and its pointer were placed with a physical right:12px, so on an
Arabic page, where a tab bar starts at the right, they covered the first
(active) tab. They now use inset-inline-end / inset-inline-start (LTR is
unchanged), and under dir=rtl the pointer's arrow glyph and its nudge are
flipped so it still points and moves toward the button. --map-info-top and
--map-info-side remain the per-tab overrides.
2026-09-29 21:08:13 +00:00
Doxa Maps
d38e066ce2 The info popup's stacked-pages hint is visible
The shadow card behind a packet's first page sits at z-index:-1; without a
stacking context of its own it was painted under the dialog's white
background and never seen. isolation:isolate on the stack keeps it just
behind the page.
2026-09-29 21:04:26 +00:00
Doxa Maps
c6f9e11427 The info popup keeps Tab inside it, as aria-modal promises
Tab from the last control wraps to the first, and Shift+Tab from the first
to the last, reading the focused element from the shadow root.
2026-09-29 19:22:10 +00:00
Doxa Maps
93f809ebcd A map explains itself: an info button, a one-time pointer and an example popup
MapInfo (library/components/info) answers "what can this map do for
you?" with real output the map makes, pre-generated so it opens at once.
The examples are an ordered list of kinds rather than a fixed set,
because maps make different things: an image (a poster), pages (a packet
that shows its first page and expands to every page), a deck (cards that
expand from a stack to a grid) and a table (a real excerpt of the
spreadsheet a map exports, with translatable headers). An example whose
image is missing drops out quietly: no broken-image icon, no empty frame.

The pointer at the button goes for good once that map's popup has been
opened and closed; a checkbox in the popup turns it off on every map.
Both are kept in localStorage behind a guard, so private browsing cannot
break the page. On a phone the popup takes the whole screen; Escape
closes it and focus returns to the button. The pointer's motion stops
under prefers-reduced-motion.

All of its text is one new catalogue area, 'mapInfo', in all eleven
locales: the component's own words, and each map's lead, takeaway and
note as mapInfo.tab.<tabId>.<field>. One area because a bundle ships only
the areas its source names, and the gallery that mounts a popup per map
names none of the maps' own areas. This commit carries the UPG-100
map's two sentences; the other maps' follow.
2026-09-29 19:08:02 +00:00