react-dropzone 10.1.9 → 10.2.2

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/.eslintignore CHANGED
@@ -1,4 +1,5 @@
1
1
  dist/
2
2
  coverage/
3
3
  typings/*
4
+ styleguide/*
4
5
  !.babelrc.js
package/.eslintrc CHANGED
@@ -1,5 +1,25 @@
1
1
  {
2
- "extends": ["okonet/node"],
2
+ "parser": "babel-eslint",
3
+ "parserOptions": {
4
+ "ecmaVersion": 2017,
5
+ "sourceType": "module"
6
+ },
7
+ "env": {
8
+ "es6": true,
9
+ "node": true,
10
+ "jest": true
11
+ },
12
+ "plugins": [
13
+ "import",
14
+ "node",
15
+ "prettier"
16
+ ],
17
+ "extends": [
18
+ // TODO: Fix this so we can use
19
+ // "okonet/node"
20
+ "eslint:recommended",
21
+ "prettier"
22
+ ],
3
23
  "rules": {
4
24
  "strict": 0,
5
25
  "node/no-unpublished-require": 0,
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # react-dropzone
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/react-dropzone.svg?style=flat-square)](https://www.npmjs.com/package/react-dropzone)
6
- [![Build Status](https://img.shields.io/travis/react-dropzone/react-dropzone/master.svg?style=flat-square)](https://travis-ci.org/react-dropzone/react-dropzone)
6
+ ![Build Status](https://github.com/react-dropzone/react-dropzone/workflows/Test/badge.svg)
7
7
  [![codecov](https://img.shields.io/codecov/c/gh/react-dropzone/react-dropzone/master.svg?style=flat-square)](https://codecov.io/gh/react-dropzone/react-dropzone)
8
8
  [![Open Collective](https://img.shields.io/opencollective/backers/react-dropzone.svg?style=flat-square)](#backers)
9
9
  [![Open Collective](https://img.shields.io/opencollective/sponsors/react-dropzone.svg?style=flat-square)](#sponsors)
@@ -81,20 +81,22 @@ import React, {useCallback} from 'react'
81
81
  import {useDropzone} from 'react-dropzone'
82
82
 
83
83
  function MyDropzone() {
84
- const onDrop = useCallback(acceptedFiles => {
85
- const reader = new FileReader()
84
+ const onDrop = useCallback((acceptedFiles) => {
85
+ acceptedFiles.forEach((file) => {
86
+ const reader = new FileReader()
86
87
 
87
- reader.onabort = () => console.log('file reading was aborted')
88
- reader.onerror = () => console.log('file reading has failed')
89
- reader.onload = () => {
88
+ reader.onabort = () => console.log('file reading was aborted')
89
+ reader.onerror = () => console.log('file reading has failed')
90
+ reader.onload = () => {
90
91
  // Do whatever you want with the file contents
91
- const binaryStr = reader.result
92
- console.log(binaryStr)
93
- }
94
-
95
- acceptedFiles.forEach(file => reader.readAsBinaryString(file))
92
+ const binaryStr = reader.result
93
+ console.log(binaryStr)
94
+ }
95
+ reader.readAsArrayBuffer(file)
96
+ })
97
+
96
98
  }, [])
97
- const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
99
+ const {getRootProps, getInputProps} = useDropzone({onDrop})
98
100
 
99
101
  return (
100
102
  <div {...getRootProps()}>
package/dist/es/index.js CHANGED
@@ -10,22 +10,22 @@ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArra
10
10
 
11
11
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
12
12
 
13
- function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
13
+ function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
14
14
 
15
15
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
16
16
 
17
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
17
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
18
18
 
19
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
19
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
20
20
 
21
- function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
21
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
22
22
 
23
23
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
24
24
 
25
25
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
26
26
 
27
27
  /* eslint prefer-template: 0 */
