{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-list",
  "title": "animated-list",
  "description": "An animated list component.",
  "dependencies": [
    "react"
  ],
  "files": [
    {
      "path": "registry/eldoraui/animated-list.tsx",
      "content": "\"use client\"\n\nimport React, { useEffect, useMemo, useState } from \"react\"\nimport { AnimatePresence, motion, useAnimationControls } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype AnimationPhase = \"idle\" | \"forming_column\" | \"scrolling_down\" | \"resetting\"\n\ntype AnimatedListProps = {\n  children: React.ReactNode\n  className?: string\n  stackGap?: number\n  columnGap?: number\n  scaleFactor?: number\n  scrollDownDuration?: number\n  formationDuration?: number\n}\n\ntype AnimatedListItemProps = {\n  children: React.ReactNode\n  className?: string\n  index: number\n  listLength: number\n  stackGap?: number\n  columnGap?: number\n  scaleFactor?: number\n}\n\nfunction InternalAnimatedListItem({\n  children,\n  className,\n  index,\n  listLength,\n  animationPhase,\n  onFormationComplete,\n  stackGap = 10,\n  columnGap = 100,\n  scaleFactor = 0.1,\n  formationDuration = 1,\n  visibleItemsCount = 4,\n  resetSpringStiffness = 120,\n  resetSpringDamping = 20,\n}: AnimatedListItemProps & {\n  animationPhase: AnimationPhase\n  onFormationComplete?: () => void\n  formationDuration: number\n  visibleItemsCount: number\n  resetSpringStiffness: number\n  resetSpringDamping: number\n}) {\n  const reverseIndex = listLength - 1 - index\n  const isVisible = reverseIndex < visibleItemsCount\n  const lastItemOffset = (listLength - 1) * columnGap\n  const isLastItem = index === listLength - 1\n\n  const itemVariants = {\n    initial: {\n      scale: 1 + index * scaleFactor,\n      y: reverseIndex * stackGap,\n      opacity: isVisible ? 1 : 0,\n    },\n    column: {\n      scale: 1,\n      y: index * columnGap - lastItemOffset,\n      opacity: 1,\n    },\n  }\n\n  const target =\n    animationPhase === \"idle\" || animationPhase === \"resetting\"\n      ? \"initial\"\n      : \"column\"\n\n  const getTransition = () => {\n    if (animationPhase === \"resetting\") {\n      return {\n        type: \"spring\" as const,\n        stiffness: resetSpringStiffness,\n        damping: resetSpringDamping,\n      }\n    } else {\n      return { duration: formationDuration, ease: [0.4, 0, 0.2, 1] as const }\n    }\n  }\n\n  const handleAnimationComplete = (definition: string) => {\n    if (\n      isLastItem &&\n      definition === \"column\" &&\n      animationPhase === \"forming_column\"\n    ) {\n      onFormationComplete?.()\n    }\n  }\n\n  return (\n    <motion.div\n      key={index}\n      className={cn(\"absolute inset-x-0 flex w-full justify-center\", className)}\n      variants={itemVariants}\n      initial=\"initial\"\n      animate={target}\n      transition={getTransition()}\n      onAnimationComplete={handleAnimationComplete}\n    >\n      {children}\n    </motion.div>\n  )\n}\n\nexport function AnimatedList({\n  children,\n  className,\n  stackGap = 20,\n  columnGap = 85,\n  scaleFactor = 0.05,\n  scrollDownDuration = 5,\n  formationDuration = 1,\n}: AnimatedListProps) {\n  const initialDelayValue = 500\n  const loopPauseDurationValue = 100\n  const listResetSpringStiffness = 100\n  const listResetSpringDamping = 25\n  const itemResetSpringStiffness = 120\n  const itemResetSpringDamping = 20\n  const visibleItemsCountValue = 4\n\n  const [animationPhase, setAnimationPhase] = useState<AnimationPhase>(\"idle\")\n  const listControls = useAnimationControls()\n  const childrenArray = useMemo(\n    () => React.Children.toArray(children),\n    [children]\n  )\n  const listLength = childrenArray.length\n  const totalHeight = listLength * columnGap\n\n  useEffect(() => {\n    let timer: NodeJS.Timeout\n    if (animationPhase === \"idle\") {\n      timer = setTimeout(\n        () => {\n          setAnimationPhase(\"forming_column\")\n        },\n        animationPhase === \"idle\" ? loopPauseDurationValue : initialDelayValue\n      )\n    }\n    return () => clearTimeout(timer)\n  }, [animationPhase, loopPauseDurationValue, initialDelayValue])\n\n  const handleFormationComplete = () => {\n    if (animationPhase === \"forming_column\") setAnimationPhase(\"scrolling_down\")\n  }\n  const handleScrollDownComplete = () => {\n    if (animationPhase === \"scrolling_down\") setAnimationPhase(\"resetting\")\n  }\n  const handleScrollUpComplete = () => {\n    if (animationPhase === \"resetting\") setAnimationPhase(\"idle\")\n  }\n\n  useEffect(() => {\n    if (animationPhase === \"scrolling_down\") {\n      listControls.start({\n        y: totalHeight,\n        transition: {\n          duration: scrollDownDuration,\n          ease: [0.4, 0, 0.2, 1] as const,\n        },\n      })\n    } else if (animationPhase === \"resetting\") {\n      listControls.start({\n        y: 0,\n        transition: {\n          type: \"spring\" as const,\n          stiffness: listResetSpringStiffness,\n          damping: listResetSpringDamping,\n        },\n      })\n    } else {\n      listControls.set({ y: 0 })\n    }\n  }, [\n    animationPhase,\n    listControls,\n    totalHeight,\n    scrollDownDuration,\n    listResetSpringStiffness,\n    listResetSpringDamping,\n  ])\n\n  const handleListAnimationComplete = (definition: { y?: number }) => {\n    if (definition.y === totalHeight && animationPhase === \"scrolling_down\") {\n      handleScrollDownComplete()\n    } else if (definition.y === 0 && animationPhase === \"resetting\") {\n      handleScrollUpComplete()\n    }\n  }\n\n  return (\n    <motion.div\n      className={cn(\"relative flex h-full w-full items-center\", className)}\n      initial={{ y: 0 }}\n      animate={listControls}\n      onAnimationComplete={handleListAnimationComplete}\n    >\n      <AnimatePresence>\n        {childrenArray.map((child, index) => (\n          <InternalAnimatedListItem\n            key={index}\n            index={index}\n            listLength={listLength}\n            animationPhase={animationPhase}\n            onFormationComplete={\n              index === listLength - 1 ? handleFormationComplete : undefined\n            }\n            stackGap={stackGap}\n            columnGap={columnGap}\n            scaleFactor={scaleFactor}\n            formationDuration={formationDuration}\n            visibleItemsCount={visibleItemsCountValue}\n            resetSpringStiffness={itemResetSpringStiffness}\n            resetSpringDamping={itemResetSpringDamping}\n          >\n            {child}\n          </InternalAnimatedListItem>\n        ))}\n      </AnimatePresence>\n    </motion.div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}