From ffa6b7076d5a7cc172781129c8f2eec8bba004a5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:02:35 +0000 Subject: [PATCH] fix(dm): prevent repeated peek animation on re-renders Use module-level variables to track if the peek animation has played for ConversationList and MessageThread, ensuring it only runs once per page session to avoid annoying scrolling behavior. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- js/ui/dm/ConversationList.js | 6 +++++- js/ui/dm/MessageThread.js | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/js/ui/dm/ConversationList.js b/js/ui/dm/ConversationList.js index 5aec1cd4..fc6f7545 100644 --- a/js/ui/dm/ConversationList.js +++ b/js/ui/dm/ConversationList.js @@ -1,5 +1,7 @@ import { ContactRow } from "./ContactRow.js"; +let hasPeekAnimationPlayed = false; + function createElement(doc, tag, className, text) { const element = doc.createElement(tag); if (className) { @@ -93,12 +95,13 @@ export function ConversationList({ }); // Peek animation - if (conversations.length > 0) { + if (conversations.length > 0 && !hasPeekAnimationPlayed) { if (typeof IntersectionObserver !== "undefined") { const observer = new IntersectionObserver((entries) => { const entry = entries[0]; if (entry.isIntersecting) { observer.disconnect(); + hasPeekAnimationPlayed = true; setTimeout(() => { if (list.scrollHeight > list.clientHeight) { list.scrollTo({ top: 40, behavior: "smooth" }); @@ -112,6 +115,7 @@ export function ConversationList({ observer.observe(list); } else { // Fallback for no IntersectionObserver (e.g. some tests or very old browsers) + hasPeekAnimationPlayed = true; setTimeout(() => { if (list.scrollHeight > list.clientHeight) { list.scrollTo({ top: 40, behavior: "smooth" }); diff --git a/js/ui/dm/MessageThread.js b/js/ui/dm/MessageThread.js index de405db2..e03f734d 100644 --- a/js/ui/dm/MessageThread.js +++ b/js/ui/dm/MessageThread.js @@ -1,6 +1,8 @@ import { DayDivider } from "./DayDivider.js"; import { MessageBubble } from "./MessageBubble.js"; +let hasPeekAnimationPlayed = false; + function createElement(doc, tag, className, text) { const element = doc.createElement(tag); if (className) { @@ -142,10 +144,13 @@ export function MessageThread({ // Scroll to bottom and peek if (messages.length > 0) { - const animate = () => { - timeline.scrollTop = timeline.scrollHeight; + const performPeek = () => { + if (hasPeekAnimationPlayed) { + return; + } if (timeline.scrollHeight > timeline.clientHeight) { + hasPeekAnimationPlayed = true; setTimeout(() => { const targetScroll = Math.max(0, timeline.scrollTop - 40); timeline.scrollTo({ top: targetScroll, behavior: "smooth" }); @@ -160,6 +165,11 @@ export function MessageThread({ } }; + const initializeScroll = () => { + timeline.scrollTop = timeline.scrollHeight; + performPeek(); + }; + if (typeof IntersectionObserver !== "undefined") { const observer = new IntersectionObserver((entries) => { const entry = entries[0]; @@ -167,15 +177,12 @@ export function MessageThread({ observer.disconnect(); // First ensure we are at bottom timeline.scrollTop = timeline.scrollHeight; - setTimeout(animate, 300); + setTimeout(initializeScroll, 300); } }, { threshold: 0.1 }); observer.observe(timeline); } else { - setTimeout(() => { - timeline.scrollTop = timeline.scrollHeight; - animate(); - }, 0); + setTimeout(initializeScroll, 0); } }