feat(web): animate structured session interactions
This commit is contained in:
@@ -325,6 +325,7 @@ describe("structured connection: data flow", () => {
|
||||
transcript: { type: "append", row: row("agent:1", "agent_text", { content: { type: "text", text: "partial" } }) },
|
||||
state: idleState,
|
||||
});
|
||||
expect(conn.el.querySelector('[data-row-id="agent:1"]')?.classList).toContain("st-row-enter");
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: { type: "patch", row: row("agent:1", "agent_text", { content: { type: "text", text: "partial done" } }) },
|
||||
@@ -332,6 +333,7 @@ describe("structured connection: data flow", () => {
|
||||
});
|
||||
const rows = conn.el.querySelectorAll(".st-row-agent");
|
||||
expect(rows).toHaveLength(1);
|
||||
expect(rows[0].classList).not.toContain("st-row-enter");
|
||||
expect(conn.el.textContent).toContain("partial done");
|
||||
expect(conn.el.textContent).not.toContain("partial\n"); // the un-patched text is gone, not appended beside it
|
||||
conn.dispose();
|
||||
@@ -357,7 +359,7 @@ describe("structured connection: data flow", () => {
|
||||
const groups = conn.el.querySelectorAll<HTMLElement>(".st-tool-group");
|
||||
expect(groups).toHaveLength(1);
|
||||
expect(groups[0].querySelector(".st-tool-group-head")!.textContent).toContain("2 tool calls");
|
||||
expect(groups[0].querySelector<HTMLElement>(".st-tool-group-body")!.hidden).toBe(true);
|
||||
expect(groups[0].querySelector<HTMLElement>(".st-tool-group-body")!.getAttribute("aria-hidden")).toBe("true");
|
||||
expect(conn.el.querySelector('[data-row-id="tool:3"]')?.closest(".st-tool-group")).toBeNull();
|
||||
conn.dispose();
|
||||
});
|
||||
@@ -1289,7 +1291,7 @@ describe("structured connection: transcript scrolling", () => {
|
||||
it("keeps pinned appends and patches at the bottom after layout", () => {
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
const { values } = metrics(conn, 600, 200);
|
||||
const { scroll, values } = metrics(conn, 600, 200);
|
||||
ws.open();
|
||||
ws.emit({ type: "transcript_snapshot", snapshot: { cursor: 0, rows: [] } });
|
||||
runFrames();
|
||||
@@ -1305,6 +1307,7 @@ describe("structured connection: transcript scrolling", () => {
|
||||
});
|
||||
runFrames();
|
||||
expect(values.top).toBe(520);
|
||||
expect(scroll.style.scrollBehavior).toBe("smooth");
|
||||
|
||||
values.height = 780;
|
||||
ws.emit({
|
||||
@@ -1319,6 +1322,32 @@ describe("structured connection: transcript scrolling", () => {
|
||||
});
|
||||
runFrames();
|
||||
expect(values.top).toBe(580);
|
||||
expect(scroll.style.scrollBehavior).toBe("smooth");
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
it("keeps follow-to-bottom immediate when reduced motion is requested", () => {
|
||||
vi.stubGlobal("matchMedia", () => ({ matches: true }));
|
||||
const ws = new FakeSocket();
|
||||
const conn = mount({ sockets: [ws] });
|
||||
const { scroll, values } = metrics(conn, 600, 200);
|
||||
ws.open();
|
||||
ws.emit({ type: "transcript_snapshot", snapshot: { cursor: 0, rows: [] } });
|
||||
runFrames();
|
||||
|
||||
values.height = 720;
|
||||
ws.emit({
|
||||
type: "projection_update",
|
||||
transcript: {
|
||||
type: "append",
|
||||
row: row("agent:1", "agent_text", { content: { type: "text", text: "quietly" } }),
|
||||
},
|
||||
state: idleState,
|
||||
});
|
||||
runFrames();
|
||||
|
||||
expect(values.top).toBe(520);
|
||||
expect(scroll.style.scrollBehavior).toBe("");
|
||||
conn.dispose();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user