Merge fix/nav-focus-stuck: rail no longer latches open after a portaled menu closes
This commit is contained in:
@@ -67,6 +67,30 @@ export default function NavSidebar({
|
|||||||
// in-flow like before. `collapsed` (persisted per-account) now means "unpinned".
|
// in-flow like before. `collapsed` (persisted per-account) now means "unpinned".
|
||||||
const [hovered, setHovered] = useState(false);
|
const [hovered, setHovered] = useState(false);
|
||||||
const [focused, setFocused] = useState(false);
|
const [focused, setFocused] = useState(false);
|
||||||
|
// onFocus/onBlur (below) track focus through the REACT tree, so the rail's portaled menus
|
||||||
|
// (language switcher, account popover) count as "inside" and keep it open while you use them.
|
||||||
|
// The case they miss: a portal unmounts while focused, and browsers fire NO blur when a focused
|
||||||
|
// node is removed — focus silently falls to the body and `focused` would latch on forever.
|
||||||
|
// Safety net: whenever focus has landed nowhere, clear it. Deferred a tick so activeElement has
|
||||||
|
// settled, and rescheduled rather than queued — only the latest state matters.
|
||||||
|
useEffect(() => {
|
||||||
|
let timer: number | undefined;
|
||||||
|
const clearIfFocusLandedNowhere = () => {
|
||||||
|
const el = document.activeElement;
|
||||||
|
if (!el || el === document.body || el === document.documentElement) setFocused(false);
|
||||||
|
};
|
||||||
|
const soon = () => {
|
||||||
|
window.clearTimeout(timer);
|
||||||
|
timer = window.setTimeout(clearIfFocusLandedNowhere, 0);
|
||||||
|
};
|
||||||
|
document.addEventListener("focusout", soon);
|
||||||
|
document.addEventListener("click", soon);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("focusout", soon);
|
||||||
|
document.removeEventListener("click", soon);
|
||||||
|
window.clearTimeout(timer);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
const pinned = !collapsed;
|
const pinned = !collapsed;
|
||||||
const expanded = pinned || hovered || focused;
|
const expanded = pinned || hovered || focused;
|
||||||
const slim = !expanded; // visual: icon-only rail
|
const slim = !expanded; // visual: icon-only rail
|
||||||
|
|||||||
Reference in New Issue
Block a user