react-dropzone 15.0.0 → 17.0.0

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.
Files changed (61) hide show
  1. package/README.md +129 -114
  2. package/dist/index.cjs +685 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +117 -0
  5. package/dist/index.d.ts +117 -0
  6. package/dist/index.js +656 -2
  7. package/dist/index.js.map +1 -0
  8. package/package.json +76 -177
  9. package/src/index.tsx +774 -0
  10. package/src/utils/index.ts +305 -0
  11. package/.babelrc.js +0 -28
  12. package/.codeclimate.yml +0 -15
  13. package/.editorconfig +0 -13
  14. package/.eslintignore +0 -3
  15. package/.eslintrc +0 -37
  16. package/.gitpod.yml +0 -6
  17. package/.husky/commit-msg +0 -5
  18. package/.husky/pre-commit +0 -5
  19. package/.nvmrc +0 -1
  20. package/.releaserc.json +0 -27
  21. package/CHANGELOG.md +0 -9
  22. package/commitlint.config.js +0 -1
  23. package/dist/es/index.js +0 -1051
  24. package/dist/es/package.json +0 -1
  25. package/dist/es/utils/index.js +0 -366
  26. package/examples/.eslintrc +0 -5
  27. package/examples/accept/README.md +0 -144
  28. package/examples/basic/README.md +0 -70
  29. package/examples/class-component/README.md +0 -45
  30. package/examples/drag-overlay/README.md +0 -132
  31. package/examples/events/README.md +0 -164
  32. package/examples/file-dialog/README.md +0 -90
  33. package/examples/forms/README.md +0 -69
  34. package/examples/maxFiles/README.md +0 -58
  35. package/examples/no-jsx/README.md +0 -32
  36. package/examples/pintura/README.md +0 -146
  37. package/examples/plugins/README.md +0 -55
  38. package/examples/previews/README.md +0 -86
  39. package/examples/styling/README.md +0 -126
  40. package/examples/theme.css +0 -37
  41. package/examples/validator/README.md +0 -68
  42. package/rollup.config.js +0 -33
  43. package/src/.eslintrc +0 -37
  44. package/src/__snapshots__/index.spec.js.snap +0 -3
  45. package/src/index.js +0 -1103
  46. package/src/index.spec.js +0 -3838
  47. package/src/utils/index.js +0 -362
  48. package/src/utils/index.spec.js +0 -625
  49. package/styleguide.config.js +0 -107
  50. package/testSetup.js +0 -8
  51. package/typings/.eslintrc +0 -28
  52. package/typings/react-dropzone.d.ts +0 -102
  53. package/typings/tests/accept.tsx +0 -54
  54. package/typings/tests/all.tsx +0 -46
  55. package/typings/tests/basic.tsx +0 -53
  56. package/typings/tests/events.tsx +0 -31
  57. package/typings/tests/file-dialog.tsx +0 -20
  58. package/typings/tests/hook.tsx +0 -15
  59. package/typings/tests/plugin.tsx +0 -87
  60. package/typings/tests/refs.tsx +0 -18
  61. package/typings/tests/tsconfig.json +0 -22
