Skip to content

Commit 11fc465

Browse files
fix: resume autoscroll behaviour on message sent (#296)
1 parent 260f8bf commit 11fc465

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

components/app/session-view.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React, { useState } from 'react';
3+
import React, { useEffect, useRef, useState } from 'react';
44
import { motion } from 'motion/react';
55
import type { AppConfig } from '@/app-config';
66
import { ChatTranscript } from '@/components/app/chat-transcript';
@@ -71,6 +71,7 @@ export const SessionView = ({
7171

7272
const messages = useChatMessages();
7373
const [chatOpen, setChatOpen] = useState(false);
74+
const scrollAreaRef = useRef<HTMLDivElement>(null);
7475

7576
const controls: ControlBarControls = {
7677
leave: true,
@@ -80,6 +81,15 @@ export const SessionView = ({
8081
screenShare: appConfig.supportsVideoInput,
8182
};
8283

84+
useEffect(() => {
85+
const lastMessage = messages.at(-1);
86+
const lastMessageIsLocal = lastMessage?.from?.isLocal === true;
87+
88+
if (scrollAreaRef.current && lastMessageIsLocal) {
89+
scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight;
90+
}
91+
}, [messages]);
92+
8393
return (
8494
<section className="bg-background relative z-10 h-full w-full overflow-hidden" {...props}>
8595
{/* Chat Transcript */}
@@ -90,7 +100,7 @@ export const SessionView = ({
90100
)}
91101
>
92102
<Fade top className="absolute inset-x-4 top-0 h-40" />
93-
<ScrollArea className="px-4 pt-40 pb-[150px] md:px-6 md:pb-[180px]">
103+
<ScrollArea ref={scrollAreaRef} className="px-4 pt-40 pb-[150px] md:px-6 md:pb-[180px]">
94104
<ChatTranscript
95105
hidden={!chatOpen}
96106
messages={messages}

components/livekit/scroll-area/hooks/useAutoScroll.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect } from 'react';
22

3-
const AUTO_SCROLL_THRESHOLD_PX = 50;
3+
const AUTO_SCROLL_THRESHOLD_PX = 100;
44

55
export function useAutoScroll(scrollContentContainer?: Element | null) {
66
useEffect(() => {
Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
11
'use client';
22

3-
import { useRef } from 'react';
3+
import { forwardRef, useCallback, useRef } from 'react';
44
import { useAutoScroll } from '@/components/livekit/scroll-area/hooks/useAutoScroll';
55
import { cn } from '@/lib/utils';
66

77
interface ScrollAreaProps {
88
children?: React.ReactNode;
9+
className?: string;
910
}
1011

11-
export function ScrollArea({
12-
className,
13-
children,
14-
}: ScrollAreaProps & React.HTMLAttributes<HTMLDivElement>) {
12+
export const ScrollArea = forwardRef<HTMLDivElement, ScrollAreaProps>(function ScrollArea(
13+
{ className, children },
14+
ref
15+
) {
1516
const scrollContentRef = useRef<HTMLDivElement>(null);
1617

1718
useAutoScroll(scrollContentRef.current);
1819

20+
const mergedRef = useCallback(
21+
(node: HTMLDivElement | null) => {
22+
scrollContentRef.current = node;
23+
24+
if (typeof ref === 'function') {
25+
ref(node);
26+
} else if (ref) {
27+
ref.current = node;
28+
}
29+
},
30+
[ref]
31+
);
32+
1933
return (
20-
<div ref={scrollContentRef} className={cn('overflow-y-scroll scroll-smooth', className)}>
34+
<div ref={mergedRef} className={cn('overflow-y-scroll scroll-smooth', className)}>
2135
<div>{children}</div>
2236
</div>
2337
);
24-
}
38+
});

0 commit comments

Comments
 (0)