{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "text-morph",
  "type": "registry:block",
  "title": "Text morph",
  "description": "Text morph",
  "files": [
    {
      "path": "components/usages/textmorphusage.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport { TextMorph } from \"@/registry/open-source/text-morph\";\n\nexport default function TextMorphButton() {\n\tconst [text, setText] = useState(\"Continue\");\n\n\treturn (\n\t\t<button\n\t\t\tonClick={() => setText(text === \"Continue\" ? \"Confirm\" : \"Continue\")}\n\t\t\tclassName=\"flex h-10 w-[120px] shrink-0 items-center justify-center rounded-full bg-background px-4 text-base font-medium text-secondary shadow-2xs transition-colors hover:bg-background dark:bg-background dark:text-secondary dark:hover:bg-background\"\n\t\t>\n\t\t\t<TextMorph>{text}</TextMorph>\n\t\t</button>\n\t);\n}\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/textmorphusage.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport { TextMorph } from \"@/registry/open-source/text-morph\";\n\nexport default function TextMorphButton() {\n\tconst [text, setText] = useState(\"Continue\");\n\n\treturn (\n\t\t<button\n\t\t\tonClick={() => setText(text === \"Continue\" ? \"Confirm\" : \"Continue\")}\n\t\t\tclassName=\"flex h-10 w-[120px] shrink-0 items-center justify-center rounded-full bg-background px-4 text-base font-medium text-secondary shadow-2xs transition-colors hover:bg-background dark:bg-background dark:text-secondary dark:hover:bg-background\"\n\t\t>\n\t\t\t<TextMorph>{text}</TextMorph>\n\t\t</button>\n\t);\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/text-morph.tsx",
      "content": "\"use client\";\n\nimport { useId, useMemo } from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { AnimatePresence, motion, Transition, Variants } from \"motion/react\";\n\n// Credit:\n// https://motion-primitives.com/docs/text-morph\n\nexport type TextMorphProps = {\n\tchildren: string;\n\tas?: React.ElementType;\n\tclassName?: string;\n\tstyle?: React.CSSProperties;\n\tvariants?: Variants;\n\ttransition?: Transition;\n};\n\nexport function TextMorph({\n\tchildren,\n\tas: Component = \"p\",\n\tclassName,\n\tstyle,\n\tvariants,\n\ttransition,\n}: TextMorphProps) {\n\tconst uniqueId = useId();\n\n\tconst characters = useMemo(() => {\n\t\tconst charCounts: Record<string, number> = {};\n\n\t\treturn children.split(\"\").map((char) => {\n\t\t\tconst lowerChar = char.toLowerCase();\n\t\t\tcharCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1;\n\n\t\t\treturn {\n\t\t\t\tid: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`,\n\t\t\t\tlabel: char === \" \" ? \"\\u00A0\" : char,\n\t\t\t};\n\t\t});\n\t}, [children, uniqueId]);\n\n\tconst defaultVariants: Variants = {\n\t\tinitial: { opacity: 0 },\n\t\tanimate: { opacity: 1 },\n\t\texit: { opacity: 0 },\n\t};\n\n\tconst defaultTransition: Transition = {\n\t\ttype: \"spring\",\n\t\tstiffness: 280,\n\t\tdamping: 18,\n\t\tmass: 0.3,\n\t};\n\n\treturn (\n\t\t<Component className={cn(className)} aria-label={children} style={style}>\n\t\t\t<AnimatePresence mode=\"popLayout\" initial={false}>\n\t\t\t\t{characters.map((character) => (\n\t\t\t\t\t<motion.span\n\t\t\t\t\t\tkey={character.id}\n\t\t\t\t\t\tlayoutId={character.id}\n\t\t\t\t\t\tclassName=\"inline-block\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tinitial=\"initial\"\n\t\t\t\t\t\tanimate=\"animate\"\n\t\t\t\t\t\texit=\"exit\"\n\t\t\t\t\t\tvariants={variants || defaultVariants}\n\t\t\t\t\t\ttransition={transition || defaultTransition}\n\t\t\t\t\t>\n\t\t\t\t\t\t{character.label}\n\t\t\t\t\t</motion.span>\n\t\t\t\t))}\n\t\t\t</AnimatePresence>\n\t\t</Component>\n\t);\n}\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"
    }
  ]
}