react-dropzone 16.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.
package/dist/index.cjs CHANGED
@@ -24,50 +24,44 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- let react = require("react");
28
- react = __toESM(react, 1);
29
- let prop_types = require("prop-types");
30
- prop_types = __toESM(prop_types, 1);
31
27
  let file_selector = require("file-selector");
28
+ let react = require("react");
32
29
  let attr_accept = require("attr-accept");
33
30
  attr_accept = __toESM(attr_accept, 1);
34
31
  let react_jsx_runtime = require("react/jsx-runtime");
35
- //#region src/utils/index.js
32
+ //#region src/utils/index.ts
36
33
  const accepts = typeof attr_accept.default === "function" ? attr_accept.default : attr_accept.default.default;
37
34
  const FILE_INVALID_TYPE = "file-invalid-type";
38
35
  const FILE_TOO_LARGE = "file-too-large";
39
36
  const FILE_TOO_SMALL = "file-too-small";
40
37
  const TOO_MANY_FILES = "too-many-files";
41
- const ErrorCode = {
42
- FileInvalidType: FILE_INVALID_TYPE,
43
- FileTooLarge: FILE_TOO_LARGE,
44
- FileTooSmall: FILE_TOO_SMALL,
45
- TooManyFiles: TOO_MANY_FILES
46
- };
47
- /**
48
- *
49
- * @param {string} accept
50
- */
51
- const getInvalidTypeRejectionErr = (accept = "") => {
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 = "") {
52
46
  const acceptArr = accept.split(",");
53
47
  const msg = acceptArr.length > 1 ? `one of ${acceptArr.join(", ")}` : acceptArr[0];
54
48
  return {
55
49
  code: FILE_INVALID_TYPE,
56
50
  message: `File type must be ${msg}`
57
51
  };
58
- };
59
- const getTooLargeRejectionErr = (maxSize) => {
52
+ }
53
+ function getTooLargeRejectionErr(maxSize) {
60
54
  return {
61
55
  code: FILE_TOO_LARGE,
62
56
  message: `File is larger than ${maxSize} ${maxSize === 1 ? "byte" : "bytes"}`
63
57
  };
64
- };
65
- const getTooSmallRejectionErr = (minSize) => {
58
+ }
59
+ function getTooSmallRejectionErr(minSize) {
66
60
  return {
67
61
  code: FILE_TOO_SMALL,
68
62
  message: `File is smaller than ${minSize} ${minSize === 1 ? "byte" : "bytes"}`
69
63
  };
70
- };
64
+ }
71
65
  const TOO_MANY_FILES_REJECTION = {
72
66
  code: TOO_MANY_FILES,
73
67
  message: "Too many files"
@@ -78,16 +72,6 @@ const TOO_MANY_FILES_REJECTION = {
78
72
  * During drag events, browsers may return DataTransferItem objects instead of File objects.
79
73
  * Some browsers (e.g., Chrome) return an empty MIME type for certain file types (like .md files)
80
74
  * on DataTransferItem during drag events, even though the type is correctly set during drop.
81
- *
82
- * This function detects such cases by checking for:
83
- * 1. Empty type string
84
- * 2. Presence of getAsFile method (indicates it's a DataTransferItem, not a File)
85
- *
86
- * We accept these during drag to provide proper UI feedback, while maintaining
87
- * strict validation during drop when real File objects are available.
88
- *
89
- * @param {File | DataTransferItem} file
90
- * @returns {boolean}
91
75
  */
92
76
  function isDataTransferItemWithEmptyType(file) {
93
77
  return file.type === "" && typeof file.getAsFile === "function";
@@ -100,13 +84,9 @@ function isDataTransferItemWithEmptyType(file) {
100
84
  *
101
85
  * Chrome/other browsers may return an empty MIME type for files during drag events,
102
86
  * so we accept those as well (we'll validate properly on drop).
103
- *
104
- * @param {File} file
105
- * @param {string} accept
106
- * @returns
107
87
  */
108
88
  function fileAccepted(file, accept) {
109
- const isAcceptable = file.type === "application/x-moz-file" || accepts(file, accept) || isDataTransferItemWithEmptyType(file);
89
+ const isAcceptable = file.type === "application/x-moz-file" || accepts(file, accept ?? "") || isDataTransferItemWithEmptyType(file);
110
90
  return [isAcceptable, isAcceptable ? null : getInvalidTypeRejectionErr(accept)];
111
91
  }
112
92
  function fileMatchSize(file, minSize, maxSize) {
@@ -122,19 +102,7 @@ function fileMatchSize(file, minSize, maxSize) {
122
102
  function isDefined(value) {
123
103
  return value !== void 0 && value !== null;
124
104
  }
125
- /**
126
- *
127
- * @param {object} options
128
- * @param {File[]} options.files
129
- * @param {string} [options.accept]
130
- * @param {number} [options.minSize]
131
- * @param {number} [options.maxSize]
132
- * @param {boolean} [options.multiple]
133
- * @param {number} [options.maxFiles]
134
- * @param {(f: File) => FileError|FileError[]|null} [options.validator]
135
- * @returns
136
- */
137
- function allFilesAccepted({ files, accept, minSize, maxSize, multiple, maxFiles, validator }) {
105
+ function allFilesAccepted({ files, accept, minSize, maxSize, multiple, maxFiles = 0, validator }) {
138
106
  if (!multiple && files.length > 1 || multiple && maxFiles >= 1 && files.length > maxFiles) return false;
139
107
  return files.every((file) => {
140
108
  const [accepted] = fileAccepted(file, accept);
@@ -165,14 +133,11 @@ function isIeOrEdge(userAgent = window.navigator.userAgent) {
165
133
  return isIe(userAgent) || isEdge(userAgent);
166
134
  }
167
135
  /**
168
- * This is intended to be used to compose event handlers
136
+ * This is intended to be used to compose event handlers.
169
137
  * They are executed in order until one of them calls `event.isPropagationStopped()`.
170
138
  * Note that the check is done on the first invoke too,
171
139
  * meaning that if propagation was stopped before invoking the fns,
172
140
  * no handlers will be executed.
173
- *
174
- * @param {Function} fns the event hanlder functions
175
- * @return {Function} the event handler to add to an element
176
141
  */
177
142
  function composeEventHandlers(...fns) {
178
143
  return (event, ...args) => fns.some((fn) => {
@@ -181,19 +146,13 @@ function composeEventHandlers(...fns) {
181
146
  });
182
147
  }
183
148
  /**
184
- * canUseFileSystemAccessAPI checks if the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
185
- * is supported by the browser.
186
- * @returns {boolean}
149
+ * canUseFileSystemAccessAPI checks if the File System Access API is supported by the browser.
187
150
  */
188
151
  function canUseFileSystemAccessAPI() {
189
152
  return "showOpenFilePicker" in window;
190
153
  }
191
154
  /**
192
- * Convert the `{accept}` dropzone prop to the
193
- * `{types}` option for https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
194
- *
195
- * @param {AcceptProp} accept
196
- * @returns {{accept: string[]}[]}
155
+ * Convert the `{accept}` dropzone prop to the `{types}` option for showOpenFilePicker.
197
156
  */
198
157
  function pickerOptionsFromAccept(accept) {
199
158
  if (isDefined(accept)) return [{
@@ -209,75 +168,47 @@ function pickerOptionsFromAccept(accept) {
209
168
  ok = false;
210
169
  }
211
170
  return ok;
212
- }).reduce((agg, [mimeType, ext]) => ({
213
- ...agg,
214
- [mimeType]: ext
215
- }), {})
171
+ }).reduce((agg, [mimeType, ext]) => {
172
+ agg[mimeType] = ext;
173
+ return agg;
174
+ }, {})
216
175
  }];
217
- return accept;
218
176
  }
219
177
  /**
220
178
  * Convert the `{accept}` dropzone prop to an array of MIME types/extensions.
221
- * @param {AcceptProp} accept
222
- * @returns {string}
223
179
  */
224
180
  function acceptPropAsAcceptAttr(accept) {
225
- if (isDefined(accept)) return Object.entries(accept).reduce((a, [mimeType, ext]) => [
226
- ...a,
227
- mimeType,
228
- ...ext
229
- ], []).filter((v) => isMIMEType(v) || isExt(v)).join(",");
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(",");
230
185
  }
231
186
  /**
232
187
  * Check if v is an exception caused by aborting a request (e.g window.showOpenFilePicker()).
233
- *
234
- * See https://developer.mozilla.org/en-US/docs/Web/API/DOMException.
235
- * @param {any} v
236
- * @returns {boolean} True if v is an abort exception.
237
188
  */
238
189
  function isAbort(v) {
239
190
  return v instanceof DOMException && (v.name === "AbortError" || v.code === v.ABORT_ERR);
240
191
  }
241
192
  /**
242
193
  * Check if v is a security error.
243
- *
244
- * See https://developer.mozilla.org/en-US/docs/Web/API/DOMException.
245
- * @param {any} v
246
- * @returns {boolean} True if v is a security error.
247
194
  */
248
195
  function isSecurityError(v) {
249
196
  return v instanceof DOMException && (v.name === "SecurityError" || v.code === v.SECURITY_ERR);
250
197
  }
251
198
  /**
252
199
  * Check if v is a MIME type string.
253
- *
254
- * See accepted format: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers.
255
- *
256
- * @param {string} v
257
200
  */
258
201
  function isMIMEType(v) {
259
202
  return v === "audio/*" || v === "video/*" || v === "image/*" || v === "text/*" || v === "application/*" || /\w+\/[-+.\w]+/g.test(v);
260
203
  }
261
204
  /**
262
205
  * Check if v is a file extension.
263
- * @param {string} v
264
206
  */
265
207
  function isExt(v) {
266
208
  return /^.*\.[\w]+$/.test(v);
267
209
  }
268
- /**
269
- * @typedef {Object.<string, string[]>} AcceptProp
270
- */
271
- /**
272
- * @typedef {object} FileError
273
- * @property {string} message
274
- * @property {ErrorCode|string} code
275
- */
276
- /**
277
- * @typedef {"file-invalid-type"|"file-too-large"|"file-too-small"|"too-many-files"} ErrorCode
278
- */
279
210
  //#endregion
280
- //#region src/index.jsx
211
+ //#region src/index.tsx
281
212
  /**
282
213
  * Convenience wrapper component for the `useDropzone` hook
283
214
  *
@@ -295,261 +226,12 @@ function isExt(v) {
295
226
  const Dropzone = (0, react.forwardRef)(({ children, ...params }, ref) => {
296
227
  const { open, ...props } = useDropzone(params);
297
228
  (0, react.useImperativeHandle)(ref, () => ({ open }), [open]);
298
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: children({
229
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: children?.({
299
230
  ...props,
300
231
  open
301
232
  }) });
302
233
  });
303
234
  Dropzone.displayName = "Dropzone";
304
- const defaultProps = {
305
- disabled: false,
306
- getFilesFromEvent: file_selector.fromEvent,
307
- maxSize: Infinity,
308
- minSize: 0,
309
- multiple: true,
310
- maxFiles: 0,
311
- preventDropOnDocument: true,
312
- noClick: false,
313
- noKeyboard: false,
314
- noDrag: false,
315
- noDragEventsBubbling: false,
316
- validator: null,
317
- useFsAccessApi: false,
318
- autoFocus: false
319
- };
320
- Dropzone.defaultProps = defaultProps;
321
- Dropzone.propTypes = {
322
- /**
323
- * Render function that exposes the dropzone state and prop getter fns
324
- *
325
- * @param {object} params
326
- * @param {Function} params.getRootProps Returns the props you should apply to the root drop container you render
327
- * @param {Function} params.getInputProps Returns the props you should apply to hidden file input you render
328
- * @param {Function} params.open Open the native file selection dialog
329
- * @param {boolean} params.isFocused Dropzone area is in focus
330
- * @param {boolean} params.isFileDialogActive File dialog is opened
331
- * @param {boolean} params.isDragActive Active drag is in progress
332
- * @param {boolean} params.isDragAccept Dragged files are accepted
333
- * @param {boolean} params.isDragReject True only during an active drag when some dragged files would be rejected. After drop, this resets to false. Use fileRejections for post-drop errors.
334
- * @param {boolean} params.isDragGlobal Files are being dragged anywhere on the document
335
- * @param {File[]} params.acceptedFiles Accepted files
336
- * @param {FileRejection[]} params.fileRejections Rejected files and why they were rejected. This persists after drop and is the source of truth for post-drop rejections.
337
- */
338
- children: prop_types.default.func,
339
- /**
340
- * Set accepted file types.
341
- * Checkout https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker types option for more information.
342
- * Keep in mind that mime type determination is not reliable across platforms. CSV files,
343
- * for example, are reported as text/plain under macOS but as application/vnd.ms-excel under
344
- * Windows. In some cases there might not be a mime type set at all (https://github.com/react-dropzone/react-dropzone/issues/276).
345
- */
346
- accept: prop_types.default.objectOf(prop_types.default.arrayOf(prop_types.default.string)),
347
- /**
348
- * Allow drag 'n' drop (or selection from the file dialog) of multiple files
349
- */
350
- multiple: prop_types.default.bool,
351
- /**
352
- * If false, allow dropped items to take over the current browser window
353
- */
354
- preventDropOnDocument: prop_types.default.bool,
355
- /**
356
- * If true, disables click to open the native file selection dialog
357
- */
358
- noClick: prop_types.default.bool,
359
- /**
360
- * If true, disables SPACE/ENTER to open the native file selection dialog.
361
- * Note that it also stops tracking the focus state.
362
- */
363
- noKeyboard: prop_types.default.bool,
364
- /**
365
- * If true, disables drag 'n' drop
366
- */
367
- noDrag: prop_types.default.bool,
368
- /**
369
- * If true, stops drag event propagation to parents
370
- */
371
- noDragEventsBubbling: prop_types.default.bool,
372
- /**
373
- * Minimum file size (in bytes)
374
- */
375
- minSize: prop_types.default.number,
376
- /**
377
- * Maximum file size (in bytes)
378
- */
379
- maxSize: prop_types.default.number,
380
- /**
381
- * Maximum accepted number of files
382
- * The default value is 0 which means there is no limitation to how many files are accepted.
383
- */
384
- maxFiles: prop_types.default.number,
385
- /**
386
- * Enable/disable the dropzone
387
- */
388
- disabled: prop_types.default.bool,
389
- /**
390
- * Use this to provide a custom file aggregator
391
- *
392
- * @param {(DragEvent|Event|Array<FileSystemFileHandle>)} event A drag event or input change event (if files were selected via the file dialog)
393
- */
394
- getFilesFromEvent: prop_types.default.func,
395
- /**
396
- * Cb for when closing the file dialog with no selection
397
- */
398
- onFileDialogCancel: prop_types.default.func,
399
- /**
400
- * Cb for when opening the file dialog
401
- */
402
- onFileDialogOpen: prop_types.default.func,
403
- /**
404
- * Set to true to use the https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API
405
- * to open the file picker instead of using an `<input type="file">` click event.
406
- */
407
- useFsAccessApi: prop_types.default.bool,
408
- /**
409
- * Set to true to focus the root element on render
410
- */
411
- autoFocus: prop_types.default.bool,
412
- /**
413
- * Cb for when the `dragenter` event occurs.
414
- *
415
- * @param {DragEvent} event
416
- */
417
- onDragEnter: prop_types.default.func,
418
- /**
419
- * Cb for when the `dragleave` event occurs
420
- *
421
- * @param {DragEvent} event
422
- */
423
- onDragLeave: prop_types.default.func,
424
- /**
425
- * Cb for when the `dragover` event occurs
426
- *
427
- * @param {DragEvent} event
428
- */
429
- onDragOver: prop_types.default.func,
430
- /**
431
- * Cb for when the `drop` event occurs.
432
- * Note that this callback is invoked after the `getFilesFromEvent` callback is done.
433
- *
434
- * Files are accepted or rejected based on the `accept`, `multiple`, `minSize` and `maxSize` props.
435
- * `accept` must be a valid [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml) according to [input element specification](https://www.w3.org/wiki/HTML/Elements/input/file) or a valid file extension.
436
- * If `multiple` is set to false and additional files are dropped,
437
- * all files besides the first will be rejected.
438
- * Any file which does not have a size in the [`minSize`, `maxSize`] range, will be rejected as well.
439
- *
440
- * Note that the `onDrop` callback will always be invoked regardless if the dropped files were accepted or rejected.
441
- * If you'd like to react to a specific scenario, use the `onDropAccepted`/`onDropRejected` props.
442
- *
443
- * `onDrop` will provide you with an array of [File](https://developer.mozilla.org/en-US/docs/Web/API/File) objects which you can then process and send to a server.
444
- * For example, with [SuperAgent](https://github.com/visionmedia/superagent) as a http/ajax library:
445
- *
446
- * ```js
447
- * function onDrop(acceptedFiles) {
448
- * const req = request.post('/upload')
449
- * acceptedFiles.forEach(file => {
450
- * req.attach(file.name, file)
451
- * })
452
- * req.end(callback)
453
- * }
454
- * ```
455
- *
456
- * @param {File[]} acceptedFiles
457
- * @param {FileRejection[]} fileRejections
458
- * @param {(DragEvent|Event)} event A drag event or input change event (if files were selected via the file dialog)
459
- */
460
- onDrop: prop_types.default.func,
461
- /**
462
- * Cb for when the `drop` event occurs.
463
- * Note that if no files are accepted, this callback is not invoked.
464
- *
465
- * @param {File[]} files
466
- * @param {(DragEvent|Event)} event
467
- */
468
- onDropAccepted: prop_types.default.func,
469
- /**
470
- * Cb for when the `drop` event occurs.
471
- * Note that if no files are rejected, this callback is not invoked.
472
- *
473
- * @param {FileRejection[]} fileRejections
474
- * @param {(DragEvent|Event)} event
475
- */
476
- onDropRejected: prop_types.default.func,
477
- /**
478
- * Cb for when there's some error from any of the promises.
479
- *
480
- * @param {Error} error
481
- */
482
- onError: prop_types.default.func,
483
- /**
484
- * Custom validation function. It must return null if there's no errors.
485
- * @param {File} file
486
- * @returns {FileError|FileError[]|null}
487
- */
488
- validator: prop_types.default.func
489
- };
490
- /**
491
- * A function that is invoked for the `dragenter`,
492
- * `dragover` and `dragleave` events.
493
- * It is not invoked if the items are not files (such as link, text, etc.).
494
- *
495
- * @callback dragCb
496
- * @param {DragEvent} event
497
- */
498
- /**
499
- * A function that is invoked for the `drop` or input change event.
500
- * It is not invoked if the items are not files (such as link, text, etc.).
501
- *
502
- * @callback dropCb
503
- * @param {File[]} acceptedFiles List of accepted files
504
- * @param {FileRejection[]} fileRejections List of rejected files and why they were rejected. This is the authoritative source for post-drop file rejections.
505
- * @param {(DragEvent|Event)} event A drag event or input change event (if files were selected via the file dialog)
506
- */
507
- /**
508
- * A function that is invoked for the `drop` or input change event.
509
- * It is not invoked if the items are files (such as link, text, etc.).
510
- *
511
- * @callback dropAcceptedCb
512
- * @param {File[]} files List of accepted files that meet the given criteria
513
- * (`accept`, `multiple`, `minSize`, `maxSize`)
514
- * @param {(DragEvent|Event)} event A drag event or input change event (if files were selected via the file dialog)
515
- */
516
- /**
517
- * A function that is invoked for the `drop` or input change event.
518
- *
519
- * @callback dropRejectedCb
520
- * @param {File[]} files List of rejected files that do not meet the given criteria
521
- * (`accept`, `multiple`, `minSize`, `maxSize`)
522
- * @param {(DragEvent|Event)} event A drag event or input change event (if files were selected via the file dialog)
523
- */
524
- /**
525
- * A function that is used aggregate files,
526
- * in a asynchronous fashion, from drag or input change events.
527
- *
528
- * @callback getFilesFromEvent
529
- * @param {(DragEvent|Event|Array<FileSystemFileHandle>)} event A drag event or input change event (if files were selected via the file dialog)
530
- * @returns {(File[]|Promise<File[]>)}
531
- */
532
- /**
533
- * An object with the current dropzone state.
534
- *
535
- * @typedef {object} DropzoneState
536
- * @property {boolean} isFocused Dropzone area is in focus
537
- * @property {boolean} isFileDialogActive File dialog is opened
538
- * @property {boolean} isDragActive Active drag is in progress
539
- * @property {boolean} isDragAccept Dragged files are accepted
540
- * @property {boolean} isDragReject True only during an active drag when some dragged files would be rejected. After drop, this resets to false. Use fileRejections for post-drop errors.
541
- * @property {boolean} isDragGlobal Files are being dragged anywhere on the document
542
- * @property {File[]} acceptedFiles Accepted files
543
- * @property {FileRejection[]} fileRejections Rejected files and why they were rejected. This persists after drop and is the source of truth for post-drop rejections.
544
- */
545
- /**
546
- * An object with the dropzone methods.
547
- *
548
- * @typedef {object} DropzoneMethods
549
- * @property {Function} getRootProps Returns the props you should apply to the root drop container you render
550
- * @property {Function} getInputProps Returns the props you should apply to hidden file input you render
551
- * @property {Function} open Open the native file selection dialog
552
- */
553
235
  const initialState = {
554
236
  isFocused: false,
555
237
  isFileDialogActive: false,
@@ -578,81 +260,13 @@ const initialState = {
578
260
  * )
579
261
  * }
580
262
  * ```
581
- *
582
- * @function useDropzone
583
- *
584
- * @param {object} props
585
- * @param {import("./utils").AcceptProp} [props.accept] Set accepted file types.
586
- * Checkout https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker types option for more information.
587
- * Keep in mind that mime type determination is not reliable across platforms. CSV files,
588
- * for example, are reported as text/plain under macOS but as application/vnd.ms-excel under
589
- * Windows. In some cases there might not be a mime type set at all (https://github.com/react-dropzone/react-dropzone/issues/276).
590
- * @param {boolean} [props.multiple=true] Allow drag 'n' drop (or selection from the file dialog) of multiple files
591
- * @param {boolean} [props.preventDropOnDocument=true] If false, allow dropped items to take over the current browser window
592
- * @param {boolean} [props.noClick=false] If true, disables click to open the native file selection dialog
593
- * @param {boolean} [props.noKeyboard=false] If true, disables SPACE/ENTER to open the native file selection dialog.
594
- * Note that it also stops tracking the focus state.
595
- * @param {boolean} [props.noDrag=false] If true, disables drag 'n' drop
596
- * @param {boolean} [props.noDragEventsBubbling=false] If true, stops drag event propagation to parents
597
- * @param {number} [props.minSize=0] Minimum file size (in bytes)
598
- * @param {number} [props.maxSize=Infinity] Maximum file size (in bytes)
599
- * @param {boolean} [props.disabled=false] Enable/disable the dropzone
600
- * @param {getFilesFromEvent} [props.getFilesFromEvent] Use this to provide a custom file aggregator
601
- * @param {Function} [props.onFileDialogCancel] Cb for when closing the file dialog with no selection
602
- * @param {boolean} [props.useFsAccessApi] Set to true to use the https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API
603
- * to open the file picker instead of using an `<input type="file">` click event.
604
- * @param {boolean} autoFocus Set to true to auto focus the root element.
605
- * @param {Function} [props.onFileDialogOpen] Cb for when opening the file dialog
606
- * @param {dragCb} [props.onDragEnter] Cb for when the `dragenter` event occurs.
607
- * @param {dragCb} [props.onDragLeave] Cb for when the `dragleave` event occurs
608
- * @param {dragCb} [props.onDragOver] Cb for when the `dragover` event occurs
609
- * @param {dropCb} [props.onDrop] Cb for when the `drop` event occurs.
610
- * Note that this callback is invoked after the `getFilesFromEvent` callback is done.
611
- *
612
- * Files are accepted or rejected based on the `accept`, `multiple`, `minSize` and `maxSize` props.
613
- * `accept` must be an object with keys as a valid [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml) according to [input element specification](https://www.w3.org/wiki/HTML/Elements/input/file) and the value an array of file extensions (optional).
614
- * If `multiple` is set to false and additional files are dropped,
615
- * all files besides the first will be rejected.
616
- * Any file which does not have a size in the [`minSize`, `maxSize`] range, will be rejected as well.
617
- *
618
- * Note that the `onDrop` callback will always be invoked regardless if the dropped files were accepted or rejected.
619
- * If you'd like to react to a specific scenario, use the `onDropAccepted`/`onDropRejected` props.
620
- *
621
- * The second parameter (fileRejections) is the authoritative list of rejected files after a drop.
622
- * Use this parameter or the fileRejections state property to handle post-drop file rejections,
623
- * as isDragReject only indicates rejection state during active drag operations.
624
- *
625
- * `onDrop` will provide you with an array of [File](https://developer.mozilla.org/en-US/docs/Web/API/File) objects which you can then process and send to a server.
626
- * For example, with [SuperAgent](https://github.com/visionmedia/superagent) as a http/ajax library:
627
- *
628
- * ```js
629
- * function onDrop(acceptedFiles) {
630
- * const req = request.post('/upload')
631
- * acceptedFiles.forEach(file => {
632
- * req.attach(file.name, file)
633
- * })
634
- * req.end(callback)
635
- * }
636
- * ```
637
- * @param {dropAcceptedCb} [props.onDropAccepted]
638
- * @param {dropRejectedCb} [props.onDropRejected]
639
- * @param {(error: Error) => void} [props.onError]
640
- *
641
- * @returns {DropzoneState & DropzoneMethods}
642
263
  */
643
264
  function useDropzone(props = {}) {
644
- const { accept, disabled, getFilesFromEvent, maxSize, minSize, multiple, maxFiles, onDragEnter, onDragLeave, onDragOver, onDrop, onDropAccepted, onDropRejected, onFileDialogCancel, onFileDialogOpen, useFsAccessApi, autoFocus, preventDropOnDocument, noClick, noKeyboard, noDrag, noDragEventsBubbling, onError, validator } = {
645
- ...defaultProps,
646
- ...props
647
- };
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;
648
266
  const acceptAttr = (0, react.useMemo)(() => acceptPropAsAcceptAttr(accept), [accept]);
649
267
  const pickerTypes = (0, react.useMemo)(() => pickerOptionsFromAccept(accept), [accept]);
650
268
  const onFileDialogOpenCb = (0, react.useMemo)(() => typeof onFileDialogOpen === "function" ? onFileDialogOpen : noop, [onFileDialogOpen]);
651
269
  const onFileDialogCancelCb = (0, react.useMemo)(() => typeof onFileDialogCancel === "function" ? onFileDialogCancel : noop, [onFileDialogCancel]);
652
- /**
653
- * @constant
654
- * @type {React.MutableRefObject<HTMLElement>}
655
- */
656
270
  const rootRef = (0, react.useRef)(null);
657
271
  const inputRef = (0, react.useRef)(null);
658
272
  const [state, dispatch] = (0, react.useReducer)(reducer, initialState);
@@ -662,7 +276,7 @@ function useDropzone(props = {}) {
662
276
  if (!fsAccessApiWorksRef.current && isFileDialogActive) setTimeout(() => {
663
277
  if (inputRef.current) {
664
278
  const { files } = inputRef.current;
665
- if (!files.length) {
279
+ if (!files?.length) {
666
280
  dispatch({ type: "closeDialog" });
667
281
  onFileDialogCancelCb();
668
282
  }
@@ -683,7 +297,7 @@ function useDropzone(props = {}) {
683
297
  const dragTargetsRef = (0, react.useRef)([]);
684
298
  const globalDragTargetsRef = (0, react.useRef)([]);
685
299
  const onDocumentDrop = (event) => {
686
- if (rootRef.current && rootRef.current.contains(event.target)) return;
300
+ if (rootRef.current && event.target && rootRef.current.contains(event.target)) return;
687
301
  event.preventDefault();
688
302
  dragTargetsRef.current = [];
689
303
  };
@@ -701,7 +315,7 @@ function useDropzone(props = {}) {
701
315
  }, [rootRef, preventDropOnDocument]);
702
316
  (0, react.useEffect)(() => {
703
317
  const onDocumentDragEnter = (event) => {
704
- globalDragTargetsRef.current = [...globalDragTargetsRef.current, event.target];
318
+ if (event.target) globalDragTargetsRef.current = [...globalDragTargetsRef.current, event.target];
705
319
  if (isEvtWithFiles(event)) dispatch({
706
320
  isDragGlobal: true,
707
321
  type: "setDragGlobal"
@@ -754,7 +368,7 @@ function useDropzone(props = {}) {
754
368
  }, [onError]);
755
369
  const onDragEnterCb = (0, react.useCallback)((event) => {
756
370
  event.preventDefault();
757
- event.persist();
371
+ event.persist?.();
758
372
  stopPropagation(event);
759
373
  dragTargetsRef.current = [...dragTargetsRef.current, event.target];
760
374
  if (isEvtWithFiles(event)) Promise.resolve(getFilesFromEvent(event)).then((files) => {
@@ -791,7 +405,7 @@ function useDropzone(props = {}) {
791
405
  ]);
792
406
  const onDragOverCb = (0, react.useCallback)((event) => {
793
407
  event.preventDefault();
794
- event.persist();
408
+ event.persist?.();
795
409
  stopPropagation(event);
796
410
  const hasFiles = isEvtWithFiles(event);
797
411
  if (hasFiles && event.dataTransfer) try {
@@ -802,9 +416,9 @@ function useDropzone(props = {}) {
802
416
  }, [onDragOver, noDragEventsBubbling]);
803
417
  const onDragLeaveCb = (0, react.useCallback)((event) => {
804
418
  event.preventDefault();
805
- event.persist();
419
+ event.persist?.();
806
420
  stopPropagation(event);
807
- const targets = dragTargetsRef.current.filter((target) => rootRef.current && rootRef.current.contains(target));
421
+ const targets = dragTargetsRef.current.filter((target) => rootRef.current?.contains(target));
808
422
  const targetIdx = targets.indexOf(event.target);
809
423
  if (targetIdx !== -1) targets.splice(targetIdx, 1);
810
424
  dragTargetsRef.current = targets;
@@ -834,7 +448,7 @@ function useDropzone(props = {}) {
834
448
  if (customErrors) errors = errors.concat(customErrors);
835
449
  fileRejections.push({
836
450
  file,
837
- errors: errors.filter((e) => e)
451
+ errors: errors.filter((e) => e != null)
838
452
  });
839
453
  }
840
454
  });
@@ -869,7 +483,7 @@ function useDropzone(props = {}) {
869
483
  ]);
870
484
  const onDropCb = (0, react.useCallback)((event) => {
871
485
  event.preventDefault();
872
- event.persist();
486
+ event.persist?.();
873
487
  stopPropagation(event);
874
488
  dragTargetsRef.current = [];
875
489
  if (isEvtWithFiles(event)) Promise.resolve(getFilesFromEvent(event)).then((files) => {
@@ -901,7 +515,7 @@ function useDropzone(props = {}) {
901
515
  } else if (isSecurityError(e)) {
902
516
  fsAccessApiWorksRef.current = false;
903
517
  if (inputRef.current) {
904
- inputRef.current.value = null;
518
+ inputRef.current.value = "";
905
519
  inputRef.current.click();
906
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."));
907
521
  } else onErrCb(e);
@@ -911,7 +525,7 @@ function useDropzone(props = {}) {
911
525
  if (inputRef.current) {
912
526
  dispatch({ type: "openDialog" });
913
527
  onFileDialogOpenCb();
914
- inputRef.current.value = null;
528
+ inputRef.current.value = "";
915
529
  inputRef.current.click();
916
530
  }
917
531
  }, [
@@ -925,7 +539,7 @@ function useDropzone(props = {}) {
925
539
  multiple
926
540
  ]);
927
541
  const onKeyDownCb = (0, react.useCallback)((event) => {
928
- if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) return;
542
+ if (!rootRef.current?.isEqualNode(event.target)) return;
929
543
  if (event.key === " " || event.key === "Enter" || event.keyCode === 32 || event.keyCode === 13) {
930
544
  event.preventDefault();
931
545
  openFileDialog();
@@ -1024,13 +638,7 @@ function useDropzone(props = {}) {
1024
638
  open: composeHandler(openFileDialog)
1025
639
  };
1026
640
  }
1027
- /**
1028
- * @param {DropzoneState} state
1029
- * @param {{type: string} & DropzoneState} action
1030
- * @returns {DropzoneState}
1031
- */
1032
641
  function reducer(state, action) {
1033
- /* istanbul ignore next */
1034
642
  switch (action.type) {
1035
643
  case "focus": return {
1036
644
  ...state,