{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "typewriter",
  "title": "Typewriter",
  "description": "Text that types itself out, cycling through phrases.",
  "dependencies": [
    "gsap"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/typewriter.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { TextPlugin } from \"gsap/TextPlugin\";\nimport { ScrollTrigger } from \"gsap/ScrollTrigger\";\n\nimport { gsap, motionScale, useGSAP } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\nif (typeof window !== \"undefined\") gsap.registerPlugin(TextPlugin, ScrollTrigger);\n\ntype TypewriterProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n  /** One phrase, or several to type, hold, delete and cycle. */\n  text: string | string[];\n  /** Characters per second. */\n  speed?: number;\n  /** Seconds a phrase stays before it is deleted. */\n  hold?: number;\n  loop?: boolean;\n  cursor?: boolean;\n};\n\n/**\n * Types text out with a blinking block caret (GSAP TextPlugin), optionally cycling through phrases.\n * The first phrase is server-rendered, so it is indexed and readable without JavaScript.\n */\nfunction Typewriter({ text, speed = 28, hold = 1.6, loop = true, cursor = true, className, ...props }: TypewriterProps) {\n  const ref = React.useRef<HTMLSpanElement>(null);\n  const phrases = Array.isArray(text) ? text : [text];\n\n  useGSAP(\n    () => {\n      const el = ref.current?.querySelector<HTMLElement>('[data-slot=\"typewriter-text\"]');\n      if (!el || !motionScale(el)) return;\n      const tl = gsap.timeline({ repeat: loop && phrases.length > 1 ? -1 : 0, paused: true });\n      phrases.forEach((p, i) => {\n        tl.set(el, { text: \"\" }).to(el, { text: { value: p }, duration: p.length / speed, ease: \"none\" });\n        if (phrases.length > 1 && (loop || i < phrases.length - 1)) tl.to(el, { text: { value: \"\" }, duration: p.length / (speed * 2.2), ease: \"none\", delay: hold });\n      });\n      ScrollTrigger.create({ trigger: el, start: \"top 95%\", once: true, onEnter: () => tl.play() });\n    },\n    { scope: ref, dependencies: [phrases.join(\"|\"), speed, hold, loop] },\n  );\n\n  return (\n    <span ref={ref} data-slot=\"typewriter\" className={cn(\"inline-flex items-baseline\", className)} {...props}>\n      <span data-slot=\"typewriter-text\" className=\"whitespace-pre-wrap\">\n        {phrases[0]}\n      </span>\n      {cursor && <span aria-hidden=\"true\" className=\"ms-0.5 inline-block h-[1em] w-[0.5ch] translate-y-[0.12em] animate-pulse bg-signal\" />}\n    </span>\n  );\n}\n\nexport { Typewriter };\nexport type { TypewriterProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/typewriter",
  "categories": [
    "effects"
  ],
  "type": "registry:ui"
}