feat(upload): showUploadList options showPreviewIcon, showDownloadIcon and showRemoveIcon support function (#50245)

This commit is contained in:
Guo Yunhe 2024-08-07 11:42:33 +08:00 committed by GitHub
parent 96722dbcd5
commit 3f4eb4b9d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 267 additions and 15 deletions

View File

@ -391,7 +391,7 @@ const InternalUpload: React.ForwardRefRenderFunction<UploadRef, UploadProps> = (
// use showRemoveIcon if it is specified explicitly
const realShowRemoveIcon =
typeof showRemoveIcon === 'undefined' ? !mergedDisabled : !!showRemoveIcon;
typeof showRemoveIcon === 'undefined' ? !mergedDisabled : showRemoveIcon;
const renderUploadList = (button?: React.ReactNode, buttonVisible?: boolean) => {
if (!showUploadList) {

View File

@ -25,9 +25,9 @@ export interface ListItemProps {
items: UploadFile[];
listType?: UploadListType;
isImgUrl?: (file: UploadFile) => boolean;
showRemoveIcon?: boolean;
showDownloadIcon?: boolean;
showPreviewIcon?: boolean;
showRemoveIcon?: boolean | ((file: UploadFile) => boolean);
showDownloadIcon?: boolean | ((file: UploadFile) => boolean);
showPreviewIcon?: boolean | ((file: UploadFile) => boolean);
removeIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
downloadIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
previewIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
@ -138,7 +138,11 @@ const ListItem = React.forwardRef<HTMLDivElement, ListItemProps>(
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
const removeIcon = showRemoveIcon
const removeIcon = (
typeof showRemoveIcon === 'function'
? showRemoveIcon(file)
: showRemoveIcon
)
? actionIconRender(
(typeof customRemoveIcon === 'function' ? customRemoveIcon(file) : customRemoveIcon) || (
<DeleteOutlined />
@ -153,7 +157,8 @@ const ListItem = React.forwardRef<HTMLDivElement, ListItemProps>(
: null;
const downloadIcon =
showDownloadIcon && mergedStatus === 'done'
(typeof showDownloadIcon === 'function' ? showDownloadIcon(file) : showDownloadIcon) &&
mergedStatus === 'done'
? actionIconRender(
(typeof customDownloadIcon === 'function'
? customDownloadIcon(file)
@ -208,7 +213,8 @@ const ListItem = React.forwardRef<HTMLDivElement, ListItemProps>(
);
const previewIcon =
showPreviewIcon && (file.url || file.thumbUrl) ? (
(typeof showPreviewIcon === 'function' ? showPreviewIcon(file) : showPreviewIcon) &&
(file.url || file.thumbUrl) ? (
<a
href={file.url || file.thumbUrl}
target="_blank"

View File

@ -1370,3 +1370,202 @@ exports[`Upload List should support showRemoveIcon and showPreviewIcon 1`] = `
</div>
</span>
`;
exports[`Upload List should support showXxxIcon functions 1`] = `
<span
class="ant-upload-wrapper"
>
<div
class="ant-upload ant-upload-select"
>
<span
class="ant-upload"
>
<input
accept=""
style="display: none;"
type="file"
/>
<button
type="button"
>
upload
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
>
<div
class="ant-upload-list-item-container"
>
<div
class="ant-upload-list-item ant-upload-list-item-uploading"
>
<div
class="ant-upload-icon"
>
<span
aria-label="loading"
class="anticon anticon-loading anticon-spin"
role="img"
>
<svg
aria-hidden="true"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</span>
</div>
<a
class="ant-upload-list-item-name"
href="https://cdn.xxx.com/aaa"
rel="noopener noreferrer"
target="_blank"
title="image"
>
image
</a>
<span
class="ant-upload-list-item-actions"
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-action"
title="Remove file"
type="button"
>
<span
class="ant-btn-icon"
>
<i>
RM
</i>
</span>
</button>
</span>
</div>
</div>
<div
class="ant-upload-list-item-container"
>
<div
class="ant-upload-list-item ant-upload-list-item-done"
>
<div
class="ant-upload-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<a
class="ant-upload-list-item-name"
href="https://cdn.xxx.com/aaa"
rel="noopener noreferrer"
target="_blank"
title="image"
>
image
</a>
<span
class="ant-upload-list-item-actions"
/>
</div>
</div>
<div
class="ant-upload-list-item-container"
>
<div
class="ant-upload-list-item ant-upload-list-item-done"
>
<div
class="ant-upload-icon"
>
<span
aria-label="paper-clip"
class="anticon anticon-paper-clip"
role="img"
>
<svg
aria-hidden="true"
data-icon="paper-clip"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M779.3 196.6c-94.2-94.2-247.6-94.2-341.7 0l-261 260.8c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l261-260.8c32.4-32.4 75.5-50.2 121.3-50.2s88.9 17.8 121.2 50.2c32.4 32.4 50.2 75.5 50.2 121.2 0 45.8-17.8 88.8-50.2 121.2l-266 265.9-43.1 43.1c-40.3 40.3-105.8 40.3-146.1 0-19.5-19.5-30.2-45.4-30.2-73s10.7-53.5 30.2-73l263.9-263.8c6.7-6.6 15.5-10.3 24.9-10.3h.1c9.4 0 18.1 3.7 24.7 10.3 6.7 6.7 10.3 15.5 10.3 24.9 0 9.3-3.7 18.1-10.3 24.7L372.4 653c-1.7 1.7-2.6 4-2.6 6.4s.9 4.7 2.6 6.4l36.9 36.9a9 9 0 0012.7 0l215.6-215.6c19.9-19.9 30.8-46.3 30.8-74.4s-11-54.6-30.8-74.4c-41.1-41.1-107.9-41-149 0L463 364 224.8 602.1A172.22 172.22 0 00174 724.8c0 46.3 18.1 89.8 50.8 122.5 33.9 33.8 78.3 50.7 122.7 50.7 44.4 0 88.8-16.9 122.6-50.7l309.2-309C824.8 492.7 850 432 850 367.5c.1-64.6-25.1-125.3-70.7-170.9z"
/>
</svg>
</span>
</div>
<a
class="ant-upload-list-item-name"
href="https://cdn.xxx.com/aaa"
rel="noopener noreferrer"
target="_blank"
title="image"
>
image
</a>
<span
class="ant-upload-list-item-actions"
>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-action"
title="Download file"
type="button"
>
<span
class="ant-btn-icon"
>
<i>
DL
</i>
</span>
</button>
<button
class="ant-btn ant-btn-text ant-btn-sm ant-btn-icon-only ant-upload-list-item-action"
title="Remove file"
type="button"
>
<span
class="ant-btn-icon"
>
<i>
RM
</i>
</span>
</button>
</span>
</div>
</div>
</div>
</span>
`;

View File

@ -685,6 +685,53 @@ describe('Upload List', () => {
unmount();
});
it('should support showXxxIcon functions', () => {
const list = [
{
name: 'image',
status: 'uploading',
uid: '-4',
url: 'https://cdn.xxx.com/aaa',
response: {
protected: true,
},
},
{
name: 'image',
status: 'done',
uid: '-5',
url: 'https://cdn.xxx.com/aaa',
},
{
name: 'image',
status: 'done',
uid: '-5',
url: 'https://cdn.xxx.com/aaa',
response: {
protected: true,
},
},
];
const { container: wrapper, unmount } = render(
<Upload
defaultFileList={list as UploadProps['defaultFileList']}
showUploadList={{
showRemoveIcon: (file) => file.response?.protected,
showDownloadIcon: (file) => file.response?.protected,
showPreviewIcon: (file) => file.response?.protected,
removeIcon: <i>RM</i>,
downloadIcon: <i>DL</i>,
previewIcon: <i>PV</i>,
}}
>
<button type="button">upload</button>
</Upload>,
);
expect(wrapper.firstChild).toMatchSnapshot();
unmount();
});
it('should support removeIcon and downloadIcon', () => {
const list = [
{

View File

@ -70,7 +70,7 @@ Common props ref[Common props](/docs/react/common-props)
| openFileDialogOnClick | Click open file dialog | boolean | true | |
| previewFile | Customize preview file logic | (file: File \| Blob) => Promise&lt;dataURL: string> | - | |
| progress | Custom progress bar | [ProgressProps](/components/progress/#api) (support `type="line"` only) | { strokeWidth: 2, showInfo: false } | 4.3.0 |
| showUploadList | Whether to show default upload list, could be an object to specify `extra`(5.20.0+), `showPreviewIcon`, `showRemoveIcon`, `showDownloadIcon`, `removeIcon` and `downloadIcon` individually | boolean \| { extra?: ReactNode \| (file: UploadFile) => ReactNode, showPreviewIcon?: boolean, showDownloadIcon?: boolean, showRemoveIcon?: boolean, previewIcon?: ReactNode \| (file: UploadFile) => ReactNode, removeIcon?: ReactNode \| (file: UploadFile) => ReactNode, downloadIcon?: ReactNode \| (file: UploadFile) => ReactNode } | true | `extra`: 5.20.0 |
| showUploadList | Whether to show default upload list, could be an object to specify `extra`, `showPreviewIcon`, `showRemoveIcon`, `showDownloadIcon`, `removeIcon` and `downloadIcon` individually | boolean \| { extra?: ReactNode \| (file: UploadFile) => ReactNode, showPreviewIcon?: boolean \| (file: UploadFile) => boolean, showDownloadIcon?: boolean \| (file: UploadFile) => boolean, showRemoveIcon?: boolean \| (file: UploadFile) => boolean, previewIcon?: ReactNode \| (file: UploadFile) => ReactNode, removeIcon?: ReactNode \| (file: UploadFile) => ReactNode, downloadIcon?: ReactNode \| (file: UploadFile) => ReactNode } | true | `extra`: 5.20.0, `showPreviewIcon` function: 5.21.0, `showRemoveIcon` function: 5.21.0, `showDownloadIcon` function: 5.21.0 |
| withCredentials | The ajax upload with cookie sent | boolean | false | |
| onChange | A callback function, can be executed when uploading state is changing. It will trigger by every uploading phase. see [onChange](#onchange) | function | - | |
| onDrop | A callback function executed when files are dragged and dropped into the upload area | (event: React.DragEvent) => void | - | 4.16.0 |

View File

@ -71,7 +71,7 @@ demo:
| openFileDialogOnClick | 点击打开文件对话框 | boolean | true | |
| previewFile | 自定义文件预览逻辑 | (file: File \| Blob) => Promise&lt;dataURL: string> | - | |
| progress | 自定义进度条样式 | [ProgressProps](/components/progress-cn#api)(仅支持 `type="line"` | { strokeWidth: 2, showInfo: false } | 4.3.0 |
| showUploadList | 是否展示文件列表, 可设为一个对象,用于单独设定 `extra`(5.20.0+), `showPreviewIcon`, `showRemoveIcon`, `showDownloadIcon`, `removeIcon``downloadIcon` | boolean \| { extra?: ReactNode \| (file: UploadFile) => ReactNode, showPreviewIcon?: boolean, showRemoveIcon?: boolean, showDownloadIcon?: boolean, previewIcon?: ReactNode \| (file: UploadFile) => ReactNode, removeIcon?: ReactNode \| (file: UploadFile) => ReactNode, downloadIcon?: ReactNode \| (file: UploadFile) => ReactNode } | true | `extra`: 5.20.0 |
| showUploadList | 是否展示文件列表, 可设为一个对象,用于单独设定 `extra`(5.20.0+), `showPreviewIcon`, `showRemoveIcon`, `showDownloadIcon`, `removeIcon``downloadIcon` | boolean \| { extra?: ReactNode \| (file: UploadFile) => ReactNode, showPreviewIcon?: boolean \| (file: UploadFile) => boolean, showDownloadIcon?: boolean \| (file: UploadFile) => boolean, showRemoveIcon?: boolean \| (file: UploadFile) => boolean, previewIcon?: ReactNode \| (file: UploadFile) => ReactNode, removeIcon?: ReactNode \| (file: UploadFile) => ReactNode, downloadIcon?: ReactNode \| (file: UploadFile) => ReactNode } | true | `extra`: 5.20.0, `showPreviewIcon` function: 5.21.0, `showRemoveIcon` function: 5.21.0, `showDownloadIcon` function: 5.21.0 |
| withCredentials | 上传请求时是否携带 cookie | boolean | false | |
| onChange | 上传文件改变时的回调,上传每个阶段都会触发该事件。详见 [onChange](#onchange) | function | - | |
| onDrop | 当文件被拖入上传区域时执行的回调功能 | (event: React.DragEvent) => void | - | 4.16.0 |

View File

@ -51,9 +51,9 @@ export interface UploadChangeParam<T = UploadFile> {
export interface ShowUploadListInterface<T = any> {
extra?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);
showRemoveIcon?: boolean;
showPreviewIcon?: boolean;
showDownloadIcon?: boolean;
showRemoveIcon?: boolean | ((file: UploadFile<T>) => boolean);
showPreviewIcon?: boolean | ((file: UploadFile<T>) => boolean);
showDownloadIcon?: boolean | ((file: UploadFile<T>) => boolean);
removeIcon?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);
downloadIcon?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);
previewIcon?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);
@ -150,9 +150,9 @@ export interface UploadListProps<T = any> {
progress?: UploadListProgressProps;
prefixCls?: string;
className?: string;
showRemoveIcon?: boolean;
showDownloadIcon?: boolean;
showPreviewIcon?: boolean;
showRemoveIcon?: boolean | ((file: UploadFile<T>) => boolean);
showDownloadIcon?: boolean | ((file: UploadFile<T>) => boolean);
showPreviewIcon?: boolean | ((file: UploadFile<T>) => boolean);
removeIcon?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);
downloadIcon?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);
previewIcon?: React.ReactNode | ((file: UploadFile<T>) => React.ReactNode);