diff --git a/src/renderer/src/components/CodeBlockView/SvgPreview.tsx b/src/renderer/src/components/CodeBlockView/SvgPreview.tsx index b68c73f486..9180aef297 100644 --- a/src/renderer/src/components/CodeBlockView/SvgPreview.tsx +++ b/src/renderer/src/components/CodeBlockView/SvgPreview.tsx @@ -1,28 +1,53 @@ import { CodeTool, usePreviewToolHandlers, usePreviewTools } from '@renderer/components/CodeToolbar' -import { memo, useCallback, useEffect, useRef } from 'react' -import styled from 'styled-components' +import { memo, useEffect, useRef } from 'react' interface Props { children: string setTools?: (value: React.SetStateAction) => void } +/** + * 使用 Shadow DOM 渲染 SVG + */ const SvgPreview: React.FC = ({ children, setTools }) => { const svgContainerRef = useRef(null) - const sanitizeSvg = useCallback((svgContent: string): string => { - return svgContent.replace(/]*>[\s\S]*?<\/style>/gi, '') - }, []) - useEffect(() => { - if (svgContainerRef.current) { - svgContainerRef.current.innerHTML = sanitizeSvg(children) - } - }, [children, sanitizeSvg]) + const container = svgContainerRef.current + if (!container) return + + const shadowRoot = container.shadowRoot || container.attachShadow({ mode: 'open' }) + + // 添加基础样式 + const style = document.createElement('style') + style.textContent = ` + :host { + padding: 1em; + background-color: white; + overflow: auto; + border: 0.5px solid var(--color-code-background); + border-top-left-radius: 0; + border-top-right-radius: 0; + display: block; + } + svg { + max-width: 100%; + height: auto; + } + ` + + // 清空并重新添加内容 + shadowRoot.innerHTML = '' + shadowRoot.appendChild(style) + + const svgContainer = document.createElement('div') + svgContainer.innerHTML = children + shadowRoot.appendChild(svgContainer) + }, [children]) // 使用通用图像工具 const { handleCopyImage, handleDownload } = usePreviewToolHandlers(svgContainerRef, { - imgSelector: '.svg-preview svg', + imgSelector: 'svg', prefix: 'svg-image' }) @@ -33,16 +58,7 @@ const SvgPreview: React.FC = ({ children, setTools }) => { handleDownload }) - return + return
} -const SvgPreviewContainer = styled.div` - padding: 1em; - background-color: white; - overflow: auto; - border: 0.5px solid var(--color-code-background); - border-top-left-radius: 0; - border-top-right-radius: 0; -` - export default memo(SvgPreview) diff --git a/src/renderer/src/components/CodeToolbar/usePreviewTools.tsx b/src/renderer/src/components/CodeToolbar/usePreviewTools.tsx index f5ce914e44..c9fb904fc7 100644 --- a/src/renderer/src/components/CodeToolbar/usePreviewTools.tsx +++ b/src/renderer/src/components/CodeToolbar/usePreviewTools.tsx @@ -32,6 +32,14 @@ export const usePreviewToolHandlers = ( // 创建选择器函数 const getImgElement = useCallback(() => { if (!containerRef.current) return null + + // 优先尝试从 Shadow DOM 中查找 + const shadowRoot = containerRef.current.shadowRoot + if (shadowRoot) { + return shadowRoot.querySelector(imgSelector) as SVGElement | null + } + + // 降级到常规 DOM 查找 return containerRef.current.querySelector(imgSelector) as SVGElement | null }, [containerRef, imgSelector])