// author: Khoa Phan "use client" import { createContext, useContext, useRef, type HTMLAttributes, type PropsWithChildren, } from "react" import { motion, useScroll, useTransform, type MotionValue, type UseScrollOptions, } from "motion/react" import { cn } from "@/lib/utils" interface StackingCardsProps extends PropsWithChildren, HTMLAttributes { scrollOptions?: UseScrollOptions scaleMultiplier?: number totalCards: number } interface StackingCardItemProps extends HTMLAttributes, PropsWithChildren { index: number topPosition?: string } export default function StackingCards({ children, className, scrollOptions, scaleMultiplier, totalCards, ...props }: StackingCardsProps) { const targetRef = useRef(null) const { scrollYProgress } = useScroll({ offset: ["start start", "end end"], ...scrollOptions, target: targetRef, }) return (
{children}
) } const StackingCardItem = ({ index, topPosition, className, children, ...props }: StackingCardItemProps) => { const { progress, scaleMultiplier, totalCards = 0, } = useStackingCardsContext() // Get from Context const scaleTo = 1 - (totalCards - index) * (scaleMultiplier ?? 0.03) const rangeScale = [index * (1 / totalCards), 1] const scale = useTransform(progress, rangeScale, [1, scaleTo]) const top = topPosition ?? `${5 + index * 3}%` return (
{children}
) } const StackingCardsContext = createContext<{ progress: MotionValue scaleMultiplier?: number totalCards?: number } | null>(null) export const useStackingCardsContext = () => { const context = useContext(StackingCardsContext) if (!context) throw new Error("StackingCardItem must be used within StackingCards") return context } export { StackingCardItem }