Commit graph

3 commits

Author SHA1 Message Date
doxa-maps-88655c70
e390454d31 Map controls: restore the keyboard focus ring that outline:none removed
The brief says of the no-selection chooser: "Keep the dropdowns as the
keyboard/screen-reader path." Pin clicking is mouse-only by
construction, so that path is load-bearing — and nothing had ever
pressed Tab. There was zero keyboard coverage across 42 probes.

The path itself is sound, and is now asserted: 30 distinct focus stops;
the chooser's region keys are real focusable buttons and Enter on one
selects it ("All Regions" to "Africa") with no mouse involved; the
SELECT VIEW strip carries role=tab on both buttons with exactly one
aria-selected.

The defect that fell out: of those 30 stops, 29 showed a 2px ring and
one showed outline:none — button.mcb, the shared MapControlButton. Its
line 38 sets outline:none deliberately, to kill the webkit focus box on
click/tap alongside -webkit-tap-highlight-color, but it had no
:focus-visible replacement. So a sighted keyboard user tabbing onto ANY
map control in ANY bundle saw nothing at all. The accessible name was
already correct (aria-label mirrors title, fixed 2026-09-21), so screen
readers were never affected — only the people who navigate by eye and
keyboard, which is the very group outline:none was written for.

The fix is a :focus-visible rule plus a .dark variant. :focus-visible
is the correct half of the pair: it never fires for a mouse click, so
the original reason for outline:none still holds. Consumers re-checked
per RULE 2 — ShareButton, ZoomIn, ZoomOut, Fullscreen, Help,
ThemeToggle, Location, map-controls/index.js, my-upg-100-list and
research-dashboard's DashboardDataTable — all render the button
icon-only and none styled focus themselves, so the rule only adds a
ring where there was none. All five affected bundles rebuilt.

Proven both ways: Tab gives solid 2px rgb(26,115,232) with
:focus-visible true and the "Share" label intact; a real mouse click on
a fresh page gives outline:none with :focus-visible false.

Three of my own errors on the way, each caught before it shipped. I
first read a region key's name as "Africa315" and nearly fixed a
non-bug — the button already carries aria-label="Open the Africa
dashboard", which wins over textContent, and the label and count have a
real 7.5px flex gap. I put backticks in a CSS comment inside a template
literal, which ended the string and broke four of five builds;
check:sfc-parse caught it at once. And my mouse assertion failed twice
on correct behaviour: synthetic PointerEvents with a manual focus() do
not update the browser's pointer-modality heuristic, and clicking the
button that had just held keyboard focus leaves the page in keyboard
modality. Only a fresh page with no key ever pressed is a clean test.

Regression: 22 suites green at the time of commit, including new
keyboard and focus-ring suites.
2026-09-24 08:14:01 +00:00
doxa-maps-88655c70
a5c5cf1910 give every map control an accessible name
The zoom buttons render an icon through a slot and carried only `title`, so their
accessible name was empty: a screen reader announced "button" with no indication of what
it does. title is a tooltip, not an accessible name — unreliably announced, and never
surfaced to touch users.

Found while proving the research-dashboard zoom controls actually work. They do: a click
triggered six tile requests at zoom level 2, so the open-work item is function-verified,
not just present. The probe that matched aria-label found nothing while the probe that
fell back to title found both buttons, and that discrepancy was the defect.

One binding in the shared MapControlButton reaches all eight control buttons — zoom in
and out, fullscreen, location, help, share, hamburger, theme — across seven map bundles,
because every one composes this base. No caller changes: the component does not set
inheritAttrs:false, so a caller passing its own aria-label still wins through normal
fallthrough, and undefined omits the attribute when there is no title to mirror.

Verified across all seven bundles: 34 control buttons, 0 without an accessible name.
2026-09-21 13:02:56 +00:00
doxa-maps
d5ba21fa76 doxa-maps — portable bundler for embeddable JAMstack maps
Standalone repo that builds embeddable JAMstack map bundles (web components),
composes them into a lazy-loaded SPA via layouts/, and optionally wraps a
Capacitor Android/iOS app — one build, choose your output/CDN. Diátaxis docs.

History reset to a single clean commit; no PII, IPs, or internal terms.
2026-09-10 01:53:07 +00:00