From 662984fb3e07a4629a1a72122080725fe9599987 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Wed, 23 Feb 2022 23:05:40 +0800 Subject: [PATCH] refactor: upload --- .../__tests__/__snapshots__/demo.test.js.snap | 19 +- .../__tests__/__snapshots__/demo.test.js.snap | 6 +- components/upload old/Dragger.tsx | 22 - components/upload old/Upload.tsx | 342 ----------- components/upload old/UploadList.tsx | 284 --------- .../__tests__/__snapshots__/demo.test.js.snap | 126 ---- .../__snapshots__/uploadlist.test.js.snap | 75 --- components/upload old/__tests__/demo.test.js | 3 - components/upload old/__tests__/mock.js | 14 - components/upload old/__tests__/requests.js | 11 - .../upload old/__tests__/upload.test.js | 331 ----------- .../upload old/__tests__/uploadlist.test.js | 433 -------------- components/upload old/demo/avatar.vue | 116 ---- components/upload old/demo/directory.vue | 35 -- components/upload old/demo/drag.vue | 68 --- components/upload old/demo/fileList.vue | 81 --- components/upload old/demo/index.vue | 52 -- components/upload old/demo/picture-card.vue | 126 ---- components/upload old/demo/picture-style.vue | 108 ---- components/upload old/demo/preview-file.vue | 58 -- components/upload old/demo/transform-file.vue | 66 --- .../upload old/demo/upload-manually.vue | 96 ---- components/upload old/index.en-US.md | 80 --- components/upload old/index.tsx | 21 - components/upload old/index.zh-CN.md | 81 --- components/upload old/interface.tsx | 116 ---- components/upload old/style/index.less | 542 ------------------ components/upload old/utils.jsx | 130 ----- components/upload/Upload.tsx | 67 ++- components/upload/UploadList/ListItem.tsx | 1 - components/upload/UploadList/index.tsx | 9 +- .../__tests__/__snapshots__/demo.test.js.snap | 337 ++++++++--- .../__snapshots__/uploadlist.test.js.snap | 102 ++-- components/upload/__tests__/upload.test.js | 32 +- .../upload/__tests__/uploadlist.test.js | 2 +- components/upload/demo/avatar.vue | 2 +- components/upload/demo/custom-render.vue | 93 +++ .../demo/customize-progress-bar.vue} | 25 +- components/upload/demo/defaultFileList.vue | 4 +- components/upload/demo/drag.vue | 8 +- components/upload/demo/index.vue | 15 + components/upload/demo/max-count.vue | 63 ++ components/upload/demo/picture-style.vue | 4 +- components/upload/demo/preview-file.vue | 3 +- components/upload/demo/transform-file.vue | 16 +- .../demo/upload-custom-action-icon.vue} | 25 +- components/upload/demo/upload-manually.vue | 2 +- components/upload/demo/upload-png-only.vue | 85 +++ components/upload/index.en-US.md | 56 +- components/upload/index.zh-CN.md | 56 +- components/upload/interface.tsx | 31 +- components/upload/utils.tsx | 6 +- components/vc-upload/AjaxUploader.tsx | 14 +- components/vc-upload/interface.tsx | 1 + package.json | 1 - 55 files changed, 834 insertions(+), 3668 deletions(-) delete mode 100644 components/upload old/Dragger.tsx delete mode 100644 components/upload old/Upload.tsx delete mode 100644 components/upload old/UploadList.tsx delete mode 100644 components/upload old/__tests__/__snapshots__/demo.test.js.snap delete mode 100644 components/upload old/__tests__/__snapshots__/uploadlist.test.js.snap delete mode 100644 components/upload old/__tests__/demo.test.js delete mode 100644 components/upload old/__tests__/mock.js delete mode 100644 components/upload old/__tests__/requests.js delete mode 100644 components/upload old/__tests__/upload.test.js delete mode 100644 components/upload old/__tests__/uploadlist.test.js delete mode 100644 components/upload old/demo/avatar.vue delete mode 100644 components/upload old/demo/directory.vue delete mode 100644 components/upload old/demo/drag.vue delete mode 100644 components/upload old/demo/fileList.vue delete mode 100644 components/upload old/demo/index.vue delete mode 100644 components/upload old/demo/picture-card.vue delete mode 100644 components/upload old/demo/picture-style.vue delete mode 100644 components/upload old/demo/preview-file.vue delete mode 100644 components/upload old/demo/transform-file.vue delete mode 100644 components/upload old/demo/upload-manually.vue delete mode 100644 components/upload old/index.en-US.md delete mode 100644 components/upload old/index.tsx delete mode 100644 components/upload old/index.zh-CN.md delete mode 100755 components/upload old/interface.tsx delete mode 100644 components/upload old/style/index.less delete mode 100644 components/upload old/utils.jsx create mode 100644 components/upload/demo/custom-render.vue rename components/{upload old/demo/basic.vue => upload/demo/customize-progress-bar.vue} (69%) create mode 100644 components/upload/demo/max-count.vue rename components/{upload old/demo/defaultFileList.vue => upload/demo/upload-custom-action-icon.vue} (63%) create mode 100644 components/upload/demo/upload-png-only.vue diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap index 6534f8592..d926893d1 100644 --- a/components/form/__tests__/__snapshots__/demo.test.js.snap +++ b/components/form/__tests__/__snapshots__/demo.test.js.snap @@ -1535,8 +1535,10 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = `
-
-
+
+
+ +
@@ -1550,17 +1552,18 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = `
-

+

Click or drag file to this area to upload

-

Support for a single or bulk upload.

+

Support for a single or bulk upload.

