fix(keys): a list inside the topmost layer walks by keyboard
The list keys are the page's and an open layer silences them, so the player's related videos could only be reached by Tab. A layer now names its root element; with the focus on a row inside the topmost one, j/k, the arrows and Enter walk that list, the walk stays inside the layer, and the player's seek and volume arrows leave a focused row alone.
This commit is contained in:
@@ -25,7 +25,8 @@ import type { Page } from "./urlState";
|
||||
* `page`, `search` and `list` are the PAGE-LEVEL scopes: they act on the page underneath
|
||||
* every overlay, so `dispatch` keeps them quiet while a layer that owns the keyboard is open. That is
|
||||
* also what keeps them clear of the players' bare letters — the Plex player's `s` and `k` only ever
|
||||
* run with the player's own layer up. */
|
||||
* run with the player's own layer up. The one exception is a list INSIDE the topmost layer, with the
|
||||
* focus in it (`dispatch`'s `inTopLayer`, decided by lib/listNav). */
|
||||
export type KeyScope =
|
||||
| "global"
|
||||
| "page"
|
||||
@@ -358,11 +359,13 @@ const stepsOf = (chord: string): string[] => chord.split(" ");
|
||||
* implementation cannot drift without tsc saying so. Skipped while typing unless the row opts in
|
||||
* with `allowInInput` (Escape, and only Escape), on a key a focused widget already handled, and — for a page-level scope — while a layer that
|
||||
* owns the keyboard is open. The rule lives here rather than in each listener so a new page-level
|
||||
* surface cannot forget it. */
|
||||
* surface cannot forget it. `inTopLayer` is the one way past it: the caller has checked that the
|
||||
* key acts inside that topmost layer, not on the page behind (a list in the player). */
|
||||
export function dispatch<S extends KeyScope>(
|
||||
e: KeyboardEvent,
|
||||
scope: S,
|
||||
handlers: { readonly [K in ShortcutId<S>]: (e: KeyboardEvent) => void },
|
||||
{ inTopLayer = false }: { inTopLayer?: boolean } = {},
|
||||
): boolean {
|
||||
if (sequenceEvents.has(e)) return false;
|
||||
// A key a focused widget already handled is not a shortcut: every listener here is on `window`,
|
||||
@@ -374,7 +377,7 @@ export function dispatch<S extends KeyScope>(
|
||||
if (e.key === "Escape" && escapeHandled(e)) return false;
|
||||
const live = liveSequence(e);
|
||||
if (live && live.scope !== scope) return false;
|
||||
const quiet = isPageLevelScope(scope) && anyBlockingLayer();
|
||||
const quiet = isPageLevelScope(scope) && anyBlockingLayer() && !inTopLayer;
|
||||
const typing = isTypingTarget(e);
|
||||
const run = (id: string) => (handlers as Record<string, (ev: KeyboardEvent) => void>)[id]?.(e);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user