fix(feed): re-measure header on feed↔channel Back so --hdr-h can't stick at 8px
PageShell is reused (never remounted) across feed↔channel navigation — same component position in App.tsx — so a one-shot useLayoutEffect kept its ResizeObserver bound to the FIRST header node. On channel-open that node detached and fired the observer with a 0 box, rewriting --hdr-h to 0+0+8=8px on the still-mounted content div. Back restored the pt-(--hdr-h) pad class with that stale value, sliding the content toolbar up under the header — stuck until reload. Hold both the header and content nodes in state (callback refs) and key the measurement effect to the live nodes, so it re-runs every time the header mounts/unmounts; drop the stale pad when the header is absent (channel page). Adds a regression test: header removed then restored must re-measure, not 8px.
This commit is contained in:
@@ -50,4 +50,27 @@ describe("PageShell --hdr-h (E5 S7)", () => {
|
||||
const { container } = render(<PageShell>content</PageShell>);
|
||||
expect(container.querySelector('[class*="pt-(--hdr-h)"]')).toBeNull();
|
||||
});
|
||||
|
||||
it("re-measures when the header is removed then restored (feed→channel→back)", () => {
|
||||
// PageShell is REUSED across feed↔channel navigation (same component position in App.tsx) — it
|
||||
// never remounts, so the header DOM node is swapped under a stable PageShell. The measurement
|
||||
// must re-run on that swap; a one-shot effect kept observing the FIRST node and, when it detached,
|
||||
// rewrote --hdr-h to a stale 8px that stuck on Back. Regression for the channel-Back header overlap.
|
||||
const hdr = () => <div data-testid="hdr">H</div>;
|
||||
const { container, rerender } = render(<PageShell header={hdr()}>content</PageShell>);
|
||||
const measure = (top: number, h: number) => {
|
||||
const el = container.querySelector('[data-testid="hdr"]') as HTMLElement;
|
||||
Object.defineProperty(el, "offsetTop", { value: top, configurable: true });
|
||||
Object.defineProperty(el, "offsetHeight", { value: h, configurable: true });
|
||||
roCb?.();
|
||||
};
|
||||
measure(12, 52);
|
||||
const content = () => container.querySelector('[class*="pt-(--hdr-h)"]') as HTMLElement;
|
||||
expect(content().style.getPropertyValue("--hdr-h")).toBe("72px"); // 12 + 52 + 8
|
||||
|
||||
rerender(<PageShell>content</PageShell>); // → channel page: header gone
|
||||
rerender(<PageShell header={hdr()}>content</PageShell>); // → Back: header returns as a NEW node
|
||||
measure(12, 52); // fires the NEW header's observer
|
||||
expect(content().style.getPropertyValue("--hdr-h")).toBe("72px"); // re-measured, not the stale 8px
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user