{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "letter-hover",
  "type": "registry:block",
  "title": "Letter hover",
  "description": "Letter hover",
  "files": [
    {
      "path": "components/usages/letterhoverusage.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\n\nimport LetterSwapForward from \"@/registry/open-source/letter-hover\";\nimport { RandomLetterSwapPingPong } from \"@/registry/open-source/random-letter-swap-hover\";\n\nexport default function Usage() {\n\treturn (\n\t\t<div className=\"h-screen w-full flex items-center justify-center relative overflow-hidden bg-background\">\n\t\t\t<div className=\"w-dvw h-dvh rounded-lg bg-background text-xl md:text-3xl  flex flex-col items-center justify-center font-calendas\">\n\t\t\t\t<div className=\" p-12 text-secondary rounded-xl align-text-top  gap-y-1 md:gap-y-2 flex flex-col\">\n\t\t\t\t\t<LetterSwapForward\n\t\t\t\t\t\tlabel=\"Hover me chief!\"\n\t\t\t\t\t\treverse={true}\n\t\t\t\t\t\tclassName=\"italic\"\n\t\t\t\t\t/>\n\t\t\t\t\t<LetterSwapForward\n\t\t\t\t\t\tlabel=\"{awesome}\"\n\t\t\t\t\t\treverse={false}\n\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t/>\n\t\t\t\t\t<LetterSwapForward\n\t\t\t\t\t\tlabel=\"Good day!\"\n\t\t\t\t\t\tstaggerFrom={\"center\"}\n\t\t\t\t\t\tclassName=\"mono\"\n\t\t\t\t\t/>\n\t\t\t\t\t<RandomLetterSwapPingPong\n\t\t\t\t\t\tlabel=\"More text?\"\n\t\t\t\t\t\tstaggerFrom={\"center\"}\n\t\t\t\t\t\treverse={false}\n\t\t\t\t\t\tclassName=\"font-overused-grotesk font-bold\"\n\t\t\t\t\t/>\n\t\t\t\t\t<RandomLetterSwapPingPong\n\t\t\t\t\t\tlabel=\"oh, seriously?!\"\n\t\t\t\t\t\tstaggerFrom={\"last\"}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>{\" \"}\n\t\t</div>\n\t);\n}\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/letterhoverusage.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\n\nimport LetterSwapForward from \"@/registry/open-source/letter-hover\";\nimport { RandomLetterSwapPingPong } from \"@/registry/open-source/random-letter-swap-hover\";\n\nexport default function Usage() {\n\treturn (\n\t\t<div className=\"h-screen w-full flex items-center justify-center relative overflow-hidden bg-background\">\n\t\t\t<div className=\"w-dvw h-dvh rounded-lg bg-background text-xl md:text-3xl  flex flex-col items-center justify-center font-calendas\">\n\t\t\t\t<div className=\" p-12 text-secondary rounded-xl align-text-top  gap-y-1 md:gap-y-2 flex flex-col\">\n\t\t\t\t\t<LetterSwapForward\n\t\t\t\t\t\tlabel=\"Hover me chief!\"\n\t\t\t\t\t\treverse={true}\n\t\t\t\t\t\tclassName=\"italic\"\n\t\t\t\t\t/>\n\t\t\t\t\t<LetterSwapForward\n\t\t\t\t\t\tlabel=\"{awesome}\"\n\t\t\t\t\t\treverse={false}\n\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t/>\n\t\t\t\t\t<LetterSwapForward\n\t\t\t\t\t\tlabel=\"Good day!\"\n\t\t\t\t\t\tstaggerFrom={\"center\"}\n\t\t\t\t\t\tclassName=\"mono\"\n\t\t\t\t\t/>\n\t\t\t\t\t<RandomLetterSwapPingPong\n\t\t\t\t\t\tlabel=\"More text?\"\n\t\t\t\t\t\tstaggerFrom={\"center\"}\n\t\t\t\t\t\treverse={false}\n\t\t\t\t\t\tclassName=\"font-overused-grotesk font-bold\"\n\t\t\t\t\t/>\n\t\t\t\t\t<RandomLetterSwapPingPong\n\t\t\t\t\t\tlabel=\"oh, seriously?!\"\n\t\t\t\t\t\tstaggerFrom={\"last\"}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>{\" \"}\n\t\t</div>\n\t);\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/letter-hover.tsx",
      "content": "\"use client\";\r\n\r\nimport { useState } from \"react\";\r\n\r\nimport {\r\n\tDynamicAnimationOptions,\r\n\tmotion,\r\n\tstagger,\r\n\tuseAnimate,\r\n} from \"motion/react\";\r\n\r\n// Credit:\r\n// https://www.fancycomponents.dev/docs/components/text/letter-swap\r\n\r\ninterface TextProps {\r\n\tlabel: string;\r\n\treverse?: boolean;\r\n\ttransition?: DynamicAnimationOptions;\r\n\tstaggerDuration?: number;\r\n\tstaggerFrom?: \"first\" | \"last\" | \"center\" | number;\r\n\tclassName?: string;\r\n\tonClick?: () => void;\r\n}\r\n\r\nconst LetterSwapForward = ({\r\n\tlabel,\r\n\treverse = true,\r\n\ttransition = {\r\n\t\ttype: \"spring\",\r\n\t\tduration: 0.7,\r\n\t},\r\n\tstaggerDuration = 0.03,\r\n\tstaggerFrom = \"first\",\r\n\tclassName,\r\n\tonClick,\r\n\t...props\r\n}: TextProps) => {\r\n\tconst [scope, animate] = useAnimate();\r\n\tconst [blocked, setBlocked] = useState(false);\r\n\r\n\tconst hoverStart = () => {\r\n\t\tif (blocked) return;\r\n\r\n\t\tsetBlocked(true);\r\n\r\n\t\t// Function to merge user transition with stagger and delay\r\n\t\tconst mergeTransition = (baseTransition: DynamicAnimationOptions) => ({\r\n\t\t\t...baseTransition,\r\n\t\t\tdelay: stagger(staggerDuration, {\r\n\t\t\t\tfrom: staggerFrom,\r\n\t\t\t}),\r\n\t\t});\r\n\r\n\t\tanimate(\r\n\t\t\t\".letter\",\r\n\t\t\t{ y: reverse ? \"100%\" : \"-100%\" },\r\n\t\t\tmergeTransition(transition)\r\n\t\t).then(() => {\r\n\t\t\tanimate(\r\n\t\t\t\t\".letter\",\r\n\t\t\t\t{\r\n\t\t\t\t\ty: 0,\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tduration: 0,\r\n\t\t\t\t}\r\n\t\t\t).then(() => {\r\n\t\t\t\tsetBlocked(false);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tanimate(\r\n\t\t\t\".letter-secondary\",\r\n\t\t\t{\r\n\t\t\t\ttop: \"0%\",\r\n\t\t\t},\r\n\t\t\tmergeTransition(transition)\r\n\t\t).then(() => {\r\n\t\t\tanimate(\r\n\t\t\t\t\".letter-secondary\",\r\n\t\t\t\t{\r\n\t\t\t\t\ttop: reverse ? \"-100%\" : \"100%\",\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\tduration: 0,\r\n\t\t\t\t}\r\n\t\t\t);\r\n\t\t});\r\n\t};\r\n\r\n\treturn (\r\n\t\t<span\r\n\t\t\tclassName={`flex justify-center items-center relative overflow-hidden  ${className} `}\r\n\t\t\tonMouseEnter={hoverStart}\r\n\t\t\tonClick={onClick}\r\n\t\t\tref={scope}\r\n\t\t\t{...props}\r\n\t\t>\r\n\t\t\t<span className=\"sr-only\">{label}</span>\r\n\r\n\t\t\t{label.split(\"\").map((letter: string, i: number) => {\r\n\t\t\t\treturn (\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\tclassName=\"whitespace-pre relative flex\"\r\n\t\t\t\t\t\tkey={i + \"letter-hover\"}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t<motion.span className={`relative letter`} style={{ top: 0 }}>\r\n\t\t\t\t\t\t\t{letter}\r\n\t\t\t\t\t\t</motion.span>\r\n\t\t\t\t\t\t<motion.span\r\n\t\t\t\t\t\t\tclassName=\"absolute letter-secondary \"\r\n\t\t\t\t\t\t\taria-hidden={true}\r\n\t\t\t\t\t\t\tstyle={{ top: reverse ? \"-100%\" : \"100%\" }}\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t{letter}\r\n\t\t\t\t\t\t</motion.span>\r\n\t\t\t\t\t</span>\r\n\t\t\t\t);\r\n\t\t\t})}\r\n\t\t</span>\r\n\t);\r\n};\r\n\r\nexport default LetterSwapForward;\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/random-letter-swap-hover.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport { debounce } from \"lodash\";\nimport { DynamicAnimationOptions, motion, useAnimate } from \"motion/react\";\n\n// Credit:\n// https://www.fancycomponents.dev/docs/components/text/random-letter-swap\n\ninterface TextProps {\n\tlabel: string;\n\treverse?: boolean;\n\ttransition?: DynamicAnimationOptions;\n\tstaggerDuration?: number;\n\tclassName?: string;\n\tonClick?: () => void;\n}\n\nconst RandomLetterSwapForward = ({\n\tlabel,\n\treverse = true,\n\ttransition = {\n\t\ttype: \"spring\",\n\t\tduration: 0.8,\n\t},\n\tstaggerDuration = 0.02,\n\tclassName,\n\tonClick,\n\t...props\n}: TextProps) => {\n\tconst [scope, animate] = useAnimate();\n\tconst [blocked, setBlocked] = useState(false);\n\n\tconst mergeTransition = (\n\t\ttransition: DynamicAnimationOptions,\n\t\ti: number\n\t) => ({\n\t\t...transition,\n\t\tdelay: i * staggerDuration,\n\t});\n\n\tconst shuffledIndices = Array.from(\n\t\t{ length: label.length },\n\t\t(_, i) => i\n\t).sort(() => Math.random() - 0.5);\n\n\tconst hoverStart = debounce(\n\t\t() => {\n\t\t\tif (blocked) return;\n\t\t\tsetBlocked(true);\n\n\t\t\tfor (let i = 0; i < label.length; i++) {\n\t\t\t\tconst randomIndex = shuffledIndices[i];\n\t\t\t\tanimate(\n\t\t\t\t\t\".letter-\" + randomIndex,\n\t\t\t\t\t{\n\t\t\t\t\t\ty: reverse ? \"100%\" : \"-100%\",\n\t\t\t\t\t},\n\t\t\t\t\tmergeTransition(transition, i)\n\t\t\t\t).then(() => {\n\t\t\t\t\tanimate(\n\t\t\t\t\t\t\".letter-\" + randomIndex,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ty: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tduration: 0,\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tanimate(\n\t\t\t\t\t\".letter-secondary-\" + randomIndex,\n\t\t\t\t\t{\n\t\t\t\t\t\ttop: \"0%\",\n\t\t\t\t\t},\n\t\t\t\t\tmergeTransition(transition, i)\n\t\t\t\t)\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\tanimate(\n\t\t\t\t\t\t\t\".letter-secondary-\" + randomIndex,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttop: reverse ? \"-100%\" : \"100%\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tduration: 0,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t})\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\tif (i === label.length - 1) {\n\t\t\t\t\t\t\tsetBlocked(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t100,\n\t\t{ leading: true, trailing: true }\n\t);\n\n\treturn (\n\t\t<motion.span\n\t\t\tclassName={`flex justify-center items-center relative overflow-hidden ${className}`}\n\t\t\tonHoverStart={hoverStart}\n\t\t\tonClick={onClick}\n\t\t\tref={scope}\n\t\t\t{...props}\n\t\t>\n\t\t\t<span className=\"sr-only\">{label}</span>\n\n\t\t\t{label.split(\"\").map((letter: string, i: number) => {\n\t\t\t\treturn (\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName=\"whitespace-pre relative flex\"\n\t\t\t\t\t\tkey={i + \"random-letter-swap\"}\n\t\t\t\t\t>\n\t\t\t\t\t\t<motion.span\n\t\t\t\t\t\t\tclassName={`relative pb-2 letter-${i}`}\n\t\t\t\t\t\t\tstyle={{ top: 0 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t</motion.span>\n\t\t\t\t\t\t<motion.span\n\t\t\t\t\t\t\tclassName={`absolute letter-secondary-${i}`}\n\t\t\t\t\t\t\taria-hidden={true}\n\t\t\t\t\t\t\tstyle={{ top: reverse ? \"-100%\" : \"100%\" }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t</motion.span>\n\t\t\t\t\t</span>\n\t\t\t\t);\n\t\t\t})}\n\t\t</motion.span>\n\t);\n};\n\nconst RandomLetterSwapPingPong = ({\n\tlabel,\n\treverse = true,\n\ttransition = {\n\t\ttype: \"spring\",\n\t\tduration: 0.8,\n\t},\n\tstaggerDuration = 0.02,\n\tclassName,\n\tonClick,\n\t...props\n}: TextProps) => {\n\tconst [scope, animate] = useAnimate();\n\tconst [blocked, setBlocked] = useState(false);\n\n\tconst mergeTransition = (\n\t\ttransition: DynamicAnimationOptions,\n\t\ti: number\n\t) => ({\n\t\t...transition,\n\t\tdelay: i * staggerDuration,\n\t});\n\n\tconst shuffledIndices = Array.from(\n\t\t{ length: label.length },\n\t\t(_, i) => i\n\t).sort(() => Math.random() - 0.5);\n\n\tconst hoverStart = debounce(\n\t\t() => {\n\t\t\tif (blocked) return;\n\t\t\tsetBlocked(true);\n\n\t\t\tfor (let i = 0; i < label.length; i++) {\n\t\t\t\tconst randomIndex = shuffledIndices[i];\n\t\t\t\tanimate(\n\t\t\t\t\t\".letter-\" + randomIndex,\n\t\t\t\t\t{\n\t\t\t\t\t\ty: reverse ? \"100%\" : \"-100%\",\n\t\t\t\t\t},\n\t\t\t\t\tmergeTransition(transition, i)\n\t\t\t\t);\n\n\t\t\t\tanimate(\n\t\t\t\t\t\".letter-secondary-\" + randomIndex,\n\t\t\t\t\t{\n\t\t\t\t\t\ttop: \"0%\",\n\t\t\t\t\t},\n\t\t\t\t\tmergeTransition(transition, i)\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\t100,\n\t\t{ leading: true, trailing: true }\n\t);\n\n\tconst hoverEnd = debounce(\n\t\t() => {\n\t\t\tsetBlocked(false);\n\n\t\t\tfor (let i = 0; i < label.length; i++) {\n\t\t\t\tconst randomIndex = shuffledIndices[i];\n\t\t\t\tanimate(\n\t\t\t\t\t\".letter-\" + randomIndex,\n\t\t\t\t\t{\n\t\t\t\t\t\ty: 0,\n\t\t\t\t\t},\n\t\t\t\t\tmergeTransition(transition, i)\n\t\t\t\t);\n\n\t\t\t\tanimate(\n\t\t\t\t\t\".letter-secondary-\" + randomIndex,\n\t\t\t\t\t{\n\t\t\t\t\t\ttop: reverse ? \"-100%\" : \"100%\",\n\t\t\t\t\t},\n\t\t\t\t\tmergeTransition(transition, i)\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\t100,\n\t\t{ leading: true, trailing: true }\n\t);\n\n\treturn (\n\t\t<motion.span\n\t\t\tclassName={`flex justify-center items-center relative overflow-hidden  ${className} `}\n\t\t\tonHoverStart={hoverStart}\n\t\t\tonHoverEnd={hoverEnd}\n\t\t\tonClick={onClick}\n\t\t\tref={scope}\n\t\t\t{...props}\n\t\t>\n\t\t\t<span className=\"sr-only\">{label}</span>\n\n\t\t\t{label.split(\"\").map((letter: string, i: number) => {\n\t\t\t\treturn (\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName=\"whitespace-pre relative flex\"\n\t\t\t\t\t\tkey={i + \"random-letter-swap-hover\"}\n\t\t\t\t\t>\n\t\t\t\t\t\t<motion.span\n\t\t\t\t\t\t\tclassName={`relative pb-2 letter-${i}`}\n\t\t\t\t\t\t\tstyle={{ top: 0 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t</motion.span>\n\t\t\t\t\t\t<motion.span\n\t\t\t\t\t\t\tclassName={`absolute letter-secondary-${i}`}\n\t\t\t\t\t\t\taria-hidden={true}\n\t\t\t\t\t\t\tstyle={{ top: reverse ? \"-100%\" : \"100%\" }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{letter}\n\t\t\t\t\t\t</motion.span>\n\t\t\t\t\t</span>\n\t\t\t\t);\n\t\t\t})}\n\t\t</motion.span>\n\t);\n};\n\nexport { RandomLetterSwapForward, RandomLetterSwapPingPong };\n",
      "type": "registry:ui"
    }
  ]
}