дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix(agents): leave a conversation's end for scrolls no layout caused (#2283)
Following the end snapped back any scroll away from it that didn't follow a wheel, touch, key or pointer press. A scroll without one, like dragging the scrollbar thumb where no pointer event reaches the page or a programmatic jump, was undone. The offset WebKit moves back on its own comes with a change of the content height while rows lay out; only such a scroll keeps following now, any other leaves the end.
Цей коміт міститься в:
1 джерело
502cc348ba
коміт
40be4e4c17
2 files changed
+25
-3
No files matched your search
@@ -554,8 +554,11 @@ function Stream({ task, entries, subagent, onOpenSubagent, finding, findFocus, o
|
||||
while (entries && start > 0 && isProcessEntry(entries[start]!) && isProcessEntry(entries[start - 1]!)) start--;
|
||||
const dragging = useRef(false);
|
||||
// When the user last scrolled the conversation (wheel, touch, keys, the scrollbar, Find):
|
||||
// only that leaves the end. WebKit also moves the offset back on its own while rows lay out.
|
||||
// that leaves the end. WebKit also moves the offset back on its own while rows lay out,
|
||||
// which comes with a change of the content height; a scroll without one is meant too (the
|
||||
// scrollbar thumb, a jump), whatever moved it.
|
||||
const userScrolled = useRef(-Infinity);
|
||||
const seenHeight = useRef(0);
|
||||
const markUserScroll = useCallback(() => {
|
||||
userScrolled.current = performance.now();
|
||||
}, []);
|
||||
@@ -723,7 +726,9 @@ function Stream({ task, entries, subagent, onOpenSubagent, finding, findFocus, o
|
||||
onScroll={(e) => {
|
||||
const el = e.currentTarget;
|
||||
const atEnd = el.scrollHeight - el.scrollTop - el.clientHeight < 40;
|
||||
const byUser = dragging.current || performance.now() - userScrolled.current < 500;
|
||||
const laidOut = el.scrollHeight !== seenHeight.current;
|
||||
seenHeight.current = el.scrollHeight;
|
||||
const byUser = dragging.current || performance.now() - userScrolled.current < 500 || !laidOut;
|
||||
const stick = atEnd || (position.current.stick && !byUser);
|
||||
// Still following: back to the end the offset was moved away from.
|
||||
if (stick && !atEnd) el.scrollTop = el.scrollHeight;
|
||||
|
||||
@@ -362,7 +362,10 @@ describe("scrolling", () => {
|
||||
let height = 1000;
|
||||
Object.defineProperty(el, "scrollHeight", { configurable: true, get: () => height });
|
||||
Object.defineProperty(el, "clientHeight", { configurable: true, value: 400 });
|
||||
// The conversation grew after it was scrolled to the end, or WebKit moved the offset back.
|
||||
el.scrollTop = 600;
|
||||
fireEvent.scroll(el);
|
||||
// The conversation grew after it was scrolled to the end, or WebKit moved the offset back
|
||||
// while rows laid out: both change the content height.
|
||||
height = 1300;
|
||||
el.scrollTop = 600;
|
||||
fireEvent.scroll(el);
|
||||
@@ -376,6 +379,20 @@ describe("scrolling", () => {
|
||||
expect(await screen.findByRole("button", { name: "Jump to Latest" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("leaves the end for a scroll that no layout caused, as dragging the scrollbar thumb", async () => {
|
||||
render(<SessionEditor input={input("A")} />);
|
||||
expect(await screen.findByText("Answer A")).toBeInTheDocument();
|
||||
const el = stream();
|
||||
Object.defineProperty(el, "scrollHeight", { configurable: true, value: 1000 });
|
||||
Object.defineProperty(el, "clientHeight", { configurable: true, value: 400 });
|
||||
el.scrollTop = 600;
|
||||
fireEvent.scroll(el);
|
||||
el.scrollTop = 0;
|
||||
fireEvent.scroll(el);
|
||||
expect(el.scrollTop).toBe(0);
|
||||
expect(await screen.findByRole("button", { name: "Jump to Latest" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("offers one click back to the latest message after scrolling up", async () => {
|
||||
render(<SessionEditor input={input("A")} />);
|
||||
expect(await screen.findByText("Answer A")).toBeInTheDocument();
|
||||
|
||||
Reference in new issue
Заблокувати користувача