(
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*uYT7SZwhJnUAAAAAAAAAAAAADgCCAQ"
/>
),
- toolbarRender: (_, { icons: { closeIcon } }) => (
-
- ),
}}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
diff --git a/components/image/demo/toolbarRender.md b/components/image/demo/toolbarRender.md
index 5794885071..5b570567fc 100644
--- a/components/image/demo/toolbarRender.md
+++ b/components/image/demo/toolbarRender.md
@@ -1,7 +1,35 @@
## zh-CN
-可以自定义工具栏。
+可以自定义工具栏并添加下载图片按钮。
## en-US
-You can customize the toolbar.
+You can customize the toolbar and add a button for downloading the image.
+
+```css
+.toolbar-wrapper {
+ position: fixed;
+ bottom: 32px;
+ left: 50%;
+ padding: 0px 24px;
+ color: #fff;
+ font-size: 20px;
+ background-color: rgba(0, 0, 0, 0.1);
+ border-radius: 100px;
+ transform: translateX(-50%);
+}
+
+.toolbar-wrapper .anticon {
+ padding: 12px;
+ cursor: pointer;
+}
+
+.toolbar-wrapper .anticon[disabled] {
+ cursor: not-allowed;
+ opacity: 0.3;
+}
+
+.toolbar-wrapper .anticon:hover {
+ opacity: 0.3;
+}
+```
diff --git a/components/image/demo/toolbarRender.tsx b/components/image/demo/toolbarRender.tsx
index 92e968a6d4..5701b35841 100644
--- a/components/image/demo/toolbarRender.tsx
+++ b/components/image/demo/toolbarRender.tsx
@@ -1,5 +1,12 @@
-import { DownloadOutlined } from '@ant-design/icons';
-import { Image } from 'antd';
+import {
+ DownloadOutlined,
+ RotateLeftOutlined,
+ RotateRightOutlined,
+ SwapOutlined,
+ ZoomInOutlined,
+ ZoomOutOutlined,
+} from '@ant-design/icons';
+import { Image, Space } from 'antd';
import React from 'react';
const src = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';
@@ -12,7 +19,7 @@ const App: React.FC = () => {
const url = URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
- link.download = 'image.jpg';
+ link.download = 'image.png';
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(url);
@@ -23,36 +30,26 @@ const App: React.FC = () => {
return (
(
-
- -
-
-
- {flipYIcon}
- {flipXIcon}
- {rotateLeftIcon}
- {rotateRightIcon}
- {zoomOutIcon}
- {zoomInIcon}
- {closeIcon}
-
+
+
+
+
+
+
+
+
+
),
}}
- src={src}
/>
);
};
diff --git a/components/image/index.en-US.md b/components/image/index.en-US.md
index 34b9d89221..4d0c412a41 100644
--- a/components/image/index.en-US.md
+++ b/components/image/index.en-US.md
@@ -40,7 +40,7 @@ Previewable image.
| fallback | Load failure fault-tolerant src | string | - | 4.6.0 |
| height | Image height | string \| number | - | 4.6.0 |
| placeholder | Load placeholder, use default placeholder when set `true` | ReactNode | - | 4.6.0 |
-| preview | preview config, disabled when `false` | boolean \| [PreviewType](#PreviewType) | true | 4.6.0 [PreviewType](#PreviewType):4.7.0 |
+| preview | preview config, disabled when `false` | boolean \| [PreviewType](#previewtype) | true | 4.6.0 [PreviewType](#previewtype):4.7.0 |
| src | Image path | string | - | 4.6.0 |
| width | Image width | string \| number | - | 4.6.0 |
| onError | Load failed callback | (event: Event) => void | - | 4.12.0 |
@@ -61,18 +61,20 @@ Other attributes [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/El
| scaleStep | `1 + scaleStep` is the step to increase or decrease the scale | number | 0.5 | - |
| minScale | Min scale | number | 1 | 5.7.0 |
| maxScale | Max scale | number | 50 | 5.7.0 |
+| closeIcon | Custom close icon | React.ReactNode | - | 5.7.0 |
| forceRender | Force render preview dialog | boolean | - | - |
-| toolbarRender | Custom toolbar render | (originalNode: React.ReactNode, info: Omit<[ToolbarRenderInfoType](#ToolbarRenderInfoType), 'current' \| 'total'>) => React.ReactNode | - | 5.7.0 |
-| imageRender | Custom preview content | (originalNode: React.ReactNode, info: { transform: [TransformType](#TransformType) }) => React.ReactNode | - | 5.7.0 |
-| onTransform | Callback when the transform of image changed | { transform: [TransformType](#TransformType), action: [TransformAction](#TransformAction) } | - | 5.7.0 |
+| toolbarRender | Custom toolbar render | (originalNode: React.ReactNode, info: Omit<[ToolbarRenderInfoType](#toolbarrenderinfotype), 'current' \| 'total'>) => React.ReactNode | - | 5.7.0 |
+| imageRender | Custom preview content | (originalNode: React.ReactNode, info: { transform: [TransformType](#transformtype) }) => React.ReactNode | - | 5.7.0 |
+| onTransform | Callback when the transform of image changed | { transform: [TransformType](#transformtype), action: [TransformAction](#transformaction) } | - | 5.7.0 |
| onVisibleChange | Callback when `visible` changed | (visible: boolean, prevVisible: boolean) => void | - | - |
## PreviewGroup
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
-| preview | Preview config, `disabled` when false | boolean \| [PreviewGroupType](#PreviewGroupType) | true | 4.6.0 [PreviewGroupType](#PreviewGroupType):4.7.0 |
+| preview | Preview config, `disabled` when false | boolean \| [PreviewGroupType](#previewgrouptype) | true | 4.6.0 [PreviewGroupType](#previewgrouptype):4.7.0 |
| items | Preview items | string[] \| { src: string, crossOrigin: string, ... }[] | - | 5.7.0 |
+| fallback | Load failure fault-tolerant src | string | - | 5.7.0 |
### PreviewGroupType
@@ -87,11 +89,12 @@ Other attributes [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/El
| scaleStep | `1 + scaleStep` is the step to increase or decrease the scale | number | 0.5 | - |
| minScale | Min scale | number | 1 | 5.7.0 |
| maxScale | Max scale | number | 50 | 5.7.0 |
+| closeIcon | Custom close icon | React.ReactNode | - | 5.7.0 |
| forceRender | Force render preview dialog | boolean | - | - |
-| countRender | Custom preview count content | (current: number, total: number) => string | - | 4.20.0 |
-| toolbarRender | Custom toolbar render | (originalNode: React.ReactNode, info: [ToolbarRenderInfoType](#ToolbarRenderInfoType)) => React.ReactNode | - | 5.7.0 |
-| imageRender | Custom preview content | (originalNode: React.ReactNode, info: { transform: [TransformType](#TransformType), current: number }) => React.ReactNode | - | 5.7.0 |
-| onTransform | Callback when the transform of image changed | { transform: [TransformType](#TransformType), action: [TransformAction](#TransformAction) } | - | 5.7.0 |
+| countRender | Custom preview count content | (current: number, total: number) => React.ReactNode | - | 4.20.0 |
+| toolbarRender | Custom toolbar render | (originalNode: React.ReactNode, info: [ToolbarRenderInfoType](#toolbarrenderinfotype)) => React.ReactNode | - | 5.7.0 |
+| imageRender | Custom preview content | (originalNode: React.ReactNode, info: { transform: [TransformType](#transformtype), current: number }) => React.ReactNode | - | 5.7.0 |
+| onTransform | Callback when the transform of image changed | { transform: [TransformType](#transformtype), action: [TransformAction](#transformaction) } | - | 5.7.0 |
| onChange | Callback when switch preview image | (current: number, prevCurrent: number) => void | - | 5.3.0 |
| onVisibleChange | Callback when `visible` changed | (visible: boolean, prevVisible: boolean, current: number) => void | - | current 参数 5.3.0 |
@@ -140,7 +143,6 @@ type TransformAction =
rotateRightIcon: React.ReactNode;
zoomOutIcon: React.ReactNode;
zoomInIcon: React.ReactNode;
- closeIcon: React.ReactNode;
};
actions: {
onFlipY: () => void;
@@ -149,7 +151,6 @@ type TransformAction =
onRotateRight: () => void;
onZoomOut: () => void;
onZoomIn: () => void;
- onClose: () => void;
};
transform: TransformType,
current: number;
diff --git a/components/image/index.zh-CN.md b/components/image/index.zh-CN.md
index 84236c5bfe..dd4111d240 100644
--- a/components/image/index.zh-CN.md
+++ b/components/image/index.zh-CN.md
@@ -41,7 +41,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*LVQ3R5JjjJEAAA
| fallback | 加载失败容错地址 | string | - | 4.6.0 |
| height | 图像高度 | string \| number | - | 4.6.0 |
| placeholder | 加载占位, 为 `true` 时使用默认占位 | ReactNode | - | 4.6.0 |
-| preview | 预览参数,为 `false` 时禁用 | boolean \| [PreviewType](#PreviewType) | true | 4.6.0 [PreviewType](#PreviewType):4.7.0 |
+| preview | 预览参数,为 `false` 时禁用 | boolean \| [PreviewType](#previewtype) | true | 4.6.0 [PreviewType](#previewyype):4.7.0 |
| src | 图片地址 | string | - | 4.6.0 |
| width | 图像宽度 | string \| number | - | 4.6.0 |
| onError | 加载错误回调 | (event: Event) => void | - | 4.12.0 |
@@ -62,18 +62,20 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*LVQ3R5JjjJEAAA
| scaleStep | `1 + scaleStep` 为缩放放大的每步倍数 | number | 0.5 | - |
| minScale | 最小缩放倍数 | number | 1 | 5.7.0 |
| maxScale | 最大放大倍数 | number | 50 | 5.7.0 |
+| closeIcon | 自定义关闭 Icon | React.ReactNode | - | 5.7.0 |
| forceRender | 强制渲染预览图 | boolean | - | - |
-| toolbarRender | 自定义工具栏 | (originalNode: React.ReactNode, info: Omit<[ToolbarRenderInfoType](#ToolbarRenderInfoType), 'current' \| 'total'>) => React.ReactNode | - | 5.7.0 |
-| imageRender | 自定义预览内容 | (originalNode: React.ReactNode, info: { transform: [TransformType](#TransformType) }) => React.ReactNode | - | 5.7.0 |
-| onTransform | 预览图 transform 变化的回调 | { transform: [TransformType](#TransformType), action: [TransformAction](#TransformAction) } | - | 5.7.0 |
+| toolbarRender | 自定义工具栏 | (originalNode: React.ReactNode, info: Omit<[ToolbarRenderInfoType](#toolbarrenderinfotype), 'current' \| 'total'>) => React.ReactNode | - | 5.7.0 |
+| imageRender | 自定义预览内容 | (originalNode: React.ReactNode, info: { transform: [TransformType](#transformtype) }) => React.ReactNode | - | 5.7.0 |
+| onTransform | 预览图 transform 变化的回调 | { transform: [TransformType](#transformtype), action: [TransformAction](#transformaction) } | - | 5.7.0 |
| onVisibleChange | 当 `visible` 发生改变时的回调 | (visible: boolean, prevVisible: boolean) => void | - | - |
## PreviewGroup
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
-| preview | 预览参数,为 `false` 时禁用 | boolean \| [PreviewGroupType](#PreviewGroupType) | true | 4.6.0 [PreviewGroupType](#PreviewGroupType):4.7.0 |
+| preview | 预览参数,为 `false` 时禁用 | boolean \| [PreviewGroupType](#previewgrouptype) | true | 4.6.0 [PreviewGroupType](#previewgrouptype):4.7.0 |
| items | 预览数组 | string[] \| { src: string, crossOrigin: string, ... }[] | - | 5.7.0 |
+| fallback | 加载失败容错地址 | string | - | 5.7.0 |
### PreviewGroupType
@@ -88,11 +90,12 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*LVQ3R5JjjJEAAA
| scaleStep | `1 + scaleStep` 为缩放放大的每步倍数 | number | 0.5 | - |
| minScale | 最小缩放倍数 | number | 1 | 5.7.0 |
| maxScale | 最大放大倍数 | number | 50 | 5.7.0 |
+| closeIcon | 自定义关闭 Icon | React.ReactNode | - | 5.7.0 |
| forceRender | 强制渲染预览图 | boolean | - | - |
-| countRender | 自定义预览计数内容 | (current: number, total: number) => string | - | 4.20.0 |
-| toolbarRender | 自定义工具栏 | (originalNode: React.ReactNode, info: [ToolbarRenderInfoType](#ToolbarRenderInfoType)) => React.ReactNode | - | 5.7.0 |
-| imageRender | 自定义预览内容 | (originalNode: React.ReactNode, info: { transform: [TransformType](#TransformType), current: number }) => React.ReactNode | - | 5.7.0 |
-| onTransform | 预览图 transform 变化的回调 | { transform: [TransformType](#TransformType), action: [TransformAction](#TransformAction) } | - | 5.7.0 |
+| countRender | 自定义预览计数内容 | (current: number, total: number) => React.ReactNode | - | 4.20.0 |
+| toolbarRender | 自定义工具栏 | (originalNode: React.ReactNode, info: [ToolbarRenderInfoType](#toolbarrenderinfotype)) => React.ReactNode | - | 5.7.0 |
+| imageRender | 自定义预览内容 | (originalNode: React.ReactNode, info: { transform: [TransformType](#transformtype), current: number }) => React.ReactNode | - | 5.7.0 |
+| onTransform | 预览图 transform 变化的回调 | { transform: [TransformType](#transformtype), action: [TransformAction](#transformaction) } | - | 5.7.0 |
| onChange | 切换预览图的回调 | (current: number, prevCurrent: number) => void | - | 5.3.0 |
| onVisibleChange | 当 `visible` 发生改变时的回调 | (visible: boolean, prevVisible: boolean, current: number) => void | - | current 参数 5.3.0 |
@@ -141,7 +144,6 @@ type TransformAction =
rotateRightIcon: React.ReactNode;
zoomOutIcon: React.ReactNode;
zoomInIcon: React.ReactNode;
- closeIcon: React.ReactNode;
};
actions: {
onFlipY: () => void;
@@ -150,7 +152,6 @@ type TransformAction =
onRotateRight: () => void;
onZoomOut: () => void;
onZoomIn: () => void;
- onClose: () => void;
};
transform: TransformType,
current: number;
diff --git a/components/image/style/index.ts b/components/image/style/index.ts
index 932a9a6585..16d3e9b6cb 100644
--- a/components/image/style/index.ts
+++ b/components/image/style/index.ts
@@ -1,7 +1,7 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import { genModalMaskStyle } from '../../modal/style';
-import { resetComponent, textEllipsis } from '../../style';
+import { textEllipsis } from '../../style';
import { initFadeMotion, initZoomMotion } from '../../style/motion';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
@@ -43,14 +43,15 @@ export const genBoxStyle = (position?: PositionType): CSSObject => ({
});
export const genImageMaskStyle = (token: ImageToken): CSSObject => {
- const { iconCls, motionDurationSlow, paddingXXS, marginXXS, prefixCls } = token;
+ const { iconCls, motionDurationSlow, paddingXXS, marginXXS, prefixCls, colorTextLightSolid } =
+ token;
return {
position: 'absolute',
inset: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
- color: '#fff',
+ color: colorTextLightSolid,
background: new TinyColor('#000').setAlpha(0.5).toRgbString(),
cursor: 'pointer',
opacity: 0,
@@ -70,22 +71,70 @@ export const genImageMaskStyle = (token: ImageToken): CSSObject => {
};
export const genPreviewOperationsStyle = (token: ImageToken): CSSObject => {
- const { previewCls, modalMaskBg, paddingSM, previewOperationColorDisabled, motionDurationSlow } =
- token;
+ const {
+ previewCls,
+ modalMaskBg,
+ paddingSM,
+ marginXL,
+ margin,
+ paddingLG,
+ previewOperationColorDisabled,
+ motionDurationSlow,
+ iconCls,
+ colorTextLightSolid,
+ } = token;
const operationBg = new TinyColor(modalMaskBg).setAlpha(0.1);
const operationBgHover = operationBg.clone().setAlpha(0.2);
return {
- [`${previewCls}-operations`]: {
- ...resetComponent(token),
+ [`${previewCls}-footer`]: {
+ position: 'fixed',
+ bottom: marginXL,
+ left: {
+ _skip_check_: true,
+ value: 0,
+ },
+ width: '100%',
display: 'flex',
- justifyContent: 'flex-end',
+ flexDirection: 'column',
alignItems: 'center',
color: token.previewOperationColor,
- listStyle: 'none',
- background: operationBg.toRgbString(),
- pointerEvents: 'auto',
+ },
+ [`${previewCls}-progress`]: {
+ marginBottom: margin,
+ },
+ [`${previewCls}-close`]: {
+ position: 'fixed',
+ top: marginXL,
+ right: {
+ _skip_check_: true,
+ value: marginXL,
+ },
+ display: 'flex',
+ color: colorTextLightSolid,
+ backgroundColor: operationBg.toRgbString(),
+ borderRadius: '50%',
+ padding: paddingSM,
+ outline: 0,
+ border: 0,
+ cursor: 'pointer',
+ transition: `all ${motionDurationSlow}`,
+
+ '&:hover': {
+ backgroundColor: operationBgHover.toRgbString(),
+ },
+
+ [`& > ${iconCls}`]: {
+ fontSize: token.previewOperationSize,
+ },
+ },
+ [`${previewCls}-operations`]: {
+ display: 'flex',
+ alignItems: 'center',
+ padding: `0 ${paddingLG}px`,
+ backgroundColor: operationBg.toRgbString(),
+ borderRadius: 100,
'&-operation': {
marginInlineStart: paddingSM,
@@ -94,28 +143,22 @@ export const genPreviewOperationsStyle = (token: ImageToken): CSSObject => {
transition: `all ${motionDurationSlow}`,
userSelect: 'none',
- '&:hover': {
- background: operationBgHover.toRgbString(),
+ [`&:not(${previewCls}-operations-operation-disabled):hover > ${iconCls}`]: {
+ opacity: 0.3,
},
'&-disabled': {
color: previewOperationColorDisabled,
- pointerEvents: 'none',
+ cursor: 'not-allowed',
},
'&:first-of-type': {
marginInlineStart: 0,
},
- },
- '&-progress': {
- position: 'absolute',
- left: { _skip_check_: true, value: '50%' },
- transform: 'translateX(-50%)',
- },
-
- '&-icon': {
- fontSize: token.previewOperationSize,
+ [`& > ${iconCls}`]: {
+ fontSize: token.previewOperationSize,
+ },
},
},
};
@@ -151,7 +194,6 @@ export const genPreviewSwitchStyle = (token: ImageToken): CSSObject => {
transform: `translateY(-50%)`,
cursor: 'pointer',
transition: `all ${motionDurationSlow}`,
- pointerEvents: 'auto',
userSelect: 'none',
'&:hover': {
@@ -202,7 +244,7 @@ export const genImagePreviewStyle: GenerateStyle = (token: ImageToke
[`${previewCls}-img`]: {
maxWidth: '100%',
- maxHeight: '100%',
+ maxHeight: '70%',
verticalAlign: 'middle',
transform: 'scale3d(1, 1, 1)',
cursor: 'grab',
@@ -258,10 +300,7 @@ export const genImagePreviewStyle: GenerateStyle = (token: ImageToke
{
[`${componentCls}-preview-operations-wrapper`]: {
position: 'fixed',
- insetBlockStart: 0,
- insetInlineEnd: 0,
zIndex: token.zIndexPopup + 1,
- width: '100%',
},
'&': [genPreviewOperationsStyle(token), genPreviewSwitchStyle(token)],
},
diff --git a/package.json b/package.json
index a9f51dd7cb..8bcd89af9b 100644
--- a/package.json
+++ b/package.json
@@ -129,7 +129,7 @@
"rc-drawer": "~6.2.0",
"rc-dropdown": "~4.1.0",
"rc-field-form": "~1.34.0",
- "rc-image": "~6.1.0",
+ "rc-image": "~7.0.0-2",
"rc-input": "~1.1.0",
"rc-input-number": "~8.0.0",
"rc-mentions": "~2.5.0",