Files
iptvnator/.changes/dashboard-rail-focus-reveal.md
c9d169e3dc fix(dashboard): scroll a focused rail card fully into view (#1785)
* fix(dashboard): scroll a focused rail card fully into view

Chromium skips its focus scroll when 32px or more of the element already
shows, so Tab onto the last source card of a rail that overflows by less
than a card left it half-hidden under the edge fade. The rail track now
handles focusin and scrolls to the first card-start snap position that
reveals the whole card; a plain "nearest" scroll is not enough because
mandatory snapping can round it back (seen on the live channel rail).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): keep mouse clicks on partly hidden rail cards

A mouse press focuses the card link on mousedown. Revealing the card at
that moment could slide it from under the pointer when the target snap
position overshoots (the live channel rail moves 316px for a 306px
card), so the click landed elsewhere. The rail now reveals a card only
for keyboard and programmatic focus, using the CDK FocusMonitor origin.

Adds an Electron E2E that checks the final layout after snapping: Tab and
focus() leave the last source card fully visible, and a mouse press keeps
the rail still and still opens the source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): tell pointer focus apart without touching the DOM

FocusMonitor toggles cdk-*-focused classes on the monitored track, so a
mouse press on a source card mutated the DOM before the click. The J2
"open a source" performance journey rejects iterations with DOM activity
between its settle snapshot and the click. Read the input modality from
the CDK InputModalityDetector in a focusin handler instead: it only
listens, so the rail stays untouched until the click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): reveal script-focused rail cards after a mouse click

The input modality stays "mouse" after any click, so a later focus() on
a partly hidden card left it clipped. The rail now skips the reveal only
for focus caused by a press inside the track: the focus has to arrive
within 100ms of that pointerdown (650ms for touch, whose focus comes
with the tap's compatibility mouse events, as in the CDK FocusMonitor).
Only event timestamps are compared, so the DOM still stays untouched
before the click.

The E2E now clicks elsewhere before the script focus, and unit tests
cover a tap and focus() after an earlier mouse press.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(dashboard): keep an over-wide focused rail card in view

In a window narrower than a card (or under zoom), a focused card could
never fit, so its own snap offset fell short of the needed scroll and
the rail jumped to the next card's snap point, moving the focused card
offscreen. Such a card is now aligned at its own start instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(dashboard): select rail internals through stable test ids

The dashboard contract makes data-test-id hooks the supported Electron
E2E selector surface. The rail now exposes -viewport, -track and
-card-link hooks next to its existing ones, and the focus E2E selects
those (and the rail heading by role) instead of internal class names.
The dashboard doc lists the new hooks and records the focus-reveal
contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: 4gray <fourgray@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 10:24:57 +02:00

228 B

type, area
type area
fix dashboard

Moving keyboard focus onto a dashboard rail card, such as a source in Recently Used Sources, now scrolls the rail so the whole card shows instead of leaving it half-hidden under the edge fade.