+
+
+
-
+
-
- - +
diff --git a/components/space/__tests__/__snapshots__/demo.test.js.snap b/components/space/__tests__/__snapshots__/demo.test.js.snap index 12f7e81bc..b9a1b8aa9 100644 --- a/components/space/__tests__/__snapshots__/demo.test.js.snap +++ b/components/space/__tests__/__snapshots__/demo.test.js.snap @@ -61,8 +61,10 @@ exports[`renders ./components/space/demo/base.vue correctly 1`] = ` Button
-
-
+
+
+ +
diff --git a/components/upload old/Dragger.tsx b/components/upload old/Dragger.tsx deleted file mode 100644 index d3d985eb1..000000000 --- a/components/upload old/Dragger.tsx +++ /dev/null @@ -1,22 +0,0 @@ -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 {getSlot(this)}; - }, -}); diff --git a/components/upload old/Upload.tsx b/components/upload old/Upload.tsx deleted file mode 100644 index 6bf14054e..000000000 --- a/components/upload old/Upload.tsx +++ /dev/null @@ -1,342 +0,0 @@ -import classNames from '../_util/classNames'; -import uniqBy from 'lodash-es/uniqBy'; -import findIndex from 'lodash-es/findIndex'; -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 { 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'; - -export default defineComponent({ - name: 'AUpload', - mixins: [BaseMixin], - inheritAttrs: false, - Dragger, - props: initDefaultProps(uploadProps, { - type: 'select', - multiple: false, - action: '', - data: {}, - accept: '', - beforeUpload: T, - showUploadList: true, - listType: 'text', // or pictrue - disabled: false, - supportServerRender: true, - }), - setup() { - const formItemContext = useInjectFormItemContext(); - return { - upload: null, - progressTimer: null, - configProvider: inject('configProvider', defaultConfigProvider), - formItemContext, - }; - }, - // recentUploadStatus: boolean | PromiseLike; - 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); - } - }, - - onSuccess(response, file, xhr) { - this.clearProgressTimer(); - try { - if (typeof response === 'string') { - response = JSON.parse(response); - } - } catch (e) { - /* do nothing */ - } - const fileList = this.sFileList; - const targetItem = getFileItem(file, fileList); - // removed - if (!targetItem) { - return; - } - targetItem.status = 'done'; - targetItem.response = response; - targetItem.xhr = xhr; - this.handleChange({ - file: { ...targetItem }, - fileList, - }); - }, - onProgress(e, file) { - const fileList = this.sFileList; - const targetItem = getFileItem(file, fileList); - // removed - if (!targetItem) { - return; - } - 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); - // removed - if (!targetItem) { - return; - } - 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 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 ; - }, - }, - 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', - }; - - const uploadList = showUploadList ? ( - - ) : null; - - const children = getSlot(this); - - 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 ( - -
- -
{children}
-
-
- {uploadList} -
- ); - } - - const uploadButtonCls = classNames(prefixCls, { - [`${prefixCls}-select`]: true, - [`${prefixCls}-select-${listType}`]: true, - [`${prefixCls}-disabled`]: disabled, - }); - - // 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 = ( -
- {children} -
- ); - - if (listType === 'picture-card') { - return ( - - {uploadList} - {uploadButton} - - ); - } - return ( - - {uploadButton} - {uploadList} - - ); - }, -}); diff --git a/components/upload old/UploadList.tsx b/components/upload old/UploadList.tsx deleted file mode 100644 index a621f2cd1..000000000 --- a/components/upload old/UploadList.tsx +++ /dev/null @@ -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' ? : ; - - if (listType === 'picture' || listType === 'picture-card') { - if (listType === 'picture-card' && file.status === 'uploading') { - icon =
{locale.uploading}
; - } else if (!file.thumbUrl && !file.url) { - icon = ; - } else { - const thumbnail = isImageUrl(file) ? ( - {file.name} - ) : ( - - ); - icon = ( - this.handlePreview(file, e)} - href={file.url || file.thumbUrl} - target="_blank" - rel="noopener noreferrer" - > - {thumbnail} - - ); - } - } - - 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 ? : null; - - progress = ( -
- {loadingProgress} -
- ); - } - 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 ? ( - this.handleClose(file)} /> - ) : null; - const downloadIcon = - showDownloadIcon && file.status === 'done' ? ( - this.handleDownload(file)} /> - ) : null; - const downloadOrDelete = listType !== 'picture-card' && ( - - {downloadIcon && {downloadIcon}} - {removeIcon && {removeIcon}} - - ); - 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 - ? [ - this.handlePreview(file, e)} - > - {file.name} - , - downloadOrDelete, - ] - : [ - this.handlePreview(file, e)} - title={file.name} - > - {file.name} - , - downloadOrDelete, - ]; - const style: CSSProperties | undefined = - file.url || file.thumbUrl - ? undefined - : { - pointerEvents: 'none', - opacity: 0.5, - }; - const previewIcon = showPreviewIcon ? ( - this.handlePreview(file, e)} - title={locale.previewFile} - > - - - ) : null; - const actions = listType === 'picture-card' && file.status !== 'uploading' && ( - - {previewIcon} - {file.status === 'done' && downloadIcon} - {removeIcon} - - ); - let message; - if (file.response && typeof file.response === 'string') { - message = file.response; - } else { - message = (file.error && file.error.statusText) || locale.uploadError; - } - const iconAndPreview = ( - - {icon} - {preview} - - ); - const transitionProps = getTransitionProps('fade'); - const dom = ( -
-
{iconAndPreview}
- {actions} - {progress} -
- ); - const listContainerNameClass = classNames({ - [`${prefixCls}-list-picture-card-container`]: listType === 'picture-card', - }); - return ( -
- {file.status === 'error' ? {dom} : {dom}} -
- ); - }); - 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 ( - - {list} - - ); - }, -}); diff --git a/components/upload old/__tests__/__snapshots__/demo.test.js.snap b/components/upload old/__tests__/__snapshots__/demo.test.js.snap deleted file mode 100644 index 924cda504..000000000 --- a/components/upload old/__tests__/__snapshots__/demo.test.js.snap +++ /dev/null @@ -1,126 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders ./components/upload/demo/avatar.vue correctly 1`] = ` -
-
Upload
-
-`; - -exports[`renders ./components/upload/demo/basic.vue correctly 1`] = ` -
-
-`; - -exports[`renders ./components/upload/demo/defaultFileList.vue correctly 1`] = ` -
-
-
- - -
-
- - -
-
- -
- - - -
-
-
-`; - -exports[`renders ./components/upload/demo/directory.vue correctly 1`] = ` -
-
-`; - -exports[`renders ./components/upload/demo/drag.vue correctly 1`] = ` -

-

Click or drag file to this area to upload

-

Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files

-
-
-`; - -exports[`renders ./components/upload/demo/fileList.vue correctly 1`] = ` -
-
-
- - -
-
-`; - -exports[`renders ./components/upload/demo/picture-card.vue correctly 1`] = ` -
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
image.png - -
- - -
-
-
-
-
Upload
-
- -
-`; - -exports[`renders ./components/upload/demo/picture-style.vue correctly 1`] = ` -
-
-
- - -
-
- - -
-


-
-
- - -
-
- - -
-
-`; - -exports[`renders ./components/upload/demo/preview-file.vue correctly 1`] = ` -
-
-`; - -exports[`renders ./components/upload/demo/transform-file.vue correctly 1`] = ` -
-
-`; diff --git a/components/upload old/__tests__/__snapshots__/uploadlist.test.js.snap b/components/upload old/__tests__/__snapshots__/uploadlist.test.js.snap deleted file mode 100644 index 9ec7b50d1..000000000 --- a/components/upload old/__tests__/__snapshots__/uploadlist.test.js.snap +++ /dev/null @@ -1,75 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Upload List handle error 1`] = ` -
foo.png
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`Upload List handle error 2`] = ` -
foo.png
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`Upload List should be uploading when upload a file 1`] = `
`; - -exports[`Upload List should non-image format file preview 1`] = ` -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-`; diff --git a/components/upload old/__tests__/demo.test.js b/components/upload old/__tests__/demo.test.js deleted file mode 100644 index 8fd9b81ab..000000000 --- a/components/upload old/__tests__/demo.test.js +++ /dev/null @@ -1,3 +0,0 @@ -import demoTest from '../../../tests/shared/demoTest'; - -demoTest('upload', { skip: ['upload-manually'] }); diff --git a/components/upload old/__tests__/mock.js b/components/upload old/__tests__/mock.js deleted file mode 100644 index 1f2e57c8a..000000000 --- a/components/upload old/__tests__/mock.js +++ /dev/null @@ -1,14 +0,0 @@ -import mock from 'xhr-mock'; - -export function setup() { - mock.setup(); - mock.post('http://upload.com/', (req, res) => { - req.headers({ - 'content-length': 100, - }); - req.body('thisisbody'); - return res; - }); -} - -export const teardown = mock.teardown.bind(mock); diff --git a/components/upload old/__tests__/requests.js b/components/upload old/__tests__/requests.js deleted file mode 100644 index d90ed171f..000000000 --- a/components/upload old/__tests__/requests.js +++ /dev/null @@ -1,11 +0,0 @@ -export const successRequest = ({ onSuccess, file }) => { - setTimeout(() => { - onSuccess(null, file); - }); -}; - -export const errorRequest = ({ onError }) => { - setTimeout(() => { - onError(); - }); -}; diff --git a/components/upload old/__tests__/upload.test.js b/components/upload old/__tests__/upload.test.js deleted file mode 100644 index e82a8907e..000000000 --- a/components/upload old/__tests__/upload.test.js +++ /dev/null @@ -1,331 +0,0 @@ -import { mount } from '@vue/test-utils'; -import Upload from '..'; -import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from '../utils'; -import PropsTypes from '../../_util/vue-types'; -import { uploadListProps } from '../interface'; -import { setup, teardown } from './mock'; - -uploadListProps.items = PropsTypes.any; - -describe('Upload', () => { - beforeEach(() => setup()); - afterEach(() => teardown()); - it('should get refs inside Upload in componentDidMount', () => { - let ref = null; - const APP = { - mounted() { - ref = this.$refs.input; - }, - render() { - return ( - - - - ); - }, - }; - mount(APP); - expect(ref).toBeDefined(); - }); - - xit('return promise in beforeUpload', done => { - const data = jest.fn(); - const props = { - props: { - action: 'http://upload.com', - beforeUpload: () => new Promise(resolve => setTimeout(() => resolve('success'), 100)), - data, - }, - listeners: { - change: ({ file }) => { - if (file.status !== 'uploading') { - expect(data).toBeCalled(); - done(); - } - }, - }, - slots: { - default: () => , - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - wrapper.findComponent('ajaxUploader').vm.onChange({ - target: { - files: [{ file: 'foo.png' }], - }, - }); - }, 0); - }); - - xit('upload promise return file in beforeUpload', done => { - const data = jest.fn(); - const props = { - action: 'http://upload.com', - beforeUpload: file => - new Promise(resolve => - setTimeout(() => { - const result = file; - result.name = 'test.png'; - resolve(result); - }, 100), - ), - data, - onChange: ({ file }) => { - if (file.status !== 'uploading') { - expect(data).toBeCalled(); - expect(file.name).toEqual('test.png'); - done(); - } - }, - slots: { - default: () => , - }, - sync: false, - }; - - const wrapper = mount(Upload, props); - - setTimeout(() => { - wrapper.find({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [{ file: 'foo.png' }], - }, - }); - }, 0); - }); - - xit('should not stop upload when return value of beforeUpload is false', done => { - const data = jest.fn(); - const props = { - action: 'http://upload.com', - beforeUpload: () => false, - data, - onChange: ({ file }) => { - expect(file instanceof File).toBe(true); - expect(data).not.toBeCalled(); - done(); - }, - slots: { - default: () => , - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - const mockFile = new File(['foo'], 'foo.png', { - type: 'image/png', - }); - wrapper.find({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [mockFile], - }, - }); - }, 0); - }); - - xit('should increase percent automaticly when call autoUpdateProgress in IE', done => { - let uploadInstance; - let lastPercent = -1; - const props = { - props: { - action: 'http://upload.com', - }, - listeners: { - change: ({ file }) => { - if (file.percent === 0 && file.status === 'uploading') { - // manually call it - uploadInstance.autoUpdateProgress(0, file); - } - if (file.status === 'uploading') { - expect(file.percent).toBeGreaterThan(lastPercent); - lastPercent = file.percent; - } - if (file.status === 'done' || file.status === 'error') { - done(); - } - }, - }, - slots: { - default: '', - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - const mockFile = new File(['foo'], 'foo.png', { - type: 'image/png', - }); - wrapper.find({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [mockFile], - }, - }); - uploadInstance = wrapper.vm; - }, 0); - }); - xit('should not stop upload when return value of beforeUpload is not false', done => { - const data = jest.fn(); - const props = { - props: { - action: 'http://upload.com', - beforeUpload() {}, - data, - }, - listeners: { - change: () => { - expect(data).toBeCalled(); - done(); - }, - }, - slots: { - default: '', - }, - sync: false, - }; - - const wrapper = mount(Upload, props); - setTimeout(() => { - const mockFile = new File(['foo'], 'foo.png', { - type: 'image/png', - }); - wrapper.find({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [mockFile], - }, - }); - }, 0); - }); - - 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 = [ - { - uid: '-1', - name: 'item.jpg', - }, - ]; - const targetItem = getFileItem(file, fileList); - expect(targetItem).toBe(fileList[0]); - }); - - it('should be able to remove fileItem', () => { - const file = { uid: '-1', name: 'item.jpg' }; - const fileList = [ - { - uid: '-1', - name: 'item.jpg', - }, - { - uid: '-2', - name: 'item2.jpg', - }, - ]; - const targetItem = removeFileItem(file, fileList); - expect(targetItem).toEqual(fileList.slice(1)); - }); - - it('should not be able to remove fileItem', () => { - const file = { uid: '-3', name: 'item.jpg' }; - const fileList = [ - { - uid: '-1', - name: 'item.jpg', - }, - { - uid: '-2', - name: 'item2.jpg', - }, - ]; - const targetItem = removeFileItem(file, fileList); - expect(targetItem).toBe(null); - }); - }); - - it('should support linkProps as object', () => { - const fileList = [ - { - uid: '-1', - name: 'foo.png', - status: 'done', - url: 'http://www.baidu.com/xxx.png', - linkProps: { - download: 'image', - rel: 'noopener', - }, - }, - ]; - const props = { - props: { - fileList, - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - const linkNode = wrapper.find('a.ant-upload-list-item-name'); - expect(linkNode.props().download).toBe('image'); - expect(linkNode.props().rel).toBe('noopener'); - }, 0); - }); - - it('should support linkProps as json stringify', () => { - const linkPropsString = JSON.stringify({ - download: 'image', - rel: 'noopener', - }); - const fileList = [ - { - uid: '-1', - name: 'foo.png', - status: 'done', - url: 'http://www.baidu.com/xxx.png', - linkProps: linkPropsString, - }, - ]; - const props = { - props: { - fileList, - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - const linkNode = wrapper.find('a.ant-upload-list-item-name'); - expect(linkNode.props().download).toBe('image'); - expect(linkNode.props().rel).toBe('noopener'); - }, 0); - }); -}); diff --git a/components/upload old/__tests__/uploadlist.test.js b/components/upload old/__tests__/uploadlist.test.js deleted file mode 100644 index 6fe88fca9..000000000 --- a/components/upload old/__tests__/uploadlist.test.js +++ /dev/null @@ -1,433 +0,0 @@ -import { mount } from '@vue/test-utils'; -import * as Vue from 'vue'; -import Upload from '..'; -import { errorRequest, successRequest } from './requests'; -import PropsTypes from '../../_util/vue-types'; -import { uploadListProps } from '../interface'; -import { sleep } from '../../../tests/utils'; -import { h } from 'vue'; - -uploadListProps.items = PropsTypes.any; - -const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout)); -const fileList = [ - { - uid: -1, - name: 'xxx.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - thumbUrl: 'https://zos.alipayobjects.com/rmsportal/IQKRngzUuFzJzGzRJXUs.png', - }, - { - uid: -2, - name: 'yyy.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/IQKRngzUuFzJzGzRJXUs.png', - thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }, -]; - -describe('Upload List', () => { - // jsdom not support `createObjectURL` yet. Let's handle this. - const originCreateObjectURL = window.URL.createObjectURL; - window.URL.createObjectURL = jest.fn(() => ''); - const originHTMLCanvasElementGetContext = window.HTMLCanvasElement.prototype.getContext; - window.HTMLCanvasElement.prototype.getContext = jest.fn(() => ''); - // https://github.com/ant-design/ant-design/issues/4653 - afterAll(() => { - window.URL.createObjectURL = originCreateObjectURL; - window.HTMLCanvasElement.prototype.getContext = originHTMLCanvasElementGetContext; - }); - it('should use file.thumbUrl for in priority', done => { - const props = { - props: { - defaultFileList: fileList, - listType: 'picture', - action: '', - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - Vue.nextTick(() => { - fileList.forEach((file, i) => { - const linkNode = wrapper.findAll('.ant-upload-list-item-thumbnail')[i]; - const imgNode = wrapper.findAll('.ant-upload-list-item-thumbnail img')[i]; - expect(linkNode.attributes().href).toBe(file.url); - expect(imgNode.attributes().src).toBe(file.thumbUrl); - }); - done(); - }); - }); - - // https://github.com/ant-design/ant-design/issues/7269 - it('should remove correct item when uid is 0', done => { - const list = [ - { - uid: 0, - name: 'xxx.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - thumbUrl: 'https://zos.alipayobjects.com/rmsportal/IQKRngzUuFzJzGzRJXUs.png', - }, - { - uid: 1, - name: 'xxx.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - thumbUrl: 'https://zos.alipayobjects.com/rmsportal/IQKRngzUuFzJzGzRJXUs.png', - }, - ]; - const props = { - props: { - defaultFileList: list, - action: '', - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(async () => { - expect(wrapper.findAll('.ant-upload-list-item').length).toBe(2); - wrapper.findAll('.ant-upload-list-item')[0].find('.anticon-delete').trigger('click'); - await delay(400); - // wrapper.update(); - expect(wrapper.findAll('.ant-upload-list-item').length).toBe(1); - done(); - }, 0); - }); - - xit('should be uploading when upload a file', done => { - const props = { - props: { - action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', - customRequest: successRequest, - onChange: ({ file }) => { - if (file.status === 'uploading') { - expect(wrapper.html()).toMatchSnapshot(); - done(); - } - if (file.status === 'done') { - expect(wrapper.html()).toMatchSnapshot(); - done(); - } - }, - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - const mockFile = new File(['foo'], 'foo.png', { - type: 'image/png', - }); - wrapper.findComponent({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [mockFile], - }, - }); - }, 0); - }); - - xit('handle error', done => { - const props = { - props: { - action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', - customRequest: errorRequest, - }, - listeners: { - change: ({ file }) => { - if (file.status !== 'uploading') { - expect(wrapper.html()).toMatchSnapshot(); - done(); - } - }, - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(() => { - const mockFile = new File(['foo'], 'foo.png', { - type: 'image/png', - }); - wrapper.findComponent({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [mockFile], - }, - }); - }, 0); - }); - - xit('does concat filelist when beforeUpload returns false', done => { - const handleChange = jest.fn(); - const props = { - props: { - action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', - listType: 'picture', - defaultFileList: fileList, - beforeUpload: () => false, - onChange: handleChange, - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - - setTimeout(() => { - const mockFile = new File(['foo'], 'foo.png', { - type: 'image/png', - }); - wrapper.findComponent({ name: 'ajaxUploader' }).vm.onChange({ - target: { - files: [mockFile], - }, - }); - Vue.nextTick(() => { - expect(wrapper.vm.sFileList.length).toBe(fileList.length + 1); - expect(handleChange.mock.calls[0][0].fileList).toHaveLength(3); - done(); - }); - }, 0); - }); - - // https://github.com/ant-design/ant-design/issues/7762 - // it('work with form validation', (done) => { - // let errors - // const TestForm = { - // methods: { - // handleSubmit () { - // const { validateFields } = this.form - // validateFields((err) => { - // errors = err - // }) - // }, - // }, - // render () { - // const { getFieldDecorator } = this.form - - // return ( - //
- // - // {getFieldDecorator('file', { - // valuePropname: 'fileList', - // getValueFromEvent: e => e.fileList, - // rules: [ - // { - // required: true, - // validator: (rule, value, callback) => { - // if (!value || value.length === 0) { - // callback('file required') - // } else { - // callback() - // } - // }, - // }, - // ], - // })( - // false} - // > - // - // - // )} - // - //
- // ) - // }, - // } - - // const App = Form.create()(TestForm) - // console.dir(App) - // const wrapper = mount(() => { - // return - // }) - // setTimeout(async () => { - // wrapper.find(Form).trigger('submit') - // expect(errors.file.errors).toEqual([{ message: 'file required', field: 'file' }]) - - // const mockFile = new File(['foo'], 'foo.png', { - // type: 'image/png', - // }) - // wrapper.findComponent({ name: 'ajaxUploader' }).vm.onChange({ - // target: { - // files: [mockFile], - // }, - // }) - // wrapper.find(Form).trigger('submit') - // expect(errors).toBeNull() - // done() - // }, 0) - // }) - - it('should support onPreview', async () => { - const handlePreview = jest.fn(); - const props = { - props: { - defaultFileList: fileList, - listType: 'picture-card', - action: '', - onPreview: handlePreview, - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - await sleep(500); - wrapper.findAll('.anticon-eye')[0].trigger('click'); - expect(handlePreview).toBeCalledWith(fileList[0]); - wrapper.findAll('.anticon-eye')[1].trigger('click'); - expect(handlePreview).toBeCalledWith(fileList[1]); - }); - - it('should support onRemove', done => { - const handleRemove = jest.fn(); - const handleChange = jest.fn(); - const props = { - props: { - defaultFileList: fileList, - listType: 'picture-card', - action: '', - remove: handleRemove, - onChange: handleChange, - }, - - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - jest.setTimeout(300000); - setTimeout(async () => { - wrapper.findAll('.anticon-delete')[0].trigger('click'); - expect(handleRemove).toBeCalledWith(fileList[0]); - wrapper.findAll('.anticon-delete')[1].trigger('click'); - expect(handleRemove).toBeCalledWith(fileList[1]); - await delay(0); - expect(handleChange.mock.calls.length).toBe(2); - done(); - }, 0); - }); - - xit('should generate thumbUrl from file', done => { - const handlePreview = jest.fn(); - const newFileList = [...fileList]; - const newFile = { ...fileList[0], uid: -3, originFileObj: new File([], 'xxx.png') }; - delete newFile.thumbUrl; - newFileList.push(newFile); - const props = { - props: { - defaultFileList: newFileList, - listType: 'picture-card', - action: '', - onPreview: handlePreview, - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - setTimeout(async () => { - const newFile = { ...fileList[2], uid: -4, originFileObj: new File([], 'xxx.png') }; - newFileList.push(newFile); - wrapper.setProps({ - defaultFileList: [...newFileList], - }); - await delay(200); - expect(wrapper.vm.sFileList[2].thumbUrl).not.toBe(undefined); - done(); - }, 1000); - }); - - it('should non-image format file preview', done => { - const list = [ - { - name: 'not-image', - status: 'done', - uid: -3, - url: 'https://cdn.xxx.com/aaa.zip', - thumbUrl: 'data:application/zip;base64,UEsDBAoAAAAAADYZYkwAAAAAAAAAAAAAAAAdAAk', - originFileObj: new File([], 'aaa.zip'), - }, - { - name: 'image', - status: 'done', - uid: -4, - url: 'https://cdn.xxx.com/aaa', - }, - { - name: 'not-image', - status: 'done', - uid: -5, - url: 'https://cdn.xxx.com/aaa.xx', - }, - { - name: 'not-image', - status: 'done', - uid: -6, - url: 'https://cdn.xxx.com/aaa.png/xx.xx', - }, - { - name: 'image', - status: 'done', - uid: -7, - url: 'https://cdn.xxx.com/xx.xx/aaa.png', - }, - { - name: 'image', - status: 'done', - uid: -8, - url: 'https://cdn.xxx.com/xx.xx/aaa.png', - thumbUrl: 'data:image/png;base64,UEsDBAoAAAAAADYZYkwAAAAAAAAAAAAAAAAdAAk', - }, - { - name: 'image', - status: 'done', - uid: -9, - url: 'https://cdn.xxx.com/xx.xx/aaa.png?query=123', - }, - { - name: 'image', - status: 'done', - uid: -10, - url: 'https://cdn.xxx.com/xx.xx/aaa.png#anchor', - }, - { - name: 'image', - status: 'done', - uid: -11, - url: 'https://cdn.xxx.com/xx.xx/aaa.png?query=some.query.with.dot', - }, - ]; - const props = { - props: { - defaultFileList: list, - listType: 'picture', - action: '', - }, - slots: { - default: () => h('button', 'upload'), - }, - sync: false, - }; - const wrapper = mount(Upload, props); - Vue.nextTick(() => { - expect(wrapper.html()).toMatchSnapshot(); - done(); - }); - }); -}); diff --git a/components/upload old/demo/avatar.vue b/components/upload old/demo/avatar.vue deleted file mode 100644 index cd68f1a22..000000000 --- a/components/upload old/demo/avatar.vue +++ /dev/null @@ -1,116 +0,0 @@ - ---- -order: 1 -title: - zh-CN: 用户头像 - en-US: Avatar ---- - -## zh-CN - -点击上传用户头像,并使用 `beforeUpload` 限制用户上传的图片格式和大小。 - -> `beforeUpload` 的返回值可以是一个 Promise 以支持异步处理,如服务端校验等:[示例](http://react-component.github.io/upload/examples/beforeUpload.html)。 - -## en-US - -Click to upload user's avatar, and validate size and format of picture with `beforeUpload`. - -> The return value of function `beforeUpload` can be a Promise to check asynchronously. [demo](http://react-component.github.io/upload/examples/beforeUpload.html) - - - - - diff --git a/components/upload old/demo/directory.vue b/components/upload old/demo/directory.vue deleted file mode 100644 index feaacb078..000000000 --- a/components/upload old/demo/directory.vue +++ /dev/null @@ -1,35 +0,0 @@ - ---- -order: 8 -title: - zh-CN: 文件夹上传 - en-US: Upload directory ---- - -## zh-CN - -支持上传一个文件夹里的所有文件。 - -## en-US - -You can select and upload a whole directory. - - - - diff --git a/components/upload old/demo/drag.vue b/components/upload old/demo/drag.vue deleted file mode 100644 index 6bf30241a..000000000 --- a/components/upload old/demo/drag.vue +++ /dev/null @@ -1,68 +0,0 @@ - ---- -order: 5 -title: - zh-CN: 拖拽上传 - en-US: Drag and Drop ---- - -## zh-CN - -把文件拖入指定区域,完成上传,同样支持点击上传。 - -设置 `multiple` 后,在 `IE10+` 可以一次上传多个文件。 - -## 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. - - - - diff --git a/components/upload old/demo/fileList.vue b/components/upload old/demo/fileList.vue deleted file mode 100644 index 963343540..000000000 --- a/components/upload old/demo/fileList.vue +++ /dev/null @@ -1,81 +0,0 @@ - ---- -order: 4 -title: - zh-CN: 完全控制的上传列表 - en-US: Complete control over file list ---- - -## zh-CN - -使用 `fileList` 对列表进行完全控制,可以实现各种自定义功能,以下演示二种情况: - -1. 上传列表数量的限制。 - -2. 读取远程路径并显示链接。 - -## en-US - -You can gain full control over filelist by configuring `fileList`. You can accomplish all kinds of customed functions. The following shows two circumstances: - -1. limit the number of uploaded files. - -2. read from response and show file link. - - - - diff --git a/components/upload old/demo/index.vue b/components/upload old/demo/index.vue deleted file mode 100644 index b1ae4e92e..000000000 --- a/components/upload old/demo/index.vue +++ /dev/null @@ -1,52 +0,0 @@ - - diff --git a/components/upload old/demo/picture-card.vue b/components/upload old/demo/picture-card.vue deleted file mode 100644 index 34fdd976d..000000000 --- a/components/upload old/demo/picture-card.vue +++ /dev/null @@ -1,126 +0,0 @@ - ---- -order: 3 -title: - zh-CN: 照片墙 - en-US: Pictures Wall ---- - -## zh-CN - -用户可以上传图片并在列表中显示缩略图。当上传照片数到达限制后,上传按钮消失。 - -## en-US - -After users upload picture, the thumbnail will be shown in list. The upload button will disappear when count meets limitation. - - - - - diff --git a/components/upload old/demo/picture-style.vue b/components/upload old/demo/picture-style.vue deleted file mode 100644 index 9ad5b92a9..000000000 --- a/components/upload old/demo/picture-style.vue +++ /dev/null @@ -1,108 +0,0 @@ - ---- -order: 6 -title: - zh-CN: 图片列表样式 - en-US: Pictures with list style ---- - -## 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. - - - - - - diff --git a/components/upload old/demo/preview-file.vue b/components/upload old/demo/preview-file.vue deleted file mode 100644 index 9f2ceb2fb..000000000 --- a/components/upload old/demo/preview-file.vue +++ /dev/null @@ -1,58 +0,0 @@ - ---- -order: 9 -title: - zh-CN: 自定义预览 - en-US: Customize preview file ---- - -## zh-CN - -自定义本地预览,用于处理非图片格式文件(例如视频文件)。 - -## en-US - -Customize local preview. Can handle with non-image format files such as video. - - - - diff --git a/components/upload old/demo/transform-file.vue b/components/upload old/demo/transform-file.vue deleted file mode 100644 index 857a6b89a..000000000 --- a/components/upload old/demo/transform-file.vue +++ /dev/null @@ -1,66 +0,0 @@ - ---- -order: 10 -title: - zh-CN: 上传前转换文件 - en-US: Transform file before request ---- - -## zh-CN - -使用 `beforeUpload` 转换上传的文件(例如添加水印)。 - -## en-US - -Use `beforeUpload` for transform file before request such as add a watermark. - - - - diff --git a/components/upload old/demo/upload-manually.vue b/components/upload old/demo/upload-manually.vue deleted file mode 100644 index d84c67de8..000000000 --- a/components/upload old/demo/upload-manually.vue +++ /dev/null @@ -1,96 +0,0 @@ - ---- -order: 7 -title: - zh-CN: 手动上传 - en-US: Upload manually ---- - -## zh-CN - -`beforeUpload` 返回 `false` 后,手动上传文件。 - -## en-US - -Upload files manually after `beforeUpload` returns `false`. - - - - diff --git a/components/upload old/index.en-US.md b/components/upload old/index.en-US.md deleted file mode 100644 index 84500cf84..000000000 --- a/components/upload old/index.en-US.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -category: Components -type: Data Entry -title: Upload -cover: https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg ---- - -Upload file by selecting or dragging. - -## When To Use - -Uploading is the process of publishing information (web pages, text, pictures, video, etc.) to a remote server via a web page or upload tool. - -- When you need to upload one or more files. -- When you need to show the process of uploading. -- When you need to upload files by dragging and dropping. - -## 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. **Warning:this function is not supported in IE9**。 | (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 | | -| fileList | List of files that have been uploaded (controlled). Here is a common issue [#2423](https://github.com/ant-design/ant-design/issues/2423) when using it | object\[] | - | | -| headers | Set request headers, valid above IE10. | object | - | | -| listType | Built-in stylesheets, support for three types: `text`, `picture` or `picture-card` | string | `text` | | -| 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 | - | 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 | | -| 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` | - | 1.5.0 | - -### events - -| Events Name | Description | Arguments | Version | -| --- | --- | --- | --- | --- | -| change | A callback function, can be executed when uploading state is changing. See [change](#change) | Function | - | | -| 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) | - | | - -### change - -> The function will be called when uploading is in progress, completed or failed - -When uploading state change, it returns: - -```jsx -{ - file: { /* ... */ }, - fileList: [ /* ... */ ], - event: { /* ... */ }, -} -``` - -1. `file` File object for the current operation. - - ```jsx - { - uid: 'uid', // unique identifier, negative is recommend, to prevent interference with internal generated id - name: 'xx.png', // file name - status: 'done', // options:uploading, done, error, removed - response: '{"status": "success"}', // response from server - linkProps: '{"download": "image"}', // additional html props of file link - xhr: 'XMLHttpRequest{ ... }', // XMLHttpRequest Header - } - ``` - -2. `fileList` current list of files -3. `event` response from server, including uploading progress, supported by advanced browsers. diff --git a/components/upload old/index.tsx b/components/upload old/index.tsx deleted file mode 100644 index a29ac4d3c..000000000 --- a/components/upload old/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { App, Plugin } from 'vue'; -import Upload from './Upload'; -import Dragger from './Dragger'; - -export type { UploadProps, UploadListProps, UploadChangeParam } from './interface'; - -Upload.Dragger = Dragger; - -/* 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; - }; diff --git a/components/upload old/index.zh-CN.md b/components/upload old/index.zh-CN.md deleted file mode 100644 index 73db3ef2c..000000000 --- a/components/upload old/index.zh-CN.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -category: Components -subtitle: 上传 -type: 数据录入 -title: Upload -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` | 无 | | -| customRequest | 通过覆盖默认的上传行为,可以自定义自己的上传实现 | Function | 无 | | -| data | 上传所需参数或返回上传参数的方法 | object\|(file) => object | 无 | | -| disabled | 是否禁用 | boolean | false | | -| fileList | 已经上传的文件列表(受控) | object\[] | 无 | | -| headers | 设置上传的请求头部,IE10 以上有效 | object | 无 | | -| listType | 上传列表的内建样式,支持三种基本样式 `text`, `picture` 和 `picture-card` | string | `text` | | -| multiple | 是否支持多选文件,`ie10+` 支持。开启后按住 ctrl 可选择多个文件。 | boolean | false | | -| name | 发到后台的文件参数名 | string | `file` | | -| previewFile | 自定义文件预览逻辑 | (file: File \| Blob) => Promise | 无 | 1.5.0 | -| showUploadList | 是否展示 uploadList, 可设为一个对象,用于单独设定 showPreviewIcon 和 showRemoveIcon | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean } | true | | -| 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` | 无   | 1.5.0 | - -### 事件 - -| 事件名称 | 说明 | 回调参数 | 版本 | -| --- | --- | --- | --- | --- | -| change | 上传文件改变时的状态,详见 [change](#change) | Function | 无 | | -| preview | 点击文件链接或预览图标时的回调 | Function(file) | 无 | | -| download | 点击下载文件时的回调,如果没有指定,则默认跳转到文件 url 对应的标签页。 | Function(file): void | 跳转新标签页 | 1.5.0 | -| reject | 拖拽文件不符合 accept 类型时的回调 | Function(fileList) | 无 | | - -### change - -> 上传中、完成、失败都会调用这个函数。 - -文件状态改变的回调,返回为: - -```jsx -{ - file: { /* ... */ }, - fileList: [ /* ... */ ], - event: { /* ... */ }, -} -``` - -1. `file` 当前操作的文件对象。 - - ```jsx - { - uid: 'uid', // 文件唯一标识,建议设置为负数,防止和内部产生的 id 冲突 - name: 'xx.png', // 文件名 - status: 'done', // 状态有:uploading done error removed - response: '{"status": "success"}', // 服务端响应内容 - linkProps: '{"download": "image"}', // 下载链接额外的 HTML 属性 - xhr: 'XMLHttpRequest{ ... }', // XMLHttpRequest Header - } - ``` - -2. `fileList` 当前的文件列表。 -3. `event` 上传中的服务端响应内容,包含了上传进度等信息,高级浏览器支持。 diff --git a/components/upload old/interface.tsx b/components/upload old/interface.tsx deleted file mode 100755 index d95add183..000000000 --- a/components/upload old/interface.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import type { ExtractPropTypes, PropType } from 'vue'; -import { tuple } from '../_util/type'; -import PropsTypes from '../_util/vue-types'; - -export const UploadFileStatus = PropsTypes.oneOf( - tuple('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 { - uid: string; - size?: number; - name: string; - fileName?: string; - lastModified?: number; - lastModifiedDate?: Date; - url?: string; - status?: UploadFileStatus; - percent?: number; - thumbUrl?: string; - originFileObj?: any; - response?: T; - error?: any; - linkProps?: any; - type?: string; - xhr?: T; - preview?: string; -} - -export interface UploadChangeParam { - 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; - downloadFile?: string; - uploadError?: string; - previewFile?: string; -} - -export const uploadProps = { - type: PropsTypes.oneOf(tuple('drag', 'select')), - name: PropsTypes.string, - defaultFileList: { type: Array as PropType }, - fileList: { type: Array as PropType }, - 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 }, - 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>, - }, - onDownload: { type: Function as PropType<(file: UploadFile) => void> }, - 'onUpdate:fileList': { type: Function as PropType<(files: UploadFile[]) => void> }, -}; - -export type UploadProps = Partial>; -export const uploadListProps = { - listType: PropsTypes.oneOf(tuple('text', 'picture', 'picture-card')), - // items: PropsTypes.arrayOf(UploadFile), - items: { type: Array as PropType }, - progressAttr: PropsTypes.object, - prefixCls: PropsTypes.string, - showRemoveIcon: PropsTypes.looseBool, - showDownloadIcon: PropsTypes.looseBool, - showPreviewIcon: PropsTypes.looseBool, - locale: { type: Object as PropType }, - 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 UploadListProps = Partial>; diff --git a/components/upload old/style/index.less b/components/upload old/style/index.less deleted file mode 100644 index 17f4154eb..000000000 --- a/components/upload old/style/index.less +++ /dev/null @@ -1,542 +0,0 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; - -@upload-prefix-cls: ~'@{ant-prefix}-upload'; -@upload-item: ~'@{ant-prefix}-upload-list-item'; -@upload-picture-card-size: 104px; -@upload-picture-card-border-style: @border-style-base; - -.@{upload-prefix-cls} { - .reset-component(); - - outline: 0; - - p { - margin: 0; - } - - &-btn { - display: block; - width: 100%; - outline: none; - } - - input[type='file'] { - cursor: pointer; - } - - &&-select { - display: inline-block; - } - - &&-disabled { - cursor: not-allowed; - } - - &&-select-picture-card { - display: table; - float: left; - width: @upload-picture-card-size; - height: @upload-picture-card-size; - margin-right: 8px; - margin-bottom: 8px; - text-align: center; - vertical-align: top; - background-color: @background-color-light; - border: @border-width-base dashed @border-color-base; - border-radius: @border-radius-base; - cursor: pointer; - transition: border-color 0.3s ease; - - > .@{upload-prefix-cls} { - display: table-cell; - width: 100%; - height: 100%; - padding: 8px; - text-align: center; - vertical-align: middle; - } - - &:hover { - border-color: @primary-color; - } - } - - &&-drag { - position: relative; - width: 100%; - height: 100%; - text-align: center; - background: @background-color-light; - border: @border-width-base dashed @border-color-base; - border-radius: @border-radius-base; - cursor: pointer; - transition: border-color 0.3s; - - .@{upload-prefix-cls} { - padding: 16px 0; - } - - &.@{upload-prefix-cls}-drag-hover:not(.@{upload-prefix-cls}-disabled) { - border-color: @primary-7; - } - - &.@{upload-prefix-cls}-disabled { - cursor: not-allowed; - } - - .@{upload-prefix-cls}-btn { - display: table; - height: 100%; - } - - .@{upload-prefix-cls}-drag-container { - display: table-cell; - vertical-align: middle; - } - - &:not(.@{upload-prefix-cls}-disabled):hover { - border-color: @primary-5; - } - - p.@{upload-prefix-cls}-drag-icon { - .@{iconfont-css-prefix} { - color: @primary-5; - font-size: 48px; - } - - margin-bottom: 20px; - } - p.@{upload-prefix-cls}-text { - margin: 0 0 4px; - color: @heading-color; - font-size: @font-size-lg; - } - p.@{upload-prefix-cls}-hint { - 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; - } - } - &:hover .@{iconfont-css-prefix}-plus { - color: @text-color-secondary; - } - } - - &-picture-card-wrapper { - .clearfix(); - - display: inline-block; - width: 100%; - } -} - -.@{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; - } - } - } - &-item { - position: relative; - height: 22px; - margin-top: 8px; - font-size: @font-size-base; - &-name { - display: inline-block; - width: 100%; - padding-left: @font-size-base + 8px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - &-name-icon-count-1 { - padding-right: 14px; - } - - &-card-actions { - position: absolute; - right: 0; - opacity: 0; - &.picture { - top: 25px; - line-height: 1; - opacity: 1; - } - .anticon { - padding-right: 6px; - color: rgba(0, 0, 0, 0.45); - } - } - - &-info { - height: 100%; - padding: 0 12px 0 4px; - transition: background-color 0.3s; - - > span { - display: block; - width: 100%; - height: 100%; - } - - .@{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; - } - } - - .@{iconfont-css-prefix}-close { - .iconfont-size-under-12px(10px); - - position: absolute; - top: 6px; - right: 4px; - color: @text-color-secondary; - line-height: 0; - cursor: pointer; - opacity: 0; - transition: all 0.3s; - &:hover { - color: @text-color; - } - } - - &:hover &-info { - background-color: @item-hover-bg; - } - - &:hover .@{iconfont-css-prefix}-close { - opacity: 1; - } - - &:hover &-card-actions { - opacity: 1; - } - - &-error, - &-error .@{iconfont-css-prefix}-paper-clip, - &-error &-name { - color: @error-color; - } - - &-error &-card-actions { - .anticon { - color: @error-color; - } - opacity: 1; - } - - &-progress { - position: absolute; - bottom: -12px; - width: 100%; - padding-left: @font-size-base + 12px; - font-size: @font-size-base; - line-height: 0; - } - } - - &-picture, - &-picture-card { - .@{upload-item} { - position: relative; - height: 66px; - padding: 8px; - 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; - } - } - - .@{upload-item}-info { - padding: 0; - } - - .@{upload-item}:hover .@{upload-item}-info { - background: transparent; - } - - .@{upload-item}-uploading { - border-style: dashed; - } - - .@{upload-item}-thumbnail { - position: absolute; - top: 8px; - left: 8px; - width: 48px; - height: 48px; - font-size: 26px; - line-height: 54px; - text-align: center; - opacity: 0.8; - } - - .@{upload-item}-icon { - position: absolute; - top: 50%; - left: 50%; - font-size: 26px; - transform: translate(-50%, -50%); - } - - .@{upload-item}-image { - max-width: 100%; - } - - .@{upload-item}-thumbnail img { - display: block; - width: 48px; - height: 48px; - overflow: hidden; - } - - .@{upload-item}-name { - display: inline-block; - box-sizing: border-box; - max-width: 100%; - margin: 0 0 0 8px; - padding-right: 8px; - padding-left: 48px; - overflow: hidden; - line-height: 44px; - white-space: nowrap; - text-overflow: ellipsis; - 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; - } - - .@{upload-item}-progress { - bottom: 14px; - width: ~'calc(100% - 24px)'; - margin-top: 0; - padding-left: 56px; - } - - .@{iconfont-css-prefix}-close { - position: absolute; - top: 8px; - right: 8px; - line-height: 1; - opacity: 1; - } - } - - &-picture-card { - &.@{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; - } - - .@{upload-item}-info { - position: relative; - height: 100%; - overflow: hidden; - - &::before { - position: absolute; - z-index: 1; - width: 100%; - height: 100%; - background-color: fade(@black, 50%); - opacity: 0; - transition: all 0.3s; - content: ' '; - } - } - - .@{upload-item}:hover .@{upload-item}-info::before { - opacity: 1; - } - - .@{upload-item}-actions { - position: absolute; - top: 50%; - left: 50%; - z-index: 10; - white-space: nowrap; - transform: translate(-50%, -50%); - opacity: 0; - transition: all 0.3s; - - .@{iconfont-css-prefix}-eye, - .@{iconfont-css-prefix}-download, - .@{iconfont-css-prefix}-delete { - z-index: 10; - width: 16px; - margin: 0 4px; - color: @text-color-dark; - font-size: 16px; - cursor: pointer; - transition: all 0.3s; - &:hover { - color: @text-color-inverse; - } - } - } - - .@{upload-item}-info:hover + .@{upload-item}-actions, - .@{upload-item}-actions:hover { - opacity: 1; - } - - .@{upload-item}-thumbnail, - .@{upload-item}-thumbnail img { - position: static; - display: block; - width: 100%; - height: 100%; - object-fit: cover; - } - - .@{upload-item}-name { - display: none; - margin: 8px 0 0; - padding: 0; - line-height: @line-height-base; - text-align: center; - } - - .anticon-picture + .@{upload-item}-name { - position: absolute; - bottom: 10px; - display: block; - } - - .@{upload-item}-uploading { - &.@{upload-item} { - background-color: @background-color-light; - } - - .@{upload-item}-info { - height: auto; - &::before, - .@{iconfont-css-prefix}-eye-o, - .@{iconfont-css-prefix}-delete { - display: none; - } - } - - &-text { - margin-top: 18px; - color: @text-color-secondary; - } - } - - .@{upload-item}-progress { - bottom: 32px; - padding-left: 0; - } - } - - .@{upload-prefix-cls}-success-icon { - color: @success-color; - font-weight: bold; - } - - .@{upload-prefix-cls}-animate-enter, - .@{upload-prefix-cls}-animate-leave, - .@{upload-prefix-cls}-animate-inline-enter, - .@{upload-prefix-cls}-animate-inline-leave { - animation-duration: 0.3s; - 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-enter { - animation-name: uploadAnimateInlineIn; - } - - .@{upload-prefix-cls}-animate-inline-leave { - animation-name: uploadAnimateInlineOut; - } -} - -@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; - height: 0; - margin: 0; - padding: 0; - opacity: 0; - } -} - -@keyframes uploadAnimateInlineOut { - to { - width: 0; - height: 0; - margin: 0; - padding: 0; - opacity: 0; - } -} diff --git a/components/upload old/utils.jsx b/components/upload old/utils.jsx deleted file mode 100644 index 2ee74403e..000000000 --- a/components/upload old/utils.jsx +++ /dev/null @@ -1,130 +0,0 @@ -export function T() { - return true; -} - -// Fix IE file.status problem -// via coping a new Object -export function fileToObject(file) { - return { - ...file, - lastModified: file.lastModified, - lastModifiedDate: file.lastModifiedDate, - name: file.name, - size: file.size, - type: file.type, - uid: file.uid, - percent: 0, - originFileObj: 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; - }; -} - -export function getFileItem(file, fileList) { - const matchKey = file.uid !== undefined ? 'uid' : 'name'; - return fileList.filter(item => item[matchKey] === file[matchKey])[0]; -} - -export function removeFileItem(file, fileList) { - const matchKey = file.uid !== undefined ? 'uid' : 'name'; - const removed = fileList.filter(item => item[matchKey] !== file[matchKey]); - if (removed.length === fileList.length) { - return null; - } - return removed; -} - -// ==================== Default Image Preview ==================== -const extname = (url = '') => { - const temp = url.split('/'); - const filename = temp[temp.length - 1]; - const filenameWithoutSuffix = filename.split(/#|\?/)[0]; - return (/\.[^./\\]*$/.exec(filenameWithoutSuffix) || [''])[0]; -}; - -const isImageFileType = type => !!type && type.indexOf('image/') === 0; - -export const isImageUrl = file => { - if (isImageFileType(file.type)) { - return true; - } - const url = file.thumbUrl || file.url; - const extension = extname(url); - if ( - /^data:image\//.test(url) || - /(webp|svg|png|gif|jpg|jpeg|jfif|bmp|dpg|ico)$/i.test(extension) - ) { - return true; - } - if (/^data:/.test(url)) { - // other file types of base64 - return false; - } - if (extension) { - // other file types which have extension - return false; - } - return true; -}; - -const MEASURE_SIZE = 200; -export function previewImage(file) { - return new Promise(resolve => { - if (!isImageFileType(file.type)) { - resolve(''); - return; - } - - const canvas = document.createElement('canvas'); - canvas.width = MEASURE_SIZE; - canvas.height = MEASURE_SIZE; - canvas.style.cssText = `position: fixed; left: 0; top: 0; width: ${MEASURE_SIZE}px; height: ${MEASURE_SIZE}px; z-index: 9999; display: none;`; - document.body.appendChild(canvas); - const ctx = canvas.getContext('2d'); - const img = new Image(); - img.onload = () => { - const { width, height } = img; - - let drawWidth = MEASURE_SIZE; - let drawHeight = MEASURE_SIZE; - let offsetX = 0; - let offsetY = 0; - - if (width < height) { - drawHeight = height * (MEASURE_SIZE / width); - offsetY = -(drawHeight - drawWidth) / 2; - } else { - drawWidth = width * (MEASURE_SIZE / height); - offsetX = -(drawWidth - drawHeight) / 2; - } - - ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight); - const dataURL = canvas.toDataURL(); - document.body.removeChild(canvas); - - resolve(dataURL); - }; - img.src = window.URL.createObjectURL(file); - }); -} diff --git a/components/upload/Upload.tsx b/components/upload/Upload.tsx index 3ba5d4aa8..7035ed2e8 100644 --- a/components/upload/Upload.tsx +++ b/components/upload/Upload.tsx @@ -4,10 +4,10 @@ import UploadList from './UploadList'; import type { UploadType, UploadListType, - RcFile, UploadFile, UploadChangeParam, ShowUploadListInterface, + FileType, } from './interface'; import { uploadProps } from './interface'; import { file2Obj, getFileItem, removeFileItem, updateFileList } from './utils'; @@ -57,16 +57,21 @@ export default defineComponent({ const upload = ref(); onMounted(() => { devWarning( - 'fileList' in props || !('value' in props), + props.fileList !== undefined || attrs.value === undefined, 'Upload', '`value` is not a valid prop, do you mean `fileList`?', ); devWarning( - !('transformFile' in props), + 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 = ( @@ -98,10 +103,10 @@ export default defineComponent({ formItemContext.onFieldChange(); }; - const mergedBeforeUpload = async (file: RcFile, fileListArgs: RcFile[]) => { + const mergedBeforeUpload = async (file: FileType, fileListArgs: FileType[]) => { const { beforeUpload, transformFile } = props; - let parsedFile: File | Blob | string = file; + let parsedFile: FileType | Blob | string = file; if (beforeUpload) { const result = await beforeUpload(file, fileListArgs); @@ -128,7 +133,7 @@ export default defineComponent({ parsedFile = await transformFile(parsedFile as any); } - return parsedFile as RcFile; + return parsedFile as File; }; const onBatchStart: RcUploadProps['onBatchStart'] = batchFileInfoList => { @@ -142,7 +147,7 @@ export default defineComponent({ return; } - const objectFileList = filteredFileInfoList.map(info => file2Obj(info.file as RcFile)); + const objectFileList = filteredFileInfoList.map(info => file2Obj(info.file as FileType)); // Concat new files with prev files let newFileList = [...mergedFileList.value]; @@ -185,7 +190,7 @@ export default defineComponent({ }); }; - const onSuccess = (response: any, file: RcFile, xhr: any) => { + const onSuccess = (response: any, file: FileType, xhr: any) => { try { if (typeof response === 'string') { response = JSON.parse(response); @@ -210,7 +215,7 @@ export default defineComponent({ onInternalChange(targetItem, nextFileList); }; - const onProgress = (e: { percent: number }, file: RcFile) => { + const onProgress = (e: { percent: number }, file: FileType) => { // removed if (!getFileItem(file, mergedFileList.value)) { return; @@ -225,7 +230,7 @@ export default defineComponent({ onInternalChange(targetItem, nextFileList, e); }; - const onError = (error: Error, response: any, file: RcFile) => { + const onError = (error: Error, response: any, file: FileType) => { // removed if (!getFileItem(file, mergedFileList.value)) { return; @@ -243,29 +248,30 @@ export default defineComponent({ const handleRemove = (file: UploadFile) => { let currentFile: UploadFile; - Promise.resolve( - typeof props.onRemove === 'function' ? props.onRemove(file) : props.onRemove, - ).then(ret => { - // Prevent removing file - if (ret === false) { - return; - } + const mergedRemove = props.onRemove || props.remove; + Promise.resolve(typeof mergedRemove === 'function' ? mergedRemove(file) : mergedRemove).then( + ret => { + // Prevent removing file + if (ret === false) { + return; + } - const removedFileList = removeFileItem(file, mergedFileList.value); + const removedFileList = removeFileItem(file, mergedFileList.value); - 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); + 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); - } - }); + onInternalChange(currentFile, removedFileList); + } + }, + ); }; const onFileDrop = (e: DragEvent) => { @@ -344,6 +350,7 @@ export default defineComponent({ beforeUpload: mergedBeforeUpload, onChange: undefined, }; + delete (rcUploadProps as any).remove; // Remove id to avoid open by label when trigger is hidden // !children: https://github.com/ant-design/ant-design/issues/14298 diff --git a/components/upload/UploadList/ListItem.tsx b/components/upload/UploadList/ListItem.tsx index 4e51a8184..6d492d37d 100644 --- a/components/upload/UploadList/ListItem.tsx +++ b/components/upload/UploadList/ListItem.tsx @@ -148,7 +148,6 @@ export default defineComponent({ title: locale.removeFile, }) : null; - const downloadIcon = showDownloadIcon && file.status === 'done' ? actionIconRender({ diff --git a/components/upload/UploadList/index.tsx b/components/upload/UploadList/index.tsx index bcc19773a..6947f061d 100644 --- a/components/upload/UploadList/index.tsx +++ b/components/upload/UploadList/index.tsx @@ -189,13 +189,14 @@ export default defineComponent({ onPreview={onInternalPreview} onDownload={onInternalDownload} onClose={onInternalClose} + removeIcon={removeIcon} + previewIcon={previewIcon} + downloadIcon={downloadIcon} + itemRender={itemRender} v-slots={{ - removeIcon, - previewIcon, - downloadIcon, + ...slots, iconRender: internalIconRender, actionIconRender, - itemRender, }} /> ); diff --git a/components/upload/__tests__/__snapshots__/demo.test.js.snap b/components/upload/__tests__/__snapshots__/demo.test.js.snap index 924cda504..bd98f94f5 100644 --- a/components/upload/__tests__/__snapshots__/demo.test.js.snap +++ b/components/upload/__tests__/__snapshots__/demo.test.js.snap @@ -1,126 +1,305 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders ./components/upload/demo/avatar.vue correctly 1`] = ` -
+
Upload
`; exports[`renders ./components/upload/demo/basic.vue correctly 1`] = ` -
-
+
+
+ +
+`; + +exports[`renders ./components/upload/demo/custom-render.vue correctly 1`] = ` +
+
+
+
+
xxx.png
+ + + + + +
+
+
+
+
yyy.png
+ + + + + +
+
+
+
+
zzz.png
+ + + + + +
+
+ +
+`; + +exports[`renders ./components/upload/demo/customize-progress-bar.vue correctly 1`] = ` +
+
+ +
`; exports[`renders ./components/upload/demo/defaultFileList.vue correctly 1`] = ` -
+
-
- - -
-
- - -
-
- -
- +
+
+
+
+
+ + + +
+
+
+ +
+ + + +
+
+
`; exports[`renders ./components/upload/demo/directory.vue correctly 1`] = ` -
-
-`; - -exports[`renders ./components/upload/demo/drag.vue correctly 1`] = ` -

