import copy from "copy-to-clipboard"; import hljs from "highlight.js"; import { CopyIcon } from "lucide-react"; import { useCallback, useMemo } from "react"; import toast from "react-hot-toast"; import { cn } from "@/utils"; import MermaidBlock from "./MermaidBlock"; import { BaseProps } from "./types"; import "highlight.js/styles/atom-one-dark.css"; import "highlight.js/styles/github.css"; // Special languages that are rendered differently. enum SpecialLanguage { HTML = "__html", MERMAID = "mermaid", } interface Props extends BaseProps { language: string; content: string; } const CodeBlock: React.FC = ({ language, content }: Props) => { const formatedLanguage = useMemo(() => (language || "").toLowerCase() || "text", [language]); // Users can set Markdown code blocks as `__html` to render HTML directly. if (formatedLanguage === SpecialLanguage.HTML) { return (
); } else if (formatedLanguage === SpecialLanguage.MERMAID) { return ; } const highlightedCode = useMemo(() => { try { const lang = hljs.getLanguage(formatedLanguage); if (lang) { return hljs.highlight(content, { language: formatedLanguage, }).value; } } catch (error) { // Skip error and use default highlighted code. } // Escape any HTML entities when rendering original content. return Object.assign(document.createElement("span"), { textContent: content, }).innerHTML; }, [formatedLanguage, content]); const handleCopyButtonClick = useCallback(() => { copy(content); toast.success("Copied to clipboard!"); }, [content]); return (
{formatedLanguage}
          
        
); }; export default CodeBlock;