{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "markdown-content",
	"type": "registry:ui",
	"title": "Markdown Content",
	"description": "A component that renders markdown content.",
	"dependencies": [
		"react-markdown",
		"marked",
		"shiki",
		"remark-gfm",
		"rehype-raw"
	],
	"files": [
		{
			"path": "./src/registry/ui/markdown-content.tsx",
			"content": "import { marked } from \"marked\";\nimport type * as React from \"react\";\nimport { isValidElement, memo, Suspense, useMemo } from \"react\";\nimport ReactMarkdown, { type Components } from \"react-markdown\";\nimport rehypeRaw from \"rehype-raw\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"@/lib/utils\";\n\nconst DEFAULT_PRE_BLOCK_CLASS =\n\t\"my-4 overflow-x-auto w-fit rounded-xl bg-zinc-950 text-zinc-50 dark:bg-zinc-900 border border-border p-4\";\n\nconst extractTextContent = (node: React.ReactNode): string => {\n\tif (typeof node === \"string\") {\n\t\treturn node;\n\t}\n\tif (Array.isArray(node)) {\n\t\treturn node.map(extractTextContent).join(\"\");\n\t}\n\tif (isValidElement(node)) {\n\t\t// @ts-expect-error\n\t\treturn extractTextContent(node.props.children);\n\t}\n\treturn \"\";\n};\n\ninterface HighlightedPreProps extends React.HTMLAttributes<HTMLPreElement> {\n\tlanguage: string;\n}\n\nconst HighlightedPre = memo(\n\tasync ({\n\t\tchildren,\n\t\tclassName,\n\t\tlanguage,\n\t\t...props\n\t}: HighlightedPreProps) => {\n\t\tconst { codeToTokens, bundledLanguages } = await import(\"shiki\");\n\t\tconst code = extractTextContent(children);\n\n\t\tif (!(language in bundledLanguages)) {\n\t\t\treturn (\n\t\t\t\t<pre\n\t\t\t\t\t{...props}\n\t\t\t\t\tclassName={cn(DEFAULT_PRE_BLOCK_CLASS, className)}\n\t\t\t\t>\n\t\t\t\t\t<code className=\"whitespace-pre-wrap\">{children}</code>\n\t\t\t\t</pre>\n\t\t\t);\n\t\t}\n\n\t\tconst { tokens } = await codeToTokens(code, {\n\t\t\tlang: language as keyof typeof bundledLanguages,\n\t\t\tthemes: {\n\t\t\t\tlight: \"github-dark\",\n\t\t\t\tdark: \"github-dark\",\n\t\t\t},\n\t\t});\n\n\t\treturn (\n\t\t\t<pre {...props} className={cn(DEFAULT_PRE_BLOCK_CLASS, className)}>\n\t\t\t\t<code className=\"whitespace-pre-wrap break-all\">\n\t\t\t\t\t{tokens.map((line, lineIndex) => (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={`line-${\n\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: Needed for react key\n\t\t\t\t\t\t\t\tlineIndex\n\t\t\t\t\t\t\t}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{line.map((token, tokenIndex) => {\n\t\t\t\t\t\t\t\tconst style =\n\t\t\t\t\t\t\t\t\ttypeof token.htmlStyle === \"string\"\n\t\t\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t\t\t: token.htmlStyle;\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tkey={`token-${\n\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: Needed for react key\n\t\t\t\t\t\t\t\t\t\t\ttokenIndex\n\t\t\t\t\t\t\t\t\t\t}`}\n\t\t\t\t\t\t\t\t\t\tstyle={style}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{token.content}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t{lineIndex !== tokens.length - 1 && \"\\n\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t))}\n\t\t\t\t</code>\n\t\t\t</pre>\n\t\t);\n\t},\n);\n\nHighlightedPre.displayName = \"HighlightedPre\";\n\ninterface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {\n\tlanguage: string;\n}\n\nconst CodeBlock = ({\n\tchildren,\n\tlanguage,\n\tclassName,\n\t...props\n}: CodeBlockProps) => {\n\treturn (\n\t\t<Suspense\n\t\t\tfallback={\n\t\t\t\t<pre\n\t\t\t\t\t{...props}\n\t\t\t\t\tclassName={cn(DEFAULT_PRE_BLOCK_CLASS, className)}\n\t\t\t\t>\n\t\t\t\t\t<code className=\"whitespace-pre-wrap\">{children}</code>\n\t\t\t\t</pre>\n\t\t\t}\n\t\t>\n\t\t\t<HighlightedPre language={language} {...props}>\n\t\t\t\t{children}\n\t\t\t</HighlightedPre>\n\t\t</Suspense>\n\t);\n};\n\nCodeBlock.displayName = \"CodeBlock\";\n\nconst components: Partial<Components> = {\n\th1: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n\t\t<h1 className=\"mt-2 scroll-m-20 text-4xl font-bold\" {...props}>\n\t\t\t{children}\n\t\t</h1>\n\t),\n\th2: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n\t\t<h2\n\t\t\tclassName=\"mt-8 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight first:mt-0\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</h2>\n\t),\n\th3: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n\t\t<h3\n\t\t\tclassName=\"mt-4 scroll-m-20 text-xl font-semibold tracking-tight\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</h3>\n\t),\n\th4: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n\t\t<h4\n\t\t\tclassName=\"mt-4 scroll-m-20 text-lg font-semibold tracking-tight\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</h4>\n\t),\n\th5: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n\t\t<h5\n\t\t\tclassName=\"mt-4 scroll-m-20 text-lg font-semibold tracking-tight\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</h5>\n\t),\n\th6: ({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (\n\t\t<h6\n\t\t\tclassName=\"mt-4 scroll-m-20 text-base font-semibold tracking-tight\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</h6>\n\t),\n\tp: ({ children, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (\n\t\t<p className=\"leading-6 not-first:mt-4 break-all\" {...props}>\n\t\t\t{children}\n\t\t</p>\n\t),\n\tstrong: ({ children, ...props }: React.HTMLAttributes<HTMLElement>) => (\n\t\t<span className=\"font-semibold\" {...props}>\n\t\t\t{children}\n\t\t</span>\n\t),\n\tspan: ({\n\t\tchildren,\n\t\tclassName,\n\t\t...props\n\t}: {\n\t\t\"data-type\"?: string;\n\t\t\"data-id\"?: string;\n\t\t\"data-label\"?: string;\n\t} & React.HTMLAttributes<HTMLSpanElement>) => {\n\t\tconst dataType = props[\"data-type\"];\n\t\tconst dataId = props[\"data-id\"];\n\t\tconst dataLabel = props[\"data-label\"];\n\n\t\tconsole.log(\"dataType\", className);\n\n\t\tif (className?.includes(\"mention\")) {\n\t\t\treturn (\n\t\t\t\t<span\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"bg-primary text-primary-foreground rounded-sm px-2 py-0.5\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t\tdata-type={dataType}\n\t\t\t\t\tdata-id={dataId}\n\t\t\t\t\tdata-label={dataLabel}\n\t\t\t\t\ttitle={dataLabel}\n\t\t\t\t\t{...props}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</span>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<span className={className} {...props}>\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t);\n\t},\n\ta: ({\n\t\tchildren,\n\t\t...props\n\t}: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (\n\t\t<a\n\t\t\tclassName=\"font-medium underline underline-offset-4 whitespace-pre-wrap break-all\"\n\t\t\ttarget=\"_blank\"\n\t\t\trel=\"noreferrer\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</a>\n\t),\n\tol: ({ children, ...props }: React.HTMLAttributes<HTMLOListElement>) => (\n\t\t<ol className=\"my-4 ml-6 list-decimal\" {...props}>\n\t\t\t{children}\n\t\t</ol>\n\t),\n\tul: ({ children, ...props }: React.HTMLAttributes<HTMLUListElement>) => (\n\t\t<ul className=\"my-4 ml-6 list-disc\" {...props}>\n\t\t\t{children}\n\t\t</ul>\n\t),\n\tli: ({ children, ...props }: React.LiHTMLAttributes<HTMLLIElement>) => (\n\t\t<li className=\"mt-2 break-all\" {...props}>\n\t\t\t{children}\n\t\t</li>\n\t),\n\tblockquote: ({\n\t\tchildren,\n\t\t...props\n\t}: React.HTMLAttributes<HTMLQuoteElement>) => (\n\t\t<blockquote className=\"mt-4 border-l-2 pl-6 italic\" {...props}>\n\t\t\t{children}\n\t\t</blockquote>\n\t),\n\thr: (props: React.HTMLAttributes<HTMLHRElement>) => (\n\t\t<hr className=\"my-4 md:my-8\" {...props} />\n\t),\n\ttable: ({ children, ...props }: React.HTMLAttributes<HTMLTableElement>) => (\n\t\t<div className=\"my-6 w-full overflow-y-auto\">\n\t\t\t<table\n\t\t\t\tclassName=\"relative w-full overflow-hidden border-none text-sm\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</table>\n\t\t</div>\n\t),\n\ttr: ({ children, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (\n\t\t<tr className=\"last:border-b-none m-0 border-b\" {...props}>\n\t\t\t{children}\n\t\t</tr>\n\t),\n\tth: ({\n\t\tchildren,\n\t\t...props\n\t}: React.HTMLAttributes<HTMLTableCellElement>) => (\n\t\t<th\n\t\t\tclassName=\"px-4 py-2 text-left font-bold [[align=center]]:text-center [[align=right]]:text-right\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</th>\n\t),\n\ttd: ({\n\t\tchildren,\n\t\t...props\n\t}: React.HTMLAttributes<HTMLTableCellElement>) => (\n\t\t<td\n\t\t\tclassName=\"px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right\"\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</td>\n\t),\n\timg: ({ alt, ...props }: React.ImgHTMLAttributes<HTMLImageElement>) => (\n\t\t// biome-ignore lint/performance/noImgElement: Required for image\n\t\t<img className=\"rounded-md\" alt={alt} {...props} />\n\t),\n\tcode: ({ children, node, className, ...props }) => {\n\t\tconst match = /language-(\\w+)/.exec(className || \"\");\n\t\tif (match) {\n\t\t\treturn (\n\t\t\t\t<CodeBlock language={match[1]} className={className} {...props}>\n\t\t\t\t\t{children}\n\t\t\t\t</CodeBlock>\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\t<code\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm break-all\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</code>\n\t\t);\n\t},\n\tpre: ({ children }) => <>{children}</>,\n};\n\nfunction parseMarkdownIntoBlocks(markdown: string): string[] {\n\tif (!markdown) {\n\t\treturn [];\n\t}\n\tconst tokens = marked.lexer(markdown);\n\treturn tokens.map((token) => token.raw);\n}\n\ninterface MarkdownBlockProps {\n\tcontent: string;\n\tclassName?: string;\n}\n\nconst MemoizedMarkdownBlock = memo(\n\t({ content, className }: MarkdownBlockProps) => {\n\t\treturn (\n\t\t\t<div className={className}>\n\t\t\t\t<ReactMarkdown\n\t\t\t\t\tremarkPlugins={[remarkGfm]}\n\t\t\t\t\trehypePlugins={[rehypeRaw]}\n\t\t\t\t\tcomponents={components}\n\t\t\t\t>\n\t\t\t\t\t{content}\n\t\t\t\t</ReactMarkdown>\n\t\t\t</div>\n\t\t);\n\t},\n\t(prevProps, nextProps) => {\n\t\tif (prevProps.content !== nextProps.content) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n);\n\nMemoizedMarkdownBlock.displayName = \"MemoizedMarkdownBlock\";\n\ninterface MarkdownContentProps {\n\tcontent: string;\n\tclassName?: string;\n}\n\nexport const MarkdownContent = memo(\n\t({ content, className }: MarkdownContentProps) => {\n\t\tconst blocks = useMemo(\n\t\t\t() => parseMarkdownIntoBlocks(content || \"\"),\n\t\t\t[content],\n\t\t);\n\n\t\treturn blocks.map((block, index) => (\n\t\t\t<MemoizedMarkdownBlock\n\t\t\t\tcontent={block}\n\t\t\t\tclassName={className}\n\t\t\t\tkey={`block_${\n\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: Needed for react key\n\t\t\t\t\tindex\n\t\t\t\t}`}\n\t\t\t/>\n\t\t));\n\t},\n);\n\nMarkdownContent.displayName = \"MarkdownContent\";\n",
			"type": "registry:ui"
		}
	]
}
