80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { ReactNode, useEffect } from "react";
|
|
import Lenis from "@studio-freight/lenis";
|
|
import gsap from 'gsap';
|
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
|
|
interface LenisProviderProps {
|
|
children: ReactNode;
|
|
root?: boolean; // If true, applies to the window scroll. If false, applies to a specific div.
|
|
className?: string; // Only relevant if root is false
|
|
}
|
|
|
|
/**
|
|
* Provides smooth scrolling using Lenis.
|
|
* This component should ideally wrap the entire application in layout.tsx.
|
|
* If `root` is false, it can be applied to a specific scrollable div.
|
|
*/
|
|
export function LenisSmoothScroll({ children, root = true, className }: LenisProviderProps) {
|
|
useEffect(() => {
|
|
const lenis = new Lenis({
|
|
duration: 1.2,
|
|
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xgi
|
|
orientation: "vertical", gestureOrientation: "vertical", smoothWheel: true,
|
|
wheelMultiplier: 1,
|
|
smoothTouch: false,
|
|
touchMultiplier: 2,
|
|
syncTouch: false,
|
|
infinite: false,
|
|
});
|
|
|
|
function raf(time: DOMHighResTimeStamp) {
|
|
lenis.raf(time);
|
|
requestAnimationFrame(raf);
|
|
}
|
|
|
|
requestAnimationFrame(raf);
|
|
|
|
// Integrate with GSAP ScrollTrigger
|
|
// This is crucial for GSAP ScrollTrigger to work correctly with Lenis.
|
|
// Ensure GSAP and ScrollTrigger are already registered globally or imported locally.
|
|
const syncScroll = () => {
|
|
// Check if GSAP and ScrollTrigger are available globally or imported.
|
|
// If using GSAP context, pass the context.
|
|
if (typeof window !== 'undefined' && window.innerWidth > 768) { // Example: only enable for larger screens
|
|
lenis.on('scroll', ScrollTrigger.update);
|
|
gsap.ticker.add((time) => {
|
|
lenis.raf(time * 1000)
|
|
})
|
|
gsap.ticker.lagSmoothing(0)
|
|
}
|
|
};
|
|
|
|
// Delay syncScroll to ensure ScrollTrigger is registered if it's external
|
|
const timeout = setTimeout(syncScroll, 0);
|
|
|
|
|
|
return () => {
|
|
clearTimeout(timeout);
|
|
lenis.destroy();
|
|
// Remove the listener for GSAP ScrollTrigger if it was added
|
|
if (typeof window !== 'undefined' && window.innerWidth > 768) {
|
|
gsap.ticker.remove(lenis.raf)
|
|
// lenis.off('scroll', ScrollTrigger.update); // Lenis handles removing its own listeners
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
if (root) {
|
|
return <>{children}</>;
|
|
} else {
|
|
// If not root, apply to a specific div
|
|
return (
|
|
<div className={className} style={{ overflowY: 'scroll' }}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
}
|