Files

72 lines
1.6 KiB
TypeScript

"use client";
import type { ReactNode } from "react";
import { useEffect, useRef } from "react";
export function SmoothScrollProvider({
children,
}: {
children: ReactNode;
}) {
const teardownRef = useRef<() => void>(() => {});
useEffect(() => {
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)",
).matches;
const hasCoarsePointer = window.matchMedia("(pointer: coarse)").matches;
if (prefersReducedMotion || hasCoarsePointer) {
return undefined;
}
let isMounted = true;
const setupSmoothScroll = async () => {
const [{ default: Lenis }, { gsap }, { ScrollTrigger }] =
await Promise.all([
import("lenis"),
import("gsap"),
import("gsap/ScrollTrigger"),
]);
if (!isMounted) {
return;
}
gsap.registerPlugin(ScrollTrigger);
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
smoothWheel: true,
});
const handleScroll = () => ScrollTrigger.update();
const tick = (time: number) => {
lenis.raf(time * 1000);
};
lenis.on("scroll", handleScroll);
gsap.ticker.add(tick);
gsap.ticker.lagSmoothing(0);
teardownRef.current = () => {
lenis.off?.("scroll", handleScroll);
gsap.ticker.remove(tick);
lenis.destroy();
};
};
void setupSmoothScroll();
return () => {
isMounted = false;
teardownRef.current();
teardownRef.current = () => {};
};
}, []);
return <>{children}</>;
}