diff --git a/src/_common b/src/_common index f7f15f02f1..e6d6e0697a 160000 --- a/src/_common +++ b/src/_common @@ -1 +1 @@ -Subproject commit f7f15f02f11d3d387af6b18685ac9b10ee32be19 +Subproject commit e6d6e0697afb9a13caab5a31bee8a0a5b4712911 diff --git a/src/_util/parseTNode.ts b/src/_util/parseTNode.ts index 51259b8efa..468639ee23 100644 --- a/src/_util/parseTNode.ts +++ b/src/_util/parseTNode.ts @@ -15,7 +15,7 @@ export default function parseTNode( node = renderNode(renderParams); } else if (renderNode === true) { node = defaultNode; - } else { + } else if (renderNode !== null) { node = renderNode ?? defaultNode; } return node as ReactNode; diff --git a/src/image-viewer/ImageViewerModal.tsx b/src/image-viewer/ImageViewerModal.tsx index 75267b5053..de4d051694 100644 --- a/src/image-viewer/ImageViewerModal.tsx +++ b/src/image-viewer/ImageViewerModal.tsx @@ -232,7 +232,7 @@ type ImageViewerHeaderProps = { function OneImagePreview({ image, classPrefix }: { image: ImageInfo; classPrefix: string }) { const { previewUrl } = useImagePreviewUrl(image.thumbnail || image.mainImage); - return ; + return ; } const ImageViewerHeader = (props: ImageViewerHeaderProps) => { diff --git a/src/space/Space.tsx b/src/space/Space.tsx index 105cf3ac7c..fccf227e26 100644 --- a/src/space/Space.tsx +++ b/src/space/Space.tsx @@ -1,4 +1,4 @@ -import React, { CSSProperties, forwardRef, useMemo } from 'react'; +import React, { CSSProperties, ReactNode, forwardRef, useMemo } from 'react'; import classNames from 'classnames'; import { isFragment } from 'react-is'; import useConfig from '../hooks/useConfig'; @@ -37,6 +37,8 @@ const toArray = (children: React.ReactNode): React.ReactElement[] => { return ret; }; +const EMPTY_NODE: ReactNode[] = ['', false, null, undefined]; + const Space = forwardRef((props: SpaceProps, ref: React.Ref) => { const { className, style, align, direction, size, breakLine, separator } = props; const { classPrefix } = useConfig(); @@ -78,7 +80,7 @@ const Space = forwardRef((props: SpaceProps, ref: React.Ref) => const showSeparator = index + 1 !== childCount && separator; return ( <> -
{child}
+ {EMPTY_NODE.includes(child) ? null :
{child}
} {showSeparator &&
{separator}
} ); diff --git a/src/table/FilterController.tsx b/src/table/FilterController.tsx index c452ddc6b3..a44f20ffd2 100644 --- a/src/table/FilterController.tsx +++ b/src/table/FilterController.tsx @@ -133,9 +133,10 @@ export default function TableFilterController(props: TableFilterControllerProps) const defaultFilterIcon = t(locale.filterIcon) || ; const filterValue = tFilterValue?.[column.colKey]; const isObjectTrue = typeof filterValue === 'object' && !isEmpty(filterValue); - const isValueTrue = filterValue && typeof filterValue !== 'object'; + // false is a valid filter value + const isValueExist = ![null, undefined, ''].includes(filterValue) && typeof filterValue !== 'object'; return ( -
+
primaryTableElement : undefined} visible={filterPopupVisible} diff --git a/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap b/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap index 7c06c68c4c..b0b2a03e2c 100644 --- a/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap +++ b/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap @@ -906,9 +906,6 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = ` />
-
@@ -934,8 +931,20 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = `

+ + + img.txt

@@ -976,9 +985,6 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = ` /> -
@@ -1027,8 +1033,20 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = `

+ + + img1.txt

@@ -1069,9 +1087,6 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = ` /> -
@@ -1120,9 +1135,21 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = `

- 待上传 + + + + img2.txt

  • props.theme: theme=image-flow works fine 1`] = `
    - - - - - - - - @@ -1195,7 +1199,7 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = `

    img3.txt

    @@ -1239,29 +1243,6 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = `
    - - - - - - - - @@ -1281,7 +1262,7 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = `

    img4.txt

    diff --git a/src/upload/_example/base.jsx b/src/upload/_example/base.jsx index d6c2963783..59768ec17b 100644 --- a/src/upload/_example/base.jsx +++ b/src/upload/_example/base.jsx @@ -174,8 +174,8 @@ export default function UploadExample() { { - console.log(val); + onChange={(val, ctx) => { + console.log(val, ctx); setFiles1(val); }} action="https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo" diff --git a/src/upload/_example/file-flow-list.jsx b/src/upload/_example/file-flow-list.jsx index 09ae6948a7..0fe609e0fd 100644 --- a/src/upload/_example/file-flow-list.jsx +++ b/src/upload/_example/file-flow-list.jsx @@ -28,6 +28,13 @@ export default function FileFlowList() { } }; + const formatResponse = (res) => { + if (!res) { + return { status: 'fail', error: '上传失败,原因:文件过大或网络不通' }; + } + return res; + }; + return ( @@ -63,6 +70,7 @@ export default function FileFlowList() { isBatchUpload={isBatchUpload} allowUploadDuplicateFile={allowUploadDuplicateFile} onValidate={onValidate} + formatResponse={formatResponse} /> ); diff --git a/src/upload/_example/img-flow-list.jsx b/src/upload/_example/img-flow-list.jsx index 89c92edfe6..ab8e4bf121 100644 --- a/src/upload/_example/img-flow-list.jsx +++ b/src/upload/_example/img-flow-list.jsx @@ -1,10 +1,12 @@ import React, { useState } from 'react'; -import { Upload, Space, MessagePlugin, Switch } from 'tdesign-react'; +import { Upload, Space, MessagePlugin, Switch, Checkbox, Divider } from 'tdesign-react'; const ABRIDGE_NAME = [4, 6]; export default function TUploadImageFlow() { const [autoUpload, setAutoUpload] = useState(false); + const [showImageFileName, setShowImageFileName] = useState(true); + const [showUploadButton, setShowUploadButton] = useState(true); const [files, setFiles] = useState([ { url: 'https://tdesign.gtimg.com/demo/demo-image-1.png', status: 'success', name: 'demo-image-1.png' }, { url: 'https://tdesign.gtimg.com/site/avatar.jpg', status: 'success', name: 'avatar.jpg' }, @@ -12,6 +14,30 @@ export default function TUploadImageFlow() { // eslint-disable-next-line const [files2, setFiles2] = useState([]); + const staticFiles = [ + { + url: 'https://tdesign.gtimg.com/demo/demo-image-1.png', + name: 'loading.svg', + status: 'success', + }, + { + url: 'https://tdesign.gtimg.com/demo/demo-image-1.png', + name: 'loading.svg', + status: 'waiting', + }, + { + // url: 'https://tdesign.gtimg.com/demo/demo-image-1.png', + name: 'loading.svg', + status: 'progress', + percent: 10, + }, + { + url: 'https://tdesign.gtimg.com/demo/demo-image-1.png', + name: 'loading.svg', + status: 'fail', + }, + ]; + // 示例代码:自定义上传方法,一个请求上传一个文件 // eslint-disable-next-line const requestMethod1 = () => { @@ -58,10 +84,18 @@ export default function TUploadImageFlow() { // 因接口返回的 url 是同一个,所以看到的图片都是一个 return ( -
    - 是否自动上传: - -
    + +
    + AutoUpload + +
    + + Show Image Name + + + Show UploadButton Or CancelUploadButton + +

    @@ -79,6 +113,9 @@ export default function TUploadImageFlow() { autoUpload={autoUpload} max={8} abridgeName={ABRIDGE_NAME} + showImageFileName={showImageFileName} + uploadButton={showUploadButton ? {} : null} + cancelUploadButton={showUploadButton ? { theme: 'default', content: '取消上传' } : null} onValidate={onValidate} /> @@ -97,6 +134,16 @@ export default function TUploadImageFlow() { uploadAllFilesInOneRequest={true} onValidate={onValidate} /> */} + +
    + Different Status Images + +
    ); } diff --git a/src/upload/defaultProps.ts b/src/upload/defaultProps.ts index 3874caf673..6156660793 100644 --- a/src/upload/defaultProps.ts +++ b/src/upload/defaultProps.ts @@ -14,11 +14,12 @@ export const uploadDefaultProps: TdUploadProps = { method: 'POST', multiple: false, name: 'file', + showImageFileName: true, showThumbnail: false, showUploadProgress: true, theme: 'file', uploadAllFilesInOneRequest: false, - uploadPastedFiles: false, + uploadPastedFiles: true, useMockProgress: true, withCredentials: false, }; diff --git a/src/upload/hooks/useUpload.ts b/src/upload/hooks/useUpload.ts index 225e501ec0..5ac22f263e 100644 --- a/src/upload/hooks/useUpload.ts +++ b/src/upload/hooks/useUpload.ts @@ -1,4 +1,4 @@ -import { useRef, useState, useMemo, ChangeEventHandler, MouseEvent, useEffect } from 'react'; +import { useRef, useState, useMemo, ChangeEventHandler, MouseEvent, useEffect, ClipboardEventHandler } from 'react'; import merge from 'lodash/merge'; import { SizeLimitObj, TdUploadProps, UploadChangeContext, UploadFile, UploadRemoveContext } from '../type'; import { @@ -49,12 +49,12 @@ export default function useUpload(props: TdUploadProps) { const [uploading, setUploading] = useState(false); // 文件列表显示的内容(自动上传和非自动上传有所不同) - const [displayFiles, setDisplayFiles] = useState(uploadValue); + const [displayFiles, setDisplayFiles] = useState(uploadValue || []); useEffect(() => { const files = getDisplayFiles({ multiple: props.multiple, toUploadFiles, - uploadValue: [...uploadValue], + uploadValue: uploadValue ? [...uploadValue] : [], autoUpload, isBatchUpload, }); @@ -63,10 +63,15 @@ export default function useUpload(props: TdUploadProps) { const uploadFilePercent = (params: { file: UploadFile; percent: number }) => { const { file, percent } = params; - const index = toUploadFiles.findIndex((item) => file.raw === item.raw); - const newFiles = [...toUploadFiles]; - newFiles[index] = { ...newFiles[index], percent }; - setToUploadFiles(newFiles); + if (autoUpload) { + const index = toUploadFiles.findIndex((item) => file.raw === item.raw); + const newFiles = [...toUploadFiles]; + newFiles[index] = { ...newFiles[index], percent }; + setToUploadFiles(newFiles); + } else { + const index = uploadValue.findIndex((item) => file.raw === item.raw); + uploadValue[index] = { ...uploadValue[index], percent }; + } }; const updateProgress = ( @@ -153,7 +158,7 @@ export default function useUpload(props: TdUploadProps) { // @ts-ignore files: [...files], allowUploadDuplicateFile: props.allowUploadDuplicateFile, - max: props.max, + max: props.multiple ? props.max : 0, sizeLimit: props.sizeLimit, isBatchUpload, autoUpload, @@ -217,6 +222,11 @@ export default function useUpload(props: TdUploadProps) { onFileChange?.(files); } + const onPasteFileChange: ClipboardEventHandler = (e) => { + // @ts-ignore + onFileChange?.([...e.clipboardData.files]); + }; + /** * 上传文件。对外暴露方法,修改时需谨慎 * @param toFiles 本地上传的文件列表 @@ -334,9 +344,9 @@ export default function useUpload(props: TdUploadProps) { }); setUploading(false); + // autoUpload do not need to reset to waiting state if (autoUpload) { - // toUploadFiles.current = toUploadFiles.current.map((item) => ({ ...item, status: 'waiting' })); - setToUploadFiles(toUploadFiles.map((item) => ({ ...item, status: 'waiting' }))); + setToUploadFiles([]); } else { setUploadValue( uploadValue.map((item) => { @@ -356,6 +366,14 @@ export default function useUpload(props: TdUploadProps) { props.onCancelUpload?.(); }; + // 矫正数据格式为数组 + useEffect(() => { + if (!Array.isArray(uploadValue)) { + setUploadValue([], { trigger: 'default' }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [uploadValue]); + return { t, locale, @@ -377,6 +395,7 @@ export default function useUpload(props: TdUploadProps) { onFileChange, onNormalFileChange, onDragFileChange, + onPasteFileChange, onRemove, triggerUpload, cancelUpload, diff --git a/src/upload/interface.ts b/src/upload/interface.ts index 5f1bd31755..b662780091 100644 --- a/src/upload/interface.ts +++ b/src/upload/interface.ts @@ -2,6 +2,7 @@ import { MouseEvent, ReactNode } from 'react'; import { StyledProps } from '../common'; import { TdUploadProps, UploadFile, UploadRemoveContext } from './type'; import { GlobalConfigProvider } from '../config-provider/type'; +import { ImageViewerProps } from '../image-viewer'; export interface CommonDisplayFileProps { accept: string; @@ -24,6 +25,7 @@ export interface CommonDisplayFileProps { showUploadProgress?: boolean; children?: ReactNode; fileListDisplay?: TdUploadProps['fileListDisplay']; + imageViewerProps?: ImageViewerProps; onRemove?: (p: UploadRemoveContext) => void; } diff --git a/src/upload/themes/DraggerFile.tsx b/src/upload/themes/DraggerFile.tsx index bc2f8fd716..c3a138206e 100644 --- a/src/upload/themes/DraggerFile.tsx +++ b/src/upload/themes/DraggerFile.tsx @@ -57,6 +57,7 @@ const DraggerFile: FC = (props) => { } + {...props.imageViewerProps} > ); diff --git a/src/upload/themes/ImageCard.tsx b/src/upload/themes/ImageCard.tsx index c31c6c7dbb..50c70556c9 100644 --- a/src/upload/themes/ImageCard.tsx +++ b/src/upload/themes/ImageCard.tsx @@ -25,6 +25,7 @@ export interface ImageCardUploadProps extends CommonDisplayFileProps { uploadFiles?: (toFiles?: UploadFile[]) => void; cancelUpload?: (context: { e: MouseEvent; file: UploadFile }) => void; onPreview?: TdUploadProps['onPreview']; + showImageFileName?: boolean; } const ImageCard = (props: ImageCardUploadProps) => { @@ -59,6 +60,7 @@ const ImageCard = (props: ImageCardUploadProps) => { )} images={displayFiles.map((t) => t.url || t.raw)} defaultIndex={index} + {...props.imageViewerProps} /> {!disabled && ( @@ -101,6 +103,14 @@ const ImageCard = (props: ImageCardUploadProps) => { return (
    {parseTNode(fileListDisplay, { + triggerUpload: props.triggerUpload, + uploadFiles: props.uploadFiles, + cancelUpload: props.cancelUpload, + onPreview: props.onPreview, + onRemove: props.onRemove, + toUploadFiles: props.toUploadFiles, + sizeOverLimitMessage: props.sizeOverLimitMessage, + locale: props.locale, files: displayFiles, })}
    @@ -120,6 +130,7 @@ const ImageCard = (props: ImageCardUploadProps) => { {file.status === 'fail' && renderFailFile(file, index, loadCard)} {!['progress', 'fail'].includes(file.status) && renderMainContent(file, index)} {fileName && + props.showImageFileName && (file.url ? ( {fileName} @@ -133,10 +144,19 @@ const ImageCard = (props: ImageCardUploadProps) => { {showTrigger && (
  • -

    {locale?.triggerUploadText?.image}

    +

    + {locale?.triggerUploadText?.image} +

  • )} diff --git a/src/upload/themes/MultipleFlowList.tsx b/src/upload/themes/MultipleFlowList.tsx index f7784258e8..5d2b60f782 100644 --- a/src/upload/themes/MultipleFlowList.tsx +++ b/src/upload/themes/MultipleFlowList.tsx @@ -1,5 +1,7 @@ import React, { MouseEvent, useMemo, useState } from 'react'; import classNames from 'classnames'; +import isFunction from 'lodash/isFunction'; +import isObject from 'lodash/isObject'; import { BrowseIcon as TdBrowseIcon, DeleteIcon as TdDeleteIcon, @@ -16,7 +18,7 @@ import { import useGlobalIcon from '../../hooks/useGlobalIcon'; import ImageViewer from '../../image-viewer'; import { CommonDisplayFileProps } from '../interface'; -import TButton from '../../button'; +import TButton, { ButtonProps } from '../../button'; import { UploadFile, TdUploadProps } from '../type'; import useDrag, { UploadDragEvents } from '../hooks/useDrag'; import { @@ -43,10 +45,13 @@ export interface ImageFlowListProps extends CommonDisplayFileProps { draggable?: boolean; showThumbnail?: boolean; onPreview?: TdUploadProps['onPreview']; + uploadButton?: TdUploadProps['uploadButton']; + cancelUploadButton?: TdUploadProps['cancelUploadButton']; + showImageFileName?: boolean; } const ImageFlowList = (props: ImageFlowListProps) => { - const { draggable = true, accept, showThumbnail, onPreview } = props; + const { draggable = true, accept, showThumbnail, cancelUploadButton, uploadButton, onPreview } = props; // locale 已经在 useUpload 中统一处理优先级 const { locale, uploading, disabled, displayFiles, classPrefix } = props; const uploadPrefix = `${classPrefix}-upload`; @@ -171,7 +176,7 @@ const ImageFlowList = (props: ImageFlowListProps) => { )}
    - {(file.url || file.raw) && ( + {(file.url || file.raw) && !['progress', 'fail'].includes(file.status) && ( { @@ -197,9 +202,12 @@ const ImageFlowList = (props: ImageFlowListProps) => { )}
    -

    - {file.status === 'waiting' ? locale.progress.waitingText : fileName} -

    + {props.showImageFileName && ( +

    + {['success', 'waiting'].includes(file.status) && iconMap[file.status]} + {fileName} +

    + )} ); }; @@ -210,7 +218,7 @@ const ImageFlowList = (props: ImageFlowListProps) => {
    {iconMap[file.status]} - {textMap[file.status]} + {file.response?.error ? file.response.error || textMap[file.status] : textMap[file.status]} {props.showUploadProgress && file.status === 'progress' ? ` ${file.percent || 0}%` : ''}
    @@ -293,8 +301,16 @@ const ImageFlowList = (props: ImageFlowListProps) => { ) : null; const renderFileList = () => { + if (props.fileListDisplay === null) return null; if (props.fileListDisplay) { return parseTNode(props.fileListDisplay, { + cancelUpload: props.cancelUpload, + uploadFiles: props.uploadFiles, + onPreview: props.onPreview, + onRemove: props.onRemove, + toUploadFiles: props.toUploadFiles, + sizeOverLimitMessage: props.sizeOverLimitMessage, + locale: props.locale, files: displayFiles, dragEvents: innerDragEvents, }); @@ -355,6 +371,7 @@ const ImageFlowList = (props: ImageFlowListProps) => { const renderImageList = () => { if (props.fileListDisplay) { return parseTNode(props.fileListDisplay, { + ...props, files: displayFiles, dragEvents: innerDragEvents, }); @@ -366,6 +383,41 @@ const ImageFlowList = (props: ImageFlowListProps) => { ); }; + const renderCancelUploadButton = () => { + if (cancelUploadButton === null) return null; + if (isFunction(cancelUploadButton)) return parseTNode(cancelUploadButton); + const cancelButtonProps = (isObject(cancelUploadButton) ? cancelUploadButton : undefined) as ButtonProps; + return ( + props.cancelUpload?.({ e })} + {...cancelButtonProps} + > + {locale?.cancelUploadText} + + ); + }; + + const renderUploadButton = () => { + if (uploadButton === null) return null; + if (isFunction(uploadButton)) return parseTNode(uploadButton); + const uploadButtonProps = (isObject(uploadButton) ? uploadButton : undefined) as ButtonProps; + return ( + props.uploadFiles?.()} + {...uploadButtonProps} + > + {uploadText} + + ); + }; + const cardClassName = `${uploadPrefix}__flow-card-area`; return (
    @@ -395,24 +447,9 @@ const ImageFlowList = (props: ImageFlowListProps) => { {!props.autoUpload && (
    - props.cancelUpload?.({ e })} - > - {locale?.cancelUploadText} - + {renderCancelUploadButton()} - props.uploadFiles?.()} - > - {uploadText} - + {renderUploadButton()}
    )} @@ -422,6 +459,7 @@ const ImageFlowList = (props: ImageFlowListProps) => { onClose={closePreview} index={previewIndex} onIndexChange={previewIndexChange} + {...props.imageViewerProps} >
    ); diff --git a/src/upload/themes/NormalFile.tsx b/src/upload/themes/NormalFile.tsx index 014fd6908e..b117b61c1d 100644 --- a/src/upload/themes/NormalFile.tsx +++ b/src/upload/themes/NormalFile.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import isFunction from 'lodash/isFunction'; import { CloseIcon as TdCloseIcon, TimeFilledIcon as TdTimeFilledIcon, @@ -8,6 +7,7 @@ import { CloseCircleFilledIcon as TdCloseCircleFilledIcon, } from 'tdesign-icons-react'; import classNames from 'classnames'; +import parseTNode from '../../_util/parseTNode'; import TLoading from '../../loading'; import Link from '../../link'; import { UploadFile } from '../type'; @@ -109,7 +109,7 @@ export default function NormalFile(props: NormalFileProps) { {file?.name && file.status === 'fail' && ( )} - {!disabled && ( + {Boolean(!disabled && file?.name) && ( props.onRemove({ e, file, index: 0 })} @@ -120,10 +120,15 @@ export default function NormalFile(props: NormalFileProps) { ); }; - const { displayFiles } = props; - const fileListDisplay = isFunction(props.fileListDisplay) - ? props.fileListDisplay({ files: displayFiles }) - : props.fileListDisplay; + const { displayFiles, fileListDisplay } = props; + + const fileListDisplayNode = parseTNode(fileListDisplay, { + onRemove: props.onRemove, + toUploadFiles: props.toUploadFiles, + sizeOverLimitMessage: props.sizeOverLimitMessage, + locale: props.locale, + files: displayFiles, + }); const classes = [`${uploadPrefix}__single`, `${uploadPrefix}__single-${theme}`]; return ( @@ -136,11 +141,7 @@ export default function NormalFile(props: NormalFileProps) { {props.placeholder} )} - {fileListDisplay || renderFilePreviewAsText(displayFiles)} - - {props.sizeOverLimitMessage && ( - {props.sizeOverLimitMessage} - )} + {fileListDisplayNode === null ? null : fileListDisplayNode || renderFilePreviewAsText(displayFiles)} {/* 单文件上传失败要显示失败的原因 */} {!props.multiple && displayFiles[0]?.status === 'fail' && theme === 'file' ? ( diff --git a/src/upload/type.ts b/src/upload/type.ts index 3d6eb2d459..8b92013f7b 100644 --- a/src/upload/type.ts +++ b/src/upload/type.ts @@ -4,6 +4,7 @@ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { ImageViewerProps } from '../image-viewer'; import { UploadConfig } from '../config-provider/type'; import { ButtonProps } from '../button'; import { PlainObject, TNode, UploadDisplayDragEvents } from '../common'; @@ -42,6 +43,13 @@ export interface TdUploadProps { * 如果是自动上传模式 `autoUpload=true`,表示单个文件上传之前的钩子函数,若函数返回值为 `false` 则表示不上传当前文件。
    如果是非自动上传模式 `autoUpload=false`,函数返回值为 `false` 时表示从上传文件中剔除当前文件 */ beforeUpload?: (file: UploadFile) => boolean | Promise; + /** + * 批量文件/图片上传,`autoUpload=false` 场景下,透传“取消上传”按钮属性 + */ + cancelUploadButton?: + | null + | ButtonProps + | TNode<{ disabled: boolean; cancelUploadText: string; cancelUpload: (ctx: { e: MouseEvent }) => void }>; /** * 非拖拽场景,指触发上传的元素,如:“选择文件”。如果是拖拽场景,则是指拖拽区域 */ @@ -85,13 +93,17 @@ export interface TdUploadProps { */ formatRequest?: (requestData: { [key: string]: any }) => { [key: string]: any }; /** - * 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
    此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒,如果存在会判定为本次上传失败。
    此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接 + * 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
    示例返回值:`{ error, url, status, files }`
    此函数的返回值 `error` 会作为错误文本提醒,表示上传失败的原因,如果存在会判定为本次上传失败。
    此函数的返回值 `url` 会作为单个文件上传成功后的链接。
    `files` 表示一个请求同时上传多个文件后的文件列表 */ formatResponse?: (response: any, context: FormatResponseContext) => ResponseType; /** * 设置上传的请求头部,`action` 存在时有效 */ headers?: { [key: string]: string }; + /** + * 透传图片预览组件全部属性 + */ + imageViewerProps?: ImageViewerProps; /** * 用于添加属性到 HTML 元素 `input` */ @@ -106,7 +118,7 @@ export interface TdUploadProps { */ locale?: UploadConfig; /** - * 用于控制文件上传数量,值为 0 则不限制 + * 用于控制文件上传数量,值为 0 则不限制。注意,单文件上传场景,请勿设置 `max` 属性 * @default 0 */ max?: number; @@ -138,6 +150,11 @@ export interface TdUploadProps { * 自定义上传方法。返回值 `status` 表示上传成功或失败;`error` 或 `response.error` 表示上传失败的原因;
    `response` 表示请求上传成功后的返回数据,`response.url` 表示上传成功后的图片/文件地址,`response.files` 表示一个请求上传多个文件/图片后的返回值。
    示例一:`{ status: 'fail', error: '上传失败', response }`。
    示例二:`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`。
    示例三:`{ status: 'success', files: [{ url: 'https://xxx.png', name: 'xxx.png' }]}` */ requestMethod?: (files: UploadFile | UploadFile[]) => Promise; + /** + * 是否显示图片的文件名称 + * @default true + */ + showImageFileName?: boolean; /** * 是否在文件列表中显示缩略图,`theme=file-flow` 时有效 * @default false @@ -178,9 +195,16 @@ export interface TdUploadProps { * @default false */ uploadAllFilesInOneRequest?: boolean; + /** + * 批量文件/图片上传,`autoUpload=false` 场景下,透传“点击上传”按钮属性 + */ + uploadButton?: + | null + | ButtonProps + | TNode<{ disabled: boolean; uploading: boolean; uploadFiles: () => void; uploadText: string }>; /** * 是否允许粘贴上传剪贴板中的文件 - * @default false + * @default true */ uploadPastedFiles?: boolean; /** @@ -267,7 +291,7 @@ export interface UploadInstanceFunctions { /** * 设置上传中文件的上传进度 */ - uploadFilePercent: () => void; + uploadFilePercent: (params: { file: UploadFile; percent: number }) => void; /** * 组件实例方法,默认上传未成功上传过的所有文件。带参数时,表示上传指定文件 */ @@ -322,7 +346,10 @@ export interface UploadFile extends PlainObject { url?: string; } -export type ResponseType = { error?: string; url?: string } & Record; +export type ResponseType = { error?: string; url?: string; status?: 'fail' | 'success'; files?: UploadFile[] } & Record< + string, + any +>; export interface FormatResponseContext { file: UploadFile; @@ -359,7 +386,14 @@ export interface UploadChangeContext { files?: UploadFile[]; } -export type UploadChangeTrigger = 'add' | 'remove' | 'abort' | 'progress-success' | 'progress' | 'progress-fail'; +export type UploadChangeTrigger = + | 'add' + | 'remove' + | 'abort' + | 'progress-success' + | 'progress' + | 'progress-fail' + | 'default'; export interface UploadFailContext { e?: ProgressEvent; diff --git a/src/upload/upload.en-US.md b/src/upload/upload.en-US.md index 3ed13c1e18..026c1d037d 100644 --- a/src/upload/upload.en-US.md +++ b/src/upload/upload.en-US.md @@ -14,6 +14,7 @@ allowUploadDuplicateFile | Boolean | false | allow to upload duplicate name file autoUpload | Boolean | true | post upload request automatically after files being selected | N beforeAllFilesUpload | Function | - | before all files upload, return false can stop uploading file。Typescript:`(file: UploadFile[]) => boolean \| Promise` | N beforeUpload | Function | - | stop one of files to upload。Typescript:`(file: UploadFile) => boolean \| Promise` | N +cancelUploadButton | TNode | - | cancel upload button props, which showed on `autoUpload=false` and multiple files/images upload。Typescript:`null \| ButtonProps \| TNode<{ disabled: boolean; cancelUploadText: string; cancelUpload: (ctx: { e: MouseEvent }) => void }>`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N children | TNode | - | to define upload trigger elements if `draggable=false`, to define drag elements if `draggable=true`。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N data | Object | - | extra request data of uploading. `formatRequest` can redefine all request data。Typescript:`Record \| ((files: UploadFile[]) => Record)` | N disabled | Boolean | - | make upload to be disabled | N @@ -24,8 +25,9 @@ files | Array | [] | Typescript:`Array` | N defaultFiles | Array | [] | uncontrolled property。Typescript:`Array` | N format | Function | - | to redefine `UploadFile` data structure。Typescript:`(file: File) => UploadFile` | N formatRequest | Function | - | redefine request data。Typescript:`(requestData: { [key: string]: any }) => { [key: string]: any }` | N -formatResponse | Function | - | redefine response data structure。Typescript:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N +formatResponse | Function | - | redefine response data structure。Typescript:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string; status?: 'fail' \| 'success'; files?: UploadFile[] } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N headers | Object | - | HTTP Request Header。Typescript:`{[key: string]: string}` | N +imageViewerProps | Object | - | ImageViewer Component Props。Typescript:`ImageViewerProps`,[ImageViewer API Documents](./image-viewer?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N inputAttributes | Object | - | add attributes to HTML element `input`。Typescript:`CSSProperties` | N isBatchUpload | Boolean | false | make all files to be a whole package, files can only be replaced or deleted together, can not add more files | N locale | Object | - | upload language config, priority of `locale` is higher than global language config。Typescript:`UploadConfig` `import { UploadConfig } from '../config-provider/type'`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N @@ -36,6 +38,7 @@ multiple | Boolean | false | multiple files uploading | N name | String | file | field name of files in upload request data | N placeholder | String | - | placeholder | N requestMethod | Function | - | custom upload request method。Typescript:`(files: UploadFile \| UploadFile[]) => Promise` `interface RequestMethodResponse { status: 'success' \| 'fail'; error?: string; response: { url?: string; files?: UploadFile[]; [key: string]: any } }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N +showImageFileName | Boolean | true | show image's name | N showThumbnail | Boolean | false | show thumbnail before file name, only works on `theme=file-flow` | N showUploadProgress | Boolean | true | show upload progress nodes | N sizeLimit | Number / Object | - | files size limit。Typescript:`number \| SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N @@ -45,11 +48,12 @@ tips | TNode | - | tips text below upload component, define it's color with `sta trigger | TElement | - | trigger elements UI。Typescript:`TNode` `interface TriggerContext { dragActive?: boolean; files: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N triggerButtonProps | Object | - | trigger button props, it can be used to change color/size/href/... of the trigger button。Typescript:`ButtonProps`,[Button API Documents](./button?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N uploadAllFilesInOneRequest | Boolean | false | uploading all files in one request | N -uploadPastedFiles | Boolean | false | allow to upload files in clipboard after pasting | N +uploadButton | TNode | - | upload button props, which showed on `autoUpload=false` and multiple files/images upload。Typescript:`null \| ButtonProps \| TNode<{ disabled: boolean; uploading: boolean; uploadFiles: () => void; uploadText: string }>`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +uploadPastedFiles | Boolean | true | allow to upload files in clipboard after pasting | N useMockProgress | Boolean | true | use mock progress, instead of real progress | N withCredentials | Boolean | false | uploading request with cookie | N onCancelUpload | Function | | Typescript:`() => void`
    trigger on cancel button click | N -onChange | Function | | Typescript:`(value: Array, context: UploadChangeContext) => void`
    trigger on uploaded files change。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。
    `interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`

    `type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail'`
    | N +onChange | Function | | Typescript:`(value: Array, context: UploadChangeContext) => void`
    trigger on uploaded files change。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。
    `interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`

    `type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail' \| 'default'`
    | N onDragenter | Function | | Typescript:`(context: { e: DragEvent }) => void`
    trigger on file dragged into drag elements | N onDragleave | Function | | Typescript:`(context: { e: DragEvent }) => void`
    trigger on file dragged leave drag elements | N onDrop | Function | | Typescript:`(context: { e: DragEvent }) => void`
    trigger on file dropped | N @@ -71,7 +75,7 @@ name | params | return | description className | String | - | 类名 | N style | Object | - | 样式,Typescript:`React.CSSProperties` | N triggerUpload | \- | \- | required。instance function: trigger system file select -uploadFilePercent | \- | \- | required。instance function: set uploading file progress percent +uploadFilePercent | `(params: { file: UploadFile; percent: number })` | \- | required。instance function: set uploading file progress percent uploadFiles | `(files?: UploadFile[])` | \- | required。instance function: upload all files which status are not success ### UploadFile diff --git a/src/upload/upload.md b/src/upload/upload.md index e82ead212f..5516220453 100644 --- a/src/upload/upload.md +++ b/src/upload/upload.md @@ -14,6 +14,7 @@ allowUploadDuplicateFile | Boolean | false | 是否允许重复上传相同文 autoUpload | Boolean | true | 是否在选择文件后自动发起请求上传文件 | N beforeAllFilesUpload | Function | - | 如果是自动上传模式 `autoUpload=true`,表示全部文件上传之前的钩子函数,函数参数为上传的文件,函数返回值决定是否继续上传,若返回值为 `false` 则终止上传。
    如果是非自动上传模式 `autoUpload=false`,则函数返回值为 `false` 时表示本次选中的文件不会加入到文件列表中,即不触发 `onChange` 事件。TS 类型:`(file: UploadFile[]) => boolean \| Promise` | N beforeUpload | Function | - | 如果是自动上传模式 `autoUpload=true`,表示单个文件上传之前的钩子函数,若函数返回值为 `false` 则表示不上传当前文件。
    如果是非自动上传模式 `autoUpload=false`,函数返回值为 `false` 时表示从上传文件中剔除当前文件。TS 类型:`(file: UploadFile) => boolean \| Promise` | N +cancelUploadButton | TNode | - | 批量文件/图片上传,`autoUpload=false` 场景下,透传“取消上传”按钮属性。TS 类型:`null \| ButtonProps \| TNode<{ disabled: boolean; cancelUploadText: string; cancelUpload: (ctx: { e: MouseEvent }) => void }>`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N children | TNode | - | 非拖拽场景,指触发上传的元素,如:“选择文件”。如果是拖拽场景,则是指拖拽区域。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N data | Object | - | 上传请求所需的额外字段,默认字段有 `file`,表示文件信息。可以添加额外的文件名字段,如:`{file_name: "custom-file-name.txt"}`。`autoUpload=true` 时有效。也可以使用 `formatRequest` 完全自定义上传请求的字段。TS 类型:`Record \| ((files: UploadFile[]) => Record)` | N disabled | Boolean | - | 是否禁用 | N @@ -24,18 +25,20 @@ files | Array | [] | 已上传文件列表,同 `value`。TS 类型:`UploadFi defaultFiles | Array | [] | 已上传文件列表,同 `value`。TS 类型:`UploadFile`。非受控属性。TS 类型:`Array` | N format | Function | - | 转换文件 `UploadFile` 的数据结构,可新增或修改 `UploadFile` 的属性,注意不能删除 `UploadFile` 属性。`action` 存在时有效。TS 类型:`(file: File) => UploadFile` | N formatRequest | Function | - | 用于新增或修改文件上传请求 参数。`action` 存在时有效。一个请求上传一个文件时,默认请求字段有 `file`。
    一个请求上传多个文件时,默认字段有 `file[0]/file[1]/file[2]/.../length`,其中 `length` 表示本次上传的文件数量。
    ⚠️非常注意,此处的 `file[0]/file[1]` 仅仅是一个字段名,并非表示 `file` 是一个数组,接口获取字段时注意区分。
    可以使用 `name` 定义 `file` 字段的别名。
    也可以使用 `formatRequest` 自定义任意字段,如添加一个字段 `fileList` ,存储文件数组。TS 类型:`(requestData: { [key: string]: any }) => { [key: string]: any }` | N -formatResponse | Function | - | 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
    此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒,如果存在会判定为本次上传失败。
    此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接。TS 类型:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N +formatResponse | Function | - | 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
    示例返回值:`{ error, url, status, files }`
    此函数的返回值 `error` 会作为错误文本提醒,表示上传失败的原因,如果存在会判定为本次上传失败。
    此函数的返回值 `url` 会作为单个文件上传成功后的链接。
    `files` 表示一个请求同时上传多个文件后的文件列表。TS 类型:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string; status?: 'fail' \| 'success'; files?: UploadFile[] } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N headers | Object | - | 设置上传的请求头部,`action` 存在时有效。TS 类型:`{[key: string]: string}` | N +imageViewerProps | Object | - | 透传图片预览组件全部属性。TS 类型:`ImageViewerProps`,[ImageViewer API Documents](./image-viewer?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N inputAttributes | Object | - | 用于添加属性到 HTML 元素 `input`。TS 类型:`CSSProperties` | N isBatchUpload | Boolean | false | 多个文件是否作为一个独立文件包,整体替换,整体删除。不允许追加文件,只允许替换文件。`theme=file-flow` 时有效 | N locale | Object | - | 上传组件文本语言配置,支持自定义配置组件中的全部文本。优先级高于全局配置中语言。TS 类型:`UploadConfig` `import { UploadConfig } from '../config-provider/type'`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N -max | Number | 0 | 用于控制文件上传数量,值为 0 则不限制 | N +max | Number | 0 | 用于控制文件上传数量,值为 0 则不限制。注意,单文件上传场景,请勿设置 `max` 属性 | N method | String | POST | HTTP 请求类型。可选项:POST/GET/PUT/OPTION/PATCH/post/get/put/option/patch | N mockProgressDuration | Number | - | 模拟进度间隔时间,单位:毫秒,默认:300。由于原始的上传请求,小文件上传进度只有 0 和 100,故而新增模拟进度,每间隔 `mockProgressDuration` 毫秒刷新一次模拟进度。小文件设置小一点,大文件设置大一点。注意:当 `useMockProgress` 为真时,当前设置有效 | N multiple | Boolean | false | 支持多文件上传 | N name | String | file | 文件上传时的名称 | N placeholder | String | - | 占位符 | N requestMethod | Function | - | 自定义上传方法。返回值 `status` 表示上传成功或失败;`error` 或 `response.error` 表示上传失败的原因;
    `response` 表示请求上传成功后的返回数据,`response.url` 表示上传成功后的图片/文件地址,`response.files` 表示一个请求上传多个文件/图片后的返回值。
    示例一:`{ status: 'fail', error: '上传失败', response }`。
    示例二:`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`。
    示例三:`{ status: 'success', files: [{ url: 'https://xxx.png', name: 'xxx.png' }]}`。TS 类型:`(files: UploadFile \| UploadFile[]) => Promise` `interface RequestMethodResponse { status: 'success' \| 'fail'; error?: string; response: { url?: string; files?: UploadFile[]; [key: string]: any } }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N +showImageFileName | Boolean | true | 是否显示图片的文件名称 | N showThumbnail | Boolean | false | 是否在文件列表中显示缩略图,`theme=file-flow` 时有效 | N showUploadProgress | Boolean | true | 是否显示上传进度 | N sizeLimit | Number / Object | - | 图片文件大小限制,默认单位 KB。可选单位有:`'B' \| 'KB' \| 'MB' \| 'GB'`。示例一:`1000`。示例二:`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`。TS 类型:`number \| SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N @@ -45,11 +48,12 @@ tips | TNode | - | 组件下方文本提示,可以使用 `status` 定义文本 trigger | TElement | - | 触发上传的元素,`files` 指本次显示的全部文件。TS 类型:`TNode` `interface TriggerContext { dragActive?: boolean; files: UploadFile[] }`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N triggerButtonProps | Object | - | 透传选择按钮全部属性。TS 类型:`ButtonProps`,[Button API Documents](./button?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts) | N uploadAllFilesInOneRequest | Boolean | false | 是否在同一个请求中上传全部文件,默认一个请求上传一个文件。多文件上传时有效 | N -uploadPastedFiles | Boolean | false | 是否允许粘贴上传剪贴板中的文件 | N +uploadButton | TNode | - | 批量文件/图片上传,`autoUpload=false` 场景下,透传“点击上传”按钮属性。TS 类型:`null \| ButtonProps \| TNode<{ disabled: boolean; uploading: boolean; uploadFiles: () => void; uploadText: string }>`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +uploadPastedFiles | Boolean | true | 是否允许粘贴上传剪贴板中的文件 | N useMockProgress | Boolean | true | 是否在请求时间超过 300ms 后显示模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传,真实的上传进度只有 0 和 100,不利于交互呈现,因此组件内置模拟上传进度。真实上传进度一般用于大文件上传。 | N withCredentials | Boolean | false | 上传请求时是否携带 cookie | N onCancelUpload | Function | | TS 类型:`() => void`
    点击「取消上传」时触发 | N -onChange | Function | | TS 类型:`(value: Array, context: UploadChangeContext) => void`
    已上传文件列表发生变化时触发,`trigger` 表示触发本次的来源。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。
    `interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`

    `type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail'`
    | N +onChange | Function | | TS 类型:`(value: Array, context: UploadChangeContext) => void`
    已上传文件列表发生变化时触发,`trigger` 表示触发本次的来源。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。
    `interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`

    `type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail' \| 'default'`
    | N onDragenter | Function | | TS 类型:`(context: { e: DragEvent }) => void`
    进入拖拽区域时触发 | N onDragleave | Function | | TS 类型:`(context: { e: DragEvent }) => void`
    离开拖拽区域时触发 | N onDrop | Function | | TS 类型:`(context: { e: DragEvent }) => void`
    拖拽结束时触发 | N @@ -71,7 +75,7 @@ onWaitingUploadFilesChange | Function | | TS 类型:`(context: { files: Array className | String | - | 类名 | N style | Object | - | 样式,TS 类型:`React.CSSProperties` | N triggerUpload | \- | \- | 必需。组件实例方法,打开文件选择器 -uploadFilePercent | \- | \- | 必需。设置上传中文件的上传进度 +uploadFilePercent | `(params: { file: UploadFile; percent: number })` | \- | 必需。设置上传中文件的上传进度 uploadFiles | `(files?: UploadFile[])` | \- | 必需。组件实例方法,默认上传未成功上传过的所有文件。带参数时,表示上传指定文件 ### UploadFile diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx index 291f609c48..1439fc4eeb 100644 --- a/src/upload/upload.tsx +++ b/src/upload/upload.tsx @@ -35,6 +35,7 @@ function TdUpload(props: UploadProps, ref: uploadFiles, onNormalFileChange, onDragFileChange, + onPasteFileChange, triggerUpload, cancelUpload, uploadFilePercent, @@ -91,6 +92,7 @@ function TdUpload(props: UploadProps, ref: autoUpload: props.autoUpload, showUploadProgress: props.showUploadProgress, fileListDisplay: props.fileListDisplay, + imageViewerProps: props.imageViewerProps, onRemove, }; @@ -130,6 +132,7 @@ function TdUpload(props: UploadProps, ref: uploadFiles={uploadFiles} cancelUpload={cancelUpload} onPreview={props.onPreview} + showImageFileName={props.showImageFileName} /> ); @@ -143,6 +146,9 @@ function TdUpload(props: UploadProps, ref: cancelUpload={cancelUpload} onPreview={props.onPreview} showThumbnail={props.showThumbnail} + showImageFileName={props.showImageFileName} + uploadButton={props.uploadButton} + cancelUploadButton={props.cancelUploadButton} >
    {triggerElement} @@ -164,8 +170,20 @@ function TdUpload(props: UploadProps, ref: ); + const uploadClasses = [ + props.className, + `${classPrefix}-upload`, + { + [`${classPrefix}-upload--theme-${props.theme}`]: props.theme === 'file-input', + }, + ]; + return ( -
    +
    (props: UploadProps, ref: {props.tips} )} + + {sizeOverLimitMessage && {sizeOverLimitMessage}}
    ); } diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index 4dd31892ec..95e026eef0 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -92225,9 +92225,6 @@ exports[`csr snapshot test > csr test src/form/_example/disabled.jsx 1`] = ` />
    -
    @@ -93008,9 +93005,6 @@ exports[`csr snapshot test > csr test src/form/_example/disabled.jsx 1`] = ` /> -
    @@ -294421,7 +294415,7 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` />

    请选择图片

    @@ -294470,7 +294464,7 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` />

    Click to upload

    @@ -294539,9 +294533,6 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` /> -
    @@ -294636,7 +294627,7 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` />

    Click to upload

    @@ -294793,7 +294784,7 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` />

    请选择图片

    @@ -294842,7 +294833,7 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` />

    Click to upload

    @@ -294911,9 +294902,6 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` /> -
    @@ -295008,7 +294996,7 @@ exports[`csr snapshot test > csr test src/upload/_example/image.jsx 1`] = ` />

    Click to upload

    @@ -295101,20 +295089,77 @@ exports[`csr snapshot test > csr test src/upload/_example/img-flow-list.jsx 1`]
    -
    - 是否自动上传: - +
    + AutoUpload + +
    +
    +
    + +
    +
    + +
    csr test src/upload/_example/img-flow-list.jsx 1`] />
    + + + +
    + + + + + + + + + + + + + +
    + +

    + + + + demo…-1.png +

    + +
  • +
    +
    + +
    +
    + > + + + +
    @@ -295266,11 +295410,120 @@ exports[`csr snapshot test > csr test src/upload/_example/img-flow-list.jsx 1`]

    - demo…-1.png + + + + avatar.jpg

  • + + +
    +
    + + 取消上传 + +
    + +
    + + + +
    +
    +
    +
    +
    + + Different Status Images + +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    • @@ -295308,9 +295561,108 @@ exports[`csr snapshot test > csr test src/upload/_example/img-flow-list.jsx 1`] />
    +
    +
    +
    +
    + + + + + + + + + + + + + +
    + +

    + + + + loading.svg +

    + +
  • +
    +
    + +
    +
    + > + + + +
    @@ -295359,37 +295711,139 @@ exports[`csr snapshot test > csr test src/upload/_example/img-flow-list.jsx 1`]

    - avatar.jpg + + + + loading.svg

  • - - -
    -
    - - Cancel - -
    -