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/src/index.js CHANGED
@@ -7,10 +7,10 @@ import React, {
7
7
  useImperativeHandle,
8
8
  useMemo,
9
9
  useReducer,
10
- useRef
11
- } from 'react'
12
- import PropTypes from 'prop-types'
13
- import {fromEvent} from 'file-selector'
10
+ useRef,
11
+ } from "react";
12
+ import PropTypes from "prop-types";
13
+ import { fromEvent } from "file-selector";
14
14
  import {
15
15
  allFilesAccepted,
16
16
  composeEventHandlers,
@@ -18,12 +18,14 @@ import {
18
18
  fileMatchSize,
19
19
  filePickerOptionsTypes,
20
20
  canUseFileSystemAccessAPI,
21
+ isAbort,
21
22
  isEvtWithFiles,
22
23
  isIeOrEdge,
23
24
  isPropagationStopped,
25
+ isSecurityError,
24
26
  onDocumentDragOver,
25
- TOO_MANY_FILES_REJECTION
26
- } from './utils/index'
27
+ TOO_MANY_FILES_REJECTION,
28
+ } from "./utils/index";
27
29
 
28
30
  /**
29
31
  * Convenience wrapper component for the `useDropzone` hook
@@ -39,16 +41,16 @@ import {
39
41
  * </Dropzone>
40
42
  * ```
41
43
  */
42
- const Dropzone = forwardRef(({children, ...params}, ref) => {
43
- const {open, ...props} = useDropzone(params)
44
+ const Dropzone = forwardRef(({ children, ...params }, ref) => {
45
+ const { open, ...props } = useDropzone(params);
44
46
 
45
- useImperativeHandle(ref, () => ({open}), [open])
47
+ useImperativeHandle(ref, () => ({ open }), [open]);
46
48
 
47
49
  // TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
48
- return <Fragment>{children({...props, open})}</Fragment>
49
- })
50
+ return <Fragment>{children({ ...props, open })}</Fragment>;
51
+ });
50
52
 
51
- Dropzone.displayName = 'Dropzone'
53
+ Dropzone.displayName = "Dropzone";
52
54
 
53
55
  // Add default props for react-docgen
54
56
  const defaultProps = {
@@ -64,10 +66,10 @@ const defaultProps = {
64
66
  noDrag: false,
65
67
  noDragEventsBubbling: false,
66
68
  validator: null,
67
- useFsAccessApi: false,
68
- }
69
+ useFsAccessApi: true,
70
+ };
69
71
 
70
- Dropzone.defaultProps = defaultProps
72
+ Dropzone.defaultProps = defaultProps;
71
73
 
72
74
  Dropzone.propTypes = {
73
75
  /**
@@ -96,7 +98,10 @@ Dropzone.propTypes = {
96
98
  * Windows. In some cases there might not be a mime type set at all.
97
99
  * See: https://github.com/react-dropzone/react-dropzone/issues/276
98
100
  */
99
- accept: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
101
+ accept: PropTypes.oneOfType([
102
+ PropTypes.string,
103
+ PropTypes.arrayOf(PropTypes.string),
104
+ ]),
100
105
 
101
106
  /**
102
107
  * Allow drag 'n' drop (or selection from the file dialog) of multiple files
@@ -248,10 +253,10 @@ Dropzone.propTypes = {
248
253
  * @param {File} file
249
254
  * @returns {FileError|FileError[]}
250
255
  */
251
- validator: PropTypes.func
252
- }
256
+ validator: PropTypes.func,
257
+ };
253
258
 
254
- export default Dropzone
259
+ export default Dropzone;
255
260
 
