Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | 1x 6x 6x 6x | import React, { useState } from "react"; import { useDropzone } from "react-dropzone"; import { StyledProps } from "../_type"; import { upload, ProgressInfo, UploadEventContext } from "./uploadFile"; import { uuid } from "../_util/uuid"; import { injectValue } from "../_util/inject-value"; import { isCallable } from "../_util/is-callable"; import { File } from "./preset/File"; import { Dragger } from "./preset/Dragger"; import { Image } from "./preset/Image"; import { withStatics } from "../_util/with-statics"; import { UploadContext } from "./UploadContext"; export interface UploadProps extends StyledProps { /** * 唤起文件选择的组件 * * 直接传递 ReactNode 将默认在该元素使用点击上传 * * 使用 Render Props 形式可自定义点击/拖拽上传 * * - `open`: 打开文件选择 * - `getDraggerProps(props?)`: 在需要执行拖拽的根元素传递这些 props * - `isDragging`: 是否有文件拖拽至可拖拽区域 * * @docType React.ReactNode | (props: { open: () => void, getDraggerProps: (props?: object) => object, isDragging: boolean }) => React.ReactNode; */ children: | React.ReactNode | ((props: { open: () => void; getDraggerProps: (props?: object) => object; isDragging: boolean; }) => React.ReactNode); /** * 是否支持多选文件 * @default false */ multiple?: boolean; /** * 上传地址 */ action?: string; /** * 接受的文件类型 */ accept?: string | string[]; /** * 上传文件大小限制(bytes) */ maxSize?: number; /** * 请求文件参数名 * @default "file" */ name?: string; /** * 设置请求头部 */ headers?: object | ((file: File) => object); /** * 附加请求参数 */ data?: object | ((file: File) => object); /** * 请求时是否携带 cookie * @default false */ withCredentials?: boolean; /** * 上传文件前调用 * * - `isAccepted`: 当前文件是否符合 `accept` 及 `maxSize` 限制 * * 返回 `true` (Promise `resolve`)执行上传 * * 返回 `false` (Promise `reject`)时不执行后续上传流程 */ beforeUpload?: ( file: File, fileList: File[], isAccepted: boolean ) => boolean | Promise<boolean>; /** * 上传开始时回调 */ onStart?: (file: File, context: { xhr: XMLHttpRequest }) => void; /** * 上传进度更新时回调 */ onProgress?: (progress: ProgressInfo, context: UploadEventContext) => void; /** * 上传成功时回调 */ onSuccess?: (result: object | string, context: UploadEventContext) => void; /** * 上传失败时回调 */ onError?: (error: Error, context: UploadEventContext) => void; } function isPromise(p: any): p is Promise<any> { return p && typeof p === "object" && typeof p.then === "function"; } export const Upload = withStatics( function Upload({ action, accept, maxSize, multiple = false, headers, data, name = "file", withCredentials, beforeUpload = (_, __, isAccepted) => isAccepted, onStart = () => null, onProgress, onSuccess, onError, children, className, style, }: UploadProps) { const [dragging, setDragging] = useState(false); const { getInputProps, getRootProps, open } = useDropzone({ accept, maxSize, multiple, noClick: true, noKeyboard: true, onDrop: uploadFiles, onDragEnter: () => setDragging(true), onDragLeave: () => setDragging(false), }); function uploadFiles(acceptedFiles: File[], rejectedFiles: File[]) { const fileList = [...acceptedFiles, ...rejectedFiles]; acceptedFiles.forEach(file => { file["id"] = uuid(); // eslint-disable-line dot-notation uploadFile(file, fileList, true); }); rejectedFiles.forEach(file => { file["id"] = uuid(); // eslint-disable-line dot-notation uploadFile(file, fileList, false); }); setDragging(false); } function uploadFile(file: File, fileList: File[], isAccepted: boolean) { const couldUpload = beforeUpload(file, fileList, isAccepted); if (isPromise(couldUpload)) { couldUpload.then(() => request(file)).catch(() => null); } else { if (!couldUpload) { return; } setTimeout(() => request(file), 0); } } function request(file) { const xhr = upload({ action, filename: name, file, data: injectValue(data)(file), headers: injectValue(headers)(file), withCredentials, onProgress, onSuccess, onError, }); onStart(file, { xhr }); } return ( <UploadContext.Provider value={{ open, getDraggerProps: getRootProps, isDragging: dragging }} > <span className={className} style={style}> <input {...getInputProps()} /> {isCallable(children) ? ( children({ open, getDraggerProps: getRootProps, isDragging: dragging, }) ) : ( <span onClick={open}>{children}</span> )} </span> </UploadContext.Provider> ); }, { defaultLabelAlign: "middle", File, Dragger, Image, } ); |