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:
@@ -50,6 +50,7 @@ import {
|
||||
anyLayerAbove,
|
||||
escapeHandled,
|
||||
} from "../../lib/layerStack";
|
||||
import { focusInNavList } from "../../lib/listNav";
|
||||
import { trapTab, useDialogChrome } from "../../components/ui/dialogFocus";
|
||||
import DownloadButton from "../downloads/DownloadButton";
|
||||
import ClipPanel, { ClipCropFrame, type ClipCrop } from "./ClipPanel";
|
||||
@@ -709,10 +710,11 @@ export default function PlayerModal({
|
||||
// over the player by doing so.
|
||||
const overlayOrder = useOverlayOrder();
|
||||
// This player is a dismissable layer: register it so a Modal or popover opened ABOVE it (e.g. the
|
||||
// download dialog, or an anchored menu) takes Escape first and this player defers.
|
||||
// download dialog, or an anchored menu) takes Escape first and this player defers. Its root lets
|
||||
// the keyboard walk a list inside it (the related videos).
|
||||
const layerIdRef = useRef<number | null>(null);
|
||||
useEffect(() => {
|
||||
const id = pushLayer();
|
||||
const id = pushLayer({ root: () => dialogRef.current });
|
||||
layerIdRef.current = id;
|
||||
return () => {
|
||||
removeLayer(id);
|
||||
@@ -740,7 +742,9 @@ export default function PlayerModal({
|
||||
// there: deferring would scroll something invisible and leave the viewer with no volume control at
|
||||
// all. Both flags, not just fullscreen: since F stopped taking the browser's lock, maximise is the
|
||||
// common case and checking only `isFullscreen` made the keys dead exactly where they matter most.
|
||||
// On a row of a list in the player (the related videos) the arrows walk the list instead.
|
||||
const volume = (e: KeyboardEvent, up: boolean) => {
|
||||
if (focusInNavList()) return;
|
||||
const covered = isFullscreenRef.current || maximized;
|
||||
if (!covered && canScrollBy(document.activeElement as HTMLElement | null, up ? -1 : 1))
|
||||
return;
|
||||
@@ -748,6 +752,7 @@ export default function PlayerModal({
|
||||
nudgeVolume(up ? 5 : -5);
|
||||
};
|
||||
const seek = (e: KeyboardEvent, secs: number) => {
|
||||
if (focusInNavList()) return;
|
||||
e.preventDefault();
|
||||
nudgeSeek(secs);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user