48 lines
1.3 KiB
TypeScript

"use client";
import React, { useRef } from "react";
import { type MotionValue } from "motion/react";
import { useSectionProgress } from "@/lib/scroll";
type PinProps = {
/**
* Height of the pin section in viewport heights.
* 300 means the section is 300vh tall, so the sticky area lasts for 3 screens.
*/
heightVH?: number;
className?: string;
/**
* Render prop that receives a MotionValue<number> progress [0..1]
* representing how far through the pin section the user has scrolled.
*/
children: (progress: MotionValue<number>) => React.ReactNode;
};
/**
* Pin creates a tall section with an inner sticky container.
* It computes a normalized progress [0..1] across the entire section using Lenis-driven scroll updates.
*/
export function Pin({ heightVH = 300, className, children }: PinProps) {
const sectionRef = useRef<HTMLElement>(null!);
const progress = useSectionProgress(sectionRef);
return (
<section
ref={sectionRef}
className={className}
style={{
height: `${heightVH}vh`,
position: "relative",
}}
aria-hidden={false}
>
<div
className="sticky top-0 h-screen w-full"
style={{ willChange: "transform" }}
>
{children(progress)}
</div>
</section>
);
}