react-dropzone 13.0.0 → 14.1.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/README.md CHANGED
@@ -230,7 +230,7 @@ dropzoneRef.open()
230
230
  ```js static
231
231
  import React from 'react'
232
232
  import Dropzone from 'react-dropzone'
233
- import {act, fireEvent, render, waitFor} from '@testing-library/react'
233
+ import {act, fireEvent, render} from '@testing-library/react'
234
234
 
235
235
  test('invoke onDragEnter when dragenter event occurs', async () => {
236
236
  const file = new File([
@@ -248,25 +248,17 @@ test('invoke onDragEnter when dragenter event occurs', async () => {
248
248
  )}
249
249
  </Dropzone>
250
250
  )
251
- const { container, rerender } = render(ui)
252
- const dropzone = container.querySelector('div')
253
-
254
- dispatchEvt(dropzone, 'dragenter', data)
255
- await flushPromises(rerender, ui)
256
-
251
+ const { container } = render(ui)
252
+
253
+ await act(
254
+ () => fireEvent.dragEnter(
255
+ container.querySelector('div'),
256
+ data,
257
+ )
258
+ );
257
259
  expect(onDragEnter).toHaveBeenCalled()
258
260
  })
259
261
 
260
- async function flushPromises(rerender, ui) {
261
- await act(() => waitFor(() => rerender(ui)))
262
- }
263
-
264
- function dispatchEvt(node, type, data) {
265
- const event = new Event(type, { bubbles: true })
266
- Object.assign(event, data)
267
- fireEvent(node, event)
268
- }
269
-
270
262
  function mockData(files) {
271
263
  return {
272
264
  dataTransfer: {
package/dist/es/index.js CHANGED
@@ -86,7 +86,8 @@ var defaultProps = {
86
86
  noDrag: false,
87
87
  noDragEventsBubbling: false,
88
88
  validator: null,
89
- useFsAccessApi: true
89
+ useFsAccessApi: true,
90
+ autoFocus: false
90
91
  };
91
92
  Dropzone.defaultProps = defaultProps;
92
93
  Dropzone.propTypes = {
@@ -102,7 +103,6 @@ Dropzone.propTypes = {
102
103
  * @param {boolean} params.isDragActive Active drag is in progress
103
104
  * @param {boolean} params.isDragAccept Dragged files are accepted
104
105
  * @param {boolean} params.isDragReject Some dragged files are rejected
105
- * @param {File[]} params.draggedFiles Files in active drag
106
106
  * @param {File[]} params.acceptedFiles Accepted files
107
107
  * @param {FileRejection[]} params.fileRejections Rejected files and why they were rejected
108
108
  */
@@ -192,6 +192,11 @@ Dropzone.propTypes = {
192
192
  */
193
193
  useFsAccessApi: PropTypes.bool,
194
194
 
195
+ /**
196
+ * Set to true to focus the root element on render
197
+ */
198
+ autoFocus: PropTypes.bool,
199
+
195
200
  /**
196
201
  * Cb for when the `dragenter` event occurs.
197
202
  *
@@ -326,29 +331,33 @@ export default Dropzone;
326
331
  */
327
332
 
328
333
  /**
329
- * An object with the current dropzone state and some helper functions.
334
+ * An object with the current dropzone state.
330
335
  *
331
336
  * @typedef {object} DropzoneState
332
- * @property {Function} getRootProps Returns the props you should apply to the root drop container you render
333
- * @property {Function} getInputProps Returns the props you should apply to hidden file input you render
334
- * @property {Function} open Open the native file selection dialog
335
337
  * @property {boolean} isFocused Dropzone area is in focus
336
338
  * @property {boolean} isFileDialogActive File dialog is opened
337
339
  * @property {boolean} isDragActive Active drag is in progress
338
340
  * @property {boolean} isDragAccept Dragged files are accepted
339
341
  * @property {boolean} isDragReject Some dragged files are rejected
340
- * @property {File[]} draggedFiles Files in active drag
341
342
  * @property {File[]} acceptedFiles Accepted files
342
343
  * @property {FileRejection[]} fileRejections Rejected files and why they were rejected
343
344
  */
344
345
 
346
+ /**
347
+ * An object with the dropzone methods.
348
+ *
349
+ * @typedef {object} DropzoneMethods
350
+ * @property {Function} getRootProps Returns the props you should apply to the root drop container you render
351
+ * @property {Function} getInputProps Returns the props you should apply to hidden file input you render
352
+ * @property {Function} open Open the native file selection dialog
353
+ */
354
+
345
355
  var initialState = {
346
356
  isFocused: false,
347
357
  isFileDialogActive: false,
348
358
  isDragActive: false,
349
359
  isDragAccept: false,
350
360
  isDragReject: false,
351
- draggedFiles: [],
352
361
  acceptedFiles: [],
353
362
  fileRejections: []
354
363
  };
@@ -393,6 +402,7 @@ var initialState = {
393
402
  * @param {Function} [props.onFileDialogCancel] Cb for when closing the file dialog with no selection
394
403
  * @param {boolean} [props.useFsAccessApi] Set to true to use the https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API
395
404
  * to open the file picker instead of using an `<input type="file">` click event.
405
+ * @param {boolean} autoFocus Set to true to auto focus the root element.
396
406
  * @param {Function} [props.onFileDialogOpen] Cb for when opening the file dialog
397
407
  * @param {dragCb} [props.onDragEnter] Cb for when the `dragenter` event occurs.
398
408
  * @param {dragCb} [props.onDragLeave] Cb for when the `dragleave` event occurs
@@ -425,7 +435,7 @@ var initialState = {
425
435
  * @param {dropRejectedCb} [props.onDropRejected]
426
436
  * @param {(error: Error) => void} [props.onError]
427
437
  *
428
- * @returns {DropzoneState}
438
+ * @returns {DropzoneState & DropzoneMethods}
429
439
  */
430
440
 
431
441
  export function useDropzone() {
@@ -448,6 +458,7 @@ export function useDropzone() {
448
458
  onFileDialogCancel = _defaultProps$props.onFileDialogCancel,
449
459
  onFileDialogOpen = _defaultProps$props.onFileDialogOpen,
450
460
  useFsAccessApi = _defaultProps$props.useFsAccessApi,
461
+ autoFocus = _defaultProps$props.autoFocus,
451
462
  preventDropOnDocument = _defaultProps$props.preventDropOnDocument,
452
463
  noClick = _defaultProps$props.noClick,
453
464
  noKeyboard = _defaultProps$props.noKeyboard,
@@ -468,6 +479,11 @@ export function useDropzone() {
468
479
  var onFileDialogCancelCb = useMemo(function () {
469
480
  return typeof onFileDialogCancel === "function" ? onFileDialogCancel : noop;
470
481
  }, [onFileDialogCancel]);
482
+ /**
483
+ * @constant
484
+ * @type {React.MutableRefObject<HTMLElement>}
485
+ */
486
+
471
487
  var rootRef = useRef(null);
472
488
  var inputRef = useRef(null);
473
489
 
@@ -477,8 +493,7 @@ export function useDropzone() {
477
493
  dispatch = _useReducer2[1];
478
494
 
479
495
  var isFocused = state.isFocused,
480
- isFileDialogActive = state.isFileDialogActive,
481
- draggedFiles = state.draggedFiles;
496
+ isFileDialogActive = state.isFileDialogActive;
482
497
  var fsAccessApiWorksRef = useRef(typeof window !== "undefined" && window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI()); // Update file dialog active state when the window is focused on
483
498
 
484
499
  var onWindowFocus = function onWindowFocus() {
@@ -529,7 +544,15 @@ export function useDropzone() {
529
544
  document.removeEventListener("drop", onDocumentDrop);
530
545
  }
531
546
  };
532
- }, [rootRef, preventDropOnDocument]);
547
+ }, [rootRef, preventDropOnDocument]); // Auto focus the root when autoFocus is true
548
+
549
+ useEffect(function () {
550
+ if (!disabled && autoFocus && rootRef.current) {
551
+ rootRef.current.focus();
552
+ }
553
+
554
+ return function () {};
555
+ }, [rootRef, autoFocus, disabled]);
533
556
  var onErrCb = useCallback(function (e) {
534
557
  if (onError) {
535
558
  onError(e);
@@ -546,13 +569,24 @@ export function useDropzone() {
546
569
  dragTargetsRef.current = [].concat(_toConsumableArray(dragTargetsRef.current), [event.target]);
547
570
 
548
571
  if (isEvtWithFiles(event)) {
549
- Promise.resolve(getFilesFromEvent(event)).then(function (draggedFiles) {
572
+ Promise.resolve(getFilesFromEvent(event)).then(function (files) {
550
573
  if (isPropagationStopped(event) && !noDragEventsBubbling) {
551
574
  return;
552
575
  }
553
576
 
577
+ var fileCount = files.length;
578
+ var isDragAccept = fileCount > 0 && allFilesAccepted({
579
+ files: files,
580
+ accept: acceptAttr,
581
+ minSize: minSize,
582
+ maxSize: maxSize,
583
+ multiple: multiple,
584
+ maxFiles: maxFiles
585
+ });
586
+ var isDragReject = fileCount > 0 && !isDragAccept;
554
587
  dispatch({
555
- draggedFiles: draggedFiles,
588
+ isDragAccept: isDragAccept,
589
+ isDragReject: isDragReject,
556
590
  isDragActive: true,
557
591
  type: "setDraggedFiles"
558
592
  });
@@ -564,7 +598,7 @@ export function useDropzone() {
564
598
  return onErrCb(e);
565
599
  });
566
600
  }
567
- }, [getFilesFromEvent, onDragEnter, onErrCb, noDragEventsBubbling]);
601
+ }, [getFilesFromEvent, onDragEnter, onErrCb, noDragEventsBubbling, acceptAttr, minSize, maxSize, multiple, maxFiles]);
568
602
  var onDragOverCb = useCallback(function (event) {
569
603
  event.preventDefault();
570
604
  event.persist();
@@ -608,9 +642,10 @@ export function useDropzone() {
608
642
  }
609
643
 
610
644
  dispatch({
611
- isDragActive: false,
612
645
  type: "setDraggedFiles",
613
- draggedFiles: []
646
+ isDragActive: false,
647
+ isDragAccept: false,
648
+ isDragReject: false
614
649
  });
615
650
 
616
651
  if (isEvtWithFiles(event) && onDragLeave) {
@@ -837,7 +872,7 @@ export function useDropzone() {
837
872
  onDragOver: composeDragHandler(composeEventHandlers(onDragOver, onDragOverCb)),
838
873
  onDragLeave: composeDragHandler(composeEventHandlers(onDragLeave, onDragLeaveCb)),
839
874
  onDrop: composeDragHandler(composeEventHandlers(onDrop, onDropCb)),
840
- role: typeof role === "string" && role !== "" ? role : "button"
875
+ role: typeof role === "string" && role !== "" ? role : "presentation"
841
876
  }, refKey, rootRef), !disabled && !noKeyboard ? {
842
877
  tabIndex: 0
843
878
  } : {}), rest);
@@ -870,19 +905,7 @@ export function useDropzone() {
870
905
  return _objectSpread(_objectSpread({}, inputProps), rest);
871
906
  };
872
907
  }, [inputRef, accept, multiple, onDropCb, disabled]);
873
- var fileCount = draggedFiles.length;
874
- var isDragAccept = fileCount > 0 && allFilesAccepted({
875
- files: draggedFiles,
876
- accept: acceptAttr,
877
- minSize: minSize,
878
- maxSize: maxSize,
879
- multiple: multiple,
880
- maxFiles: maxFiles
881
- });
882
- var isDragReject = fileCount > 0 && !isDragAccept;
883
908
  return _objectSpread(_objectSpread({}, state), {}, {
884
- isDragAccept: isDragAccept,
885
- isDragReject: isDragReject,
886
909
  isFocused: isFocused && !disabled,
887
910
  getRootProps: getRootProps,
888
911
  getInputProps: getInputProps,
@@ -891,6 +914,11 @@ export function useDropzone() {
891
914
  open: composeHandler(openFileDialog)
892
915
  });
893
916
  }
917
+ /**
918
+ * @param {DropzoneState} state
919
+ * @param {{type: string} & DropzoneState} action
920
+ * @returns {DropzoneState}
921
+ */
894
922
 
895
923
  function reducer(state, action) {
896
924
  /* istanbul ignore next */
@@ -916,12 +944,10 @@ function reducer(state, action) {
916
944
  });
917
945
 
918
946
  case "setDraggedFiles":
919
- /* eslint no-case-declarations: 0 */
920
- var isDragActive = action.isDragActive,
921
- draggedFiles = action.draggedFiles;
922
947
  return _objectSpread(_objectSpread({}, state), {}, {
923
- draggedFiles: draggedFiles,
924
- isDragActive: isDragActive
948
+ isDragActive: action.isDragActive,
949
+ isDragAccept: action.isDragAccept,
950
+ isDragReject: action.isDragReject
925
951
  });
926
952
 
927
953
  case "setFiles":