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:
@@ -41,6 +41,19 @@ export function isStandInFocus(el: Element | null): boolean {
|
||||
return el !== null && el === standIn;
|
||||
}
|
||||
|
||||
/** Marks an element that can hold the focus without being a control: the page's scroll region
|
||||
* (`<main tabIndex={-1}>`, the skip link's target) takes it from a mouse click on the page's blank
|
||||
* area. Holding it there is the focus RESTING on the page, the same as <body>. */
|
||||
export const FOCUS_REST_ATTRS = { "data-focus-rest": "" } as const;
|
||||
|
||||
/** Whether the focus is nowhere the reader chose — <body>, the keeper's stand-in, or a resting place
|
||||
* (`FOCUS_REST_ATTRS`) — so a restore may take it. The page region used to count as a choice: a
|
||||
* click on its background focused it, and Back then left the focus there instead of on the item
|
||||
* the view was opened from (E28 review H1). */
|
||||
export function focusIsUnclaimed(el: Element | null = document.activeElement): boolean {
|
||||
return !el || el === document.body || isStandInFocus(el) || el.hasAttribute("data-focus-rest");
|
||||
}
|
||||
|
||||
/** Where the focus goes once `lost` (removed with the nodes of `record`) has left the page — never
|
||||
* outside `root`: a slot with nothing focusable left (a page swapped for its loading fallback) must
|
||||
* not send the focus to the first control of the whole document. */
|
||||
@@ -80,8 +93,7 @@ export function useFocusKeeper(ref: RefObject<HTMLElement | null>): void {
|
||||
const lost = held;
|
||||
if (!lost || lost.isConnected) return;
|
||||
held = null;
|
||||
const active = document.activeElement;
|
||||
if (active && active !== document.body) return; // something already took the focus
|
||||
if (!focusIsUnclaimed()) return; // something already took the focus
|
||||
for (const r of records) {
|
||||
const target = slotFor(r, lost, root);
|
||||
if (target) {
|
||||
|
||||
Reference in New Issue
Block a user