Fix Jump to Latest sticking visible while scrolled to the live bottom.
This commit is contained in:
@@ -785,9 +785,16 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||||||
atLiveEndRef.current = liveTimelineLinked && rangeAtEnd;
|
atLiveEndRef.current = liveTimelineLinked && rangeAtEnd;
|
||||||
|
|
||||||
// Historical / non-live windows are never "at bottom" of the room.
|
// Historical / non-live windows are never "at bottom" of the room.
|
||||||
|
// When we return to the live end, re-check scroll — IntersectionObserver may
|
||||||
|
// not re-fire if the anchor stayed intersecting across the transition.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!liveTimelineLinked || !rangeAtEnd) {
|
if (!liveTimelineLinked || !rangeAtEnd) {
|
||||||
setAtBottom(false);
|
setAtBottom(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const scrollEl = scrollRef.current;
|
||||||
|
if (scrollEl && isScrolledToBottom(scrollEl, 100)) {
|
||||||
|
setAtBottom(true);
|
||||||
}
|
}
|
||||||
}, [liveTimelineLinked, rangeAtEnd]);
|
}, [liveTimelineLinked, rangeAtEnd]);
|
||||||
|
|
||||||
@@ -1034,11 +1041,16 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||||||
if (!targetEntry) return;
|
if (!targetEntry) return;
|
||||||
|
|
||||||
// Leave the live bottom immediately so Jump to Latest stays available.
|
// Leave the live bottom immediately so Jump to Latest stays available.
|
||||||
if (!targetEntry.isIntersecting || !atLiveEndRef.current) {
|
// Only intersection clears atBottom here; !atLiveEnd is handled by the
|
||||||
|
// liveTimelineLinked/rangeAtEnd effect so we don't stick false when the
|
||||||
|
// live end reconnects without a new intersection event.
|
||||||
|
if (!targetEntry.isIntersecting) {
|
||||||
setAtBottom(false);
|
setAtBottom(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!atLiveEndRef.current) return;
|
||||||
|
|
||||||
setAtBottom(true);
|
setAtBottom(true);
|
||||||
setLatestUnreadMessage(null);
|
setLatestUnreadMessage(null);
|
||||||
if (document.hasFocus()) {
|
if (document.hasFocus()) {
|
||||||
@@ -1145,7 +1157,16 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||||||
const onScroll = () => {
|
const onScroll = () => {
|
||||||
if (restoringScrollRef.current) return;
|
if (restoringScrollRef.current) return;
|
||||||
window.cancelAnimationFrame(raf);
|
window.cancelAnimationFrame(raf);
|
||||||
raf = window.requestAnimationFrame(() => persistTimelineScroll(roomId));
|
raf = window.requestAnimationFrame(() => {
|
||||||
|
persistTimelineScroll(roomId);
|
||||||
|
// Keep Jump to Latest in sync with real scroll position when on the live end.
|
||||||
|
// IntersectionObserver alone can miss transitions and leave atBottom stuck.
|
||||||
|
if (atLiveEndRef.current) {
|
||||||
|
const at = isScrolledToBottom(scrollEl, 100);
|
||||||
|
setAtBottom(at);
|
||||||
|
if (at) setLatestUnreadMessage(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
scrollEl.addEventListener('scroll', onScroll, { passive: true });
|
scrollEl.addEventListener('scroll', onScroll, { passive: true });
|
||||||
@@ -1250,6 +1271,9 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||||||
scrollToBottomRef.current.smooth,
|
scrollToBottomRef.current.smooth,
|
||||||
scrollToBottomRef.current.force
|
scrollToBottomRef.current.force
|
||||||
);
|
);
|
||||||
|
if (atLiveEndRef.current) {
|
||||||
|
setAtBottom(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [scrollToBottomCount]);
|
}, [scrollToBottomCount]);
|
||||||
@@ -2588,7 +2612,12 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
|
|||||||
</MessageBase>
|
</MessageBase>
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
<span ref={atBottomAnchorRef} />
|
{/* 1×1 so IntersectionObserver reliably detects the live bottom */}
|
||||||
|
<span
|
||||||
|
ref={atBottomAnchorRef}
|
||||||
|
aria-hidden
|
||||||
|
style={{ display: 'block', width: 1, height: 1 }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Scroll>
|
</Scroll>
|
||||||
{(showUnreadTop || returnToEventId) && (
|
{(showUnreadTop || returnToEventId) && (
|
||||||
|
|||||||
Reference in New Issue
Block a user