fix(a11y): move the card grids by a row, not to the end
`RovingGridController.measureColumns` read `offsetTop`, and every card
in these grids is drawn by a `lit-virtualizer`, which positions its
children with a transform — which `offsetTop` does not see. So all of
them reported 0, every rendered card counted as one row, and ArrowDown
was `min(i + everything, last)` while ArrowUp was `max(i - everything,
0)`: the vertical arrows have been End and Home in the albums, artists
and genres grids since the day this was written. At 700x700 with three
real rows of 3/3/2, ArrowDown from card 0 landed on card 7.
Two things behind it, both only visible once the grid splits:
`cover-grid`'s scrollToIndex was `querySelector('lit-virtualizer')` —
always `#grid-before` — while the roving index spans the whole album
list, so with a dropdown open End scrolled the wrong half to an index
it does not contain. It now picks the half that holds the index and
rebases it.
And the focus is retried on a deadline rather than taken once at the
host's `updateComplete`: a scroll of 5 000 rows produces the card a few
hundred ms later, so the tab stop moved and nothing took focus, which
looks exactly like the key not being handled.
Also waits for the virtualizer in album-dropdown.spec's expandCard,
which flaked on roughly one run in two on main.
This commit is contained in:
@@ -289,11 +289,7 @@ export class CoverGrid
|
||||
private roving = new RovingGridController(this, {
|
||||
cardSelector: '.album-card',
|
||||
count: () => this.buildGridEntries().length,
|
||||
scrollToIndex: (index) => {
|
||||
this.shadowRoot
|
||||
?.querySelector<LitVirtualizer>('lit-virtualizer')
|
||||
?.scrollToIndex(index, 'nearest');
|
||||
},
|
||||
scrollToIndex: (index) => this.scrollGridToIndex(index),
|
||||
});
|
||||
|
||||
private contextMenuTarget: ContextMenuTarget = {
|
||||
@@ -849,6 +845,33 @@ export class CoverGrid
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring a card into view, in whichever virtualizer currently holds
|
||||
* it.
|
||||
*
|
||||
* The roving tab stop's index is an index into the whole filtered
|
||||
* album list, but a split grid draws that list across *two*
|
||||
* virtualizers, each of which indexes only its own slice. This used
|
||||
* to be `querySelector('lit-virtualizer')` — always `#grid-before`
|
||||
* — so with a dropdown open, End scrolled the before-grid to an
|
||||
* index it does not contain and the card that should have taken
|
||||
* focus was never rendered to take it.
|
||||
*/
|
||||
private scrollGridToIndex(index: number): void {
|
||||
const split = this.splitMode && this.expandedTracks.length > 0;
|
||||
const after = split && index >= this.splitIndex;
|
||||
|
||||
const id = !split
|
||||
? '#grid-single'
|
||||
: after
|
||||
? '#grid-after'
|
||||
: '#grid-before';
|
||||
|
||||
this.shadowRoot
|
||||
?.querySelector<LitVirtualizer>(id)
|
||||
?.scrollToIndex(after ? index - this.splitIndex : index, 'nearest');
|
||||
}
|
||||
|
||||
/** Rebuild before/after caches if the entries or splitIndex changed. */
|
||||
private ensureSplitCache(): void {
|
||||
const entries = this.buildGridEntries();
|
||||
|
||||
Reference in New Issue
Block a user