mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-03 23:23:21 +00:00
Retained tabs stay mounted under display:none while inactive, which reports a zero-width onLayout. ControlledAgentControls fed that straight into its density resolver, so a hidden tab's toolbar collapsed to its tightest density and painted one frame collapsed before re-expanding when the tab became visible again. Extract the zero-width guard that useContainerWidthBelow already had into a shared readMeasuredWidth helper, and use it in the composer toolbar's own layout handler so a display:none measurement can never drive its density. Also bump the chat outline rail's MIN_PANEL_WIDTH breakpoint (818 -> 918) so the rail disappears earlier under a narrower panel, and widen the chat-outline e2e spec's viewport so its panel keeps healthy margin over the new threshold.
91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { act, renderHook } from "@testing-library/react";
|
|
import type { LayoutChangeEvent } from "react-native";
|
|
import { describe, expect, it } from "vitest";
|
|
import { readMeasuredWidth, useContainerWidthBelow } from "./use-container-width";
|
|
|
|
function layoutEvent(width: number): LayoutChangeEvent {
|
|
return {
|
|
nativeEvent: {
|
|
layout: {
|
|
width,
|
|
height: 48,
|
|
x: 0,
|
|
y: 0,
|
|
},
|
|
},
|
|
} as LayoutChangeEvent;
|
|
}
|
|
|
|
describe("readMeasuredWidth", () => {
|
|
it("returns the width of a rendered container", () => {
|
|
expect(readMeasuredWidth(layoutEvent(650))).toBe(650);
|
|
});
|
|
|
|
it("returns null for the zero width a hidden retained panel reports", () => {
|
|
expect(readMeasuredWidth(layoutEvent(0))).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("useContainerWidthBelow", () => {
|
|
it("does not re-render for width changes that stay in the same threshold bucket", () => {
|
|
let renderCount = 0;
|
|
const { result } = renderHook(() => {
|
|
renderCount += 1;
|
|
return useContainerWidthBelow(700);
|
|
});
|
|
|
|
expect(result.current.isBelow).toBe(true);
|
|
expect(renderCount).toBe(1);
|
|
|
|
act(() => {
|
|
result.current.onLayout(layoutEvent(650));
|
|
result.current.onLayout(layoutEvent(620));
|
|
result.current.onLayout(layoutEvent(699));
|
|
});
|
|
|
|
expect(result.current.isBelow).toBe(true);
|
|
expect(renderCount).toBe(1);
|
|
});
|
|
|
|
it("re-renders when the width crosses the threshold", () => {
|
|
let renderCount = 0;
|
|
const { result } = renderHook(() => {
|
|
renderCount += 1;
|
|
return useContainerWidthBelow(700);
|
|
});
|
|
|
|
act(() => {
|
|
result.current.onLayout(layoutEvent(760));
|
|
});
|
|
|
|
expect(result.current.isBelow).toBe(false);
|
|
expect(renderCount).toBe(2);
|
|
});
|
|
|
|
it("ignores zero-width measurements from hidden mounted content", () => {
|
|
let renderCount = 0;
|
|
const { result } = renderHook(() => {
|
|
renderCount += 1;
|
|
return useContainerWidthBelow(700, { initialIsBelow: false });
|
|
});
|
|
|
|
expect(result.current.isBelow).toBe(false);
|
|
|
|
act(() => {
|
|
result.current.onLayout(layoutEvent(0));
|
|
});
|
|
|
|
expect(result.current.isBelow).toBe(false);
|
|
expect(renderCount).toBe(1);
|
|
|
|
act(() => {
|
|
result.current.onLayout(layoutEvent(650));
|
|
});
|
|
|
|
expect(result.current.isBelow).toBe(true);
|
|
expect(renderCount).toBe(2);
|
|
});
|
|
});
|