Skip to content

Commit 472b3d0

Browse files
committed
Auto scroll to the bottom of the chat on new messages
1 parent 73a0a62 commit 472b3d0

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

apps/array/src/renderer/features/sessions/components/ConversationView.tsx

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,35 @@ export function ConversationView({
5757
const items = useMemo(() => buildConversationItems(events), [events]);
5858
const lastTurn = items.filter((i): i is Turn => i.type === "turn").pop();
5959

60-
// Scroll to bottom on initial mount
61-
const hasScrolledRef = useRef(false);
60+
const isNearBottomRef = useRef(true);
61+
const prevItemsLengthRef = useRef(0);
62+
63+
// Update isNearBottom on scroll
6264
useLayoutEffect(() => {
63-
if (hasScrolledRef.current) return;
6465
const el = scrollRef.current;
65-
if (el && items.length > 0) {
66+
if (!el) return;
67+
68+
const handleScroll = () => {
69+
const threshold = 100;
70+
const distanceFromBottom =
71+
el.scrollHeight - el.scrollTop - el.clientHeight;
72+
isNearBottomRef.current = distanceFromBottom <= threshold;
73+
};
74+
75+
el.addEventListener("scroll", handleScroll);
76+
return () => el.removeEventListener("scroll", handleScroll);
77+
}, []);
78+
79+
// Scroll to bottom on first render and when new content arrives
80+
useLayoutEffect(() => {
81+
const el = scrollRef.current;
82+
if (!el) return;
83+
84+
const isNewContent = items.length > prevItemsLengthRef.current;
85+
prevItemsLengthRef.current = items.length;
86+
87+
if (isNearBottomRef.current || isNewContent) {
6688
el.scrollTop = el.scrollHeight;
67-
hasScrolledRef.current = true;
6889
}
6990
}, [items]);
7091

0 commit comments

Comments
 (0)