feat: Add useScrollAnchor hook for scrolling functionality
This commit is contained in:
parent
024d0506f3
commit
f12523d3f0
87
src/hooks/useScrollAnchor.tsx
Normal file
87
src/hooks/useScrollAnchor.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
|
export const useScrollAnchor = () => {
|
||||||
|
const messagesRef = useRef<HTMLDivElement>(null)
|
||||||
|
const scrollRef = useRef<HTMLDivElement>(null)
|
||||||
|
const visibilityRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
const [isAtBottom, setIsAtBottom] = useState(true)
|
||||||
|
const [isVisible, setIsVisible] = useState(false)
|
||||||
|
|
||||||
|
const scrollToBottom = useCallback(() => {
|
||||||
|
if (messagesRef.current) {
|
||||||
|
messagesRef.current.scrollIntoView({
|
||||||
|
block: "end",
|
||||||
|
behavior: "smooth"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (messagesRef.current) {
|
||||||
|
if (isAtBottom && !isVisible) {
|
||||||
|
messagesRef.current.scrollIntoView({
|
||||||
|
block: "end"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isAtBottom, isVisible])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { current } = scrollRef
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
const handleScroll = (event: Event) => {
|
||||||
|
const target = event.target as HTMLDivElement
|
||||||
|
const offset = 25
|
||||||
|
const isAtBottom =
|
||||||
|
target.scrollTop + target.clientHeight >= target.scrollHeight - offset
|
||||||
|
console.log(target.scrollTop, target.clientHeight, target.scrollHeight)
|
||||||
|
setIsAtBottom(isAtBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
current.addEventListener("scroll", handleScroll, {
|
||||||
|
passive: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
current.removeEventListener("scroll", handleScroll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visibilityRef.current) {
|
||||||
|
let observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
console.log(entry.isIntersecting)
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setIsVisible(true)
|
||||||
|
} else {
|
||||||
|
setIsVisible(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rootMargin: "0px 0px -100px 0px"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
observer.observe(visibilityRef.current)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
messagesRef,
|
||||||
|
scrollRef,
|
||||||
|
visibilityRef,
|
||||||
|
scrollToBottom,
|
||||||
|
isAtBottom,
|
||||||
|
isVisible
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user