{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "streaming-text",
  "title": "Streaming Text",
  "description": "A reply arriving token by token, without the jitter.",
  "dependencies": [],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/streaming-text.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { gsap, motionScale } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\ntype StreamingTextProps = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n  /** The text so far; append to it as tokens arrive. */\n  text: string;\n  streaming?: boolean;\n};\n\n/**\n * A reply arriving token by token without the jitter: each new chunk fades up out of a slight blur instead of\n * popping in, and a signal caret marks the writing edge. Everything already shown stays perfectly still.\n */\nfunction StreamingText({ text, streaming = false, className, ...props }: StreamingTextProps) {\n  const ref = React.useRef<HTMLDivElement>(null);\n  const [chunks, setChunks] = React.useState<string[]>(() => (text ? [text] : []));\n  const seen = React.useRef(text.length);\n\n  React.useEffect(() => {\n    if (text.length < seen.current) {\n      seen.current = text.length;\n      setChunks(text ? [text] : []);\n      return;\n    }\n    if (text.length === seen.current) return;\n    const next = text.slice(seen.current);\n    seen.current = text.length;\n    setChunks((c) => [...c, next]);\n  }, [text]);\n\n  React.useLayoutEffect(() => {\n    const el = ref.current;\n    const last = el?.querySelector<HTMLElement>('[data-chunk]:last-of-type');\n    if (!el || !last || last.dataset.shown || !motionScale(el)) return;\n    last.dataset.shown = \"true\";\n    gsap.fromTo(last, { opacity: 0, filter: \"blur(3px)\" }, { opacity: 1, filter: \"blur(0px)\", duration: 0.35, ease: \"cue\", clearProps: \"filter\" });\n  }, [chunks.length]);\n\n  return (\n    <div ref={ref} data-slot=\"streaming-text\" className={cn(\"text-sm leading-relaxed whitespace-pre-wrap\", className)} {...props}>\n      {chunks.map((c, i) => (\n        <span key={i} data-chunk>\n          {c}\n        </span>\n      ))}\n      {streaming && <span aria-hidden=\"true\" className=\"ms-0.5 inline-block h-[1.05em] w-[0.45em] translate-y-[0.18em] animate-pulse rounded-[1px] bg-signal\" />}\n    </div>\n  );\n}\n\nexport { StreamingText };\nexport type { StreamingTextProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/streaming-text",
  "categories": [
    "agents"
  ],
  "type": "registry:ui"
}