57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
import { useEffect, useRef } from "react";
|
|
|
|
export const useSmoothScroll = (ease = 0.08) => {
|
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
const current = useRef(0);
|
|
const target = useRef(0);
|
|
const animationId = useRef<number | null>(null);
|
|
|
|
useEffect(() => {
|
|
const container = containerRef.current;
|
|
if (!container) return;
|
|
|
|
const setBodyHeight = () => {
|
|
document.body.style.height = `${container.getBoundingClientRect().height}px`;
|
|
};
|
|
|
|
const update = () => {
|
|
const diff = target.current - current.current;
|
|
|
|
current.current += diff * ease;
|
|
if (Math.abs(diff) < 0.1) current.current = target.current;
|
|
|
|
const y = -current.current;
|
|
|
|
// ✅ Smooth transform only
|
|
container.style.transform = `translate3d(0, ${y}px, 0)`;
|
|
animationId.current = requestAnimationFrame(update);
|
|
};
|
|
|
|
const handleScroll = () => {
|
|
// ✅ Track native scroll instead of preventing it
|
|
target.current = window.scrollY;
|
|
};
|
|
|
|
const handleResize = () => {
|
|
setBodyHeight();
|
|
};
|
|
|
|
setBodyHeight();
|
|
|
|
// ✅ Use native scroll, not preventDefault
|
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
window.addEventListener("resize", handleResize);
|
|
|
|
animationId.current = requestAnimationFrame(update);
|
|
|
|
return () => {
|
|
if (animationId.current) cancelAnimationFrame(animationId.current);
|
|
window.removeEventListener("scroll", handleScroll);
|
|
window.removeEventListener("resize", handleResize);
|
|
document.body.style.height = "";
|
|
};
|
|
}, [ease]);
|
|
|
|
return containerRef;
|
|
};
|