From d297282320da8808cab5d43c0d46655532a1bd31 Mon Sep 17 00:00:00 2001 From: Alois Date: Sun, 24 May 2026 20:37:57 +0200 Subject: [PATCH] (fix): chat message measurement (qol): update todos --- packages/call/todo.md | 1 - packages/chat/src/screen.tsx | 49 +++++++++++++++++++++++++++++++++--- packages/chat/todo.md | 1 + 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 packages/chat/todo.md diff --git a/packages/call/todo.md b/packages/call/todo.md index 61d70ed..4db4db0 100644 --- a/packages/call/todo.md +++ b/packages/call/todo.md @@ -11,4 +11,3 @@ - Desktop-App screenshares - Context menus - Popout Window -- If micGated=true & isSpeaking=false for 5 seconds show banner with mic detection diff --git a/packages/chat/src/screen.tsx b/packages/chat/src/screen.tsx index 30344a5..f72580d 100644 --- a/packages/chat/src/screen.tsx +++ b/packages/chat/src/screen.tsx @@ -8,6 +8,7 @@ import Message from "./components/message"; import { PAGE_SIZE } from "./values"; import { useIsMobile } from "@tensamin/ui"; +import { Loader2 } from "lucide-react"; function getDistanceFromBottom(element: HTMLDivElement) { return element.scrollHeight - (element.scrollTop + element.clientHeight); @@ -360,9 +361,38 @@ export default function Screen() { return; } - scrollRef.current.scrollTop = scrollRef.current.scrollHeight; - isAtBottomRef.current = true; - setHasScrolledToBottomInitially(true); + let rafId: number; + let stableFrames = 0; + let lastScrollHeight = 0; + + const settleToBottom = () => { + if (!scrollRef.current || hasScrolledToBottomInitially) { + return; + } + + scrollRef.current.scrollTop = scrollRef.current.scrollHeight; + const currentScrollHeight = scrollRef.current.scrollHeight; + + if (currentScrollHeight === lastScrollHeight) { + stableFrames++; + } else { + stableFrames = 0; + lastScrollHeight = currentScrollHeight; + } + + if (stableFrames >= 2) { + isAtBottomRef.current = true; + setHasScrolledToBottomInitially(true); + } else { + rafId = requestAnimationFrame(settleToBottom); + } + }; + + settleToBottom(); + + return () => { + cancelAnimationFrame(rafId); + }; }, [hasScrolledToBottomInitially, virtualRowCount]); React.useLayoutEffect(() => { @@ -442,6 +472,19 @@ export default function Screen() { }} onScroll={handleContainerScroll} > + {messagesQuery.isPending && ( +
+

+ + Loading... +

+
+ )} + {messagesQuery.isFetchingNextPage && ( +
+ +
+ )}