fix(nav): Back restores the focus after a click on the page's blank area
The page region is <main tabIndex=-1>, so a background click focused it and the Back restore took that for the reader's choice. A resting place is marked and one predicate (focusIsUnclaimed) decides "the focus is nowhere" everywhere.
This commit is contained in:
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import { api, type DiagnosticsLevel } from "../lib/api";
|
||||
import { levelInForce } from "../lib/diagnostics";
|
||||
import { focusIsUnclaimed } from "../lib/useFocusKeeper";
|
||||
import { updateMeCache, useMe } from "../lib/useMe";
|
||||
import { Button } from "./ui/Button";
|
||||
import InlineNotice from "./ui/InlineNotice";
|
||||
@@ -61,7 +62,7 @@ export default function DiagnosticsSettings() {
|
||||
const from = closedFrom.current;
|
||||
if (!from || from.isConnected) return;
|
||||
closedFrom.current = null;
|
||||
if (document.activeElement && document.activeElement !== document.body) return;
|
||||
if (!focusIsUnclaimed()) return;
|
||||
pickerRef.current?.querySelector<HTMLElement>('[aria-pressed="true"]')?.focus();
|
||||
});
|
||||
const watchFocus = () => {
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import { moduleDef } from "../lib/modules";
|
||||
import type { Page } from "../lib/urlState";
|
||||
import { qk } from "../lib/queryKeys";
|
||||
import { focusIsUnclaimed } from "../lib/useFocusKeeper";
|
||||
import { LEVEL_TAG, logClock } from "./logLineParts";
|
||||
import { Button } from "./ui/Button";
|
||||
import { IconButton } from "./ui/IconButton";
|
||||
@@ -54,7 +55,7 @@ export default function IssueComposer({ id }: { id: string }) {
|
||||
useEffect(
|
||||
() => () => {
|
||||
window.setTimeout(() => {
|
||||
if (document.activeElement === document.body)
|
||||
if (focusIsUnclaimed())
|
||||
document.querySelector<HTMLElement>('nav [aria-current="page"]')?.focus();
|
||||
}, 0);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useLayoutEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { useScrollFade } from "../../lib/useScrollFade";
|
||||
import { useFocusKeeper } from "../../lib/useFocusKeeper";
|
||||
import { FOCUS_REST_ATTRS, useFocusKeeper } from "../../lib/useFocusKeeper";
|
||||
import { StickyTopProvider } from "./stickyTop";
|
||||
import { CONTENT_ID } from "./landmarks";
|
||||
import { ensureNavId, peekNavId, subscribeNav } from "../../lib/history";
|
||||
@@ -158,11 +158,13 @@ export default function PageScroller({
|
||||
|
||||
return (
|
||||
// `id` + `tabIndex={-1}`: the skip link's target (ui/SkipLink) takes the focus, so the next Tab
|
||||
// lands on the page's first control.
|
||||
// lands on the page's first control. A click on the page's background focuses it too, which is
|
||||
// the focus RESTING, not a choice a Back restore must respect (`FOCUS_REST_ATTRS`).
|
||||
<main
|
||||
ref={setRef}
|
||||
id={CONTENT_ID}
|
||||
tabIndex={-1}
|
||||
{...FOCUS_REST_ATTRS}
|
||||
style={fade.style}
|
||||
className="flex-1 min-w-0 overflow-y-auto scrollbar-gutter-stable focus:outline-none"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user