forked from Mirrors/gomuks
web/timeline: keep scroll position when loading history
This commit is contained in:
parent
39ed3956f8
commit
8d669902d9
1 changed files with 22 additions and 6 deletions
|
@ -32,20 +32,36 @@ const TimelineView = ({ room }: TimelineViewProps) => {
|
||||||
.catch(err => console.error("Failed to load history", err))
|
.catch(err => console.error("Failed to load history", err))
|
||||||
}, [client, room.roomID])
|
}, [client, room.roomID])
|
||||||
const bottomRef = useRef<HTMLDivElement>(null)
|
const bottomRef = useRef<HTMLDivElement>(null)
|
||||||
const isAtBottom = useRef(true)
|
const timelineViewRef = useRef<HTMLDivElement>(null)
|
||||||
|
const prevOldestTimelineRow = useRef(0)
|
||||||
|
const oldScrollHeight = useRef(0)
|
||||||
|
const scrolledToBottom = useRef(true)
|
||||||
|
|
||||||
|
// When the user scrolls the timeline manually, remember if they were at the bottom,
|
||||||
|
// so that we can keep them at the bottom when new events are added.
|
||||||
const handleScroll = useMemo(() => () => {
|
const handleScroll = useMemo(() => () => {
|
||||||
if (!bottomRef.current?.parentElement) {
|
if (!timelineViewRef.current) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const timelineView = bottomRef.current.parentElement
|
const timelineView = timelineViewRef.current
|
||||||
isAtBottom.current = timelineView.scrollTop + timelineView.clientHeight + 1 >= timelineView.scrollHeight
|
scrolledToBottom.current = timelineView.scrollTop + timelineView.clientHeight + 1 >= timelineView.scrollHeight
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(() => {
|
// Save the scroll height prior to updating the timeline, so that we can adjust the scroll position if needed.
|
||||||
if (bottomRef.current && isAtBottom.current) {
|
if (timelineViewRef.current) {
|
||||||
bottomRef.current.scrollIntoView()
|
oldScrollHeight.current = timelineViewRef.current.scrollHeight
|
||||||
}
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
if (bottomRef.current && scrolledToBottom.current) {
|
||||||
|
// For any timeline changes, if we were at the bottom, scroll to the new bottom
|
||||||
|
bottomRef.current.scrollIntoView()
|
||||||
|
} else if (timelineViewRef.current && prevOldestTimelineRow.current > timeline[0]?.timeline_rowid) {
|
||||||
|
// When new entries are added to the top of the timeline, scroll down to keep the same position
|
||||||
|
timelineViewRef.current.scrollTop += timelineViewRef.current.scrollHeight - oldScrollHeight.current
|
||||||
|
}
|
||||||
|
prevOldestTimelineRow.current = timeline[0]?.timeline_rowid ?? 0
|
||||||
}, [timeline])
|
}, [timeline])
|
||||||
return <div className="timeline-view" onScroll={handleScroll}>
|
|
||||||
|
return <div className="timeline-view" onScroll={handleScroll} ref={timelineViewRef}>
|
||||||
<button onClick={loadHistory}>Load history</button>
|
<button onClick={loadHistory}>Load history</button>
|
||||||
{timeline.map(entry => <TimelineEvent
|
{timeline.map(entry => <TimelineEvent
|
||||||
key={entry.event_rowid} room={room} eventRowID={entry.event_rowid}
|
key={entry.event_rowid} room={room} eventRowID={entry.event_rowid}
|
||||||
|
|
Loading…
Add table
Reference in a new issue