256
261
  /**
257
262
  * A function that is invoked for the `dragenter`,
@@ -325,8 +330,8 @@ const initialState = {
325
330
  isDragReject: false,
326
331
  draggedFiles: [],
327
332
  acceptedFiles: [],
328
- fileRejections: []
329
- }
333
+ fileRejections: [],
334
+ };
330
335
 
331
336
  /**
332
337
  * A React hook that creates a drag 'n' drop area.
@@ -426,271 +431,295 @@ export function useDropzone(options = {}) {
426
431
  noKeyboard,
427
432
  noDrag,
428
433
  noDragEventsBubbling,
429
- validator
434
+ validator,
430
435
  } = {
431
436
  ...defaultProps,
432
- ...options
433
- }
437
+ ...options,
438
+ };
434
439
 
435
440
  const onFileDialogOpenCb = useMemo(
436
- () => typeof onFileDialogOpen === 'function' ? onFileDialogOpen : noop,
437
- [onFileDialogOpen])
441
+ () => (typeof onFileDialogOpen === "function" ? onFileDialogOpen : noop),
442
+ [onFileDialogOpen]
443
+ );
438
444
  const onFileDialogCancelCb = useMemo(
439
- () => typeof onFileDialogCancel === 'function' ? onFileDialogCancel : noop,
440
- [onFileDialogCancel])
445
+ () =>
446
+ typeof onFileDialogCancel === "function" ? onFileDialogCancel : noop,
447
+ [onFileDialogCancel]
448
+ );
449
+
450
+ const rootRef = useRef(null);
451
+ const inputRef = useRef(null);
441
452
 
442
- const rootRef = useRef(null)
443
- const inputRef = useRef(null)
453
+ const [state, dispatch] = useReducer(reducer, initialState);
454
+ const { isFocused, isFileDialogActive, draggedFiles } = state;
444
455
 
445
- const [state, dispatch] = useReducer(reducer, initialState)
446
- const {isFocused, isFileDialogActive, draggedFiles} = state
456
+ const fsAccessApiWorksRef = useRef(
457
+ window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI()
458
+ );
447
459
 
448
460
  // Update file dialog active state when the window is focused on
449
461
  const onWindowFocus = () => {
450
462
  // Execute the timeout only if the file dialog is opened in the browser
451
- if (isFileDialogActive) {
463
+ if (!fsAccessApiWorksRef.current && isFileDialogActive) {
452
464
  setTimeout(() => {
453
465
  if (inputRef.current) {
454
- const {files} = inputRef.current
466
+ const { files } = inputRef.current;
455
467
 
456
468
  if (!files.length) {
457
- dispatch({type: 'closeDialog'})
458
- onFileDialogCancelCb()
469
+ dispatch({ type: "closeDialog" });
470
+ onFileDialogCancelCb();
459
471
  }
460
472
  }
461
- }, 300)
473
+ }, 300);
462
474
  }
463
- }
475
+ };
464
476
  useEffect(() => {
465
- if (useFsAccessApi && canUseFileSystemAccessAPI()) {
466
- return () => {}
467
- }
468
-
469
- window.addEventListener('focus', onWindowFocus, false)
477
+ window.addEventListener("focus", onWindowFocus, false);
470
478
  return () => {
471
- window.removeEventListener('focus', onWindowFocus, false)
472
- }
473
- }, [inputRef, isFileDialogActive, onFileDialogCancelCb, useFsAccessApi])
479
+ window.removeEventListener("focus", onWindowFocus, false);
480
+ };
481
+ }, [inputRef, isFileDialogActive, onFileDialogCancelCb, fsAccessApiWorksRef]);
474
482
 
475
- const dragTargetsRef = useRef([])
476
- const onDocumentDrop = event => {
483
+ const dragTargetsRef = useRef([]);
484
+ const onDocumentDrop = (event) => {
477
485
  if (rootRef.current && rootRef.current.contains(event.target)) {
478
486
  // If we intercepted an event for our instance, let it propagate down to the instance's onDrop handler
479
- return
487
+ return;
480
488
  }
481
- event.preventDefault()
482
- dragTargetsRef.current = []
483
- }
489
+ event.preventDefault();
490
+ dragTargetsRef.current = [];
491
+ };
484
492
 
485
493
  useEffect(() => {
486
494
  if (preventDropOnDocument) {
487
- document.addEventListener('dragover', onDocumentDragOver, false)
488
- document.addEventListener('drop', onDocumentDrop, false)
495
+ document.addEventListener("dragover", onDocumentDragOver, false);
496
+ document.addEventListener("drop", onDocumentDrop, false);
489
497
  }
490
498
 
491
499
  return () => {
492
500
  if (preventDropOnDocument) {
493
- document.removeEventListener('dragover', onDocumentDragOver)
494
- document.removeEventListener('drop', onDocumentDrop)
501
+ document.removeEventListener("dragover", onDocumentDragOver);
502
+ document.removeEventListener("drop", onDocumentDrop);
495
503
  }
496
- }
497
- }, [rootRef, preventDropOnDocument])
504
+ };
505
+ }, [rootRef, preventDropOnDocument]);
498
506
 
499
507
  const onDragEnterCb = useCallback(
500
- event => {
501
- event.preventDefault()
508
+ (event) => {
509
+ event.preventDefault();
502
510
  // Persist here because we need the event later after getFilesFromEvent() is done
503
- event.persist()
504
- stopPropagation(event)
511
+ event.persist();
512
+ stopPropagation(event);
505
513
 
506
- dragTargetsRef.current = [...dragTargetsRef.current, event.target]
514
+ dragTargetsRef.current = [...dragTargetsRef.current, event.target];
507
515
 
508
516
  if (isEvtWithFiles(event)) {
509
- Promise.resolve(getFilesFromEvent(event)).then(draggedFiles => {
517
+ Promise.resolve(getFilesFromEvent(event)).then((draggedFiles) => {
510
518
  if (isPropagationStopped(event) && !noDragEventsBubbling) {
511
- return
519
+ return;
512
520
  }
513
521
 
514
522
  dispatch({
515
523
  draggedFiles,
516
524
  isDragActive: true,
517
- type: 'setDraggedFiles'
518
- })
525
+ type: "setDraggedFiles",
526
+ });
519
527
 
520
528
  if (onDragEnter) {
521
- onDragEnter(event)
529
+ onDragEnter(event);
522
530
  }
523
- })
531
+ });
524
532
  }
525
533
  },
526
534
  [getFilesFromEvent, onDragEnter, noDragEventsBubbling]
527
- )
535
+ );
528
536
 
529
537
  const onDragOverCb = useCallback(
530
- event => {
531
- event.preventDefault()
532
- event.persist()
533
- stopPropagation(event)
538
+ (event) => {
539
+ event.preventDefault();
540
+ event.persist();
541
+ stopPropagation(event);
534
542
 
535
543
  const hasFiles = isEvtWithFiles(event);
536
544
  if (hasFiles && event.dataTransfer) {
537
545
  try {
538
- event.dataTransfer.dropEffect = 'copy'
546
+ event.dataTransfer.dropEffect = "copy";
539
547
  } catch {} /* eslint-disable-line no-empty */
