@@ -10,30 +10,55 @@ interface Message {
1010
1111interface MessageListProps {
1212 messages : Message [ ] ;
13+ loading ?: boolean ;
1314}
1415
15- export default function MessageList ( { messages } : MessageListProps ) {
16+ export default function MessageList ( {
17+ messages,
18+ loading = false ,
19+ } : MessageListProps ) {
1620 const messagesEndRef = useRef < HTMLDivElement > ( null ) ;
21+ const prevMessagesLengthRef = useRef < number > ( 0 ) ;
22+ const prevLoadingRef = useRef < boolean > ( false ) ;
1723
18- // Only scroll to bottom when new messages are added or updated
24+ // Enhanced scrolling behavior to handle:
25+ // 1. New messages being added
26+ // 2. Loading indicator appearing/disappearing
27+ // 3. New user messages (to ensure they're always visible)
1928 useEffect ( ( ) => {
20- const shouldScroll = messagesEndRef . current && messages . length > 0 ;
21- if ( shouldScroll ) {
22- // Store current scroll position and total scroll height
23- const messageContainer = messagesEndRef . current ?. parentElement ;
24- if ( messageContainer ) {
25- // Only scroll if we're already near the bottom or if messages length has changed
26- const isNearBottom =
27- messageContainer . scrollHeight -
28- messageContainer . scrollTop -
29- messageContainer . clientHeight <
30- 100 ;
31- if ( isNearBottom ) {
32- messagesEndRef . current ?. scrollIntoView ( { behavior : "smooth" } ) ;
33- }
29+ const lastMessage = messages [ messages . length - 1 ] ;
30+ const isNewUserMessage =
31+ messages . length > prevMessagesLengthRef . current &&
32+ lastMessage ?. role === "user" ;
33+
34+ const loadingChanged = loading !== prevLoadingRef . current ;
35+
36+ // Store current scroll position and total scroll height
37+ const messageContainer = messagesEndRef . current ?. parentElement ;
38+ if ( messagesEndRef . current && messageContainer ) {
39+ // Determine if we should force scroll
40+ const shouldForceScroll =
41+ isNewUserMessage || // New user message added
42+ loading || // Loading indicator is active
43+ loadingChanged ; // Loading state changed
44+
45+ // Check if we're already near the bottom
46+ const isNearBottom =
47+ messageContainer . scrollHeight -
48+ messageContainer . scrollTop -
49+ messageContainer . clientHeight <
50+ 100 ;
51+
52+ // Scroll if we're forced to or if we're already near the bottom
53+ if ( shouldForceScroll || isNearBottom ) {
54+ messagesEndRef . current . scrollIntoView ( { behavior : "smooth" } ) ;
3455 }
3556 }
36- } , [ messages ] ) ;
57+
58+ // Update references for next comparison
59+ prevMessagesLengthRef . current = messages . length ;
60+ prevLoadingRef . current = loading ;
61+ } , [ messages , loading ] ) ;
3762
3863 // If no messages, show a placeholder
3964 if ( messages . length === 0 ) {
@@ -44,6 +69,24 @@ export default function MessageList({ messages }: MessageListProps) {
4469 ) ;
4570 }
4671
72+ // Define a component for the animated dots
73+ const LoadingDots = ( ) => (
74+ < div className = "flex space-x-1" >
75+ < div
76+ className = "w-2 h-2 rounded-full bg-white animate-pulse"
77+ style = { { animationDelay : "0ms" } }
78+ > </ div >
79+ < div
80+ className = "w-2 h-2 rounded-full bg-white animate-pulse"
81+ style = { { animationDelay : "300ms" } }
82+ > </ div >
83+ < div
84+ className = "w-2 h-2 rounded-full bg-white animate-pulse"
85+ style = { { animationDelay : "600ms" } }
86+ > </ div >
87+ </ div >
88+ ) ;
89+
4790 return (
4891 < div className = "flex-1 overflow-y-auto p-4 bg-white" >
4992 { messages . map ( ( message ) => (
@@ -71,6 +114,19 @@ export default function MessageList({ messages }: MessageListProps) {
71114 </ div >
72115 </ div >
73116 ) ) }
117+
118+ { /* Loading indicator for message being sent */ }
119+ { loading && (
120+ < div className = "mb-4 text-right" >
121+ < div className = "inline-block px-4 py-2 rounded-lg bg-blue-500 text-white rounded-tr-none" >
122+ < div className = "text-xs mb-1 font-bold text-left" > You</ div >
123+ < div className = "h-6 flex items-center" >
124+ < LoadingDots />
125+ </ div >
126+ </ div >
127+ </ div >
128+ ) }
129+
74130 < div ref = { messagesEndRef } />
75131 </ div >
76132 ) ;
0 commit comments