import React, { useMemo, useState } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { useTranslation } from 'react-i18next'; import { normalizeInlineCodeFences } from '../../utils/chatFormatting'; import { copyTextToClipboard } from '../../../../utils/clipboard'; type MarkdownProps = { children: React.ReactNode; className?: string; }; type CodeBlockProps = { node?: any; inline?: boolean; className?: string; children?: React.ReactNode; }; const CodeBlock = ({ node, inline, className, children, ...props }: CodeBlockProps) => { const { t } = useTranslation('chat'); const [copied, setCopied] = useState(false); const raw = Array.isArray(children) ? children.join('') : String(children ?? ''); const looksMultiline = /[\r\n]/.test(raw); const inlineDetected = inline || (node && node.type === 'inlineCode'); const shouldInline = inlineDetected || !looksMultiline; if (shouldInline) { return ( {children} ); } const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : 'text'; return (
{language && language !== 'text' && (
{language}
)} {raw}
); }; const markdownComponents = { code: CodeBlock, blockquote: ({ children }: { children?: React.ReactNode }) => (
{children}
), a: ({ href, children }: { href?: string; children?: React.ReactNode }) => ( {children} ), p: ({ children }: { children?: React.ReactNode }) =>
{children}
, table: ({ children }: { children?: React.ReactNode }) => (
{children}
), thead: ({ children }: { children?: React.ReactNode }) => {children}, th: ({ children }: { children?: React.ReactNode }) => ( {children} ), td: ({ children }: { children?: React.ReactNode }) => ( {children} ), }; export function Markdown({ children, className }: MarkdownProps) { const content = normalizeInlineCodeFences(String(children ?? '')); const remarkPlugins = useMemo(() => [remarkGfm, remarkMath], []); const rehypePlugins = useMemo(() => [rehypeKatex], []); return (
{content}
); }