80 lines
1.8 KiB
JavaScript
80 lines
1.8 KiB
JavaScript
import { useEffect, useRef } from "react";
|
|
import Lenis from "lenis";
|
|
import { gsap } from "gsap";
|
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
|
|
let scrollTriggerRegistered = false;
|
|
|
|
const registerScrollTrigger = () => {
|
|
if (!scrollTriggerRegistered) {
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
scrollTriggerRegistered = true;
|
|
}
|
|
};
|
|
|
|
function useLenisSmoothScroll(dependencyKey = "") {
|
|
const lenisRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") {
|
|
return undefined;
|
|
}
|
|
|
|
const prefersReducedMotion = window.matchMedia(
|
|
"(prefers-reduced-motion: reduce)"
|
|
).matches;
|
|
|
|
if (prefersReducedMotion) {
|
|
return undefined;
|
|
}
|
|
|
|
registerScrollTrigger();
|
|
|
|
const lenis = new Lenis({
|
|
anchors: {
|
|
duration: 1.05,
|
|
easing: (time) => 1 - Math.pow(1 - time, 4),
|
|
},
|
|
duration: 1.1,
|
|
easing: (time) => Math.min(1, 1.001 - Math.pow(2, -10 * time)),
|
|
lerp: 0.09,
|
|
smoothWheel: true,
|
|
syncTouch: false,
|
|
wheelMultiplier: 0.9,
|
|
});
|
|
lenisRef.current = lenis;
|
|
|
|
const updateScrollTrigger = () => ScrollTrigger.update();
|
|
const raf = (time) => {
|
|
lenis.raf(time * 1000);
|
|
};
|
|
|
|
lenis.on("scroll", updateScrollTrigger);
|
|
gsap.ticker.add(raf);
|
|
gsap.ticker.lagSmoothing(0);
|
|
|
|
return () => {
|
|
lenis.off("scroll", updateScrollTrigger);
|
|
gsap.ticker.remove(raf);
|
|
lenis.destroy();
|
|
lenisRef.current = null;
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") {
|
|
return undefined;
|
|
}
|
|
|
|
const frame = window.requestAnimationFrame(() => {
|
|
lenisRef.current?.scrollTo(0, { immediate: true, force: true });
|
|
window.scrollTo(0, 0);
|
|
ScrollTrigger.refresh();
|
|
});
|
|
|
|
return () => window.cancelAnimationFrame(frame);
|
|
}, [dependencyKey]);
|
|
}
|
|
|
|
export default useLenisSmoothScroll;
|