Add src/lib/animations/lenis-smooth-scroll.tsx

This commit is contained in:
2026-06-09 23:37:50 +00:00
parent 6fc5a31513
commit 4c6e26cb4e

View File

@@ -0,0 +1,79 @@
"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>
);
}
}