540
548
  }
541
549
 
542
550
  if (hasFiles && onDragOver) {
543
- onDragOver(event)
551
+ onDragOver(event);
544
552
  }
545
553
 
546
- return false
554
+ return false;
547
555
  },
548
556
  [onDragOver, noDragEventsBubbling]
549
- )
557
+ );
550
558
 
551
559
  const onDragLeaveCb = useCallback(
552
- event => {
553
- event.preventDefault()
554
- event.persist()
555
- stopPropagation(event)
560
+ (event) => {
561
+ event.preventDefault();
562
+ event.persist();
563
+ stopPropagation(event);
556
564
 
557
565
  // Only deactivate once the dropzone and all children have been left
558
566
  const targets = dragTargetsRef.current.filter(
559
- target => rootRef.current && rootRef.current.contains(target)
560
- )
567
+ (target) => rootRef.current && rootRef.current.contains(target)
568
+ );
561
569
  // Make sure to remove a target present multiple times only once
562
570
  // (Firefox may fire dragenter/dragleave multiple times on the same element)
563
- const targetIdx = targets.indexOf(event.target)
571
+ const targetIdx = targets.indexOf(event.target);
564
572
  if (targetIdx !== -1) {
565
- targets.splice(targetIdx, 1)
573
+ targets.splice(targetIdx, 1);
566
574
  }
567
- dragTargetsRef.current = targets
575
+ dragTargetsRef.current = targets;
568
576
  if (targets.length > 0) {
569
- return
577
+ return;
570
578
  }
571
579
 
572
580
  dispatch({
573
581
  isDragActive: false,
574
- type: 'setDraggedFiles',
575
- draggedFiles: []
576
- })
582
+ type: "setDraggedFiles",
583
+ draggedFiles: [],
584
+ });
577
585
 
