fix: Stop autoscroll when user manually scrolls up during streaming (#16795)

https://github.com/user-attachments/assets/2ca908ca-63b8-4895-9ed7-7beaeea13ca9
This commit is contained in:
Abdul Rahman
2025-12-27 13:49:44 +05:30
committed by GitHub
parent 7400a3051c
commit 952dee955c
2 changed files with 23 additions and 4 deletions
@@ -8,7 +8,7 @@ export const AgentChatMessagesEffect = ({
}: {
messages: ExtendedUIMessage[];
}) => {
const { scrollToBottom } = useAgentChatScrollToBottom();
const { scrollToBottom, isNearBottom } = useAgentChatScrollToBottom();
const [, setPreviousMessages] = useState<ExtendedUIMessage[] | null>(null);
useEffect(() => {
@@ -22,10 +22,18 @@ export const AgentChatMessagesEffect = ({
// We intentionally force this effect because the chat transport streams messages incrementally
// and the only reliable way to react to those chunks is through useEffect updates.
scrollToBottom();
const isNewMessage =
previousMessages === null ||
messages.length !== previousMessages.length;
if (isNewMessage || isNearBottom) {
scrollToBottom();
}
return messages;
});
}, [messages, scrollToBottom]);
}, [messages, scrollToBottom, isNearBottom]);
return null;
};
@@ -1,12 +1,23 @@
import { AI_CHAT_SCROLL_WRAPPER_ID } from '@/ai/constants/AiChatScrollWrapperId';
import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperHTMLElement';
import { scrollWrapperScrollBottomComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollBottomComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { isDefined } from 'twenty-shared/utils';
const SCROLL_BOTTOM_THRESHOLD_PX = 10;
export const useAgentChatScrollToBottom = () => {
const { getScrollWrapperElement } = useScrollWrapperHTMLElement(
AI_CHAT_SCROLL_WRAPPER_ID,
);
const scrollBottom = useRecoilComponentValue(
scrollWrapperScrollBottomComponentState,
AI_CHAT_SCROLL_WRAPPER_ID,
);
const isNearBottom = scrollBottom <= SCROLL_BOTTOM_THRESHOLD_PX;
const scrollToBottom = () => {
const { scrollWrapperElement } = getScrollWrapperElement();
if (!isDefined(scrollWrapperElement)) {
@@ -18,5 +29,5 @@ export const useAgentChatScrollToBottom = () => {
});
};
return { scrollToBottom };
return { scrollToBottom, isNearBottom };
};