{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "morphotextflip",
  "type": "registry:ui",
  "title": "MorphoText Flip",
  "description": "Animated text component that flips between words with smooth transitions.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "clsx", "tailwind-merge"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/morphotextflip.tsx",
      "content": "'use client';\nimport React, { useState, useEffect, useId } from 'react';\nimport { motion, AnimatePresence } from 'motion/react';\nimport { cn } from '@/lib/utils';\n\nexport interface MorphoTextFlipProps {\n  words?: string[];\n  interval?: number;\n  className?: string;\n  textClassName?: string;\n  animationDuration?: number;\n  animationType?: 'slideUp' | 'fadeScale' | 'flipY' | 'slideRotate' | 'elastic';\n}\n\nexport function MorphoTextFlip({\n  words = ['remarkable', 'bold', 'scalable', 'beautiful'],\n  interval = 3000,\n  className,\n  textClassName,\n  animationDuration = 700,\n  animationType = 'slideUp',\n}: MorphoTextFlipProps) {\n  const id = useId();\n  const [currentWordIndex, setCurrentWordIndex] = useState(0);\n  const [width, setWidth] = useState('auto');\n  const textRef = React.useRef<HTMLDivElement>(null);\n  const measureRef = React.useRef<HTMLDivElement>(null);\n\n  const updateWidthForWord = () => {\n    if (measureRef.current) {\n      const textWidth = measureRef.current.scrollWidth + 48;\n      setWidth(`${textWidth}px`);\n    }\n  };\n\n  useEffect(() => {\n    const timer = setTimeout(() => {\n      updateWidthForWord();\n    }, 10);\n    return () => clearTimeout(timer);\n  }, [currentWordIndex]);\n\n  useEffect(() => {\n    const intervalId = setInterval(() => {\n      setCurrentWordIndex((prevIndex) => (prevIndex + 1) % words.length);\n    }, interval);\n    return () => clearInterval(intervalId);\n  }, [words, interval]);\n\n  const animationVariants = {\n    slideUp: {\n      initial: { y: 40, opacity: 0 },\n      animate: { y: 0, opacity: 1 },\n      exit: { y: -40, opacity: 0 },\n    },\n    fadeScale: {\n      initial: { scale: 0.8, opacity: 0 },\n      animate: { scale: 1, opacity: 1 },\n      exit: { scale: 1.2, opacity: 0 },\n    },\n    flipY: {\n      initial: { rotateY: 90, opacity: 0 },\n      animate: { rotateY: 0, opacity: 1 },\n      exit: { rotateY: -90, opacity: 0 },\n    },\n    slideRotate: {\n      initial: { x: 100, rotate: 10, opacity: 0 },\n      animate: { x: 0, rotate: 0, opacity: 1 },\n      exit: { x: -100, rotate: -10, opacity: 0 },\n    },\n    elastic: {\n      initial: { scale: 0, rotate: -180 },\n      animate: { scale: 1, rotate: 0 },\n      exit: { scale: 0, rotate: 180 },\n    },\n  };\n\n  const currentVariant = animationVariants[animationType];\n  const duration = animationDuration / 1000;\n\n  return (\n    <motion.div\n      layout\n      layoutId={`words-container-${id}`}\n      animate={{ width }}\n      transition={{\n        duration: duration * 0.4,\n        ease: 'easeInOut',\n        type: 'spring',\n        stiffness: 300,\n        damping: 30,\n      }}\n      className={cn(\n        'relative inline-block overflow-hidden rounded-2xl px-6 pt-2 pb-3 backdrop-blur-xs border border-gray-200 shadow-xl bg-white/70 dark:bg-slate-800/70 dark:border-slate-700',\n        className,\n      )}\n    >\n      <div className='relative flex items-center justify-center'>\n        <div\n          ref={measureRef}\n          className={cn(\n            'absolute opacity-0 pointer-events-none whitespace-nowrap',\n            textClassName || 'text-4xl font-bold md:text-7xl',\n          )}\n          style={{ top: -9999 }}\n        >\n          {words[currentWordIndex]}\n        </div>\n\n        <AnimatePresence mode='wait'>\n          <motion.div\n            key={words[currentWordIndex]}\n            initial={currentVariant.initial}\n            animate={currentVariant.animate}\n            exit={currentVariant.exit}\n            transition={{\n              duration: duration * 0.6,\n              ease:\n                animationType === 'elastic'\n                  ? [0.68, -0.55, 0.265, 1.55]\n                  : 'easeInOut',\n            }}\n            className={cn(\n              'whitespace-nowrap',\n              textClassName ||\n                'text-4xl font-bold text-rose-600 dark:text-rose-400 md:text-7xl',\n            )}\n            ref={textRef}\n          >\n            {words[currentWordIndex]}\n          </motion.div>\n        </AnimatePresence>\n      </div>\n    </motion.div>\n  );\n}\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