578
586
  if (isEvtWithFiles(event) && onDragLeave) {
579
- onDragLeave(event)
587
+ onDragLeave(event);
580
588
  }
581
589
  },
582
590
  [rootRef, onDragLeave, noDragEventsBubbling]
583
- )
591
+ );
584
592
 
585
- const setFiles = useCallback((files, event) => {
586
- const acceptedFiles = []
587
- const fileRejections = []
593
+ const setFiles = useCallback(
594
+ (files, event) => {
595
+ const acceptedFiles = [];
596
+ const fileRejections = [];
588
597
 
589
- files.forEach(file => {
590
- const [accepted, acceptError] = fileAccepted(file, accept)
591
- const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize)
592
- const customErrors = validator ? validator(file) : null;
598
+ files.forEach((file) => {
599
+ const [accepted, acceptError] = fileAccepted(file, accept);
600
+ const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize);
601
+ const customErrors = validator ? validator(file) : null;
593
602
 
594
- if (accepted && sizeMatch && !customErrors) {
595
- acceptedFiles.push(file)
596
- } else {
597
- let errors = [acceptError, sizeError];
603
+ if (accepted && sizeMatch && !customErrors) {
604
+ acceptedFiles.push(file);
605
+ } else {
606
+ let errors = [acceptError, sizeError];
598
607
 
599
- if (customErrors) {
600
- errors = errors.concat(customErrors);
601
- }
608
+ if (customErrors) {
609
+ errors = errors.concat(customErrors);
610
+ }
602
611
 
603
- fileRejections.push({file, errors: errors.filter(e => e)})
612
+ fileRejections.push({ file, errors: errors.filter((e) => e) });
613
+ }
614
+ });
615
+
616
+ if (
617
+ (!multiple && acceptedFiles.length > 1) ||
618
+ (multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles)
619
+ ) {
620
+ // Reject everything and empty accepted files
621
+ acceptedFiles.forEach((file) => {
622
+ fileRejections.push({ file, errors: [TOO_MANY_FILES_REJECTION] });
623
+ });
624
+ acceptedFiles.splice(0);
604
625
  }
605
- })
606
-
607
- if ((!multiple && acceptedFiles.length > 1) || (multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles)) {
608
- // Reject everything and empty accepted files
609
- acceptedFiles.forEach(file => {
610
- fileRejections.push({file, errors: [TOO_MANY_FILES_REJECTION]})
611
- })
612
- acceptedFiles.splice(0)
613
- }
614
626
 
615
- dispatch({
616
- acceptedFiles,
617
- fileRejections,
618
- type: 'setFiles'
619
- })
627
+ dispatch({
628
+ acceptedFiles,
629
+ fileRejections,
630
+ type: "setFiles",
631
+ });
620
632
 
621
- if (onDrop) {
622
- onDrop(acceptedFiles, fileRejections, event)
623
- }
633
+ if (onDrop) {
634
+ onDrop(acceptedFiles, fileRejections, event);
635
+ }
624
636
 
625
- if (fileRejections.length > 0 && onDropRejected) {
626
- onDropRejected(fileRejections, event)
627
- }
637
+ if (fileRejections.length > 0 && onDropRejected) {
638
+ onDropRejected(fileRejections, event);
639
+ }
628
640
 
629
- if (acceptedFiles.length > 0 && onDropAccepted) {
630
- onDropAccepted(acceptedFiles, event)
631
- }
632
- }, [
633
- dispatch,
634
- multiple,
635
- accept,
636
- minSize,
637
- maxSize,
638
- maxFiles,
639
- onDrop,
640
- onDropAccepted,
641
- onDropRejected,
642
- validator
643
- ]);
641
+ if (acceptedFiles.length > 0 && onDropAccepted) {
642
+ onDropAccepted(acceptedFiles, event);
643
+ }
644
+ },
645
+ [
646
+ dispatch,
647
+ multiple,
648
+ accept,
649
+ minSize,
650
+ maxSize,
651
+ maxFiles,
652
+ onDrop,
653
+ onDropAccepted,
654
+ onDropRejected,
655
+ validator,
656
+ ]
657
+ );
644
658
 
