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..7798b465d 100644
--- a/packages/x-markdown/src/plugins/Mermaid/__test__/index.test.tsx
+++ b/packages/x-markdown/src/plugins/Mermaid/__test__/index.test.tsx
@@ -2,6 +2,13 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import Mermaid from '../index';
+const getActionButtonByLabel = (label: string): HTMLElement => {
+ const icon = screen.getByLabelText(label);
+ const button = icon.closest('.ant-actions-item');
+ if (!button) throw new Error(`Action button with label '${label}' not found.`);
+ return button as HTMLElement;
+};
+
// Mock mermaid
jest.mock('mermaid', () => ({
initialize: jest.fn(),
@@ -135,7 +142,7 @@ describe('Mermaid Plugin', () => {
render({mermaidContent});
- const copyButton = screen.getByRole('button', { name: 'copy' });
+ const copyButton = getActionButtonByLabel('copy');
fireEvent.click(copyButton);
await waitFor(() => {
@@ -154,7 +161,7 @@ describe('Mermaid Plugin', () => {
render({mermaidContent});
- const copyButton = screen.getByRole('button', { name: 'copy' });
+ const copyButton = getActionButtonByLabel('copy');
// 确保点击不会抛出错误
expect(() => fireEvent.click(copyButton)).not.toThrow();
@@ -177,7 +184,7 @@ describe('Mermaid Plugin', () => {
render({mermaidContent});
- const copyButton = screen.getByRole('button', { name: 'copy' });
+ const copyButton = getActionButtonByLabel('copy');
fireEvent.click(copyButton);
await waitFor(() => {
@@ -192,23 +199,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('undo')).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 = getActionButtonByLabel('zoom-in');
+ const zoomOutButton = getActionButtonByLabel('zoom-out');
fireEvent.click(zoomInButton);
fireEvent.click(zoomOutButton);
@@ -217,7 +224,7 @@ describe('Mermaid Plugin', () => {
it('should handle reset functionality', () => {
render({mermaidContent});
- const resetButton = screen.getByRole('button', { name: 'Reset' });
+ const resetButton = getActionButtonByLabel('undo');
fireEvent.click(resetButton);
});
});
@@ -500,7 +507,7 @@ describe('Mermaid Plugin', () => {
container.querySelector = mockQuerySelector;
}
- const downloadButton = screen.getByRole('button', { name: 'download' });
+ const downloadButton = getActionButtonByLabel('download');
fireEvent.click(downloadButton);
// Wait for async operations
@@ -542,7 +549,7 @@ describe('Mermaid Plugin', () => {
container.querySelector = mockQuerySelector;
}
- const downloadButton = screen.getByRole('button', { name: 'download' });
+ const downloadButton = getActionButtonByLabel('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 bb1639b9d..99f98d00d 100644
--- a/packages/x-markdown/src/plugins/Mermaid/index.tsx
+++ b/packages/x-markdown/src/plugins/Mermaid/index.tsx
@@ -1,9 +1,17 @@
-import { CopyOutlined, DownloadOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons';
+import {
+ CopyOutlined,
+ DownloadOutlined,
+ UndoOutlined,
+ 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 type { ItemType } from '@ant-design/x/es/actions/interface';
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 { message, Segmented } from 'antd';
import classnames from 'classnames';
import throttle from 'lodash.throttle';
import mermaid from 'mermaid';
@@ -222,6 +230,46 @@ const Mermaid: React.FC = React.memo((props) => {
}
};
+ // ============================ Action Items ============================
+ const baseItems: ItemType[] = [
+ {
+ key: 'copy',
+ icon: ,
+ label: contextLocale.copy,
+ onItemClick: handleCopyCode,
+ },
+ ];
+
+ const imageItems: ItemType[] = [
+ ...baseItems,
+ {
+ key: 'zoomIn',
+ icon: ,
+ label: contextLocale.zoomIn,
+ onItemClick: handleZoomIn,
+ },
+ {
+ key: 'zoomOut',
+ icon: ,
+ label: contextLocale.zoomOut,
+ onItemClick: handleZoomOut,
+ },
+ {
+ key: 'zoomReset',
+ icon: ,
+ label: contextLocale.zoomReset,
+ onItemClick: handleReset,
+ },
+ {
+ key: 'download',
+ icon: ,
+ label: contextLocale.download,
+ onItemClick: handleDownload,
+ },
+ ];
+
+ const actionItems = renderType === RenderType.Image ? imageItems : baseItems;
+
const renderHeader = () => {
if (header === null) return null;
if (header) return header;
@@ -244,39 +292,7 @@ const Mermaid: React.FC = React.memo((props) => {
value={renderType}
onChange={setRenderType}
/>
-
-
- } onClick={handleCopyCode} />
-
- {renderType === RenderType.Image ? (
- <>
-
- } onClick={handleZoomIn} />
-
-
- }
- onClick={handleZoomOut}
- />
-
-
-
-
-
- }
- onClick={handleDownload}
- />
-
- >
- ) : null}
-
+
);
};
diff --git a/packages/x/components/locale/zh_CN.ts b/packages/x/components/locale/zh_CN.ts
index 725d54f0d..1f9b5820a 100644
--- a/packages/x/components/locale/zh_CN.ts
+++ b/packages/x/components/locale/zh_CN.ts
@@ -24,8 +24,8 @@ const localeValues: Required = {
Mermaid: {
copySuccess: '复制成功',
copy: '复制代码',
- zoomIn: '缩小',
- zoomOut: '放大',
+ zoomIn: '放大',
+ zoomOut: '缩小',
zoomReset: '重置',
download: '下载',
code: '代码',