From 01bffa3c8ccb41655361e746775e86829a9bea7d Mon Sep 17 00:00:00 2001 From: Ananovo Date: Sat, 1 Aug 2026 17:10:38 +0800 Subject: [PATCH] fix(web): stabilize chat scrolling and mobile alignment (#1278) * fix(web): stabilize chat scrolling and mobile alignment * fix(web): scope chat scroll containment --- .../components/AssistantChat/HappyThread.tsx | 26 +++++++++++++++++-- web/src/index.css | 22 ++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/web/src/components/AssistantChat/HappyThread.tsx b/web/src/components/AssistantChat/HappyThread.tsx index a4700112..9bb73e39 100644 --- a/web/src/components/AssistantChat/HappyThread.tsx +++ b/web/src/components/AssistantChat/HappyThread.tsx @@ -461,6 +461,28 @@ export function HappyThread(props: { failureCount: 0, autoPaused: false }) + + useLayoutEffect(() => { + const viewport = viewportRef.current + if (!viewport) return + + const updateScrollbarGutter = () => { + const supportsStableBothEdges = typeof CSS !== 'undefined' + && typeof CSS.supports === 'function' + && CSS.supports('scrollbar-gutter: stable both-edges') + const gutter = supportsStableBothEdges + ? Math.max(0, (viewport.offsetWidth - viewport.clientWidth) / 2) + : 0 + viewport.style.setProperty('--chat-scroll-gutter-inline', `${gutter}px`) + } + + updateScrollbarGutter() + if (typeof ResizeObserver === 'undefined') return + + const observer = new ResizeObserver(updateScrollbarGutter) + observer.observe(viewport) + return () => observer.disconnect() + }, []) const requestOlderRef = useRef<(source: HistoryLoadSource) => Promise>( () => Promise.resolve('transient-stop') ) @@ -1414,10 +1436,10 @@ export function HappyThread(props: { >
-
+