{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "fancy-text",
  "type": "registry:ui",
  "title": "Fancy Text",
  "description": "A refined text reveal animation with smooth character motion and a clean, modern visual flow.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "clsx", "tailwind-merge"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/fancy-text.tsx",
      "content": "'use client';\n\nimport React, { useLayoutEffect, useRef, useState } from 'react';\nimport { motion } from 'motion/react';\nimport { cn } from '@/lib/utils';\n\ninterface FancyTextProps {\n  children: string;\n  className?: string;\n  fillClassName?: string;\n  stagger?: number;\n  duration?: number;\n  delay?: number;\n}\n\nconst FancyText = React.forwardRef<HTMLSpanElement, FancyTextProps>(\n  (\n    {\n      children,\n      className = 'text-5xl font-black leading-none text-black/10 dark:text-white/10',\n      fillClassName = 'text-black dark:text-white',\n      stagger = 0.08,\n      duration = 1.4,\n      delay = 0,\n    },\n    ref,\n  ) => {\n    const spanRef = useRef<HTMLSpanElement>(null);\n    const finalRef = (ref ?? spanRef) as React.RefObject<HTMLSpanElement>;\n\n    const chars = children.split('');\n    const [hideBase, setHideBase] = useState(false);\n    const [isSmall, setIsSmall] = useState(false);\n\n    useLayoutEffect(() => {\n      if (!finalRef.current) return;\n      const size = parseFloat(getComputedStyle(finalRef.current).fontSize);\n      setIsSmall(size < 28);\n    }, [finalRef]);\n\n    return (\n      <span ref={finalRef} className='relative inline-block'>\n        <span\n          className={cn(className)}\n          style={{ opacity: hideBase && isSmall ? 0 : 1 }}\n        >\n          {children}\n        </span>\n\n        <span className='absolute inset-0 flex overflow-hidden'>\n          {chars.map((char, i) => (\n            <motion.span\n              key={i}\n              className={cn(className, fillClassName)}\n              initial={{ clipPath: 'inset(100% 0% 0% 0%)' }}\n              animate={{ clipPath: 'inset(0% 0% 0% 0%)' }}\n              transition={{\n                duration,\n                delay: delay + i * stagger,\n                ease: [0.25, 0.1, 0.25, 1],\n              }}\n              onAnimationComplete={() => {\n                if (i === chars.length - 1 && isSmall) setHideBase(true);\n              }}\n              style={{\n                display: 'inline-block',\n                whiteSpace: char === ' ' ? 'pre' : 'normal',\n              }}\n            >\n              {char === ' ' ? '\\u00A0' : char}\n            </motion.span>\n          ))}\n        </span>\n      </span>\n    );\n  },\n);\n\nFancyText.displayName = 'FancyText';\nexport { FancyText };\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}"
    }
  ]
}
