{
  "title": "Animated Stack",
  "description": "A smooth stacked card component that expands on hover and collapses with animation.",
  "name": "gsap-animated-stack",
  "dependencies": [
    "gsap",
    "@gsap/react"
  ],
  "registryDependencies": [],
  "type": "registry:ui",
  "files": [
    {
      "path": "components/paceui/gsap/animated-stack.tsx",
      "type": "registry:ui",
      "content": "import { Children, type ReactNode, useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { gsap } from \"gsap\";\n\ntype AnimatedStackProps = {\n    children: ReactNode;\n    visibleCount?: number;\n    gap?: number;\n    offset?: number;\n    direction?: \"up\" | \"down\";\n};\n\nexport const AnimatedStack = ({\n    children,\n    visibleCount = 3,\n    gap = 8,\n    offset = 8,\n    direction = \"up\",\n}: AnimatedStackProps) => {\n    const containerRef = useRef<HTMLDivElement>(null);\n    const itemsRef = useRef<HTMLDivElement[]>([]);\n    const prevItemCount = useRef(0);\n    const timeoutRef = useRef<NodeJS.Timeout>(null);\n    const lastItemHeight = useRef(0);\n    const [expanded, setExpanded] = useState(false);\n\n    itemsRef.current = [];\n\n    const registerItemRef = (el: HTMLDivElement) => {\n        if (el && !itemsRef.current.includes(el)) itemsRef.current.push(el);\n    };\n\n    const calculatePositions = useCallback(\n        (arr: number[]) =>\n            arr\n                .reduce((acc, val) => [...acc, acc.at(-1)! + val + gap], [0])\n                .slice(0, -1)\n                .reverse(),\n        [gap],\n    );\n\n    useEffect(() => {\n        const items = itemsRef.current;\n        const total = items.length;\n\n        const heights = items.map((el) => el.getBoundingClientRect().height);\n        lastItemHeight.current = heights.at(-1) || 0;\n        const positions = calculatePositions(heights);\n\n        items.forEach((el, i) => {\n            const rev = total - 1 - i;\n            let y = 0;\n            let opacity = 1,\n                scale = 1;\n\n            if (expanded) {\n                y = (positions[i] || 0) * (direction == \"down\" ? 1 : -1);\n            } else {\n                if (rev >= visibleCount) {\n                    y = offset * (visibleCount - 1);\n                    opacity = 0;\n                } else if (i !== total - 1) {\n                    y = rev * offset * (direction == \"down\" ? 1 : -1);\n                    scale = 1 - (total - i) * 0.015;\n                }\n            }\n\n            const isNew = total > prevItemCount.current && i === total - 1;\n\n            if (isNew) {\n                gsap.fromTo(\n                    el,\n                    { opacity: 0, y: y + 20 * (direction == \"down\" ? -1 : 1) },\n                    { opacity: 1, y, duration: 0.8, ease: \"power2.out\" },\n                );\n            } else {\n                gsap.to(el, { y, opacity, scaleX: scale, duration: 0.8, ease: \"power4.inOut\" });\n            }\n        });\n        prevItemCount.current = total;\n    }, [children, expanded, visibleCount, direction, calculatePositions, gap, offset]);\n\n    return (\n        <div\n            ref={containerRef}\n            className=\"relative w-full overflow-visible\"\n            style={{ height: lastItemHeight.current }}\n            onMouseEnter={() => {\n                if (timeoutRef.current) clearTimeout(timeoutRef.current);\n                setExpanded(true);\n            }}\n            onMouseLeave={() => {\n                timeoutRef.current = setTimeout(() => setExpanded(false), 1500);\n            }}>\n            {Children.map(children, (child) => (\n                <div ref={registerItemRef} className=\"absolute w-full\">\n                    {child}\n                </div>\n            ))}\n        </div>\n    );\n};\n"
    }
  ],
  "mcp": {
    "description": "Provides refined UI interactions and accessible controls. A smooth stacked card component that expands on hover and collapses with animation. Configurable props include: {; children: ReactNode;; visibleCount?: number;; gap?: number;. Relies on gsap, @gsap/react. Optimal for building reusable interface elements and user input flows.",
    "tags": [
      "component",
      "gsap",
      "animation"
    ]
  }
}