fix(dashboard): portal MobileNavBar to document.body for robust fixed positioning

vpdebug on Android tablet captured the nav bar's getBoundingClientRect
at y=2800 with html height 798 — meaning some ancestor was creating a
containing block for the bar's `position: fixed`, putting it 2000+ px
below the visible window. Any ancestor with `transform`, `filter`,
`will-change`, or `contain: paint` would do that, and it's hard to
audit which of our many ancestors (providers, view wrappers, plugin
hosts) introduces one in a given Android Chrome state.

Sidestep the whole question: render the bar via createPortal into
document.body. Its only ancestor is body, so `position: fixed; bottom: 0`
is now guaranteed to pin to the visual viewport bottom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-22 11:12:32 -07:00
parent 4bd9711e87
commit 49839245e1

View File

@@ -1,5 +1,6 @@
import "./MobileNavBar.css"; import "./MobileNavBar.css";
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from "react"; import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { createPortal } from "react-dom";
import { import {
Activity, Activity,
Bot, Bot,
@@ -296,7 +297,12 @@ export function MobileNavBar({
|| view === "stash-recovery" || view === "stash-recovery"
|| (isPluginViewId(view) && !topLevelPrimaryPluginViews.some((entry) => buildPluginTaskViewId(entry.pluginId, entry.view.viewId) === view)); || (isPluginViewId(view) && !topLevelPrimaryPluginViews.some((entry) => buildPluginTaskViewId(entry.pluginId, entry.view.viewId) === view));
return ( // Portal the bar directly into document.body so its `position: fixed`
// can't be hijacked by an ancestor's containing block (any ancestor with
// transform/filter/will-change/contain creates a fixed-positioning
// containing block — and we hit exactly that on Android tablet, leaving
// the bar positioned far below the visible window).
const content = (
<> <>
<nav <nav
ref={navRef} ref={navRef}
@@ -837,4 +843,6 @@ export function MobileNavBar({
)} )}
</> </>
); );
if (typeof document === "undefined") return content;
return createPortal(content, document.body);
} }