package/dist/index.cjs ADDED
@@ -0,0 +1,685 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
+ key = keys[i];
15
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: ((k) => from[k]).bind(null, key),
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+ //#endregion
27
+ let file_selector = require("file-selector");
28
+ let react = require("react");
29
+ let attr_accept = require("attr-accept");
30
+ attr_accept = __toESM(attr_accept, 1);
31
+ let react_jsx_runtime = require("react/jsx-runtime");
32
+ //#region src/utils/index.ts
33
+ const accepts = typeof attr_accept.default === "function" ? attr_accept.default : attr_accept.default.default;
34
+ const FILE_INVALID_TYPE = "file-invalid-type";
35
+ const FILE_TOO_LARGE = "file-too-large";
36
+ const FILE_TOO_SMALL = "file-too-small";
37
+ const TOO_MANY_FILES = "too-many-files";
38
+ let ErrorCode = /* @__PURE__ */ function(ErrorCode) {
39
+ ErrorCode["FileInvalidType"] = "file-invalid-type";
40
+ ErrorCode["FileTooLarge"] = "file-too-large";
41
+ ErrorCode["FileTooSmall"] = "file-too-small";
42
+ ErrorCode["TooManyFiles"] = "too-many-files";
43
+ return ErrorCode;
44
+ }({});
45
+ function getInvalidTypeRejectionErr(accept = "") {
46
+ const acceptArr = accept.split(",");
47
+ const msg = acceptArr.length > 1 ? `one of ${acceptArr.join(", ")}` : acceptArr[0];
48
+ return {
49
+ code: FILE_INVALID_TYPE,
50
+ message: `File type must be ${msg}`
51
+ };
52
+ }
53
+ function getTooLargeRejectionErr(maxSize) {
54
+ return {
55
+ code: FILE_TOO_LARGE,
56
+ message: `File is larger than ${maxSize} ${maxSize === 1 ? "byte" : "bytes"}`
57
+ };
58
+ }
59
+ function getTooSmallRejectionErr(minSize) {
60
+ return {
61
+ code: FILE_TOO_SMALL,
62
+ message: `File is smaller than ${minSize} ${minSize === 1 ? "byte" : "bytes"}`
63
+ };
64
+ }
65
+ const TOO_MANY_FILES_REJECTION = {
66
+ code: TOO_MANY_FILES,
67
+ message: "Too many files"
68
+ };
69
+ /**
70
+ * Check if the given file is a DataTransferItem with an empty type.
71
+ *
72
+ * During drag events, browsers may return DataTransferItem objects instead of File objects.
73
+ * Some browsers (e.g., Chrome) return an empty MIME type for certain file types (like .md files)
74
+ * on DataTransferItem during drag events, even though the type is correctly set during drop.
75
+ */
76
+ function isDataTransferItemWithEmptyType(file) {
77
+ return file.type === "" && typeof file.getAsFile === "function";
78
+ }
79
+ /**
80
+ * Check if file is accepted.
81
+ *
82
+ * Firefox versions prior to 53 return a bogus MIME type for every file drag,
83
+ * so dragovers with that MIME type will always be accepted.
84
+ *
85
+ * Chrome/other browsers may return an empty MIME type for files during drag events,
86
+ * so we accept those as well (we'll validate properly on drop).
87
+ */
88
+ function fileAccepted(file, accept) {
89
+ const isAcceptable = file.type === "application/x-moz-file" || accepts(file, accept ?? "") || isDataTransferItemWithEmptyType(file);
90
+ return [isAcceptable, isAcceptable ? null : getInvalidTypeRejectionErr(accept)];
91
+ }
92
+ function fileMatchSize(file, minSize, maxSize) {
93
+ if (isDefined(file.size)) {
94
+ if (isDefined(minSize) && isDefined(maxSize)) {
95
+ if (file.size > maxSize) return [false, getTooLargeRejectionErr(maxSize)];
96
+ if (file.size < minSize) return [false, getTooSmallRejectionErr(minSize)];
97
+ } else if (isDefined(minSize) && file.size < minSize) return [false, getTooSmallRejectionErr(minSize)];
98
+ else if (isDefined(maxSize) && file.size > maxSize) return [false, getTooLargeRejectionErr(maxSize)];
99
+ }
100
+ return [true, null];
101
+ }
102
+ function isDefined(value) {
103
+ return value !== void 0 && value !== null;
104
+ }
105
+ function allFilesAccepted({ files, accept, minSize, maxSize, multiple, maxFiles = 0, validator }) {
106
+ if (!multiple && files.length > 1 || multiple && maxFiles >= 1 && files.length > maxFiles) return false;
107
+ return files.every((file) => {
108
+ const [accepted] = fileAccepted(file, accept);
109
+ const [sizeMatch] = fileMatchSize(file, minSize, maxSize);
110
+ const customErrors = validator ? validator(file) : null;
111
+ return accepted && sizeMatch && !customErrors;
112
+ });
113
+ }
114
+ function isPropagationStopped(event) {
115
+ if (typeof event.isPropagationStopped === "function") return event.isPropagationStopped();
116
+ else if (typeof event.cancelBubble !== "undefined") return event.cancelBubble;
117
+ return false;
118
+ }
119
+ function isEvtWithFiles(event) {
120
+ if (!event.dataTransfer) return !!event.target && !!event.target.files;
121
+ return Array.prototype.some.call(event.dataTransfer.types, (type) => type === "Files" || type === "application/x-moz-file");
122
+ }
123
+ function onDocumentDragOver(event) {
124
+ event.preventDefault();
125
+ }
126
+ function isIe(userAgent) {
127
+ return userAgent.indexOf("MSIE") !== -1 || userAgent.indexOf("Trident/") !== -1;
128
+ }
129
+ function isEdge(userAgent) {
130
+ return userAgent.indexOf("Edge/") !== -1;
131
+ }
132
+ function isIeOrEdge(userAgent = window.navigator.userAgent) {
133
+ return isIe(userAgent) || isEdge(userAgent);
134
+ }
135
+ /**
136
+ * This is intended to be used to compose event handlers.
137
+ * They are executed in order until one of them calls `event.isPropagationStopped()`.
138
+ * Note that the check is done on the first invoke too,
139
+ * meaning that if propagation was stopped before invoking the fns,
140
+ * no handlers will be executed.
141
+ */
142
+ function composeEventHandlers(...fns) {
143
+ return (event, ...args) => fns.some((fn) => {
144
+ if (!isPropagationStopped(event) && fn) fn(event, ...args);
145
+ return isPropagationStopped(event);
146
+ });
147
+ }
148
+ /**
149
+ * canUseFileSystemAccessAPI checks if the File System Access API is supported by the browser.
150
+ */
151
+ function canUseFileSystemAccessAPI() {
152
+ return "showOpenFilePicker" in window;
153
+ }
154
+ /**
155
+ * Convert the `{accept}` dropzone prop to the `{types}` option for showOpenFilePicker.
156
+ */
157
+ function pickerOptionsFromAccept(accept) {
158
+ if (isDefined(accept)) return [{
159
+ description: "Files",
160
+ accept: Object.entries(accept).filter(([mimeType, ext]) => {
161
+ let ok = true;
162
+ if (!isMIMEType(mimeType)) {
163
+ console.warn(`Skipped "${mimeType}" because it is not a valid MIME type. Check https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types for a list of valid MIME types.`);
164
+ ok = false;
165
+ }
166
+ if (!Array.isArray(ext) || !ext.every(isExt)) {
167
+ console.warn(`Skipped "${mimeType}" because an invalid file extension was provided.`);
168
+ ok = false;
169
+ }
170
+ return ok;
171
+ }).reduce((agg, [mimeType, ext]) => {
172
+ agg[mimeType] = ext;
173
+ return agg;
174
+ }, {})
175
+ }];
176
+ }
177
+ /**
178
+ * Convert the `{accept}` dropzone prop to an array of MIME types/extensions.
179
+ */
180
+ function acceptPropAsAcceptAttr(accept) {
181
+ if (isDefined(accept)) return Object.entries(accept).reduce((a, [mimeType, ext]) => {
182
+ a.push(mimeType, ...ext);
183
+ return a;
184
+ }, []).filter((v) => isMIMEType(v) || isExt(v)).join(",");
185
+ }
186
+ /**
187
+ * Check if v is an exception caused by aborting a request (e.g window.showOpenFilePicker()).
188
+ */
189
+ function isAbort(v) {
190
+ return v instanceof DOMException && (v.name === "AbortError" || v.code === v.ABORT_ERR);
191
+ }
192
+ /**
193
+ * Check if v is a security error.
194
+ */
195
+ function isSecurityError(v) {
196
+ return v instanceof DOMException && (v.name === "SecurityError" || v.code === v.SECURITY_ERR);
197
+ }
198
+ /**
199
+ * Check if v is a MIME type string.
200
+ */
201
+ function isMIMEType(v) {
202
+ return v === "audio/*" || v === "video/*" || v === "image/*" || v === "text/*" || v === "application/*" || /\w+\/[-+.\w]+/g.test(v);
203
+ }
204
+ /**
205
+ * Check if v is a file extension.
206
+ */
207
+ function isExt(v) {
208
+ return /^.*\.[\w]+$/.test(v);
209
+ }
210
+ //#endregion
211
+ //#region src/index.tsx
212
+ /**
213
+ * Convenience wrapper component for the `useDropzone` hook
214
+ *
215
+ * ```jsx
216
+ * <Dropzone>
217
+ * {({getRootProps, getInputProps}) => (
218
+ * <div {...getRootProps()}>
219
+ * <input {...getInputProps()} />
220
+ * <p>Drag 'n' drop some files here, or click to select files</p>
221
+ * </div>
222
+ * )}
223
+ * </Dropzone>
224
+ * ```
225
+ */
226
+ const Dropzone = (0, react.forwardRef)(({ children, ...params }, ref) => {
227
+ const { open, ...props } = useDropzone(params);
228
+ (0, react.useImperativeHandle)(ref, () => ({ open }), [open]);
229
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: children?.({
230
+ ...props,
231
+ open
232
+ }) });
233
+ });
234
+ Dropzone.displayName = "Dropzone";
235
+ const initialState = {
236
+ isFocused: false,
237
+ isFileDialogActive: false,
238
+ isDragActive: false,
239
+ isDragAccept: false,
240
+ isDragReject: false,
241
+ isDragGlobal: false,
242
+ acceptedFiles: [],
243
+ fileRejections: []
244
+ };
245
+ /**
246
+ * A React hook that creates a drag 'n' drop area.
247
+ *
248
+ * ```jsx
249
+ * function MyDropzone(props) {
250
+ * const {getRootProps, getInputProps} = useDropzone({
251
+ * onDrop: acceptedFiles => {
252
+ * // do something with the File objects, e.g. upload to some server
253
+ * }
254
+ * });
255
+ * return (
256
+ * <div {...getRootProps()}>
257
+ * <input {...getInputProps()} />
258
+ * <p>Drag and drop some files here, or click to select files</p>
259
+ * </div>
260
+ * )
261
+ * }
262
+ * ```
263
+ */
264
+ function useDropzone(props = {}) {
265
+ const { accept, disabled = false, getFilesFromEvent = file_selector.fromEvent, maxSize = Number.POSITIVE_INFINITY, minSize = 0, multiple = true, maxFiles = 0, onDragEnter, onDragLeave, onDragOver, onDrop, onDropAccepted, onDropRejected, onFileDialogCancel, onFileDialogOpen, useFsAccessApi = false, autoFocus = false, preventDropOnDocument = true, noClick = false, noKeyboard = false, noDrag = false, noDragEventsBubbling = false, onError, validator } = props;
266
+ const acceptAttr = (0, react.useMemo)(() => acceptPropAsAcceptAttr(accept), [accept]);
267
+ const pickerTypes = (0, react.useMemo)(() => pickerOptionsFromAccept(accept), [accept]);
268
+ const onFileDialogOpenCb = (0, react.useMemo)(() => typeof onFileDialogOpen === "function" ? onFileDialogOpen : noop, [onFileDialogOpen]);
269
+ const onFileDialogCancelCb = (0, react.useMemo)(() => typeof onFileDialogCancel === "function" ? onFileDialogCancel : noop, [onFileDialogCancel]);
270
+ const rootRef = (0, react.useRef)(null);
271
+ const inputRef = (0, react.useRef)(null);
272
+ const [state, dispatch] = (0, react.useReducer)(reducer, initialState);
273
+ const { isFocused, isFileDialogActive } = state;
274
+ const fsAccessApiWorksRef = (0, react.useRef)(typeof window !== "undefined" && window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI());
275
+ const onWindowFocus = () => {
276
+ if (!fsAccessApiWorksRef.current && isFileDialogActive) setTimeout(() => {
277
+ if (inputRef.current) {
278
+ const { files } = inputRef.current;
279
+ if (!files?.length) {
280
+ dispatch({ type: "closeDialog" });
281
+ onFileDialogCancelCb();
282
+ }
283
+ }
284
+ }, 300);
285
+ };
286
+ (0, react.useEffect)(() => {
287
+ window.addEventListener("focus", onWindowFocus, false);
288
+ return () => {
289
+ window.removeEventListener("focus", onWindowFocus, false);
290
+ };
291
+ }, [
292
+ inputRef,
293
+ isFileDialogActive,
294
+ onFileDialogCancelCb,
295
+ fsAccessApiWorksRef
296
+ ]);
297
+ const dragTargetsRef = (0, react.useRef)([]);
298
+ const globalDragTargetsRef = (0, react.useRef)([]);
299
+ const onDocumentDrop = (event) => {
300
+ if (rootRef.current && event.target && rootRef.current.contains(event.target)) return;
301
+ event.preventDefault();
302
+ dragTargetsRef.current = [];
303
+ };
304
+ (0, react.useEffect)(() => {
305
+ if (preventDropOnDocument) {
306
+ document.addEventListener("dragover", onDocumentDragOver, false);
307
+ document.addEventListener("drop", onDocumentDrop, false);
308
+ }
309
+ return () => {
310
+ if (preventDropOnDocument) {
311
+ document.removeEventListener("dragover", onDocumentDragOver);
312
+ document.removeEventListener("drop", onDocumentDrop);
313
+ }
314
+ };
315
+ }, [rootRef, preventDropOnDocument]);
316
+ (0, react.useEffect)(() => {
317
+ const onDocumentDragEnter = (event) => {
318
+ if (event.target) globalDragTargetsRef.current = [...globalDragTargetsRef.current, event.target];
319
+ if (isEvtWithFiles(event)) dispatch({
320
+ isDragGlobal: true,
321
+ type: "setDragGlobal"
322
+ });
323
+ };
324
+ const onDocumentDragLeave = (event) => {
325
+ globalDragTargetsRef.current = globalDragTargetsRef.current.filter((el) => el !== event.target && el !== null);
326
+ if (globalDragTargetsRef.current.length > 0) return;
327
+ dispatch({
328
+ isDragGlobal: false,
329
+ type: "setDragGlobal"
330
+ });
331
+ };
332
+ const onDocumentDragEnd = () => {
333
+ globalDragTargetsRef.current = [];
334
+ dispatch({
335
+ isDragGlobal: false,
336
+ type: "setDragGlobal"
337
+ });
338
+ };
339
+ const onDocumentDropGlobal = () => {
340
+ globalDragTargetsRef.current = [];
341
+ dispatch({
342
+ isDragGlobal: false,
343
+ type: "setDragGlobal"
344
+ });
345
+ };
346
+ document.addEventListener("dragenter", onDocumentDragEnter, false);
347
+ document.addEventListener("dragleave", onDocumentDragLeave, false);
348
+ document.addEventListener("dragend", onDocumentDragEnd, false);
349
+ document.addEventListener("drop", onDocumentDropGlobal, false);
350
+ return () => {
351
+ document.removeEventListener("dragenter", onDocumentDragEnter);
352
+ document.removeEventListener("dragleave", onDocumentDragLeave);
353
+ document.removeEventListener("dragend", onDocumentDragEnd);
354
+ document.removeEventListener("drop", onDocumentDropGlobal);
355
+ };
356
+ }, [rootRef]);
357
+ (0, react.useEffect)(() => {
358
+ if (!disabled && autoFocus && rootRef.current) rootRef.current.focus();
359
+ return () => {};
360
+ }, [
361
+ rootRef,
362
+ autoFocus,
363
+ disabled
364
+ ]);
365
+ const onErrCb = (0, react.useCallback)((e) => {
366
+ if (onError) onError(e);
367
+ else console.error(e);
368
+ }, [onError]);
369
+ const onDragEnterCb = (0, react.useCallback)((event) => {
370
+ event.preventDefault();
371
+ event.persist?.();
372
+ stopPropagation(event);
373
+ dragTargetsRef.current = [...dragTargetsRef.current, event.target];
374
+ if (isEvtWithFiles(event)) Promise.resolve(getFilesFromEvent(event)).then((files) => {
375
+ if (isPropagationStopped(event) && !noDragEventsBubbling) return;
376
+ const fileCount = files.length;
377
+ const isDragAccept = fileCount > 0 && allFilesAccepted({
378
+ files,
379
+ accept: acceptAttr,
380
+ minSize,
381
+ maxSize,
382
+ multiple,
383
+ maxFiles,
384
+ validator
385
+ });
386
+ dispatch({
387
+ isDragAccept,
388
+ isDragReject: fileCount > 0 && !isDragAccept,
389
+ isDragActive: true,
390
+ type: "setDraggedFiles"
391
+ });
392
+ if (onDragEnter) onDragEnter(event);
393
+ }).catch((e) => onErrCb(e));
394
+ }, [
395
+ getFilesFromEvent,
396
+ onDragEnter,
397
+ onErrCb,
398
+ noDragEventsBubbling,
399
+ acceptAttr,
400
+ minSize,
401
+ maxSize,
402
+ multiple,
403
+ maxFiles,
404
+ validator
405
+ ]);
406
+ const onDragOverCb = (0, react.useCallback)((event) => {
407
+ event.preventDefault();
408
+ event.persist?.();
409
+ stopPropagation(event);
410
+ const hasFiles = isEvtWithFiles(event);
411
+ if (hasFiles && event.dataTransfer) try {
412
+ event.dataTransfer.dropEffect = "copy";
413
+ } catch {}
414
+ if (hasFiles && onDragOver) onDragOver(event);
415
+ return false;
416
+ }, [onDragOver, noDragEventsBubbling]);
417
+ const onDragLeaveCb = (0, react.useCallback)((event) => {
418
+ event.preventDefault();
419
+ event.persist?.();
420
+ stopPropagation(event);
421
+ const targets = dragTargetsRef.current.filter((target) => rootRef.current?.contains(target));
422
+ const targetIdx = targets.indexOf(event.target);
423
+ if (targetIdx !== -1) targets.splice(targetIdx, 1);
424
+ dragTargetsRef.current = targets;
425
+ if (targets.length > 0) return;
426
+ dispatch({
427
+ type: "setDraggedFiles",
428
+ isDragActive: false,
429
+ isDragAccept: false,
430
+ isDragReject: false
431
+ });
432
+ if (isEvtWithFiles(event) && onDragLeave) onDragLeave(event);
433
+ }, [
434
+ rootRef,
435
+ onDragLeave,
436
+ noDragEventsBubbling
437
+ ]);
438
+ const setFiles = (0, react.useCallback)((files, event) => {
439
+ const acceptedFiles = [];
440
+ const fileRejections = [];
441
+ files.forEach((file) => {
442
+ const [accepted, acceptError] = fileAccepted(file, acceptAttr);
443
+ const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize);
444
+ const customErrors = validator ? validator(file) : null;
445
+ if (accepted && sizeMatch && !customErrors) acceptedFiles.push(file);
446
+ else {
447
+ let errors = [acceptError, sizeError];
448
+ if (customErrors) errors = errors.concat(customErrors);
449
+ fileRejections.push({
450
+ file,
451
+ errors: errors.filter((e) => e != null)
452
+ });
453
+ }
454
+ });
455
+ if (!multiple && acceptedFiles.length > 1 || multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles) {
456
+ acceptedFiles.forEach((file) => {
457
+ fileRejections.push({
458
+ file,
459
+ errors: [TOO_MANY_FILES_REJECTION]
460
+ });
461
+ });
462
+ acceptedFiles.splice(0);
463
+ }
464
+ dispatch({
465
+ acceptedFiles,
466
+ fileRejections,
467
+ type: "setFiles"
468
+ });
469
+ if (onDrop) onDrop(acceptedFiles, fileRejections, event);
470
+ if (fileRejections.length > 0 && onDropRejected) onDropRejected(fileRejections, event);
471
+ if (acceptedFiles.length > 0 && onDropAccepted) onDropAccepted(acceptedFiles, event);
472
+ }, [
473
+ dispatch,
474
+ multiple,
475
+ acceptAttr,
476
+ minSize,
477
+ maxSize,
478
+ maxFiles,
479
+ onDrop,
480
+ onDropAccepted,
481
+ onDropRejected,
482
+ validator
483
+ ]);
484
+ const onDropCb = (0, react.useCallback)((event) => {
485
+ event.preventDefault();
486
+ event.persist?.();
487
+ stopPropagation(event);
488
+ dragTargetsRef.current = [];
489
+ if (isEvtWithFiles(event)) Promise.resolve(getFilesFromEvent(event)).then((files) => {
490
+ if (isPropagationStopped(event) && !noDragEventsBubbling) return;
491
+ setFiles(files, event);
492
+ }).catch((e) => onErrCb(e));
493
+ dispatch({ type: "reset" });
494
+ }, [
495
+ getFilesFromEvent,
496
+ setFiles,
497
+ onErrCb,
498
+ noDragEventsBubbling
499
+ ]);
500
+ const openFileDialog = (0, react.useCallback)(() => {
501
+ if (fsAccessApiWorksRef.current) {
502
+ dispatch({ type: "openDialog" });
503
+ onFileDialogOpenCb();
504
+ const opts = {
505
+ multiple,
506
+ types: pickerTypes
507
+ };
508
+ window.showOpenFilePicker(opts).then((handles) => getFilesFromEvent(handles)).then((files) => {
509
+ setFiles(files, null);
510
+ dispatch({ type: "closeDialog" });
511
+ }).catch((e) => {
512
+ if (isAbort(e)) {
513
+ onFileDialogCancelCb(e);
514
+ dispatch({ type: "closeDialog" });
515
+ } else if (isSecurityError(e)) {
516
+ fsAccessApiWorksRef.current = false;
517
+ if (inputRef.current) {
518
+ inputRef.current.value = "";
519
+ inputRef.current.click();
520
+ } else onErrCb(/* @__PURE__ */ new Error("Cannot open the file picker because the https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API is not supported and no <input> was provided."));
521
+ } else onErrCb(e);
522
+ });
523
+ return;
524
+ }
525
+ if (inputRef.current) {
526
+ dispatch({ type: "openDialog" });
527
+ onFileDialogOpenCb();
528
+ inputRef.current.value = "";
529
+ inputRef.current.click();
530
+ }
531
+ }, [
532
+ dispatch,
533
+ onFileDialogOpenCb,
534
+ onFileDialogCancelCb,
535
+ useFsAccessApi,
536
+ setFiles,
537
+ onErrCb,
538
+ pickerTypes,
539
+ multiple
540
+ ]);
541
+ const onKeyDownCb = (0, react.useCallback)((event) => {
542
+ if (!rootRef.current?.isEqualNode(event.target)) return;
543
+ if (event.key === " " || event.key === "Enter" || event.keyCode === 32 || event.keyCode === 13) {
544
+ event.preventDefault();
545
+ openFileDialog();
546
+ }
547
+ }, [rootRef, openFileDialog]);
548
+ const onFocusCb = (0, react.useCallback)(() => {
549
+ dispatch({ type: "focus" });
550
+ }, []);
551
+ const onBlurCb = (0, react.useCallback)(() => {
552
+ dispatch({ type: "blur" });
553
+ }, []);
554
+ const onClickCb = (0, react.useCallback)(() => {
555
+ if (noClick) return;
556
+ if (isIeOrEdge()) setTimeout(openFileDialog, 0);
557
+ else openFileDialog();
558
+ }, [noClick, openFileDialog]);
559
+ const composeHandler = (fn) => {
560
+ return disabled ? null : fn;
561
+ };
562
+ const composeKeyboardHandler = (fn) => {
563
+ return noKeyboard ? null : composeHandler(fn);
564
+ };
565
+ const composeDragHandler = (fn) => {
566
+ return noDrag ? null : composeHandler(fn);
567
+ };
568
+ const stopPropagation = (event) => {
569
+ if (noDragEventsBubbling) event.stopPropagation();
570
+ };
571
+ const getRootProps = (0, react.useMemo)(() => ({ refKey = "ref", role, onKeyDown, onFocus, onBlur, onClick, onDragEnter, onDragOver, onDragLeave, onDrop, ...rest } = {}) => ({
572
+ onKeyDown: composeKeyboardHandler(composeEventHandlers(onKeyDown, onKeyDownCb)),
573
+ onFocus: composeKeyboardHandler(composeEventHandlers(onFocus, onFocusCb)),
574
+ onBlur: composeKeyboardHandler(composeEventHandlers(onBlur, onBlurCb)),
575
+ onClick: composeHandler(composeEventHandlers(onClick, onClickCb)),
576
+ onDragEnter: composeDragHandler(composeEventHandlers(onDragEnter, onDragEnterCb)),
577
+ onDragOver: composeDragHandler(composeEventHandlers(onDragOver, onDragOverCb)),
578
+ onDragLeave: composeDragHandler(composeEventHandlers(onDragLeave, onDragLeaveCb)),
579
+ onDrop: composeDragHandler(composeEventHandlers(onDrop, onDropCb)),
580
+ role: typeof role === "string" && role !== "" ? role : "presentation",
581
+ [refKey]: rootRef,
582
+ ...!disabled && !noKeyboard ? { tabIndex: 0 } : {},
583
+ ...rest
584
+ }), [
585
+ rootRef,
586
+ onKeyDownCb,
587
+ onFocusCb,
588
+ onBlurCb,
589
+ onClickCb,
590
+ onDragEnterCb,
591
+ onDragOverCb,
592
+ onDragLeaveCb,
593
+ onDropCb,
594
+ noKeyboard,
595
+ noDrag,
596
+ disabled
597
+ ]);
598
+ const onInputElementClick = (0, react.useCallback)((event) => {
599
+ event.stopPropagation();
600
+ }, []);
601
+ const getInputProps = (0, react.useMemo)(() => ({ refKey = "ref", onChange, onClick, ...rest } = {}) => {
602
+ return {
603
+ accept: acceptAttr,
604
+ multiple,
605
+ type: "file",
606
+ style: {
607
+ border: 0,
608
+ clip: "rect(0, 0, 0, 0)",
609
+ clipPath: "inset(50%)",
610
+ height: "1px",
611
+ margin: "0 -1px -1px 0",
612
+ overflow: "hidden",
613
+ padding: 0,
614
+ position: "absolute",
615
+ width: "1px",
616
+ whiteSpace: "nowrap"
617
+ },
618
+ onChange: composeHandler(composeEventHandlers(onChange, onDropCb)),
619
+ onClick: composeHandler(composeEventHandlers(onClick, onInputElementClick)),
620
+ tabIndex: -1,
621
+ [refKey]: inputRef,
622
+ ...rest
623
+ };
624
+ }, [
625
+ inputRef,
626
+ accept,
627
+ multiple,
628
+ onDropCb,
629
+ disabled
630
+ ]);
631
+ return {
632
+ ...state,
633
+ isFocused: isFocused && !disabled,
634
+ getRootProps,
635
+ getInputProps,
636
+ rootRef,
637
+ inputRef,
638
+ open: composeHandler(openFileDialog)
639
+ };
640
+ }
641
+ function reducer(state, action) {
642
+ switch (action.type) {
643
+ case "focus": return {
644
+ ...state,
645
+ isFocused: true
646
+ };
647
+ case "blur": return {
648
+ ...state,
649
+ isFocused: false
650
+ };
651
+ case "openDialog": return {
652
+ ...initialState,
653
+ isFileDialogActive: true
654
+ };
655
+ case "closeDialog": return {
656
+ ...state,
657
+ isFileDialogActive: false
658
+ };
659
+ case "setDraggedFiles": return {
660
+ ...state,
661
+ isDragActive: action.isDragActive,
662
+ isDragAccept: action.isDragAccept,
663
+ isDragReject: action.isDragReject
664
+ };
665
+ case "setFiles": return {
666
+ ...state,
667
+ acceptedFiles: action.acceptedFiles,
668
+ fileRejections: action.fileRejections,
669
+ isDragReject: false
670
+ };
671
+ case "setDragGlobal": return {
672
+ ...state,
673
+ isDragGlobal: action.isDragGlobal
674
+ };
675
+ case "reset": return { ...initialState };
676
+ default: return state;
677
+ }
678
+ }
679
+ function noop() {}
680
+ //#endregion
681
+ exports.ErrorCode = ErrorCode;
682
+ exports.default = Dropzone;
683
+ exports.useDropzone = useDropzone;
684
+
685
+ //# sourceMappingURL=index.cjs.map