// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { Check, Copy } from "lucide-react";
import { useMemo, useState } from "react";
import ReactMarkdown, {
type Options as ReactMarkdownOptions,
} from "react-markdown";
import rehypeKatex from "rehype-katex";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import "katex/dist/katex.min.css";
import { Button } from "~/components/ui/button";
import { rehypeSplitWordsIntoSpans } from "~/core/rehype";
import { cn } from "~/lib/utils";
import Image from "./image";
import { Tooltip } from "./tooltip";
export function Markdown({
className,
children,
style,
enableCopy,
animate = false,
...props
}: ReactMarkdownOptions & {
className?: string;
enableCopy?: boolean;
style?: React.CSSProperties;
animate?: boolean;
}) {
const rehypePlugins = useMemo(() => {
if (animate) {
return [rehypeKatex, rehypeSplitWordsIntoSpans];
}
return [rehypeKatex];
}, [animate]);
return (
(
{children}
),
img: ({ src, alt }) => (
),
}}
{...props}
>
{dropMarkdownQuote(processKatexInMarkdown(children))}
{enableCopy && typeof children === "string" && (
)}
);
}
function CopyButton({ content }: { content: string }) {
const [copied, setCopied] = useState(false);
return (
);
}
function processKatexInMarkdown(markdown?: string | null) {
if (!markdown) return markdown;
const markdownWithKatexSyntax = markdown
.replace(/\\\\\[/g, "$$$$") // Replace '\\[' with '$$'
.replace(/\\\\\]/g, "$$$$") // Replace '\\]' with '$$'
.replace(/\\\\\(/g, "$$$$") // Replace '\\(' with '$$'
.replace(/\\\\\)/g, "$$$$") // Replace '\\)' with '$$'
.replace(/\\\[/g, "$$$$") // Replace '\[' with '$$'
.replace(/\\\]/g, "$$$$") // Replace '\]' with '$$'
.replace(/\\\(/g, "$$$$") // Replace '\(' with '$$'
.replace(/\\\)/g, "$$$$"); // Replace '\)' with '$$';
return markdownWithKatexSyntax;
}
function dropMarkdownQuote(markdown?: string | null) {
if (!markdown) return markdown;
return markdown
.replace(/^```markdown\n/gm, "")
.replace(/^```text\n/gm, "")
.replace(/^```\n/gm, "")
.replace(/\n```$/gm, "");
}