{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "morphing-text",
  "type": "registry:ui",
  "title": "Morphing Text",
  "description": "A dynamic text morphing component for Magic UI.",
  "files": [
    {
      "path": "registry/magicui/morphing-text.tsx",
      "content": "\"use client\"\n\nimport { useCallback, useEffect, useRef } from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst morphTime = 1.5\nconst cooldownTime = 0.5\n\nconst useMorphingText = (texts: string[]) => {\n  const textIndexRef = useRef(0)\n  const morphRef = useRef(0)\n  const cooldownRef = useRef(0)\n  const timeRef = useRef(new Date())\n\n  const text1Ref = useRef<HTMLSpanElement>(null)\n  const text2Ref = useRef<HTMLSpanElement>(null)\n\n  const setStyles = useCallback(\n    (fraction: number) => {\n      const [current1, current2] = [text1Ref.current, text2Ref.current]\n      if (!current1 || !current2) return\n\n      current2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`\n      current2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`\n\n      const invertedFraction = 1 - fraction\n      current1.style.filter = `blur(${Math.min(\n        8 / invertedFraction - 8,\n        100\n      )}px)`\n      current1.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`\n\n      current1.textContent = texts[textIndexRef.current % texts.length]\n      current2.textContent = texts[(textIndexRef.current + 1) % texts.length]\n    },\n    [texts]\n  )\n\n  const doMorph = useCallback(() => {\n    morphRef.current -= cooldownRef.current\n    cooldownRef.current = 0\n\n    let fraction = morphRef.current / morphTime\n\n    if (fraction > 1) {\n      cooldownRef.current = cooldownTime\n      fraction = 1\n    }\n\n    setStyles(fraction)\n\n    if (fraction === 1) {\n      textIndexRef.current++\n    }\n  }, [setStyles])\n\n  const doCooldown = useCallback(() => {\n    morphRef.current = 0\n    const [current1, current2] = [text1Ref.current, text2Ref.current]\n    if (current1 && current2) {\n      current2.style.filter = \"none\"\n      current2.style.opacity = \"100%\"\n      current1.style.filter = \"none\"\n      current1.style.opacity = \"0%\"\n    }\n  }, [])\n\n  useEffect(() => {\n    let animationFrameId: number\n\n    const animate = () => {\n      animationFrameId = requestAnimationFrame(animate)\n\n      const newTime = new Date()\n      const dt = (newTime.getTime() - timeRef.current.getTime()) / 1000\n      timeRef.current = newTime\n\n      cooldownRef.current -= dt\n\n      if (cooldownRef.current <= 0) doMorph()\n      else doCooldown()\n    }\n\n    animate()\n    return () => {\n      cancelAnimationFrame(animationFrameId)\n    }\n  }, [doMorph, doCooldown])\n\n  return { text1Ref, text2Ref }\n}\n\ninterface MorphingTextProps {\n  className?: string\n  texts: string[]\n}\n\nconst Texts: React.FC<Pick<MorphingTextProps, \"texts\">> = ({ texts }) => {\n  const { text1Ref, text2Ref } = useMorphingText(texts)\n  return (\n    <>\n      <span\n        className=\"absolute inset-x-0 top-0 m-auto inline-block w-full\"\n        ref={text1Ref}\n      />\n      <span\n        className=\"absolute inset-x-0 top-0 m-auto inline-block w-full\"\n        ref={text2Ref}\n      />\n    </>\n  )\n}\n\nconst SvgFilters: React.FC = () => (\n  <svg\n    id=\"filters\"\n    className=\"fixed h-0 w-0\"\n    preserveAspectRatio=\"xMidYMid slice\"\n  >\n    <defs>\n      <filter id=\"threshold\">\n        <feColorMatrix\n          in=\"SourceGraphic\"\n          type=\"matrix\"\n          values=\"1 0 0 0 0\n                  0 1 0 0 0\n                  0 0 1 0 0\n                  0 0 0 255 -140\"\n        />\n      </filter>\n    </defs>\n  </svg>\n)\n\nexport const MorphingText: React.FC<MorphingTextProps> = ({\n  texts,\n  className,\n}) => (\n  <div\n    className={cn(\n      \"relative mx-auto h-16 w-full max-w-3xl text-center font-sans text-[40pt] leading-none font-bold filter-[url(#threshold)_blur(0.6px)] md:h-24 lg:text-[6rem]\",\n      className\n    )}\n  >\n    <Texts texts={texts} />\n    <SvgFilters />\n  </div>\n)\n",
      "type": "registry:ui"
    }
  ]
}