fix(web): follow composer and rail layout
This commit is contained in:
@@ -935,6 +935,7 @@ describe("structured connection: reconnection/error/loading", () => {
|
||||
describe("structured connection: transcript scrolling", () => {
|
||||
let frames: Map<number, FrameRequestCallback>;
|
||||
let nextFrame: number;
|
||||
let resizeCallback: ResizeObserverCallback;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -949,6 +950,14 @@ describe("structured connection: transcript scrolling", () => {
|
||||
vi.stubGlobal("cancelAnimationFrame", (id: number) => {
|
||||
frames.delete(id);
|
||||
});
|
||||
vi.stubGlobal("ResizeObserver", class {
|
||||
constructor(callback: ResizeObserverCallback) {
|
||||
resizeCallback = callback;
|
||||
}
|
||||
observe(): void {}
|
||||
unobserve(): void {}
|
||||
disconnect(): void {}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -977,6 +986,13 @@ describe("structured connection: transcript scrolling", () => {
|
||||
for (const [, cb] of pending) cb(0);
|
||||
}
|
||||
|
||||
function resizeBody(width: number): void {
|
||||
resizeCallback(
|
||||
[{ contentRect: { width } } as ResizeObserverEntry],
|
||||
{} as ResizeObserver,
|
||||
);
|
||||
}
|
||||
|
||||
it("shows the bottom after the initial transcript snapshot is laid out", () => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
@@ -1034,6 +1050,55 @@ describe("structured connection: transcript scrolling", () => {
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ position: "pinned", top: 800, expected: 880, manuallyScrolled: false },
|
||||
{ position: "manually scrolled", top: 180, expected: 180, manuallyScrolled: true },
|
||||
])("preserves the $position position when the composer grows", ({ top, expected, manuallyScrolled }) => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
const { scroll, values } = metrics(conn, 1000, 200);
|
||||
ws.open();
|
||||
ws.emit({ type: "transcript_snapshot", snapshot: { cursor: 0, rows: [] } });
|
||||
runFrames();
|
||||
|
||||
values.top = top;
|
||||
if (manuallyScrolled) scroll.dispatchEvent(new Event("scroll"));
|
||||
const input = conn.el.querySelector<HTMLTextAreaElement>(".structured-input")!;
|
||||
Object.defineProperty(input, "scrollHeight", { configurable: true, value: 120 });
|
||||
input.value = "one\ntwo\nthree";
|
||||
input.dispatchEvent(new Event("input"));
|
||||
values.height = 1080;
|
||||
runFrames();
|
||||
|
||||
expect(input.style.height).toBe("120px");
|
||||
expect(values.top).toBe(expected);
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ position: "pinned", top: 800, expected: 850, manuallyScrolled: false },
|
||||
{ position: "manually scrolled", top: 180, expected: 180, manuallyScrolled: true },
|
||||
])("preserves the $position position across the narrow breakpoint", ({ top, expected, manuallyScrolled }) => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
const { scroll, values } = metrics(conn, 1000, 200);
|
||||
ws.open();
|
||||
ws.emit({ type: "transcript_snapshot", snapshot: { cursor: 0, rows: [] } });
|
||||
runFrames();
|
||||
|
||||
values.top = top;
|
||||
if (manuallyScrolled) scroll.dispatchEvent(new Event("scroll"));
|
||||
resizeBody(500);
|
||||
values.clientHeight = 150;
|
||||
runFrames();
|
||||
|
||||
expect(conn.el.querySelector(".structured-body")!.classList).toContain("st-narrow");
|
||||
expect(values.top).toBe(expected);
|
||||
resizeBody(500);
|
||||
expect(frames.size).toBe(0);
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("preserves a user-scrolled position across updates, approvals, and tool expansion", () => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
@@ -1143,10 +1208,17 @@ describe("structured connection: transcript scrolling", () => {
|
||||
|
||||
conn.onUnmount();
|
||||
expect(frames.size).toBe(0);
|
||||
const input = conn.el.querySelector<HTMLTextAreaElement>(".structured-input")!;
|
||||
Object.defineProperty(input, "scrollHeight", { configurable: true, value: 120 });
|
||||
input.dispatchEvent(new Event("input"));
|
||||
resizeBody(500);
|
||||
expect(frames.size).toBe(0);
|
||||
conn.onMount({ focus: false });
|
||||
expect(frames.size).toBe(2);
|
||||
conn.dispose();
|
||||
expect(frames.size).toBe(0);
|
||||
resizeBody(700);
|
||||
expect(conn.el.querySelector(".structured-body")!.classList).toContain("st-narrow");
|
||||
runFrames();
|
||||
expect(values.top).toBe(25);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user