645
659
  const onDropCb = useCallback(
646
- event => {
647
- event.preventDefault()
660
+ (event) => {
661
+ event.preventDefault();
648
662
  // Persist here because we need the event later after getFilesFromEvent() is done
649
- event.persist()
650
- stopPropagation(event)
663
+ event.persist();
664
+ stopPropagation(event);
651
665
 
652
- dragTargetsRef.current = []
666
+ dragTargetsRef.current = [];
653
667
 
654
668
  if (isEvtWithFiles(event)) {
655
- Promise.resolve(getFilesFromEvent(event)).then(files => {
669
+ Promise.resolve(getFilesFromEvent(event)).then((files) => {
656
670
  if (isPropagationStopped(event) && !noDragEventsBubbling) {
657
- return
671
+ return;
658
672
  }
659
- setFiles(files, event)
660
- })
673
+ setFiles(files, event);
674
+ });
661
675
  }
662
- dispatch({type: 'reset'})
676
+ dispatch({ type: "reset" });
663
677
  },
664
- [
665
- getFilesFromEvent,
666
- setFiles,
667
- noDragEventsBubbling
668
- ]
669
- )
678
+ [getFilesFromEvent, setFiles, noDragEventsBubbling]
679
+ );
670
680
 
671
681
  // Fn for opening the file dialog programmatically
672
682
  const openFileDialog = useCallback(() => {
673
- if (useFsAccessApi && canUseFileSystemAccessAPI()) {
674
- dispatch({type: 'openDialog'})
675
- onFileDialogOpenCb()
683
+ // No point to use FS access APIs if context is not secure
684
+ // https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#feature_detection
685
+ if (fsAccessApiWorksRef.current) {
686
+ dispatch({ type: "openDialog" });
687
+ onFileDialogOpenCb();
676
688
  // https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
677
689
  const opts = {
678
690
  multiple,
679
- types: filePickerOptionsTypes(accept)
691
+ types: filePickerOptionsTypes(accept),
680
692
  };
681
- window.showOpenFilePicker(opts)
682
- .then(handles => getFilesFromEvent(handles))
683
- .then(files => setFiles(files, null))
684
- .catch(e => onFileDialogCancelCb(e))
685
- .finally(() => dispatch({type: 'closeDialog'}));
686
- return
693
+ window
694
+ .showOpenFilePicker(opts)
695
+ .then((handles) => getFilesFromEvent(handles))
696
+ .then((files) => {
697
+ setFiles(files, null);
698
+ dispatch({ type: "closeDialog" });
699
+ })
700
+ .catch((e) => {
701
+ // AbortError means the user canceled
702
+ if (isAbort(e)) {
703
+ onFileDialogCancelCb(e);
704
+ dispatch({ type: "closeDialog" });
705
+ } else if (isSecurityError(e)) {
706
+ fsAccessApiWorksRef.current = false;
707
+ // CORS, so cannot use this API
708
+ // Try using the input
709
+ if (inputRef.current) {
710
+ inputRef.current.value = null;
711
+ inputRef.current.click();
712
+ }
713
+ }
714
+ });
715
+ return;
687
716
  }
688
717
 
689
718
  if (inputRef.current) {
690
- dispatch({type: 'openDialog'})
691
- onFileDialogOpenCb()
692
- inputRef.current.value = null
693
- inputRef.current.click()
719
+ dispatch({ type: "openDialog" });
720
+ onFileDialogOpenCb();
721
+ inputRef.current.value = null;
722
+ inputRef.current.click();
694
723
  }
695
724
  }, [
696
725
  dispatch,
@@ -699,94 +728,105 @@ export function useDropzone(options = {}) {
699
728
  useFsAccessApi,
700
729
  setFiles,
701
730
  accept,
702
- multiple
703
- ])
731
+ multiple,
732
+ ]);
704
733
 