-

Click or drag file to this area to upload

-

Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files

-
-
-`; - -exports[`renders ./components/upload/demo/fileList.vue correctly 1`] = ` -
+
-
`; -exports[`renders ./components/upload/demo/picture-card.vue correctly 1`] = ` -
- - -
-
- - -
-
- - -
-
- - -
-
+exports[`renders ./components/upload/demo/drag.vue correctly 1`] = ` +

+

Click or drag file to this area to upload

+

Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files

+
-
-
image.png - -
- +
+`; + +exports[`renders ./components/upload/demo/fileList.vue correctly 1`] = ` +
+
+
+
+ +
+ +
+`; + +exports[`renders ./components/upload/demo/max-count.vue correctly 1`] = ` +
+
+
+ +
-
-
Upload
-
+ +
+
+ +
+ +
+`; + +exports[`renders ./components/upload/demo/picture-card.vue correctly 1`] = ` +
+ + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+
Uploading...
image.png
+ + +
+
+
+ +
+
image.png +
+
+ + +
+
+
+
Upload
+
+
`; exports[`renders ./components/upload/demo/picture-style.vue correctly 1`] = ` -
+
-
+
+
+ + + +
+
+
+
+ + + +
+
- -
-
- - -
-


+


-
+
+
+ + + +
+
+
+
+ + + +
+
- -
-
- - -
`; exports[`renders ./components/upload/demo/preview-file.vue correctly 1`] = ` -
-
+
+
+ +
`; exports[`renders ./components/upload/demo/transform-file.vue correctly 1`] = ` -
-
+
+
+ +
+`; + +exports[`renders ./components/upload/demo/upload-custom-action-icon.vue correctly 1`] = ` +
+
+
+
+
xxx.png
+
+ + +
+
+
+
+
yyy.png
+
+ + +
+
+
+ +
+ + + +
+
+ +
+`; + +exports[`renders ./components/upload/demo/upload-png-only.vue correctly 1`] = ` +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+ +
+ + + +
+
+ +
`; diff --git a/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap b/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap index 9ec7b50d1..5a2aa53b8 100644 --- a/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap +++ b/components/upload/__tests__/__snapshots__/uploadlist.test.js.snap @@ -35,41 +35,71 @@ exports[`Upload List handle error 2`] = ` exports[`Upload List should be uploading when upload a file 1`] = `
`; exports[`Upload List should non-image format file preview 1`] = ` -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
`; diff --git a/components/upload/__tests__/upload.test.js b/components/upload/__tests__/upload.test.js index e82a8907e..d6e9da8ea 100644 --- a/components/upload/__tests__/upload.test.js +++ b/components/upload/__tests__/upload.test.js @@ -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 = [ diff --git a/components/upload/__tests__/uploadlist.test.js b/components/upload/__tests__/uploadlist.test.js index 6fe88fca9..52cd2fff1 100644 --- a/components/upload/__tests__/uploadlist.test.js +++ b/components/upload/__tests__/uploadlist.test.js @@ -300,7 +300,7 @@ describe('Upload List', () => { defaultFileList: fileList, listType: 'picture-card', action: '', - remove: handleRemove, + onRemove: handleRemove, onChange: handleChange, }, diff --git a/components/upload/demo/avatar.vue b/components/upload/demo/avatar.vue index cd68f1a22..66e14fc15 100644 --- a/components/upload/demo/avatar.vue +++ b/components/upload/demo/avatar.vue @@ -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 diff --git a/components/upload/demo/custom-render.vue b/components/upload/demo/custom-render.vue new file mode 100644 index 000000000..0a77bf336 --- /dev/null +++ b/components/upload/demo/custom-render.vue @@ -0,0 +1,93 @@ + +--- +order: 0 +title: + zh-CN: 自定义上传列表 + en-US: Custom Render +--- + +## zh-CN + +使用 `itemRender` 插槽进行完全自定义列表 + +## en-US + +Custom render by using `itemRender` slot. + + + + diff --git a/components/upload old/demo/basic.vue b/components/upload/demo/customize-progress-bar.vue similarity index 69% rename from components/upload old/demo/basic.vue rename to components/upload/demo/customize-progress-bar.vue index 3c9862438..c3afe5dbe 100644 --- a/components/upload old/demo/basic.vue +++ b/components/upload/demo/customize-progress-bar.vue @@ -1,27 +1,28 @@ --- -order: 0 +order: 15 title: - zh-CN: 点击上传 - en-US: Upload by clicking + zh-CN: 自定义进度条样式 + en-US: Customize Progress Bar --- ## zh-CN -经典款式,用户点击按钮弹出文件选择框。 +使用 `progress` 属性自定义进度条样式。 ## en-US -Classic mode. File selection dialog pops up when upload button is clicked. +Use `progress` for customize progress bar. +