{
  "name": "flip-words",
  "type": "registry:ui",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/flip-words.tsx",
      "content": "\"use client\";\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { AnimatePresence, motion, LayoutGroup } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const FlipWords = ({\n  words,\n  duration = 3000,\n  className,\n}: {\n  words: string[];\n  duration?: number;\n  className?: string;\n}) => {\n  const [currentWord, setCurrentWord] = useState(words[0]);\n  const [isAnimating, setIsAnimating] = useState<boolean>(false);\n\n  // thanks for the fix Julian - https://github.com/Julian-AT\n  const startAnimation = useCallback(() => {\n    const word = words[words.indexOf(currentWord) + 1] || words[0];\n    setCurrentWord(word);\n    setIsAnimating(true);\n  }, [currentWord, words]);\n\n  useEffect(() => {\n    if (!isAnimating)\n      setTimeout(() => {\n        startAnimation();\n      }, duration);\n  }, [isAnimating, duration, startAnimation]);\n\n  return (\n    <AnimatePresence\n      onExitComplete={() => {\n        setIsAnimating(false);\n      }}\n    >\n      <motion.div\n        initial={{\n          opacity: 0,\n          y: 10,\n        }}\n        animate={{\n          opacity: 1,\n          y: 0,\n        }}\n        transition={{\n          type: \"spring\",\n          stiffness: 100,\n          damping: 10,\n        }}\n        exit={{\n          opacity: 0,\n          y: -40,\n          x: 40,\n          filter: \"blur(8px)\",\n          scale: 2,\n          position: \"absolute\",\n        }}\n        className={cn(\n          \"z-10 inline-block relative text-left text-neutral-900 dark:text-neutral-100 px-2\",\n          className\n        )}\n        key={currentWord}\n      >\n        {/* edit suggested by Sajal: https://x.com/DewanganSajal */}\n        {currentWord.split(\" \").map((word, wordIndex) => (\n          <motion.span\n            key={word + wordIndex}\n            initial={{ opacity: 0, y: 10, filter: \"blur(8px)\" }}\n            animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n            transition={{\n              delay: wordIndex * 0.3,\n              duration: 0.3,\n            }}\n            className=\"inline-block whitespace-nowrap\"\n          >\n            {word.split(\"\").map((letter, letterIndex) => (\n              <motion.span\n                key={word + letterIndex}\n                initial={{ opacity: 0, y: 10, filter: \"blur(8px)\" }}\n                animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n                transition={{\n                  delay: wordIndex * 0.3 + letterIndex * 0.05,\n                  duration: 0.2,\n                }}\n                className=\"inline-block\"\n              >\n                {letter}\n              </motion.span>\n            ))}\n            <span className=\"inline-block\">&nbsp;</span>\n          </motion.span>\n        ))}\n      </motion.div>\n    </AnimatePresence>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/flip-words.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Flip Words"
}