Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(upload): fileListDisplay #1781

Merged
merged 4 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** React 特有全局类型 */

import { ReactElement, ReactNode, CSSProperties, FormEvent } from 'react';
import { ReactElement, ReactNode, CSSProperties, FormEvent, DragEvent } from 'react';

// TElement 表示 API 只接受传入组件
export type TElement = ReactElement | (() => ReactElement);
Expand All @@ -26,6 +26,13 @@ export interface StyledProps {
className?: string;
style?: CSSProperties;
}

export interface UploadDisplayDragEvents {
onDrop?: (event: DragEvent<HTMLDivElement>) => void;
onDragEnter?: (event: DragEvent<HTMLDivElement>) => void;
onDragOver?: (event: DragEvent<HTMLDivElement>) => void;
onDragLeave?: (event: DragEvent<HTMLDivElement>) => void;
}
/** 通用全局类型 */

export type OptionData = {
Expand Down
1 change: 1 addition & 0 deletions src/upload/hooks/useUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export default function useUpload(props: TdUploadProps) {
currentFiles: p.files,
percent: p.percent,
type: p.type,
XMLHttpRequest: p.XMLHttpRequest,
});
};

Expand Down
27 changes: 14 additions & 13 deletions src/upload/themes/DraggerFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from 'tdesign-icons-react';
import { abridgeName, getFileSizeText } from '../../_common/js/upload/utils';
import { TdUploadProps, UploadFile } from '../type';
import Button from '../../button';
import Link from '../../link';
import { CommonDisplayFileProps } from '../interface';
import useCommonClassName from '../../hooks/useCommonClassName';
import TLoading from '../../loading';
Expand Down Expand Up @@ -93,9 +93,10 @@ const DraggerFile: FC<DraggerProps> = (props) => {
</small>
<div className={`${uploadPrefix}__dragger-btns`}>
{['progress', 'waiting'].includes(file.status) && !disabled && (
<Button
<Link
theme="primary"
variant="text"
hover="color"
disabled={disabled}
className={`${uploadPrefix}__dragger-progress-cancel`}
onClick={(e) =>
props.cancelUpload?.({
Expand All @@ -105,40 +106,40 @@ const DraggerFile: FC<DraggerProps> = (props) => {
}
>
{locale?.cancelUploadText}
</Button>
</Link>
)}
{!props.autoUpload && file.status === 'waiting' && (
<Button
variant="text"
<Link
theme="primary"
hover="color"
disabled={disabled}
onClick={() => props.uploadFiles?.()}
className={`${uploadPrefix}__dragger-upload-btn`}
>
{locale.triggerUploadText.normal}
</Button>
</Link>
)}
</div>
{['fail', 'success'].includes(file?.status) && !disabled && (
<div className={`${uploadPrefix}__dragger-btns`}>
<Button
<Link
theme="primary"
variant="text"
hover="color"
disabled={disabled}
className={`${uploadPrefix}__dragger-progress-cancel`}
onClick={props.triggerUpload}
>
{locale.triggerUploadText.reupload}
</Button>
<Button
</Link>
<Link
theme="danger"
variant="text"
hover="color"
disabled={disabled}
className={`${uploadPrefix}__dragger-delete-btn`}
onClick={(e) => props.onRemove({ e, index: 0, file })}
>
{locale.triggerUploadText.delete}
</Button>
</Link>
</div>
)}
</div>
Expand Down
99 changes: 54 additions & 45 deletions src/upload/themes/MultipleFlowList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface ImageFlowListProps extends CommonDisplayFileProps {
}

const ImageFlowList = (props: ImageFlowListProps) => {
const { draggable = true } = props;
// locale 已经在 useUpload 中统一处理优先级
const { locale, uploading, disabled, displayFiles, classPrefix } = props;
const uploadPrefix = `${classPrefix}-upload`;
Expand All @@ -47,8 +48,7 @@ const ImageFlowList = (props: ImageFlowListProps) => {
return locale.triggerUploadText.normal;
}, [locale, uploading]);

const draggable = props.draggable ?? true;
const dragEvents = draggable
const innerDragEvents = draggable
? {
onDrop: drag.handleDrop,
onDragEnter: drag.handleDragenter,
Expand Down Expand Up @@ -173,50 +173,59 @@ const ImageFlowList = (props: ImageFlowListProps) => {
</td>
) : null;

const renderFileList = () => (
<table className={`${uploadPrefix}__flow-table`} {...dragEvents}>
<thead>
<tr>
<th>{locale.file?.fileNameText}</th>
<th>{locale.file?.fileSizeText}</th>
<th>{locale.file?.fileStatusText}</th>
{disabled ? null : <th>{locale.file?.fileOperationText}</th>}
</tr>
</thead>
<tbody>
{!displayFiles.length && (
const renderFileList = () => {
if (props.fileListDisplay) {
const list = props.fileListDisplay({
files: displayFiles,
dragEvents: innerDragEvents,
});
return list;
}
return (
<table className={`${uploadPrefix}__flow-table`} {...innerDragEvents}>
<thead>
<tr>
<td colSpan={4}>{renderEmpty()}</td>
<th>{locale.file?.fileNameText}</th>
<th>{locale.file?.fileSizeText}</th>
<th>{locale.file?.fileStatusText}</th>
{disabled ? null : <th>{locale.file?.fileOperationText}</th>}
</tr>
)}
{displayFiles.map((file, index) => {
// 合并操作出现条件为:当前为合并上传模式且列表内没有待上传文件
const showBatchUploadAction = props.isBatchUpload;
const deleteNode =
showBatchUploadAction && !displayFiles.find((item) => item.status !== 'success')
? renderBatchActionCol(index)
: renderNormalActionCol(file, index);
const fileName = props.abridgeName?.length ? abridgeName(file.name, ...props.abridgeName) : file.name;
return (
<tr key={file.name + index}>
<td>
{file.url ? (
<Link href={file.url} target="_blank" hover="color">
{fileName}
</Link>
) : (
fileName
)}
</td>
<td>{returnFileSize(file.size)}</td>
<td>{renderStatus(file)}</td>
{disabled ? null : deleteNode}
</thead>
<tbody>
{!displayFiles.length && (
<tr>
<td colSpan={4}>{renderEmpty()}</td>
</tr>
);
})}
</tbody>
</table>
);
)}
{displayFiles.map((file, index) => {
// 合并操作出现条件为:当前为合并上传模式且列表内没有待上传文件
const showBatchUploadAction = props.isBatchUpload;
const deleteNode =
showBatchUploadAction && !displayFiles.find((item) => item.status !== 'success')
? renderBatchActionCol(index)
: renderNormalActionCol(file, index);
const fileName = props.abridgeName?.length ? abridgeName(file.name, ...props.abridgeName) : file.name;
return (
<tr key={file.name + index}>
<td>
{file.url ? (
<Link href={file.url} target="_blank" hover="color">
{fileName}
</Link>
) : (
fileName
)}
</td>
<td>{returnFileSize(file.size)}</td>
<td>{renderStatus(file)}</td>
{disabled ? null : deleteNode}
</tr>
);
})}
</tbody>
</table>
);
};

const cardClassName = `${uploadPrefix}__flow-card-area`;
return (
Expand All @@ -231,7 +240,7 @@ const ImageFlowList = (props: ImageFlowListProps) => {
</div>

{props.theme === 'image-flow' && (
<div className={cardClassName} {...dragEvents}>
<div className={cardClassName} {...innerDragEvents}>
{displayFiles.length ? (
<ul className={`${uploadPrefix}__card clearfix`}>
{displayFiles.map((file, index) => renderImgItem(file, index))}
Expand All @@ -246,7 +255,7 @@ const ImageFlowList = (props: ImageFlowListProps) => {
(displayFiles.length ? (
renderFileList()
) : (
<div className={cardClassName} {...dragEvents}>
<div className={cardClassName} {...innerDragEvents}>
{renderEmpty()}
</div>
))}
Expand Down
5 changes: 3 additions & 2 deletions src/upload/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { UploadConfig } from '../config-provider/type';
import { ButtonProps } from '../button';
import { TNode } from '../common';
import { TNode, UploadDisplayDragEvents } from '../common';
import { MouseEvent, DragEvent } from 'react';

export interface TdUploadProps<T extends UploadFile = UploadFile> {
Expand Down Expand Up @@ -65,7 +65,7 @@ export interface TdUploadProps<T extends UploadFile = UploadFile> {
/**
* 用于完全自定义文件列表内容
*/
fileListDisplay?: TNode<{ files: UploadFile[] }>;
fileListDisplay?: TNode<{ files: UploadFile[]; dragEvents?: UploadDisplayDragEvents }>;
/**
* 已上传文件列表,同 `value`
* @default []
Expand Down Expand Up @@ -363,6 +363,7 @@ export interface ProgressContext {
currentFiles: UploadFile[];
percent: number;
type: UploadProgressType;
XMLHttpRequest?: XMLHttpRequest;
}

export type UploadProgressType = 'real' | 'mock';
Expand Down
4 changes: 2 additions & 2 deletions src/upload/upload.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ data | Object | - | Typescript:`Record<string, any> \| ((file: File) => Record
disabled | Boolean | - | \- | N
dragContent | TNode | - | drag content。Typescript:`TNode \| TNode<TriggerContext>`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N
draggable | Boolean | undefined | \- | N
fileListDisplay | TElement | - | Typescript:`TNode<{ files: UploadFile[] }>`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N
fileListDisplay | TElement | - | Typescript:`TNode<{ files: UploadFile[]; dragEvents?: UploadDisplayDragEvents }>`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N
files | Array | [] | Typescript:`Array<T>` | N
defaultFiles | Array | [] | uncontrolled property。Typescript:`Array<T>` | N
format | Function | - | Typescript:`(file: File) => UploadFile` | N
Expand Down Expand Up @@ -55,7 +55,7 @@ onFail | Function | | Typescript:`(options: UploadFailContext) => void`<br/>`
onOneFileFail | Function | | Typescript:`(options: UploadFailContext) => void`<br/>trigger on one file upload failed | N
onOneFileSuccess | Function | | Typescript:`(context: Pick<SuccessContext, 'e' \| 'file' \| 'response'>) => void`<br/> | N
onPreview | Function | | Typescript:`(options: { file: UploadFile; index: number; e: MouseEvent }) => void`<br/> | N
onProgress | Function | | Typescript:`(options: ProgressContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/> | N
onProgress | Function | | Typescript:`(options: ProgressContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType; XMLHttpRequest?: XMLHttpRequest }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/> | N
onRemove | Function | | Typescript:`(context: UploadRemoveContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface UploadRemoveContext { index?: number; file?: UploadFile; e: MouseEvent }`<br/> | N
onSelectChange | Function | | Typescript:`(files: File[], context: UploadSelectChangeContext) => void`<br/>trigger after file choose and before upload。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[] }`<br/> | N
onSuccess | Function | | Typescript:`(context: SuccessContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; currentFiles?: UploadFile[]; response?: any; results?: SuccessContext[] }`<br/> | N
Expand Down
4 changes: 2 additions & 2 deletions src/upload/upload.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ data | Object | - | 上传文件时所需的额外数据。TS 类型:`Record<s
disabled | Boolean | - | 是否禁用 | N
dragContent | TNode | - | 用于自定义拖拽区域。TS 类型:`TNode \| TNode<TriggerContext>`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N
draggable | Boolean | undefined | 是否启用拖拽上传,不同的组件风格默认值不同 | N
fileListDisplay | TElement | - | 用于完全自定义文件列表内容。TS 类型:`TNode<{ files: UploadFile[] }>`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N
fileListDisplay | TElement | - | 用于完全自定义文件列表内容。TS 类型:`TNode<{ files: UploadFile[]; dragEvents?: UploadDisplayDragEvents }>`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N
files | Array | [] | 已上传文件列表,同 `value`。TS 类型:`Array<T>` | N
defaultFiles | Array | [] | 已上传文件列表,同 `value`。非受控属性。TS 类型:`Array<T>` | N
format | Function | - | 文件上传前转换文件的数据结构,可新增或修改文件对象的属性。TS 类型:`(file: File) => UploadFile` | N
Expand Down Expand Up @@ -55,7 +55,7 @@ onFail | Function | | TS 类型:`(options: UploadFailContext) => void`<br/>
onOneFileFail | Function | | TS 类型:`(options: UploadFailContext) => void`<br/>多文件/图片场景下,单个文件上传失败后触发,如果一个请求上传一个文件,则会触发多次。单文件/图片不会触发 | N
onOneFileSuccess | Function | | TS 类型:`(context: Pick<SuccessContext, 'e' \| 'file' \| 'response'>) => void`<br/>单个文件上传成功后触发,在多文件场景下会触发多次。`context.file` 表示当前上传成功的单个文件,`context.response` 表示上传请求的返回数据 | N
onPreview | Function | | TS 类型:`(options: { file: UploadFile; index: number; e: MouseEvent }) => void`<br/>点击图片预览时触发,文件没有预览 | N
onProgress | Function | | TS 类型:`(options: ProgressContext) => void`<br/>上传进度变化时触发,真实进度和模拟进度都会触发。`type=real` 表示真实上传进度,`type=mock` 表示模拟上传进度。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/> | N
onProgress | Function | | TS 类型:`(options: ProgressContext) => void`<br/>上传进度变化时触发,真实进度和模拟进度都会触发。`type=real` 表示真实上传进度,`type=mock` 表示模拟上传进度。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType; XMLHttpRequest?: XMLHttpRequest }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/> | N
onRemove | Function | | TS 类型:`(context: UploadRemoveContext) => void`<br/>移除文件时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface UploadRemoveContext { index?: number; file?: UploadFile; e: MouseEvent }`<br/> | N
onSelectChange | Function | | TS 类型:`(files: File[], context: UploadSelectChangeContext) => void`<br/>选择文件或图片之后,上传之前,触发该事件。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[] }`<br/> | N
onSuccess | Function | | TS 类型:`(context: SuccessContext) => void`<br/>上传成功后触发。<br/>`context.currentFiles` 表示当次请求上传的文件,`context.fileList` 表示上传成功后的文件,`context.response` 表示上传请求的返回数据。<br/>`context.results` 表示单次选择全部文件上传成功后的响应结果,可以在这个字段存在时提醒用户上传成功或失败。<br />。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; currentFiles?: UploadFile[]; response?: any; results?: SuccessContext[] }`<br/> | N
Expand Down
Loading