From 826bcd32a165bb5c4718c4236fc89fe8cfd38858 Mon Sep 17 00:00:00 2001 From: "yangxiaoshan.yxs" Date: Tue, 11 Nov 2025 09:13:34 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor(x-markdown):=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20Actions=20=E7=BB=84=E4=BB=B6=E6=9B=BF=E6=8D=A2=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 HighlightCode 和 Mermaid 插件中用 Actions.Copy 替换复制按钮 - 在 Mermaid 插件中用 Actions 组件重构缩放和下载操作 --- .../src/plugins/HighlightCode/index.tsx | 8 +-- .../x-markdown/src/plugins/Mermaid/index.tsx | 66 +++++++++++-------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/packages/x-markdown/src/plugins/HighlightCode/index.tsx b/packages/x-markdown/src/plugins/HighlightCode/index.tsx index 9fabe4428..c99c18d61 100644 --- a/packages/x-markdown/src/plugins/HighlightCode/index.tsx +++ b/packages/x-markdown/src/plugins/HighlightCode/index.tsx @@ -1,9 +1,9 @@ -import { CopyOutlined } from '@ant-design/icons'; import useXComponentConfig from '@ant-design/x/es/_util/hooks/use-x-component-config'; +import Actions from '@ant-design/x/es/actions'; import useLocale from '@ant-design/x/es/locale/useLocale'; import useXProviderContext from '@ant-design/x/es/x-provider/hooks/use-x-provider-context'; import locale_EN from '@ant-design/x/locale/en_US'; -import { Button, message, Tooltip } from 'antd'; +import { message } from 'antd'; import classnames from 'classnames'; import React from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; @@ -99,9 +99,7 @@ const HighlightCode: React.FC = (props) => { > {lang} - - - - - + + ); + }, + }, + { + label: contextLocale.download, + key: 'download', + icon: , + onItemClick: handleDownload, + }, + ]} + /> ) : null} From b468c22c1cde65a9f7954a621c9dc6da970727eb Mon Sep 17 00:00:00 2001 From: "yangxiaoshan.yxs" Date: Tue, 11 Nov 2025 10:49:15 +0800 Subject: [PATCH 2/3] =?UTF-8?q?refactor(x-markdown):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=86=97=E4=BD=99=E7=9A=84=E5=A4=8D=E5=88=B6=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用 `Actions.Copy` 组件直接处理复制功能 - 移除 `message` 和 `useLocale` 相关代码 --- .../src/plugins/HighlightCode/index.tsx | 26 +------------------ .../x-markdown/src/plugins/Mermaid/index.tsx | 20 ++------------ 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/packages/x-markdown/src/plugins/HighlightCode/index.tsx b/packages/x-markdown/src/plugins/HighlightCode/index.tsx index c99c18d61..47bf123bd 100644 --- a/packages/x-markdown/src/plugins/HighlightCode/index.tsx +++ b/packages/x-markdown/src/plugins/HighlightCode/index.tsx @@ -1,9 +1,6 @@ import useXComponentConfig from '@ant-design/x/es/_util/hooks/use-x-component-config'; import Actions from '@ant-design/x/es/actions'; -import useLocale from '@ant-design/x/es/locale/useLocale'; import useXProviderContext from '@ant-design/x/es/x-provider/hooks/use-x-provider-context'; -import locale_EN from '@ant-design/x/locale/en_US'; -import { message } from 'antd'; import classnames from 'classnames'; import React from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; @@ -32,9 +29,6 @@ const HighlightCode: React.FC = (props) => { highlightProps, } = props; - // ============================ locale ============================ - const [contextLocale] = useLocale('HighlightCode', locale_EN.HighlightCode); - // ============================ Prefix ============================ const { getPrefixCls, direction } = useXProviderContext(); const prefixCls = getPrefixCls('highlightCode', customizePrefixCls); @@ -57,23 +51,6 @@ const HighlightCode: React.FC = (props) => { }, ); - // ============================ locale ============================ - const [messageApi, contextHolder] = message.useMessage(); - - const handleCopyCode = async () => { - if (!children) return; - - try { - await navigator.clipboard.writeText(children.trim()); - messageApi.open({ - type: 'success', - content: contextLocale.copySuccess, - }); - } catch (error) { - console.error('Failed to copy code:', error); - } - }; - const renderTitle = () => { if (header === null) return null; @@ -88,7 +65,6 @@ const HighlightCode: React.FC = (props) => { )} style={{ ...contextConfig.styles.header, ...styles.header }} > - {contextHolder} = (props) => { > {lang} - + ); }; diff --git a/packages/x-markdown/src/plugins/Mermaid/index.tsx b/packages/x-markdown/src/plugins/Mermaid/index.tsx index f11dea883..e77fb725d 100644 --- a/packages/x-markdown/src/plugins/Mermaid/index.tsx +++ b/packages/x-markdown/src/plugins/Mermaid/index.tsx @@ -4,7 +4,7 @@ import Actions from '@ant-design/x/es/actions'; import useLocale from '@ant-design/x/es/locale/useLocale'; import useXProviderContext from '@ant-design/x/es/x-provider/hooks/use-x-provider-context'; import locale_EN from '@ant-design/x/locale/en_US'; -import { Button, message, Segmented, Space, Tooltip } from 'antd'; +import { Button, Segmented, Space, Tooltip } from 'antd'; import classnames from 'classnames'; import throttle from 'lodash.throttle'; import mermaid from 'mermaid'; @@ -45,7 +45,6 @@ const Mermaid: React.FC = React.memo((props) => { const [lastMousePos, setLastMousePos] = useState({ x: 0, y: 0 }); const containerRef = useRef(null); const id = `mermaid-${uuid++}-${children?.length || 0}`; - const [messageApi, contextHolder] = message.useMessage(); // ============================ locale ============================ const [contextLocale] = useLocale('Mermaid', locale_EN.Mermaid); @@ -209,20 +208,6 @@ const Mermaid: React.FC = React.memo((props) => { setScale((prev) => Math.max(prev - 0.2, 0.5)); }; - const handleCopyCode = async () => { - if (!children) return; - - try { - await navigator.clipboard.writeText(children.trim()); - messageApi.open({ - type: 'success', - content: contextLocale.copySuccess, - }); - } catch (error) { - console.error('Failed to copy code:', error); - } - }; - const renderHeader = () => { if (header === null) return null; if (header) return header; @@ -236,7 +221,6 @@ const Mermaid: React.FC = React.memo((props) => { )} style={{ ...contextConfig.styles.header, ...styles.header }} > - {contextHolder} = React.memo((props) => { onChange={setRenderType} /> - + {renderType === RenderType.Image ? ( <> Date: Fri, 21 Nov 2025 09:54:35 +0800 Subject: [PATCH 3/3] =?UTF-8?q?test(mermaid):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E5=92=8C=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将按钮名称从小写改为首字母大写 - 使用 label 替代 role 进行元素查找 - 简化重置按钮的实现方式 --- .../plugins/Mermaid/__test__/index.test.tsx | 33 +++++++++---------- .../x-markdown/src/plugins/Mermaid/index.tsx | 20 +++++------ 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/packages/x-markdown/src/plugins/Mermaid/__test__/index.test.tsx b/packages/x-markdown/src/plugins/Mermaid/__test__/index.test.tsx index ef8d09195..58bc7a432 100644 --- a/packages/x-markdown/src/plugins/Mermaid/__test__/index.test.tsx +++ b/packages/x-markdown/src/plugins/Mermaid/__test__/index.test.tsx @@ -135,7 +135,7 @@ describe('Mermaid Plugin', () => { render({mermaidContent}); - const copyButton = screen.getByRole('button', { name: 'copy' }); + const copyButton = screen.getByRole('button', { name: 'Copy' }); fireEvent.click(copyButton); await waitFor(() => { @@ -154,7 +154,7 @@ describe('Mermaid Plugin', () => { render({mermaidContent}); - const copyButton = screen.getByRole('button', { name: 'copy' }); + const copyButton = screen.getByRole('button', { name: 'Copy' }); // 确保点击不会抛出错误 expect(() => fireEvent.click(copyButton)).not.toThrow(); @@ -177,12 +177,11 @@ describe('Mermaid Plugin', () => { render({mermaidContent}); - const copyButton = screen.getByRole('button', { name: 'copy' }); + const copyButton = screen.getByRole('button', { name: 'Copy' }); fireEvent.click(copyButton); - await waitFor(() => { - expect(consoleSpy).toHaveBeenCalledWith('Failed to copy code:', expect.any(Error)); - }); + // 由于Actions.Copy组件有自己的错误处理,我们只需要确保点击不会抛出错误 + expect(() => fireEvent.click(copyButton)).not.toThrow(); consoleSpy.mockRestore(); }); @@ -192,23 +191,23 @@ describe('Mermaid Plugin', () => { it('should show zoom controls only in image mode', () => { render({mermaidContent}); - expect(screen.getByRole('button', { name: 'zoom-in' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: 'zoom-out' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: 'Reset' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: 'download' })).toBeInTheDocument(); + expect(screen.getByLabelText('zoom-in')).toBeInTheDocument(); + expect(screen.getByLabelText('zoom-out')).toBeInTheDocument(); + expect(screen.getByLabelText('one-to-one')).toBeInTheDocument(); + expect(screen.getByLabelText('download')).toBeInTheDocument(); const codeButton = screen.getByText('Code'); fireEvent.click(codeButton); - expect(screen.queryByRole('button', { name: 'zoom-in' })).not.toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'zoom-out' })).not.toBeInTheDocument(); + expect(screen.queryByLabelText('zoom-in')).not.toBeInTheDocument(); + expect(screen.queryByLabelText('zoom-out')).not.toBeInTheDocument(); }); it('should handle zoom in/out', () => { render({mermaidContent}); - const zoomInButton = screen.getByRole('button', { name: 'zoom-in' }); - const zoomOutButton = screen.getByRole('button', { name: 'zoom-out' }); + const zoomInButton = screen.getByLabelText('zoom-in'); + const zoomOutButton = screen.getByLabelText('zoom-out'); fireEvent.click(zoomInButton); fireEvent.click(zoomOutButton); @@ -217,7 +216,7 @@ describe('Mermaid Plugin', () => { it('should handle reset functionality', () => { render({mermaidContent}); - const resetButton = screen.getByRole('button', { name: 'Reset' }); + const resetButton = screen.getByLabelText('one-to-one'); fireEvent.click(resetButton); }); }); @@ -500,7 +499,7 @@ describe('Mermaid Plugin', () => { container.querySelector = mockQuerySelector; } - const downloadButton = screen.getByRole('button', { name: 'download' }); + const downloadButton = screen.getByLabelText('download'); fireEvent.click(downloadButton); // Wait for async operations @@ -542,7 +541,7 @@ describe('Mermaid Plugin', () => { container.querySelector = mockQuerySelector; } - const downloadButton = screen.getByRole('button', { name: 'download' }); + const downloadButton = screen.getByLabelText('download'); fireEvent.click(downloadButton); // Should not throw and should return early diff --git a/packages/x-markdown/src/plugins/Mermaid/index.tsx b/packages/x-markdown/src/plugins/Mermaid/index.tsx index e77fb725d..f2eed349d 100644 --- a/packages/x-markdown/src/plugins/Mermaid/index.tsx +++ b/packages/x-markdown/src/plugins/Mermaid/index.tsx @@ -1,10 +1,15 @@ -import { DownloadOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; +import { + DownloadOutlined, + OneToOneOutlined, + ZoomInOutlined, + ZoomOutOutlined, +} from '@ant-design/icons'; import useXComponentConfig from '@ant-design/x/es/_util/hooks/use-x-component-config'; import Actions from '@ant-design/x/es/actions'; import useLocale from '@ant-design/x/es/locale/useLocale'; import useXProviderContext from '@ant-design/x/es/x-provider/hooks/use-x-provider-context'; import locale_EN from '@ant-design/x/locale/en_US'; -import { Button, Segmented, Space, Tooltip } from 'antd'; +import { Segmented, Space } from 'antd'; import classnames from 'classnames'; import throttle from 'lodash.throttle'; import mermaid from 'mermaid'; @@ -250,15 +255,8 @@ const Mermaid: React.FC = React.memo((props) => { { label: contextLocale.zoomReset, key: 'zoomReset', - actionRender: (item) => { - return ( - - - - ); - }, + icon: , + onItemClick: handleReset, }, { label: contextLocale.download,