{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "artifact",
  "title": "Artifact",
  "description": "Something the agent made, in its own panel with actions.",
  "dependencies": [
    "lucide-react",
    "react-dom"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/artifact.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { DownloadIcon, Maximize2Icon, Minimize2Icon, XIcon } from \"lucide-react\";\n\nimport { enterOnce } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\ntype ArtifactProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n  title: React.ReactNode;\n  /** Kind shown as a label, e.g. \"Document\", \"React component\", \"Chart\". */\n  kind?: string;\n  onClose?: () => void;\n  onDownload?: () => void;\n  /** Extra header actions. */\n  actions?: React.ReactNode;\n};\n\n/**\n * Something an agent made (a document, a component, a chart) shown in its own panel beside the chat, with a header\n * of actions and a full-screen toggle.\n */\nfunction Artifact({ title, kind, onClose, onDownload, actions, className, children, ...props }: ArtifactProps) {\n  const [full, setFull] = React.useState(false);\n  React.useEffect(() => {\n    if (!full) return;\n    const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setFull(false);\n    window.addEventListener(\"keydown\", onKey);\n    document.body.style.overflow = \"hidden\";\n    return () => {\n      window.removeEventListener(\"keydown\", onKey);\n      document.body.style.overflow = \"\";\n    };\n  }, [full]);\n  const enter = React.useCallback((node: HTMLElement | null) => enterOnce(node, (s) => ({ opacity: 0, x: 16 * s }), { duration: 0.35 }), []);\n  const btn = \"grid size-7 place-items-center rounded-md text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 [&_svg]:size-3.5\";\n  const panel = (\n    <section\n      ref={full ? undefined : enter}\n      data-slot=\"artifact\"\n      data-fullscreen={full || undefined}\n      role={full ? \"dialog\" : undefined}\n      aria-modal={full || undefined}\n      className={cn(\"flex min-h-0 flex-col overflow-hidden rounded-2xl border border-border bg-card shadow-raised\", full ? \"fixed inset-3 z-[100] sm:inset-6\" : className)}\n      {...props}\n    >\n      <header className=\"flex items-center gap-2 border-b border-border px-3 py-2\">\n        <div className=\"grid min-w-0 flex-1\">\n          {kind && <span className=\"cue-label\">{kind}</span>}\n          <span className=\"truncate text-sm font-medium\">{title}</span>\n        </div>\n        {actions}\n        {onDownload && (\n          <button type=\"button\" aria-label=\"Download\" onClick={onDownload} className={btn}>\n            <DownloadIcon />\n          </button>\n        )}\n        <button type=\"button\" aria-label={full ? \"Exit full screen\" : \"Full screen\"} onClick={() => setFull((f) => !f)} className={btn}>\n          {full ? <Minimize2Icon /> : <Maximize2Icon />}\n        </button>\n        {onClose && (\n          <button type=\"button\" aria-label=\"Close\" onClick={onClose} className={btn}>\n            <XIcon />\n          </button>\n        )}\n      </header>\n      <div className=\"min-h-0 flex-1 overflow-auto\">{children}</div>\n    </section>\n  );\n  if (!full) return panel;\n  return createPortal(\n    <>\n      <div aria-hidden=\"true\" onClick={() => setFull(false)} className=\"fixed inset-0 z-[99] bg-black/30 backdrop-blur-[2px] dark:bg-black/60\" />\n      {panel}\n    </>,\n    document.body,\n  );\n}\n\nexport { Artifact };\nexport type { ArtifactProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/artifact",
  "categories": [
    "agents"
  ],
  "type": "registry:ui"
}