Wall of People Groups: focus returns to the wall when a dialog closes, and the map pin hint stays off the wall
This commit is contained in:
parent
ef7325990a
commit
bee12baea0
4 changed files with 14 additions and 2 deletions
|
|
@ -122,6 +122,7 @@ export default {
|
|||
if (this._wc) { this._wc.setWorld(this.canvasWidth, this.canvasHeight); return; }
|
||||
this._wc = new WallCanvas(this.$refs.canvas, {
|
||||
worldW: this.canvasWidth, worldH: this.canvasHeight,
|
||||
label: this.$t('wall.title'),
|
||||
spacing: this.cardSpacing, vSpacing: this.cardVerticalSpacing,
|
||||
labels: (k, p, n) => (n === undefined ? this.$t(k, p) : this.$t(k, p, n)),
|
||||
prayCount: (d) => Number(d.peoplePraying || 0) + (this.$store?.prayers?.[d.ID] || 0),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ const FOCUSABLE = 'button:not([disabled]),[href],input:not([disabled]),textarea:
|
|||
export function trapDialog(container, onClose) {
|
||||
if (!container) return () => {}
|
||||
const root = container.getRootNode ? container.getRootNode() : document
|
||||
const prev = root.activeElement || document.activeElement
|
||||
// The opener: the element that had focus, or (a click on a non-focusable surface leaves <body>)
|
||||
// the wall's canvas, so focus has somewhere sensible to come back to.
|
||||
let prev = root.activeElement || document.activeElement
|
||||
if (!prev || prev === document.body) prev = (root.querySelector && root.querySelector('canvas.wall-canvas-el')) || prev
|
||||
const focusables = () => [...container.querySelectorAll(FOCUSABLE)]
|
||||
const onKey = (e) => {
|
||||
if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); onClose(); return }
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ export class WallCanvas {
|
|||
this.canvas = document.createElement('canvas')
|
||||
this.canvas.className = 'wall-canvas-el'
|
||||
this.canvas.style.cssText = 'display:block;width:100%;height:100%;touch-action:none'
|
||||
// Focusable, with a name: a dialog opened from a click on the wall returns focus HERE on close
|
||||
// (a non-focusable canvas left focus on <body>), and the wall itself is reachable by keyboard.
|
||||
this.canvas.tabIndex = 0
|
||||
if (opts.label) this.canvas.setAttribute('aria-label', opts.label)
|
||||
this.canvas.setAttribute('role', 'img')
|
||||
host.appendChild(this.canvas)
|
||||
this.ctx = this.canvas.getContext('2d')
|
||||
this.icons = Object.fromEntries(Object.entries(ICON).map(([k, d]) => [k, new Path2D(d)]))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"type": "monolithic",
|
||||
"label": "Wall of People Groups",
|
||||
"note": "Monolithic composite (capability 3): ONE root .vue nests the zoomable d3 wall, its cards, and the prayer and comments dialogs. index.js registers exactly ONE tag (wall-of-people-groups); none of the inner components is independently embeddable."
|
||||
"note": "Monolithic composite (capability 3): ONE root .vue nests the zoomable d3 wall, its cards, and the prayer and comments dialogs. index.js registers exactly ONE tag (wall-of-people-groups); none of the inner components is independently embeddable.",
|
||||
"config": {
|
||||
"pinHint": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue