{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gif-text",
  "type": "registry:block",
  "title": "Gif text",
  "description": "Gif text",
  "files": [
    {
      "path": "components/usages/giftextusage.tsx",
      "content": "\"use client\"\r\n\r\nimport { useState } from \"react\"\r\n\r\nimport { Input } from \"@/components/ui/input\"\r\nimport {\r\n\tSelect,\r\n\tSelectContent,\r\n\tSelectItem,\r\n\tSelectTrigger,\r\n\tSelectValue,\r\n} from \"@/components/ui/select\"\r\nimport { GifText } from \"@/registry/open-source/gif-text\"\r\n\r\n\r\nexport default function Usage() {\r\n\tconst [text, setText] = useState(\"TextGif\")\r\n\tconst [size, setSize] = useState(\"xl\")\r\n\tconst [weight, setWeight] = useState(\"bold\")\r\n\r\n\tconst gifUrls = [\r\n\t\t\"https://media.giphy.com/media/3zvbrvbRe7wxBofOBI/giphy.gif\",\r\n\t\t\"https://media.giphy.com/media/fnglNFjBGiyAFtm6ke/giphy.gif\",\r\n\t\t\"https://media.giphy.com/media/9Pmfazv34l7aNIKK05/giphy.gif\",\r\n\t\t\"https://media.giphy.com/media/4bhs1boql4XVJgmm4H/giphy.gif\",\r\n\t]\r\n\r\n\tconst [selectedGif, setSelectedGif] = useState(gifUrls[0])\r\n\r\n\treturn (\r\n\t\t<div className=\"max-w-3xl mx-auto space-y-8 p-6 bg-neutral-50 dark:bg-neutral-900 rounded-xl\">\r\n\t\t\t{/* Preview */}\r\n\t\t\t<div className=\"flex items-center justify-center p-12 bg-white dark:bg-black rounded-xl\">\r\n\t\t\t\t<GifText\r\n\t\t\t\t\tgifUrl={selectedGif}\r\n\t\t\t\t\ttext={text}\r\n\t\t\t\t\tsize={size as any}\r\n\t\t\t\t\tweight={weight as any}\r\n\t\t\t\t/>\r\n\t\t\t</div>\r\n\r\n\t\t\t{/* Controls */}\r\n\t\t\t<div className=\"grid gap-6 md:grid-cols-2\">\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">Text</label>\r\n\t\t\t\t\t<Input\r\n\t\t\t\t\t\tvalue={text}\r\n\t\t\t\t\t\tonChange={(e) => setText(e.target.value)}\r\n\t\t\t\t\t\tplaceholder=\"Enter text\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">GIF Background</label>\r\n\t\t\t\t\t<Select value={selectedGif} onValueChange={setSelectedGif}>\r\n\t\t\t\t\t\t<SelectTrigger>\r\n\t\t\t\t\t\t\t<SelectValue placeholder=\"Select GIF\" />\r\n\t\t\t\t\t\t</SelectTrigger>\r\n\t\t\t\t\t\t<SelectContent>\r\n\t\t\t\t\t\t\t{gifUrls.map((gif, index) => (\r\n\t\t\t\t\t\t\t\t<SelectItem key={index} value={gif}>\r\n\t\t\t\t\t\t\t\t\tGIF {index + 1}\r\n\t\t\t\t\t\t\t\t</SelectItem>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</SelectContent>\r\n\t\t\t\t\t</Select>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">Text Size</label>\r\n\t\t\t\t\t<Select value={size} onValueChange={setSize}>\r\n\t\t\t\t\t\t<SelectTrigger>\r\n\t\t\t\t\t\t\t<SelectValue placeholder=\"Select size\" />\r\n\t\t\t\t\t\t</SelectTrigger>\r\n\t\t\t\t\t\t<SelectContent>\r\n\t\t\t\t\t\t\t{[\"sm\", \"md\", \"lg\", \"xl\", \"xxl\"].map((s) => (\r\n\t\t\t\t\t\t\t\t<SelectItem key={s} value={s}>\r\n\t\t\t\t\t\t\t\t\t{s}\r\n\t\t\t\t\t\t\t\t</SelectItem>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</SelectContent>\r\n\t\t\t\t\t</Select>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">Font Weight</label>\r\n\t\t\t\t\t<Select value={weight} onValueChange={setWeight}>\r\n\t\t\t\t\t\t<SelectTrigger>\r\n\t\t\t\t\t\t\t<SelectValue placeholder=\"Select weight\" />\r\n\t\t\t\t\t\t</SelectTrigger>\r\n\t\t\t\t\t\t<SelectContent>\r\n\t\t\t\t\t\t\t{[\"normal\", \"medium\", \"semi\", \"bold\"].map((w) => (\r\n\t\t\t\t\t\t\t\t<SelectItem key={w} value={w}>\r\n\t\t\t\t\t\t\t\t\t{w}\r\n\t\t\t\t\t\t\t\t</SelectItem>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</SelectContent>\r\n\t\t\t\t\t</Select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t{/* Examples */}\r\n\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t<h2 className=\"text-xl font-semibold\">Examples</h2>\r\n\t\t\t\t<div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n\t\t\t\t\t<div className=\"flex flex-col items-center justify-center p-6 bg-white dark:bg-black rounded-xl\">\r\n\t\t\t\t\t\t<GifText\r\n\t\t\t\t\t\t\tgifUrl={gifUrls[1]}\r\n\t\t\t\t\t\t\ttext=\"Headings\"\r\n\t\t\t\t\t\t\tsize=\"xl\"\r\n\t\t\t\t\t\t\tweight=\"bold\"\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div className=\"flex flex-col items-center justify-center p-6 bg-white dark:bg-black rounded-xl\">\r\n\t\t\t\t\t\t<GifText gifUrl={gifUrls[2]} text=\"$49\" size=\"xxl\" weight=\"bold\" />\r\n\t\t\t\t\t\t<p className=\"text-sm mt-2\">per month</p>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t)\r\n}\r\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/giftextusage.tsx",
      "content": "\"use client\"\r\n\r\nimport { useState } from \"react\"\r\n\r\nimport { Input } from \"@/components/ui/input\"\r\nimport {\r\n\tSelect,\r\n\tSelectContent,\r\n\tSelectItem,\r\n\tSelectTrigger,\r\n\tSelectValue,\r\n} from \"@/components/ui/select\"\r\nimport { GifText } from \"@/registry/open-source/gif-text\"\r\n\r\n\r\nexport default function Usage() {\r\n\tconst [text, setText] = useState(\"TextGif\")\r\n\tconst [size, setSize] = useState(\"xl\")\r\n\tconst [weight, setWeight] = useState(\"bold\")\r\n\r\n\tconst gifUrls = [\r\n\t\t\"https://media.giphy.com/media/3zvbrvbRe7wxBofOBI/giphy.gif\",\r\n\t\t\"https://media.giphy.com/media/fnglNFjBGiyAFtm6ke/giphy.gif\",\r\n\t\t\"https://media.giphy.com/media/9Pmfazv34l7aNIKK05/giphy.gif\",\r\n\t\t\"https://media.giphy.com/media/4bhs1boql4XVJgmm4H/giphy.gif\",\r\n\t]\r\n\r\n\tconst [selectedGif, setSelectedGif] = useState(gifUrls[0])\r\n\r\n\treturn (\r\n\t\t<div className=\"max-w-3xl mx-auto space-y-8 p-6 bg-neutral-50 dark:bg-neutral-900 rounded-xl\">\r\n\t\t\t{/* Preview */}\r\n\t\t\t<div className=\"flex items-center justify-center p-12 bg-white dark:bg-black rounded-xl\">\r\n\t\t\t\t<GifText\r\n\t\t\t\t\tgifUrl={selectedGif}\r\n\t\t\t\t\ttext={text}\r\n\t\t\t\t\tsize={size as any}\r\n\t\t\t\t\tweight={weight as any}\r\n\t\t\t\t/>\r\n\t\t\t</div>\r\n\r\n\t\t\t{/* Controls */}\r\n\t\t\t<div className=\"grid gap-6 md:grid-cols-2\">\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">Text</label>\r\n\t\t\t\t\t<Input\r\n\t\t\t\t\t\tvalue={text}\r\n\t\t\t\t\t\tonChange={(e) => setText(e.target.value)}\r\n\t\t\t\t\t\tplaceholder=\"Enter text\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">GIF Background</label>\r\n\t\t\t\t\t<Select value={selectedGif} onValueChange={setSelectedGif}>\r\n\t\t\t\t\t\t<SelectTrigger>\r\n\t\t\t\t\t\t\t<SelectValue placeholder=\"Select GIF\" />\r\n\t\t\t\t\t\t</SelectTrigger>\r\n\t\t\t\t\t\t<SelectContent>\r\n\t\t\t\t\t\t\t{gifUrls.map((gif, index) => (\r\n\t\t\t\t\t\t\t\t<SelectItem key={index} value={gif}>\r\n\t\t\t\t\t\t\t\t\tGIF {index + 1}\r\n\t\t\t\t\t\t\t\t</SelectItem>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</SelectContent>\r\n\t\t\t\t\t</Select>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">Text Size</label>\r\n\t\t\t\t\t<Select value={size} onValueChange={setSize}>\r\n\t\t\t\t\t\t<SelectTrigger>\r\n\t\t\t\t\t\t\t<SelectValue placeholder=\"Select size\" />\r\n\t\t\t\t\t\t</SelectTrigger>\r\n\t\t\t\t\t\t<SelectContent>\r\n\t\t\t\t\t\t\t{[\"sm\", \"md\", \"lg\", \"xl\", \"xxl\"].map((s) => (\r\n\t\t\t\t\t\t\t\t<SelectItem key={s} value={s}>\r\n\t\t\t\t\t\t\t\t\t{s}\r\n\t\t\t\t\t\t\t\t</SelectItem>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</SelectContent>\r\n\t\t\t\t\t</Select>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t\t<label className=\"text-sm font-medium\">Font Weight</label>\r\n\t\t\t\t\t<Select value={weight} onValueChange={setWeight}>\r\n\t\t\t\t\t\t<SelectTrigger>\r\n\t\t\t\t\t\t\t<SelectValue placeholder=\"Select weight\" />\r\n\t\t\t\t\t\t</SelectTrigger>\r\n\t\t\t\t\t\t<SelectContent>\r\n\t\t\t\t\t\t\t{[\"normal\", \"medium\", \"semi\", \"bold\"].map((w) => (\r\n\t\t\t\t\t\t\t\t<SelectItem key={w} value={w}>\r\n\t\t\t\t\t\t\t\t\t{w}\r\n\t\t\t\t\t\t\t\t</SelectItem>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</SelectContent>\r\n\t\t\t\t\t</Select>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t{/* Examples */}\r\n\t\t\t<div className=\"space-y-4\">\r\n\t\t\t\t<h2 className=\"text-xl font-semibold\">Examples</h2>\r\n\t\t\t\t<div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n\t\t\t\t\t<div className=\"flex flex-col items-center justify-center p-6 bg-white dark:bg-black rounded-xl\">\r\n\t\t\t\t\t\t<GifText\r\n\t\t\t\t\t\t\tgifUrl={gifUrls[1]}\r\n\t\t\t\t\t\t\ttext=\"Headings\"\r\n\t\t\t\t\t\t\tsize=\"xl\"\r\n\t\t\t\t\t\t\tweight=\"bold\"\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div className=\"flex flex-col items-center justify-center p-6 bg-white dark:bg-black rounded-xl\">\r\n\t\t\t\t\t\t<GifText gifUrl={gifUrls[2]} text=\"$49\" size=\"xxl\" weight=\"bold\" />\r\n\t\t\t\t\t\t<p className=\"text-sm mt-2\">per month</p>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t)\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/input.tsx",
      "content": "// SHADCN UI GENERATED CODE\n\nimport React from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\n\nexport interface InputProps\n\textends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n\t({ className, type, ...props }, ref) => {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype={type}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t}\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/gif-text.tsx",
      "content": "\"use client\";\n\nimport React, { useEffect, useMemo, useState, type CSSProperties } from \"react\";\n\nimport Image from \"next/image\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\n// Credit:\n// https://www.cult-ui.com/docs/components/text-gif\n\n// Define text style variants\nconst textBaseVariants = cva(\"\", {\n\tvariants: {\n\t\tsize: {\n\t\t\tdefault: \"text-2xl sm:text-3xl lg:text-4xl\",\n\t\t\txxs: \"text-base sm:text-lg lg:text-lg\",\n\t\t\txs: \"text-lg sm:text-xl lg:text-2xl\",\n\t\t\tsm: \"text-xl sm:text-2xl lg:text-3xl\",\n\t\t\tmd: \"text-2xl sm:text-3xl lg:text-4xl\",\n\t\t\tlg: \"text-3xl sm:text-4xl lg:text-5xl\",\n\t\t\txl: \"text-4xl sm:text-5xl lg:text-6xl\",\n\t\t\txxl: \"text-[2.5rem] sm:text-6xl lg:text-[6rem]\",\n\t\t\txll: \"text-5xl sm:text-6xl lg:text-[7rem]\",\n\t\t\txxxl: \"text-[6rem] leading-5 lg:leading-8 sm:text-6xl lg:text-[8rem]\",\n\t\t},\n\t\tweight: {\n\t\t\tdefault: \"font-bold\",\n\t\t\tthin: \"font-thin\",\n\t\t\tbase: \"font-base\",\n\t\t\tsemi: \"font-semibold\",\n\t\t\tbold: \"font-bold\",\n\t\t\tblack: \"font-black\",\n\t\t},\n\t\tfont: {\n\t\t\tdefault: \"font-sansTight\",\n\t\t\tserif: \"font-serif\",\n\t\t\tmono: \"font-mono\",\n\t\t},\n\t},\n\tdefaultVariants: {\n\t\tsize: \"default\",\n\t\tweight: \"bold\",\n\t\tfont: \"default\",\n\t},\n});\n\ninterface GifTextProps extends VariantProps<typeof textBaseVariants> {\n\tgifUrl: string;\n\ttext: string;\n\tclassName?: string;\n\tfallbackColor?: string;\n\ttransitionDuration?: number;\n}\n\nconst GifText = React.memo(function GifTextComponent({\n\tgifUrl,\n\ttext,\n\tsize,\n\tweight,\n\tfont,\n\tclassName,\n\tfallbackColor = \"black\",\n\ttransitionDuration = 300,\n}: GifTextProps) {\n\tconst [loaded, setLoaded] = useState(false);\n\tconst [error, setError] = useState(false);\n\n\t// Reset states when gifUrl changes\n\tuseEffect(() => {\n\t\tsetLoaded(false);\n\t\tsetError(false);\n\t}, [gifUrl]);\n\n\t// Memoize className for performance\n\tconst textClassName = useMemo(\n\t\t() =>\n\t\t\tcn(\n\t\t\t\ttextBaseVariants({ size, weight, font }),\n\t\t\t\tloaded && !error ? \"text-transparent bg-clip-text\" : \"\",\n\t\t\t\tclassName,\n\t\t\t\t\"pb-1.5 md:pb-4\"\n\t\t\t),\n\t\t[size, weight, font, className, loaded, error]\n\t);\n\n\t// Memoize style for performance\n\tconst textStyle = useMemo(() => {\n\t\tconst style: CSSProperties = {\n\t\t\tbackgroundSize: \"cover\",\n\t\t\tbackgroundPosition: \"center\",\n\t\t\tbackgroundRepeat: \"no-repeat\",\n\t\t\tWebkitBackgroundClip: \"text\",\n\t\t\tlineHeight: 1,\n\t\t\ttextAlign: \"center\",\n\t\t\tcolor: fallbackColor, // Always set the fallback color initially\n\t\t\tWebkitTextFillColor: fallbackColor, // Safari fix\n\t\t\ttransition: `background-image ${transitionDuration}ms ease-in-out, color ${transitionDuration}ms ease-in-out`,\n\t\t};\n\n\t\tif (loaded && !error) {\n\t\t\tstyle.backgroundImage = `url(${gifUrl})`;\n\t\t\tstyle.color = \"transparent\";\n\t\t\tstyle.WebkitTextFillColor = \"transparent\"; // Safari fix\n\t\t}\n\n\t\treturn style;\n\t}, [loaded, error, gifUrl, transitionDuration, fallbackColor]);\n\n\treturn (\n\t\t<div className=\"relative inline-block\">\n\t\t\t{/* Hidden image for preloading */}\n\t\t\t{gifUrl && (\n\t\t\t\t<Image\n\t\t\t\t\tsrc={gifUrl || \"/itjustworks.jpg\"}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth={1}\n\t\t\t\t\theight={1}\n\t\t\t\t\tclassName=\"absolute opacity-0 pointer-events-none\"\n\t\t\t\t\tonLoad={() => {\n\t\t\t\t\t\tsetLoaded(true);\n\t\t\t\t\t\tsetError(false);\n\t\t\t\t\t}}\n\t\t\t\t\tonError={() => {\n\t\t\t\t\t\tsetError(true);\n\t\t\t\t\t\tsetLoaded(false);\n\t\t\t\t\t}}\n\t\t\t\t\tpriority\n\t\t\t\t\tunoptimized\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<span className={textClassName} style={textStyle}>\n\t\t\t\t{text}\n\t\t\t</span>\n\t\t</div>\n\t);\n});\n\n// Export common GIF URLs\nconst gifUrls = [\n\t\"https://media.giphy.com/media/3zvbrvbRe7wxBofOBI/giphy.gif\",\n\t\"https://media.giphy.com/media/fnglNFjBGiyAFtm6ke/giphy.gif\",\n\t\"https://media.giphy.com/media/9Pmfazv34l7aNIKK05/giphy.gif\",\n\t\"https://media.giphy.com/media/4bhs1boql4XVJgmm4H/giphy.gif\",\n];\n\n// Optional: Preloader component\nfunction PreloadGifs() {\n\treturn (\n\t\t<div className=\"hidden\">\n\t\t\t{gifUrls.map((url) => (\n\t\t\t\t<Image\n\t\t\t\t\tkey={url}\n\t\t\t\t\tsrc={url}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth={1}\n\t\t\t\t\theight={1}\n\t\t\t\t\tpriority\n\t\t\t\t\tunoptimized\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\nexport { GifText };\n",
      "type": "registry:ui"
    }
  ]
}