{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "text-gif",
  "type": "registry:ui",
  "description": "Text component with GIF-like animation effects and customizable styling",
  "dependencies": [
    "class-variance-authority"
  ],
  "files": [
    {
      "path": "registry/default/ui/text-gif.tsx",
      "content": "\"use client\"\n\nimport React, { useEffect, useMemo, useState, type CSSProperties } from \"react\"\nimport Image from \"next/image\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\n// Define text style variants\nconst textBaseVariants = cva(\"\", {\n  variants: {\n    size: {\n      default: \"text-2xl sm:text-3xl lg:text-4xl\",\n      xxs: \"text-base sm:text-lg lg:text-lg\",\n      xs: \"text-lg sm:text-xl lg:text-2xl\",\n      sm: \"text-xl sm:text-2xl lg:text-3xl\",\n      md: \"text-2xl sm:text-3xl lg:text-4xl\",\n      lg: \"text-3xl sm:text-4xl lg:text-5xl\",\n      xl: \"text-4xl sm:text-5xl lg:text-6xl\",\n      xxl: \"text-[2.5rem] sm:text-6xl lg:text-[6rem]\",\n      xll: \"text-5xl sm:text-6xl lg:text-[7rem]\",\n      xxxl: \"text-[6rem] leading-5 sm:text-6xl lg:text-[8rem] lg:leading-8\",\n    },\n    weight: {\n      default: \"font-bold\",\n      thin: \"font-thin\",\n      base: \"font-base\",\n      semi: \"font-semibold\",\n      bold: \"font-bold\",\n      black: \"font-black\",\n    },\n    font: {\n      default: \"font-sansTight\",\n      serif: \"font-serif\",\n      mono: \"font-mono\",\n    },\n  },\n  defaultVariants: {\n    size: \"default\",\n    weight: \"bold\",\n    font: \"default\",\n  },\n})\n\ninterface TextGifProps extends VariantProps<typeof textBaseVariants> {\n  gifUrl: string\n  text: string\n  className?: string\n  fallbackColor?: string\n  transitionDuration?: number\n}\n\nconst TextGif = React.memo(function TextGifComponent({\n  gifUrl,\n  text,\n  size,\n  weight,\n  font,\n  className,\n  fallbackColor = \"black\",\n  transitionDuration = 300,\n}: TextGifProps) {\n  const [loaded, setLoaded] = useState(false)\n  const [error, setError] = useState(false)\n\n  // Reset states when gifUrl changes\n  useEffect(() => {\n    setLoaded(false)\n    setError(false)\n  }, [gifUrl])\n\n  // Memoize className for performance\n  const textClassName = useMemo(\n    () =>\n      cn(\n        textBaseVariants({ size, weight, font }),\n        loaded && !error ? \"bg-clip-text text-transparent\" : \"\",\n        className,\n        \"pb-1.5 md:pb-4\"\n      ),\n    [size, weight, font, className, loaded, error]\n  )\n\n  // Memoize style for performance\n  const textStyle = useMemo(() => {\n    const style: CSSProperties = {\n      backgroundSize: \"cover\",\n      backgroundPosition: \"center\",\n      backgroundRepeat: \"no-repeat\",\n      WebkitBackgroundClip: \"text\",\n      lineHeight: 1,\n      textAlign: \"center\",\n      color: fallbackColor, // Always set the fallback color initially\n      WebkitTextFillColor: fallbackColor, // Safari fix\n      transition: `background-image ${transitionDuration}ms ease-in-out, color ${transitionDuration}ms ease-in-out`,\n    }\n\n    if (loaded && !error) {\n      style.backgroundImage = `url(${gifUrl})`\n      style.color = \"transparent\"\n      style.WebkitTextFillColor = \"transparent\" // Safari fix\n    }\n\n    return style\n  }, [loaded, error, gifUrl, transitionDuration, fallbackColor])\n\n  return (\n    <div className=\"relative inline-block\">\n      {/* Hidden image for preloading */}\n      {gifUrl && (\n        <Image\n          src={gifUrl || \"/placeholder.svg\"}\n          alt=\"\"\n          width={1}\n          height={1}\n          className=\"pointer-events-none absolute opacity-0\"\n          onLoad={() => {\n            setLoaded(true)\n            setError(false)\n          }}\n          onError={() => {\n            setError(true)\n            setLoaded(false)\n          }}\n          priority\n          unoptimized\n        />\n      )}\n      <span className={textClassName} style={textStyle}>\n        {text}\n      </span>\n    </div>\n  )\n})\n\n// Export common GIF URLs\nconst gifUrls = [\n  \"https://media.giphy.com/media/3zvbrvbRe7wxBofOBI/giphy.gif\",\n  \"https://media.giphy.com/media/fnglNFjBGiyAFtm6ke/giphy.gif\",\n  \"https://media.giphy.com/media/9Pmfazv34l7aNIKK05/giphy.gif\",\n  \"https://media.giphy.com/media/4bhs1boql4XVJgmm4H/giphy.gif\",\n]\n\n// Optional: Preloader component\nfunction PreloadGifs() {\n  return (\n    <div className=\"hidden\">\n      {gifUrls.map((url) => (\n        <Image\n          key={url}\n          src={url}\n          alt=\"\"\n          width={1}\n          height={1}\n          priority\n          unoptimized\n        />\n      ))}\n    </div>\n  )\n}\n\nexport { TextGif }\nexport default TextGif\n",
      "type": "registry:ui"
    }
  ]
}