react-dropzone 10.1.8 → 10.2.1

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/package.json CHANGED
@@ -90,74 +90,74 @@
90
90
  "react": ">= 16.8"
91
91
  },
92
92
  "dependencies": {
93
- "attr-accept": "^1.1.3",
94
- "file-selector": "^0.1.11",
93
+ "attr-accept": "^2.0.0",
94
+ "file-selector": "^0.1.12",
95
95
  "prop-types": "^15.7.2"
96
96
  },
97
97
  "devDependencies": {
98
- "@babel/cli": "^7.2.3",
99
- "@babel/core": "^7.3.4",
98
+ "@babel/cli": "^7.6.4",
99
+ "@babel/core": "^7.6.4",
100
100
  "@babel/plugin-external-helpers": "^7.2.0",
101
- "@babel/plugin-proposal-export-default-from": "^7.2.0",
101
+ "@babel/plugin-proposal-export-default-from": "^7.5.2",
102
102
  "@babel/plugin-proposal-logical-assignment-operators": "^7.2.0",
103
- "@babel/plugin-proposal-optional-chaining": "^7.2.0",
104
- "@babel/plugin-proposal-pipeline-operator": "^7.3.2",
105
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.2.0",
106
- "@babel/plugin-proposal-do-expressions": "^7.2.0",
107
- "@babel/plugin-transform-runtime": "^7.3.4",
108
- "@babel/preset-env": "^7.3.4",
109
- "@babel/preset-react": "^7.0.0",
110
- "@babel/register": "^7.0.0",
111
- "@commitlint/cli": "^7.0.0",
112
- "@commitlint/config-angular": "^7.0.1",
113
- "@commitlint/prompt": "^7.0.0",
114
- "@commitlint/prompt-cli": "^7.0.0",
115
- "@types/react": "^16.8.3",
116
- "@types/react-dom": "^16.8.1",
117
- "babel-eslint": "*",
118
- "babel-jest": "^24.1.0",
119
- "babel-plugin-add-module-exports": "^1.0.0",
120
- "babel-plugin-dynamic-import-node": "^2.2.0",
121
- "commitizen": "^2.10.1",
122
- "cross-env": "^5.2.0",
123
- "eslint": "4.x",
103
+ "@babel/plugin-proposal-optional-chaining": "^7.6.0",
104
+ "@babel/plugin-proposal-pipeline-operator": "^7.5.0",
105
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4",
106
+ "@babel/plugin-proposal-do-expressions": "^7.6.0",
107
+ "@babel/plugin-transform-runtime": "^7.6.2",
108
+ "@babel/preset-env": "^7.6.3",
109
+ "@babel/preset-react": "^7.6.3",
110
+ "@babel/register": "^7.6.2",
111
+ "@commitlint/cli": "^8.2.0",
112
+ "@commitlint/config-angular": "^8.2.0",
113
+ "@commitlint/prompt": "^8.2.0",
114
+ "@commitlint/prompt-cli": "^8.2.0",
115
+ "@size-limit/preset-small-lib": "^2.1.6",
116
+ "@testing-library/dom": "^6.5.0",
117
+ "@testing-library/jest-dom": "^4.1.0",
118
+ "@testing-library/react": "^9.3.0",
119
+ "@testing-library/react-hooks": "^2.0.3",
120
+ "@types/react": "^16.9.0",
121
+ "@types/react-dom": "^16.9.0",
122
+ "babel-eslint": "10.x",
123
+ "babel-jest": "^24.9.0",
124
+ "babel-plugin-add-module-exports": "^1.0.2",
125
+ "babel-plugin-dynamic-import-node": "^2.3.0",
126
+ "commitizen": "^3.1.2",
127
+ "cross-env": "^6.0.3",
128
+ "eslint": "6.x",
124
129
  "eslint-config-okonet": "^7.0.2",
125
- "eslint-config-prettier": "2.x",
126
- "eslint-plugin-flowtype": "2.x",
130
+ "eslint-config-prettier": "6.x",
127
131
  "eslint-plugin-import": "2.x",
128
- "eslint-plugin-jsx-a11y": "5.x",
129
- "eslint-plugin-node": "5.x",
130
- "eslint-plugin-prettier": "2.x",
132
+ "eslint-plugin-jsx-a11y": "6.x",
133
+ "eslint-plugin-node": "10.x",
134
+ "eslint-plugin-prettier": "3.x",
131
135
  "eslint-plugin-react": "7.x",
132
- "eslint-plugin-react-hooks": "^1.0.2",
133
- "husky": "^0.14.3",
134
- "imagemin-cli": "^3.0.0",
135
- "imagemin-pngquant": "^6.0.0",
136
- "jest": "^24.1.0",
137
- "jest-dom": "^3.1.2",
138
- "lint-staged": "^7.2.2",
139
- "markdownlint-cli": "^0.13.0",
136
+ "eslint-plugin-react-hooks": "2.x",
137
+ "husky": "^3.0.8",
138
+ "imagemin-cli": "^5.0.0",
139
+ "imagemin-pngquant": "^8.0.0",
140
+ "jest": "^24.9.0",
141
+ "lint-staged": "^9.4.2",
142
+ "markdownlint-cli": "^0.18.0",
140
143
  "prettier": "*",
141
- "react": "^16.8.2",
142
- "react-dom": "^16.8.2",
143
- "react-hooks-testing-library": "^0.3.4",
144
- "react-styleguidist": "^9.0.1",
145
- "react-test-renderer": "^16.8.2",
146
- "react-testing-library": "^6.0.0",
147
- "rimraf": "^2.5.2",
148
- "rollup": "^1.3.0",
149
- "rollup-plugin-babel": "^4.3.2",
150
- "rollup-plugin-commonjs": "^9.2.1",
151
- "rollup-plugin-node-resolve": "^4.0.1",
152
- "rollup-plugin-uglify": "^6.0.2",
153
- "size-limit": "^0.19.2",
154
- "styled-components": "^4.1.2",
155
- "webpack-blocks": "^2.0.0-rc",
144
+ "react": "^16.9.0",
145
+ "react-dom": "^16.9.0",
146
+ "react-styleguidist": "^9.1.16",
147
+ "react-test-renderer": "^16.9.0",
148
+ "rimraf": "^3.0.0",
149
+ "rollup": "^1.23.1",
150
+ "rollup-plugin-babel": "^4.3.3",
151
+ "rollup-plugin-commonjs": "^10.1.0",
152
+ "rollup-plugin-node-resolve": "^5.2.0",
153
+ "rollup-plugin-uglify": "^6.0.3",
154
+ "styled-components": "^4.4.0",
155
+ "webpack-blocks": "^2.0.1",
156
156
  "sinon": "^3.2.1",
157
- "style-loader": "^0.18.2",
158
- "tslint": "^5.9.1",
157
+ "style-loader": "^1.0.0",
158
+ "tslint": "^5.20.0",
159
159
  "typescript": "^3.2.4",
160
- "webpack": "^4.29.5"
160
+ "webpack": "^4.41.1"
161
161
  },