705
734
  // Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
706
735
  const onKeyDownCb = useCallback(
707
- event => {
736
+ (event) => {
708
737
  // Ignore keyboard events bubbling up the DOM tree
709
738
  if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
710
- return
739
+ return;
711
740
  }
712
741
 
713
742
  if (event.keyCode === 32 || event.keyCode === 13) {
714
- event.preventDefault()
715
- openFileDialog()
743
+ event.preventDefault();
744
+ openFileDialog();
716
745
  }
717
746
  },
718
- [rootRef, inputRef, openFileDialog]
719
- )
747
+ [rootRef, openFileDialog]
748
+ );
720
749
 
721
750
  // Update focus state for the dropzone
722
751
  const onFocusCb = useCallback(() => {
723
- dispatch({type: 'focus'})
724
- }, [])
752
+ dispatch({ type: "focus" });
753
+ }, []);
725
754
  const onBlurCb = useCallback(() => {
726
- dispatch({type: 'blur'})
727
- }, [])
755
+ dispatch({ type: "blur" });
756
+ }, []);
728
757
 
729
758
  // Cb to open the file dialog when click occurs on the dropzone
730
759
  const onClickCb = useCallback(() => {
731
760
  if (noClick) {
732
- return
761
+ return;
733
762
  }
734
763
 
735
764
  // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
736
765
  // to ensure React can handle state changes
737
766
  // See: https://github.com/react-dropzone/react-dropzone/issues/450
738
767
  if (isIeOrEdge()) {
739
- setTimeout(openFileDialog, 0)
768
+ setTimeout(openFileDialog, 0);
740
769
  } else {
741
- openFileDialog()
770
+ openFileDialog();
742
771
  }
743
- }, [inputRef, noClick, openFileDialog])
772
+ }, [noClick, openFileDialog]);
744
773
 
745
- const composeHandler = fn => {
746
- return disabled ? null : fn
747
- }
774
+ const composeHandler = (fn) => {
775
+ return disabled ? null : fn;
776
+ };
748
777
 
749
- const composeKeyboardHandler = fn => {
750
- return noKeyboard ? null : composeHandler(fn)
751
- }
778
+ const composeKeyboardHandler = (fn) => {
779
+ return noKeyboard ? null : composeHandler(fn);
780
+ };
752
781
 
753
- const composeDragHandler = fn => {
754
- return noDrag ? null : composeHandler(fn)
755
- }
782
+ const composeDragHandler = (fn) => {
783
+ return noDrag ? null : composeHandler(fn);
784
+ };
756
785
 
757
- const stopPropagation = event => {
786
+ const stopPropagation = (event) => {
758
787
  if (noDragEventsBubbling) {
759
- event.stopPropagation()
788
+ event.stopPropagation();
760
789
  }
761
- }
790
+ };
762
791
 
