import React, { useCallback, useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import 'katex/dist/katex.min.css'; import RemarkMath from 'remark-math'; // Math syntax import RemarkBreaks from 'remark-breaks'; // Line break import RehypeKatex from 'rehype-katex'; // Math render import RemarkGfm from 'remark-gfm'; // Special markdown syntax import RehypeExternalLinks from 'rehype-external-links'; import styles from './index.module.scss'; import dynamic from 'next/dynamic'; import { Box } from '@chakra-ui/react'; import { CodeClassNameEnum, mdTextFormat } from './utils'; const CodeLight = dynamic(() => import('./codeBlock/CodeLight'), { ssr: false }); const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false }); const MdImage = dynamic(() => import('./img/Image'), { ssr: false }); const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr: false }); const IframeCodeBlock = dynamic(() => import('./codeBlock/Iframe'), { ssr: false }); const IframeHtmlCodeBlock = dynamic(() => import('./codeBlock/iframe-html'), { ssr: false }); const VideoBlock = dynamic(() => import('./codeBlock/Video'), { ssr: false }); const AudioBlock = dynamic(() => import('./codeBlock/Audio'), { ssr: false }); const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false }); const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false }); const A = dynamic(() => import('./A'), { ssr: false }); type Props = { source?: string; showAnimation?: boolean; isDisabled?: boolean; forbidZhFormat?: boolean; }; const Markdown = (props: Props) => { const source = props.source || ''; if (source.length < 200000) { return ; } return {source}; }; const MarkdownRender = ({ source = '', showAnimation, isDisabled, forbidZhFormat }: Props) => { const components = useMemo( () => ({ img: Image, pre: RewritePre, code: Code, a: A }), [] ); const formatSource = useMemo(() => { if (showAnimation || forbidZhFormat) return source; return mdTextFormat(source); }, [forbidZhFormat, showAnimation, source]); const urlTransform = useCallback((val: string) => { return val; }, []); return ( {formatSource} {isDisabled && } ); }; export default React.memo(Markdown); /* Custom dom */ function Code(e: any) { const { className, codeBlock, children } = e; const match = /language-(\w+)/.exec(className || ''); const codeType = match?.[1]?.toLowerCase(); const strChildren = String(children); const Component = useMemo(() => { if (codeType === CodeClassNameEnum.mermaid) { return ; } if (codeType === CodeClassNameEnum.guide) { return ; } if (codeType === CodeClassNameEnum.questionGuide) { return ; } if (codeType === CodeClassNameEnum.echarts) { return ; } if (codeType === CodeClassNameEnum.iframe) { return ; } if (codeType === CodeClassNameEnum.html || codeType === CodeClassNameEnum.svg) { return ( {children} ); } if (codeType === CodeClassNameEnum.video) { return ; } if (codeType === CodeClassNameEnum.audio) { return ; } return ( {children} ); }, [codeType, className, codeBlock, match, children, strChildren]); return Component; } function Image({ src }: { src?: string }) { return ; } function RewritePre({ children }: any) { const modifiedChildren = React.Children.map(children, (child) => { if (React.isValidElement(child)) { // @ts-ignore return React.cloneElement(child, { codeBlock: true }); } return child; }); return <>{modifiedChildren}; }