react-dropzone 11.5.3 → 11.6.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/.eslintignore +1 -3
- package/.eslintrc +1 -1
- package/.husky/commit-msg +5 -0
- package/.husky/pre-commit +5 -0
- package/.nvmrc +1 -1
- package/README.md +77 -29
- package/dist/es/index.js +153 -121
- package/dist/es/utils/index.js +37 -1
- package/dist/index.js +16 -2
- package/examples/events/README.md +3 -1
- package/package.json +78 -75
- package/rollup.config.js +9 -6
- package/src/.eslintrc +7 -3
- package/src/index.js +172 -133
- package/src/index.spec.js +212 -0
- package/src/utils/index.js +36 -2
- package/src/utils/index.spec.js +92 -29
- package/typings/.eslintrc +28 -0
- package/tslint.json +0 -101
package/package.json
CHANGED
|
@@ -5,19 +5,21 @@
|
|
|
5
5
|
"module": "dist/es/index.js",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"scripts": {
|
|
8
|
-
"
|
|
8
|
+
"cz": "git-cz",
|
|
9
9
|
"clean": "rimraf ./dist",
|
|
10
|
-
"build": "
|
|
10
|
+
"build": "yarn clean && yarn build:umd && yarn build:es",
|
|
11
11
|
"build:umd": "cross-env NODE_ENV=es rollup -c",
|
|
12
12
|
"build:es": "cross-env BABEL_ENV=es babel ./src --out-dir ./dist/es --ignore '**/*.spec.js'",
|
|
13
13
|
"start": "styleguidist server",
|
|
14
14
|
"styleguide": "styleguidist build",
|
|
15
|
-
"test": "cross-env NODE_ENV=test
|
|
15
|
+
"test": "cross-env NODE_ENV=test yarn eslint:src && jest --coverage && yarn typescript",
|
|
16
16
|
"test:watch": "cross-env NODE_ENV=test jest --watch",
|
|
17
17
|
"eslint:src": "eslint .",
|
|
18
18
|
"commitmsg": "commitlint -e",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
19
|
+
"prepublish": "yarn build && yarn size",
|
|
20
|
+
"_postinstall": "husky install",
|
|
21
|
+
"prepublishOnly": "pinst --disable",
|
|
22
|
+
"postpublish": "pinst --enable",
|
|
21
23
|
"logo": "cd logo && sketchtool export artboards logo.sketch",
|
|
22
24
|
"imagemin": "imagemin --out-dir=logo --plugin=pngquant --plugin=svgo",
|
|
23
25
|
"size": "size-limit",
|
|
@@ -36,18 +38,22 @@
|
|
|
36
38
|
],
|
|
37
39
|
"lint-staged": {
|
|
38
40
|
"*.js": [
|
|
39
|
-
"eslint --fix"
|
|
40
|
-
"git add"
|
|
41
|
+
"eslint --fix"
|
|
41
42
|
],
|
|
42
43
|
"*.ts": [
|
|
43
|
-
"
|
|
44
|
+
"eslint ."
|
|
44
45
|
],
|
|
45
46
|
"*.{svg,png}": [
|
|
46
|
-
"imagemin"
|
|
47
|
-
"git add"
|
|
47
|
+
"imagemin"
|
|
48
48
|
]
|
|
49
49
|
},
|
|
50
|
+
"config": {
|
|
51
|
+
"commitizen": {
|
|
52
|
+
"path": "@commitlint/prompt"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
50
55
|
"jest": {
|
|
56
|
+
"testEnvironment": "jsdom",
|
|
51
57
|
"clearMocks": true,
|
|
52
58
|
"setupFilesAfterEnv": [
|
|
53
59
|
"<rootDir>/testSetup.js"
|
|
@@ -91,85 +97,82 @@
|
|
|
91
97
|
"react": ">= 16.8"
|
|
92
98
|
},
|
|
93
99
|
"dependencies": {
|
|
94
|
-
"attr-accept": "^2.2.
|
|
95
|
-
"file-selector": "^0.
|
|
96
|
-
"prop-types": "^15.
|
|
100
|
+
"attr-accept": "^2.2.2",
|
|
101
|
+
"file-selector": "^0.4.0",
|
|
102
|
+
"prop-types": "^15.8.1"
|
|
97
103
|
},
|
|
98
104
|
"devDependencies": {
|
|
99
|
-
"@babel/cli": "^7.
|
|
100
|
-
"@babel/core": "^7.
|
|
101
|
-
"@babel/
|
|
102
|
-
"@babel/plugin-
|
|
103
|
-
"@babel/plugin-proposal-
|
|
104
|
-
"@babel/plugin-proposal-
|
|
105
|
-
"@babel/plugin-proposal-
|
|
106
|
-
"@babel/plugin-proposal-
|
|
107
|
-
"@babel/plugin-proposal-
|
|
108
|
-
"@babel/plugin-
|
|
109
|
-
"@babel/
|
|
110
|
-
"@babel/preset-
|
|
111
|
-
"@babel/
|
|
112
|
-
"@
|
|
113
|
-
"@commitlint/
|
|
114
|
-
"@commitlint/
|
|
115
|
-
"@commitlint/prompt
|
|
116
|
-
"@
|
|
117
|
-
"@
|
|
118
|
-
"@
|
|
119
|
-
"@
|
|
120
|
-
"@
|
|
105
|
+
"@babel/cli": "^7.16.8",
|
|
106
|
+
"@babel/core": "^7.16.12",
|
|
107
|
+
"@babel/eslint-parser": "^7.16.5",
|
|
108
|
+
"@babel/plugin-external-helpers": "^7.16.7",
|
|
109
|
+
"@babel/plugin-proposal-do-expressions": "^7.16.7",
|
|
110
|
+
"@babel/plugin-proposal-export-default-from": "^7.16.7",
|
|
111
|
+
"@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
|
|
112
|
+
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
|
|
113
|
+
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
|
114
|
+
"@babel/plugin-proposal-pipeline-operator": "^7.16.7",
|
|
115
|
+
"@babel/plugin-transform-runtime": "^7.16.10",
|
|
116
|
+
"@babel/preset-env": "^7.16.11",
|
|
117
|
+
"@babel/preset-react": "^7.16.7",
|
|
118
|
+
"@babel/register": "^7.16.9",
|
|
119
|
+
"@commitlint/cli": "^16.1.0",
|
|
120
|
+
"@commitlint/config-angular": "^16.0.0",
|
|
121
|
+
"@commitlint/prompt": "^16.1.0",
|
|
122
|
+
"@commitlint/prompt-cli": "^16.1.0",
|
|
123
|
+
"@rollup/plugin-babel": "^5.3.0",
|
|
124
|
+
"@rollup/plugin-commonjs": "^21.0.1",
|
|
125
|
+
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
126
|
+
"@size-limit/preset-small-lib": "^7.0.5",
|
|
127
|
+
"@size-limit/webpack": "^7.0.5",
|
|
128
|
+
"@size-limit/webpack-why": "^7.0.5",
|
|
129
|
+
"@testing-library/dom": "^8.11.3",
|
|
130
|
+
"@testing-library/jest-dom": "^5.16.1",
|
|
131
|
+
"@testing-library/react": "^12.1.2",
|
|
132
|
+
"@testing-library/react-hooks": "^7.0.2",
|
|
121
133
|
"@types/react": "^17.0.0",
|
|
122
134
|
"@types/react-dom": "^17.0.0",
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"babel-
|
|
135
|
+
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
|
136
|
+
"@typescript-eslint/parser": "^5.10.1",
|
|
137
|
+
"babel-jest": "^27.4.6",
|
|
138
|
+
"babel-plugin-add-module-exports": "^1.0.4",
|
|
126
139
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
127
|
-
"commitizen": "^4.2.
|
|
128
|
-
"cross-env": "^7.0.
|
|
129
|
-
"eslint": "
|
|
130
|
-
"eslint-config-
|
|
131
|
-
"eslint-
|
|
132
|
-
"eslint-plugin-
|
|
133
|
-
"eslint-plugin-
|
|
134
|
-
"eslint-plugin-
|
|
135
|
-
"eslint-plugin-
|
|
136
|
-
"eslint-plugin-react": "
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"imagemin-
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"prettier": "
|
|
140
|
+
"commitizen": "^4.2.4",
|
|
141
|
+
"cross-env": "^7.0.3",
|
|
142
|
+
"eslint": "^8.8.0",
|
|
143
|
+
"eslint-config-prettier": "^8.3.0",
|
|
144
|
+
"eslint-plugin-import": "^2.25.4",
|
|
145
|
+
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
146
|
+
"eslint-plugin-node": "^11.1.0",
|
|
147
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
148
|
+
"eslint-plugin-react": "^7.28.0",
|
|
149
|
+
"eslint-plugin-react-hooks": "^4.3.0",
|
|
150
|
+
"husky": "^7.0.4",
|
|
151
|
+
"imagemin-cli": "^7.0.0",
|
|
152
|
+
"imagemin-pngquant": "^9.0.2",
|
|
153
|
+
"jest": "^27.4.7",
|
|
154
|
+
"lint-staged": "^12.3.2",
|
|
155
|
+
"markdownlint-cli": "^0.30.0",
|
|
156
|
+
"pinst": "^2.1.6",
|
|
157
|
+
"prettier": "^2.5.1",
|
|
145
158
|
"react": "^17.0.0",
|
|
146
159
|
"react-dom": "^17.0.0",
|
|
147
|
-
"react-styleguidist": "^11.0
|
|
160
|
+
"react-styleguidist": "^11.2.0",
|
|
148
161
|
"react-test-renderer": "^17.0.0",
|
|
149
162
|
"rimraf": "^3.0.2",
|
|
150
|
-
"rollup": "^2.
|
|
151
|
-
"rollup-plugin-
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"sinon": "^9.0.3",
|
|
156
|
-
"size-limit": "^4.5.7",
|
|
157
|
-
"style-loader": "^1.2.1",
|
|
158
|
-
"styled-components": "^5.2.0",
|
|
159
|
-
"tslint": "^6.1.3",
|
|
163
|
+
"rollup": "^2.66.1",
|
|
164
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
165
|
+
"size-limit": "^7.0.5",
|
|
166
|
+
"style-loader": "^3.3.1",
|
|
167
|
+
"styled-components": "^5.3.3",
|
|
160
168
|
"typescript": "^4.0.2",
|
|
161
|
-
"webpack": "^
|
|
169
|
+
"webpack": "^5.67.0",
|
|
162
170
|
"webpack-blocks": "^2.1.0"
|
|
163
171
|
},
|
|
164
172
|
"typings": "typings/react-dropzone.d.ts",
|
|
165
|
-
"
|
|
166
|
-
"commitizen": {
|
|
167
|
-
"path": "@commitlint/prompt"
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
"version": "11.5.3",
|
|
173
|
+
"version": "11.6.0",
|
|
171
174
|
"engines": {
|
|
172
|
-
"node": ">= 10"
|
|
175
|
+
"node": ">= 10.13"
|
|
173
176
|
},
|
|
174
177
|
"browserslist": [
|
|
175
178
|
"defaults"
|
package/rollup.config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const nodeResolve = require('rollup
|
|
2
|
-
const commonjs = require('rollup
|
|
3
|
-
const babel = require('rollup
|
|
4
|
-
const {
|
|
1
|
+
const { nodeResolve } = require('@rollup/plugin-node-resolve')
|
|
2
|
+
const commonjs = require('@rollup/plugin-commonjs')
|
|
3
|
+
const { babel } = require('@rollup/plugin-babel')
|
|
4
|
+
const { terser } = require('rollup-plugin-terser')
|
|
5
5
|
|
|
6
6
|
const umdGlobals = {
|
|
7
7
|
react: 'React',
|
|
@@ -23,8 +23,11 @@ module.exports = [
|
|
|
23
23
|
plugins: [
|
|
24
24
|
nodeResolve(),
|
|
25
25
|
commonjs({ include: '**/node_modules/**' }),
|
|
26
|
-
babel({
|
|
27
|
-
|
|
26
|
+
babel({
|
|
27
|
+
exclude: '**/node_modules/**',
|
|
28
|
+
babelHelpers: 'bundled',
|
|
29
|
+
}),
|
|
30
|
+
terser()
|
|
28
31
|
]
|
|
29
32
|
}
|
|
30
33
|
]
|
package/src/.eslintrc
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"root": true,
|
|
3
|
-
"parser": "babel-
|
|
3
|
+
"parser": "@babel/eslint-parser",
|
|
4
4
|
"parserOptions": {
|
|
5
5
|
"ecmaVersion": 2017,
|
|
6
6
|
"sourceType": "module"
|
|
@@ -23,12 +23,16 @@
|
|
|
23
23
|
"eslint:recommended",
|
|
24
24
|
"plugin:react/recommended",
|
|
25
25
|
"plugin:jsx-a11y/recommended",
|
|
26
|
-
"prettier"
|
|
27
|
-
"prettier/react"
|
|
26
|
+
"prettier"
|
|
28
27
|
],
|
|
29
28
|
"rules": {
|
|
30
29
|
"react-hooks/rules-of-hooks": 2,
|
|
31
30
|
"react/forbid-prop-types": 0,
|
|
32
31
|
"react/require-default-props": 0
|
|
32
|
+
},
|
|
33
|
+
"settings": {
|
|
34
|
+
"react": {
|
|
35
|
+
"version": "detect"
|
|
36
|
+
}
|
|
33
37
|
}
|
|
34
38
|
}
|
package/src/index.js
CHANGED
|
@@ -10,12 +10,14 @@ import React, {
|
|
|
10
10
|
useRef
|
|
11
11
|
} from 'react'
|
|
12
12
|
import PropTypes from 'prop-types'
|
|
13
|
-
import {
|
|
13
|
+
import {fromEvent} from 'file-selector'
|
|
14
14
|
import {
|
|
15
15
|
allFilesAccepted,
|
|
16
16
|
composeEventHandlers,
|
|
17
17
|
fileAccepted,
|
|
18
18
|
fileMatchSize,
|
|
19
|
+
filePickerOptionsTypes,
|
|
20
|
+
canUseFileSystemAccessAPI,
|
|
19
21
|
isEvtWithFiles,
|
|
20
22
|
isIeOrEdge,
|
|
21
23
|
isPropagationStopped,
|
|
@@ -37,13 +39,13 @@ import {
|
|
|
37
39
|
* </Dropzone>
|
|
38
40
|
* ```
|
|
39
41
|
*/
|
|
40
|
-
const Dropzone = forwardRef(({
|
|
41
|
-
const {
|
|
42
|
+
const Dropzone = forwardRef(({children, ...params}, ref) => {
|
|
43
|
+
const {open, ...props} = useDropzone(params)
|
|
42
44
|
|
|
43
|
-
useImperativeHandle(ref, () => ({
|
|
45
|
+
useImperativeHandle(ref, () => ({open}), [open])
|
|
44
46
|
|
|
45
47
|
// TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
|
|
46
|
-
return <Fragment>{children({
|
|
48
|
+
return <Fragment>{children({...props, open})}</Fragment>
|
|
47
49
|
})
|
|
48
50
|
|
|
49
51
|
Dropzone.displayName = 'Dropzone'
|
|
@@ -158,9 +160,9 @@ Dropzone.propTypes = {
|
|
|
158
160
|
*/
|
|
159
161
|
onFileDialogCancel: PropTypes.func,
|
|
160
162
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Cb for when opening the file dialog
|
|
165
|
+
*/
|
|
164
166
|
onFileDialogOpen: PropTypes.func,
|
|
165
167
|
|
|
166
168
|
/**
|
|
@@ -420,23 +422,18 @@ export function useDropzone(options = {}) {
|
|
|
420
422
|
...options
|
|
421
423
|
}
|
|
422
424
|
|
|
425
|
+
const onFileDialogOpenCb = useMemo(
|
|
426
|
+
() => typeof onFileDialogOpen === 'function' ? onFileDialogOpen : noop,
|
|
427
|
+
[onFileDialogOpen])
|
|
428
|
+
const onFileDialogCancelCb = useMemo(
|
|
429
|
+
() => typeof onFileDialogCancel === 'function' ? onFileDialogCancel : noop,
|
|
430
|
+
[onFileDialogCancel])
|
|
431
|
+
|
|
423
432
|
const rootRef = useRef(null)
|
|
424
433
|
const inputRef = useRef(null)
|
|
425
434
|
|
|
426
435
|
const [state, dispatch] = useReducer(reducer, initialState)
|
|
427
|
-
const {
|
|
428
|
-
|
|
429
|
-
// Fn for opening the file dialog programmatically
|
|
430
|
-
const openFileDialog = useCallback(() => {
|
|
431
|
-
if (inputRef.current) {
|
|
432
|
-
dispatch({ type: 'openDialog' })
|
|
433
|
-
if (typeof onFileDialogOpen === 'function') {
|
|
434
|
-
onFileDialogOpen()
|
|
435
|
-
}
|
|
436
|
-
inputRef.current.value = null
|
|
437
|
-
inputRef.current.click()
|
|
438
|
-
}
|
|
439
|
-
}, [dispatch, onFileDialogOpen])
|
|
436
|
+
const {isFocused, isFileDialogActive, draggedFiles} = state
|
|
440
437
|
|
|
441
438
|
// Update file dialog active state when the window is focused on
|
|
442
439
|
const onWindowFocus = () => {
|
|
@@ -444,65 +441,26 @@ export function useDropzone(options = {}) {
|
|
|
444
441
|
if (isFileDialogActive) {
|
|
445
442
|
setTimeout(() => {
|
|
446
443
|
if (inputRef.current) {
|
|
447
|
-
const {
|
|
444
|
+
const {files} = inputRef.current
|
|
448
445
|
|
|
449
446
|
if (!files.length) {
|
|
450
|
-
dispatch({
|
|
451
|
-
|
|
452
|
-
if (typeof onFileDialogCancel === 'function') {
|
|
453
|
-
onFileDialogCancel()
|
|
454
|
-
}
|
|
447
|
+
dispatch({type: 'closeDialog'})
|
|
448
|
+
onFileDialogCancelCb()
|
|
455
449
|
}
|
|
456
450
|
}
|
|
457
451
|
}, 300)
|
|
458
452
|
}
|
|
459
453
|
}
|
|
460
454
|
useEffect(() => {
|
|
455
|
+
if (canUseFileSystemAccessAPI()) {
|
|
456
|
+
return () => {}
|
|
457
|
+
}
|
|
458
|
+
|
|
461
459
|
window.addEventListener('focus', onWindowFocus, false)
|
|
462
460
|
return () => {
|
|
463
461
|
window.removeEventListener('focus', onWindowFocus, false)
|
|
464
462
|
}
|
|
465
|
-
}, [inputRef, isFileDialogActive,
|
|
466
|
-
|
|
467
|
-
// Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
|
|
468
|
-
const onKeyDownCb = useCallback(
|
|
469
|
-
event => {
|
|
470
|
-
// Ignore keyboard events bubbling up the DOM tree
|
|
471
|
-
if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
|
|
472
|
-
return
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (event.keyCode === 32 || event.keyCode === 13) {
|
|
476
|
-
event.preventDefault()
|
|
477
|
-
openFileDialog()
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
|
-
[rootRef, inputRef, openFileDialog]
|
|
481
|
-
)
|
|
482
|
-
|
|
483
|
-
// Update focus state for the dropzone
|
|
484
|
-
const onFocusCb = useCallback(() => {
|
|
485
|
-
dispatch({ type: 'focus' })
|
|
486
|
-
}, [])
|
|
487
|
-
const onBlurCb = useCallback(() => {
|
|
488
|
-
dispatch({ type: 'blur' })
|
|
489
|
-
}, [])
|
|
490
|
-
|
|
491
|
-
// Cb to open the file dialog when click occurs on the dropzone
|
|
492
|
-
const onClickCb = useCallback(() => {
|
|
493
|
-
if (noClick) {
|
|
494
|
-
return
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
|
|
498
|
-
// to ensure React can handle state changes
|
|
499
|
-
// See: https://github.com/react-dropzone/react-dropzone/issues/450
|
|
500
|
-
if (isIeOrEdge()) {
|
|
501
|
-
setTimeout(openFileDialog, 0)
|
|
502
|
-
} else {
|
|
503
|
-
openFileDialog()
|
|
504
|
-
}
|
|
505
|
-
}, [inputRef, noClick, openFileDialog])
|
|
463
|
+
}, [inputRef, isFileDialogActive, onFileDialogCancelCb])
|
|
506
464
|
|
|
507
465
|
const dragTargetsRef = useRef([])
|
|
508
466
|
const onDocumentDrop = event => {
|
|
@@ -614,6 +572,66 @@ export function useDropzone(options = {}) {
|
|
|
614
572
|
[rootRef, onDragLeave, noDragEventsBubbling]
|
|
615
573
|
)
|
|
616
574
|
|
|
575
|
+
const setFiles = useCallback((files, event) => {
|
|
576
|
+
const acceptedFiles = []
|
|
577
|
+
const fileRejections = []
|
|
578
|
+
|
|
579
|
+
files.forEach(file => {
|
|
580
|
+
const [accepted, acceptError] = fileAccepted(file, accept)
|
|
581
|
+
const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize)
|
|
582
|
+
const customErrors = validator ? validator(file) : null;
|
|
583
|
+
|
|
584
|
+
if (accepted && sizeMatch && !customErrors) {
|
|
585
|
+
acceptedFiles.push(file)
|
|
586
|
+
} else {
|
|
587
|
+
let errors = [acceptError, sizeError];
|
|
588
|
+
|
|
589
|
+
if (customErrors) {
|
|
590
|
+
errors = errors.concat(customErrors);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
fileRejections.push({file, errors: errors.filter(e => e)})
|
|
594
|
+
}
|
|
595
|
+
})
|
|
596
|
+
|
|
597
|
+
if ((!multiple && acceptedFiles.length > 1) || (multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles)) {
|
|
598
|
+
// Reject everything and empty accepted files
|
|
599
|
+
acceptedFiles.forEach(file => {
|
|
600
|
+
fileRejections.push({file, errors: [TOO_MANY_FILES_REJECTION]})
|
|
601
|
+
})
|
|
602
|
+
acceptedFiles.splice(0)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
dispatch({
|
|
606
|
+
acceptedFiles,
|
|
607
|
+
fileRejections,
|
|
608
|
+
type: 'setFiles'
|
|
609
|
+
})
|
|
610
|
+
|
|
611
|
+
if (onDrop) {
|
|
612
|
+
onDrop(acceptedFiles, fileRejections, event)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (fileRejections.length > 0 && onDropRejected) {
|
|
616
|
+
onDropRejected(fileRejections, event)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (acceptedFiles.length > 0 && onDropAccepted) {
|
|
620
|
+
onDropAccepted(acceptedFiles, event)
|
|
621
|
+
}
|
|
622
|
+
}, [
|
|
623
|
+
dispatch,
|
|
624
|
+
multiple,
|
|
625
|
+
accept,
|
|
626
|
+
minSize,
|
|
627
|
+
maxSize,
|
|
628
|
+
maxFiles,
|
|
629
|
+
onDrop,
|
|
630
|
+
onDropAccepted,
|
|
631
|
+
onDropRejected,
|
|
632
|
+
validator
|
|
633
|
+
]);
|
|
634
|
+
|
|
617
635
|
const onDropCb = useCallback(
|
|
618
636
|
event => {
|
|
619
637
|
event.preventDefault()
|
|
@@ -628,72 +646,91 @@ export function useDropzone(options = {}) {
|
|
|
628
646
|
if (isPropagationStopped(event) && !noDragEventsBubbling) {
|
|
629
647
|
return
|
|
630
648
|
}
|
|
631
|
-
|
|
632
|
-
const acceptedFiles = []
|
|
633
|
-
const fileRejections = []
|
|
634
|
-
|
|
635
|
-
files.forEach(file => {
|
|
636
|
-
const [accepted, acceptError] = fileAccepted(file, accept)
|
|
637
|
-
const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize)
|
|
638
|
-
const customErrors = validator ? validator(file) : null;
|
|
639
|
-
|
|
640
|
-
if (accepted && sizeMatch && !customErrors) {
|
|
641
|
-
acceptedFiles.push(file)
|
|
642
|
-
} else {
|
|
643
|
-
let errors = [acceptError, sizeError];
|
|
644
|
-
|
|
645
|
-
if (customErrors) {
|
|
646
|
-
errors = errors.concat(customErrors);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
fileRejections.push({ file, errors: errors.filter(e => e) })
|
|
650
|
-
}
|
|
651
|
-
})
|
|
652
|
-
|
|
653
|
-
if ((!multiple && acceptedFiles.length > 1) || (multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles)) {
|
|
654
|
-
// Reject everything and empty accepted files
|
|
655
|
-
acceptedFiles.forEach(file => {
|
|
656
|
-
fileRejections.push({ file, errors: [TOO_MANY_FILES_REJECTION] })
|
|
657
|
-
})
|
|
658
|
-
acceptedFiles.splice(0)
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
dispatch({
|
|
662
|
-
acceptedFiles,
|
|
663
|
-
fileRejections,
|
|
664
|
-
type: 'setFiles'
|
|
665
|
-
})
|
|
666
|
-
|
|
667
|
-
if (onDrop) {
|
|
668
|
-
onDrop(acceptedFiles, fileRejections, event)
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
if (fileRejections.length > 0 && onDropRejected) {
|
|
672
|
-
onDropRejected(fileRejections, event)
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
if (acceptedFiles.length > 0 && onDropAccepted) {
|
|
676
|
-
onDropAccepted(acceptedFiles, event)
|
|
677
|
-
}
|
|
649
|
+
setFiles(files, event)
|
|
678
650
|
})
|
|
679
651
|
}
|
|
680
|
-
dispatch({
|
|
652
|
+
dispatch({type: 'reset'})
|
|
681
653
|
},
|
|
682
654
|
[
|
|
683
|
-
multiple,
|
|
684
|
-
accept,
|
|
685
|
-
minSize,
|
|
686
|
-
maxSize,
|
|
687
|
-
maxFiles,
|
|
688
655
|
getFilesFromEvent,
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
onDropRejected,
|
|
692
|
-
noDragEventsBubbling,
|
|
693
|
-
validator
|
|
656
|
+
setFiles,
|
|
657
|
+
noDragEventsBubbling
|
|
694
658
|
]
|
|
695
659
|
)
|
|
696
660
|
|
|
661
|
+
// Fn for opening the file dialog programmatically
|
|
662
|
+
const openFileDialog = useCallback(() => {
|
|
663
|
+
if (canUseFileSystemAccessAPI()) {
|
|
664
|
+
dispatch({type: 'openDialog'})
|
|
665
|
+
onFileDialogOpenCb()
|
|
666
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
|
|
667
|
+
const opts = {
|
|
668
|
+
multiple,
|
|
669
|
+
types: filePickerOptionsTypes(accept)
|
|
670
|
+
};
|
|
671
|
+
window.showOpenFilePicker(opts)
|
|
672
|
+
.then(handles => getFilesFromEvent(handles))
|
|
673
|
+
.then(files => setFiles(files, null))
|
|
674
|
+
.catch(e => onFileDialogCancelCb(e))
|
|
675
|
+
.finally(() => dispatch({type: 'closeDialog'}));
|
|
676
|
+
return
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (inputRef.current) {
|
|
680
|
+
dispatch({type: 'openDialog'})
|
|
681
|
+
onFileDialogOpenCb()
|
|
682
|
+
inputRef.current.value = null
|
|
683
|
+
inputRef.current.click()
|
|
684
|
+
}
|
|
685
|
+
}, [
|
|
686
|
+
dispatch,
|
|
687
|
+
onFileDialogOpenCb,
|
|
688
|
+
onFileDialogCancelCb,
|
|
689
|
+
setFiles,
|
|
690
|
+
accept,
|
|
691
|
+
multiple
|
|
692
|
+
])
|
|
693
|
+
|
|
694
|
+
// Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
|
|
695
|
+
const onKeyDownCb = useCallback(
|
|
696
|
+
event => {
|
|
697
|
+
// Ignore keyboard events bubbling up the DOM tree
|
|
698
|
+
if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
|
|
699
|
+
return
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
if (event.keyCode === 32 || event.keyCode === 13) {
|
|
703
|
+
event.preventDefault()
|
|
704
|
+
openFileDialog()
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
[rootRef, inputRef, openFileDialog]
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
// Update focus state for the dropzone
|
|
711
|
+
const onFocusCb = useCallback(() => {
|
|
712
|
+
dispatch({type: 'focus'})
|
|
713
|
+
}, [])
|
|
714
|
+
const onBlurCb = useCallback(() => {
|
|
715
|
+
dispatch({type: 'blur'})
|
|
716
|
+
}, [])
|
|
717
|
+
|
|
718
|
+
// Cb to open the file dialog when click occurs on the dropzone
|
|
719
|
+
const onClickCb = useCallback(() => {
|
|
720
|
+
if (noClick) {
|
|
721
|
+
return
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
|
|
725
|
+
// to ensure React can handle state changes
|
|
726
|
+
// See: https://github.com/react-dropzone/react-dropzone/issues/450
|
|
727
|
+
if (isIeOrEdge()) {
|
|
728
|
+
setTimeout(openFileDialog, 0)
|
|
729
|
+
} else {
|
|
730
|
+
openFileDialog()
|
|
731
|
+
}
|
|
732
|
+
}, [inputRef, noClick, openFileDialog])
|
|
733
|
+
|
|
697
734
|
const composeHandler = fn => {
|
|
698
735
|
return disabled ? null : fn
|
|
699
736
|
}
|
|
@@ -734,7 +771,7 @@ export function useDropzone(options = {}) {
|
|
|
734
771
|
onDragLeave: composeDragHandler(composeEventHandlers(onDragLeave, onDragLeaveCb)),
|
|
735
772
|
onDrop: composeDragHandler(composeEventHandlers(onDrop, onDropCb)),
|
|
736
773
|
[refKey]: rootRef,
|
|
737
|
-
...(!disabled && !noKeyboard ? {
|
|
774
|
+
...(!disabled && !noKeyboard ? {tabIndex: 0} : {}),
|
|
738
775
|
...rest
|
|
739
776
|
}),
|
|
740
777
|
[
|
|
@@ -758,12 +795,12 @@ export function useDropzone(options = {}) {
|
|
|
758
795
|
}, [])
|
|
759
796
|
|
|
760
797
|
const getInputProps = useMemo(
|
|
761
|
-
() => ({
|
|
798
|
+
() => ({refKey = 'ref', onChange, onClick, ...rest} = {}) => {
|
|
762
799
|
const inputProps = {
|
|
763
800
|
accept,
|
|
764
801
|
multiple,
|
|
765
802
|
type: 'file',
|
|
766
|
-
style: {
|
|
803
|
+
style: {display: 'none'},
|
|
767
804
|
onChange: composeHandler(composeEventHandlers(onChange, onDropCb)),
|
|
768
805
|
onClick: composeHandler(composeEventHandlers(onClick, onInputElementClick)),
|
|
769
806
|
autoComplete: 'off',
|
|
@@ -780,7 +817,7 @@ export function useDropzone(options = {}) {
|
|
|
780
817
|
)
|
|
781
818
|
|
|
782
819
|
const fileCount = draggedFiles.length
|
|
783
|
-
const isDragAccept = fileCount > 0 && allFilesAccepted({
|
|
820
|
+
const isDragAccept = fileCount > 0 && allFilesAccepted({files: draggedFiles, accept, minSize, maxSize, multiple, maxFiles})
|
|
784
821
|
const isDragReject = fileCount > 0 && !isDragAccept
|
|
785
822
|
|
|
786
823
|
return {
|
|
@@ -811,7 +848,7 @@ function reducer(state, action) {
|
|
|
811
848
|
}
|
|
812
849
|
case 'openDialog':
|
|
813
850
|
return {
|
|
814
|
-
...
|
|
851
|
+
...initialState,
|
|
815
852
|
isFileDialogActive: true
|
|
816
853
|
}
|
|
817
854
|
case 'closeDialog':
|
|
@@ -821,7 +858,7 @@ function reducer(state, action) {
|
|
|
821
858
|
}
|
|
822
859
|
case 'setDraggedFiles':
|
|
823
860
|
/* eslint no-case-declarations: 0 */
|
|
824
|
-
const {
|
|
861
|
+
const {isDragActive, draggedFiles} = action
|
|
825
862
|
return {
|
|
826
863
|
...state,
|
|
827
864
|
draggedFiles,
|
|
@@ -842,4 +879,6 @@ function reducer(state, action) {
|
|
|
842
879
|
}
|
|
843
880
|
}
|
|
844
881
|
|
|
845
|
-
|
|
882
|
+
function noop() {}
|
|
883
|
+
|
|
884
|
+
export {ErrorCode} from './utils'
|