// 代码预览组件 import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { memo, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { useI18n } from '../i18n/index'; interface CodeViewProps { code: string; editable?: boolean; onChange?: (value: string) => void; disabled?: boolean; showTitle?: boolean; toolbarPosition?: 'top' | 'bottom'; codeFontSizePx?: number; /** 是否在滚动内容底部显示毛玻璃渐隐遮罩(默认 false,不影响其他使用方) */ fadeBottom?: boolean; /** * 外部动作宿主:提供时编辑/复制按钮 portal 到该容器,本组件不再渲染工具栏行。 * undefined = 未提供(默认内部渲染);null = 宿主尚未挂载(暂不渲染)。 */ actionsContainer?: HTMLElement | null; } export const CodeView = memo(function CodeView({ code, editable = false, onChange, disabled = false, showTitle = true, toolbarPosition = 'top', codeFontSizePx = 12, fadeBottom = false, actionsContainer }: CodeViewProps) { const { t } = useI18n(); const [copied, setCopied] = useState(false); const [isEditing, setIsEditing] = useState(false); const [isDark, setIsDark] = useState( typeof document !== 'undefined' && document.documentElement.classList.contains('dark') ); useEffect(() => { if (typeof document === 'undefined') { return; } const updateThemeState = () => { setIsDark(document.documentElement.classList.contains('dark')); }; updateThemeState(); const observer = new MutationObserver(updateThemeState); observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); return () => observer.disconnect(); }, []); const handleCopy = async () => { await navigator.clipboard.writeText(code); setCopied(true); setTimeout(() => setCopied(false), 2000); }; const textareaClassName = [ 'w-full h-full resize-none bg-transparent p-4 leading-relaxed overflow-auto', 'font-mono text-text-primary/90 focus:outline-none', disabled ? 'opacity-60 cursor-not-allowed' : '' ] .filter(Boolean) .join(' '); const hasExternalActions = actionsContainer !== undefined; const actionButtons = (
{editable && ( )}
); return (
{/* 工具栏:可置于代码区域上方或下方;提供外部宿主时整行不渲染 */} {!hasExternalActions && (
{showTitle ? (

{t('codeView.title')}

) : null} {actionButtons}
)} {hasExternalActions && actionsContainer ? createPortal(actionButtons, actionsContainer) : null} {/* 代码区域 */}
{editable && isEditing ? (