{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "markdown-text",
  "type": "registry:component",
  "title": "Markdown Text",
  "description": "Render assistant markdown with headings, lists, links, and code blocks.",
  "registryDependencies": [
    "https://r.assistant-ui.com/tooltip-icon-button.json"
  ],
  "dependencies": [
    "@assistant-ui/react-markdown",
    "lucide-react",
    "remark-gfm"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/markdown-text.tsx",
      "content": "\"use client\";\n\nimport \"@assistant-ui/react-markdown/styles/dot.css\";\n\nimport {\n  type CodeHeaderProps,\n  MarkdownTextPrimitive,\n  unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,\n  useIsMarkdownCodeBlock,\n} from \"@assistant-ui/react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { type FC, memo, useState } from \"react\";\nimport { CheckIcon, CopyIcon } from \"lucide-react\";\n\nimport { TooltipIconButton } from \"@/components/assistant-ui/tooltip-icon-button\";\nimport { cn } from \"@/lib/utils\";\n\nconst MarkdownTextImpl = () => {\n  return (\n    <MarkdownTextPrimitive\n      remarkPlugins={[remarkGfm]}\n      className=\"aui-md\"\n      components={defaultComponents}\n      defer\n    />\n  );\n};\n\nexport const MarkdownText = memo(MarkdownTextImpl);\n\nconst CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {\n  const { isCopied, copyToClipboard } = useCopyToClipboard();\n  const onCopy = () => {\n    if (!code || isCopied) return;\n    copyToClipboard(code);\n  };\n\n  return (\n    <div className=\"aui-code-header-root border-border/50 bg-muted/50 mt-3 flex items-center justify-between rounded-t-xl border border-b-0 px-3.5 py-1.5 text-xs\">\n      <span className=\"aui-code-header-language text-muted-foreground font-medium lowercase\">\n        {language}\n      </span>\n      <TooltipIconButton tooltip=\"Copy\" onClick={onCopy}>\n        {!isCopied && (\n          <CopyIcon className=\"animate-in zoom-in-75 fade-in duration-150\" />\n        )}\n        {isCopied && (\n          <CheckIcon className=\"animate-in zoom-in-50 fade-in duration-200 ease-out\" />\n        )}\n      </TooltipIconButton>\n    </div>\n  );\n};\n\nconst useCopyToClipboard = ({\n  copiedDuration = 3000,\n}: {\n  copiedDuration?: number;\n} = {}) => {\n  const [isCopied, setIsCopied] = useState<boolean>(false);\n\n  const copyToClipboard = (value: string) => {\n    if (!value || typeof navigator === \"undefined\" || !navigator.clipboard) {\n      return;\n    }\n\n    navigator.clipboard.writeText(value).then(\n      () => {\n        setIsCopied(true);\n        setTimeout(() => setIsCopied(false), copiedDuration);\n      },\n      () => {},\n    );\n  };\n\n  return { isCopied, copyToClipboard };\n};\n\nconst defaultComponents = memoizeMarkdownComponents({\n  h1: ({ className, ...props }) => (\n    <h1\n      className={cn(\n        \"aui-md-h1 mt-5 mb-2 scroll-m-20 text-xl font-semibold first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  h2: ({ className, ...props }) => (\n    <h2\n      className={cn(\n        \"aui-md-h2 mt-5 mb-2 scroll-m-20 text-lg font-semibold first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  h3: ({ className, ...props }) => (\n    <h3\n      className={cn(\n        \"aui-md-h3 mt-4 mb-1.5 scroll-m-20 text-base font-semibold first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  h4: ({ className, ...props }) => (\n    <h4\n      className={cn(\n        \"aui-md-h4 mt-3.5 mb-1 scroll-m-20 text-base font-medium first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  h5: ({ className, ...props }) => (\n    <h5\n      className={cn(\n        \"aui-md-h5 mt-3 mb-1 text-sm font-semibold first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  h6: ({ className, ...props }) => (\n    <h6\n      className={cn(\n        \"aui-md-h6 mt-3 mb-1 text-sm font-medium first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  p: ({ className, ...props }) => (\n    <p\n      className={cn(\n        \"aui-md-p my-3 leading-relaxed first:mt-0 last:mb-0\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  a: ({ className, ...props }) => (\n    <a\n      className={cn(\n        \"aui-md-a text-primary hover:text-primary/80 underline underline-offset-2\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  blockquote: ({ className, ...props }) => (\n    <blockquote\n      className={cn(\n        \"aui-md-blockquote border-muted-foreground/30 text-muted-foreground my-3 border-s-2 ps-4\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  ul: ({ className, ...props }) => (\n    <ul\n      className={cn(\n        \"aui-md-ul marker:text-muted-foreground my-3 ms-5 list-disc [&>li]:mt-1\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  ol: ({ className, ...props }) => (\n    <ol\n      className={cn(\n        \"aui-md-ol marker:text-muted-foreground my-3 ms-5 list-decimal [&>li]:mt-1\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  hr: ({ className, ...props }) => (\n    <hr\n      className={cn(\"aui-md-hr border-muted-foreground/20 my-3\", className)}\n      {...props}\n    />\n  ),\n  table: ({ className, ...props }) => (\n    <table\n      className={cn(\n        \"aui-md-table my-3 w-full border-separate border-spacing-0 overflow-y-auto\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  th: ({ className, ...props }) => (\n    <th\n      className={cn(\n        \"aui-md-th bg-muted px-3 py-1.5 text-start font-medium first:rounded-ss-lg last:rounded-se-lg [[align=center]]:text-center [[align=right]]:text-right\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  td: ({ className, ...props }) => (\n    <td\n      className={cn(\n        \"aui-md-td border-muted-foreground/20 border-s border-b px-3 py-1.5 text-start last:border-e [[align=center]]:text-center [[align=right]]:text-right\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  tr: ({ className, ...props }) => (\n    <tr\n      className={cn(\n        \"aui-md-tr m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-es-lg [&:last-child>td:last-child]:rounded-ee-lg\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  li: ({ className, ...props }) => (\n    <li className={cn(\"aui-md-li leading-relaxed\", className)} {...props} />\n  ),\n  strong: ({ className, ...props }) => (\n    <strong\n      className={cn(\"aui-md-strong font-semibold\", className)}\n      {...props}\n    />\n  ),\n  sup: ({ className, ...props }) => (\n    <sup\n      className={cn(\"aui-md-sup [&>a]:text-xs [&>a]:no-underline\", className)}\n      {...props}\n    />\n  ),\n  pre: ({ className, ...props }) => (\n    <pre\n      className={cn(\n        \"aui-md-pre border-border/50 bg-muted/30 overflow-x-auto rounded-t-none rounded-b-xl border border-t-0 p-3.5 text-[13px] leading-relaxed\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n  code: function Code({ className, ...props }) {\n    const isCodeBlock = useIsMarkdownCodeBlock();\n    return (\n      <code\n        className={cn(\n          !isCodeBlock &&\n            \"aui-md-inline-code bg-muted rounded-md px-1.5 py-0.5 font-mono text-[0.85em]\",\n          className,\n        )}\n        {...props}\n      />\n    );\n  },\n  CodeHeader,\n});\n"
    }
  ]
}