fix(history): stop the next overlay's first Back being swallowed after a button/ESC close

useBackToClose closes an overlay programmatically (X button or ESC) by
setting the module-global suppressPop=true and calling history.back(), so
the remaining overlays' popstate handlers ignore that synthetic pop. But
the flag was only ever reset by one of those handlers — when the closed
overlay had no overlay underneath it (the common single-player case),
nothing consumed it and suppressPop leaked true.

The next overlay's first real Back then hit the stale true, reset it and
returned early without closing — the Back was silently swallowed. Symptom
in the YouTube-search flow: close the player with the X button, open
another, press Back once -> nothing happens; a second Back closes it AND
discards the search results, dumping you on the normal feed.

Fix: register a one-shot popstate listener alongside suppressPop=true so
the flag is cleared on that very pop even when no overlay remains to
consume it. Nesting is unaffected (an underlying overlay still short-
circuits first and the one-shot is a redundant no-op).
This commit is contained in:
npeter83 2026-07-01 01:42:00 +02:00
parent c1e9a3c6f9
commit 3d8015f3a9

View file

@ -66,9 +66,17 @@ export function useBackToClose(onClose: () => void): void {
const idx = overlayStack.lastIndexOf(token); const idx = overlayStack.lastIndexOf(token);
if (idx !== -1) { if (idx !== -1) {
// Closed programmatically (not via Back): drop our own history entry, and tell the // Closed programmatically (not via Back): drop our own history entry, and tell the
// remaining overlays' handlers to ignore the resulting popstate. // remaining overlays' handlers to ignore the resulting popstate. A one-shot listener
// clears the flag on that very popstate even when NO overlay remains underneath to
// consume it — otherwise suppressPop leaks `true` and silently swallows the NEXT
// overlay's first Back (reopen-after-button-close → first Back does nothing).
overlayStack.splice(idx, 1); overlayStack.splice(idx, 1);
suppressPop = true; suppressPop = true;
const clearSuppress = () => {
suppressPop = false;
window.removeEventListener("popstate", clearSuppress);
};
window.addEventListener("popstate", clearSuppress);
window.history.back(); window.history.back();
} }
}; };