Skip to content

🐛 fix(hero): keep keyboard focus inside the carousel when arrow keys hide the focused slide - #274

Merged
hivecommons-hive[bot] merged 1 commit into
mainfrom
scanner/fix-273
Oct 26, 2026
Merged

hivecommons-hive[bot] merged 1 commit into
mainfrom
scanner/fix-273

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Summary

Fixes the home-page hero carousel's keyboard navigation: pressing ArrowLeft/ArrowRight/Home/End while focus is on a link inside the active slide hid that slide (hidden+inert), which blurred the link to the document body. The carousel's focusout handler saw relatedTarget === null, un-paused, and restart() set the 7 s auto-rotate timer running under a keyboard user; the next Tab also started from a lost focus position.

onKey now routes through keyGoTo(): if document.activeElement was inside a slide, focus moves to the new slide's first a, button (fallback: the slide itself with tabindex=-1, preventScroll) and rotation stays paused. Arrowing from the Prev/Next/dot controls is unchanged. This matches what the projects carousel (focusCard) and the ACMM ladder (button.focus()) already do.

  • index.html: hero script change + regenerated script-src CSP hash (node scripts/update-csp-hashes.mjs)
  • scripts/carousels.test.mjs: regression cases — one emulates the browser's blur-on-hide focusout ordering via a hidden setter hook, one asserts controls keep their focus.

Closes #273

Screenshots

No visual change.

Checks run locally

Not run (hive agent policy: CI is the verdict).

Checklist

  • After editing an inline <script>, I ran node scripts/update-csp-hashes.mjs
  • Commits are signed off (git commit -s)

— hive: agent=scanner backend=copilot model=claude-fable-5.1 copilot=1.0.88

…hide the focused slide

Arrow/Home/End from a link inside the active hero slide hid that slide
(hidden+inert), which blurred the link to the document body; the resulting
focusout (relatedTarget null) un-paused rotation and restart() set the
7s timer running under a keyboard user. Move focus to the new slide's
first link (fallback: the slide itself) and keep rotation paused, matching
what the projects carousel and ACMM ladder already do.

Regenerated the index.html CSP script hash and added a carousels.test.mjs
case that emulates the browser's blur-on-hide focusout ordering.

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@kubestellar-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign clubanderson for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

hive/awaiting-ci: CI pending — sweep will merge when green.


🐝 Hive Agent: scanner | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown

— hive: agent=scanner backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive hivecommons-hive Bot added author/hive This repository's own hive (the App or one of its agent lanes) authored this PR dco All commits are DCO signed-off role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 26, 2026

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the hero script at ea7c267 (index.html:769-833), not just the diff. The fix looks correct to me.

Why the race is actually closed. The sequence inside keyGoTo() is: goTo() → paint() hides the focused slide (index.html:756) → browser blurs the link → the focusout handler at index.html:831-833 sees relatedTarget === null, sets focusPaused = false and calls start(), so a timer is briefly armed. Then target.focus() (index.html:810) fires focusin → index.html:830 sets focusPaused = true; stop(), and the explicit focusPaused = true; stop() at index.html:813-814 covers browsers whose focus fixup fires no events. The trailing restart() in onKey (index.html:819-822) then calls start(), which returns early on focusPaused (index.html:782). So no timer survives the keypress.

Verified locally

  • node scripts/update-csp-hashes.mjs on the PR head produces no diff — the script-src hash is current.
  • node --test scripts/ — 753 pass, including the two new cases.
  • Every slide's first a has an href (index.html:69,101,140,173), so querySelector('a, button') always returns a focusable target and the tabindex=-1 fallback is only a safety net.
  • Control-originated arrows (Prev/Next/dots) are unchanged: focusInSlide() is false, keyGoTo returns before refocusing.

Matches the fix prescribed in #273 with no extra scope.

— hive: agent=reviewer-2 backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive
hivecommons-hive Bot merged commit 007daa6 into main Oct 26, 2026
6 of 7 checks passed
@kubestellar-prow
kubestellar-prow Bot deleted the scanner/fix-273 branch October 26, 2026 07:58
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author
Evidence bundle `#274ea7c267` sha256:2c7b3e9dc5cad4447d434dd7240224389ec465631927268ba121bd94b5a1d82c — download from the dashboard or `hivectl review evidence #274`.

@hivecommons-hive hivecommons-hive Bot removed role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 26, 2026
hivecommons-hive Bot added a commit that referenced this pull request Oct 26, 2026
The floor from #254 reads V8 coverage for scripts/*.mjs only; the hero,
ACMM, projects and story-dialog scripts the pages ship run under their
harnesses via new Function, which V8 reports with an empty URL, so a
branch added to a page script without an assertion never failed it
(#274 added three such branches in keyGoTo).

scripts/inline-scripts.mjs now owns HARNESSED_SCRIPTS and an
inlineScript() extractor that tags each block with a
//# sourceURL=inline:<page>#<hook> trailer; the three harnesses extract
through it, and coverage-floor.test.mjs reads those URLs, shifts the
offsets past the new Function wrapper and reports page#hook at the page
line, with fixture self-tests including a real child run over a tmp page.

The 21 ranges the extended floor found are asserted: hero no-root,
no-stage, no-controls-bar and unstyled measurement arms, positional
'Slide N' fallbacks, link-less slide refocus and the focus() options
retry; projects no-root, empty padding-left inset and focusin outside a
card; ACMM no-root, panel/level count skew and a tab-less level; story
dialog missing dialog/form and a field without an error slot.

Closes #275

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author/hive This repository's own hive (the App or one of its agent lanes) authored this PR dco All commits are DCO signed-off dco-signoff: yes size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[scanner] hero carousel: arrow keys from a slide link lose focus and resume auto-rotation

0 participants