react-dropzone 11.7.1 → 12.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +1 -3
- package/README.md +6 -1
- package/commitlint.config.js +1 -1
- package/dist/es/index.js +66 -54
- package/dist/es/utils/index.js +44 -22
- package/dist/index.js +2 -2
- package/examples/accept/README.md +10 -3
- package/package.json +7 -6
- package/rollup.config.js +20 -20
- package/src/.eslintrc +1 -2
- package/src/index.js +333 -281
- package/src/index.spec.js +1851 -1523
- package/src/utils/index.js +128 -73
- package/src/utils/index.spec.js +440 -289
- package/styleguide.config.js +55 -52
- package/testSetup.js +7 -1
- package/typings/.eslintrc +1 -1
- package/typings/react-dropzone.d.ts +25 -14
- package/typings/tests/accept.tsx +10 -9
- package/typings/tests/all.tsx +7 -5
- package/typings/tests/basic.tsx +8 -7
- package/typings/tests/events.tsx +8 -6
- package/typings/tests/file-dialog.tsx +4 -3
- package/typings/tests/hook.tsx +6 -6
- package/typings/tests/plugin.tsx +11 -22
- package/typings/tests/refs.tsx +4 -4
package/src/utils/index.js
CHANGED
|
@@ -1,126 +1,148 @@
|
|
|
1
|
-
import accepts from
|
|
1
|
+
import accepts from "attr-accept";
|
|
2
2
|
|
|
3
3
|
// Error codes
|
|
4
|
-
export const FILE_INVALID_TYPE =
|
|
5
|
-
export const FILE_TOO_LARGE =
|
|
6
|
-
export const FILE_TOO_SMALL =
|
|
7
|
-
export const TOO_MANY_FILES =
|
|
4
|
+
export const FILE_INVALID_TYPE = "file-invalid-type";
|
|
5
|
+
export const FILE_TOO_LARGE = "file-too-large";
|
|
6
|
+
export const FILE_TOO_SMALL = "file-too-small";
|
|
7
|
+
export const TOO_MANY_FILES = "too-many-files";
|
|
8
8
|
|
|
9
9
|
export const ErrorCode = {
|
|
10
10
|
FileInvalidType: FILE_INVALID_TYPE,
|
|
11
11
|
FileTooLarge: FILE_TOO_LARGE,
|
|
12
12
|
FileTooSmall: FILE_TOO_SMALL,
|
|
13
13
|
TooManyFiles: TOO_MANY_FILES,
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
15
|
|
|
16
16
|
// File Errors
|
|
17
|
-
export const getInvalidTypeRejectionErr = accept => {
|
|
18
|
-
accept = Array.isArray(accept) && accept.length === 1 ? accept[0] : accept
|
|
19
|
-
const messageSuffix = Array.isArray(accept)
|
|
17
|
+
export const getInvalidTypeRejectionErr = (accept) => {
|
|
18
|
+
accept = Array.isArray(accept) && accept.length === 1 ? accept[0] : accept;
|
|
19
|
+
const messageSuffix = Array.isArray(accept)
|
|
20
|
+
? `one of ${accept.join(", ")}`
|
|
21
|
+
: accept;
|
|
20
22
|
return {
|
|
21
23
|
code: FILE_INVALID_TYPE,
|
|
22
|
-
message: `File type must be ${messageSuffix}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
24
|
+
message: `File type must be ${messageSuffix}`,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
25
27
|
|
|
26
|
-
export const getTooLargeRejectionErr = maxSize => {
|
|
28
|
+
export const getTooLargeRejectionErr = (maxSize) => {
|
|
27
29
|
return {
|
|
28
30
|
code: FILE_TOO_LARGE,
|
|
29
|
-
message: `File is larger than ${maxSize} ${
|
|
30
|
-
|
|
31
|
-
}
|
|
31
|
+
message: `File is larger than ${maxSize} ${
|
|
32
|
+
maxSize === 1 ? "byte" : "bytes"
|
|
33
|
+
}`,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
32
36
|
|
|
33
|
-
export const getTooSmallRejectionErr = minSize => {
|
|
37
|
+
export const getTooSmallRejectionErr = (minSize) => {
|
|
34
38
|
return {
|
|
35
39
|
code: FILE_TOO_SMALL,
|
|
36
|
-
message: `File is smaller than ${minSize} ${
|
|
37
|
-
|
|
38
|
-
}
|
|
40
|
+
message: `File is smaller than ${minSize} ${
|
|
41
|
+
minSize === 1 ? "byte" : "bytes"
|
|
42
|
+
}`,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
39
45
|
|
|
40
46
|
export const TOO_MANY_FILES_REJECTION = {
|
|
41
47
|
code: TOO_MANY_FILES,
|
|
42
|
-
message:
|
|
43
|
-
}
|
|
48
|
+
message: "Too many files",
|
|
49
|
+
};
|
|
44
50
|
|
|
45
51
|
// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with
|
|
46
52
|
// that MIME type will always be accepted
|
|
47
53
|
export function fileAccepted(file, accept) {
|
|
48
|
-
const isAcceptable =
|
|
49
|
-
|
|
54
|
+
const isAcceptable =
|
|
55
|
+
file.type === "application/x-moz-file" || accepts(file, accept);
|
|
56
|
+
return [
|
|
57
|
+
isAcceptable,
|
|
58
|
+
isAcceptable ? null : getInvalidTypeRejectionErr(accept),
|
|
59
|
+
];
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
export function fileMatchSize(file, minSize, maxSize) {
|
|
53
63
|
if (isDefined(file.size)) {
|
|
54
64
|
if (isDefined(minSize) && isDefined(maxSize)) {
|
|
55
|
-
if (file.size > maxSize) return [false, getTooLargeRejectionErr(maxSize)]
|
|
56
|
-
if (file.size < minSize) return [false, getTooSmallRejectionErr(minSize)]
|
|
65
|
+
if (file.size > maxSize) return [false, getTooLargeRejectionErr(maxSize)];
|
|
66
|
+
if (file.size < minSize) return [false, getTooSmallRejectionErr(minSize)];
|
|
57
67
|
} else if (isDefined(minSize) && file.size < minSize)
|
|
58
|
-
return [false, getTooSmallRejectionErr(minSize)]
|
|
68
|
+
return [false, getTooSmallRejectionErr(minSize)];
|
|
59
69
|
else if (isDefined(maxSize) && file.size > maxSize)
|
|
60
|
-
return [false, getTooLargeRejectionErr(maxSize)]
|
|
70
|
+
return [false, getTooLargeRejectionErr(maxSize)];
|
|
61
71
|
}
|
|
62
|
-
return [true, null]
|
|
72
|
+
return [true, null];
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
function isDefined(value) {
|
|
66
|
-
return value !== undefined && value !== null
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function allFilesAccepted({
|
|
70
|
-
|
|
76
|
+
return value !== undefined && value !== null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function allFilesAccepted({
|
|
80
|
+
files,
|
|
81
|
+
accept,
|
|
82
|
+
minSize,
|
|
83
|
+
maxSize,
|
|
84
|
+
multiple,
|
|
85
|
+
maxFiles,
|
|
86
|
+
}) {
|
|
87
|
+
if (
|
|
88
|
+
(!multiple && files.length > 1) ||
|
|
89
|
+
(multiple && maxFiles >= 1 && files.length > maxFiles)
|
|
90
|
+
) {
|
|
71
91
|
return false;
|
|
72
92
|
}
|
|
73
93
|
|
|
74
|
-
return files.every(file => {
|
|
75
|
-
const [accepted] = fileAccepted(file, accept)
|
|
76
|
-
const [sizeMatch] = fileMatchSize(file, minSize, maxSize)
|
|
77
|
-
return accepted && sizeMatch
|
|
78
|
-
})
|
|
94
|
+
return files.every((file) => {
|
|
95
|
+
const [accepted] = fileAccepted(file, accept);
|
|
96
|
+
const [sizeMatch] = fileMatchSize(file, minSize, maxSize);
|
|
97
|
+
return accepted && sizeMatch;
|
|
98
|
+
});
|
|
79
99
|
}
|
|
80
100
|
|
|
81
101
|
// React's synthetic events has event.isPropagationStopped,
|
|
82
102
|
// but to remain compatibility with other libs (Preact) fall back
|
|
83
103
|
// to check event.cancelBubble
|
|
84
104
|
export function isPropagationStopped(event) {
|
|
85
|
-
if (typeof event.isPropagationStopped ===
|
|
86
|
-
return event.isPropagationStopped()
|
|
87
|
-
} else if (typeof event.cancelBubble !==
|
|
88
|
-
return event.cancelBubble
|
|
105
|
+
if (typeof event.isPropagationStopped === "function") {
|
|
106
|
+
return event.isPropagationStopped();
|
|
107
|
+
} else if (typeof event.cancelBubble !== "undefined") {
|
|
108
|
+
return event.cancelBubble;
|
|
89
109
|
}
|
|
90
|
-
return false
|
|
110
|
+
return false;
|
|
91
111
|
}
|
|
92
112
|
|
|
93
113
|
export function isEvtWithFiles(event) {
|
|
94
114
|
if (!event.dataTransfer) {
|
|
95
|
-
return !!event.target && !!event.target.files
|
|
115
|
+
return !!event.target && !!event.target.files;
|
|
96
116
|
}
|
|
97
117
|
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
|
|
98
118
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file
|
|
99
119
|
return Array.prototype.some.call(
|
|
100
120
|
event.dataTransfer.types,
|
|
101
|
-
type => type ===
|
|
102
|
-
)
|
|
121
|
+
(type) => type === "Files" || type === "application/x-moz-file"
|
|
122
|
+
);
|
|
103
123
|
}
|
|
104
124
|
|
|
105
125
|
export function isKindFile(item) {
|
|
106
|
-
return typeof item ===
|
|
126
|
+
return typeof item === "object" && item !== null && item.kind === "file";
|
|
107
127
|
}
|
|
108
128
|
|
|
109
129
|
// allow the entire document to be a drag target
|
|
110
130
|
export function onDocumentDragOver(event) {
|
|
111
|
-
event.preventDefault()
|
|
131
|
+
event.preventDefault();
|
|
112
132
|
}
|
|
113
133
|
|
|
114
134
|
function isIe(userAgent) {
|
|
115
|
-
return
|
|
135
|
+
return (
|
|
136
|
+
userAgent.indexOf("MSIE") !== -1 || userAgent.indexOf("Trident/") !== -1
|
|
137
|
+
);
|
|
116
138
|
}
|
|
117
139
|
|
|
118
140
|
function isEdge(userAgent) {
|
|
119
|
-
return userAgent.indexOf(
|
|
141
|
+
return userAgent.indexOf("Edge/") !== -1;
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
export function isIeOrEdge(userAgent = window.navigator.userAgent) {
|
|
123
|
-
return isIe(userAgent) || isEdge(userAgent)
|
|
145
|
+
return isIe(userAgent) || isEdge(userAgent);
|
|
124
146
|
}
|
|
125
147
|
|
|
126
148
|
/**
|
|
@@ -135,12 +157,12 @@ export function isIeOrEdge(userAgent = window.navigator.userAgent) {
|
|
|
135
157
|
*/
|
|
136
158
|
export function composeEventHandlers(...fns) {
|
|
137
159
|
return (event, ...args) =>
|
|
138
|
-
fns.some(fn => {
|
|
160
|
+
fns.some((fn) => {
|
|
139
161
|
if (!isPropagationStopped(event) && fn) {
|
|
140
|
-
fn(event, ...args)
|
|
162
|
+
fn(event, ...args);
|
|
141
163
|
}
|
|
142
|
-
return isPropagationStopped(event)
|
|
143
|
-
})
|
|
164
|
+
return isPropagationStopped(event);
|
|
165
|
+
});
|
|
144
166
|
}
|
|
145
167
|
|
|
146
168
|
/**
|
|
@@ -149,7 +171,7 @@ export function composeEventHandlers(...fns) {
|
|
|
149
171
|
* @returns {boolean}
|
|
150
172
|
*/
|
|
151
173
|
export function canUseFileSystemAccessAPI() {
|
|
152
|
-
return
|
|
174
|
+
return "showOpenFilePicker" in window;
|
|
153
175
|
}
|
|
154
176
|
|
|
155
177
|
/**
|
|
@@ -159,20 +181,53 @@ export function canUseFileSystemAccessAPI() {
|
|
|
159
181
|
* @param {string|string[]} accept
|
|
160
182
|
*/
|
|
161
183
|
export function filePickerOptionsTypes(accept) {
|
|
162
|
-
accept = typeof accept ===
|
|
163
|
-
return [
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
accept = typeof accept === "string" ? accept.split(",") : accept;
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
description: "everything",
|
|
188
|
+
// TODO: Need to handle filtering more elegantly than this!
|
|
189
|
+
accept: Array.isArray(accept)
|
|
190
|
+
? // Accept just MIME types as per spec
|
|
191
|
+
// NOTE: accept can be https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers
|
|
192
|
+
accept
|
|
193
|
+
.filter(
|
|
194
|
+
(item) =>
|
|
195
|
+
item === "audio/*" ||
|
|
196
|
+
item === "video/*" ||
|
|
197
|
+
item === "image/*" ||
|
|
198
|
+
item === "text/*" ||
|
|
199
|
+
/\w+\/[-+.\w]+/g.test(item)
|
|
200
|
+
)
|
|
201
|
+
.reduce((a, b) => ({ ...a, [b]: [] }), {})
|
|
202
|
+
: {},
|
|
203
|
+
},
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Check if v is an exception caused by aborting a request (e.g window.showOpenFilePicker()).
|
|
209
|
+
*
|
|
210
|
+
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException.
|
|
211
|
+
* @param {any} v
|
|
212
|
+
* @returns {boolean} True if v is an abort exception.
|
|
213
|
+
*/
|
|
214
|
+
export function isAbort(v) {
|
|
215
|
+
return (
|
|
216
|
+
v instanceof DOMException &&
|
|
217
|
+
(v.name === "AbortError" || v.code === v.ABORT_ERR)
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Check if v is a security error.
|
|
223
|
+
*
|
|
224
|
+
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException.
|
|
225
|
+
* @param {any} v
|
|
226
|
+
* @returns {boolean} True if v is a security error.
|
|
227
|
+
*/
|
|
228
|
+
export function isSecurityError(v) {
|
|
229
|
+
return (
|
|
230
|
+
v instanceof DOMException &&
|
|
231
|
+
(v.name === "SecurityError" || v.code === v.SECURITY_ERR)
|
|
232
|
+
);
|
|
178
233
|
}
|