763
792
  const getRootProps = useMemo(
764
- () => ({
765
- refKey = 'ref',
766
- role,
767
- onKeyDown,
768
- onFocus,
769
- onBlur,
770
- onClick,
771
- onDragEnter,
772
- onDragOver,
773
- onDragLeave,
774
- onDrop,
775
- ...rest
776
- } = {}) => ({
777
- onKeyDown: composeKeyboardHandler(composeEventHandlers(onKeyDown, onKeyDownCb)),
778
- onFocus: composeKeyboardHandler(composeEventHandlers(onFocus, onFocusCb)),
779
- onBlur: composeKeyboardHandler(composeEventHandlers(onBlur, onBlurCb)),
780
- onClick: composeHandler(composeEventHandlers(onClick, onClickCb)),
781
- onDragEnter: composeDragHandler(composeEventHandlers(onDragEnter, onDragEnterCb)),
782
- onDragOver: composeDragHandler(composeEventHandlers(onDragOver, onDragOverCb)),
783
- onDragLeave: composeDragHandler(composeEventHandlers(onDragLeave, onDragLeaveCb)),
784
- onDrop: composeDragHandler(composeEventHandlers(onDrop, onDropCb)),
785
- role: typeof role === 'string' && role !== '' ? role : 'button',
786
- [refKey]: rootRef,
787
- ...(!disabled && !noKeyboard ? {tabIndex: 0} : {}),
788
- ...rest
789
- }),
793
+ () =>
794
+ ({
795
+ refKey = "ref",
796
+ role,
797
+ onKeyDown,
798
+ onFocus,
799
+ onBlur,
800
+ onClick,
801
+ onDragEnter,
802
+ onDragOver,
803
+ onDragLeave,
804
+ onDrop,
805
+ ...rest
806
+ } = {}) => ({
807
+ onKeyDown: composeKeyboardHandler(
808
+ composeEventHandlers(onKeyDown, onKeyDownCb)
809
+ ),
810
+ onFocus: composeKeyboardHandler(
811
+ composeEventHandlers(onFocus, onFocusCb)
812
+ ),
813
+ onBlur: composeKeyboardHandler(composeEventHandlers(onBlur, onBlurCb)),
814
+ onClick: composeHandler(composeEventHandlers(onClick, onClickCb)),
815
+ onDragEnter: composeDragHandler(
816
+ composeEventHandlers(onDragEnter, onDragEnterCb)
817
+ ),
818
+ onDragOver: composeDragHandler(
819
+ composeEventHandlers(onDragOver, onDragOverCb)
820
+ ),
821
+ onDragLeave: composeDragHandler(
822
+ composeEventHandlers(onDragLeave, onDragLeaveCb)
823
+ ),
824
+ onDrop: composeDragHandler(composeEventHandlers(onDrop, onDropCb)),
825
+ role: typeof role === "string" && role !== "" ? role : "button",
826
+ [refKey]: rootRef,
827
+ ...(!disabled && !noKeyboard ? { tabIndex: 0 } : {}),
828
+ ...rest,
829
+ }),
790
830
  [
791
831
  rootRef,
792
832
  onKeyDownCb,
@@ -799,39 +839,51 @@ export function useDropzone(options = {}) {
799
839
  onDropCb,
800
840
  noKeyboard,
801
841
  noDrag,
802
- disabled
842
+ disabled,
803
843
  ]
804
- )
844
+ );
805
845
 
806
- const onInputElementClick = useCallback(event => {
807
- event.stopPropagation()
808
- }, [])
846
+ const onInputElementClick = useCallback((event) => {
847
+ event.stopPropagation();
848
+ }, []);
809
849
 