28
- import React, { forwardRef, Fragment, useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
28
+ import React, { forwardRef, Fragment, useCallback, useEffect, useImperativeHandle, useMemo, useReducer, useRef } from 'react';
29
29
  import PropTypes from 'prop-types';
30
30
  import { fromEvent } from 'file-selector';
31
31
  import { allFilesAccepted, composeEventHandlers, fileAccepted, fileMatchSize, isEvtWithFiles, isIeOrEdge, isPropagationStopped, onDocumentDragOver } from './utils/index';
@@ -52,25 +52,11 @@ var Dropzone = forwardRef(function (_ref, ref) {
52
52
  open = _useDropzone.open,
53
53
  props = _objectWithoutProperties(_useDropzone, ["open"]);
54
54
 
55
- useEffect(function () {
56
- if (typeof ref === 'function') {
57
- ref({
58
- open: open
59
- });
60
- } else if (_typeof(ref) === 'object' && ref !== null) {
61
- ref.current = {
62
- open: open
63
- };
64
- }
65
-
66
- return function () {
67
- if (typeof ref === 'function') {
68
- ref(null);
69
- } else if (_typeof(ref) === 'object' && ref !== null) {
70
- ref.current = null;
71
- }
55
+ useImperativeHandle(ref, function () {
56
+ return {
57
+ open: open
72
58
  };
73
- }, [ref]); // TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
59
+ }, [open]); // TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
74
60
 
75
61
  return React.createElement(Fragment, null, children(_objectSpread({}, props, {
76
62
  open: open
@@ -309,80 +295,80 @@ var initialState = {
309
295
  draggedFiles: [],
310
296
  acceptedFiles: [],
311
297
  rejectedFiles: []
312
- /**
313
- * A React hook that creates a drag 'n' drop area.
314
- *
315
- * ```jsx
316
- * function MyDropzone(props) {
317
- * const {getRootProps, getInputProps} = useDropzone({
318
- * onDrop: acceptedFiles => {
319
- * // do something with the File objects, e.g. upload to some server
320
- * }
321
- * });
322
- * return (
323
- * <div {...getRootProps()}>
324
- * <input {...getInputProps()} />
325
- * <p>Drag and drop some files here, or click to select files</p>
326
- * </div>
327
- * )
328
- * }
329
- * ```
330
- *
331
- * @function useDropzone
332
- *
333
- * @param {object} props
334
- * @param {string|string[]} [props.accept] Set accepted file types.
335
- * See https://github.com/okonet/attr-accept for more information.
336
- * Keep in mind that mime type determination is not reliable across platforms. CSV files,
337
- * for example, are reported as text/plain under macOS but as application/vnd.ms-excel under
338
- * Windows. In some cases there might not be a mime type set at all.
339
- * See: https://github.com/react-dropzone/react-dropzone/issues/276
340
- * @param {boolean} [props.multiple=true] Allow drag 'n' drop (or selection from the file dialog) of multiple files
341
- * @param {boolean} [props.preventDropOnDocument=true] If false, allow dropped items to take over the current browser window
342
- * @param {boolean} [props.noClick=false] If true, disables click to open the native file selection dialog
343
- * @param {boolean} [props.noKeyboard=false] If true, disables SPACE/ENTER to open the native file selection dialog.
344
- * Note that it also stops tracking the focus state.
345
- * @param {boolean} [props.noDrag=false] If true, disables drag 'n' drop
346
- * @param {boolean} [props.noDragEventsBubbling=false] If true, stops drag event propagation to parents
347
- * @param {number} [props.minSize=0] Minimum file size (in bytes)
348
- * @param {number} [props.maxSize=Infinity] Maximum file size (in bytes)
349
- * @param {boolean} [props.disabled=false] Enable/disable the dropzone
350
- * @param {getFilesFromEvent} [props.getFilesFromEvent] Use this to provide a custom file aggregator
351
- * @param {Function} [props.onFileDialogCancel] Cb for when closing the file dialog with no selection
352
- * @param {dragCb} [props.onDragEnter] Cb for when the `dragenter` event occurs.
353
- * @param {dragCb} [props.onDragLeave] Cb for when the `dragleave` event occurs
354
- * @param {dragCb} [props.onDragOver] Cb for when the `dragover` event occurs
355
- * @param {dropCb} [props.onDrop] Cb for when the `drop` event occurs.
356
- * Note that this callback is invoked after the `getFilesFromEvent` callback is done.
357
- *
358
- * Files are accepted or rejected based on the `accept`, `multiple`, `minSize` and `maxSize` props.
359
- * `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.
360
- * If `multiple` is set to false and additional files are droppped,
361
- * all files besides the first will be rejected.
362
- * Any file which does not have a size in the [`minSize`, `maxSize`] range, will be rejected as well.
363
- *
364
- * Note that the `onDrop` callback will always be invoked regardless if the dropped files were accepted or rejected.
365
- * If you'd like to react to a specific scenario, use the `onDropAccepted`/`onDropRejected` props.
366
- *
367
- * `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.
368
- * For example, with [SuperAgent](https://github.com/visionmedia/superagent) as a http/ajax library:
369
- *
370
- * ```js
371
- * function onDrop(acceptedFiles) {
372
- * const req = request.post('/upload')
373
- * acceptedFiles.forEach(file => {
374
- * req.attach(file.name, file)
375
- * })
376
- * req.end(callback)
377
- * }
378
- * ```
379
- * @param {dropAcceptedCb} [props.onDropAccepted]
380
- * @param {dropRejectedCb} [props.onDropRejected]
381
- *
382
- * @returns {DropzoneState}
383
- */
384
-
385
298
  };
299
+ /**
300
+ * A React hook that creates a drag 'n' drop area.
301
+ *
302
+ * ```jsx
303
+ * function MyDropzone(props) {
304
+ * const {getRootProps, getInputProps} = useDropzone({
305
+ * onDrop: acceptedFiles => {
306
+ * // do something with the File objects, e.g. upload to some server
307
+ * }
308
+ * });
309
+ * return (
310
+ * <div {...getRootProps()}>
311
+ * <input {...getInputProps()} />
312
+ * <p>Drag and drop some files here, or click to select files</p>
313
+ * </div>
314
+ * )
315
+ * }
316
+ * ```
317
+ *
318
+ * @function useDropzone
319
+ *
320
+ * @param {object} props
321
+ * @param {string|string[]} [props.accept] Set accepted file types.
322
+ * See https://github.com/okonet/attr-accept for more information.
323
+ * Keep in mind that mime type determination is not reliable across platforms. CSV files,
324
+ * for example, are reported as text/plain under macOS but as application/vnd.ms-excel under
325
+ * Windows. In some cases there might not be a mime type set at all.
326
+ * See: https://github.com/react-dropzone/react-dropzone/issues/276
327
+ * @param {boolean} [props.multiple=true] Allow drag 'n' drop (or selection from the file dialog) of multiple files
328
+ * @param {boolean} [props.preventDropOnDocument=true] If false, allow dropped items to take over the current browser window
329
+ * @param {boolean} [props.noClick=false] If true, disables click to open the native file selection dialog
330
+ * @param {boolean} [props.noKeyboard=false] If true, disables SPACE/ENTER to open the native file selection dialog.
331
+ * Note that it also stops tracking the focus state.
332
+ * @param {boolean} [props.noDrag=false] If true, disables drag 'n' drop
333
+ * @param {boolean} [props.noDragEventsBubbling=false] If true, stops drag event propagation to parents
334
+ * @param {number} [props.minSize=0] Minimum file size (in bytes)
335
+ * @param {number} [props.maxSize=Infinity] Maximum file size (in bytes)
336
+ * @param {boolean} [props.disabled=false] Enable/disable the dropzone
337
+ * @param {getFilesFromEvent} [props.getFilesFromEvent] Use this to provide a custom file aggregator
338
+ * @param {Function} [props.onFileDialogCancel] Cb for when closing the file dialog with no selection
339
+ * @param {dragCb} [props.onDragEnter] Cb for when the `dragenter` event occurs.
340
+ * @param {dragCb} [props.onDragLeave] Cb for when the `dragleave` event occurs
341
+ * @param {dragCb} [props.onDragOver] Cb for when the `dragover` event occurs
342
+ * @param {dropCb} [props.onDrop] Cb for when the `drop` event occurs.
343
+ * Note that this callback is invoked after the `getFilesFromEvent` callback is done.
344
+ *
345
+ * Files are accepted or rejected based on the `accept`, `multiple`, `minSize` and `maxSize` props.
346
+ * `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.
347
+ * If `multiple` is set to false and additional files are droppped,
348
+ * all files besides the first will be rejected.
349
+ * Any file which does not have a size in the [`minSize`, `maxSize`] range, will be rejected as well.
350
+ *
351
+ * Note that the `onDrop` callback will always be invoked regardless if the dropped files were accepted or rejected.
352
+ * If you'd like to react to a specific scenario, use the `onDropAccepted`/`onDropRejected` props.
353
+ *
354
+ * `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.
355
+ * For example, with [SuperAgent](https://github.com/visionmedia/superagent) as a http/ajax library:
356
+ *
357
+ * ```js
358
+ * function onDrop(acceptedFiles) {
359
+ * const req = request.post('/upload')
360
+ * acceptedFiles.forEach(file => {
361
+ * req.attach(file.name, file)
362
+ * })
363
+ * req.end(callback)
364
+ * }
365
+ * ```
366
+ * @param {dropAcceptedCb} [props.onDropAccepted]
367
+ * @param {dropRejectedCb} [props.onDropRejected]
368
+ *
369
+ * @returns {DropzoneState}
370
+ */
371
+
386
372
  export function useDropzone() {
387
373
  var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
388
374
  accept = _ref2.accept,
@@ -426,7 +412,7 @@ export function useDropzone() {
426
412
  isFileDialogActive = state.isFileDialogActive,
427
413
  draggedFiles = state.draggedFiles; // Fn for opening the file dialog programmatically
428
414
 
429
- var openFileDialog = function openFileDialog() {
415
+ var openFileDialog = useCallback(function () {
430
416
  if (inputRef.current) {
431
417
  dispatch({
432
418
  type: 'openDialog'
@@ -434,8 +420,7 @@ export function useDropzone() {
434
420
  inputRef.current.value = null;
435
421
  inputRef.current.click();
436
422
  }
437
- }; // Update file dialog active state when the window is focused on
438
-
423
+ }, [dispatch]); // Update file dialog active state when the window is focused on
439
424
 
440
425
  var onWindowFocus = function onWindowFocus() {
441
426
  // Execute the timeout only if the file dialog is opened in the browser
@@ -604,9 +589,6 @@ export function useDropzone() {
604
589
  event.persist();
605
590
  stopPropagation(event);
606
591
  dragTargetsRef.current = [];
607
- dispatch({
608
- type: 'reset'
609
- });
610
592
 
611
593
  if (isEvtWithFiles(event)) {
612
594
  Promise.resolve(getFilesFromEvent(event)).then(function (files) {
@@ -617,7 +599,7 @@ export function useDropzone() {
617
599
  var acceptedFiles = [];
618
600
  var rejectedFiles = [];
619
601
  files.forEach(function (file) {
620
- if (fileAccepted(file, accept) && fileMatchSize(file, maxSize, minSize)) {
602
+ if (fileAccepted(file, accept) && fileMatchSize(file, minSize, maxSize)) {
621
603
  acceptedFiles.push(file);
622
604
  } else {
623
605
  rejectedFiles.push(file);
@@ -647,6 +629,10 @@ export function useDropzone() {
647
629
  }
648
630
  });
649
631
  }
632
+
633
+ dispatch({
634
+ type: 'reset'
635
+ });
650
636
  }, [multiple, accept, minSize, maxSize, getFilesFromEvent, onDrop, onDropAccepted, onDropRejected, noDragEventsBubbling]);
651
637
 
652
638
  var composeHandler = function composeHandler(fn) {
@@ -693,7 +679,7 @@ export function useDropzone() {
693
679
  onDrop: composeDragHandler(composeEventHandlers(onDrop, onDropCb))
694
680
  }, refKey, rootRef), !disabled && !noKeyboard ? {
695
681
  tabIndex: 0
696
- } : {}, rest);
682
+ } : {}, {}, rest);
697
683
  };
698
684
  }, [rootRef, onKeyDownCb, onFocusCb, onBlurCb, onClickCb, onDragEnterCb, onDragOverCb, onDragLeaveCb, onDropCb, noKeyboard, noDrag, disabled]);
699
685
  var onInputElementClick = useCallback(function (event) {
@@ -721,13 +707,18 @@ export function useDropzone() {
721
707
  tabIndex: -1
722
708
  }, refKey, inputRef);
723
709
 
724
- return _objectSpread({}, inputProps, rest);
710
+ return _objectSpread({}, inputProps, {}, rest);
725
711
  };
726
712
  }, [inputRef, accept, multiple, onDropCb, disabled]);
727
713
  var fileCount = draggedFiles.length;
728
- var isMultipleAllowed = multiple || fileCount <= 1;
729
- var isDragAccept = fileCount > 0 && allFilesAccepted(draggedFiles, accept);
730
- var isDragReject = fileCount > 0 && (!isDragAccept || !isMultipleAllowed);
714
+ var isDragAccept = fileCount > 0 && allFilesAccepted({
715
+ files: draggedFiles,
716
+ accept: accept,
717
+ minSize: minSize,
718
+ maxSize: maxSize,
719
+ multiple: multiple
720
+ });
721
+ var isDragReject = fileCount > 0 && !isDragAccept;
731
722
  return _objectSpread({}, state, {
732
723
  isDragAccept: isDragAccept,
733
724
  isDragReject: isDragReject,
@@ -782,7 +773,9 @@ function reducer(state, action) {
782
773
  return _objectSpread({}, state, {
783
774
  isFileDialogActive: false,
784
775
  isDragActive: false,
785
- draggedFiles: []
776
+ draggedFiles: [],
777
+ acceptedFiles: [],
778
+ rejectedFiles: []
786
779
  });
787
780
 
788
781
  default:
@@ -6,12 +6,31 @@ import accepts from 'attr-accept'; // Firefox versions prior to 53 return a bogu
6
6
  export function fileAccepted(file, accept) {
7
7
  return file.type === 'application/x-moz-file' || accepts(file, accept);
8
8
  }
9
- export function fileMatchSize(file, maxSize, minSize) {
10
- return file.size <= maxSize && file.size >= minSize;
9
+ export function fileMatchSize(file, minSize, maxSize) {
10
+ if (isDefined(file.size)) {
11
+ if (isDefined(minSize) && isDefined(maxSize)) return file.size >= minSize && file.size <= maxSize;else if (isDefined(minSize)) return file.size >= minSize;else if (isDefined(maxSize)) return file.size <= maxSize;
12
+ }
13
+
14
+ return true;
15
+ }
16
+
17
+ function isDefined(value) {
18
+ return value !== undefined && value !== null;
11
19
  }
12
- export function allFilesAccepted(files, accept) {
20
+
21
+ export function allFilesAccepted(_ref) {
22
+ var files = _ref.files,
23
+ accept = _ref.accept,
24
+ minSize = _ref.minSize,
25
+ maxSize = _ref.maxSize,
26
+ multiple = _ref.multiple;
27
+
28
+ if (!multiple && files.length > 1) {
29
+ return false;
30
+ }
31
+
13
32
  return files.every(function (file) {
14
- return fileAccepted(file, accept);
33
+ return fileAccepted(file, accept) && fileMatchSize(file, minSize, maxSize);
15
34
  });
16
35
  } // React's synthetic events has event.isPropagationStopped,
17
36
  // but to remain compatibility with other libs (Preact) fall back