Skip to content

Commit 83096a3

Browse files
axin7123vivekr
authored andcommitted
fix(ui): improve message scroll behavior to ensure bottom content visibility
- Implement dual-phase scrolling: virtualizer positioning + native scroll to bottom - Reduce excessive bottom padding from pb-40 to pb-20 for better viewport usage - Unify scroll behavior across auto-scroll, history loading, and manual scroll - Fix issue where streamed content bottom couldn't reach viewport
1 parent 97c6651 commit 83096a3

File tree

1 file changed

+46
-16
lines changed

1 file changed

+46
-16
lines changed

src/components/ClaudeCodeSession.tsx

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,22 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
274274
// Auto-scroll to bottom when new messages arrive
275275
useEffect(() => {
276276
if (displayableMessages.length > 0) {
277-
rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { align: 'end', behavior: 'smooth' });
277+
// Use a more precise scrolling method to ensure content is fully visible
278+
setTimeout(() => {
279+
const scrollElement = parentRef.current;
280+
if (scrollElement) {
281+
// First, scroll using virtualizer to get close to the bottom
282+
rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { align: 'end', behavior: 'auto' });
283+
284+
// Then use direct scroll to ensure we reach the absolute bottom
285+
requestAnimationFrame(() => {
286+
scrollElement.scrollTo({
287+
top: scrollElement.scrollHeight,
288+
behavior: 'smooth'
289+
});
290+
});
291+
}
292+
}, 50);
278293
}
279294
}, [displayableMessages.length, rowVirtualizer]);
280295

@@ -326,7 +341,17 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
326341
// Scroll to bottom after loading history
327342
setTimeout(() => {
328343
if (loadedMessages.length > 0) {
329-
rowVirtualizer.scrollToIndex(loadedMessages.length - 1, { align: 'end', behavior: 'auto' });
344+
const scrollElement = parentRef.current;
345+
if (scrollElement) {
346+
// Use the same improved scrolling method
347+
rowVirtualizer.scrollToIndex(loadedMessages.length - 1, { align: 'end', behavior: 'auto' });
348+
requestAnimationFrame(() => {
349+
scrollElement.scrollTo({
350+
top: scrollElement.scrollHeight,
351+
behavior: 'auto'
352+
});
353+
});
354+
}
330355
}
331356
}, 100);
332357
} catch (err) {
@@ -1141,7 +1166,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
11411166
const messagesList = (
11421167
<div
11431168
ref={parentRef}
1144-
className="flex-1 overflow-y-auto relative pb-40"
1169+
className="flex-1 overflow-y-auto relative pb-20"
11451170
style={{
11461171
contain: 'strict',
11471172
}}
@@ -1187,7 +1212,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
11871212
initial={{ opacity: 0, y: 8 }}
11881213
animate={{ opacity: 1, y: 0 }}
11891214
transition={{ duration: 0.15 }}
1190-
className="flex items-center justify-center py-4 mb-40"
1215+
className="flex items-center justify-center py-4 mb-20"
11911216
>
11921217
<div className="rotating-symbol text-primary" />
11931218
</motion.div>
@@ -1199,7 +1224,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
11991224
initial={{ opacity: 0, y: 8 }}
12001225
animate={{ opacity: 1, y: 0 }}
12011226
transition={{ duration: 0.15 }}
1202-
className="rounded-lg border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive mb-40 w-full max-w-6xl mx-auto"
1227+
className="rounded-lg border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive mb-20 w-full max-w-6xl mx-auto"
12031228
>
12041229
{error}
12051230
</motion.div>
@@ -1409,18 +1434,23 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
14091434
variant="ghost"
14101435
size="sm"
14111436
onClick={() => {
1412-
// Use virtualizer to scroll to the last item
1413-
if (displayableMessages.length > 0) {
1414-
// Scroll to bottom of the container
1415-
const scrollElement = parentRef.current;
1416-
if (scrollElement) {
1417-
scrollElement.scrollTo({
1418-
top: scrollElement.scrollHeight,
1419-
behavior: 'smooth'
1420-
});
1437+
// Use the improved scrolling method for manual scroll to bottom
1438+
if (displayableMessages.length > 0) {
1439+
const scrollElement = parentRef.current;
1440+
if (scrollElement) {
1441+
// First, scroll using virtualizer to get close to the bottom
1442+
rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { align: 'end', behavior: 'auto' });
1443+
1444+
// Then use direct scroll to ensure we reach the absolute bottom
1445+
requestAnimationFrame(() => {
1446+
scrollElement.scrollTo({
1447+
top: scrollElement.scrollHeight,
1448+
behavior: 'smooth'
1449+
});
1450+
});
1451+
}
14211452
}
1422-
}
1423-
}}
1453+
}}
14241454
className="px-3 py-2 hover:bg-accent rounded-none"
14251455
>
14261456
<ChevronDown className="h-4 w-4" />

0 commit comments

Comments
 (0)