123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652 |
- /* eslint-disable max-len */
- import React, { ReactNode, CSSProperties, RefObject, ChangeEvent, DragEvent } from 'react';
- import cls from 'classnames';
- import PropTypes from 'prop-types';
- import { noop, pick } from 'lodash';
- import UploadFoundation, { CustomFile, UploadAdapter, BeforeUploadObjectResult, AfterUploadResult } from '@douyinfe/semi-foundation/upload/foundation';
- import { strings, cssClasses } from '@douyinfe/semi-foundation/upload/constants';
- import FileCard from './fileCard';
- import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
- import LocaleConsumer from '../locale/localeConsumer';
- import { IconUpload } from '@douyinfe/semi-icons';
- import { FileItem, RenderFileItemProps, UploadListType, PromptPositionType, BeforeUploadProps, AfterUploadProps, OnChangeProps, customRequestArgs, CustomError } from './interface';
- import { Locale } from '../locale/interface';
- import '@douyinfe/semi-foundation/upload/upload.scss';
- const prefixCls = cssClasses.PREFIX;
- export { FileItem, RenderFileItemProps, UploadListType, PromptPositionType, BeforeUploadProps, AfterUploadProps, OnChangeProps, customRequestArgs, CustomError, BeforeUploadObjectResult, AfterUploadResult };
- export interface UploadProps {
- accept?: string;
- action: string;
- afterUpload?: (object: AfterUploadProps) => AfterUploadResult;
- beforeUpload?: (object: BeforeUploadProps) => BeforeUploadObjectResult | Promise<BeforeUploadObjectResult> | boolean;
- beforeClear?: (fileList: Array<FileItem>) => boolean | Promise<boolean>;
- beforeRemove?: (file: FileItem, fileList: Array<FileItem>) => boolean | Promise<boolean>;
- capture?: boolean | string | undefined;
- children?: ReactNode;
- className?: string;
- customRequest?: (object: customRequestArgs) => void;
- data?: Record<string, any> | ((file: File) => Record<string, unknown>);
- defaultFileList?: Array<FileItem>;
- directory?: boolean;
- disabled?: boolean;
- dragIcon?: ReactNode;
- dragMainText?: ReactNode;
- dragSubText?: ReactNode;
- draggable?: boolean;
- fileList?: Array<FileItem>;
- fileName?: string;
- headers?: Record<string, any> | ((file: File) => Record<string, string>);
- hotSpotLocation?: 'start' | 'end';
- itemStyle?: CSSProperties;
- limit?: number;
- listType?: UploadListType;
- maxSize?: number;
- minSize?: number;
- multiple?: boolean;
- name?: string;
- onAcceptInvalid?: (files: File[]) => void;
- onChange?: (object: OnChangeProps) => void;
- onClear?: () => void;
- onDrop?: (e: Event, files: Array<File>, fileList: Array<FileItem>) => void;
- onError?: (e: CustomError, file: File, fileList: Array<FileItem>, xhr: XMLHttpRequest) => void;
- onExceed?: (fileList: Array<File>) => void;
- onFileChange?: (files: Array<File>) => void;
- onOpenFileDialog?: () => void;
- onPreviewClick?: (fileItem: FileItem) => void;
- onProgress?: (percent: number, file: File, fileList: Array<FileItem>) => void;
- onRemove?: (currentFile: File, fileList: Array<FileItem>, currentFileItem: FileItem) => void;
- onRetry?: (fileItem: FileItem) => void;
- onSizeError?: (file: File, fileList: Array<FileItem>) => void;
- onSuccess?: (responseBody: any, file: File, fileList: Array<FileItem>) => void;
- previewFile?: (renderFileItemProps: RenderFileItemProps) => ReactNode;
- prompt?: ReactNode;
- promptPosition?: PromptPositionType;
- renderFileItem?: (renderFileItemProps: RenderFileItemProps) => ReactNode;
- renderPicInfo?: (renderFileItemProps: RenderFileItemProps) => ReactNode;
- renderThumbnail?: (renderFileItemProps: RenderFileItemProps) => ReactNode;
- renderPicPreviewIcon?: (renderFileItemProps: RenderFileItemProps) => ReactNode;
- renderFileOperation?: (fileItem: RenderFileItemProps) => ReactNode;
- showClear?: boolean;
- showPicInfo?: boolean; // Show pic info in picture wall
- showReplace?: boolean; // Display replacement function
- showRetry?: boolean;
- showUploadList?: boolean;
- style?: CSSProperties;
- timeout?: number;
- transformFile?: (file: File) => FileItem;
- uploadTrigger?: 'auto' | 'custom';
- validateMessage?: ReactNode;
- validateStatus?: ValidateStatus;
- withCredentials?: boolean;
- }
- export interface UploadState {
- dragAreaStatus: 'default' | 'legal' | 'illegal'; // Status of the drag zone
- fileList: Array<FileItem>;
- inputKey: number;
- localUrls: Array<string>;
- replaceIdx: number;
- replaceInputKey: number;
- }
- class Upload extends BaseComponent<UploadProps, UploadState> {
- static propTypes = {
- accept: PropTypes.string, // Limit allowed file types
- action: PropTypes.string.isRequired,
- afterUpload: PropTypes.func,
- beforeClear: PropTypes.func,
- beforeRemove: PropTypes.func,
- beforeUpload: PropTypes.func,
- children: PropTypes.node,
- className: PropTypes.string,
- customRequest: PropTypes.func,
- data: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), // Extra parameters attached when uploading
- defaultFileList: PropTypes.array,
- directory: PropTypes.bool, // Support folder upload
- disabled: PropTypes.bool,
- dragIcon: PropTypes.node,
- dragMainText: PropTypes.node,
- dragSubText: PropTypes.node,
- draggable: PropTypes.bool,
- fileList: PropTypes.array, // files had been uploaded
- fileName: PropTypes.string, // same as name, to avoid props conflict in Form.Upload
- headers: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
- hotSpotLocation: PropTypes.oneOf(['start','end']),
- itemStyle: PropTypes.object,
- limit: PropTypes.number, // 最大允许上传文件个数
- listType: PropTypes.oneOf<UploadProps['listType']>(strings.LIST_TYPE),
- maxSize: PropTypes.number, // 文件大小限制,单位kb
- minSize: PropTypes.number, // 文件大小限制,单位kb
- multiple: PropTypes.bool,
- name: PropTypes.string, // file name
- onAcceptInvalid: PropTypes.func,
- onChange: PropTypes.func,
- onClear: PropTypes.func,
- onDrop: PropTypes.func,
- onError: PropTypes.func,
- onExceed: PropTypes.func, // Callback exceeding limit
- onFileChange: PropTypes.func, // Callback when file is selected
- onOpenFileDialog: PropTypes.func,
- onPreviewClick: PropTypes.func,
- onProgress: PropTypes.func,
- onRemove: PropTypes.func,
- onRetry: PropTypes.func,
- onSizeError: PropTypes.func, // Callback with invalid file size
- onSuccess: PropTypes.func,
- previewFile: PropTypes.func, // Custom preview
- prompt: PropTypes.node,
- promptPosition: PropTypes.oneOf<UploadProps['promptPosition']>(strings.PROMPT_POSITION),
- renderFileItem: PropTypes.func,
- renderPicPreviewIcon: PropTypes.func,
- renderFileOperation: PropTypes.func,
- renderPicInfo: PropTypes.func,
- renderThumbnail: PropTypes.func,
- showClear: PropTypes.bool,
- showPicInfo: PropTypes.bool,
- showReplace: PropTypes.bool,
- showRetry: PropTypes.bool,
- showUploadList: PropTypes.bool, // whether to show fileList
- style: PropTypes.object,
- timeout: PropTypes.number,
- transformFile: PropTypes.func,
- uploadTrigger: PropTypes.oneOf<UploadProps['uploadTrigger']>(strings.UPLOAD_TRIGGER), // auto、custom
- validateMessage: PropTypes.node,
- validateStatus: PropTypes.oneOf<UploadProps['validateStatus']>(strings.VALIDATE_STATUS),
- withCredentials: PropTypes.bool,
- };
- static defaultProps: Partial<UploadProps> = {
- defaultFileList: [],
- disabled: false,
- listType: 'list' as const,
- hotSpotLocation: 'end',
- multiple: false,
- onAcceptInvalid: noop,
- onChange: noop,
- beforeRemove: () => true,
- beforeClear: () => true,
- onClear: noop,
- onDrop: noop,
- onError: noop,
- onExceed: noop,
- onFileChange: noop,
- onOpenFileDialog: noop,
- onProgress: noop,
- onRemove: noop,
- onRetry: noop,
- onSizeError: noop,
- onSuccess: noop,
- promptPosition: 'right' as const,
- showClear: true,
- showPicInfo: false,
- showReplace: false,
- showRetry: true,
- showUploadList: true,
- uploadTrigger: 'auto' as const,
- withCredentials: false,
- };
- static FileCard = FileCard;
- constructor(props: UploadProps) {
- super(props);
- this.state = {
- fileList: props.defaultFileList || [],
- replaceIdx: -1,
- inputKey: Math.random(),
- replaceInputKey: Math.random(),
- // Status of the drag zone
- dragAreaStatus: 'default',
- localUrls: [],
- };
- this.foundation = new UploadFoundation(this.adapter);
- this.inputRef = React.createRef<HTMLInputElement>();
- this.replaceInputRef = React.createRef<HTMLInputElement>();
- }
- /**
- * Notes:
- * The input parameter and return value here do not declare the type, otherwise tsc may report an error in form/fields.tsx when wrap after withField
- * `The types of the parameters "props" and "nextProps" are incompatible.
- The attribute "action" is missing in the type "Readonly<any>", but it is required in the type "UploadProps".`
- * which seems to be a bug, remove props type declare here
- */
- static getDerivedStateFromProps(props) {
- const { fileList } = props;
- if ('fileList' in props) {
- return {
- fileList: fileList || []
- };
- }
- return null;
- }
- get adapter(): UploadAdapter<UploadProps, UploadState> {
- return {
- ...super.adapter,
- notifyFileSelect: (files): void => this.props.onFileChange(files),
- notifyError: (error, fileInstance, fileList, xhr): void => this.props.onError(error, fileInstance, fileList, xhr),
- notifySuccess: (responseBody, file, fileList): void => this.props.onSuccess(responseBody, file, fileList),
- notifyProgress: (percent, file, fileList): void => this.props.onProgress(percent, file, fileList),
- notifyRemove: (file, fileList, fileItem): void => this.props.onRemove(file, fileList, fileItem),
- notifySizeError: (file, fileList): void => this.props.onSizeError(file, fileList),
- notifyExceed: (fileList): void => this.props.onExceed(fileList),
- updateFileList: (fileList, cb): void => {
- if (typeof cb === 'function') {
- this.setState({ fileList }, cb);
- } else {
- this.setState({ fileList });
- }
- },
- notifyBeforeUpload: ({ file, fileList }): boolean | BeforeUploadObjectResult | Promise<BeforeUploadObjectResult> => this.props.beforeUpload({ file, fileList }),
- notifyAfterUpload: ({ response, file, fileList }): AfterUploadResult => this.props.afterUpload({ response, file, fileList }),
- resetInput: (): void => {
- this.setState(prevState => ({
- inputKey: Math.random()
- }));
- },
- resetReplaceInput: (): void => {
- this.setState(prevState => ({
- replaceInputKey: Math.random()
- }));
- },
- updateDragAreaStatus: (dragAreaStatus: string): void => this.setState({ dragAreaStatus } as { dragAreaStatus: 'default' | 'legal' | 'illegal' }),
- notifyChange: ({ currentFile, fileList }): void => this.props.onChange({ currentFile, fileList }),
- updateLocalUrls: (urls): void => this.setState({ localUrls: urls }),
- notifyClear: (): void => this.props.onClear(),
- notifyPreviewClick: (file): void => this.props.onPreviewClick(file),
- notifyDrop: (e, files, fileList): void => this.props.onDrop(e, files, fileList),
- notifyAcceptInvalid: (invalidFiles): void => this.props.onAcceptInvalid(invalidFiles),
- notifyBeforeRemove: (file, fileList): boolean | Promise<boolean> => this.props.beforeRemove(file, fileList),
- notifyBeforeClear: (fileList): boolean | Promise<boolean> => this.props.beforeClear(fileList),
- };
- }
- foundation: UploadFoundation;
- inputRef: RefObject<HTMLInputElement> = null;
- replaceInputRef: RefObject<HTMLInputElement> = null;
- componentWillUnmount(): void {
- this.foundation.destroy();
- }
- onClick = (): void => {
- const { inputRef, props } = this;
- const { onOpenFileDialog } = props;
- const isDisabled = Boolean(this.props.disabled);
- if (isDisabled || !inputRef || !inputRef.current) {
- return;
- }
- inputRef.current.click();
- if (onOpenFileDialog && typeof onOpenFileDialog) {
- onOpenFileDialog();
- }
- };
- onChange = (e: ChangeEvent<HTMLInputElement>): void => {
- const { files } = e.target;
- this.foundation.handleChange(files);
- };
- replace = (index: number): void => {
- this.setState({ replaceIdx: index }, () => {
- this.replaceInputRef.current.click();
- });
- };
- onReplaceChange = (e: ChangeEvent<HTMLInputElement>): void => {
- const { files } = e.target;
- this.foundation.handleReplaceChange(files);
- };
- clear = (): void => {
- this.foundation.handleClear();
- };
- remove = (fileItem: FileItem): void => {
- this.foundation.handleRemove(fileItem);
- };
- /**
- * ref method
- * insert files at index
- * @param files Array<CustomFile>
- * @param index number
- * @returns
- */
- insert = (files: Array<CustomFile>, index: number): void => {
- return this.foundation.insertFileToList(files, index);
- }
- /**
- * ref method
- * manual upload by user
- */
- upload = (): void => {
- const { fileList } = this.state;
- this.foundation.startUpload(fileList);
- };
- renderFile = (file: FileItem, index: number, locale: Locale['Upload']): ReactNode => {
- const { name, status, validateMessage, _sizeInvalid, uid } = file;
- const { previewFile, listType, itemStyle, showPicInfo, renderPicInfo, renderPicPreviewIcon, renderFileOperation, renderFileItem, renderThumbnail, disabled, onPreviewClick } = this.props;
- const onRemove = (): void => this.remove(file);
- const onRetry = (): void => {
- this.foundation.retry(file);
- };
- const onReplace = (): void => {
- this.replace(index);
- };
- const fileCardProps = {
- ...pick(this.props, ['showRetry', 'showReplace', '']),
- ...file,
- previewFile,
- listType,
- onRemove,
- onRetry,
- index,
- key: uid || `${name}${index}`,
- style: itemStyle,
- disabled,
- showPicInfo,
- renderPicInfo,
- renderPicPreviewIcon,
- renderFileOperation,
- renderThumbnail,
- onReplace,
- onPreviewClick: typeof onPreviewClick !== 'undefined' ? (): void => this.foundation.handlePreviewClick(file) : undefined,
- };
- if (status === strings.FILE_STATUS_UPLOAD_FAIL && !validateMessage) {
- fileCardProps.validateMessage = locale.fail;
- }
- if (_sizeInvalid && !validateMessage) {
- fileCardProps.validateMessage = locale.illegalSize;
- }
- if (typeof renderFileItem === 'undefined') {
- return <FileCard {...fileCardProps} />;
- } else {
- return renderFileItem(fileCardProps);
- }
- };
- renderFileList = (): ReactNode => {
- const { listType } = this.props;
- if (listType === strings.FILE_LIST_PIC) {
- return this.renderFileListPic();
- }
- if (listType === strings.FILE_LIST_DEFAULT) {
- return this.renderFileListDefault();
- }
- return null;
- };
- renderFileListPic = () => {
- const { showUploadList, limit, disabled, children, draggable, hotSpotLocation } = this.props;
- const { fileList: stateFileList, dragAreaStatus } = this.state;
- const fileList = this.props.fileList || stateFileList;
- const showAddTriggerInList = limit ? limit > fileList.length : true;
- const dragAreaBaseCls = `${prefixCls}-drag-area`;
- const uploadAddCls = cls(`${prefixCls}-add`, {
- [`${prefixCls}-picture-add`]: true,
- [`${prefixCls}-picture-add-disabled`]: disabled,
- });
- const fileListCls = cls(`${prefixCls}-file-list`, {
- [`${prefixCls}-picture-file-list`]: true,
- });
- const dragAreaCls = cls({
- [`${dragAreaBaseCls}-legal`]: dragAreaStatus === strings.DRAG_AREA_LEGAL,
- [`${dragAreaBaseCls}-illegal`]: dragAreaStatus === strings.DRAG_AREA_ILLEGAL
- });
- const mainCls = `${prefixCls}-file-list-main`;
- const addContentProps = {
- role: 'button',
- className: uploadAddCls,
- onClick: this.onClick,
- };
- const containerProps = {
- className: fileListCls
- };
- const draggableProps = {
- onDrop: this.onDrop,
- onDragOver: this.onDragOver,
- onDragLeave: this.onDragLeave,
- onDragEnter: this.onDragEnter,
- };
- if (draggable) {
- Object.assign(addContentProps, draggableProps, { className: cls(uploadAddCls, dragAreaCls) });
- }
- const addContent = (
- <div {...addContentProps}>
- {children}
- </div>
- );
- if (!showUploadList || !fileList.length) {
- if (showAddTriggerInList) {
- return addContent;
- }
- return null;
- }
- return (
- <LocaleConsumer componentName="Upload">
- {(locale: Locale['Upload']) => (
- <div {...containerProps}>
- <div className={mainCls} role="list" aria-label="picture list">
- {showAddTriggerInList && hotSpotLocation === 'start' ? addContent : null}
- {fileList.map((file, index) => this.renderFile(file, index, locale))}
- {showAddTriggerInList && hotSpotLocation === 'end' ? addContent : null}
- </div>
- </div>
- )}
- </LocaleConsumer>
- );
- }
- renderFileListDefault = () => {
- const { showUploadList, limit, disabled } = this.props;
- const { fileList: stateFileList } = this.state;
- const fileList = this.props.fileList || stateFileList;
- const fileListCls = cls(`${prefixCls}-file-list`);
- const titleCls = `${prefixCls}-file-list-title`;
- const mainCls = `${prefixCls}-file-list-main`;
- const showTitle = limit !== 1 && fileList.length;
- const showClear = this.props.showClear && !disabled;
- const containerProps = {
- className: fileListCls
- };
- if (!showUploadList || !fileList.length) {
- return null;
- }
- return (
- <LocaleConsumer componentName="Upload">
- {(locale: Locale['Upload']) => (
- <div {...containerProps}>
- {showTitle ? (
- <div className={titleCls}>
- <span className={`${titleCls}-choosen`}>{locale.selectedFiles}</span>
- {showClear ? (
- <span role="button" tabIndex={0} onClick={this.clear} className={`${titleCls}-clear`}>
- {locale.clear}
- </span>
- ) : null}
- </div>
- ) : null}
- <div className={mainCls} role="list" aria-label="file list">
- {fileList.map((file, index) => this.renderFile(file, index, locale))}
- </div>
- </div>
- )}
- </LocaleConsumer>
- );
- }
- onDrop = (e: DragEvent<HTMLDivElement>): void => {
- this.foundation.handleDrop(e);
- };
- onDragOver = (e: DragEvent<HTMLDivElement>): void => {
- // When a drag element moves within the target element
- this.foundation.handleDragOver(e);
- };
- onDragLeave = (e: DragEvent<HTMLDivElement>): void => {
- this.foundation.handleDragLeave(e);
- };
- onDragEnter = (e: DragEvent<HTMLDivElement>): void => {
- this.foundation.handleDragEnter(e);
- };
- renderAddContent = () => {
- const { draggable, children, listType, disabled } = this.props;
- const uploadAddCls = cls(`${prefixCls}-add`);
- if (listType === strings.FILE_LIST_PIC) {
- return null;
- }
- if (draggable) {
- return this.renderDragArea();
- }
- return (
- <div role="button" tabIndex={0} aria-disabled={disabled} className={uploadAddCls} onClick={this.onClick}>
- {children}
- </div>
- );
- }
- renderDragArea = (): ReactNode => {
- const { dragAreaStatus } = this.state;
- const { children, dragIcon, dragMainText, dragSubText, disabled } = this.props;
- const dragAreaBaseCls = `${prefixCls}-drag-area`;
- const dragAreaCls = cls(dragAreaBaseCls, {
- [`${dragAreaBaseCls}-legal`]: dragAreaStatus === strings.DRAG_AREA_LEGAL,
- [`${dragAreaBaseCls}-illegal`]: dragAreaStatus === strings.DRAG_AREA_ILLEGAL,
- [`${dragAreaBaseCls}-custom`]: children,
- });
- return (
- <LocaleConsumer componentName="Upload">
- {(locale: Locale['Upload']): ReactNode => (
- <div
- role="button"
- tabIndex={0}
- aria-disabled={disabled}
- className={dragAreaCls}
- onDrop={this.onDrop}
- onDragOver={this.onDragOver}
- onDragLeave={this.onDragLeave}
- onDragEnter={this.onDragEnter}
- onClick={this.onClick}
- >
- {children ? (
- children
- ) : (
- <>
- <div className={`${dragAreaBaseCls}-icon`}>
- {dragIcon || <IconUpload size="extra-large" />}
- </div>
- <div className={`${dragAreaBaseCls}-text`}>
- <div className={`${dragAreaBaseCls}-main-text`}>
- {dragMainText || locale.mainText}
- </div>
- <div className={`${dragAreaBaseCls}-sub-text`}>{dragSubText}</div>
- <div className={`${dragAreaBaseCls}-tips`}>
- {dragAreaStatus === strings.DRAG_AREA_LEGAL && (
- <span className={`${dragAreaBaseCls}-tips-legal`}>{locale.legalTips}</span>
- )}
- {dragAreaStatus === strings.DRAG_AREA_ILLEGAL && (
- <span className={`${dragAreaBaseCls}-tips-illegal`}>
- {locale.illegalTips}
- </span>
- )}
- </div>
- </div>
- </>
- )}
- </div>
- )}
- </LocaleConsumer>
- );
- };
- render(): ReactNode {
- const {
- style,
- className,
- multiple,
- accept,
- disabled,
- children,
- capture,
- listType,
- prompt,
- promptPosition,
- draggable,
- validateMessage,
- validateStatus,
- directory,
- } = this.props;
- const uploadCls = cls(prefixCls, {
- [`${prefixCls}-picture`]: listType === strings.FILE_LIST_PIC,
- [`${prefixCls}-disabled`]: disabled,
- [`${prefixCls}-default`]: validateStatus === 'default',
- [`${prefixCls}-error`]: validateStatus === 'error',
- [`${prefixCls}-warning`]: validateStatus === 'warning',
- [`${prefixCls}-success`]: validateStatus === 'success',
- }, className);
- const inputCls = cls(`${prefixCls}-hidden-input`);
- const inputReplaceCls = cls(`${prefixCls}-hidden-input-replace`);
- const promptCls = cls(`${prefixCls}-prompt`);
- const validateMsgCls = cls(`${prefixCls}-validate-message`);
- const dirProps = directory ? { directory: 'directory', webkitdirectory: 'webkitdirectory' } : {};
- return (
- <div className={uploadCls} style={style} x-prompt-pos={promptPosition}>
- <input
- key={this.state.inputKey}
- capture={capture}
- multiple={multiple}
- accept={accept}
- onChange={this.onChange}
- type="file"
- autoComplete="off"
- tabIndex={-1}
- className={inputCls}
- ref={this.inputRef}
- {...dirProps}
- />
- <input
- key={this.state.replaceInputKey}
- multiple={false}
- accept={accept}
- onChange={this.onReplaceChange}
- type="file"
- autoComplete="off"
- tabIndex={-1}
- className={inputReplaceCls}
- ref={this.replaceInputRef}
- />
- {this.renderAddContent()}
- {prompt ? <div className={promptCls}>{prompt}</div> : null}
- {validateMessage ? <div className={validateMsgCls}>{validateMessage}</div> : null}
- {this.renderFileList()}
- </div>
- );
- }
- }
- export default Upload;
|