Refactor upload (#5290)

* refactor: vc-upload

* refactor: vc-upload

* refactor: upload

* refactor: upload

* refactor: upload
This commit is contained in:
tangjinzhou 2022-02-24 09:58:58 +08:00 committed by GitHub
parent 3cf5d4fa43
commit 04baae5a57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 2899 additions and 1725 deletions

View File

@ -224,7 +224,7 @@ export {
TypographyTitle,
} from './typography';
export type { UploadProps, UploadListProps, UploadChangeParam } from './upload';
export type { UploadProps, UploadListProps, UploadChangeParam, UploadFile } from './upload';
export { default as Upload, UploadDragger } from './upload';

View File

@ -1535,8 +1535,10 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = `
</label></div>
<div class="ant-col ant-col-14 ant-form-item-control">
<div class="ant-form-item-control-input">
<div class="ant-form-item-control-input-content"><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span role="button" tabindex="0" class="ant-upload"><input id="validate_other_upload" type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture"></div></span>
<div class="ant-form-item-control-input-content"><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input id="validate_other_upload" type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<!---->
</div></span>
</div>
<!---->
</div>
@ -1550,17 +1552,18 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = `
</label></div>
<div class="ant-col ant-col-14 ant-form-item-control">
<div class="ant-form-item-control-input">
<div class="ant-form-item-control-input-content"><span><div class="ant-upload ant-upload-drag"><span role="button" tabindex="0" class="ant-upload ant-upload-btn"><input id="validate_other_dragger" type="file" style="display: none;" accept=""><div class="ant-upload-drag-container"><p class="ant-upload-drag-icon"><span role="img" aria-label="inbox" class="anticon anticon-inbox"><svg focusable="false" class="" data-icon="inbox" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"><path d="M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0060.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z"></path></svg></span></p>
<div class="ant-form-item-control-input-content"><span><div class="ant-upload ant-upload-drag"><span tabindex="0" class="ant-upload ant-upload-btn" role="button"><input id="validate_other_dragger" type="file" style="display: none;" accept="" capture="false"><p class="ant-upload-drag-icon"><span role="img" aria-label="inbox" class="anticon anticon-inbox"><svg focusable="false" class="" data-icon="inbox" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"><path d="M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0060.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z"></path></svg></span></p>
<p class="ant-upload-text">Click or drag file to this area to upload</p>
<p class="ant-upload-hint">Support for a single or bulk upload.</p>
<p class="ant-upload-hint">Support for a single or bulk upload.</p></span>
</div>
<div class="ant-upload-list ant-upload-list-text">
<!---->
</div></span>
</div>
<div class="ant-upload-list ant-upload-list-text"></div></span>
<!---->
</div>
<!---->
</div>
<!---->
<!---->
<!---->
</div>
</div>
<div class="ant-row ant-form-item">

View File

@ -9,6 +9,7 @@ import type { TransferLocale } from '../transfer';
import type { PickerLocale as DatePickerLocale } from '../date-picker/generatePicker';
import type { PaginationLocale } from '../pagination/Pagination';
import type { TableLocale } from '../table/interface';
import type { UploadLocale } from '../upload/interface';
interface TransferLocaleForEmpty {
description: string;
@ -18,7 +19,6 @@ export interface Locale {
Pagination?: PaginationLocale;
Table?: TableLocale;
Popconfirm?: Record<string, any>;
Upload?: Record<string, any>;
Form?: {
optional?: string;
defaultValidateMessages: ValidateMessages;
@ -32,6 +32,7 @@ export interface Locale {
Modal?: ModalLocale;
Transfer?: Partial<TransferLocale>;
Select?: Record<string, any>;
Upload?: UploadLocale;
Empty?: TransferLocaleForEmpty;
global?: Record<string, any>;
PageHeader?: { back: string };

View File

@ -61,8 +61,10 @@ exports[`renders ./components/space/demo/base.vue correctly 1`] = `
<!----><span>Button</span>
</button></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text"></div></span>
<div class="ant-space-item" style="margin-right: 8px;"><span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<!---->
</div></span>
</div>
<!---->
<div class="ant-space-item">

View File

@ -965,6 +965,10 @@
@typography-title-margin-top: 1.2em;
@typography-title-margin-bottom: 0.5em;
// Upload
// ---
@upload-actions-color: @text-color-secondary;
// Image
// ---
@image-size-base: 48px;

View File

@ -1,22 +1,22 @@
import { defineComponent } from 'vue';
import { getOptionProps, getSlot } from '../_util/props-util';
import Upload from './Upload';
import { uploadProps } from './interface';
export default defineComponent({
name: 'AUploadDragger',
inheritAttrs: false,
props: uploadProps,
render() {
const props = getOptionProps(this);
const { height, ...restProps } = props;
const { style, ...restAttrs } = this.$attrs;
const draggerProps = {
...restProps,
...restAttrs,
type: 'drag',
style: { ...(style as any), height },
} as any;
return <Upload {...draggerProps}>{getSlot(this)}</Upload>;
props: uploadProps(),
setup(props, { slots, attrs }) {
return () => {
const { height, ...restProps } = props;
const { style, ...restAttrs } = attrs;
const draggerProps = {
...restProps,
...restAttrs,
type: 'drag',
style: { ...(style as any), height: typeof height === 'number' ? `${height}px` : height },
} as any;
return <Upload {...draggerProps} v-slots={slots}></Upload>;
};
},
});

View File

@ -1,86 +1,196 @@
import classNames from '../_util/classNames';
import uniqBy from 'lodash-es/uniqBy';
import findIndex from 'lodash-es/findIndex';
import type { UploadProps as RcUploadProps } from '../vc-upload';
import VcUpload from '../vc-upload';
import BaseMixin from '../_util/BaseMixin';
import { getOptionProps, hasProp, getSlot } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { defaultConfigProvider } from '../config-provider';
import Dragger from './Dragger';
import UploadList from './UploadList';
import type { UploadFile } from './interface';
import type {
UploadType,
UploadListType,
UploadFile,
UploadChangeParam,
ShowUploadListInterface,
FileType,
} from './interface';
import { uploadProps } from './interface';
import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from './utils';
import { defineComponent, inject } from 'vue';
import { getDataAndAriaProps } from '../_util/util';
import { useInjectFormItemContext } from '../form/FormItemContext';
import { file2Obj, getFileItem, removeFileItem, updateFileList } from './utils';
import { useLocaleReceiver } from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale/default';
import { computed, defineComponent, onMounted, ref, toRef } from 'vue';
import { flattenChildren, initDefaultProps } from '../_util/props-util';
import useMergedState from '../_util/hooks/useMergedState';
import devWarning from '../vc-util/devWarning';
import useConfigInject from '../_util/hooks/useConfigInject';
import type { VueNode } from '../_util/type';
import classNames from '../_util/classNames';
import { useInjectFormItemContext } from '../form';
export const LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`;
export default defineComponent({
name: 'AUpload',
mixins: [BaseMixin],
inheritAttrs: false,
Dragger,
props: initDefaultProps(uploadProps, {
type: 'select',
props: initDefaultProps(uploadProps(), {
type: 'select' as UploadType,
multiple: false,
action: '',
data: {},
accept: '',
beforeUpload: T,
showUploadList: true,
listType: 'text', // or pictrue
listType: 'text' as UploadListType, // or picture
disabled: false,
supportServerRender: true,
}),
setup() {
setup(props, { slots, attrs, expose }) {
const formItemContext = useInjectFormItemContext();
return {
upload: null,
progressTimer: null,
configProvider: inject('configProvider', defaultConfigProvider),
formItemContext,
};
},
// recentUploadStatus: boolean | PromiseLike<any>;
data() {
return {
sFileList: this.fileList || this.defaultFileList || [],
dragState: 'drop',
};
},
watch: {
fileList(val) {
this.sFileList = val || [];
},
},
beforeUnmount() {
this.clearProgressTimer();
},
methods: {
onStart(file) {
const targetItem = fileToObject(file);
targetItem.status = 'uploading';
const nextFileList = this.sFileList.concat();
const fileIndex = findIndex(nextFileList, ({ uid }) => uid === targetItem.uid);
if (fileIndex === -1) {
nextFileList.push(targetItem);
} else {
nextFileList[fileIndex] = targetItem;
}
this.handleChange({
file: targetItem,
fileList: nextFileList,
});
// fix ie progress
if (!window.File || (typeof process === 'object' && process.env.TEST_IE)) {
this.autoUpdateProgress(0, targetItem);
}
},
const [mergedFileList, setMergedFileList] = useMergedState(props.defaultFileList || [], {
value: toRef(props, 'fileList'),
postState: list => {
const timestamp = Date.now();
return (list ?? []).map((file, index) => {
if (!file.uid && !Object.isFrozen(file)) {
file.uid = `__AUTO__${timestamp}_${index}__`;
}
return file;
});
},
});
const dragState = ref('drop');
onSuccess(response, file, xhr) {
this.clearProgressTimer();
const upload = ref();
onMounted(() => {
devWarning(
props.fileList !== undefined || attrs.value === undefined,
'Upload',
'`value` is not a valid prop, do you mean `fileList`?',
);
devWarning(
props.transformFile === undefined,
'Upload',
'`transformFile` is deprecated. Please use `beforeUpload` directly.',
);
devWarning(
props.remove === undefined,
'Upload',
'`remove` props is deprecated. Please use `remove` event.',
);
});
const onInternalChange = (
file: UploadFile,
changedFileList: UploadFile[],
event?: { percent: number },
) => {
let cloneList = [...changedFileList];
// Cut to match count
if (props.maxCount === 1) {
cloneList = cloneList.slice(-1);
} else if (props.maxCount) {
cloneList = cloneList.slice(0, props.maxCount);
}
setMergedFileList(cloneList);
const changeInfo: UploadChangeParam<UploadFile> = {
file: file as UploadFile,
fileList: cloneList,
};
if (event) {
changeInfo.event = event;
}
props['onUpdate:fileList']?.(changeInfo.fileList);
props.onChange?.(changeInfo);
formItemContext.onFieldChange();
};
const mergedBeforeUpload = async (file: FileType, fileListArgs: FileType[]) => {
const { beforeUpload, transformFile } = props;
let parsedFile: FileType | Blob | string = file;
if (beforeUpload) {
const result = await beforeUpload(file, fileListArgs);
if (result === false) {
return false;
}
// Hack for LIST_IGNORE, we add additional info to remove from the list
delete (file as any)[LIST_IGNORE];
if ((result as any) === LIST_IGNORE) {
Object.defineProperty(file, LIST_IGNORE, {
value: true,
configurable: true,
});
return false;
}
if (typeof result === 'object' && result) {
parsedFile = result as File;
}
}
if (transformFile) {
parsedFile = await transformFile(parsedFile as any);
}
return parsedFile as File;
};
const onBatchStart: RcUploadProps['onBatchStart'] = batchFileInfoList => {
// Skip file which marked as `LIST_IGNORE`, these file will not add to file list
const filteredFileInfoList = batchFileInfoList.filter(
info => !(info.file as any)[LIST_IGNORE],
);
// Nothing to do since no file need upload
if (!filteredFileInfoList.length) {
return;
}
const objectFileList = filteredFileInfoList.map(info => file2Obj(info.file as FileType));
// Concat new files with prev files
let newFileList = [...mergedFileList.value];
objectFileList.forEach(fileObj => {
// Replace file if exist
newFileList = updateFileList(fileObj, newFileList);
});
objectFileList.forEach((fileObj, index) => {
// Repeat trigger `onChange` event for compatible
let triggerFileObj: UploadFile = fileObj;
if (!filteredFileInfoList[index].parsedFile) {
// `beforeUpload` return false
const { originFileObj } = fileObj;
let clone;
try {
clone = new File([originFileObj], originFileObj.name, {
type: originFileObj.type,
}) as any as UploadFile;
} catch (e) {
clone = new Blob([originFileObj], {
type: originFileObj.type,
}) as any as UploadFile;
clone.name = originFileObj.name;
clone.lastModifiedDate = new Date();
clone.lastModified = new Date().getTime();
}
clone.uid = fileObj.uid;
triggerFileObj = clone;
} else {
// Inject `uploading` status
fileObj.status = 'uploading';
}
onInternalChange(triggerFileObj, newFileList);
});
};
const onSuccess = (response: any, file: FileType, xhr: any) => {
try {
if (typeof response === 'string') {
response = JSON.parse(response);
@ -88,255 +198,233 @@ export default defineComponent({
} catch (e) {
/* do nothing */
}
const fileList = this.sFileList;
const targetItem = getFileItem(file, fileList);
// removed
if (!targetItem) {
if (!getFileItem(file, mergedFileList.value)) {
return;
}
const targetItem = file2Obj(file);
targetItem.status = 'done';
targetItem.percent = 100;
targetItem.response = response;
targetItem.xhr = xhr;
this.handleChange({
file: { ...targetItem },
fileList,
});
},
onProgress(e, file) {
const fileList = this.sFileList;
const targetItem = getFileItem(file, fileList);
const nextFileList = updateFileList(targetItem, mergedFileList.value);
onInternalChange(targetItem, nextFileList);
};
const onProgress = (e: { percent: number }, file: FileType) => {
// removed
if (!targetItem) {
if (!getFileItem(file, mergedFileList.value)) {
return;
}
const targetItem = file2Obj(file);
targetItem.status = 'uploading';
targetItem.percent = e.percent;
this.handleChange({
event: e,
file: { ...targetItem },
fileList: this.sFileList,
});
},
onError(error, response, file) {
this.clearProgressTimer();
const fileList = this.sFileList;
const targetItem = getFileItem(file, fileList);
const nextFileList = updateFileList(targetItem, mergedFileList.value);
onInternalChange(targetItem, nextFileList, e);
};
const onError = (error: Error, response: any, file: FileType) => {
// removed
if (!targetItem) {
if (!getFileItem(file, mergedFileList.value)) {
return;
}
const targetItem = file2Obj(file);
targetItem.error = error;
targetItem.response = response;
targetItem.status = 'error';
this.handleChange({
file: { ...targetItem },
fileList,
});
},
onReject(fileList) {
this.$emit('reject', fileList);
},
handleRemove(file) {
const { remove: onRemove } = this;
const { sFileList: fileList } = this.$data;
Promise.resolve(typeof onRemove === 'function' ? onRemove(file) : onRemove).then(ret => {
// Prevent removing file
if (ret === false) {
return;
}
const nextFileList = updateFileList(targetItem, mergedFileList.value);
const removedFileList = removeFileItem(file, fileList);
if (removedFileList) {
file.status = 'removed'; // eslint-disable-line
if (this.upload) {
this.upload.abort(file);
}
this.handleChange({
file,
fileList: removedFileList,
});
}
});
},
handleManualRemove(file) {
if (this.$refs.uploadRef) {
(this.$refs.uploadRef as any).abort(file);
}
this.handleRemove(file);
},
handleChange(info) {
if (!hasProp(this, 'fileList')) {
this.setState({ sFileList: info.fileList });
}
this.$emit('update:fileList', info.fileList);
this.$emit('change', info);
this.formItemContext.onFieldChange();
},
onFileDrop(e) {
this.setState({
dragState: e.type,
});
},
reBeforeUpload(file, fileList) {
const { beforeUpload } = this.$props;
const { sFileList: stateFileList } = this.$data;
if (!beforeUpload) {
return true;
}
const result = beforeUpload(file, fileList);
if (result === false) {
this.handleChange({
file,
fileList: uniqBy(
stateFileList.concat(fileList.map(fileToObject)),
(item: UploadFile) => item.uid,
),
});
return false;
}
if (result && result.then) {
return result;
}
return true;
},
clearProgressTimer() {
clearInterval(this.progressTimer);
},
autoUpdateProgress(_, file) {
const getPercent = genPercentAdd();
let curPercent = 0;
this.clearProgressTimer();
this.progressTimer = setInterval(() => {
curPercent = getPercent(curPercent);
this.onProgress(
{
percent: curPercent * 100,
},
file,
);
}, 200);
},
renderUploadList(locale) {
const {
showUploadList = {},
listType,
previewFile,
disabled,
locale: propLocale,
} = getOptionProps(this);
const { showRemoveIcon, showPreviewIcon, showDownloadIcon } = showUploadList;
const { sFileList: fileList } = this.$data;
const { onDownload, onPreview } = this.$props;
const uploadListProps = {
listType,
items: fileList,
previewFile,
showRemoveIcon: !disabled && showRemoveIcon,
showPreviewIcon,
showDownloadIcon,
locale: { ...locale, ...propLocale },
onRemove: this.handleManualRemove,
onDownload,
onPreview,
};
return <UploadList {...uploadListProps} />;
},
},
render() {
const {
prefixCls: customizePrefixCls,
showUploadList,
listType,
type,
disabled,
} = getOptionProps(this);
const { sFileList: fileList, dragState } = this.$data;
const { class: className, style } = this.$attrs;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const vcUploadProps = {
...this.$props,
id: this.$props.id ?? this.formItemContext.id.value,
prefixCls,
beforeUpload: this.reBeforeUpload,
onStart: this.onStart,
onError: this.onError,
onProgress: this.onProgress,
onSuccess: this.onSuccess,
onReject: this.onReject,
ref: 'uploadRef',
onInternalChange(targetItem, nextFileList);
};
const uploadList = showUploadList ? (
<LocaleReceiver
componentName="Upload"
defaultLocale={defaultLocale.Upload}
children={this.renderUploadList}
/>
) : null;
const handleRemove = (file: UploadFile) => {
let currentFile: UploadFile;
const mergedRemove = props.onRemove || props.remove;
Promise.resolve(typeof mergedRemove === 'function' ? mergedRemove(file) : mergedRemove).then(
ret => {
// Prevent removing file
if (ret === false) {
return;
}
const children = getSlot(this);
const removedFileList = removeFileItem(file, mergedFileList.value);
if (type === 'drag') {
const dragCls = classNames(prefixCls, {
[`${prefixCls}-drag`]: true,
[`${prefixCls}-drag-uploading`]: fileList.some((file: any) => file.status === 'uploading'),
[`${prefixCls}-drag-hover`]: dragState === 'dragover',
[`${prefixCls}-disabled`]: disabled,
});
return (
<span class={className} {...getDataAndAriaProps(this.$attrs)}>
<div
class={dragCls}
onDrop={this.onFileDrop}
onDragover={this.onFileDrop}
onDragleave={this.onFileDrop}
style={style}
>
<VcUpload {...vcUploadProps} class={`${prefixCls}-btn`}>
<div class={`${prefixCls}-drag-container`}>{children}</div>
</VcUpload>
</div>
{uploadList}
</span>
if (removedFileList) {
currentFile = { ...file, status: 'removed' };
mergedFileList.value?.forEach(item => {
const matchKey = currentFile.uid !== undefined ? 'uid' : 'name';
if (item[matchKey] === currentFile[matchKey] && !Object.isFrozen(item)) {
item.status = 'removed';
}
});
upload.value?.abort(currentFile);
onInternalChange(currentFile, removedFileList);
}
},
);
}
};
const uploadButtonCls = classNames(prefixCls, {
[`${prefixCls}-select`]: true,
[`${prefixCls}-select-${listType}`]: true,
[`${prefixCls}-disabled`]: disabled,
const onFileDrop = (e: DragEvent) => {
dragState.value = e.type;
if (e.type === 'drop') {
props.onDrop?.(e);
}
};
expose({
onBatchStart,
onSuccess,
onProgress,
onError,
fileList: mergedFileList,
upload,
});
// Remove id to avoid open by label when trigger is hidden
// https://github.com/ant-design/ant-design/issues/14298
if (!children.length || disabled) {
delete vcUploadProps.id;
}
const uploadButton = (
<div class={uploadButtonCls} style={children.length ? undefined : { display: 'none' }}>
<VcUpload {...vcUploadProps}>{children}</VcUpload>
</div>
const { prefixCls, direction } = useConfigInject('upload', props);
const [locale] = useLocaleReceiver(
'Upload',
defaultLocale.Upload,
computed(() => props.locale),
);
const renderUploadList = (button?: VueNode) => {
const {
removeIcon,
previewIcon,
downloadIcon,
previewFile,
onPreview,
onDownload,
disabled,
isImageUrl,
progress,
itemRender,
iconRender,
showUploadList,
} = props;
const { showDownloadIcon, showPreviewIcon, showRemoveIcon } =
typeof showUploadList === 'boolean' ? ({} as ShowUploadListInterface) : showUploadList;
return showUploadList ? (
<UploadList
listType={props.listType}
items={mergedFileList.value}
previewFile={previewFile}
onPreview={onPreview}
onDownload={onDownload}
onRemove={handleRemove}
showRemoveIcon={!disabled && showRemoveIcon}
showPreviewIcon={showPreviewIcon}
showDownloadIcon={showDownloadIcon}
removeIcon={removeIcon}
previewIcon={previewIcon}
downloadIcon={downloadIcon}
iconRender={iconRender}
locale={locale.value}
isImageUrl={isImageUrl}
progress={progress}
itemRender={itemRender}
v-slots={{ ...slots, appendAction: () => button }}
/>
) : (
button
);
};
return () => {
const { listType, disabled, type } = props;
const rcUploadProps = {
onBatchStart,
onError,
onProgress,
onSuccess,
...(props as RcUploadProps),
id: props.id ?? formItemContext.id.value,
prefixCls: prefixCls.value,
beforeUpload: mergedBeforeUpload,
onChange: undefined,
};
delete (rcUploadProps as any).remove;
if (listType === 'picture-card') {
// Remove id to avoid open by label when trigger is hidden
// !children: https://github.com/ant-design/ant-design/issues/14298
// disabled: https://github.com/ant-design/ant-design/issues/16478
// https://github.com/ant-design/ant-design/issues/24197
if (!slots.default || disabled) {
delete rcUploadProps.id;
}
if (type === 'drag') {
const dragCls = classNames(
prefixCls.value,
{
[`${prefixCls.value}-drag`]: true,
[`${prefixCls.value}-drag-uploading`]: mergedFileList.value.some(
file => file.status === 'uploading',
),
[`${prefixCls.value}-drag-hover`]: dragState.value === 'dragover',
[`${prefixCls.value}-disabled`]: disabled,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
},
attrs.class,
);
return (
<span>
<div
class={dragCls}
onDrop={onFileDrop}
onDragover={onFileDrop}
onDragleave={onFileDrop}
style={attrs.style}
>
<VcUpload
{...rcUploadProps}
ref={upload}
class={`${prefixCls.value}-btn`}
v-slots={slots}
>
<div class={`${prefixCls}-drag-container`}>{slots.default?.()}</div>
</VcUpload>
</div>
{renderUploadList()}
</span>
);
}
const uploadButtonCls = classNames(prefixCls.value, {
[`${prefixCls.value}-select`]: true,
[`${prefixCls.value}-select-${listType}`]: true,
[`${prefixCls.value}-disabled`]: disabled,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
});
const children = flattenChildren(slots.default?.());
const uploadButton = (
<div
class={uploadButtonCls}
style={children && children.length ? undefined : { display: 'none' }}
>
<VcUpload {...rcUploadProps} ref={upload} v-slots={slots} />
</div>
);
if (listType === 'picture-card') {
return (
<span class={classNames(`${prefixCls.value}-picture-card-wrapper`, attrs.class)}>
{renderUploadList(uploadButton)}
</span>
);
}
return (
<span class={classNames(`${prefixCls}-picture-card-wrapper`, className)}>
{uploadList}
<span class={attrs.class}>
{uploadButton}
{renderUploadList()}
</span>
);
}
return (
<span class={className}>
{uploadButton}
{uploadList}
</span>
);
};
},
});

View File

@ -1,284 +0,0 @@
import type { CSSProperties } from 'vue';
import { defineComponent, inject, nextTick } from 'vue';
import BaseMixin from '../_util/BaseMixin';
import { getOptionProps, initDefaultProps } from '../_util/props-util';
import {
getTransitionProps,
Transition,
getTransitionGroupProps,
TransitionGroup,
} from '../_util/transition';
import { defaultConfigProvider } from '../config-provider';
import { previewImage, isImageUrl } from './utils';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import PaperClipOutlined from '@ant-design/icons-vue/PaperClipOutlined';
import PictureTwoTone from '@ant-design/icons-vue/PictureTwoTone';
import FileTwoTone from '@ant-design/icons-vue/FileOutlined';
import DeleteOutlined from '@ant-design/icons-vue/DeleteOutlined';
import DownloadOutlined from '@ant-design/icons-vue/DownloadOutlined';
import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
import Tooltip from '../tooltip';
import Progress from '../progress';
import classNames from '../_util/classNames';
import { uploadListProps } from './interface';
export default defineComponent({
name: 'AUploadList',
mixins: [BaseMixin],
props: initDefaultProps(uploadListProps, {
listType: 'text', // or picture
progressAttr: {
strokeWidth: 2,
showInfo: false,
},
showRemoveIcon: true,
showDownloadIcon: false,
showPreviewIcon: true,
previewFile: previewImage,
}),
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
updated() {
nextTick(() => {
const { listType, items, previewFile } = this.$props;
if (listType !== 'picture' && listType !== 'picture-card') {
return;
}
(items || []).forEach(file => {
if (
typeof document === 'undefined' ||
typeof window === 'undefined' ||
!window.FileReader ||
!window.File ||
!(file.originFileObj instanceof File || file.originFileObj instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;
}
/*eslint-disable */
file.thumbUrl = '';
if (previewFile) {
previewFile(file.originFileObj).then(previewDataUrl => {
// Need append '' to avoid dead loop
file.thumbUrl = previewDataUrl || '';
(this as any).$forceUpdate();
});
}
});
});
},
methods: {
handlePreview(file, e) {
const { onPreview } = this.$props;
if (!onPreview) {
return;
}
e.preventDefault();
return this.$emit('preview', file);
},
handleDownload(file) {
const { onDownload } = this.$props;
if (typeof onDownload === 'function') {
this.$emit('download', file);
} else if (file.url) {
window.open(file.url);
}
},
handleClose(file) {
this.$emit('remove', file);
},
},
render() {
const {
prefixCls: customizePrefixCls,
items = [],
listType,
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
locale,
progressAttr,
} = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const list = items.map(file => {
let progress;
let icon = file.status === 'uploading' ? <LoadingOutlined /> : <PaperClipOutlined />;
if (listType === 'picture' || listType === 'picture-card') {
if (listType === 'picture-card' && file.status === 'uploading') {
icon = <div class={`${prefixCls}-list-item-uploading-text`}>{locale.uploading}</div>;
} else if (!file.thumbUrl && !file.url) {
icon = <PictureTwoTone class={`${prefixCls}-list-item-thumbnail`} />;
} else {
const thumbnail = isImageUrl(file) ? (
<img
src={file.thumbUrl || file.url}
alt={file.name}
class={`${prefixCls}-list-item-image`}
/>
) : (
<FileTwoTone class={`${prefixCls}-list-item-icon`} />
);
icon = (
<a
class={`${prefixCls}-list-item-thumbnail`}
onClick={e => this.handlePreview(file, e)}
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
>
{thumbnail}
</a>
);
}
}
if (file.status === 'uploading') {
const progressProps = {
...progressAttr,
type: 'line',
percent: file.percent,
};
// show loading icon if upload progress listener is disabled
const loadingProgress = 'percent' in file ? <Progress {...progressProps} /> : null;
progress = (
<div class={`${prefixCls}-list-item-progress`} key="progress">
{loadingProgress}
</div>
);
}
const infoUploadingClass = classNames({
[`${prefixCls}-list-item`]: true,
[`${prefixCls}-list-item-${file.status}`]: true,
[`${prefixCls}-list-item-list-type-${listType}`]: true,
});
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
const removeIcon = showRemoveIcon ? (
<DeleteOutlined title={locale.removeFile} onClick={() => this.handleClose(file)} />
) : null;
const downloadIcon =
showDownloadIcon && file.status === 'done' ? (
<DownloadOutlined title={locale.downloadFile} onClick={() => this.handleDownload(file)} />
) : null;
const downloadOrDelete = listType !== 'picture-card' && (
<span
key="download-delete"
class={`${prefixCls}-list-item-card-actions ${listType === 'picture' ? 'picture' : ''}`}
>
{downloadIcon && <a title={locale.downloadFile}>{downloadIcon}</a>}
{removeIcon && <a title={locale.removeFile}>{removeIcon}</a>}
</span>
);
const listItemNameClass = classNames({
[`${prefixCls}-list-item-name`]: true,
[`${prefixCls}-list-item-name-icon-count-${
[downloadIcon, removeIcon].filter(x => x).length
}`]: true,
});
const preview = file.url
? [
<a
target="_blank"
rel="noopener noreferrer"
class={listItemNameClass}
title={file.name}
{...linkProps}
href={file.url}
onClick={e => this.handlePreview(file, e)}
>
{file.name}
</a>,
downloadOrDelete,
]
: [
<span
key="view"
class={`${prefixCls}-list-item-name`}
onClick={e => this.handlePreview(file, e)}
title={file.name}
>
{file.name}
</span>,
downloadOrDelete,
];
const style: CSSProperties | undefined =
file.url || file.thumbUrl
? undefined
: {
pointerEvents: 'none',
opacity: 0.5,
};
const previewIcon = showPreviewIcon ? (
<a
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
style={style}
onClick={e => this.handlePreview(file, e)}
title={locale.previewFile}
>
<EyeOutlined />
</a>
) : null;
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
<span class={`${prefixCls}-list-item-actions`}>
{previewIcon}
{file.status === 'done' && downloadIcon}
{removeIcon}
</span>
);
let message;
if (file.response && typeof file.response === 'string') {
message = file.response;
} else {
message = (file.error && file.error.statusText) || locale.uploadError;
}
const iconAndPreview = (
<span>
{icon}
{preview}
</span>
);
const transitionProps = getTransitionProps('fade');
const dom = (
<div class={infoUploadingClass} key={file.uid}>
<div class={`${prefixCls}-list-item-info`}>{iconAndPreview}</div>
{actions}
<Transition {...transitionProps}>{progress}</Transition>
</div>
);
const listContainerNameClass = classNames({
[`${prefixCls}-list-picture-card-container`]: listType === 'picture-card',
});
return (
<div key={file.uid} class={listContainerNameClass}>
{file.status === 'error' ? <Tooltip title={message}>{dom}</Tooltip> : <span>{dom}</span>}
</div>
);
});
const listClassNames = classNames({
[`${prefixCls}-list`]: true,
[`${prefixCls}-list-${listType}`]: true,
});
const animationDirection = listType === 'picture-card' ? 'animate-inline' : 'animate';
const transitionGroupProps = {
...getTransitionGroupProps(`${prefixCls}-${animationDirection}`),
class: listClassNames,
};
return (
<TransitionGroup {...transitionGroupProps} tag="div">
{list}
</TransitionGroup>
);
},
});

View File

@ -0,0 +1,286 @@
import { computed, defineComponent, onBeforeUnmount, onMounted, ref } from 'vue';
import type { ExtractPropTypes, PropType, CSSProperties } from 'vue';
import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
import DeleteOutlined from '@ant-design/icons-vue/DeleteOutlined';
import DownloadOutlined from '@ant-design/icons-vue/DownloadOutlined';
import Tooltip from '../../tooltip';
import Progress from '../../progress';
import type {
ItemRender,
UploadFile,
UploadListProgressProps,
UploadListType,
UploadLocale,
} from '../interface';
import type { VueNode } from '../../_util/type';
import useConfigInject from '../../_util/hooks/useConfigInject';
import Transition, { getTransitionProps } from '../../_util/transition';
export const listItemProps = () => {
return {
prefixCls: String,
locale: { type: Object as PropType<UploadLocale>, default: undefined as UploadLocale },
file: Object as PropType<UploadFile>,
items: Array as PropType<UploadFile[]>,
listType: String as PropType<UploadListType>,
isImgUrl: Function as PropType<(file: UploadFile) => boolean>,
showRemoveIcon: { type: Boolean, default: undefined },
showDownloadIcon: { type: Boolean, default: undefined },
showPreviewIcon: { type: Boolean, default: undefined },
removeIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
downloadIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
previewIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
iconRender: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
actionIconRender: Function as PropType<
(opt: {
customIcon: VueNode;
callback: () => void;
prefixCls: string;
title?: string | undefined;
}) => VueNode
>,
itemRender: Function as PropType<ItemRender>,
onPreview: Function as PropType<(file: UploadFile, e: Event) => void>,
onClose: Function as PropType<(file: UploadFile) => void>,
onDownload: Function as PropType<(file: UploadFile) => void>,
progress: Object as PropType<UploadListProgressProps>,
};
};
export type ListItemProps = Partial<ExtractPropTypes<ReturnType<typeof listItemProps>>>;
export default defineComponent({
name: 'ListItem',
inheritAttrs: false,
props: listItemProps(),
setup(props, { slots, attrs }) {
const showProgress = ref(false);
const progressRafRef = ref();
onMounted(() => {
progressRafRef.value = setTimeout(() => {
showProgress.value = true;
}, 300);
});
onBeforeUnmount(() => {
clearTimeout(progressRafRef.value);
});
const { rootPrefixCls } = useConfigInject('upload', props);
const transitionProps = computed(() => getTransitionProps(`${rootPrefixCls.value}-fade`));
return () => {
const {
prefixCls,
locale,
listType,
file,
items,
progress: progressProps,
iconRender = slots.iconRender,
actionIconRender = slots.actionIconRender,
itemRender = slots.itemRender,
isImgUrl,
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
previewIcon: customPreviewIcon = slots.previewIcon,
removeIcon: customRemoveIcon = slots.removeIcon,
downloadIcon: customDownloadIcon = slots.downloadIcon,
onPreview,
onDownload,
onClose,
} = props;
const { class: className, style } = attrs;
// This is used for legacy span make scrollHeight the wrong value.
// We will force these to be `display: block` with non `picture-card`
const spanClassName = `${prefixCls}-span`;
const iconNode = iconRender({ file });
let icon = <div class={`${prefixCls}-text-icon`}>{iconNode}</div>;
if (listType === 'picture' || listType === 'picture-card') {
if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) {
const uploadingClassName = {
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: file.status !== 'uploading',
};
icon = <div class={uploadingClassName}>{iconNode}</div>;
} else {
const thumbnail = isImgUrl?.(file) ? (
<img
src={file.thumbUrl || file.url}
alt={file.name}
class={`${prefixCls}-list-item-image`}
/>
) : (
iconNode
);
const aClassName = {
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: isImgUrl && !isImgUrl(file),
};
icon = (
<a
class={aClassName}
onClick={e => onPreview(file, e)}
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
>
{thumbnail}
</a>
);
}
}
const infoUploadingClass = {
[`${prefixCls}-list-item`]: true,
[`${prefixCls}-list-item-${file.status}`]: true,
[`${prefixCls}-list-item-list-type-${listType}`]: true,
};
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
const removeIcon = showRemoveIcon
? actionIconRender({
customIcon: customRemoveIcon ? customRemoveIcon({ file }) : <DeleteOutlined />,
callback: () => onClose(file),
prefixCls,
title: locale.removeFile,
})
: null;
const downloadIcon =
showDownloadIcon && file.status === 'done'
? actionIconRender({
customIcon: customDownloadIcon ? customDownloadIcon({ file }) : <DownloadOutlined />,
callback: () => onDownload(file),
prefixCls,
title: locale.downloadFile,
})
: null;
const downloadOrDelete = listType !== 'picture-card' && (
<span
key="download-delete"
class={[
`${prefixCls}-list-item-card-actions`,
{
picture: listType === 'picture',
},
]}
>
{downloadIcon}
{removeIcon}
</span>
);
const listItemNameClass = `${prefixCls}-list-item-name`;
const preview = file.url
? [
<a
key="view"
target="_blank"
rel="noopener noreferrer"
class={listItemNameClass}
title={file.name}
{...linkProps}
href={file.url}
onClick={e => onPreview(file, e)}
>
{file.name}
</a>,
downloadOrDelete,
]
: [
<span
key="view"
class={listItemNameClass}
onClick={e => onPreview(file, e)}
title={file.name}
>
{file.name}
</span>,
downloadOrDelete,
];
const previewStyle: CSSProperties = {
pointerEvents: 'none',
opacity: 0.5,
};
const previewIcon = showPreviewIcon ? (
<a
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
style={file.url || file.thumbUrl ? undefined : previewStyle}
onClick={e => onPreview(file, e)}
title={locale.previewFile}
>
{customPreviewIcon ? customPreviewIcon({ file }) : <EyeOutlined />}
</a>
) : null;
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
<span class={`${prefixCls}-list-item-actions`}>
{previewIcon}
{file.status === 'done' && downloadIcon}
{removeIcon}
</span>
);
let message;
if (file.response && typeof file.response === 'string') {
message = file.response;
} else {
message = file.error?.statusText || file.error?.message || locale.uploadError;
}
const iconAndPreview = (
<span class={spanClassName}>
{icon}
{preview}
</span>
);
const dom = (
<div class={infoUploadingClass}>
<div class={`${prefixCls}-list-item-info`}>{iconAndPreview}</div>
{actions}
{showProgress.value && (
<Transition {...transitionProps.value}>
<div v-show={file.status === 'uploading'} class={`${prefixCls}-list-item-progress`}>
{'percent' in file ? (
<Progress {...progressProps} type="line" percent={file.percent} />
) : null}
</div>
</Transition>
)}
</div>
);
const listContainerNameClass = {
[`${prefixCls}-list-${listType}-container`]: true,
[`${className}`]: !!className,
};
const item =
file.status === 'error' ? (
<Tooltip title={message} getPopupContainer={node => node.parentNode as HTMLElement}>
{dom}
</Tooltip>
) : (
dom
);
return (
<div class={listContainerNameClass} style={style} ref={ref}>
{itemRender
? itemRender({
originNode: item,
file,
fileList: items,
actions: {
download: onDownload.bind(null, file),
preview: onPreview.bind(null, file),
remove: onClose.bind(null, file),
},
})
: item}
</div>
);
};
},
});

View File

@ -0,0 +1,211 @@
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import PaperClipOutlined from '@ant-design/icons-vue/PaperClipOutlined';
import PictureTwoTone from '@ant-design/icons-vue/PictureTwoTone';
import FileTwoTone from '@ant-design/icons-vue/FileTwoTone';
import type { UploadListType, InternalUploadFile, UploadFile } from '../interface';
import { uploadListProps } from '../interface';
import { previewImage, isImageUrl } from '../utils';
import type { ButtonProps } from '../../button';
import Button from '../../button';
import ListItem from './ListItem';
import type { HTMLAttributes } from 'vue';
import { computed, defineComponent, getCurrentInstance, onMounted, ref, watchEffect } from 'vue';
import { initDefaultProps, isValidElement } from '../../_util/props-util';
import type { VueNode } from '../../_util/type';
import useConfigInject from '../../_util/hooks/useConfigInject';
import { getTransitionGroupProps, TransitionGroup } from '../../_util/transition';
import listAnimation from './listAnimation';
const HackSlot = (_, { slots }) => {
return slots.default?.()[0];
};
export default defineComponent({
name: 'AUploadList',
props: initDefaultProps(uploadListProps(), {
listType: 'text' as UploadListType, // or picture
progress: {
strokeWidth: 2,
showInfo: false,
},
showRemoveIcon: true,
showDownloadIcon: false,
showPreviewIcon: true,
previewFile: previewImage,
isImageUrl,
items: [],
}),
setup(props, { slots, expose }) {
const motionAppear = ref(false);
const instance = getCurrentInstance();
onMounted(() => {
motionAppear.value == true;
});
watchEffect(() => {
if (props.listType !== 'picture' && props.listType !== 'picture-card') {
return;
}
(props.items || []).forEach((file: InternalUploadFile) => {
if (
typeof document === 'undefined' ||
typeof window === 'undefined' ||
!(window as any).FileReader ||
!(window as any).File ||
!(file.originFileObj instanceof File || (file.originFileObj as Blob) instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;
}
file.thumbUrl = '';
if (props.previewFile) {
props.previewFile(file.originFileObj as File).then((previewDataUrl: string) => {
// Need append '' to avoid dead loop
file.thumbUrl = previewDataUrl || '';
instance.update();
});
}
});
});
// ============================= Events =============================
const onInternalPreview = (file: UploadFile, e?: Event) => {
if (!props.onPreview) {
return;
}
e?.preventDefault();
return props.onPreview(file);
};
const onInternalDownload = (file: UploadFile) => {
if (typeof props.onDownload === 'function') {
props.onDownload(file);
} else if (file.url) {
window.open(file.url);
}
};
const onInternalClose = (file: UploadFile) => {
props.onRemove?.(file);
};
const internalIconRender = ({ file }: { file: UploadFile }) => {
const iconRender = props.iconRender || slots.iconRender;
if (iconRender) {
return iconRender({ file, listType: props.listType });
}
const isLoading = file.status === 'uploading';
const fileIcon =
props.isImageUrl && props.isImageUrl(file) ? <PictureTwoTone /> : <FileTwoTone />;
let icon: VueNode = isLoading ? <LoadingOutlined /> : <PaperClipOutlined />;
if (props.listType === 'picture') {
icon = isLoading ? <LoadingOutlined /> : fileIcon;
} else if (props.listType === 'picture-card') {
icon = isLoading ? props.locale.uploading : fileIcon;
}
return icon;
};
const actionIconRender = (opt: {
customIcon: VueNode;
callback: () => void;
prefixCls: string;
title?: string;
}) => {
const { customIcon, callback, prefixCls, title } = opt;
const btnProps: ButtonProps & HTMLAttributes = {
type: 'text',
size: 'small',
title,
onClick: () => {
callback();
},
class: `${prefixCls}-list-item-card-actions-btn`,
};
if (isValidElement(customIcon)) {
return <Button {...btnProps} v-slots={{ icon: () => customIcon }} />;
}
return (
<Button {...btnProps}>
<span>{customIcon}</span>
</Button>
);
};
expose({
handlePreview: onInternalPreview,
handleDownload: onInternalDownload,
});
const { prefixCls, direction } = useConfigInject('upload', props);
const listClassNames = computed(() => ({
[`${prefixCls.value}-list`]: true,
[`${prefixCls.value}-list-${props.listType}`]: true,
[`${prefixCls.value}-list-rtl`]: direction.value === 'rtl',
}));
const transitionGroupProps = computed(() => ({
...listAnimation(
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
),
...getTransitionGroupProps(
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
),
class: listClassNames.value,
appear: motionAppear.value,
}));
return () => {
const {
listType,
locale,
isImageUrl: isImgUrl,
items = [],
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
removeIcon,
previewIcon,
downloadIcon,
progress,
appendAction = slots.appendAction,
itemRender,
} = props;
const appendActionDom = appendAction?.()[0];
return (
<TransitionGroup {...transitionGroupProps.value} tag="div">
{items.map(file => {
const { uid: key } = file;
return (
<ListItem
key={key}
locale={locale}
prefixCls={prefixCls.value}
file={file}
items={items}
progress={progress}
listType={listType}
isImgUrl={isImgUrl}
showPreviewIcon={showPreviewIcon}
showRemoveIcon={showRemoveIcon}
showDownloadIcon={showDownloadIcon}
onPreview={onInternalPreview}
onDownload={onInternalDownload}
onClose={onInternalClose}
removeIcon={removeIcon}
previewIcon={previewIcon}
downloadIcon={downloadIcon}
itemRender={itemRender}
v-slots={{
...slots,
iconRender: internalIconRender,
actionIconRender,
}}
/>
);
})}
{isValidElement(appendActionDom) ? (
<HackSlot key="__ant_upload_appendAction">{appendActionDom}</HackSlot>
) : null}
</TransitionGroup>
);
};
},
});

View File

@ -0,0 +1,44 @@
import { addClass, removeClass } from '../../vc-util/Dom/class';
import { nextTick } from 'vue';
import type { CSSMotionProps } from '../../_util/transition';
const listAnimation = (name): CSSMotionProps => {
return {
name,
appear: true,
css: true,
onBeforeEnter: (node: HTMLDivElement) => {
addClass(node, name);
node.style.height = '0px';
node.style.opacity = '0';
},
onEnter: (node: HTMLDivElement) => {
nextTick(() => {
node.style.height = `${node.scrollHeight}px`;
node.style.opacity = '1';
});
},
onAfterEnter: (node: HTMLDivElement) => {
if (node) removeClass(node, name);
node.style.height = undefined;
node.style.opacity = undefined;
},
onBeforeLeave: (node: HTMLDivElement) => {
addClass(node, name);
node.style.height = `${node.offsetHeight}px`;
node.style.opacity = undefined;
},
onLeave: (node: HTMLDivElement) => {
setTimeout(() => {
node.style.height = '0px';
node.style.opacity = '0';
});
},
onAfterLeave: (node: HTMLDivElement) => {
if (node) removeClass(node, name);
node.style.height = undefined;
node.style.opacity = undefined;
},
};
};
export default listAnimation;

View File

@ -1,126 +1,305 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/upload/demo/avatar.vue correctly 1`] = `
<span class="ant-upload-picture-card-wrapper avatar-uploader"><!----><div class="ant-upload ant-upload-select ant-upload-select-picture-card"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><div><span role="img" aria-label="plus" class="anticon anticon-plus"><svg focusable="false" class="" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><defs><style></style></defs><path d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"></path><path d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"></path></svg></span>
<span class="ant-upload-picture-card-wrapper avatar-uploader"><div class="ant-upload ant-upload-select ant-upload-select-picture-card"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><div><span role="img" aria-label="plus" class="anticon anticon-plus"><svg focusable="false" class="" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><defs><style></style></defs><path d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"></path><path d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"></path></svg></span>
<div class="ant-upload-text">Upload</div>
</div></span></div></span>
`;
exports[`renders ./components/upload/demo/basic.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept="" multiple=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text"></div></span>
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<!---->
</div></span>
`;
exports[`renders ./components/upload/demo/custom-render.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<div class="ant-upload-list-text-container">
<div class="ant-space ant-space-horizontal ant-space-align-center">
<div class="ant-space-item" style="margin-right: 8px;"><span style="">xxx.png</span></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><a href="javascript:;">download</a></div>
<!---->
<div class="ant-space-item"><a href="javascript:;">delete</a></div>
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<div class="ant-space ant-space-horizontal ant-space-align-center">
<div class="ant-space-item" style="margin-right: 8px;"><span style="">yyy.png</span></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><a href="javascript:;">download</a></div>
<!---->
<div class="ant-space-item"><a href="javascript:;">delete</a></div>
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<div class="ant-space ant-space-horizontal ant-space-align-center">
<div class="ant-space-item" style="margin-right: 8px;"><span style="color: red;">zzz.png</span></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><a href="javascript:;">download</a></div>
<!---->
<div class="ant-space-item"><a href="javascript:;">delete</a></div>
<!---->
</div>
</div>
<!---->
</div></span>
`;
exports[`renders ./components/upload/demo/customize-progress-bar.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Click to Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<!---->
</div></span>
`;
exports[`renders ./components/upload/demo/defaultFileList.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"><div class="ant-upload-list-item-info"><span><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="xxx.png" href="http://www.baidu.com/xxx.png">xxx.png</a><span class="ant-upload-list-item-card-actions "><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"><div class="ant-upload-list-item-info"><span><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="yyy.png" href="http://www.baidu.com/yyy.png">yyy.png</a><span class="ant-upload-list-item-card-actions "><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class="">
<!---->
<div class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="zzz.png" href="http://www.baidu.com/zzz.png">zzz.png</a><span class="ant-upload-list-item-card-actions "><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="xxx.png" href="http://www.baidu.com/xxx.png">xxx.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="yyy.png" href="http://www.baidu.com/yyy.png">yyy.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<!---->
<div class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="zzz.png" href="http://www.baidu.com/zzz.png">zzz.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<!---->
</div></span>
`;
exports[`renders ./components/upload/demo/directory.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept="" directory="directory" webkitdirectory="webkitdirectory"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload Directory</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text"></div></span>
`;
exports[`renders ./components/upload/demo/drag.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-drag"><span role="button" tabindex="0" class="ant-upload ant-upload-btn"><input type="file" style="display: none;" accept="" multiple=""><div class="ant-upload-drag-container"><p class="ant-upload-drag-icon"><span role="img" aria-label="inbox" class="anticon anticon-inbox"><svg focusable="false" class="" data-icon="inbox" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"><path d="M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0060.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z"></path></svg></span></p>
<p class="ant-upload-text">Click or drag file to this area to upload</p>
<p class="ant-upload-hint"> Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files </p>
</div></span></div>
<div class="ant-upload-list ant-upload-list-text"></div></span>
`;
exports[`renders ./components/upload/demo/fileList.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept="" multiple=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" directory="directory" webkitdirectory="webkitdirectory" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload Directory</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text"><div class="ant-upload-list-item-info"><span><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="xxx.png" href="http://www.baidu.com/xxx.png">xxx.png</a><span class="ant-upload-list-item-card-actions "><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
</div></span>
`;
exports[`renders ./components/upload/demo/picture-card.vue correctly 1`] = `
<div class="clearfix"><span class="ant-upload-picture-card-wrapper"><div class="ant-upload-list ant-upload-list-picture-card"><div class="ant-upload-list-picture-card-container"><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></span>
<!---->
</div></span></div>
<div class="ant-upload-list-picture-card-container"><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></span>
<!---->
</div></span></div>
<div class="ant-upload-list-picture-card-container"><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></span>
<!---->
</div></span></div>
<div class="ant-upload-list-picture-card-container"><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></span>
<!---->
</div></span></div>
<div class="ant-upload-list-picture-card-container">
exports[`renders ./components/upload/demo/drag.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-drag"><span tabindex="0" class="ant-upload ant-upload-btn" role="button"><input type="file" style="display: none;" accept="" multiple="" capture="false"><p class="ant-upload-drag-icon"><span role="img" aria-label="inbox" class="anticon anticon-inbox"><svg focusable="false" class="" data-icon="inbox" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"><path d="M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0060.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z"></path></svg></span></p>
<p class="ant-upload-text">Click or drag file to this area to upload</p>
<p class="ant-upload-hint"> Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files </p></span></div>
<div class="ant-upload-list ant-upload-list-text">
<!---->
<div class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-picture-card">
<div class="ant-upload-list-item-info"><span><span role="img" aria-label="picture" class="anticon anticon-picture ant-upload-list-item-thumbnail"><svg focusable="false" class="" data-icon="picture" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 632H136v-39.9l138.5-164.3 150.1 178L658.1 489 888 761.6V792zm0-129.8L664.2 396.8c-3.2-3.8-9-3.8-12.2 0L424.6 666.4l-144-170.7c-3.2-3.8-9-3.8-12.2 0L136 652.7V232h752v430.2z" fill="#1890ff"></path><path d="M424.6 765.8l-150.1-178L136 752.1V792h752v-30.4L658.1 489z" fill="#e6f7ff"></path><path d="M136 652.7l132.4-157c3.2-3.8 9-3.8 12.2 0l144 170.7L652 396.8c3.2-3.8 9-3.8 12.2 0L888 662.2V232H136v420.7zM304 280a88 88 0 110 176 88 88 0 010-176z" fill="#e6f7ff"></path><path d="M276 368a28 28 0 1056 0 28 28 0 10-56 0z" fill="#e6f7ff"></path><path d="M304 456a88 88 0 100-176 88 88 0 000 176zm0-116c15.5 0 28 12.5 28 28s-12.5 28-28 28-28-12.5-28-28 12.5-28 28-28z" fill="#1890ff"></path></svg></span><span class="ant-upload-list-item-name" title="image.png">image.png</span>
<!----></span>
</div><span class="ant-upload-list-item-actions"><a target="_blank" rel="noopener noreferrer" style="pointer-events: none; opacity: 0.5;" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></span>
</div></span>
`;
exports[`renders ./components/upload/demo/fileList.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" multiple="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="xxx.png" href="http://www.baidu.com/xxx.png">xxx.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<!---->
</div></span>
`;
exports[`renders ./components/upload/demo/max-count.vue correctly 1`] = `
<div class="ant-space ant-space-vertical" style="width: 100%;">
<div class="ant-space-item" style="margin-bottom: 24px;"><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload (Max: 1)</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<!---->
</div></span>
</div>
<div class="ant-upload ant-upload-select ant-upload-select-picture-card"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><div><span role="img" aria-label="plus" class="anticon anticon-plus"><svg focusable="false" class="" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><defs><style></style></defs><path d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"></path><path d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"></path></svg></span>
<div class="ant-upload-text">Upload</div>
</div></span></div></span>
<!---->
<div class="ant-space-item"><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload (Max: 3)</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<!---->
</div></span></div>
<!---->
</div>
`;
exports[`renders ./components/upload/demo/picture-card.vue correctly 1`] = `
<div class="clearfix"><span class="ant-upload-picture-card-wrapper"><div class="ant-upload-list ant-upload-list-picture-card"><div class="ant-upload-list-picture-card-container"><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card"><div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
</div>
<div class="ant-upload-list-picture-card-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
</div>
<div class="ant-upload-list-picture-card-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
</div>
<div class="ant-upload-list-picture-card-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
</div>
<div class="ant-upload-list-picture-card-container">
<div class="ant-upload-list-item ant-upload-list-item-uploading ant-upload-list-item-list-type-picture-card">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-list-item-thumbnail">Uploading...</div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-card-container">
<!---->
<div class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-picture-card">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-list-item-thumbnail ant-upload-list-item-file"><span role="img" aria-label="picture" class="anticon anticon-picture"><svg focusable="false" class="" data-icon="picture" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 632H136v-39.9l138.5-164.3 150.1 178L658.1 489 888 761.6V792zm0-129.8L664.2 396.8c-3.2-3.8-9-3.8-12.2 0L424.6 666.4l-144-170.7c-3.2-3.8-9-3.8-12.2 0L136 652.7V232h752v430.2z" fill="#1890ff"></path><path d="M424.6 765.8l-150.1-178L136 752.1V792h752v-30.4L658.1 489z" fill="#e6f7ff"></path><path d="M136 652.7l132.4-157c3.2-3.8 9-3.8 12.2 0l144 170.7L652 396.8c3.2-3.8 9-3.8 12.2 0L888 662.2V232H136v420.7zM304 280a88 88 0 110 176 88 88 0 010-176z" fill="#e6f7ff"></path><path d="M276 368a28 28 0 1056 0 28 28 0 10-56 0z" fill="#e6f7ff"></path><path d="M304 456a88 88 0 100-176 88 88 0 000 176zm0-116c15.5 0 28 12.5 28 28s-12.5 28-28 28-28-12.5-28-28 12.5-28 28-28z" fill="#1890ff"></path></svg></span></div><span class="ant-upload-list-item-name" title="image.png">image.png</span>
<!----></span>
</div><span class="ant-upload-list-item-actions"><a target="_blank" rel="noopener noreferrer" style="pointer-events: none; opacity: 0.5;" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
</div>
<div class="ant-upload ant-upload-select ant-upload-select-picture-card"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><div><span role="img" aria-label="plus" class="anticon anticon-plus"><svg focusable="false" class="" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><defs><style></style></defs><path d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"></path><path d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"></path></svg></span>
<div style="margin-top: 8px;">Upload</div>
</div></span></div>
</div></span>
<!---->
</div>
`;
exports[`renders ./components/upload/demo/picture-style.vue correctly 1`] = `
<div><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>upload</span></button></span></div>
<div><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="xxx.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="xxx.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">xxx.png</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="xxx.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="xxx.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">xxx.png</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="yyy.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="yyy.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">yyy.png</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="yyy.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="yyy.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">yyy.png</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
</div></span><br><br><span class="upload-list-inline"><div class="ant-upload ant-upload-select ant-upload-select-picture"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>upload</span></button></span></div>
</div></span><br><br><span class="upload-list-inline"><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="xxx.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="xxx.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">xxx.png</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="xxx.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="xxx.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">xxx.png</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="yyy.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="yyy.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">yyy.png</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="yyy.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="yyy.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">yyy.png</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
</div></span></div>
`;
exports[`renders ./components/upload/demo/preview-file.vue correctly 1`] = `
<div><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture"></div></span></div>
<div><span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<!---->
</div></span></div>
`;
exports[`renders ./components/upload/demo/transform-file.vue correctly 1`] = `
<div><span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" style="display: none;" accept=""><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text"></div></span></div>
<div><span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<!---->
</div></span></div>
`;
exports[`renders ./components/upload/demo/upload-custom-action-icon.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="xxx.png" href="http://www.baidu.com/xxx.png">xxx.png</a><span class="ant-upload-list-item-card-actions"><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn" title="Download file" type="button"><!----><span>download</span></button><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span tabindex="-1" role="img" aria-label="star" class="anticon anticon-star"><svg focusable="false" class="" data-icon="star" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3zM664.8 561.6l36.1 210.3L512 672.7 323.1 772l36.1-210.3-152.8-149L417.6 382 512 190.7 606.4 382l211.2 30.7-152.8 148.9z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="yyy.png" href="http://www.baidu.com/yyy.png">yyy.png</a><span class="ant-upload-list-item-card-actions"><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn" title="Download file" type="button"><!----><span>download</span></button><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span tabindex="-1" role="img" aria-label="star" class="anticon anticon-star"><svg focusable="false" class="" data-icon="star" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3zM664.8 561.6l36.1 210.3L512 672.7 323.1 772l36.1-210.3-152.8-149L417.6 382 512 190.7 606.4 382l211.2 30.7-152.8 148.9z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<!---->
<div class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="zzz.png" href="http://www.baidu.com/zzz.png">zzz.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span tabindex="-1" role="img" aria-label="star" class="anticon anticon-star"><svg focusable="false" class="" data-icon="star" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M908.1 353.1l-253.9-36.9L540.7 86.1c-3.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L369.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3a32.05 32.05 0 00.6 45.3l183.7 179.1-43.4 252.9a31.95 31.95 0 0046.4 33.7L512 754l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3zM664.8 561.6l36.1 210.3L512 672.7 323.1 772l36.1-210.3-152.8-149L417.6 382 512 190.7 606.4 382l211.2 30.7-152.8 148.9z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<!---->
</div></span>
`;
exports[`renders ./components/upload/demo/upload-png-only.vue correctly 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button class="ant-btn" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Upload png only</span></button></span></div>
<div class="ant-upload-list ant-upload-list-text">
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="xxx.png" href="http://www.baidu.com/xxx.png">xxx.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="yyy.png" href="http://www.baidu.com/yyy.png">yyy.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-text-container">
<!---->
<div class="ant-upload-list-item ant-upload-list-item-error ant-upload-list-item-list-type-text">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><div class="ant-upload-text-icon"><span role="img" aria-label="paper-clip" class="anticon anticon-paper-clip"><svg focusable="false" class="" data-icon="paper-clip" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><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"></path></svg></span></div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="zzz.png" href="http://www.baidu.com/zzz.png">zzz.png</a><span class="ant-upload-list-item-card-actions"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span>
</div>
<!---->
<!---->
</div>
</div>
<!---->
</div></span>
`;

View File

@ -35,41 +35,71 @@ exports[`Upload List handle error 2`] = `
exports[`Upload List should be uploading when upload a file 1`] = `<span><div class="ant-upload ant-upload-select ant-upload-select-text"><span role="button" tabindex="0" class="ant-upload"><input type="file" accept="" style="display: none;"><button>upload</button></span></div><span tag="div" class="ant-upload-list ant-upload-list-text"></span></span>`;
exports[`Upload List should non-image format file preview 1`] = `
<span><div class="ant-upload ant-upload-select ant-upload-select-picture"><!----></div><div class="ant-upload-list ant-upload-list-picture"><div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/aaa.zip" target="_blank" rel="noopener noreferrer"><span role="img" aria-label="file" class="anticon anticon-file ant-upload-list-item-icon"><svg focusable="false" class="" data-icon="file" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"></path></svg></span></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="not-image" href="https://cdn.xxx.com/aaa.zip">not-image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/aaa" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/aaa" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image" href="https://cdn.xxx.com/aaa">image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/aaa.xx" target="_blank" rel="noopener noreferrer"><span role="img" aria-label="file" class="anticon anticon-file ant-upload-list-item-icon"><svg focusable="false" class="" data-icon="file" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"></path></svg></span></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="not-image" href="https://cdn.xxx.com/aaa.xx">not-image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/aaa.png/xx.xx" target="_blank" rel="noopener noreferrer"><span role="img" aria-label="file" class="anticon anticon-file ant-upload-list-item-icon"><svg focusable="false" class="" data-icon="file" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"></path></svg></span></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="not-image" href="https://cdn.xxx.com/aaa.png/xx.xx">not-image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png">image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png" target="_blank" rel="noopener noreferrer"><img src="data:image/png;base64,UEsDBAoAAAAAADYZYkwAAAAAAAAAAAAAAAAdAAk" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png">image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png?query=123" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png?query=123" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png?query=123">image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png#anchor" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png#anchor" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png#anchor">image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<div class=""><span><div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture"><div class="ant-upload-list-item-info"><span><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot">image</a><span class="ant-upload-list-item-card-actions picture"><!----><a title="Remove file"><span title="Remove file" tabindex="-1" role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></a></span></span></div>
<!---->
<!---->
</div></span></div>
<span><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept="" capture="false"><button>upload</button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail ant-upload-list-item-file" href="https://cdn.xxx.com/aaa.zip" target="_blank" rel="noopener noreferrer"><span role="img" aria-label="file" class="anticon anticon-file"><svg focusable="false" class="" data-icon="file" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M534 352V136H232v752h560V394H576a42 42 0 01-42-42z" fill="#e6f7ff"></path><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM602 137.8L790.2 326H602V137.8zM792 888H232V136h302v216a42 42 0 0042 42h216v494z" fill="#1890ff"></path></svg></span></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="not-image" href="https://cdn.xxx.com/aaa.zip">not-image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/aaa" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/aaa" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image" href="https://cdn.xxx.com/aaa">image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail ant-upload-list-item-file" href="https://cdn.xxx.com/aaa.xx" target="_blank" rel="noopener noreferrer"><span role="img" aria-label="file" class="anticon anticon-file"><svg focusable="false" class="" data-icon="file" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M534 352V136H232v752h560V394H576a42 42 0 01-42-42z" fill="#e6f7ff"></path><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM602 137.8L790.2 326H602V137.8zM792 888H232V136h302v216a42 42 0 0042 42h216v494z" fill="#1890ff"></path></svg></span></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="not-image" href="https://cdn.xxx.com/aaa.xx">not-image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail ant-upload-list-item-file" href="https://cdn.xxx.com/aaa.png/xx.xx" target="_blank" rel="noopener noreferrer"><span role="img" aria-label="file" class="anticon anticon-file"><svg focusable="false" class="" data-icon="file" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M534 352V136H232v752h560V394H576a42 42 0 01-42-42z" fill="#e6f7ff"></path><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM602 137.8L790.2 326H602V137.8zM792 888H232V136h302v216a42 42 0 0042 42h216v494z" fill="#1890ff"></path></svg></span></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="not-image" href="https://cdn.xxx.com/aaa.png/xx.xx">not-image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png">image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png" target="_blank" rel="noopener noreferrer"><img src="data:image/png;base64,UEsDBAoAAAAAADYZYkwAAAAAAAAAAAAAAAAdAAk" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png">image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png?query=123" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png?query=123" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png?query=123">image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png#anchor" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png#anchor" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png#anchor">image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-picture-container">
<div class="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture">
<div class="ant-upload-list-item-info"><span class="ant-upload-span"><a class="ant-upload-list-item-thumbnail" href="https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot" target="_blank" rel="noopener noreferrer"><img src="https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot" alt="image" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image" href="https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot">image</a><span class="ant-upload-list-item-card-actions picture"><!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-card-actions-btn ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span></span></div>
<!---->
<!---->
</div>
</div>
<!---->
</div></span>
`;

View File

@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import Upload from '..';
import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from '../utils';
import { getFileItem, removeFileItem } from '../utils';
import PropsTypes from '../../_util/vue-types';
import { uploadListProps } from '../interface';
import { setup, teardown } from './mock';
@ -199,36 +199,6 @@ describe('Upload', () => {
});
describe('util', () => {
// https://github.com/react-component/upload/issues/36
it('should T() return true', () => {
const res = T();
expect(res).toBe(true);
});
it('should be able to copy file instance', () => {
const file = new File([], 'aaa.zip');
const copiedFile = fileToObject(file);
['uid', 'lastModified', 'lastModifiedDate', 'name', 'size', 'type'].forEach(key => {
expect(key in copiedFile).toBe(true);
});
});
it('should be able to progress from 0.1 ', () => {
// 0.1 -> 0.98
const getPercent = genPercentAdd();
let curPercent = 0;
curPercent = getPercent(curPercent);
expect(curPercent).toBe(0.1);
});
it('should be able to progress to 0.98 ', () => {
// 0.1 -> 0.98
const getPercent = genPercentAdd();
let curPercent = 0;
for (let i = 0; i < 500; i += 1) {
curPercent = getPercent(curPercent);
}
expect(parseFloat(curPercent.toFixed(2))).toBe(0.98);
});
it('should be able to get fileItem', () => {
const file = { uid: '-1', name: 'item.jpg' };
const fileList = [

View File

@ -300,7 +300,7 @@ describe('Upload List', () => {
defaultFileList: fileList,
listType: 'picture-card',
action: '',
remove: handleRemove,
onRemove: handleRemove,
onChange: handleChange,
},

View File

@ -10,7 +10,7 @@ title:
点击上传用户头像并使用 `beforeUpload` 限制用户上传的图片格式和大小
> `beforeUpload` 的返回值可以是一个 Promise 以支持异步处理如服务端校验等[示例](http://react-component.github.io/upload/examples/beforeUpload.html)
> `beforeUpload` 的返回值可以是一个 Promise 以支持异步处理如服务端校验等可参考react版本[示例](http://react-component.github.io/upload/examples/beforeUpload.html)
## en-US

View File

@ -19,7 +19,6 @@ Classic mode. File selection dialog pops up when upload button is clicked.
<a-upload
v-model:file-list="fileList"
name="file"
:multiple="true"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:headers="headers"
@change="handleChange"

View File

@ -0,0 +1,93 @@
<docs>
---
order: 0
title:
zh-CN: 自定义上传列表
en-US: Custom Render
---
## zh-CN
使用 `itemRender` 插槽进行完全自定义列表
## en-US
Custom render by using `itemRender` slot.
</docs>
<template>
<a-upload
v-model:file-list="fileList"
name="file"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:headers="headers"
@change="handleChange"
>
<a-button>
<upload-outlined></upload-outlined>
Click to Upload
</a-button>
<template #itemRender="{ file, actions }">
<a-space>
<span :style="file.status === 'error' ? 'color: red' : ''">{{ file.name }}</span>
<a href="javascript:;" @click="actions.download">download</a>
<a href="javascript:;" @click="actions.remove">delete</a>
</a-space>
</template>
</a-upload>
</template>
<script lang="ts">
import { message } from 'ant-design-vue';
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const handleChange = (info: UploadChangeParam) => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
};
const fileList = ref<UploadProps['fileList']>([
{
uid: '-1',
name: 'xxx.png',
status: 'done',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
{
uid: '-2',
name: 'yyy.png',
status: 'done',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
{
uid: '3',
name: 'zzz.png',
status: 'error',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/zzz.png',
},
]);
return {
fileList,
headers: {
authorization: 'authorization-text',
},
handleChange,
};
},
});
</script>

View File

@ -0,0 +1,76 @@
<docs>
---
order: 15
title:
zh-CN: 自定义进度条样式
en-US: Customize Progress Bar
---
## zh-CN
使用 `progress` 属性自定义进度条样式
## en-US
Use `progress` for customize progress bar.
</docs>
<template>
<a-upload
v-model:file-list="fileList"
name="file"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:headers="headers"
:progress="progress"
@change="handleChange"
>
<a-button>
<upload-outlined></upload-outlined>
Click to Upload
</a-button>
</a-upload>
</template>
<script lang="ts">
import { message } from 'ant-design-vue';
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const handleChange = (info: UploadChangeParam) => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
};
const fileList = ref([]);
const progress: UploadProps['progress'] = {
strokeColor: {
'0%': '#108ee9',
'100%': '#87d068',
},
strokeWidth: 3,
format: percent => `${parseFloat(percent.toFixed(2))}%`,
class: 'test',
};
return {
fileList,
headers: {
authorization: 'authorization-text',
},
handleChange,
progress,
};
},
});
</script>

View File

@ -8,11 +8,11 @@ title:
## zh-CN
使用 `defaultFileList` 设置已上传的内容
使用 `fileList` 设置已上传的内容
## en-US
Use `defaultFileList` for uploaded files when page init.
Use `fileList` for uploaded files when page init.
</docs>
<template>

View File

@ -10,13 +10,13 @@ title:
把文件拖入指定区域完成上传同样支持点击上传
设置 `multiple` `IE10+` 可以一次上传多个文件
设置 `multiple` 可以一次上传多个文件
## en-US
You can drag files to a specific area, to upload. Alternatively, you can also upload by selecting.
We can upload serveral files at once in modern browsers by giving the input the `multiple` attribute.
We can upload serveral files at once by giving the input the `multiple` attribute.
</docs>
<template>
@ -26,6 +26,7 @@ We can upload serveral files at once in modern browsers by giving the input the
:multiple="true"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
@change="handleChange"
@drop="handleDrop"
>
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
@ -62,6 +63,9 @@ export default defineComponent({
return {
handleChange,
fileList: ref([]),
handleDrop: (e: DragEvent) => {
console.log(e);
},
};
},
});

View File

@ -11,6 +11,11 @@
<Directory />
<PreviewFile />
<TransformFile />
<customizeProgressBarVue />
<maxCountVue />
<uploadCustomActionIconVue />
<uploadPngOnlyVue />
<customRenderVue />
</demo-sort>
</template>
<script lang="ts">
@ -25,6 +30,11 @@ import UploadManually from './upload-manually.vue';
import Directory from './directory.vue';
import PreviewFile from './preview-file.vue';
import TransformFile from './transform-file.vue';
import customizeProgressBarVue from './customize-progress-bar.vue';
import maxCountVue from './max-count.vue';
import uploadCustomActionIconVue from './upload-custom-action-icon.vue';
import uploadPngOnlyVue from './upload-png-only.vue';
import customRenderVue from './custom-render.vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
import { defineComponent } from 'vue';
@ -44,6 +54,11 @@ export default defineComponent({
Directory,
PreviewFile,
TransformFile,
customizeProgressBarVue,
maxCountVue,
uploadCustomActionIconVue,
uploadPngOnlyVue,
customRenderVue,
},
setup() {
return {};

View File

@ -0,0 +1,63 @@
<docs>
---
order: 10
title:
zh-CN: 限制数量
en-US: Max Count
---
## zh-CN
通过 `maxCount` 限制上传数量当为 `1` 始终用最新上传的代替当前
## en-US
Limit files with `maxCount`. Will replace current one when `maxCount` is `1`.
</docs>
<template>
<a-space direction="vertical" style="width: 100%" size="large">
<a-upload
v-model:file-list="fileList"
list-type="picture"
:max-count="1"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
>
<a-button>
<upload-outlined></upload-outlined>
Upload (Max: 1)
</a-button>
</a-upload>
<a-upload
v-model:file-list="fileList2"
list-type="picture"
:max-count="3"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
>
<a-button>
<upload-outlined></upload-outlined>
Upload (Max: 3)
</a-button>
</a-upload>
</a-space>
</template>
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const fileList = ref<UploadProps['fileList']>([]);
const fileList2 = ref<UploadProps['fileList']>([]);
return {
fileList,
fileList2,
};
},
});
</script>

View File

@ -25,10 +25,10 @@ After users upload picture, the thumbnail will be shown in list. The upload butt
>
<div v-if="fileList.length < 8">
<plus-outlined />
<div class="ant-upload-text">Upload</div>
<div style="margin-top: 8px">Upload</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<a-modal :visible="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
@ -36,7 +36,7 @@ After users upload picture, the thumbnail will be shown in list. The upload butt
<script lang="ts">
import { PlusOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
import type { UploadProps } from 'ant-design-vue';
function getBase64(file: File) {
return new Promise((resolve, reject) => {
@ -52,8 +52,9 @@ export default defineComponent({
PlusOutlined,
},
setup() {
const previewVisible = ref<boolean>(false);
const previewImage = ref<string | undefined>('');
const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');
const fileList = ref<UploadProps['fileList']>([
{
@ -80,6 +81,13 @@ export default defineComponent({
status: 'done',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
{
uid: '-xxx',
percent: 50,
name: 'image.png',
status: 'uploading',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
{
uid: '-5',
name: 'image.png',
@ -89,6 +97,7 @@ export default defineComponent({
const handleCancel = () => {
previewVisible.value = false;
previewTitle.value = '';
};
const handlePreview = async (file: UploadProps['fileList'][number]) => {
if (!file.url && !file.preview) {
@ -96,9 +105,7 @@ export default defineComponent({
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
};
const handleChange = ({ fileList: newFileList }: UploadChangeParam) => {
fileList.value = newFileList;
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
return {
@ -107,7 +114,7 @@ export default defineComponent({
fileList,
handleCancel,
handlePreview,
handleChange,
previewTitle,
};
},
});

View File

@ -8,11 +8,11 @@ title:
## zh-CN
上传文件为图片可展示本地缩略图`IE8/9` 不支持浏览器本地缩略图展示[Ref](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL) `thumbUrl`
上传文件为图片可展示本地缩略图
## en-US
If uploaded file is a picture, the thumbnail can be shown. `IE8/9` do not support local thumbnail show. Please use `thumbUrl` instead.
If uploaded file is a picture, the thumbnail can be shown.
</docs>
<template>
@ -99,10 +99,7 @@ export default defineComponent({
width: 200px;
margin-right: 8px;
}
.upload-list-inline :deep(.ant-upload-animate-enter) {
animation-name: uploadAnimateInlineIn;
}
.upload-list-inline :deep(.ant-upload-animate-leave) {
animation-name: uploadAnimateInlineOut;
.upload-list-inline [class*='-upload-list-rtl'] :deep(.ant-upload-list-item) {
float: right;
}
</style>

View File

@ -33,13 +33,14 @@ Customize local preview. Can handle with non-image format files such as video.
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const previewFile = async (file: any): Promise<Response> => {
const previewFile: UploadProps['previewFile'] = async file => {
console.log('Your upload file:', file);
// Your process logic. Here we just mock to the same file
const res = await fetch('https://next.json-generator.com/api/json/get/4ytyBoLK8', {

View File

@ -20,7 +20,7 @@ Use `beforeUpload` for transform file before request such as add a watermark.
<a-upload
v-model:file-list="fileList"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:transform-file="transformFile"
:before-upload="beforeUpload"
>
<a-button>
<upload-outlined></upload-outlined>
@ -32,33 +32,37 @@ Use `beforeUpload` for transform file before request such as add a watermark.
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const transformFile = (file: any) => {
const beforeUpload: UploadProps['beforeUpload'] = file => {
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const canvas = document.createElement('canvas');
const img: HTMLImageElement = document.createElement('img');
img.src = reader.result as string;
img.onload = () => {
const ctx: CanvasRenderingContext2D = canvas.getContext('2d')!;
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
ctx.fillStyle = 'red';
ctx.textBaseline = 'middle';
ctx.fillText('Ant Design', 20, 20);
ctx.font = '33px Arial';
ctx.fillText('Ant Design Vue', 20, 20);
canvas.toBlob(resolve);
};
};
});
};
return {
transformFile,
beforeUpload,
fileList: ref([]),
};
},

View File

@ -0,0 +1,81 @@
<docs>
---
order: 12
title:
zh-CN: 自定义交互图标
en-US: custom action icon
---
## zh-CN
使用相应插槽设置列表交互图标
## en-US
Use slot for custom action icons of files.
</docs>
<template>
<a-upload
v-model:file-list="fileList"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:show-upload-list="{ showDownloadIcon: true, showRemoveIcon: true }"
@change="handleChange"
>
<a-button>
<upload-outlined></upload-outlined>
Upload
</a-button>
<template #downloadIcon>download</template>
<template #removeIcon><StarOutlined @click="handleClick"></StarOutlined></template>
</a-upload>
</template>
<script lang="ts">
import { UploadOutlined, StarOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
StarOutlined,
},
setup() {
const fileList = ref<UploadProps['fileList']>([
{
uid: '1',
name: 'xxx.png',
status: 'done',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/xxx.png',
},
{
uid: '2',
name: 'yyy.png',
status: 'done',
url: 'http://www.baidu.com/yyy.png',
},
{
uid: '3',
name: 'zzz.png',
status: 'error',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/zzz.png',
},
]);
const handleChange = ({ file, fileList }: UploadChangeParam) => {
if (file.status !== 'uploading') {
console.log(file, fileList);
}
};
return {
fileList,
handleChange,
handleClick: (e: MouseEvent) => {
console.log(e, 'custom removeIcon event');
},
};
},
});
</script>

View File

@ -17,7 +17,7 @@ Upload files manually after `beforeUpload` returns `false`.
<template>
<div class="clearfix">
<a-upload :file-list="fileList" :remove="handleRemove" :before-upload="beforeUpload">
<a-upload :file-list="fileList" :before-upload="beforeUpload" @remove="handleRemove">
<a-button>
<upload-outlined></upload-outlined>
Select File

View File

@ -0,0 +1,85 @@
<docs>
---
order: 7.1
title:
zh-CN: 只上传 png 图片
en-US: Upload png file only
---
## zh-CN
`beforeUpload` 返回 `false` `Promise.reject` 只用于拦截上传行为不会阻止文件进入上传列表[原因](https://github.com/ant-design/ant-design/issues/15561#issuecomment-475108235) `Upload.LIST_IGNORE`
## en-US
`beforeUpload` only prevent upload behavior when return false or reject promise, the prevented file would still show in file list. Here is the example you can keep prevented files out of list by return `UPLOAD.LIST_IGNORE`.
</docs>
<template>
<a-upload
v-model:file-list="fileList"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:before-upload="beforeUpload"
@change="handleChange"
>
<a-button>
<upload-outlined></upload-outlined>
Upload png only
</a-button>
</a-upload>
</template>
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
import { message, Upload } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const fileList = ref<UploadProps['fileList']>([
{
uid: '1',
name: 'xxx.png',
status: 'done',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/xxx.png',
},
{
uid: '2',
name: 'yyy.png',
status: 'done',
url: 'http://www.baidu.com/yyy.png',
},
{
uid: '3',
name: 'zzz.png',
status: 'error',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/zzz.png',
},
]);
const handleChange = ({ file, fileList }: UploadChangeParam) => {
if (file.status !== 'uploading') {
console.log(file, fileList);
}
};
const beforeUpload: UploadProps['beforeUpload'] = file => {
const isPNG = file.type === 'image/png';
if (!isPNG) {
message.error(`${file.name} is not a png file`);
}
return isPNG || Upload.LIST_IGNORE;
};
return {
fileList,
handleChange,
beforeUpload,
};
},
});
</script>

View File

@ -18,12 +18,12 @@ Uploading is the process of publishing information (web pages, text, pictures, v
## API
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| --- | --- | --- | --- | --- | --- |
| accept | File types that can be accepted. See [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept) | string | - | |
| action | Uploading URL | string\|(file) => `Promise` | - | |
| method | http method of upload request | string | `post` | 1.5.0 |
| directory | support upload whole directory ([caniuse](https://caniuse.com/#feat=input-file-directory)) | boolean | false | |
| beforeUpload | Hook function which will be executed before uploading. Uploading will be stopped with `false` or a rejected Promise returned. **Warningthis function is not supported in IE9**| (file, fileList) => `boolean | Promise` | - | |
| beforeUpload | Hook function which will be executed before uploading. Uploading will be stopped with `false` or a rejected Promise returned. | (file, fileList) => `boolean | Promise` | - | |
| customRequest | override for the default xhr behavior allowing for additional customization and ability to implement your own XMLHttpRequest | Function | - | |
| data | Uploading params or function which can return uploading params. | object\|function(file) | - | |
| disabled | disable upload button | boolean | false | |
@ -33,12 +33,20 @@ Uploading is the process of publishing information (web pages, text, pictures, v
| multiple | Whether to support selected multiple file. `IE10+` supported. You can select multiple files with CTRL holding down while multiple is set to be true | boolean | false | |
| name | The name of uploading file | string | `file` | |
| previewFile | Customize preview file logic | (file: File \| Blob) => Promise<dataURL: string> | - | 1.5.0 |
| showUploadList | Whether to show default upload list, could be an object to specify `showPreviewIcon` and `showRemoveIcon` individually | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean } | true | |
| showUploadList | Whether to show default upload list, could be an object to specify `showPreviewIcon` and `showRemoveIcon` individually | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: booleanshowDownloadIcon?: boolean } | true | showDownloadIcon(3.0) |
| supportServerRender | Need to be turned on while the server side is rendering. | boolean | false | |
| withCredentials | ajax upload with cookie sent | boolean | false | |
| openFileDialogOnClick | click open file dialog | boolean | true | |
| remove | A callback function, will be executed when removing file button is clicked, remove event will be prevented when return value is `false` or a Promise which resolve(false) or reject. | Function(file): `boolean | Promise` | - | |
| transformFile   | Customize transform file before request | Function(file): `string | Blob | File | Promise<string | Blob | File>` | - | 1.5.0 |
| directory | Support upload whole directory[caniuse](https://caniuse.com/#feat=input-file-directory) | boolean | false | 3.0 |
| iconRender | Custom show icon | v-slot:iconRender="{file: UploadFile, listType?: UploadListType}" | - | 3.0 |
| isImageUrl | Customize if render &lt;img /> in thumbnail | (file: UploadFile) => boolean | - | 3.0 |
| itemRender | Custom item of uploadList | v-slot:itemRender="{originNode: ReactElement, file: UploadFile, fileList: object\[], actions: { download: function, preview: function, remove: function }" | - | 3.0 |
| maxCount | Limit the number of uploaded files. Will replace current one when `maxCount` is `1` | number | - | 3.0 |
| openFileDialogOnClick | Click open file dialog | boolean | true | 3.0 |
| progress | Custom progress bar | [ProgressProps](/components/progress/#API) (support `type="line"` only) | { strokeWidth: 2, showInfo: false } | 3.0 |
| previewIcon | custom preview icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 |
| removeIcon | custom remove icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 |
| downloadIcon | custom download icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 |
### events
@ -48,6 +56,21 @@ Uploading is the process of publishing information (web pages, text, pictures, v
| preview | A callback function, will be executed when file link or preview icon is clicked. | Function(file) | - | |
| download | Click the method to download the file, pass the method to perform the method logic, do not pass the default jump to the new TAB. | Function(file): void | Jump to new TAB | 1.5.0 |
| reject | A callback function, will be executed when drop files is not accept. | Function(fileList) | - | |
| drop | A callback function executed when files are dragged and dropped into upload area | (event: DragEvent) => void | - | 3.0 |
| remove   | A callback function, will be executed when removing file button is clicked, remove event will be prevented when return value is false or a Promise which resolve(false) or reject | function(file): boolean \| Promise | -   | 3.0 |
### UploadFile
Extends File with additional props.
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| name | File name | string | - |
| percent | Upload progress percent | number | - |
| status | Upload status. Show different style when configured | `error` \| `success` \| `done` \| `uploading` \| `removed` | - |
| thumbUrl | Thumb image url | string | - |
| uid | unique id. Will auto generate when not provided | string | - |
| url | Download url | string | - |
### change
@ -78,3 +101,26 @@ When uploading state change, it returns:
2. `fileList` current list of files
3. `event` response from server, including uploading progress, supported by advanced browsers.
## FAQ
### How to implement upload server side?
- You can consult [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload/wiki#server-side) about how to implement server side upload interface.
- There is a mock example of [express](https://github.com/react-component/upload/blob/master/server.js) in rc-upload.
### I want to display download links.
Please set property `url` of each item in `fileList` to control content of link.
### How to use `customRequest`?
See <https://github.com/react-component/upload#customrequest>.
### Why `fileList` in control will not trigger `change` `status` update when file not in the list?
`change` only trigger when file in the list, it will ignore left events when removed from the list. Please note that there exist bug which makes event still trigger even the file is not in the list before `3.0.0-beta.10`.
### Why sometime `change` return File object and sometime return { originFileObj: File }?
For compatible case, we return File object when `beforeUpload` return `false`. It will merge to `{ originFileObj: File }` in next major version. Current version is compatible to get origin file by `info.file.originFileObj`. You can change this before major release.

View File

@ -1,21 +1,18 @@
import type { App, Plugin } from 'vue';
import Upload from './Upload';
import type { App } from 'vue';
import Upload, { LIST_IGNORE } from './Upload';
import Dragger from './Dragger';
export type { UploadProps, UploadListProps, UploadChangeParam } from './interface';
Upload.Dragger = Dragger;
export type { UploadProps, UploadListProps, UploadChangeParam, UploadFile } from './interface';
/* istanbul ignore next */
Upload.install = function (app: App) {
app.component(Upload.name, Upload);
app.component(Dragger.name, Dragger);
return app;
};
export const UploadDragger = Dragger;
export default Upload as typeof Upload &
Plugin & {
readonly Dragger: typeof Dragger;
};
export default Object.assign(Upload, {
Dragger,
LIST_IGNORE,
install(app: App) {
app.component(Upload.name, Upload);
app.component(Dragger.name, Dragger);
return app;
},
});

View File

@ -19,12 +19,12 @@ cover: https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg
## API
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| --- | --- | --- | --- | --- | --- |
| accept | 接受上传的文件类型, 详见 [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept) | string | 无 | |
| action | 上传的地址 | string\|(file) => `Promise` | 无 | |
| method | 上传请求的 http method | string | `post` | 1.5.0 |
| directory | 支持上传文件夹([caniuse](https://caniuse.com/#feat=input-file-directory) | boolean | false | |
| beforeUpload | 上传文件之前的钩子,参数为上传的文件,若返回 `false` 则停止上传。支持返回一个 Promise 对象Promise 对象 reject 时则停止上传resolve 时开始上传( resolve 传入 `File``Blob` 对象则上传 resolve 传入对象)。**注意IE9 不支持该方法**。 | (file, fileList) => `boolean | Promise` | 无 | |
| beforeUpload | 上传文件之前的钩子,参数为上传的文件,若返回 `false` 则停止上传。支持返回一个 Promise 对象Promise 对象 reject 时则停止上传resolve 时开始上传( resolve 传入 `File``Blob` 对象则上传 resolve 传入对象)。 | (file, fileList) => `boolean | Promise` | 无 | |
| customRequest | 通过覆盖默认的上传行为,可以自定义自己的上传实现 | Function | 无 | |
| data | 上传所需参数或返回上传参数的方法 | object\|(file) => object | 无 | |
| disabled | 是否禁用 | boolean | false | |
@ -34,12 +34,20 @@ cover: https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg
| multiple | 是否支持多选文件,`ie10+` 支持。开启后按住 ctrl 可选择多个文件。 | boolean | false | |
| name | 发到后台的文件参数名 | string | `file` | |
| previewFile | 自定义文件预览逻辑 | (file: File \| Blob) => Promise<dataURL: string> | 无 | 1.5.0 |
| showUploadList | 是否展示 uploadList, 可设为一个对象,用于单独设定 showPreviewIcon 和 showRemoveIcon | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean } | true | |
| showUploadList | 是否展示 uploadList, 可设为一个对象,用于单独设定 showPreviewIcon 和 showRemoveIcon | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean, showDownloadIcon?: boolean } | true | showDownloadIcon(3.0) |
| supportServerRender | 服务端渲染时需要打开这个 | boolean | false | |
| withCredentials | 上传请求时是否携带 cookie | boolean | false | |
| openFileDialogOnClick | 点击打开文件对话框 | boolean | true | |
| remove   | 点击移除文件时的回调,返回值为 false 时不移除。支持返回一个 Promise 对象Promise 对象 resolve(false) 或 reject 时不移除。               | Function(file): `boolean | Promise` | 无   | |
| transformFile   | 在上传之前转换文件。支持返回一个 Promise 对象   | Function(file): `string | Blob | File | Promise<string | Blob | File>` | 无   | 1.5.0 |
| directory | 支持上传文件夹([caniuse](https://caniuse.com/#feat=input-file-directory) | boolean | false | 3.0 |
| iconRender | 自定义显示 icon | v-slot:iconRender="{file: UploadFile, listType?: UploadListType}" | - | 3.0 |
| isImageUrl | 自定义缩略图是否使用 &lt;img /> 标签进行显示 | (file: UploadFile) => boolean | - | 3.0 |
| itemRender | 自定义上传列表项 | v-slot:itemRender="{originNode: ReactElement, file: UploadFile, fileList: object\[], actions: { download: function, preview: function, remove: function }" | - | 3.0 |
| maxCount | 限制上传数量。当为 1 时,始终用最新上传的文件代替当前文件 | number | - | 3.0 |
| openFileDialogOnClick | 点击打开文件对话框 | boolean | true | 3.0 |
| progress | 自定义进度条样式 | [ProgressProps](/components/progress/#API)(仅支持 `type="line"` | { strokeWidth: 2, showInfo: false } | 3.0 |
| previewIcon | 自定义预览 icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 |
| removeIcon | 自定义删除 icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 |
| downloadIcon | 自定义下载 icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 |
### 事件
@ -49,6 +57,21 @@ cover: https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg
| preview | 点击文件链接或预览图标时的回调 | Function(file) | 无 | |
| download | 点击下载文件时的回调,如果没有指定,则默认跳转到文件 url 对应的标签页。 | Function(file): void | 跳转新标签页 | 1.5.0 |
| reject | 拖拽文件不符合 accept 类型时的回调 | Function(fileList) | 无 | |
| drop | 当文件被拖入上传区域时执行的回调功能 | (event: DragEvent) => void | - | 3.0 |
| remove   | 点击移除文件时的回调,返回值为 false 时不移除。支持返回一个 Promise 对象Promise 对象 resolve(false) 或 reject 时不移除 | function(file): boolean \| Promise | -   | 3.0 |
### UploadFile
继承自 File附带额外属性用于渲染。
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| name | 文件名 | string | - |
| percent | 上传进度 | number | - |
| status | 上传状态,不同状态展示颜色也会有所不同 | `error` \| `success` \| `done` \| `uploading` \| `removed` | - |
| thumbUrl | 缩略图地址 | string | - |
| uid | 唯一标识符,不设置时会自动生成 | string | - |
| url | 下载地址 | string | - |
### change
@ -79,3 +102,26 @@ cover: https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg
2. `fileList` 当前的文件列表。
3. `event` 上传中的服务端响应内容,包含了上传进度等信息,高级浏览器支持。
## FAQ
### 服务端如何实现?
- 服务端上传接口实现可以参考 [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload/wiki#server-side)。
- 如果要做本地 mock 可以参考这个 [express 的例子](https://github.com/react-component/upload/blob/master/server.js)。
### 如何显示下载链接?
请使用 fileList 属性设置数组项的 url 属性进行展示控制。
### `customRequest` 怎么使用?
请参考 <https://github.com/react-component/upload#customrequest>
### 为何 `fileList` 受控时,上传不在列表中的文件不会触发 `onChange` 后续的 `status` 更新事件?
`onChange` 事件仅会作用于在列表中的文件,因而 `fileList` 不存在对应文件时后续事件会被忽略。请注意,在 `3.0.0-beta.10` 版本之前受控状态存在 bug 导致不在列表中的文件也会触发。
### `onChange` 为什么有时候返回 File 有时候返回 { originFileObj: File }
历史原因,在 `beforeUpload` 返回 `false` 时,会返回 File 对象。在下个大版本我们会统一返回 `{ originFileObj: File }` 对象。当前版本已经兼容所有场景下 `info.file.originFileObj` 获取原 File 写法。你可以提前切换。

View File

@ -1,22 +1,21 @@
import type { ExtractPropTypes, PropType } from 'vue';
import { tuple } from '../_util/type';
import PropsTypes from '../_util/vue-types';
import type {
RcFile as OriRcFile,
UploadRequestOption as RcCustomRequestOptions,
} from '../vc-upload/interface';
import type { ProgressProps } from '../progress';
import type { VueNode } from '../_util/type';
import type { ExtractPropTypes, PropType, CSSProperties } from 'vue';
export const UploadFileStatus = PropsTypes.oneOf(
tuple('error', 'success', 'done', 'uploading', 'removed'),
);
export interface FileType extends OriRcFile {
readonly lastModifiedDate: Date;
}
export type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed';
export interface HttpRequestHeader {
[key: string]: string;
}
export interface VcFile extends File {
uid: string;
readonly lastModifiedDate: Date;
readonly webkitRelativePath: string;
}
export type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed';
export interface UploadFile<T = any> {
uid: string;
size?: number;
@ -28,7 +27,7 @@ export interface UploadFile<T = any> {
status?: UploadFileStatus;
percent?: number;
thumbUrl?: string;
originFileObj?: any;
originFileObj?: FileType;
response?: T;
error?: any;
linkProps?: any;
@ -37,17 +36,23 @@ export interface UploadFile<T = any> {
preview?: string;
}
export interface UploadChangeParam<T extends object = UploadFile> {
export interface InternalUploadFile<T = any> extends UploadFile<T> {
originFileObj: FileType;
}
export interface ShowUploadListInterface {
showRemoveIcon?: boolean;
showPreviewIcon?: boolean;
showDownloadIcon?: boolean;
}
export interface UploadChangeParam<T = UploadFile> {
// https://github.com/ant-design/ant-design/issues/14420
file: T;
fileList: UploadFile[];
event?: { percent: number };
}
export const ShowUploadListInterface = PropsTypes.shape({
showRemoveIcon: PropsTypes.looseBool,
showPreviewIcon: PropsTypes.looseBool,
}).loose;
export interface UploadLocale {
uploading?: string;
removeFile?: string;
@ -56,61 +61,129 @@ export interface UploadLocale {
previewFile?: string;
}
export const uploadProps = {
type: PropsTypes.oneOf(tuple('drag', 'select')),
name: PropsTypes.string,
defaultFileList: { type: Array as PropType<UploadFile[]> },
fileList: { type: Array as PropType<UploadFile[]> },
action: PropsTypes.oneOfType([PropsTypes.string, PropsTypes.func]),
directory: PropsTypes.looseBool,
data: PropsTypes.oneOfType([PropsTypes.object, PropsTypes.func]),
method: PropsTypes.oneOf(tuple('POST', 'PUT', 'PATCH', 'post', 'put', 'patch')),
headers: PropsTypes.object,
showUploadList: PropsTypes.oneOfType([PropsTypes.looseBool, ShowUploadListInterface]),
multiple: PropsTypes.looseBool,
accept: PropsTypes.string,
beforeUpload: PropsTypes.func,
listType: PropsTypes.oneOf(tuple('text', 'picture', 'picture-card')),
// className: PropsTypes.string,
remove: PropsTypes.func,
supportServerRender: PropsTypes.looseBool,
// style: PropsTypes.object,
disabled: PropsTypes.looseBool,
prefixCls: PropsTypes.string,
customRequest: PropsTypes.func,
withCredentials: PropsTypes.looseBool,
openFileDialogOnClick: PropsTypes.looseBool,
locale: { type: Object as PropType<UploadLocale> },
height: PropsTypes.number,
id: PropsTypes.string,
previewFile: PropsTypes.func,
transformFile: PropsTypes.func,
onChange: { type: Function as PropType<(info: UploadChangeParam) => void> },
onPreview: { type: Function as PropType<(file: UploadFile) => void> },
onRemove: {
type: Function as PropType<(file: UploadFile) => void | boolean | Promise<void | boolean>>,
},
onDownload: { type: Function as PropType<(file: UploadFile) => void> },
'onUpdate:fileList': { type: Function as PropType<(files: UploadFile[]) => void> },
export type UploadType = 'drag' | 'select';
export type UploadListType = 'text' | 'picture' | 'picture-card';
export type UploadListProgressProps = Omit<ProgressProps, 'percent' | 'type'> & {
class?: string;
style?: CSSProperties;
};
export type UploadProps = Partial<ExtractPropTypes<typeof uploadProps>>;
export const uploadListProps = {
listType: PropsTypes.oneOf(tuple('text', 'picture', 'picture-card')),
// items: PropsTypes.arrayOf(UploadFile),
items: { type: Array as PropType<UploadFile[]> },
progressAttr: PropsTypes.object,
prefixCls: PropsTypes.string,
showRemoveIcon: PropsTypes.looseBool,
showDownloadIcon: PropsTypes.looseBool,
showPreviewIcon: PropsTypes.looseBool,
locale: { type: Object as PropType<UploadLocale> },
previewFile: PropsTypes.func,
onPreview: { type: Function as PropType<(file: UploadFile) => void> },
onRemove: {
type: Function as PropType<(file: UploadFile) => void | boolean>,
},
onDownload: { type: Function as PropType<(file: UploadFile) => void> },
};
export type ItemRender<T = any> = (opt: {
originNode: VueNode;
file: UploadFile;
fileList: Array<UploadFile<T>>;
actions: {
download: () => void;
preview: () => void;
remove: () => void;
};
}) => VueNode;
export type UploadListProps = Partial<ExtractPropTypes<typeof uploadListProps>>;
type PreviewFileHandler = (file: FileType | Blob) => PromiseLike<string>;
type TransformFileHandler = (
file: FileType,
) => string | Blob | FileType | PromiseLike<string | Blob | FileType>;
type BeforeUploadValueType = void | boolean | string | Blob | FileType;
function uploadProps<T = any>() {
return {
capture: [Boolean, String] as PropType<boolean | 'user' | 'environment'>,
type: String as PropType<UploadType>,
name: String,
defaultFileList: Array as PropType<Array<UploadFile<T>>>,
fileList: Array as PropType<Array<UploadFile<T>>>,
action: [String, Function] as PropType<
string | ((file: FileType) => string) | ((file: FileType) => PromiseLike<string>)
>,
directory: { type: Boolean, default: undefined },
data: [Object, Function] as PropType<
| Record<string, unknown>
| ((file: UploadFile<T>) => Record<string, unknown> | Promise<Record<string, unknown>>)
>,
method: String as PropType<'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch'>,
headers: Object as PropType<HttpRequestHeader>,
showUploadList: {
type: [Boolean, Object] as PropType<boolean | ShowUploadListInterface>,
default: undefined as boolean | ShowUploadListInterface,
},
multiple: { type: Boolean, default: undefined },
accept: String,
beforeUpload: Function as PropType<
(
file: FileType,
FileList: FileType[],
) => BeforeUploadValueType | Promise<BeforeUploadValueType>
>,
onChange: Function as PropType<(info: UploadChangeParam<T>) => void>,
'onUpdate:fileList': Function as PropType<(fileList: UploadChangeParam<T>['fileList']) => void>,
onDrop: Function as PropType<(event: DragEvent) => void>,
listType: String as PropType<UploadListType>,
onPreview: Function as PropType<(file: UploadFile<T>) => void>,
onDownload: Function as PropType<(file: UploadFile<T>) => void>,
onReject: Function as PropType<(fileList: FileType[]) => void>,
onRemove: Function as PropType<
(file: UploadFile<T>) => void | boolean | Promise<void | boolean>
>,
/** @deprecated Please use `onRemove` directly */
remove: Function as PropType<(file: UploadFile<T>) => void | boolean | Promise<void | boolean>>,
supportServerRender: { type: Boolean, default: undefined },
disabled: { type: Boolean, default: undefined },
prefixCls: String,
customRequest: Function as PropType<(options: RcCustomRequestOptions) => void>,
withCredentials: { type: Boolean, default: undefined },
openFileDialogOnClick: { type: Boolean, default: undefined },
locale: { type: Object as PropType<UploadLocale>, default: undefined as UploadLocale },
id: String,
previewFile: Function as PropType<PreviewFileHandler>,
/** @deprecated Please use `beforeUpload` directly */
transformFile: Function as PropType<TransformFileHandler>,
iconRender: Function as PropType<
(opt: { file: UploadFile<T>; listType?: UploadListType }) => VueNode
>,
isImageUrl: Function as PropType<(file: UploadFile) => boolean>,
progress: Object as PropType<UploadListProgressProps>,
itemRender: Function as PropType<ItemRender<T>>,
/** Config max count of `fileList`. Will replace current one when `maxCount` is 1 */
maxCount: Number,
height: [Number, String],
removeIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
downloadIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
previewIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
};
}
export type UploadProps = Partial<ExtractPropTypes<ReturnType<typeof uploadProps>>>;
export interface UploadState<T = any> {
fileList: UploadFile<T>[];
dragState: string;
}
function uploadListProps<T = any>() {
return {
listType: String as PropType<UploadListType>,
onPreview: Function as PropType<(file: UploadFile<T>) => void>,
onDownload: Function as PropType<(file: UploadFile<T>) => void>,
onRemove: Function as PropType<(file: UploadFile<T>) => void | boolean>,
items: Array as PropType<Array<UploadFile<T>>>,
progress: Object as PropType<UploadListProgressProps>,
prefixCls: String as PropType<string>,
showRemoveIcon: { type: Boolean, default: undefined },
showDownloadIcon: { type: Boolean, default: undefined },
showPreviewIcon: { type: Boolean, default: undefined },
removeIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
downloadIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
previewIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
locale: { type: Object as PropType<UploadLocale>, default: undefined as UploadLocale },
previewFile: Function as PropType<PreviewFileHandler>,
iconRender: Function as PropType<
(opt: { file: UploadFile<T>; listType?: UploadListType }) => VueNode
>,
isImageUrl: Function as PropType<(file: UploadFile) => boolean>,
appendAction: Function as PropType<() => VueNode>,
itemRender: Function as PropType<ItemRender<T>>,
};
}
export type UploadListProps = Partial<ExtractPropTypes<ReturnType<typeof uploadListProps>>>;
export { uploadProps, uploadListProps };

View File

@ -34,8 +34,6 @@
}
&&-select-picture-card {
display: table;
float: left;
width: @upload-picture-card-size;
height: @upload-picture-card-size;
margin-right: 8px;
@ -46,19 +44,21 @@
border: @border-width-base dashed @border-color-base;
border-radius: @border-radius-base;
cursor: pointer;
transition: border-color 0.3s ease;
transition: border-color 0.3s;
> .@{upload-prefix-cls} {
display: table-cell;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 8px;
text-align: center;
vertical-align: middle;
}
&:hover {
border-color: @primary-color;
.@{upload-prefix-cls}-disabled& {
border-color: @border-color-base;
}
}
}
@ -74,7 +74,7 @@
transition: border-color 0.3s;
.@{upload-prefix-cls} {
padding: 16px 0;
padding: @padding-md 0;
}
&.@{upload-prefix-cls}-drag-hover:not(.@{upload-prefix-cls}-disabled) {
@ -116,10 +116,12 @@
color: @text-color-secondary;
font-size: @font-size-base;
}
.@{iconfont-css-prefix}-plus {
color: @disabled-color;
font-size: 30px;
transition: all 0.3s;
&:hover {
color: @text-color-secondary;
}
@ -140,52 +142,55 @@
.@{upload-prefix-cls}-list {
.reset-component();
.clearfix();
&-item-list-type-text {
&:hover {
.@{upload-prefix-cls}-list-item-name-icon-count-1 {
padding-right: 14px;
}
.@{upload-prefix-cls}-list-item-name-icon-count-2 {
padding-right: 28px;
}
}
}
line-height: @line-height-base;
// ============================ Item ============================
&-item {
position: relative;
height: 22px;
margin-top: 8px;
height: @line-height-base * @font-size-base;
margin-top: @margin-xs;
font-size: @font-size-base;
&-name {
display: inline-block;
width: 100%;
padding-left: @font-size-base + 8px;
overflow: hidden;
line-height: @line-height-base;
white-space: nowrap;
text-overflow: ellipsis;
}
&-name-icon-count-1 {
padding-right: 14px;
}
&-card-actions {
position: absolute;
right: 0;
opacity: 0;
&.picture {
top: 25px;
&-btn {
opacity: 0;
}
&-btn.@{ant-prefix}-btn-sm {
height: 20px;
line-height: 1;
}
&.picture {
top: 22px;
line-height: 0;
}
&-btn:focus,
&.picture &-btn {
opacity: 1;
}
.anticon {
padding-right: 6px;
color: rgba(0, 0, 0, 0.45);
.@{iconfont-css-prefix} {
color: @upload-actions-color;
}
}
&-info {
height: 100%;
padding: 0 12px 0 4px;
padding: 0 4px;
transition: background-color 0.3s;
> span {
@ -195,25 +200,27 @@
}
.@{iconfont-css-prefix}-loading,
.@{iconfont-css-prefix}-paper-clip {
position: absolute;
top: (@font-size-base / 2) - 2px;
color: @text-color-secondary;
font-size: @font-size-base;
.@{upload-prefix-cls}-text-icon {
.@{iconfont-css-prefix} {
position: absolute;
top: (@font-size-base / 2) - 2px;
color: @text-color-secondary;
font-size: @font-size-base;
}
}
}
.@{iconfont-css-prefix}-close {
.iconfont-size-under-12px(10px);
position: absolute;
top: 6px;
right: 4px;
color: @text-color-secondary;
font-size: 10px;
line-height: 0;
cursor: pointer;
opacity: 0;
transition: all 0.3s;
&:hover {
color: @text-color;
}
@ -227,21 +234,24 @@
opacity: 1;
}
&:hover &-card-actions {
&:hover &-card-actions-btn {
opacity: 1;
}
&-error,
&-error .@{iconfont-css-prefix}-paper-clip,
&-error .@{upload-prefix-cls}-text-icon > .@{iconfont-css-prefix},
&-error &-name {
color: @error-color;
}
&-error &-card-actions {
.anticon {
.@{iconfont-css-prefix} {
color: @error-color;
}
opacity: 1;
&-btn {
opacity: 1;
}
}
&-progress {
@ -254,17 +264,20 @@
}
}
// =================== Picture & Picture Card ===================
&-picture,
&-picture-card {
.@{upload-item} {
position: relative;
height: 66px;
padding: 8px;
padding: @padding-xs;
border: @border-width-base @upload-picture-card-border-style @border-color-base;
border-radius: @border-radius-base;
&:hover {
background: transparent;
}
&-error {
border-color: @error-color;
}
@ -283,15 +296,30 @@
}
.@{upload-item}-thumbnail {
position: absolute;
top: 8px;
left: 8px;
width: 48px;
height: 48px;
font-size: 26px;
line-height: 54px;
line-height: 60px;
text-align: center;
opacity: 0.8;
.@{iconfont-css-prefix} {
font-size: 26px;
}
}
// Adjust the color of the error icon : https://github.com/ant-design/ant-design/pull/24160
.@{upload-item}-error .@{upload-item}-thumbnail {
.@{iconfont-css-prefix} {
svg path {
&[fill='#e6f7ff'] {
fill: @error-color-deprecated-bg;
}
&[fill='#1890ff'] {
fill: @error-color;
}
}
}
}
.@{upload-item}-icon {
@ -300,6 +328,10 @@
left: 50%;
font-size: 26px;
transform: translate(-50%, -50%);
.@{iconfont-css-prefix} {
font-size: 26px;
}
}
.@{upload-item}-image {
@ -327,16 +359,8 @@
transition: all 0.3s;
}
.@{upload-item}-name-icon-count-1 {
padding-right: 18px;
}
.@{upload-item}-name-icon-count-2 {
padding-right: 36px;
}
.@{upload-item}-uploading .@{upload-item}-name {
line-height: 28px;
margin-bottom: 12px;
}
.@{upload-item}-progress {
@ -355,21 +379,23 @@
}
}
// ======================== Picture Card ========================
&-picture-card {
&-container {
display: inline-block;
width: @upload-picture-card-size;
height: @upload-picture-card-size;
margin: 0 @margin-xs @margin-xs 0;
vertical-align: top;
}
&.@{upload-prefix-cls}-list::after {
display: none;
}
&-container {
float: left;
width: @upload-picture-card-size;
height: @upload-picture-card-size;
margin: 0 8px 8px 0;
}
.@{upload-item} {
float: left;
width: @upload-picture-card-size;
height: @upload-picture-card-size;
margin: 0 8px 8px 0;
height: 100%;
margin: 0;
}
.@{upload-item}-info {
@ -413,6 +439,7 @@
font-size: 16px;
cursor: pointer;
transition: all 0.3s;
&:hover {
color: @text-color-inverse;
}
@ -430,7 +457,7 @@
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-fit: contain;
}
.@{upload-item}-name {
@ -441,7 +468,7 @@
text-align: center;
}
.anticon-picture + .@{upload-item}-name {
.@{upload-item}-file + .@{upload-item}-name {
position: absolute;
bottom: 10px;
display: block;
@ -454,46 +481,82 @@
.@{upload-item}-info {
height: auto;
&::before,
.@{iconfont-css-prefix}-eye-o,
.@{iconfont-css-prefix}-eye,
.@{iconfont-css-prefix}-delete {
display: none;
}
}
&-text {
margin-top: 18px;
color: @text-color-secondary;
}
}
.@{upload-item}-progress {
bottom: 32px;
width: calc(100% - 14px);
padding-left: 0;
}
}
.@{upload-prefix-cls}-success-icon {
color: @success-color;
font-weight: bold;
// ======================= Picture & Text =======================
&-text,
&-picture {
&-container {
transition: opacity @animation-duration-slow, height @animation-duration-slow;
&::before {
display: table;
width: 0;
height: 0;
content: '';
}
// Don't know why span here, just stretch it
.@{upload-prefix-cls}-span {
display: block;
flex: auto;
}
}
// text & picture no need this additional element.
// But it used for picture-card, let's keep it.
.@{upload-prefix-cls}-span {
display: flex;
align-items: center;
> * {
flex: none;
}
}
.@{upload-item}-name {
flex: auto;
margin: 0;
padding: 0 @padding-xs;
}
.@{upload-item}-card-actions {
position: static;
}
}
.@{upload-prefix-cls}-animate-enter,
.@{upload-prefix-cls}-animate-leave,
// ============================ Text ============================
&-text {
.@{upload-prefix-cls}-text-icon {
.@{iconfont-css-prefix} {
position: static;
}
}
}
// =========================== Motion ===========================
.@{upload-prefix-cls}-animate-inline-appear,
.@{upload-prefix-cls}-animate-inline-enter,
.@{upload-prefix-cls}-animate-inline-leave {
animation-duration: 0.3s;
animation-duration: @animation-duration-slow;
animation-fill-mode: @ease-in-out-circ;
}
.@{upload-prefix-cls}-animate-enter {
animation-name: uploadAnimateIn;
}
.@{upload-prefix-cls}-animate-leave {
animation-name: uploadAnimateOut;
}
.@{upload-prefix-cls}-animate-inline-appear,
.@{upload-prefix-cls}-animate-inline-enter {
animation-name: uploadAnimateInlineIn;
}
@ -503,24 +566,6 @@
}
}
@keyframes uploadAnimateIn {
from {
height: 0;
margin: 0;
padding: 0;
opacity: 0;
}
}
@keyframes uploadAnimateOut {
to {
height: 0;
margin: 0;
padding: 0;
opacity: 0;
}
}
@keyframes uploadAnimateInlineIn {
from {
width: 0;
@ -540,3 +585,5 @@
opacity: 0;
}
}
@import './rtl';

View File

@ -2,5 +2,6 @@ import '../../style/index.less';
import './index.less';
// style dependencies
import '../../button/style';
import '../../progress/style';
import '../../tooltip/style';

View File

@ -0,0 +1,179 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@upload-prefix-cls: ~'@{ant-prefix}-upload';
@upload-item: ~'@{ant-prefix}-upload-list-item';
.@{upload-prefix-cls} {
&-rtl {
direction: rtl;
}
&&-select-picture-card {
.@{upload-prefix-cls}-rtl& {
margin-right: auto;
margin-left: 8px;
}
}
}
.@{upload-prefix-cls}-list {
&-rtl {
direction: rtl;
}
&-item-list-type-text {
&:hover {
.@{upload-prefix-cls}-list-item-name-icon-count-1 {
.@{upload-prefix-cls}-list-rtl & {
padding-right: 22px;
padding-left: 14px;
}
}
.@{upload-prefix-cls}-list-item-name-icon-count-2 {
.@{upload-prefix-cls}-list-rtl & {
padding-right: 22px;
padding-left: 28px;
}
}
}
}
&-item {
&-name {
.@{upload-prefix-cls}-list-rtl & {
padding-right: @font-size-base + 8px;
padding-left: 0;
}
}
&-name-icon-count-1 {
.@{upload-prefix-cls}-list-rtl & {
padding-left: 14px;
}
}
&-card-actions {
.@{upload-prefix-cls}-list-rtl & {
right: auto;
left: 0;
}
.@{iconfont-css-prefix} {
.@{upload-prefix-cls}-list-rtl & {
padding-right: 0;
padding-left: 5px;
}
}
}
&-info {
.@{upload-prefix-cls}-list-rtl & {
padding: 0 4px 0 12px;
}
}
.@{iconfont-css-prefix}-close {
.@{upload-prefix-cls}-list-rtl & {
right: auto;
left: 4px;
}
}
&-error &-card-actions {
.@{iconfont-css-prefix} {
.@{upload-prefix-cls}-list-rtl & {
padding-right: 0;
padding-left: 5px;
}
}
}
&-progress {
.@{upload-prefix-cls}-list-rtl & {
padding-right: @font-size-base + 12px;
padding-left: 0;
}
}
}
&-picture,
&-picture-card {
.@{upload-item}-info {
padding: 0;
}
.@{upload-item}-thumbnail {
.@{upload-prefix-cls}-list-rtl& {
right: 8px;
left: auto;
}
}
.@{upload-item}-icon {
.@{upload-prefix-cls}-list-rtl& {
right: 50%;
left: auto;
transform: translate(50%, -50%);
}
}
.@{upload-item}-name {
.@{upload-prefix-cls}-list-rtl& {
margin: 0 8px 0 0;
padding-right: 48px;
padding-left: 8px;
}
}
.@{upload-item}-name-icon-count-1 {
.@{upload-prefix-cls}-list-rtl& {
padding-right: 48px;
padding-left: 18px;
}
}
.@{upload-item}-name-icon-count-2 {
.@{upload-prefix-cls}-list-rtl& {
padding-right: 48px;
padding-left: 36px;
}
}
.@{upload-item}-progress {
.@{upload-prefix-cls}-list-rtl& {
padding-right: 0;
padding-left: 0;
}
}
.@{iconfont-css-prefix}-close {
.@{upload-prefix-cls}-list-rtl& {
right: auto;
left: 8px;
}
}
}
&-picture-card {
&-container {
.@{upload-prefix-cls}-list-rtl & {
margin: 0 0 @margin-xs @margin-xs;
}
}
.@{upload-item}-actions {
.@{upload-prefix-cls}-list-rtl& {
right: 50%;
left: auto;
transform: translate(50%, -50%);
}
}
.@{upload-item}-file + .@{upload-item}-name {
.@{upload-prefix-cls}-list-rtl& {
margin: 8px 0 0;
padding: 0;
}
}
}
}

View File

@ -1,10 +1,6 @@
export function T() {
return true;
}
import type { FileType, UploadFile, InternalUploadFile } from './interface';
// Fix IE file.status problem
// via coping a new Object
export function fileToObject(file) {
export function file2Obj(file: FileType): InternalUploadFile {
return {
...file,
lastModified: file.lastModified,
@ -18,35 +14,24 @@ export function fileToObject(file) {
};
}
/**
* 生成Progress percent: 0.1 -> 0.98
* - for ie
*/
export function genPercentAdd() {
let k = 0.1;
const i = 0.01;
const end = 0.98;
return function (s) {
let start = s;
if (start >= end) {
return start;
}
start += k;
k = k - i;
if (k < 0.001) {
k = 0.001;
}
return start;
};
/** Upload fileList. Replace file if exist or just push into it. */
export function updateFileList(file: UploadFile<any>, fileList: UploadFile<any>[]) {
const nextFileList = [...fileList];
const fileIndex = nextFileList.findIndex(({ uid }: UploadFile) => uid === file.uid);
if (fileIndex === -1) {
nextFileList.push(file);
} else {
nextFileList[fileIndex] = file;
}
return nextFileList;
}
export function getFileItem(file, fileList) {
export function getFileItem(file: FileType, fileList: UploadFile[]) {
const matchKey = file.uid !== undefined ? 'uid' : 'name';
return fileList.filter(item => item[matchKey] === file[matchKey])[0];
}
export function removeFileItem(file, fileList) {
export function removeFileItem(file: UploadFile, fileList: UploadFile[]) {
const matchKey = file.uid !== undefined ? 'uid' : 'name';
const removed = fileList.filter(item => item[matchKey] !== file[matchKey]);
if (removed.length === fileList.length) {
@ -63,13 +48,13 @@ const extname = (url = '') => {
return (/\.[^./\\]*$/.exec(filenameWithoutSuffix) || [''])[0];
};
const isImageFileType = type => !!type && type.indexOf('image/') === 0;
const isImageFileType = (type: string): boolean => type.indexOf('image/') === 0;
export const isImageUrl = file => {
if (isImageFileType(file.type)) {
return true;
export const isImageUrl = (file: UploadFile): boolean => {
if (file.type && !file.thumbUrl) {
return isImageFileType(file.type);
}
const url = file.thumbUrl || file.url;
const url: string = (file.thumbUrl || file.url || '') as string;
const extension = extname(url);
if (
/^data:image\//.test(url) ||
@ -89,9 +74,9 @@ export const isImageUrl = file => {
};
const MEASURE_SIZE = 200;
export function previewImage(file) {
export function previewImage(file: File | Blob): Promise<string> {
return new Promise(resolve => {
if (!isImageFileType(file.type)) {
if (!file.type || !isImageFileType(file.type)) {
resolve('');
return;
}
@ -111,7 +96,7 @@ export function previewImage(file) {
let offsetX = 0;
let offsetY = 0;
if (width < height) {
if (width > height) {
drawHeight = height * (MEASURE_SIZE / width);
offsetY = -(drawHeight - drawWidth) / 2;
} else {
@ -119,7 +104,7 @@ export function previewImage(file) {
offsetX = -(drawWidth - drawHeight) / 2;
}
ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight);
ctx!.drawImage(img, offsetX, offsetY, drawWidth, drawHeight);
const dataURL = canvas.toDataURL();
document.body.removeChild(canvas);

View File

@ -0,0 +1,317 @@
import defaultRequest from './request';
import getUid from './uid';
import attrAccept from './attr-accept';
import traverseFileTree from './traverseFileTree';
import type {
RcFile,
UploadProgressEvent,
UploadRequestError,
BeforeUploadFileType,
} from './interface';
import { uploadProps } from './interface';
import { defineComponent, onBeforeUnmount, onMounted, ref } from 'vue';
import type { ChangeEvent } from '../_util/EventInterface';
import pickAttrs from '../_util/pickAttrs';
import partition from 'lodash-es/partition';
interface ParsedFileInfo {
origin: RcFile;
action: string;
data: Record<string, unknown>;
parsedFile: RcFile;
}
export default defineComponent({
name: 'AjaxUploader',
inheritAttrs: false,
props: uploadProps(),
setup(props, { slots, attrs, expose }) {
const uid = ref(getUid());
const reqs: any = {};
const fileInput = ref<HTMLInputElement>();
let isMounted = false;
/**
* Process file before upload. When all the file is ready, we start upload.
*/
const processFile = async (file: RcFile, fileList: RcFile[]): Promise<ParsedFileInfo> => {
const { beforeUpload } = props;
let transformedFile: BeforeUploadFileType | void = file;
if (beforeUpload) {
try {
transformedFile = await beforeUpload(file, fileList);
} catch (e) {
// Rejection will also trade as false
transformedFile = false;
}
if (transformedFile === false) {
return {
origin: file,
parsedFile: null,
action: null,
data: null,
};
}
}
// Get latest action
const { action } = props;
let mergedAction: string;
if (typeof action === 'function') {
mergedAction = await action(file);
} else {
mergedAction = action;
}
// Get latest data
const { data } = props;
let mergedData: Record<string, unknown>;
if (typeof data === 'function') {
mergedData = await data(file);
} else {
mergedData = data;
}
const parsedData =
// string type is from legacy `transformFile`.
// Not sure if this will work since no related test case works with it
(typeof transformedFile === 'object' || typeof transformedFile === 'string') &&
transformedFile
? transformedFile
: file;
let parsedFile: File;
if (parsedData instanceof File) {
parsedFile = parsedData;
} else {
parsedFile = new File([parsedData], file.name, { type: file.type });
}
const mergedParsedFile: RcFile = parsedFile as RcFile;
mergedParsedFile.uid = file.uid;
return {
origin: file,
data: mergedData,
parsedFile: mergedParsedFile,
action: mergedAction,
};
};
const post = ({ data, origin, action, parsedFile }: ParsedFileInfo) => {
if (!isMounted) {
return;
}
const { onStart, customRequest, name, headers, withCredentials, method } = props;
const { uid } = origin;
const request = customRequest || defaultRequest;
const requestOption = {
action,
filename: name,
data,
file: parsedFile,
headers,
withCredentials,
method: method || 'post',
onProgress: (e: UploadProgressEvent) => {
const { onProgress } = props;
onProgress?.(e, parsedFile);
},
onSuccess: (ret: any, xhr: XMLHttpRequest) => {
const { onSuccess } = props;
onSuccess?.(ret, parsedFile, xhr);
delete reqs[uid];
},
onError: (err: UploadRequestError, ret: any) => {
const { onError } = props;
onError?.(err, ret, parsedFile);
delete reqs[uid];
},
};
onStart(origin);
reqs[uid] = request(requestOption);
};
const reset = () => {
uid.value = getUid();
};
const abort = (file?: any) => {
if (file) {
const uid = file.uid ? file.uid : file;
if (reqs[uid] && reqs[uid].abort) {
reqs[uid].abort();
}
delete reqs[uid];
} else {
Object.keys(reqs).forEach(uid => {
if (reqs[uid] && reqs[uid].abort) {
reqs[uid].abort();
}
delete reqs[uid];
});
}
};
onMounted(() => {
isMounted = true;
});
onBeforeUnmount(() => {
isMounted = false;
abort();
});
const uploadFiles = (files: File[]) => {
const originFiles = [...files] as RcFile[];
const postFiles = originFiles.map((file: RcFile & { uid?: string }) => {
// eslint-disable-next-line no-param-reassign
file.uid = getUid();
return processFile(file, originFiles);
});
// Batch upload files
Promise.all(postFiles).then(fileList => {
const { onBatchStart } = props;
onBatchStart?.(fileList.map(({ origin, parsedFile }) => ({ file: origin, parsedFile })));
fileList
.filter(file => file.parsedFile !== null)
.forEach(file => {
post(file);
});
});
};
const onChange = (e: ChangeEvent) => {
const { accept, directory } = props;
const { files } = e.target as any;
const acceptedFiles = [...files].filter(
(file: RcFile) => !directory || attrAccept(file, accept),
);
uploadFiles(acceptedFiles);
reset();
};
const onClick = (e: MouseEvent | KeyboardEvent) => {
const el = fileInput.value;
if (!el) {
return;
}
const { onClick } = props;
// TODO
// if (children && (children as any).type === 'button') {
// const parent = el.parentNode as HTMLInputElement;
// parent.focus();
// parent.querySelector('button').blur();
// }
el.click();
if (onClick) {
onClick(e);
}
};
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Enter') {
onClick(e);
}
};
const onFileDrop = (e: DragEvent) => {
const { multiple } = props;
e.preventDefault();
if (e.type === 'dragover') {
return;
}
if (props.directory) {
traverseFileTree(
Array.prototype.slice.call(e.dataTransfer.items),
uploadFiles,
(_file: RcFile) => attrAccept(_file, props.accept),
);
} else {
const files: [RcFile[], RcFile[]] = partition(
Array.prototype.slice.call(e.dataTransfer.files),
(file: RcFile) => attrAccept(file, props.accept),
);
let successFiles = files[0];
const errorFiles = files[1];
if (multiple === false) {
successFiles = successFiles.slice(0, 1);
}
uploadFiles(successFiles);
if (errorFiles.length && props.onReject) props.onReject(errorFiles);
}
};
expose({
abort,
});
return () => {
const {
componentTag: Tag,
prefixCls,
disabled,
id,
multiple,
accept,
capture,
directory,
openFileDialogOnClick,
onMouseenter,
onMouseleave,
...otherProps
} = props;
const cls = {
[prefixCls]: true,
[`${prefixCls}-disabled`]: disabled,
[attrs.class as string]: !!attrs.class,
};
// because input don't have directory/webkitdirectory type declaration
const dirProps: any = directory
? { directory: 'directory', webkitdirectory: 'webkitdirectory' }
: {};
const events = disabled
? {}
: {
onClick: openFileDialogOnClick ? onClick : () => {},
onKeydown: openFileDialogOnClick ? onKeyDown : () => {},
onMouseenter,
onMouseleave,
onDrop: onFileDrop,
onDragover: onFileDrop,
tabindex: '0',
};
return (
<Tag {...events} class={cls} role="button" style={attrs.style}>
<input
{...pickAttrs(otherProps, { aria: true, data: true })}
id={id}
type="file"
ref={fileInput}
onClick={e => e.stopPropagation()} // https://github.com/ant-design/ant-design/issues/19948
key={uid.value}
style={{ display: 'none' }}
accept={accept}
{...dirProps}
multiple={multiple}
onChange={onChange}
{...(capture != null ? { capture } : {})}
/>
{slots.default?.()}
</Tag>
);
};
},
});

View File

@ -0,0 +1,41 @@
import { defineComponent, ref } from 'vue';
import { initDefaultProps } from '../_util/props-util';
import AjaxUpload from './AjaxUploader';
import type { RcFile } from './interface';
import { uploadProps } from './interface';
function empty() {}
export default defineComponent({
name: 'Upload',
inheritAttrs: false,
props: initDefaultProps(uploadProps(), {
componentTag: 'span',
prefixCls: 'rc-upload',
data: {},
headers: {},
name: 'file',
multipart: false,
onStart: empty,
onError: empty,
onSuccess: empty,
multiple: false,
beforeUpload: null,
customRequest: null,
withCredentials: false,
openFileDialogOnClick: true,
}),
setup(props, { slots, attrs, expose }) {
const uploader = ref();
const abort = (file: RcFile) => {
uploader.value?.abort(file);
};
expose({
abort,
});
return () => {
return <AjaxUpload {...props} {...attrs} v-slots={slots} ref={uploader} />;
};
},
});

View File

@ -0,0 +1,53 @@
import { warning } from '../vc-util/warning';
import type { RcFile } from './interface';
export default (file: RcFile, acceptedFiles: string | string[]) => {
if (file && acceptedFiles) {
const acceptedFilesArray = Array.isArray(acceptedFiles)
? acceptedFiles
: acceptedFiles.split(',');
const fileName = file.name || '';
const mimeType = file.type || '';
const baseMimeType = mimeType.replace(/\/.*$/, '');
return acceptedFilesArray.some(type => {
const validType = type.trim();
// This is something like */*,* allow all files
if (/^\*(\/\*)?$/.test(type)) {
return true;
}
// like .jpg, .png
if (validType.charAt(0) === '.') {
const lowerFileName = fileName.toLowerCase();
const lowerType = validType.toLowerCase();
let affixList = [lowerType];
if (lowerType === '.jpg' || lowerType === '.jpeg') {
affixList = ['.jpg', '.jpeg'];
}
return affixList.some(affix => lowerFileName.endsWith(affix));
}
// This is something like a image/* mime type
if (/\/\*$/.test(validType)) {
return baseMimeType === validType.replace(/\/.*$/, '');
}
// Full match
if (mimeType === validType) {
return true;
}
// Invalidate type should skip
if (/^\w+$/.test(validType)) {
warning(false, `Upload takes an invalidate 'accept' type '${validType}'.Skip for check.`);
return true;
}
return false;
});
}
return true;
};

View File

@ -1,4 +0,0 @@
// rc-upload 2.9.4
import upload from './src';
export default upload;

View File

@ -0,0 +1,7 @@
// rc-upload 4.3.3
import Upload from './Upload';
import type { UploadProps } from './interface';
export type { UploadProps };
export default Upload;

View File

@ -0,0 +1,83 @@
import type { ExtractPropTypes, PropType } from 'vue';
export type BeforeUploadFileType = File | Blob | boolean | string;
export type Action = string | ((file: RcFile) => string | PromiseLike<string>);
export const uploadProps = () => {
return {
capture: [Boolean, String] as PropType<boolean | 'user' | 'environment'>,
multipart: { type: Boolean, default: undefined },
name: String,
disabled: { type: Boolean, default: undefined },
componentTag: String as PropType<any>,
action: [String, Function] as PropType<Action>,
method: String as PropType<UploadRequestMethod>,
directory: { type: Boolean, default: undefined },
data: [Object, Function] as PropType<
Record<string, unknown> | ((file: RcFile | string | Blob) => Record<string, unknown>)
>,
headers: Object as PropType<UploadRequestHeader>,
accept: String,
multiple: { type: Boolean, default: undefined },
onBatchStart: Function as PropType<
(fileList: { file: RcFile; parsedFile: Exclude<BeforeUploadFileType, boolean> }[]) => void
>,
onReject: Function as PropType<(fileList: RcFile[]) => void>,
onStart: Function as PropType<(file: RcFile) => void>,
onError: Function as PropType<
(error: Error, ret: Record<string, unknown>, file: RcFile) => void
>,
onSuccess: Function as PropType<
(response: Record<string, unknown>, file: RcFile, xhr: XMLHttpRequest) => void
>,
onProgress: Function as PropType<(event: UploadProgressEvent, file: RcFile) => void>,
beforeUpload: Function as PropType<
(
file: RcFile,
FileList: RcFile[],
) => BeforeUploadFileType | Promise<void | BeforeUploadFileType>
>,
customRequest: Function as PropType<(option: UploadRequestOption) => void>,
withCredentials: { type: Boolean, default: undefined },
openFileDialogOnClick: { type: Boolean, default: undefined },
prefixCls: String,
id: String,
onMouseenter: Function as PropType<(e: MouseEvent) => void>,
onMouseleave: Function as PropType<(e: MouseEvent) => void>,
onClick: Function as PropType<(e: MouseEvent | KeyboardEvent) => void>,
};
};
export type UploadProps = Partial<ExtractPropTypes<ReturnType<typeof uploadProps>>>;
export interface UploadProgressEvent extends Partial<ProgressEvent> {
percent?: number;
}
export type UploadRequestMethod = 'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch';
export type UploadRequestHeader = Record<string, string>;
export interface UploadRequestError extends Error {
status?: number;
method?: UploadRequestMethod;
url?: string;
}
export interface UploadRequestOption<T = any> {
onProgress?: (event: UploadProgressEvent) => void;
onError?: (event: UploadRequestError | ProgressEvent, body?: T) => void;
onSuccess?: (body: T, xhr?: XMLHttpRequest) => void;
data?: Record<string, unknown>;
filename?: string;
file: Exclude<BeforeUploadFileType, File | boolean> | RcFile;
withCredentials?: boolean;
action: string;
headers?: UploadRequestHeader;
method: UploadRequestMethod;
}
export interface RcFile extends File {
uid: string;
}

View File

@ -1,13 +1,15 @@
function getError(option, xhr) {
import type { UploadRequestOption, UploadRequestError, UploadProgressEvent } from './interface';
function getError(option: UploadRequestOption, xhr: XMLHttpRequest) {
const msg = `cannot ${option.method} ${option.action} ${xhr.status}'`;
const err = new Error(msg);
const err = new Error(msg) as UploadRequestError;
err.status = xhr.status;
err.method = option.method;
err.url = option.action;
return err;
}
function getBody(xhr) {
function getBody(xhr: XMLHttpRequest) {
const text = xhr.responseText || xhr.response;
if (!text) {
return text;
@ -20,22 +22,12 @@ function getBody(xhr) {
}
}
// option {
// onProgress: (event: { percent: number }): void,
// onError: (event: Error, body?: Object): void,
// onSuccess: (body: Object): void,
// data: Object,
// filename: String,
// file: File,
// withCredentials: Boolean,
// action: String,
// headers: Object,
// }
export default function upload(option) {
const xhr = new window.XMLHttpRequest();
export default function upload(option: UploadRequestOption) {
// eslint-disable-next-line no-undef
const xhr = new XMLHttpRequest();
if (option.onProgress && xhr.upload) {
xhr.upload.onprogress = function progress(e) {
xhr.upload.onprogress = function progress(e: UploadProgressEvent) {
if (e.total > 0) {
e.percent = (e.loaded / e.total) * 100;
}
@ -43,7 +35,8 @@ export default function upload(option) {
};
}
const formData = new window.FormData();
// eslint-disable-next-line no-undef
const formData = new FormData();
if (option.data) {
Object.keys(option.data).forEach(key => {
@ -58,11 +51,16 @@ export default function upload(option) {
return;
}
formData.append(key, option.data[key]);
formData.append(key, value as string | Blob);
});
}
formData.append(option.filename, option.file);
// eslint-disable-next-line no-undef
if (option.file instanceof Blob) {
formData.append(option.filename, option.file, (option.file as any).name);
} else {
formData.append(option.filename, option.file);
}
xhr.onerror = function error(e) {
option.onError(e);
@ -75,7 +73,7 @@ export default function upload(option) {
return option.onError(getError(option, xhr), getBody(xhr));
}
option.onSuccess(getBody(xhr), xhr);
return option.onSuccess(getBody(xhr), xhr);
};
xhr.open(option.method, option.action, true);
@ -93,11 +91,12 @@ export default function upload(option) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
for (const h in headers) {
if (headers.hasOwnProperty(h) && headers[h] !== null) {
Object.keys(headers).forEach(h => {
if (headers[h] !== null) {
xhr.setRequestHeader(h, headers[h]);
}
}
});
xhr.send(formData);
return {

View File

@ -1,262 +0,0 @@
import PropTypes from '../../_util/vue-types';
import BaseMixin from '../../_util/BaseMixin';
import partition from 'lodash-es/partition';
import classNames from '../../_util/classNames';
import defaultRequest from './request';
import getUid from './uid';
import attrAccept from './attr-accept';
import traverseFileTree from './traverseFileTree';
import { getSlot } from '../../_util/props-util';
const upLoadPropTypes = {
componentTag: PropTypes.string,
// style: PropTypes.object,
prefixCls: PropTypes.string,
name: PropTypes.string,
// className: PropTypes.string,
multiple: PropTypes.looseBool,
directory: PropTypes.looseBool,
disabled: PropTypes.looseBool,
accept: PropTypes.string,
// children: PropTypes.any,
// onStart: PropTypes.func,
data: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
action: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
headers: PropTypes.object,
beforeUpload: PropTypes.func,
customRequest: PropTypes.func,
// onProgress: PropTypes.func,
withCredentials: PropTypes.looseBool,
openFileDialogOnClick: PropTypes.looseBool,
transformFile: PropTypes.func,
method: PropTypes.string,
};
const AjaxUploader = {
inheritAttrs: false,
name: 'ajaxUploader',
mixins: [BaseMixin],
props: upLoadPropTypes,
data() {
this.reqs = {};
return {
uid: getUid(),
};
},
mounted() {
this._isMounted = true;
},
beforeUnmount() {
this._isMounted = false;
this.abort();
},
methods: {
onChange(e) {
const files = e.target.files;
this.uploadFiles(files);
this.reset();
},
onClick() {
const el = this.$refs.fileInputRef;
if (!el) {
return;
}
el.click();
},
onKeyDown(e) {
if (e.key === 'Enter') {
this.onClick();
}
},
onFileDrop(e) {
const { multiple } = this.$props;
e.preventDefault();
if (e.type === 'dragover') {
return;
}
if (this.directory) {
traverseFileTree(e.dataTransfer.items, this.uploadFiles, _file =>
attrAccept(_file, this.accept),
);
} else {
let files = partition(Array.prototype.slice.call(e.dataTransfer.files), file =>
attrAccept(file, this.accept),
);
let successFiles = files[0];
const errorFiles = files[1];
if (multiple === false) {
successFiles = successFiles.slice(0, 1);
}
this.uploadFiles(successFiles);
if (errorFiles.length) {
this.__emit('reject', errorFiles);
}
}
},
uploadFiles(files) {
const postFiles = Array.prototype.slice.call(files);
postFiles
.map(file => {
file.uid = getUid();
return file;
})
.forEach(file => {
this.upload(file, postFiles);
});
},
upload(file, fileList) {
if (!this.beforeUpload) {
// always async in case use react state to keep fileList
return setTimeout(() => this.post(file), 0);
}
const before = this.beforeUpload(file, fileList);
if (before && before.then) {
before
.then(processedFile => {
const processedFileType = Object.prototype.toString.call(processedFile);
if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
return this.post(processedFile);
}
return this.post(file);
})
.catch(e => {
console && console.log(e); // eslint-disable-line
});
} else if (before !== false) {
setTimeout(() => this.post(file), 0);
}
},
post(file) {
if (!this._isMounted) {
return;
}
const { $props: props } = this;
let { data } = props;
const { transformFile = originFile => originFile } = props;
new Promise(resolve => {
const { action } = this;
if (typeof action === 'function') {
return resolve(action(file));
}
resolve(action);
}).then(action => {
const { uid } = file;
const request = this.customRequest || defaultRequest;
const transform = Promise.resolve(transformFile(file)).catch(e => {
console.error(e); // eslint-disable-line no-console
});
transform.then(transformedFile => {
if (typeof data === 'function') {
data = data(file);
}
const requestOption = {
action,
filename: this.name,
data,
file: transformedFile,
headers: this.headers,
withCredentials: this.withCredentials,
method: props.method || 'post',
onProgress: e => {
this.__emit('progress', e, file);
},
onSuccess: (ret, xhr) => {
delete this.reqs[uid];
this.__emit('success', ret, file, xhr);
},
onError: (err, ret) => {
delete this.reqs[uid];
this.__emit('error', err, ret, file);
},
};
this.reqs[uid] = request(requestOption);
this.__emit('start', file);
});
});
},
reset() {
this.setState({
uid: getUid(),
});
},
abort(file) {
const { reqs } = this;
if (file) {
let uid = file;
if (file && file.uid) {
uid = file.uid;
}
if (reqs[uid] && reqs[uid].abort) {
reqs[uid].abort();
}
delete reqs[uid];
} else {
Object.keys(reqs).forEach(uid => {
if (reqs[uid] && reqs[uid].abort) {
reqs[uid].abort();
}
delete reqs[uid];
});
}
},
},
render() {
const { $props, $attrs } = this;
const {
componentTag: Tag,
prefixCls,
disabled,
multiple,
accept,
directory,
openFileDialogOnClick,
} = $props;
const { class: className, style, id } = $attrs;
const cls = classNames({
[prefixCls]: true,
[`${prefixCls}-disabled`]: disabled,
[className]: className,
});
const events = disabled
? {}
: {
onClick: openFileDialogOnClick ? this.onClick : () => {},
onKeydown: openFileDialogOnClick ? this.onKeyDown : () => {},
onDrop: this.onFileDrop,
onDragover: this.onFileDrop,
};
const tagProps = {
...events,
role: 'button',
tabindex: disabled ? null : '0',
class: cls,
style,
};
return (
<Tag {...tagProps}>
<input
id={id}
type="file"
ref="fileInputRef"
onClick={e => e.stopPropagation()} // https://github.com/ant-design/ant-design/issues/19948
key={this.uid}
style={{ display: 'none' }}
accept={accept}
directory={directory ? 'directory' : null}
webkitdirectory={directory ? 'webkitdirectory' : null}
multiple={multiple}
onChange={this.onChange}
/>
{getSlot(this)}
</Tag>
);
},
};
export default AjaxUploader;

View File

@ -1,281 +0,0 @@
import PropTypes from '../../_util/vue-types';
import BaseMixin from '../../_util/BaseMixin';
import classNames from '../../_util/classNames';
import getUid from './uid';
import warning from '../../_util/warning';
import { getSlot, findDOMNode } from '../../_util/props-util';
const IFRAME_STYLE = {
position: 'absolute',
top: 0,
opacity: 0,
filter: 'alpha(opacity=0)',
left: 0,
zIndex: 9999,
};
// diferent from AjaxUpload, can only upload on at one time, serial seriously
const IframeUploader = {
name: 'IframeUploader',
mixins: [BaseMixin],
props: {
componentTag: PropTypes.string,
// style: PropTypes.object,
disabled: PropTypes.looseBool,
prefixCls: PropTypes.string,
// className: PropTypes.string,
accept: PropTypes.string,
// onStart: PropTypes.func,
multiple: PropTypes.looseBool,
// children: PropTypes.any,
data: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
action: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
name: PropTypes.string,
},
data() {
this.file = {};
return {
uploading: false,
};
},
methods: {
onLoad() {
if (!this.uploading) {
return;
}
const { file } = this;
let response;
try {
const doc = this.getIframeDocument();
const script = doc.getElementsByTagName('script')[0];
if (script && script.parentNode === doc.body) {
doc.body.removeChild(script);
}
response = doc.body.innerHTML;
this.__emit('success', response, file);
} catch (err) {
warning(
false,
'cross domain error for Upload. Maybe server should return document.domain script. see Note from https://github.com/react-component/upload',
);
response = 'cross-domain';
this.__emit('error', err, null, file);
}
this.endUpload();
},
onChange() {
const target = this.getFormInputNode();
// ie8/9 don't support FileList Object
// http://stackoverflow.com/questions/12830058/ie8-input-type-file-get-files
const file = (this.file = {
uid: getUid(),
name:
target.value &&
target.value.substring(target.value.lastIndexOf('\\') + 1, target.value.length),
});
this.startUpload();
const { $props: props } = this;
if (!props.beforeUpload) {
return this.post(file);
}
const before = props.beforeUpload(file);
if (before && before.then) {
before.then(
() => {
this.post(file);
},
() => {
this.endUpload();
},
);
} else if (before !== false) {
this.post(file);
} else {
this.endUpload();
}
},
getIframeNode() {
return this.$refs.iframeRef;
},
getIframeDocument() {
return this.getIframeNode().contentDocument;
},
getFormNode() {
return this.getIframeDocument().getElementById('form');
},
getFormInputNode() {
return this.getIframeDocument().getElementById('input');
},
getFormDataNode() {
return this.getIframeDocument().getElementById('data');
},
getFileForMultiple(file) {
return this.multiple ? [file] : file;
},
getIframeHTML(domain) {
let domainScript = '';
let domainInput = '';
if (domain) {
const script = 'script';
domainScript = `<${script}>document.domain="${domain}";</${script}>`;
domainInput = `<input name="_documentDomain" value="${domain}" />`;
}
return `
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<style>
body,html {padding:0;margin:0;border:0;overflow:hidden;}
</style>
${domainScript}
</head>
<body>
<form method="post"
encType="multipart/form-data"
action="" id="form"
style="display:block;height:9999px;position:relative;overflow:hidden;">
<input id="input" type="file"
name="${this.name}"
style="position:absolute;top:0;right:0;height:9999px;font-size:9999px;cursor:pointer;"/>
${domainInput}
<span id="data"></span>
</form>
</body>
</html>
`;
},
initIframeSrc() {
if (this.domain) {
this.getIframeNode().src = `javascript:void((function(){
var d = document;
d.open();
d.domain='${this.domain}';
d.write('');
d.close();
})())`;
}
},
initIframe() {
const iframeNode = this.getIframeNode();
let win = iframeNode.contentWindow;
let doc;
this.domain = this.domain || '';
this.initIframeSrc();
try {
doc = win.document;
} catch (e) {
this.domain = document.domain;
this.initIframeSrc();
win = iframeNode.contentWindow;
doc = win.document;
}
doc.open('text/html', 'replace');
doc.write(this.getIframeHTML(this.domain));
doc.close();
this.getFormInputNode().onchange = this.onChange;
},
endUpload() {
if (this.uploading) {
this.file = {};
// hack avoid batch
this.uploading = false;
this.setState({
uploading: false,
});
this.initIframe();
}
},
startUpload() {
if (!this.uploading) {
this.uploading = true;
this.setState({
uploading: true,
});
}
},
updateIframeWH() {
const rootNode = findDOMNode(this);
const iframeNode = this.getIframeNode();
iframeNode.style.height = `${rootNode.offsetHeight}px`;
iframeNode.style.width = `${rootNode.offsetWidth}px`;
},
abort(file) {
if (file) {
let uid = file;
if (file && file.uid) {
uid = file.uid;
}
if (uid === this.file.uid) {
this.endUpload();
}
} else {
this.endUpload();
}
},
post(file) {
const formNode = this.getFormNode();
const dataSpan = this.getFormDataNode();
let { data } = this.$props;
if (typeof data === 'function') {
data = data(file);
}
const inputs = document.createDocumentFragment();
for (const key in data) {
if (data.hasOwnProperty(key)) {
const input = document.createElement('input');
input.setAttribute('name', key);
input.value = data[key];
inputs.appendChild(input);
}
}
dataSpan.appendChild(inputs);
new Promise(resolve => {
const { action } = this;
if (typeof action === 'function') {
return resolve(action(file));
}
resolve(action);
}).then(action => {
formNode.setAttribute('action', action);
formNode.submit();
dataSpan.innerHTML = '';
this.__emit('start', file);
});
},
},
mounted() {
this.$nextTick(() => {
this.updateIframeWH();
this.initIframe();
});
},
updated() {
this.$nextTick(() => {
this.updateIframeWH();
});
},
render() {
const { componentTag: Tag, disabled, prefixCls } = this.$props;
const { class: className, style } = this.$attrs;
const iframeStyle = {
...IFRAME_STYLE,
display: this.uploading || disabled ? 'none' : '',
};
const cls = classNames({
[prefixCls]: true,
[`${prefixCls}-disabled`]: disabled,
[className]: className,
});
return (
<Tag class={cls} style={{ position: 'relative', zIndex: 0, ...style }}>
<iframe ref="iframeRef" onLoad={this.onLoad} style={iframeStyle} />
{getSlot(this)}
</Tag>
);
},
};
export default IframeUploader;

View File

@ -1,97 +0,0 @@
import PropTypes from '../../_util/vue-types';
import { initDefaultProps, getSlot } from '../../_util/props-util';
import BaseMixin from '../../_util/BaseMixin';
import AjaxUpload from './AjaxUploader';
import IframeUpload from './IframeUploader';
import { defineComponent, nextTick } from 'vue';
function empty() {}
const uploadProps = {
componentTag: PropTypes.string,
prefixCls: PropTypes.string,
action: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
name: PropTypes.string,
multipart: PropTypes.looseBool,
directory: PropTypes.looseBool,
onError: PropTypes.func,
onSuccess: PropTypes.func,
onProgress: PropTypes.func,
onStart: PropTypes.func,
data: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
headers: PropTypes.object,
accept: PropTypes.string,
multiple: PropTypes.looseBool,
disabled: PropTypes.looseBool,
beforeUpload: PropTypes.func,
customRequest: PropTypes.func,
onReady: PropTypes.func,
withCredentials: PropTypes.looseBool,
supportServerRender: PropTypes.looseBool,
openFileDialogOnClick: PropTypes.looseBool,
method: PropTypes.string,
};
export default defineComponent({
name: 'Upload',
mixins: [BaseMixin],
inheritAttrs: false,
props: initDefaultProps(uploadProps, {
componentTag: 'span',
prefixCls: 'rc-upload',
data: {},
headers: {},
name: 'file',
multipart: false,
onReady: empty,
onStart: empty,
onError: empty,
onSuccess: empty,
supportServerRender: false,
multiple: false,
beforeUpload: empty,
withCredentials: false,
openFileDialogOnClick: true,
}),
data() {
this.Component = null;
return {
// Component: null, //
};
},
mounted() {
this.$nextTick(() => {
if (this.supportServerRender) {
this.Component = this.getComponent();
this.$forceUpdate();
nextTick(() => {
this.__emit('ready');
});
}
});
},
methods: {
getComponent() {
return typeof File !== 'undefined' ? AjaxUpload : IframeUpload;
},
abort(file) {
this.$refs.uploaderRef.abort(file);
},
},
render() {
const componentProps = {
...this.$props,
ref: 'uploaderRef',
...this.$attrs,
};
if (this.supportServerRender) {
const ComponentUploader = this.Component;
if (ComponentUploader) {
return <ComponentUploader {...componentProps}>{getSlot(this)}</ComponentUploader>;
}
return null;
}
const ComponentUploader = this.getComponent();
return <ComponentUploader {...componentProps}>{getSlot(this)}</ComponentUploader>;
},
});

View File

@ -1,26 +0,0 @@
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
export default (file, acceptedFiles) => {
if (file && acceptedFiles) {
const acceptedFilesArray = Array.isArray(acceptedFiles)
? acceptedFiles
: acceptedFiles.split(',');
const fileName = file.name || '';
const mimeType = file.type || '';
const baseMimeType = mimeType.replace(/\/.*$/, '');
return acceptedFilesArray.some(type => {
const validType = type.trim();
if (validType.charAt(0) === '.') {
return endsWith(fileName.toLowerCase(), validType.toLowerCase());
} else if (/\/\*$/.test(validType)) {
// This is something like a image/* mime type
return baseMimeType === validType.replace(/\/.*$/, '');
}
return mimeType === validType;
});
}
return true;
};

View File

@ -1,4 +0,0 @@
// export this package's api
import Upload from './Upload';
export default Upload;

View File

@ -1,9 +1,21 @@
function loopFiles(item, callback) {
import type { RcFile } from './interface';
interface InternalDataTransferItem extends DataTransferItem {
isFile: boolean;
file: (cd: (file: RcFile & { webkitRelativePath?: string }) => void) => void;
createReader: () => any;
fullPath: string;
isDirectory: boolean;
name: string;
path: string;
}
function loopFiles(item: InternalDataTransferItem, callback) {
const dirReader = item.createReader();
let fileList = [];
function sequence() {
dirReader.readEntries(entries => {
dirReader.readEntries((entries: InternalDataTransferItem[]) => {
const entryList = Array.prototype.slice.apply(entries);
fileList = fileList.concat(entryList);
@ -21,9 +33,11 @@ function loopFiles(item, callback) {
sequence();
}
const traverseFileTree = (files, callback, isAccepted) => {
const _traverseFileTree = (item, path) => {
path = path || '';
const traverseFileTree = (files: InternalDataTransferItem[], callback, isAccepted) => {
// eslint-disable-next-line @typescript-eslint/naming-convention
const _traverseFileTree = (item: InternalDataTransferItem, path?: string) => {
// eslint-disable-next-line no-param-reassign
item.path = path || '';
if (item.isFile) {
item.file(file => {
if (isAccepted(file)) {
@ -34,7 +48,8 @@ const traverseFileTree = (files, callback, isAccepted) => {
writable: true,
},
});
file.webkitRelativePath = item.fullPath.replace(/^\//, '');
// eslint-disable-next-line no-param-reassign
(file as any).webkitRelativePath = item.fullPath.replace(/^\//, '');
Object.defineProperties(file, {
webkitRelativePath: {
writable: false,
@ -45,16 +60,16 @@ const traverseFileTree = (files, callback, isAccepted) => {
}
});
} else if (item.isDirectory) {
loopFiles(item, entries => {
loopFiles(item, (entries: InternalDataTransferItem[]) => {
entries.forEach(entryItem => {
_traverseFileTree(entryItem, `${path}${item.name}/`);
});
});
}
};
for (const file of files) {
_traverseFileTree(file.webkitGetAsEntry());
}
files.forEach(file => {
_traverseFileTree(file.webkitGetAsEntry() as any);
});
};
export default traverseFileTree;

View File

@ -2,5 +2,6 @@ const now = +new Date();
let index = 0;
export default function uid() {
// eslint-disable-next-line no-plusplus
return `vc-upload-${now}-${++index}`;
}

View File

@ -222,7 +222,6 @@
"vue-antd-md-loader": "^1.2.1-beta.1",
"vue-clipboard2": "0.3.3",
"vue-drag-resize": "^2.0.3",
"vue-draggable-resizable": "^2.1.0",
"vue-eslint-parser": "^8.0.0",
"vue-i18n": "^9.1.7",
"vue-infinite-scroll": "^2.0.2",

View File

@ -1,5 +1,5 @@
// debugger tsx
import Demo from '../../components/form/demo/normal-login.vue';
import Demo from '../../components/upload/demo/defaultFileList.vue';
// import Demo from './demo/demo.vue';
export default {