Spaces:
Build error
Build error
import { RefObject, useEffect, useState, useCallback, useRef } from "react"; | |
export function useScrollToBottom(scrollRef: RefObject<HTMLDivElement | null>) { | |
// Track whether we should auto-scroll to the bottom when content changes | |
const [autoscroll, setAutoscroll] = useState(true); | |
// Track whether the user is currently at the bottom of the scroll area | |
const [hitBottom, setHitBottom] = useState(true); | |
// Store previous scroll position to detect scroll direction | |
const prevScrollTopRef = useRef<number>(0); | |
// Check if the scroll position is at the bottom | |
const isAtBottom = useCallback((element: HTMLElement): boolean => { | |
// Use a fixed 20px buffer | |
const bottomThreshold = 20; | |
const bottomPosition = element.scrollTop + element.clientHeight; | |
return bottomPosition >= element.scrollHeight - bottomThreshold; | |
}, []); | |
// Handle scroll events | |
const onChatBodyScroll = useCallback( | |
(e: HTMLElement) => { | |
const isCurrentlyAtBottom = isAtBottom(e); | |
setHitBottom(isCurrentlyAtBottom); | |
// Get current scroll position | |
const currentScrollTop = e.scrollTop; | |
// Detect scroll direction | |
const isScrollingUp = currentScrollTop < prevScrollTopRef.current; | |
// Update previous scroll position for next comparison | |
prevScrollTopRef.current = currentScrollTop; | |
// Turn off autoscroll only when scrolling up | |
if (isScrollingUp) { | |
setAutoscroll(false); | |
} | |
// Turn on autoscroll when scrolled to the bottom | |
if (isCurrentlyAtBottom) { | |
setAutoscroll(true); | |
} | |
}, | |
[isAtBottom], | |
); | |
// Scroll to bottom function with animation | |
const scrollDomToBottom = useCallback(() => { | |
const dom = scrollRef.current; | |
if (dom) { | |
requestAnimationFrame(() => { | |
// Set autoscroll to true when manually scrolling to bottom | |
setAutoscroll(true); | |
setHitBottom(true); | |
// Use smooth scrolling but with a fast duration | |
dom.scrollTo({ | |
top: dom.scrollHeight, | |
behavior: "smooth", | |
}); | |
}); | |
} | |
}, [scrollRef]); | |
// Auto-scroll effect that runs when content changes | |
useEffect(() => { | |
// Only auto-scroll if autoscroll is enabled | |
if (autoscroll) { | |
const dom = scrollRef.current; | |
if (dom) { | |
requestAnimationFrame(() => { | |
dom.scrollTo({ | |
top: dom.scrollHeight, | |
behavior: "smooth", | |
}); | |
}); | |
} | |
} | |
}); | |
return { | |
scrollRef, | |
autoScroll: autoscroll, | |
setAutoScroll: setAutoscroll, | |
scrollDomToBottom, | |
hitBottom, | |
setHitBottom, | |
onChatBodyScroll, | |
}; | |
} | |