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/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.9",
168
+ "version": "10.2.2",
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,6 +4,7 @@ import React, {
4
4
  Fragment,
5
5
  useCallback,
6
6
  useEffect,
7
+ useImperativeHandle,
7
8
  useMemo,
8
9
  useReducer,
9
10
  useRef
@@ -38,21 +39,7 @@ import {
38
39
  const Dropzone = forwardRef(({ children, ...params }, ref) => {
39
40
  const { open, ...props } = useDropzone(params)
40
41
 
41
- useEffect(() => {
42
- if (typeof ref === 'function') {
43
- ref({ open })
44
- } else if (typeof ref === 'object' && ref !== null) {
45
- ref.current = { open }
46
- }
47
-
48
- return () => {
49
- if (typeof ref === 'function') {
50
- ref(null)
51
- } else if (typeof ref === 'object' && ref !== null) {
52
- ref.current = null
53
- }
54
- }
55
- }, [ref])
42
+ useImperativeHandle(ref, () => ({ open }), [open])
56
43
 
57
44
  // TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
58
45
  return <Fragment>{children({ ...props, open })}</Fragment>
@@ -394,13 +381,13 @@ export function useDropzone({
394
381
  const { isFocused, isFileDialogActive, draggedFiles } = state
395
382
 
396
383
  // Fn for opening the file dialog programmatically
397
- const openFileDialog = () => {
384
+ const openFileDialog = useCallback(() => {
398
385
  if (inputRef.current) {
399
386
  dispatch({ type: 'openDialog' })
400
387
  inputRef.current.value = null
401
388
  inputRef.current.click()
402
389
  }
403
- }
390
+ }, [dispatch])
404
391
 
405
392
  // Update file dialog active state when the window is focused on
406
393
  const onWindowFocus = () => {
@@ -582,7 +569,6 @@ export function useDropzone({
582
569
  stopPropagation(event)
583
570
 
584
571
  dragTargetsRef.current = []
585
- dispatch({ type: 'reset' })
586
572
 
587
573
  if (isEvtWithFiles(event)) {
588
574
  Promise.resolve(getFilesFromEvent(event)).then(files => {
@@ -594,7 +580,7 @@ export function useDropzone({
594
580
  const rejectedFiles = []
595
581
 
596
582
  files.forEach(file => {
597
- if (fileAccepted(file, accept) && fileMatchSize(file, maxSize, minSize)) {
583
+ if (fileAccepted(file, accept) && fileMatchSize(file, minSize, maxSize)) {
598
584
  acceptedFiles.push(file)
599
585
  } else {
600
586
  rejectedFiles.push(file)
@@ -624,6 +610,7 @@ export function useDropzone({
624
610
  }
625
611
  })
626
612
  }
613
+ dispatch({ type: 'reset' })
627
614
  },
628
615
  [
629
616
  multiple,
@@ -724,9 +711,8 @@ export function useDropzone({
724
711
  )
725
712
 
726
713
  const fileCount = draggedFiles.length
727
- const isMultipleAllowed = multiple || fileCount <= 1
728
- const isDragAccept = fileCount > 0 && allFilesAccepted(draggedFiles, accept)
729
- const isDragReject = fileCount > 0 && (!isDragAccept || !isMultipleAllowed)
714
+ const isDragAccept = fileCount > 0 && allFilesAccepted({ files: draggedFiles, accept, minSize, maxSize, multiple })
715
+ const isDragReject = fileCount > 0 && !isDragAccept
730
716
 
731
717
  return {
732
718
  ...state,
@@ -783,7 +769,9 @@ function reducer(state, action) {
783
769
  ...state,
784
770
  isFileDialogActive: false,
785
771
  isDragActive: false,
786
- draggedFiles: []
772
+ draggedFiles: [],
773
+ acceptedFiles: [],
774
+ rejectedFiles: [],
787
775
  }
788
776
  default:
789
777
  return state
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,7 +1726,30 @@ describe('useDropzone() hook', () => {
1726
1726
  expect(dropzone).toHaveTextContent('dragReject')
1727
1727
  })
1728
1728
 
1729
- it('sets {isDragActive, isDragAccept, isDragReject} if all files are accepted and {multiple} is false on dragenter', async () => {
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
+
1752
+ it('sets {isDragActive, isDragAccept, isDragReject} if any files are rejected and {multiple} is false on dragenter', async () => {
1730
1753
  const ui = (
1731
1754
  <Dropzone accept="image/*" multiple={false}>
1732
1755
  {({ getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject }) => (
@@ -1747,7 +1770,7 @@ describe('useDropzone() hook', () => {
1747
1770
  await flushPromises(ui, container)
1748
1771
 
1749
1772
  expect(dropzone).toHaveTextContent('dragActive')
1750
- expect(dropzone).toHaveTextContent('dragAccept')
1773
+ expect(dropzone).not.toHaveTextContent('dragAccept')
1751
1774
  expect(dropzone).toHaveTextContent('dragReject')
1752
1775
  })
1753
1776
 
@@ -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,30 @@ 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, multiple }) {
26
+ if (!multiple && files.length > 1) {
27
+ return false;
28
+ }
29
+
30
+ return files.every(file => {
31
+ return fileAccepted(file, accept) && fileMatchSize(file, minSize, maxSize)
32
+ })
15
33
  }
16
34
 
17
35
  // 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+$/