react-dropzone 4.0.0 → 4.1.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/.babelrc +1 -1
- package/.eslintrc +6 -4
- package/.travis.yml +1 -3
- package/README.md +33 -6
- package/dist/index.js +938 -844
- package/dist/index.js.map +1 -1
- package/examples/Basic/Readme.md +42 -0
- package/package.json +27 -25
- package/src/__snapshots__/index.spec.js.snap +3 -3
- package/src/index.js +90 -67
- package/src/index.spec.js +146 -37
- package/src/utils/index.js +43 -0
- package/src/{getDataTransferItems.spec.js → utils/index.spec.js} +8 -8
- package/src/utils/styles.js +23 -0
- package/webpack.config.js +2 -5
- package/yarn.lock +2382 -1403
- package/src/getDataTransferItems.js +0 -17
package/src/index.js
CHANGED
|
@@ -2,39 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import PropTypes from 'prop-types'
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// that MIME type will always be accepted
|
|
15
|
-
return file.type === 'application/x-moz-file' || accepts(file, accept)
|
|
16
|
-
}
|
|
5
|
+
import {
|
|
6
|
+
supportMultiple,
|
|
7
|
+
fileAccepted,
|
|
8
|
+
allFilesAccepted,
|
|
9
|
+
fileMatchSize,
|
|
10
|
+
onDocumentDragOver,
|
|
11
|
+
getDataTransferItems
|
|
12
|
+
} from './utils'
|
|
13
|
+
import styles from './utils/styles'
|
|
17
14
|
|
|
18
15
|
class Dropzone extends React.Component {
|
|
19
|
-
static onDocumentDragOver(evt) {
|
|
20
|
-
// allow the entire document to be a drag target
|
|
21
|
-
evt.preventDefault()
|
|
22
|
-
}
|
|
23
|
-
|
|
24
16
|
constructor(props, context) {
|
|
25
17
|
super(props, context)
|
|
18
|
+
this.composeHandlers = this.composeHandlers.bind(this)
|
|
26
19
|
this.onClick = this.onClick.bind(this)
|
|
27
20
|
this.onDocumentDrop = this.onDocumentDrop.bind(this)
|
|
28
|
-
this.onDragStart = this.onDragStart.bind(this)
|
|
29
21
|
this.onDragEnter = this.onDragEnter.bind(this)
|
|
30
22
|
this.onDragLeave = this.onDragLeave.bind(this)
|
|
31
23
|
this.onDragOver = this.onDragOver.bind(this)
|
|
24
|
+
this.onDragStart = this.onDragStart.bind(this)
|
|
32
25
|
this.onDrop = this.onDrop.bind(this)
|
|
33
26
|
this.onFileDialogCancel = this.onFileDialogCancel.bind(this)
|
|
27
|
+
this.onInputElementClick = this.onInputElementClick.bind(this)
|
|
28
|
+
|
|
34
29
|
this.setRef = this.setRef.bind(this)
|
|
35
30
|
this.setRefs = this.setRefs.bind(this)
|
|
36
|
-
|
|
31
|
+
|
|
37
32
|
this.isFileDialogActive = false
|
|
33
|
+
|
|
38
34
|
this.state = {
|
|
39
35
|
draggedFiles: [],
|
|
40
36
|
acceptedFiles: [],
|
|
@@ -47,7 +43,7 @@ class Dropzone extends React.Component {
|
|
|
47
43
|
this.dragTargets = []
|
|
48
44
|
|
|
49
45
|
if (preventDropOnDocument) {
|
|
50
|
-
document.addEventListener('dragover',
|
|
46
|
+
document.addEventListener('dragover', onDocumentDragOver, false)
|
|
51
47
|
document.addEventListener('drop', this.onDocumentDrop, false)
|
|
52
48
|
}
|
|
53
49
|
this.fileInputEl.addEventListener('click', this.onInputElementClick, false)
|
|
@@ -58,7 +54,7 @@ class Dropzone extends React.Component {
|
|
|
58
54
|
componentWillUnmount() {
|
|
59
55
|
const { preventDropOnDocument } = this.props
|
|
60
56
|
if (preventDropOnDocument) {
|
|
61
|
-
document.removeEventListener('dragover',
|
|
57
|
+
document.removeEventListener('dragover', onDocumentDragOver)
|
|
62
58
|
document.removeEventListener('drop', this.onDocumentDrop)
|
|
63
59
|
}
|
|
64
60
|
this.fileInputEl.removeEventListener('click', this.onInputElementClick, false)
|
|
@@ -66,6 +62,14 @@ class Dropzone extends React.Component {
|
|
|
66
62
|
document.body.onfocus = null
|
|
67
63
|
}
|
|
68
64
|
|
|
65
|
+
composeHandlers(handler) {
|
|
66
|
+
if (this.props.disabled) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return handler
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
onDocumentDrop(evt) {
|
|
70
74
|
if (this.node.contains(evt.target)) {
|
|
71
75
|
// if we intercepted an event for our instance, let it propagate down to the instance's onDrop handler
|
|
@@ -159,7 +163,10 @@ class Dropzone extends React.Component {
|
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
if (
|
|
166
|
+
if (
|
|
167
|
+
fileAccepted(file, accept) &&
|
|
168
|
+
fileMatchSize(file, this.props.maxSize, this.props.minSize)
|
|
169
|
+
) {
|
|
163
170
|
acceptedFiles.push(file)
|
|
164
171
|
} else {
|
|
165
172
|
rejectedFiles.push(file)
|
|
@@ -207,7 +214,7 @@ class Dropzone extends React.Component {
|
|
|
207
214
|
|
|
208
215
|
// in IE11/Edge the file-browser dialog is blocking, ensure this is behind setTimeout
|
|
209
216
|
// this is so react can handle state changes in the onClick prop above above
|
|
210
|
-
// see: https://github.com/
|
|
217
|
+
// see: https://github.com/react-dropzone/react-dropzone/issues/450
|
|
211
218
|
setTimeout(this.open.bind(this), 0)
|
|
212
219
|
}
|
|
213
220
|
}
|
|
@@ -245,15 +252,6 @@ class Dropzone extends React.Component {
|
|
|
245
252
|
setRefs(ref) {
|
|
246
253
|
this.fileInputEl = ref
|
|
247
254
|
}
|
|
248
|
-
|
|
249
|
-
fileMatchSize(file) {
|
|
250
|
-
return file.size <= this.props.maxSize && file.size >= this.props.minSize
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
allFilesAccepted(files) {
|
|
254
|
-
return files.every(file => fileAccepted(file, this.props.accept))
|
|
255
|
-
}
|
|
256
|
-
|
|
257
255
|
/**
|
|
258
256
|
* Open system file upload dialog.
|
|
259
257
|
*
|
|
@@ -267,7 +265,12 @@ class Dropzone extends React.Component {
|
|
|
267
265
|
|
|
268
266
|
renderChildren = (children, isDragActive, isDragAccept, isDragReject) => {
|
|
269
267
|
if (typeof children === 'function') {
|
|
270
|
-
return children({
|
|
268
|
+
return children({
|
|
269
|
+
...this.state,
|
|
270
|
+
isDragActive,
|
|
271
|
+
isDragAccept,
|
|
272
|
+
isDragReject
|
|
273
|
+
})
|
|
271
274
|
}
|
|
272
275
|
return children
|
|
273
276
|
}
|
|
@@ -277,11 +280,13 @@ class Dropzone extends React.Component {
|
|
|
277
280
|
accept,
|
|
278
281
|
acceptClassName,
|
|
279
282
|
activeClassName,
|
|
283
|
+
children,
|
|
284
|
+
disabled,
|
|
285
|
+
disabledClassName,
|
|
280
286
|
inputProps,
|
|
281
287
|
multiple,
|
|
282
288
|
name,
|
|
283
289
|
rejectClassName,
|
|
284
|
-
children,
|
|
285
290
|
...rest
|
|
286
291
|
} = this.props
|
|
287
292
|
|
|
@@ -289,6 +294,7 @@ class Dropzone extends React.Component {
|
|
|
289
294
|
acceptStyle,
|
|
290
295
|
activeStyle,
|
|
291
296
|
className,
|
|
297
|
+
disabledStyle,
|
|
292
298
|
rejectStyle,
|
|
293
299
|
style,
|
|
294
300
|
...props // eslint-disable-line prefer-const
|
|
@@ -297,9 +303,11 @@ class Dropzone extends React.Component {
|
|
|
297
303
|
const { isDragActive, draggedFiles } = this.state
|
|
298
304
|
const filesCount = draggedFiles.length
|
|
299
305
|
const isMultipleAllowed = multiple || filesCount <= 1
|
|
300
|
-
const isDragAccept = filesCount > 0 &&
|
|
306
|
+
const isDragAccept = filesCount > 0 && allFilesAccepted(draggedFiles, this.props.accept)
|
|
301
307
|
const isDragReject = filesCount > 0 && (!isDragAccept || !isMultipleAllowed)
|
|
302
308
|
className = className || ''
|
|
309
|
+
const noStyles =
|
|
310
|
+
!className && !style && !activeStyle && !acceptStyle && !rejectStyle && !disabledStyle
|
|
303
311
|
|
|
304
312
|
if (isDragActive && activeClassName) {
|
|
305
313
|
className += ' ' + activeClassName
|
|
@@ -310,27 +318,16 @@ class Dropzone extends React.Component {
|
|
|
310
318
|
if (isDragReject && rejectClassName) {
|
|
311
319
|
className += ' ' + rejectClassName
|
|
312
320
|
}
|
|
321
|
+
if (disabled && disabledClassName) {
|
|
322
|
+
className += ' ' + disabledClassName
|
|
323
|
+
}
|
|
313
324
|
|
|
314
|
-
if (
|
|
315
|
-
style =
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
borderStyle: 'dashed',
|
|
321
|
-
borderRadius: 5
|
|
322
|
-
}
|
|
323
|
-
activeStyle = {
|
|
324
|
-
borderStyle: 'solid',
|
|
325
|
-
borderColor: '#6c6',
|
|
326
|
-
backgroundColor: '#eee'
|
|
327
|
-
}
|
|
328
|
-
acceptStyle = activeStyle
|
|
329
|
-
rejectStyle = {
|
|
330
|
-
borderStyle: 'solid',
|
|
331
|
-
borderColor: '#c66',
|
|
332
|
-
backgroundColor: '#eee'
|
|
333
|
-
}
|
|
325
|
+
if (noStyles) {
|
|
326
|
+
style = styles.default
|
|
327
|
+
activeStyle = styles.active
|
|
328
|
+
acceptStyle = style.active
|
|
329
|
+
rejectStyle = styles.rejected
|
|
330
|
+
disabledStyle = styles.disabled
|
|
334
331
|
}
|
|
335
332
|
|
|
336
333
|
let appliedStyle = { ...style }
|
|
@@ -345,20 +342,29 @@ class Dropzone extends React.Component {
|
|
|
345
342
|
...appliedStyle,
|
|
346
343
|
...acceptStyle
|
|
347
344
|
}
|
|
348
|
-
}
|
|
345
|
+
}
|
|
346
|
+
if (rejectStyle && isDragReject) {
|
|
349
347
|
appliedStyle = {
|
|
350
348
|
...appliedStyle,
|
|
351
349
|
...rejectStyle
|
|
352
350
|
}
|
|
353
351
|
}
|
|
352
|
+
if (disabledStyle && disabled) {
|
|
353
|
+
appliedStyle = {
|
|
354
|
+
...style,
|
|
355
|
+
...disabledStyle
|
|
356
|
+
}
|
|
357
|
+
}
|
|
354
358
|
|
|
355
359
|
const inputAttributes = {
|
|
356
360
|
accept,
|
|
361
|
+
disabled,
|
|
357
362
|
type: 'file',
|
|
358
363
|
style: { display: 'none' },
|
|
359
364
|
multiple: supportMultiple && multiple,
|
|
360
365
|
ref: this.setRefs,
|
|
361
|
-
onChange: this.onDrop
|
|
366
|
+
onChange: this.onDrop,
|
|
367
|
+
autoComplete: 'off'
|
|
362
368
|
}
|
|
363
369
|
|
|
364
370
|
if (name && name.length) {
|
|
@@ -385,13 +391,14 @@ class Dropzone extends React.Component {
|
|
|
385
391
|
className={className}
|
|
386
392
|
style={appliedStyle}
|
|
387
393
|
{...divProps /* expand user provided props first so event handlers are never overridden */}
|
|
388
|
-
onClick={this.onClick}
|
|
389
|
-
onDragStart={this.onDragStart}
|
|
390
|
-
onDragEnter={this.onDragEnter}
|
|
391
|
-
onDragOver={this.onDragOver}
|
|
392
|
-
onDragLeave={this.onDragLeave}
|
|
393
|
-
onDrop={this.onDrop}
|
|
394
|
+
onClick={this.composeHandlers(this.onClick)}
|
|
395
|
+
onDragStart={this.composeHandlers(this.onDragStart)}
|
|
396
|
+
onDragEnter={this.composeHandlers(this.onDragEnter)}
|
|
397
|
+
onDragOver={this.composeHandlers(this.onDragOver)}
|
|
398
|
+
onDragLeave={this.composeHandlers(this.onDragLeave)}
|
|
399
|
+
onDrop={this.composeHandlers(this.onDrop)}
|
|
394
400
|
ref={this.setRef}
|
|
401
|
+
aria-disabled={disabled}
|
|
395
402
|
>
|
|
396
403
|
{this.renderChildren(children, isDragActive, isDragAccept, isDragReject)}
|
|
397
404
|
<input
|
|
@@ -403,13 +410,15 @@ class Dropzone extends React.Component {
|
|
|
403
410
|
}
|
|
404
411
|
}
|
|
405
412
|
|
|
413
|
+
export default Dropzone
|
|
414
|
+
|
|
406
415
|
Dropzone.propTypes = {
|
|
407
416
|
/**
|
|
408
417
|
* Allow specific types of files. See https://github.com/okonet/attr-accept for more information.
|
|
409
|
-
* Keep in mind that mime type determination is not reliable
|
|
418
|
+
* Keep in mind that mime type determination is not reliable across platforms. CSV files,
|
|
410
419
|
* for example, are reported as text/plain under macOS but as application/vnd.ms-excel under
|
|
411
420
|
* Windows. In some cases there might not be a mime type set at all.
|
|
412
|
-
* See: https://github.com/
|
|
421
|
+
* See: https://github.com/react-dropzone/react-dropzone/issues/276
|
|
413
422
|
*/
|
|
414
423
|
accept: PropTypes.string,
|
|
415
424
|
|
|
@@ -423,6 +432,11 @@ Dropzone.propTypes = {
|
|
|
423
432
|
*/
|
|
424
433
|
disableClick: PropTypes.bool,
|
|
425
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Enable/disable the dropzone entirely
|
|
437
|
+
*/
|
|
438
|
+
disabled: PropTypes.bool,
|
|
439
|
+
|
|
426
440
|
/**
|
|
427
441
|
* Enable/disable preview generation
|
|
428
442
|
*/
|
|
@@ -478,6 +492,11 @@ Dropzone.propTypes = {
|
|
|
478
492
|
*/
|
|
479
493
|
rejectClassName: PropTypes.string,
|
|
480
494
|
|
|
495
|
+
/**
|
|
496
|
+
* className for disabled state
|
|
497
|
+
*/
|
|
498
|
+
disabledClassName: PropTypes.string,
|
|
499
|
+
|
|
481
500
|
/**
|
|
482
501
|
* CSS styles to apply
|
|
483
502
|
*/
|
|
@@ -498,6 +517,11 @@ Dropzone.propTypes = {
|
|
|
498
517
|
*/
|
|
499
518
|
rejectStyle: PropTypes.object,
|
|
500
519
|
|
|
520
|
+
/**
|
|
521
|
+
* CSS styles to apply when dropzone is disabled
|
|
522
|
+
*/
|
|
523
|
+
disabledStyle: PropTypes.object,
|
|
524
|
+
|
|
501
525
|
/**
|
|
502
526
|
* onClick callback
|
|
503
527
|
* @param {Event} event
|
|
@@ -547,11 +571,10 @@ Dropzone.propTypes = {
|
|
|
547
571
|
|
|
548
572
|
Dropzone.defaultProps = {
|
|
549
573
|
preventDropOnDocument: true,
|
|
574
|
+
disabled: false,
|
|
550
575
|
disablePreview: false,
|
|
551
576
|
disableClick: false,
|
|
552
577
|
multiple: true,
|
|
553
578
|
maxSize: Infinity,
|
|
554
579
|
minSize: 0
|
|
555
580
|
}
|
|
556
|
-
|
|
557
|
-
export default Dropzone
|
package/src/index.spec.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { mount, render } from 'enzyme'
|
|
3
3
|
import { spy, stub } from 'sinon'
|
|
4
|
+
import { onDocumentDragOver } from './utils'
|
|
4
5
|
|
|
5
6
|
const Dropzone = require(process.env.NODE_ENV === 'production' ? '../dist/index' : './index') // eslint-disable-line import/no-dynamic-require
|
|
6
7
|
const DummyChildComponent = () => null
|
|
@@ -8,6 +9,19 @@ const DummyChildComponent = () => null
|
|
|
8
9
|
let files
|
|
9
10
|
let images
|
|
10
11
|
|
|
12
|
+
const rejectColor = 'red'
|
|
13
|
+
const acceptColor = 'green'
|
|
14
|
+
|
|
15
|
+
const rejectStyle = {
|
|
16
|
+
color: rejectColor,
|
|
17
|
+
borderColor: 'black'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const acceptStyle = {
|
|
21
|
+
color: acceptColor,
|
|
22
|
+
borderWidth: '5px'
|
|
23
|
+
}
|
|
24
|
+
|
|
11
25
|
describe('Dropzone', () => {
|
|
12
26
|
beforeEach(() => {
|
|
13
27
|
files = [
|
|
@@ -85,16 +99,8 @@ describe('Dropzone', () => {
|
|
|
85
99
|
|
|
86
100
|
it('should render children function', () => {
|
|
87
101
|
const content = <p>some content</p>
|
|
88
|
-
const dropzone = mount(
|
|
89
|
-
|
|
90
|
-
{content}
|
|
91
|
-
</Dropzone>
|
|
92
|
-
)
|
|
93
|
-
const dropzoneWithFunction = mount(
|
|
94
|
-
<Dropzone>
|
|
95
|
-
{() => content}
|
|
96
|
-
</Dropzone>
|
|
97
|
-
)
|
|
102
|
+
const dropzone = mount(<Dropzone>{content}</Dropzone>)
|
|
103
|
+
const dropzoneWithFunction = mount(<Dropzone>{() => content}</Dropzone>)
|
|
98
104
|
expect(dropzoneWithFunction.html()).toEqual(dropzone.html())
|
|
99
105
|
})
|
|
100
106
|
})
|
|
@@ -126,7 +132,11 @@ describe('Dropzone', () => {
|
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
it('installs hooks to prevent stray drops from taking over the browser window', () => {
|
|
129
|
-
dropzone = mount(
|
|
135
|
+
dropzone = mount(
|
|
136
|
+
<Dropzone>
|
|
137
|
+
<p>Content</p>
|
|
138
|
+
</Dropzone>
|
|
139
|
+
)
|
|
130
140
|
expect(dropzone.html()).toMatchSnapshot()
|
|
131
141
|
expect(document.addEventListener.callCount).toEqual(2)
|
|
132
142
|
addEventCalls = collectEventListenerCalls(document.addEventListener.args)
|
|
@@ -138,7 +148,7 @@ describe('Dropzone', () => {
|
|
|
138
148
|
|
|
139
149
|
it('terminates drags and drops on elements outside our dropzone', () => {
|
|
140
150
|
const event = { preventDefault: spy() }
|
|
141
|
-
|
|
151
|
+
onDocumentDragOver(event)
|
|
142
152
|
expect(event.preventDefault.callCount).toEqual(1)
|
|
143
153
|
event.preventDefault.reset()
|
|
144
154
|
|
|
@@ -206,10 +216,25 @@ describe('Dropzone', () => {
|
|
|
206
216
|
|
|
207
217
|
it('should reset the value of input', () => {
|
|
208
218
|
const dropzone = mount(<Dropzone />)
|
|
209
|
-
expect(
|
|
210
|
-
|
|
219
|
+
expect(
|
|
220
|
+
dropzone
|
|
221
|
+
.render()
|
|
222
|
+
.find('input')
|
|
223
|
+
.attr('value')
|
|
224
|
+
).toBeUndefined()
|
|
225
|
+
expect(
|
|
226
|
+
dropzone
|
|
227
|
+
.render()
|
|
228
|
+
.find('input')
|
|
229
|
+
.attr('value', 10)
|
|
230
|
+
).not.toBeUndefined()
|
|
211
231
|
dropzone.simulate('click')
|
|
212
|
-
expect(
|
|
232
|
+
expect(
|
|
233
|
+
dropzone
|
|
234
|
+
.render()
|
|
235
|
+
.find('input')
|
|
236
|
+
.attr('value')
|
|
237
|
+
).toBeUndefined()
|
|
213
238
|
})
|
|
214
239
|
|
|
215
240
|
it('should trigger click even on the input', done => {
|
|
@@ -320,9 +345,7 @@ describe('Dropzone', () => {
|
|
|
320
345
|
)
|
|
321
346
|
|
|
322
347
|
// And using then we'll call the onDragOver with the proxy instead of event
|
|
323
|
-
const dragOverSpy = stub(
|
|
324
|
-
component.instance(),
|
|
325
|
-
'onDragOver',
|
|
348
|
+
const dragOverSpy = stub(component.instance(), 'onDragOver').callsFake(
|
|
326
349
|
component.instance().onDragOver(eventProxy)
|
|
327
350
|
)
|
|
328
351
|
|
|
@@ -339,11 +362,7 @@ describe('Dropzone', () => {
|
|
|
339
362
|
})
|
|
340
363
|
|
|
341
364
|
it('should set proper dragActive state on dragEnter', () => {
|
|
342
|
-
const dropzone = mount(
|
|
343
|
-
<Dropzone>
|
|
344
|
-
{props => <DummyChildComponent {...props} />}
|
|
345
|
-
</Dropzone>
|
|
346
|
-
)
|
|
365
|
+
const dropzone = mount(<Dropzone>{props => <DummyChildComponent {...props} />}</Dropzone>)
|
|
347
366
|
const child = dropzone.find(DummyChildComponent)
|
|
348
367
|
dropzone.simulate('dragEnter', { dataTransfer: { files } })
|
|
349
368
|
expect(child).toHaveProp('isDragActive', true)
|
|
@@ -353,12 +372,12 @@ describe('Dropzone', () => {
|
|
|
353
372
|
|
|
354
373
|
it('should set proper dragReject state on dragEnter', () => {
|
|
355
374
|
const dropzone = mount(
|
|
356
|
-
<Dropzone accept="image/*">
|
|
357
|
-
{props => <DummyChildComponent {...props} />}
|
|
358
|
-
</Dropzone>
|
|
375
|
+
<Dropzone accept="image/*">{props => <DummyChildComponent {...props} />}</Dropzone>
|
|
359
376
|
)
|
|
360
377
|
const child = dropzone.find(DummyChildComponent)
|
|
361
|
-
dropzone.simulate('dragEnter', {
|
|
378
|
+
dropzone.simulate('dragEnter', {
|
|
379
|
+
dataTransfer: { files: files.concat(images) }
|
|
380
|
+
})
|
|
362
381
|
expect(child).toHaveProp('isDragActive', true)
|
|
363
382
|
expect(child).toHaveProp('isDragAccept', false)
|
|
364
383
|
expect(child).toHaveProp('isDragReject', true)
|
|
@@ -390,12 +409,62 @@ describe('Dropzone', () => {
|
|
|
390
409
|
expect(child).toHaveProp('isDragReject', true)
|
|
391
410
|
})
|
|
392
411
|
|
|
393
|
-
it('should
|
|
412
|
+
it('should apply acceptStyle if multiple is false and single file', () => {
|
|
394
413
|
const dropzone = mount(
|
|
395
|
-
<Dropzone
|
|
414
|
+
<Dropzone
|
|
415
|
+
accept="image/*"
|
|
416
|
+
multiple={false}
|
|
417
|
+
acceptStyle={acceptStyle}
|
|
418
|
+
rejectStyle={rejectStyle}
|
|
419
|
+
>
|
|
420
|
+
{props => <DummyChildComponent {...props} />}
|
|
421
|
+
</Dropzone>
|
|
422
|
+
)
|
|
423
|
+
dropzone.simulate('dragEnter', { dataTransfer: { files: [images[0]] } })
|
|
424
|
+
const mainDiv = dropzone.find('div').at(0)
|
|
425
|
+
expect(mainDiv).toHaveProp('style', acceptStyle)
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
it('should apply rejectStyle if multiple is false and single bad file type', () => {
|
|
429
|
+
const dropzone = mount(
|
|
430
|
+
<Dropzone
|
|
431
|
+
accept="image/*"
|
|
432
|
+
multiple={false}
|
|
433
|
+
acceptStyle={acceptStyle}
|
|
434
|
+
rejectStyle={rejectStyle}
|
|
435
|
+
>
|
|
436
|
+
{props => <DummyChildComponent {...props} />}
|
|
437
|
+
</Dropzone>
|
|
438
|
+
)
|
|
439
|
+
dropzone.simulate('dragEnter', { dataTransfer: { files: [files[0]] } })
|
|
440
|
+
const mainDiv = dropzone.find('div').at(0)
|
|
441
|
+
expect(mainDiv).toHaveProp('style', rejectStyle)
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
it('should apply acceptStyle + rejectStyle if multiple is false and multiple good file types', () => {
|
|
445
|
+
const dropzone = mount(
|
|
446
|
+
<Dropzone
|
|
447
|
+
accept="image/*"
|
|
448
|
+
multiple={false}
|
|
449
|
+
acceptStyle={acceptStyle}
|
|
450
|
+
rejectStyle={rejectStyle}
|
|
451
|
+
>
|
|
396
452
|
{props => <DummyChildComponent {...props} />}
|
|
397
453
|
</Dropzone>
|
|
398
454
|
)
|
|
455
|
+
dropzone.simulate('dragEnter', { dataTransfer: { files: images } })
|
|
456
|
+
const mainDiv = dropzone.find('div').at(0)
|
|
457
|
+
const expectedStyle = {
|
|
458
|
+
...acceptStyle,
|
|
459
|
+
...rejectStyle
|
|
460
|
+
}
|
|
461
|
+
expect(mainDiv).toHaveProp('style', expectedStyle)
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
it('should set proper dragActive state if accept prop changes mid-drag', () => {
|
|
465
|
+
const dropzone = mount(
|
|
466
|
+
<Dropzone accept="image/*">{props => <DummyChildComponent {...props} />}</Dropzone>
|
|
467
|
+
)
|
|
399
468
|
const child = dropzone.find(DummyChildComponent)
|
|
400
469
|
dropzone.simulate('dragEnter', { dataTransfer: { files: images } })
|
|
401
470
|
expect(child).toHaveProp('isDragActive', true)
|
|
@@ -507,7 +576,9 @@ describe('Dropzone', () => {
|
|
|
507
576
|
|
|
508
577
|
it('should add invalid files to rejected when multiple is false', () => {
|
|
509
578
|
const dropzone = mount(<Dropzone accept="image/*" onDrop={dropSpy} multiple={false} />)
|
|
510
|
-
dropzone.simulate('drop', {
|
|
579
|
+
dropzone.simulate('drop', {
|
|
580
|
+
dataTransfer: { files: images.concat(files) }
|
|
581
|
+
})
|
|
511
582
|
const rejected = dropSpy.firstCall.args[1]
|
|
512
583
|
expect(rejected.length).toEqual(2)
|
|
513
584
|
})
|
|
@@ -551,7 +622,9 @@ describe('Dropzone', () => {
|
|
|
551
622
|
dropzone.simulate('drop', { dataTransfer: { files: images } })
|
|
552
623
|
expect(dropSpy.callCount).toEqual(2)
|
|
553
624
|
expect(dropSpy.lastCall.args[0]).toEqual([...images], [])
|
|
554
|
-
dropzone.simulate('drop', {
|
|
625
|
+
dropzone.simulate('drop', {
|
|
626
|
+
dataTransfer: { files: files.concat(images) }
|
|
627
|
+
})
|
|
555
628
|
expect(dropSpy.callCount).toEqual(3)
|
|
556
629
|
expect(dropSpy.lastCall.args[0]).toEqual([...images], [...files])
|
|
557
630
|
})
|
|
@@ -570,7 +643,9 @@ describe('Dropzone', () => {
|
|
|
570
643
|
dropzone.simulate('drop', { dataTransfer: { files: images } })
|
|
571
644
|
expect(dropAcceptedSpy.callCount).toEqual(1)
|
|
572
645
|
expect(dropAcceptedSpy.lastCall.args[0]).toEqual([...images])
|
|
573
|
-
dropzone.simulate('drop', {
|
|
646
|
+
dropzone.simulate('drop', {
|
|
647
|
+
dataTransfer: { files: files.concat(images) }
|
|
648
|
+
})
|
|
574
649
|
expect(dropAcceptedSpy.callCount).toEqual(2)
|
|
575
650
|
expect(dropAcceptedSpy.lastCall.args[0]).toEqual([...images])
|
|
576
651
|
})
|
|
@@ -589,7 +664,9 @@ describe('Dropzone', () => {
|
|
|
589
664
|
expect(dropRejectedSpy.lastCall.args[0]).toEqual([...files])
|
|
590
665
|
dropzone.simulate('drop', { dataTransfer: { files: images } })
|
|
591
666
|
expect(dropRejectedSpy.callCount).toEqual(1)
|
|
592
|
-
dropzone.simulate('drop', {
|
|
667
|
+
dropzone.simulate('drop', {
|
|
668
|
+
dataTransfer: { files: files.concat(images) }
|
|
669
|
+
})
|
|
593
670
|
expect(dropRejectedSpy.callCount).toEqual(2)
|
|
594
671
|
expect(dropRejectedSpy.lastCall.args[0]).toEqual([...files])
|
|
595
672
|
})
|
|
@@ -665,7 +742,9 @@ describe('Dropzone', () => {
|
|
|
665
742
|
onDropRejected={dropRejectedSpy}
|
|
666
743
|
/>
|
|
667
744
|
)
|
|
668
|
-
dropzone.simulate('drop', {
|
|
745
|
+
dropzone.simulate('drop', {
|
|
746
|
+
dataTransfer: { files: files.concat(images) }
|
|
747
|
+
})
|
|
669
748
|
expect(dropSpy.callCount).toEqual(1)
|
|
670
749
|
expect(dropSpy.firstCall.args[0]).toHaveLength(3)
|
|
671
750
|
expect(dropSpy.firstCall.args[1]).toHaveLength(0)
|
|
@@ -755,7 +834,9 @@ describe('Dropzone', () => {
|
|
|
755
834
|
onDropRejected={dropRejectedSpy}
|
|
756
835
|
/>
|
|
757
836
|
)
|
|
758
|
-
dropzone.simulate('drop', {
|
|
837
|
+
dropzone.simulate('drop', {
|
|
838
|
+
dataTransfer: { files: files.concat(images) }
|
|
839
|
+
})
|
|
759
840
|
expect(dropSpy.callCount).toEqual(1)
|
|
760
841
|
expect(dropSpy.firstCall.args[0]).toHaveLength(3)
|
|
761
842
|
expect(dropSpy.firstCall.args[1]).toHaveLength(0)
|
|
@@ -897,7 +978,9 @@ describe('Dropzone', () => {
|
|
|
897
978
|
})
|
|
898
979
|
|
|
899
980
|
it('does dragEnter on both dropzones', () => {
|
|
900
|
-
innerDropzone.simulate('dragEnter', {
|
|
981
|
+
innerDropzone.simulate('dragEnter', {
|
|
982
|
+
dataTransfer: { files: images }
|
|
983
|
+
})
|
|
901
984
|
expect(innerDropzone).toHaveProp('isDragActive', true)
|
|
902
985
|
expect(innerDropzone).toHaveProp('isDragReject', false)
|
|
903
986
|
expect(innerDropzone.find(InnerDragAccepted).exists()).toEqual(true)
|
|
@@ -905,7 +988,9 @@ describe('Dropzone', () => {
|
|
|
905
988
|
})
|
|
906
989
|
|
|
907
990
|
it('drops on the child dropzone', () => {
|
|
908
|
-
innerDropzone.simulate('drop', {
|
|
991
|
+
innerDropzone.simulate('drop', {
|
|
992
|
+
dataTransfer: { files: files.concat(images) }
|
|
993
|
+
})
|
|
909
994
|
})
|
|
910
995
|
|
|
911
996
|
it('accepts the drop on the inner dropzone', () => {
|
|
@@ -941,5 +1026,29 @@ describe('Dropzone', () => {
|
|
|
941
1026
|
const fn = () => dropzone.simulate('drop', { dataTransfer: { files: [] } })
|
|
942
1027
|
expect(fn).not.toThrow()
|
|
943
1028
|
})
|
|
1029
|
+
|
|
1030
|
+
it('does not allow actions when disabled props is true', done => {
|
|
1031
|
+
const dropzone = mount(<Dropzone disabled />)
|
|
1032
|
+
|
|
1033
|
+
spy(dropzone.instance(), 'open')
|
|
1034
|
+
dropzone.simulate('click')
|
|
1035
|
+
setTimeout(() => {
|
|
1036
|
+
expect(dropzone.instance().open.callCount).toEqual(0)
|
|
1037
|
+
done()
|
|
1038
|
+
}, 0)
|
|
1039
|
+
})
|
|
1040
|
+
|
|
1041
|
+
it('when toggle disabled props, Dropzone works as expected', done => {
|
|
1042
|
+
const dropzone = mount(<Dropzone disabled />)
|
|
1043
|
+
spy(dropzone.instance(), 'open')
|
|
1044
|
+
|
|
1045
|
+
dropzone.setProps({ disabled: false })
|
|
1046
|
+
|
|
1047
|
+
dropzone.simulate('click')
|
|
1048
|
+
setTimeout(() => {
|
|
1049
|
+
expect(dropzone.instance().open.callCount).toEqual(1)
|
|
1050
|
+
done()
|
|
1051
|
+
}, 0)
|
|
1052
|
+
})
|
|
944
1053
|
})
|
|
945
1054
|
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import accepts from 'attr-accept'
|
|
2
|
+
|
|
3
|
+
export const supportMultiple =
|
|
4
|
+
typeof document !== 'undefined' && document && document.createElement
|
|
5
|
+
? 'multiple' in document.createElement('input')
|
|
6
|
+
: true
|
|
7
|
+
|
|
8
|
+
export function getDataTransferItems(event) {
|
|
9
|
+
let dataTransferItemsList = []
|
|
10
|
+
if (event.dataTransfer) {
|
|
11
|
+
const dt = event.dataTransfer
|
|
12
|
+
if (dt.files && dt.files.length) {
|
|
13
|
+
dataTransferItemsList = dt.files
|
|
14
|
+
} else if (dt.items && dt.items.length) {
|
|
15
|
+
// During the drag even the dataTransfer.files is null
|
|
16
|
+
// but Chrome implements some drag store, which is accesible via dataTransfer.items
|
|
17
|
+
dataTransferItemsList = dt.items
|
|
18
|
+
}
|
|
19
|
+
} else if (event.target && event.target.files) {
|
|
20
|
+
dataTransferItemsList = event.target.files
|
|
21
|
+
}
|
|
22
|
+
// Convert from DataTransferItemsList to the native Array
|
|
23
|
+
return Array.prototype.slice.call(dataTransferItemsList)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with
|
|
27
|
+
// that MIME type will always be accepted
|
|
28
|
+
export function fileAccepted(file, accept) {
|
|
29
|
+
return file.type === 'application/x-moz-file' || accepts(file, accept)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function fileMatchSize(file, maxSize, minSize) {
|
|
33
|
+
return file.size <= maxSize && file.size >= minSize
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function allFilesAccepted(files, accept) {
|
|
37
|
+
return files.every(file => fileAccepted(file, accept))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// allow the entire document to be a drag target
|
|
41
|
+
export function onDocumentDragOver(evt) {
|
|
42
|
+
evt.preventDefault()
|
|
43
|
+
}
|