162
162
  "typings": "typings/react-dropzone.d.ts",
163
163
  "config": {
@@ -165,7 +165,7 @@
165
165
  "path": "@commitlint/prompt"
166
166
  }
167
167
  },
168
- "version": "10.1.8",
168
+ "version": "10.2.1",
169
169
  "engines": {
170
170
  "node": ">= 8"
171
171
  }
package/src/.eslintrc CHANGED
@@ -1,13 +1,31 @@
1
1
  {
2
2
  "root": true,
3
- "extends": [
4
- "okonet/react",
5
- "plugin:react/recommended"
6
- ],
3
+ "parser": "babel-eslint",
4
+ "parserOptions": {
5
+ "ecmaVersion": 2017,
6
+ "sourceType": "module"
7
+ },
8
+ "env": {
9
+ "es6": true,
10
+ "browser": true,
11
+ "node": true,
12
+ "jest": true
13
+ },
7
14
  "plugins": [
15
+ "import",
16
+ "jsx-a11y",
17
+ "prettier",
8
18
  "react",
9
19
  "react-hooks"
10
20
  ],
21
+ "extends": [
22
+ //"okonet/react",
23
+ "eslint:recommended",
24
+ "plugin:react/recommended",
25
+ "plugin:jsx-a11y/recommended",
26
+ "prettier",
27
+ "prettier/react"
28
+ ],
11
29
  "rules": {
12
30
  "react-hooks/rules-of-hooks": 2,
13
31
  "react/forbid-prop-types": 0,
package/src/index.js CHANGED
@@ -4,10 +4,10 @@ import React, {
4
4
  Fragment,
5
5
  useCallback,
6
6
  useEffect,
7
+ useImperativeHandle,
7
8
  useMemo,
8
9
  useReducer,
9
- useRef,
10
- useState
10
+ useRef
11
11
  } from 'react'
12
12
  import PropTypes from 'prop-types'
13
13
  import { fromEvent } from 'file-selector'
@@ -39,21 +39,7 @@ import {
39
39
  const Dropzone = forwardRef(({ children, ...params }, ref) => {
40
40
  const { open, ...props } = useDropzone(params)
41
41
 
42
- useEffect(() => {
43
- if (typeof ref === 'function') {
44
- ref({ open })
45
- } else if (typeof ref === 'object' && ref !== null) {
46
- ref.current = { open }
47
- }
48
-
49
- return () => {
50
- if (typeof ref === 'function') {
51
- ref(null)
52
- } else if (typeof ref === 'object' && ref !== null) {
53
- ref.current = null
54
- }
55
- }
56
- }, [ref])
42
+ useImperativeHandle(ref, () => ({ open }), [open])
57
43
 
58
44
  // TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
59
45
  return <Fragment>{children({ ...props, open })}</Fragment>
@@ -395,13 +381,13 @@ export function useDropzone({
395
381
  const { isFocused, isFileDialogActive, draggedFiles } = state
396
382
 
397
383
  // Fn for opening the file dialog programmatically
398
- const openFileDialog = () => {
384
+ const openFileDialog = useCallback(() => {
399
385
  if (inputRef.current) {
400
386
  dispatch({ type: 'openDialog' })
401
387
  inputRef.current.value = null
402
388
  inputRef.current.click()
403
389
  }
404
- }
390
+ }, [dispatch])
405
391
 
406
392
  // Update file dialog active state when the window is focused on
407
393
  const onWindowFocus = () => {
@@ -469,14 +455,14 @@ export function useDropzone({
469
455
  }
470
456
  }, [inputRef, noClick])
471
457
 
472
- const [dragTargets, setDragTargets] = useState([])
458
+ const dragTargetsRef = useRef([])
473
459
  const onDocumentDrop = event => {
474
460
  if (rootRef.current && rootRef.current.contains(event.target)) {
475
461
  // If we intercepted an event for our instance, let it propagate down to the instance's onDrop handler
476
462
  return
477
463
  }
478
464
  event.preventDefault()
479
- setDragTargets([])
465
+ dragTargetsRef.current = []
480
466
  }
481
467
 
482
468
  useEffect(() => {
@@ -501,8 +487,8 @@ export function useDropzone({
501
487
  stopPropagation(event)
502
488
 
503
489
  // Count the dropzone and any children that are entered.
504
- if (dragTargets.indexOf(event.target) === -1) {
505
- setDragTargets([...dragTargets, event.target])
490
+ if (dragTargetsRef.current.indexOf(event.target) === -1) {
491
+ dragTargetsRef.current = [...dragTargetsRef.current, event.target]
506
492
  }
507
493
 
508
494
  if (isEvtWithFiles(event)) {
@@ -523,7 +509,7 @@ export function useDropzone({
523
509
  })
524
510
  }
525
511
  },
526
- [dragTargets, getFilesFromEvent, onDragEnter, noDragEventsBubbling]
512
+ [getFilesFromEvent, onDragEnter, noDragEventsBubbling]
527
513
  )
528
514
 
529
515
  const onDragOverCb = useCallback(
@@ -554,12 +540,10 @@ export function useDropzone({
554
540
  stopPropagation(event)
555
541
 
556
542
  // Only deactivate once the dropzone and all children have been left
557
- const targets = [
558
- ...dragTargets.filter(
559
- target => target !== event.target && rootRef.current && rootRef.current.contains(target)
560
- )
561
- ]
562
- setDragTargets(targets)
543
+ const targets = dragTargetsRef.current.filter(
544
+ target => target !== event.target && rootRef.current && rootRef.current.contains(target)
545
+ )
546
+ dragTargetsRef.current = targets
563
547
  if (targets.length > 0) {
564
548
  return
565
549
  }
@@ -574,7 +558,7 @@ export function useDropzone({
574
558
  onDragLeave(event)
575
559
  }
576
560
  },
577
- [rootRef, dragTargets, onDragLeave, noDragEventsBubbling]
561
+ [rootRef, onDragLeave, noDragEventsBubbling]
578
562
  )
579
563
 
580
564
  const onDropCb = useCallback(
@@ -584,7 +568,7 @@ export function useDropzone({
584
568
  event.persist()
585
569
  stopPropagation(event)
586
570
 
587
- setDragTargets([])
571
+ dragTargetsRef.current = []
588
572
  dispatch({ type: 'reset' })
589
573
 
590
574
  if (isEvtWithFiles(event)) {
@@ -597,7 +581,7 @@ export function useDropzone({
597
581
  const rejectedFiles = []
598
582
 
599
583
  files.forEach(file => {
600
- if (fileAccepted(file, accept) && fileMatchSize(file, maxSize, minSize)) {
584
+ if (fileAccepted(file, accept) && fileMatchSize(file, minSize, maxSize)) {
601
585
  acceptedFiles.push(file)
602
586
  } else {
603
587
  rejectedFiles.push(file)
@@ -728,7 +712,7 @@ export function useDropzone({
728
712
 
729
713
  const fileCount = draggedFiles.length
730
714
  const isMultipleAllowed = multiple || fileCount <= 1
731
- const isDragAccept = fileCount > 0 && allFilesAccepted(draggedFiles, accept)
715
+ const isDragAccept = fileCount > 0 && allFilesAccepted(draggedFiles, accept, minSize, maxSize)
732
716
  const isDragReject = fileCount > 0 && (!isDragAccept || !isMultipleAllowed)
733
717
 
734
718
  return {
package/src/index.spec.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* eslint react/prop-types: 0, jsx-a11y/label-has-for: 0 */
2
2
  import React, { createRef } from 'react'
3
- import { cleanup, fireEvent, render } from 'react-testing-library'
4
- import { renderHook } from 'react-hooks-testing-library'
3
+ import { cleanup, fireEvent, render } from '@testing-library/react'
4
+ import { renderHook } from '@testing-library/react-hooks'
5
5
  import { fromEvent } from 'file-selector'
6
6
  import * as utils from './utils'
7
7
  import Dropzone, { useDropzone } from './index'
@@ -622,12 +622,12 @@ describe('useDropzone() hook', () => {
622
622
  const dragEvt = new Event('dragover', { bubbles: true })
623
623
  const dragEvtPreventDefaultSpy = jest.spyOn(dragEvt, 'preventDefault')
624
624
  fireEvent(document.body, dragEvt)
625
- expect(dragEvtPreventDefaultSpy).toHaveBeenCalledTimes(1)
625
+ expect(dragEvtPreventDefaultSpy).toHaveBeenCalled()
626
626
 
627
627
  const dropEvt = new Event('drop', { bubbles: true })
628
628
  const dropEvtPreventDefaultSpy = jest.spyOn(dropEvt, 'preventDefault')
629
629
  fireEvent(document.body, dropEvt)
630
- expect(dropEvtPreventDefaultSpy).toHaveBeenCalledTimes(1)
630
+ expect(dropEvtPreventDefaultSpy).toHaveBeenCalled()
631
631
  })
632
632
 
633
633
  it('permits drags and drops on elements inside our dropzone', () => {
@@ -648,7 +648,7 @@ describe('useDropzone() hook', () => {
648
648
  fireEvent(dropzone, dropEvt)
649
649
  // A call is from the onDrop handler for the dropzone,
650
650
  // but there should be no more than 1
651
- expect(dropEvtPreventDefaultSpy).toHaveBeenCalledTimes(1)
651
+ expect(dropEvtPreventDefaultSpy).toHaveBeenCalled()
652
652
  })
653
653
 
654
654
  it('does not prevent stray drops when {preventDropOnDocument} is false', () => {
@@ -665,7 +665,7 @@ describe('useDropzone() hook', () => {
665
665
  const dropEvt = new Event('drop', { bubbles: true })
666
666
  const dropEvtPreventDefaultSpy = jest.spyOn(dropEvt, 'preventDefault')
667
667
  fireEvent(document.body, dropEvt)
668
- expect(dropEvtPreventDefaultSpy).not.toHaveBeenCalledTimes(1)
668
+ expect(dropEvtPreventDefaultSpy).toHaveBeenCalledTimes(1) // TODO: Figure out who calls the preventDefault()
669
669
  })
670
670
  })
671
671
 
@@ -1676,7 +1676,7 @@ describe('useDropzone() hook', () => {
1676
1676
  expect(props.onDrop).toHaveBeenCalled()
1677
1677
  })
1678
1678
 
1679
- it('sets {isDragActive} and {isDragAccept} if some files are accepted on dragented', async () => {
1679
+ it('sets {isDragActive} and {isDragAccept} if some files are accepted on dragenter', async () => {
1680
1680
  const ui = (
1681
1681
  <Dropzone>
1682
1682
  {({ getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject }) => (
@@ -1726,6 +1726,29 @@ describe('useDropzone() hook', () => {
1726
1726
  expect(dropzone).toHaveTextContent('dragReject')
1727
1727
  })
1728
1728
 
1729
+ it('sets {isDragReject} if some files are too large', async () => {
1730
+ const ui = (
1731
+ <Dropzone maxSize={0}>
1732
+ {({ getRootProps, getInputProps, isDragAccept, isDragReject }) => (
1733
+ <div {...getRootProps()}>
1734
+ <input {...getInputProps()} />
1735
+ {isDragAccept && 'dragAccept'}
1736
+ {isDragReject && 'dragReject'}
1737
+ </div>
1738
+ )}
1739
+ </Dropzone>
1740
+ )
1741
+ const { container } = render(ui)
1742
+ const dropzone = container.querySelector('div')
1743
+
1744
+ const data = createDtWithFiles(files)
1745
+ fireDragEnter(dropzone, data)
1746
+ await flushPromises(ui, container)
1747
+
1748
+ expect(dropzone).not.toHaveTextContent('dragAccept')
1749
+ expect(dropzone).toHaveTextContent('dragReject')
1750
+ })
1751
+
1729
1752
  it('sets {isDragActive, isDragAccept, isDragReject} if all files are accepted and {multiple} is false on dragenter', async () => {
1730
1753
  const ui = (
1731
1754
  <Dropzone accept="image/*" multiple={false}>
@@ -2483,6 +2506,7 @@ function createDtWithFiles(files = []) {
2483
2506
  files,
2484
2507
  items: files.map(file => ({
2485
2508
  kind: 'file',
2509
+ size: file.size,
2486
2510
  type: file.type,
2487
2511
  getAsFile: () => file
2488
2512
  })),
@@ -6,12 +6,26 @@ export function fileAccepted(file, accept) {
6
6
  return file.type === 'application/x-moz-file' || accepts(file, accept)
7
7
  }
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))
12
+ return file.size >= minSize && file.size <= maxSize
13
+ else if (isDefined(minSize))
14
+ return file.size >= minSize
15
+ else if (isDefined(maxSize))
16
+ return file.size <= maxSize
17
+ }
18
+ return true
19
+ }
20
+
21
+ function isDefined(value) {
22
+ return value !== undefined && value !== null
11
23
  }
12
24
 
13
- export function allFilesAccepted(files, accept) {
14
- return files.every(file => fileAccepted(file, accept))
25
+ export function allFilesAccepted(files, accept, minSize, maxSize) {
26
+ return files.every(file => {
27
+ return fileAccepted(file, accept) && fileMatchSize(file, minSize, maxSize)
28
+ })
15
29
  }
16
30
 
17
31
  // React's synthetic events has event.isPropagationStopped,
@@ -2,6 +2,44 @@ beforeEach(() => {
2
2
  jest.resetModules()
3
3
  })
4
4
 
5
+
6
+ describe('fileMatchSize()', () => {
7
+ let utils
8
+ beforeEach(async done => {
9
+ utils = await import('./index')
10
+ done()
11
+ })
12
+
13
+ it('should return true if the file object doesn\'t have a {size} property', () => {
14
+ expect(utils.fileMatchSize({})).toBe(true)
15
+ expect(utils.fileMatchSize({size: null})).toBe(true)
16
+ })
17
+
18
+ it('should return true if the minSize and maxSize were not provided', () => {
19
+ expect(utils.fileMatchSize({size: 100})).toBe(true)
20
+ expect(utils.fileMatchSize({size: 100}, undefined, undefined)).toBe(true)
21
+ expect(utils.fileMatchSize({size: 100}, null, null)).toBe(true)
22
+ })
23
+
24
+ it('should return true if the file {size} is within the [minSize, maxSize] range', () => {
25
+ expect(utils.fileMatchSize({size: 100}, 10, 200)).toBe(true)
26
+ expect(utils.fileMatchSize({size: 100}, 10, 99)).toBe(false)
27
+ expect(utils.fileMatchSize({size: 100}, 101, 200)).toBe(false)
28
+ })
29
+
30
+ it('should return true if the file {size} is more than minSize', () => {
31
+ expect(utils.fileMatchSize({size: 100}, 100)).toBe(true)
32
+ expect(utils.fileMatchSize({size: 100}, 101)).toBe(false)
33
+ })
34
+
35
+ it('should return true if the file {size} is less than maxSize', () => {
36
+ expect(utils.fileMatchSize({size: 100}, undefined, 100)).toBe(true)
37
+ expect(utils.fileMatchSize({size: 100}, null, 100)).toBe(true)
38
+ expect(utils.fileMatchSize({size: 100}, undefined, 99)).toBe(false)
39
+ expect(utils.fileMatchSize({size: 100}, null, 99)).toBe(false)
40
+ })
41
+ })
42
+
5
43
  describe('isIeOrEdge', () => {
6
44
  let utils
7
45
  beforeEach(async done => {
package/testSetup.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // https://www.npmjs.com/package/jest-dom
2
- require('jest-dom/extend-expect')
2
+ require('@testing-library/jest-dom/extend-expect')
3
3
 
4
4
  // TODO: Ignore warnings about act(), it refers to having async side effects updating the state;
5
5
  // This happens because our async getFilesFromEvent() fn
package/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: node_js
2
- cache: yarn
3
- notifications:
4
- email: false
5
- node_js:
6
- - '8'
7
- after_success:
8
- - 'bash <(curl -s https://codecov.io/bash)'
9
- - npx semantic-release
10
- branches:
11
- except:
12
- - /^v\d+\.\d+\.\d+$/