810
850
  const getInputProps = useMemo(
811
- () => ({refKey = 'ref', onChange, onClick, ...rest} = {}) => {
812
- const inputProps = {
813
- accept,
814
- multiple,
815
- type: 'file',
816
- style: {display: 'none'},
817
- onChange: composeHandler(composeEventHandlers(onChange, onDropCb)),
818
- onClick: composeHandler(composeEventHandlers(onClick, onInputElementClick)),
819
- autoComplete: 'off',
820
- tabIndex: -1,
821
- [refKey]: inputRef
822
- }
823
-
824
- return {
825
- ...inputProps,
826
- ...rest
827
- }
828
- },
851
+ () =>
852
+ ({ refKey = "ref", onChange, onClick, ...rest } = {}) => {
853
+ const inputProps = {
854
+ accept,
855
+ multiple,
856
+ type: "file",
857
+ style: { display: "none" },
858
+ onChange: composeHandler(composeEventHandlers(onChange, onDropCb)),
859
+ onClick: composeHandler(
860
+ composeEventHandlers(onClick, onInputElementClick)
861
+ ),
862
+ autoComplete: "off",
863
+ tabIndex: -1,
864
+ [refKey]: inputRef,
865
+ };
866
+
867
+ return {
868
+ ...inputProps,
869
+ ...rest,
870
+ };
871
+ },
829
872
  [inputRef, accept, multiple, onDropCb, disabled]
830
- )
831
-
832
- const fileCount = draggedFiles.length
833
- const isDragAccept = fileCount > 0 && allFilesAccepted({files: draggedFiles, accept, minSize, maxSize, multiple, maxFiles})
834
- const isDragReject = fileCount > 0 && !isDragAccept
873
+ );
874
+
875
+ const fileCount = draggedFiles.length;
876
+ const isDragAccept =
877
+ fileCount > 0 &&
878
+ allFilesAccepted({
879
+ files: draggedFiles,
880
+ accept,
881
+ minSize,
882
+ maxSize,
883
+ multiple,
884
+ maxFiles,
885
+ });
886
+ const isDragReject = fileCount > 0 && !isDragAccept;
835
887
 
836
888
  return {
837
889
  ...state,
@@ -842,56 +894,56 @@ export function useDropzone(options = {}) {
842
894
  getInputProps,
843
895
  rootRef,
844
896
  inputRef,
845
- open: composeHandler(openFileDialog)
846
- }
897
+ open: composeHandler(openFileDialog),
898
+ };
847
899
  }
848
900
 
849
901
  function reducer(state, action) {
850
902
  /* istanbul ignore next */
851
903
  switch (action.type) {
852
- case 'focus':
904
+ case "focus":
853
905
  return {
854
906
  ...state,
855
- isFocused: true
856
- }
857
- case 'blur':
907
+ isFocused: true,
908
+ };
909
+ case "blur":
858
910
  return {
859
911
  ...state,
860
- isFocused: false
861
- }
862
- case 'openDialog':
912
+ isFocused: false,
913
+ };
914
+ case "openDialog":
863
915
  return {
864
916
  ...initialState,
865
- isFileDialogActive: true
866
- }
867
- case 'closeDialog':
917
+ isFileDialogActive: true,
918
+ };
919
+ case "closeDialog":
868
920
  return {
869
921
  ...state,
870
- isFileDialogActive: false
871
- }
872
- case 'setDraggedFiles':
922
+ isFileDialogActive: false,
923
+ };
924
+ case "setDraggedFiles":
873
925
  /* eslint no-case-declarations: 0 */
874
- const {isDragActive, draggedFiles} = action
926
+ const { isDragActive, draggedFiles } = action;
875
927
  return {
876
928
  ...state,
877
929
  draggedFiles,
878
- isDragActive
879
- }
880
- case 'setFiles':
930
+ isDragActive,
931
+ };
932
+ case "setFiles":
881
933
  return {
882
934
  ...state,
883
935
  acceptedFiles: action.acceptedFiles,
884
- fileRejections: action.fileRejections
885
- }
886
- case 'reset':
936
+ fileRejections: action.fileRejections,
937
+ };
938
+ case "reset":
887
939
  return {
888
- ...initialState
889
- }
940
+ ...initialState,
941
+ };
890
942
  default:
891
- return state
943
+ return state;
892
944
  }
893
945
  }
894
946
 
895
947
  function noop() {}
896
948
 
897
- export {ErrorCode} from './utils'
949
+ export { ErrorCode } from "./utils";