import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react' import { Alert } from 'antd' import { Virtuoso } from 'react-virtuoso' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import rehypeRaw from 'rehype-raw' import rehypeSlug from 'rehype-slug' import './LargeMarkdownViewer.css' export const LARGE_MARKDOWN_THRESHOLD = 250000 export const LARGE_MARKDOWN_NOTICE = '此文档内容过长,将采用精简模式显示' export function isLargeMarkdownContent(content = '') { return content.length > LARGE_MARKDOWN_THRESHOLD } export function MarkdownSizeNotice({ className = '' }) { return (
) } function splitMarkdownIntoBlocks(content) { if (!content) return [] const blocks = [] const lines = content.split('\n') let current = [] let inFence = false const flush = () => { if (current.length > 0) { blocks.push(current.join('\n')) current = [] } } for (const line of lines) { const isFenceLine = /^\s*(```|~~~)/.test(line) const isHeading = /^(#{1,6})\s+/.test(line) if (!inFence && isHeading) { flush() } current.push(line) if (isFenceLine) { inFence = !inFence } if (!inFence && line.trim() === '') { flush() } } flush() return blocks } const LargeMarkdownViewer = forwardRef(function LargeMarkdownViewer({ content, components, onClick }, ref) { const virtuosoRef = useRef(null) const markdownBlocks = useMemo(() => splitMarkdownIntoBlocks(content), [content]) useImperativeHandle(ref, () => ({ scrollToTop: () => { virtuosoRef.current?.scrollToIndex({ index: 0, align: 'start', behavior: 'smooth', }) }, }), []) return (
(
{block}
)} />
) }) export default LargeMarkdownViewer