diff --git a/src/Mermaid/Mermaid.tsx b/src/Mermaid/Mermaid.tsx index 66bc59539..8389b4802 100644 --- a/src/Mermaid/Mermaid.tsx +++ b/src/Mermaid/Mermaid.tsx @@ -25,6 +25,7 @@ const Mermaid = memo( shadow, enablePanZoom = true, defaultExpand = true, + enableNonPreviewWheelZoom = true, className, bodyRender, fileName, @@ -78,7 +79,12 @@ const Mermaid = memo( : originalActions; const defaultBody = ( - + {tirmedChildren} ); diff --git a/src/Mermaid/SyntaxMermaid/index.tsx b/src/Mermaid/SyntaxMermaid/index.tsx index c77b5d18c..0eb321722 100644 --- a/src/Mermaid/SyntaxMermaid/index.tsx +++ b/src/Mermaid/SyntaxMermaid/index.tsx @@ -2,7 +2,8 @@ import { useTheme } from 'antd-style'; import { kebabCase } from 'lodash-es'; -import { memo, useEffect, useId, useMemo, useState } from 'react'; +import { memo, useEffect, useId, useMemo, useRef, useState } from 'react'; +import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch'; import Image from '@/Image'; import { useMermaid } from '@/hooks/useMermaid'; @@ -11,7 +12,7 @@ import { mermaidThemes } from '../const'; import type { SyntaxMermaidProps } from '../type'; const SyntaxMermaid = memo( - ({ ref, children, theme: customTheme, variant, enablePanZoom }) => { + ({ ref, children, theme: customTheme, variant, enablePanZoom, enableNonPreviewWheelZoom }) => { const isDefaultTheme = customTheme === 'lobe-theme' || !customTheme; const background = useMemo(() => { @@ -27,6 +28,9 @@ const SyntaxMermaid = memo( theme: isDefaultTheme ? undefined : customTheme, }); const [blobUrl, setBlobUrl] = useState(); + const [isDragging, setIsDragging] = useState(false); + const [shouldPreventPreview, setShouldPreventPreview] = useState(false); + const containerRef = useRef(null); // 组件卸载时清理 Blob URL,避免内存泄漏 useEffect(() => { @@ -44,36 +48,92 @@ const SyntaxMermaid = memo( setBlobUrl(url); }, [isLoading, data]); + const handlePanningStart = () => { + setIsDragging(true); + setShouldPreventPreview(false); + }; + + const handlePanning = () => { + if (isDragging) { + setShouldPreventPreview(true); + } + }; + + const handlePanningStop = () => { + setIsDragging(false); + setTimeout(() => { + setShouldPreventPreview(false); + }, 100); + }; + if (!blobUrl) return null; return ( - {'mermaid'} + > + + + {'mermaid'} + + + ); }, ); diff --git a/src/Mermaid/demos/FullFeatured.tsx b/src/Mermaid/demos/FullFeatured.tsx index 31ba443e5..c3959bb2b 100644 --- a/src/Mermaid/demos/FullFeatured.tsx +++ b/src/Mermaid/demos/FullFeatured.tsx @@ -12,6 +12,7 @@ export default () => { value: code, }, copyable: true, + enableNonPreviewWheelZoom: true, enablePanZoom: true, shadow: false, showLanguage: true, diff --git a/src/Mermaid/demos/index.tsx b/src/Mermaid/demos/index.tsx index 4dc2e8fff..fb8808b9d 100644 --- a/src/Mermaid/demos/index.tsx +++ b/src/Mermaid/demos/index.tsx @@ -12,6 +12,7 @@ export default () => { value: code, }, copyable: true, + enableNonPreviewWheelZoom: true, enablePanZoom: false, shadow: false, showLanguage: true, diff --git a/src/Mermaid/index.md b/src/Mermaid/index.md index e1227d861..bd461c3d3 100644 --- a/src/Mermaid/index.md +++ b/src/Mermaid/index.md @@ -388,18 +388,19 @@ export default () => { ## APIs -| Property | Description | Type | Default | -| -------------- | -------------------------------------------------------- | ---------------------------------------- | ----------- | -| children | Mermaid diagram content as a string | `string` | - | -| fullFeatured | Whether to use the full-featured mode with more controls | `boolean` | - | -| variant | Style variant of the container | `'filled' \| 'outlined' \| 'borderless'` | `'filled'` | -| shadow | Whether to show shadow effect | `boolean` | - | -| enablePanZoom | Enable pan and zoom functionality | `boolean` | `true` | -| copyable | Whether to show copy button | `boolean` | `true` | -| showLanguage | Whether to show language label | `boolean` | `true` | -| language | The language label to display | `string` | `'mermaid'` | -| theme | Theme for the diagram | `'lobe-theme' \| MermaidConfig['theme']` | - | -| defaultExpand | Whether to expand by default (for fullFeatured mode) | `boolean` | `true` | -| actionIconSize | Size of action icons | `ActionIconProps['size']` | - | -| actionsRender | Custom renderer for action buttons | `(props) => ReactNode` | - | -| bodyRender | Custom renderer for diagram body | `(props) => ReactNode` | - | +| Property | Description | Type | Default | +| ------------------------- | -------------------------------------------------------- | ---------------------------------------- | ----------- | +| children | Mermaid diagram content as a string | `string` | - | +| fullFeatured | Whether to use the full-featured mode with more controls | `boolean` | - | +| variant | Style variant of the container | `'filled' \| 'outlined' \| 'borderless'` | `'filled'` | +| shadow | Whether to show shadow effect | `boolean` | - | +| enablePanZoom | Enable pan and zoom functionality | `boolean` | `true` | +| copyable | Whether to show copy button | `boolean` | `true` | +| showLanguage | Whether to show language label | `boolean` | `true` | +| language | The language label to display | `string` | `'mermaid'` | +| theme | Theme for the diagram | `'lobe-theme' \| MermaidConfig['theme']` | - | +| defaultExpand | Whether to expand by default (for fullFeatured mode) | `boolean` | `true` | +| actionIconSize | Size of action icons | `ActionIconProps['size']` | - | +| actionsRender | Custom renderer for action buttons | `(props) => ReactNode` | - | +| bodyRender | Custom renderer for diagram body | `(props) => ReactNode` | - | +| enableNonPreviewWheelZoom | Enable zoom outof preview mode | `boolean` | `true` | diff --git a/src/Mermaid/type.ts b/src/Mermaid/type.ts index 8b21165af..2f54cb3db 100644 --- a/src/Mermaid/type.ts +++ b/src/Mermaid/type.ts @@ -6,6 +6,7 @@ import type { DivProps } from '@/types'; export interface SyntaxMermaidProps { children: string; + enableNonPreviewWheelZoom?: MermaidProps['enableNonPreviewWheelZoom']; enablePanZoom?: MermaidProps['enablePanZoom']; ref?: Ref; theme?: MermaidProps['theme']; @@ -23,6 +24,7 @@ export interface MermaidProps extends DivProps { children: string; copyable?: boolean; defaultExpand?: boolean; + enableNonPreviewWheelZoom?: boolean; enablePanZoom?: boolean; fileName?: string; fullFeatured?: boolean;