react-dropzone 7.0.1 → 8.0.3

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/src/index.spec.js CHANGED
@@ -4,7 +4,6 @@
4
4
  import React from 'react'
5
5
  import { mount, render } from 'enzyme'
6
6
  import { fromEvent } from 'file-selector'
7
- import styles from './utils/styles'
8
7
  import * as utils from './utils'
9
8
 
10
9
  const flushPromises = wrapper =>
@@ -53,19 +52,6 @@ const createDtWithTextItems = () => {
53
52
  let files
54
53
  let images
55
54
 
56
- const rejectColor = 'red'
57
- const acceptColor = 'green'
58
-
59
- const rejectStyle = {
60
- color: rejectColor,
61
- borderColor: 'black'
62
- }
63
-
64
- const acceptStyle = {
65
- color: acceptColor,
66
- borderWidth: '5px'
67
- }
68
-
69
55
  describe('Dropzone', () => {
70
56
  beforeEach(() => {
71
57
  files = [createFile('file1.pdf', 1111, 'application/pdf')]
@@ -76,41 +62,42 @@ describe('Dropzone', () => {
76
62
  it('should render children', () => {
77
63
  const dropzone = mount(
78
64
  <Dropzone>
79
- <p>some content</p>
65
+ {({ getRootProps, getInputProps }) => (
66
+ <div {...getRootProps()}>
67
+ <input {...getInputProps()} />
68
+ </div>
69
+ )}
80
70
  </Dropzone>
81
71
  )
82
72
  expect(dropzone.html()).toMatchSnapshot()
83
73
  })
84
74
 
85
- it('should render an input HTML element', () => {
75
+ it('sets refs properly', () => {
86
76
  const dropzone = mount(
87
77
  <Dropzone>
88
- <p>some content</p>
78
+ {({ getRootProps, getInputProps }) => (
79
+ <div {...getRootProps()}>
80
+ <input {...getInputProps()} />
81
+ </div>
82
+ )}
89
83
  </Dropzone>
90
84
  )
91
- expect(dropzone.find('input').length).toEqual(1)
92
- })
93
-
94
- it('sets ref properly', () => {
95
- const dropzone = mount(<Dropzone />)
96
- expect(dropzone.instance().fileInputEl).not.toBeUndefined()
97
- expect(dropzone.instance().fileInputEl.tagName).toEqual('INPUT')
98
- })
99
-
100
- it('renders dynamic props on the root element', () => {
101
- const component = mount(<Dropzone hidden aria-hidden title="Dropzone" />)
102
- expect(component.html()).toContain('aria-hidden="true"')
103
- expect(component.html()).toContain('hidden=""')
104
- expect(component.html()).toContain('title="Dropzone"')
105
- })
106
-
107
- it('renders dynamic props on the input element', () => {
108
- const component = mount(<Dropzone inputProps={{ id: 'hiddenFileInput' }} />)
109
- expect(component.find('input').html()).toContain('id="hiddenFileInput"')
85
+ expect(dropzone.instance().node).not.toBeUndefined()
86
+ expect(dropzone.instance().node.tagName).toEqual('DIV')
87
+ expect(dropzone.instance().input).not.toBeUndefined()
88
+ expect(dropzone.instance().input.tagName).toEqual('INPUT')
110
89
  })
111
90
 
112
91
  it('applies the accept prop to the child input', () => {
113
- const component = render(<Dropzone className="my-dropzone" accept="image/jpeg" />)
92
+ const component = render(
93
+ <Dropzone accept="image/jpeg">
94
+ {({ getRootProps, getInputProps }) => (
95
+ <div className="my-dropzone" {...getRootProps()}>
96
+ <input {...getInputProps()} />
97
+ </div>
98
+ )}
99
+ </Dropzone>
100
+ )
114
101
 
115
102
  expect(component.attr()).not.toContain('accept')
116
103
  expect(Object.keys(component.find('input').attr())).toContain('accept')
@@ -118,17 +105,75 @@ describe('Dropzone', () => {
118
105
  })
119
106
 
120
107
  it('applies the name prop to the child input', () => {
121
- const component = render(<Dropzone className="my-dropzone" name="test-file-input" />)
108
+ const component = render(
109
+ <Dropzone name="test-file-input">
110
+ {({ getRootProps, getInputProps }) => (
111
+ <div className="my-dropzone" {...getRootProps()}>
112
+ <input {...getInputProps()} />
113
+ </div>
114
+ )}
115
+ </Dropzone>
116
+ )
122
117
  expect(component.attr()).not.toContain('name')
123
118
  expect(Object.keys(component.find('input').attr())).toContain('name')
124
119
  expect(component.find('input').attr('name')).toEqual('test-file-input')
125
120
  })
126
121
 
127
- it('should render children function', () => {
128
- const content = <p>some content</p>
129
- const dropzone = mount(<Dropzone>{content}</Dropzone>)
130
- const dropzoneWithFunction = mount(<Dropzone>{() => content}</Dropzone>)
131
- expect(dropzoneWithFunction.html()).toEqual(dropzone.html())
122
+ it('runs custom root handlers', async () => {
123
+ const evt = createDtWithFiles(files)
124
+ const rootProps = {
125
+ onClick: jest.fn(),
126
+ onKeyDown: jest.fn(),
127
+ onFocus: jest.fn(),
128
+ onBlur: jest.fn(),
129
+ onDragStart: jest.fn(),
130
+ onDragEnter: jest.fn(),
131
+ onDragOver: jest.fn(),
132
+ onDragLeave: jest.fn(),
133
+ onDrop: jest.fn()
134
+ }
135
+ const dropzone = mount(
136
+ <Dropzone>
137
+ {({ getRootProps, getInputProps }) => (
138
+ <div {...getRootProps(rootProps)}>
139
+ <input {...getInputProps()} />
140
+ </div>
141
+ )}
142
+ </Dropzone>
143
+ )
144
+
145
+ await dropzone.simulate('click')
146
+ await flushPromises(dropzone)
147
+ expect(rootProps.onClick).toHaveBeenCalled()
148
+
149
+ dropzone.simulate('focus')
150
+ expect(rootProps.onFocus).toHaveBeenCalled()
151
+
152
+ dropzone.simulate('blur')
153
+ expect(rootProps.onBlur).toHaveBeenCalled()
154
+
155
+ dropzone.simulate('keydown')
156
+ expect(rootProps.onKeyDown).toHaveBeenCalled()
157
+
158
+ await dropzone.simulate('dragStart', evt)
159
+ await flushPromises(dropzone)
160
+ expect(rootProps.onDragStart).toHaveBeenCalled()
161
+
162
+ await dropzone.simulate('dragEnter', evt)
163
+ await flushPromises(dropzone)
164
+ expect(rootProps.onDragEnter).toHaveBeenCalled()
165
+
166
+ await dropzone.simulate('dragOver', evt)
167
+ await flushPromises(dropzone)
168
+ expect(rootProps.onDragOver).toHaveBeenCalled()
169
+
170
+ await dropzone.simulate('dragLeave', evt)
171
+ await flushPromises(dropzone)
172
+ expect(rootProps.onDragLeave).toHaveBeenCalled()
173
+
174
+ await dropzone.simulate('drop', evt)
175
+ await flushPromises(dropzone)
176
+ expect(rootProps.onDrop).toHaveBeenCalled()
132
177
  })
133
178
  })
134
179
 
@@ -151,7 +196,12 @@ describe('Dropzone', () => {
151
196
  it('installs hooks to prevent stray drops from taking over the browser window', () => {
152
197
  const dropzone = mount(
153
198
  <Dropzone>
154
- <p>Content</p>
199
+ {({ getRootProps, getInputProps }) => (
200
+ <div {...getRootProps()}>
201
+ <input {...getInputProps()} />
202
+ <p>Content</p>
203
+ </div>
204
+ )}
155
205
  </Dropzone>
156
206
  )
157
207
  expect(dropzone.html()).toMatchSnapshot()
@@ -166,7 +216,12 @@ describe('Dropzone', () => {
166
216
  it('terminates drags and drops on elements outside our dropzone', () => {
167
217
  const dropzone = mount(
168
218
  <Dropzone>
169
- <p>Content</p>
219
+ {({ getRootProps, getInputProps }) => (
220
+ <div {...getRootProps()}>
221
+ <input {...getInputProps()} />
222
+ <p>Content</p>
223
+ </div>
224
+ )}
170
225
  </Dropzone>
171
226
  )
172
227
 
@@ -181,7 +236,12 @@ describe('Dropzone', () => {
181
236
  it('permits drags and drops on elements inside our dropzone', () => {
182
237
  const dropzone = mount(
183
238
  <Dropzone>
184
- <p>Content</p>
239
+ {({ getRootProps, getInputProps }) => (
240
+ <div {...getRootProps()}>
241
+ <input {...getInputProps()} />
242
+ <p>Content</p>
243
+ </div>
244
+ )}
185
245
  </Dropzone>
186
246
  )
187
247
 
@@ -196,7 +256,12 @@ describe('Dropzone', () => {
196
256
  it('removes document hooks when unmounted', () => {
197
257
  const dropzone = mount(
198
258
  <Dropzone>
199
- <p>Content</p>
259
+ {({ getRootProps, getInputProps }) => (
260
+ <div {...getRootProps()}>
261
+ <input {...getInputProps()} />
262
+ <p>Content</p>
263
+ </div>
264
+ )}
200
265
  </Dropzone>
201
266
  )
202
267
  dropzone.unmount()
@@ -209,7 +274,15 @@ describe('Dropzone', () => {
209
274
  })
210
275
 
211
276
  it('does not prevent stray drops when preventDropOnDocument is false', () => {
212
- const dropzone = mount(<Dropzone preventDropOnDocument={false} />)
277
+ const dropzone = mount(
278
+ <Dropzone preventDropOnDocument={false}>
279
+ {({ getRootProps, getInputProps }) => (
280
+ <div {...getRootProps()}>
281
+ <input {...getInputProps()} />
282
+ </div>
283
+ )}
284
+ </Dropzone>
285
+ )
213
286
  expect(dropzone.html()).toMatchSnapshot()
214
287
  expect(onAddEventListener).not.toHaveBeenCalled()
215
288
 
@@ -220,14 +293,30 @@ describe('Dropzone', () => {
220
293
 
221
294
  describe('onClick', () => {
222
295
  it('should call `open` method', () => {
223
- const dropzone = mount(<Dropzone />)
296
+ const dropzone = mount(
297
+ <Dropzone>
298
+ {({ getRootProps, getInputProps }) => (
299
+ <div {...getRootProps()}>
300
+ <input {...getInputProps()} />
301
+ </div>
302
+ )}
303
+ </Dropzone>
304
+ )
224
305
  const open = jest.spyOn(dropzone.instance(), 'open')
225
306
  dropzone.simulate('click')
226
307
  expect(open).toHaveBeenCalled()
227
308
  })
228
309
 
229
310
  it('should not call `open` if disableClick prop is true', () => {
230
- const dropzone = mount(<Dropzone disableClick />)
311
+ const dropzone = mount(
312
+ <Dropzone disableClick>
313
+ {({ getRootProps, getInputProps }) => (
314
+ <div {...getRootProps()}>
315
+ <input {...getInputProps()} />
316
+ </div>
317
+ )}
318
+ </Dropzone>
319
+ )
231
320
  const open = jest.spyOn(dropzone.instance(), 'open')
232
321
  dropzone.simulate('click')
233
322
  expect(open).not.toHaveBeenCalled()
@@ -235,7 +324,15 @@ describe('Dropzone', () => {
235
324
 
236
325
  it('should call `onClick` callback if provided', () => {
237
326
  const onClick = jest.fn()
238
- const dropzone = mount(<Dropzone onClick={onClick} />)
327
+ const dropzone = mount(
328
+ <Dropzone onClick={onClick}>
329
+ {({ getRootProps, getInputProps }) => (
330
+ <div {...getRootProps()}>
331
+ <input {...getInputProps()} />
332
+ </div>
333
+ )}
334
+ </Dropzone>
335
+ )
239
336
  const open = jest.spyOn(dropzone.instance(), 'open')
240
337
  dropzone.simulate('click')
241
338
  expect(open).toHaveBeenCalled()
@@ -244,7 +341,15 @@ describe('Dropzone', () => {
244
341
 
245
342
  it('should call `onClick` if provided even if `disableClick` is set', () => {
246
343
  const onClick = jest.fn()
247
- const dropzone = mount(<Dropzone disableClick onClick={onClick} />)
344
+ const dropzone = mount(
345
+ <Dropzone onClick={onClick} disableClick>
346
+ {({ getRootProps, getInputProps }) => (
347
+ <div {...getRootProps()}>
348
+ <input {...getInputProps()} />
349
+ </div>
350
+ )}
351
+ </Dropzone>
352
+ )
248
353
  const open = jest.spyOn(dropzone.instance(), 'open')
249
354
  dropzone.simulate('click')
250
355
  expect(open).toHaveBeenCalledTimes(0)
@@ -253,7 +358,15 @@ describe('Dropzone', () => {
253
358
 
254
359
  it('should not call `open` if event was prevented in `onClick`', () => {
255
360
  const onClick = jest.fn(event => event.preventDefault())
256
- const dropzone = mount(<Dropzone onClick={onClick} />)
361
+ const dropzone = mount(
362
+ <Dropzone onClick={onClick}>
363
+ {({ getRootProps, getInputProps }) => (
364
+ <div {...getRootProps()}>
365
+ <input {...getInputProps()} />
366
+ </div>
367
+ )}
368
+ </Dropzone>
369
+ )
257
370
  const open = jest.spyOn(dropzone.instance(), 'open')
258
371
  dropzone.simulate('click')
259
372
  expect(open).toHaveBeenCalledTimes(0)
@@ -261,7 +374,15 @@ describe('Dropzone', () => {
261
374
  })
262
375
 
263
376
  it('should reset the value of input', () => {
264
- const dropzone = mount(<Dropzone />)
377
+ const dropzone = mount(
378
+ <Dropzone>
379
+ {({ getRootProps, getInputProps }) => (
380
+ <div {...getRootProps()}>
381
+ <input {...getInputProps()} />
382
+ </div>
383
+ )}
384
+ </Dropzone>
385
+ )
265
386
  expect(
266
387
  dropzone
267
388
  .render()
@@ -284,8 +405,16 @@ describe('Dropzone', () => {
284
405
  })
285
406
 
286
407
  it('should trigger click even on the input', () => {
287
- const dropzone = mount(<Dropzone />)
288
- const onFileInputClick = jest.spyOn(dropzone.instance().fileInputEl, 'click')
408
+ const dropzone = mount(
409
+ <Dropzone>
410
+ {({ getRootProps, getInputProps }) => (
411
+ <div {...getRootProps()}>
412
+ <input {...getInputProps()} />
413
+ </div>
414
+ )}
415
+ </Dropzone>
416
+ )
417
+ const onFileInputClick = jest.spyOn(dropzone.instance().input, 'click')
289
418
  dropzone.simulate('click')
290
419
  dropzone.simulate('click')
291
420
  expect(onFileInputClick).toHaveBeenCalledTimes(2)
@@ -296,7 +425,13 @@ describe('Dropzone', () => {
296
425
  const onClickInner = jest.fn()
297
426
  const component = mount(
298
427
  <div onClick={onClickOuter}>
299
- <Dropzone onClick={onClickInner} />
428
+ <Dropzone onClick={onClickInner}>
429
+ {({ getRootProps, getInputProps }) => (
430
+ <div {...getRootProps()}>
431
+ <input {...getInputProps()} />
432
+ </div>
433
+ )}
434
+ </Dropzone>
300
435
  </div>
301
436
  )
302
437
 
@@ -316,7 +451,13 @@ describe('Dropzone', () => {
316
451
  const onClick = jest.fn()
317
452
  const component = mount(
318
453
  <div onClick={onClick}>
319
- <Dropzone disableClick />
454
+ <Dropzone disableClick>
455
+ {({ getRootProps, getInputProps }) => (
456
+ <div {...getRootProps()}>
457
+ <input {...getInputProps()} />
458
+ </div>
459
+ )}
460
+ </Dropzone>
320
461
  </div>
321
462
  )
322
463
 
@@ -326,17 +467,33 @@ describe('Dropzone', () => {
326
467
 
327
468
  it('should invoke inputProps onClick if provided', () => {
328
469
  const onClick = jest.fn()
329
- const component = mount(<Dropzone inputProps={{ onClick }} />)
470
+ const component = mount(
471
+ <Dropzone>
472
+ {({ getRootProps, getInputProps }) => (
473
+ <div {...getRootProps()}>
474
+ <input {...getInputProps({ onClick })} />
475
+ </div>
476
+ )}
477
+ </Dropzone>
478
+ )
330
479
 
331
- component.simulate('click')
332
- expect(onClick).toHaveBeenCalledWith(expect.any(MouseEvent))
480
+ component.find('input').simulate('click')
481
+ expect(onClick).toHaveBeenCalled()
333
482
  })
334
483
 
335
484
  it('should schedule open() on next tick when Edge', () => {
336
485
  const isIeOrEdgeSpy = jest.spyOn(utils, 'isIeOrEdge').mockReturnValueOnce(true)
337
486
  const setTimeoutSpy = jest.spyOn(window, 'setTimeout').mockImplementationOnce(open => open())
338
487
 
339
- const dropzone = mount(<Dropzone />)
488
+ const dropzone = mount(
489
+ <Dropzone>
490
+ {({ getRootProps, getInputProps }) => (
491
+ <div {...getRootProps()}>
492
+ <input {...getInputProps()} />
493
+ </div>
494
+ )}
495
+ </Dropzone>
496
+ )
340
497
  const open = jest.spyOn(dropzone.instance(), 'open')
341
498
  dropzone.simulate('click')
342
499
 
@@ -347,6 +504,274 @@ describe('Dropzone', () => {
347
504
  })
348
505
  })
349
506
 
507
+ describe('onFocus', () => {
508
+ it('sets focus state', async () => {
509
+ const dropzone = mount(
510
+ <Dropzone>
511
+ {({ getRootProps, getInputProps, isFocused }) => (
512
+ <div {...getRootProps()}>
513
+ <input {...getInputProps()} />
514
+ {isFocused && <span className="dropzone-focused" />}
515
+ </div>
516
+ )}
517
+ </Dropzone>
518
+ )
519
+ dropzone.simulate('focus', { isDefaultPrevented: () => false })
520
+ expect(dropzone.find('.dropzone-focused')).toHaveLength(1)
521
+ })
522
+
523
+ it('calls user supplied onFocus', async () => {
524
+ const onFocus = jest.fn()
525
+ const dropzone = mount(
526
+ <Dropzone onFocus={onFocus}>
527
+ {({ getRootProps, getInputProps }) => (
528
+ <div {...getRootProps()}>
529
+ <input {...getInputProps()} />
530
+ </div>
531
+ )}
532
+ </Dropzone>
533
+ )
534
+ dropzone.simulate('focus', { isDefaultPrevented: () => false })
535
+ expect(dropzone.state('isFocused')).toBe(true)
536
+ expect(onFocus).toHaveBeenCalled()
537
+ })
538
+
539
+ it('does not set focus state if user supplied onFocus prevented default', async () => {
540
+ const onFocus = jest.fn().mockImplementationOnce(evt => {
541
+ Object.assign(evt, {
542
+ isDefaultPrevented: () => true
543
+ })
544
+ })
545
+ const dropzone = mount(
546
+ <Dropzone onFocus={onFocus}>
547
+ {({ getRootProps, getInputProps }) => (
548
+ <div {...getRootProps()}>
549
+ <input {...getInputProps()} />
550
+ </div>
551
+ )}
552
+ </Dropzone>
553
+ )
554
+ dropzone.simulate('focus', {})
555
+ expect(onFocus).toHaveBeenCalled()
556
+ })
557
+ })
558
+
559
+ describe('onBlur', () => {
560
+ it('unsets focus state', async () => {
561
+ const dropzone = mount(
562
+ <Dropzone>
563
+ {({ getRootProps, getInputProps, isFocused }) => (
564
+ <div {...getRootProps()}>
565
+ <input {...getInputProps()} />
566
+ {isFocused && <span className="dropzone-focused" />}
567
+ </div>
568
+ )}
569
+ </Dropzone>
570
+ )
571
+ dropzone.simulate('focus', { isDefaultPrevented: () => false })
572
+ expect(dropzone.find('.dropzone-focused')).toHaveLength(1)
573
+ dropzone.simulate('blur', { isDefaultPrevented: () => false })
574
+ expect(dropzone.find('.dropzone-focused')).toHaveLength(0)
575
+ })
576
+
577
+ it('calls user supplied onBlur', async () => {
578
+ const onBlur = jest.fn()
579
+ const dropzone = mount(
580
+ <Dropzone onBlur={onBlur}>
581
+ {({ getRootProps, getInputProps }) => (
582
+ <div {...getRootProps()}>
583
+ <input {...getInputProps()} />
584
+ </div>
585
+ )}
586
+ </Dropzone>
587
+ )
588
+ dropzone.simulate('blur', { isDefaultPrevented: () => false })
589
+ expect(onBlur).toHaveBeenCalled()
590
+ })
591
+
592
+ it('does not unset focus state if user supplied onBlur prevented default', async () => {
593
+ const onBlur = jest.fn().mockImplementationOnce(evt => {
594
+ Object.assign(evt, {
595
+ isDefaultPrevented: () => true
596
+ })
597
+ })
598
+ const dropzone = mount(
599
+ <Dropzone onBlur={onBlur}>
600
+ {({ getRootProps, getInputProps }) => (
601
+ <div {...getRootProps()}>
602
+ <input {...getInputProps()} />
603
+ </div>
604
+ )}
605
+ </Dropzone>
606
+ )
607
+ dropzone.simulate('focus', { isDefaultPrevented: () => false })
608
+ dropzone.simulate('blur', {})
609
+ expect(onBlur).toHaveBeenCalled()
610
+ })
611
+ })
612
+
613
+ describe('onKeyDown', () => {
614
+ it('opens the file dialog on SPACE/ENTER if component is in focus', async () => {
615
+ const dropzone = mount(
616
+ <Dropzone>
617
+ {({ getRootProps, getInputProps }) => (
618
+ <div {...getRootProps()}>
619
+ <input {...getInputProps()} />
620
+ </div>
621
+ )}
622
+ </Dropzone>
623
+ )
624
+ const open = jest.spyOn(dropzone.instance(), 'open')
625
+
626
+ dropzone.simulate('keydown', {
627
+ keyCode: 32,
628
+ isDefaultPrevented: () => false,
629
+ preventDefault() {}
630
+ })
631
+
632
+ dropzone.simulate('keydown', {
633
+ keyCode: 13,
634
+ isDefaultPrevented: () => false,
635
+ preventDefault() {}
636
+ })
637
+
638
+ expect(open).toHaveBeenCalledTimes(2)
639
+ })
640
+
641
+ it('does not react to keydown if component is disabled', async () => {
642
+ const dropzone = mount(
643
+ <Dropzone disabled>
644
+ {({ getRootProps, getInputProps }) => (
645
+ <div {...getRootProps()}>
646
+ <input {...getInputProps()} />
647
+ </div>
648
+ )}
649
+ </Dropzone>
650
+ )
651
+ const open = jest.spyOn(dropzone.instance(), 'open')
652
+ dropzone.simulate('keydown', {
653
+ keyCode: 32,
654
+ isDefaultPrevented: () => false,
655
+ preventDefault() {}
656
+ })
657
+ expect(open).not.toHaveBeenCalled()
658
+ })
659
+
660
+ it('does not react to keydown if component is not in focus', async () => {
661
+ const dropzone = mount(
662
+ <Dropzone>
663
+ {({ getRootProps, getInputProps }) => (
664
+ <div {...getRootProps()}>
665
+ <input {...getInputProps()} />
666
+ </div>
667
+ )}
668
+ </Dropzone>
669
+ )
670
+ const open = jest.spyOn(dropzone.instance(), 'open')
671
+ dropzone.find('input').simulate('keydown', {
672
+ keyCode: 32,
673
+ isDefaultPrevented: () => false,
674
+ preventDefault() {}
675
+ })
676
+ expect(open).not.toHaveBeenCalled()
677
+ })
678
+
679
+ it('does not react to keydown from child components', async () => {
680
+ const dropzone = mount(
681
+ <Dropzone>
682
+ {({ getRootProps, getInputProps }) => (
683
+ <div {...getRootProps()}>
684
+ <input {...getInputProps()} />
685
+ </div>
686
+ )}
687
+ </Dropzone>
688
+ )
689
+ const open = jest.spyOn(dropzone.instance(), 'open')
690
+ dropzone.find('input').simulate('keydown', { keyCode: 13 })
691
+ expect(open).not.toHaveBeenCalled()
692
+ })
693
+
694
+ it('calls user supplied onKeyDown', async () => {
695
+ const onKeyDown = jest.fn()
696
+ const dropzone = mount(
697
+ <Dropzone onKeyDown={onKeyDown}>
698
+ {({ getRootProps, getInputProps }) => (
699
+ <div {...getRootProps()}>
700
+ <input {...getInputProps()} />
701
+ </div>
702
+ )}
703
+ </Dropzone>
704
+ )
705
+ const open = jest.spyOn(dropzone.instance(), 'open')
706
+ dropzone.simulate('keydown', {
707
+ keyCode: 32,
708
+ isDefaultPrevented: () => false,
709
+ preventDefault() {}
710
+ })
711
+ expect(onKeyDown).toHaveBeenCalled()
712
+ expect(open).toHaveBeenCalled()
713
+ })
714
+
715
+ it('does not call user supplied onKeyDown if component is not in focus', async () => {
716
+ const onKeyDown = jest.fn()
717
+ const dropzone = mount(
718
+ <Dropzone onKeyDown={onKeyDown}>
719
+ {({ getRootProps, getInputProps }) => (
720
+ <div {...getRootProps()}>
721
+ <input {...getInputProps()} />
722
+ </div>
723
+ )}
724
+ </Dropzone>
725
+ )
726
+ dropzone.find('input').simulate('keydown', {
727
+ keyCode: 32,
728
+ isDefaultPrevented: () => false,
729
+ preventDefault() {}
730
+ })
731
+ expect(onKeyDown).not.toHaveBeenCalled()
732
+ })
733
+
734
+ it('does not react to keydown if user-supplied onKeyDown prevents default', async () => {
735
+ const onKeyDown = jest.fn().mockImplementationOnce(evt => {
736
+ Object.assign(evt, {
737
+ isDefaultPrevented: () => true
738
+ })
739
+ })
740
+ const dropzone = mount(
741
+ <Dropzone onKeyDown={onKeyDown}>
742
+ {({ getRootProps, getInputProps }) => (
743
+ <div {...getRootProps()}>
744
+ <input {...getInputProps()} />
745
+ </div>
746
+ )}
747
+ </Dropzone>
748
+ )
749
+ const open = jest.spyOn(dropzone.instance(), 'open')
750
+ dropzone.simulate('keydown', { keyCode: 32 })
751
+ expect(onKeyDown).toHaveBeenCalled()
752
+ expect(open).not.toHaveBeenCalled()
753
+ })
754
+
755
+ it('does not react to other keys', async () => {
756
+ const dropzone = mount(
757
+ <Dropzone>
758
+ {({ getRootProps, getInputProps }) => (
759
+ <div {...getRootProps()}>
760
+ <input {...getInputProps()} />
761
+ </div>
762
+ )}
763
+ </Dropzone>
764
+ )
765
+ const open = jest.spyOn(dropzone.instance(), 'open')
766
+ dropzone.simulate('keydown', {
767
+ keyCode: 100,
768
+ isDefaultPrevented: () => false,
769
+ preventDefault() {}
770
+ })
771
+ expect(open).not.toHaveBeenCalled()
772
+ })
773
+ })
774
+
350
775
  describe('drag-n-drop', async () => {
351
776
  it('should override onDrag* methods', async () => {
352
777
  const props = {
@@ -355,7 +780,15 @@ describe('Dropzone', () => {
355
780
  onDragOver: jest.fn(),
356
781
  onDragLeave: jest.fn()
357
782
  }
358
- const component = mount(<Dropzone {...props} />)
783
+ const component = mount(
784
+ <Dropzone {...props}>
785
+ {({ getRootProps, getInputProps }) => (
786
+ <div {...getRootProps()}>
787
+ <input {...getInputProps()} />
788
+ </div>
789
+ )}
790
+ </Dropzone>
791
+ )
359
792
 
360
793
  await component.simulate('dragStart', createDtWithFiles(files))
361
794
  await flushPromises(component)
@@ -374,59 +807,6 @@ describe('Dropzone', () => {
374
807
  expect(props.onDragLeave).toHaveBeenCalled()
375
808
  })
376
809
 
377
- it('should guard dropEffect in onDragOver for IE', async () => {
378
- const props = {
379
- onDragStart: jest.fn(),
380
- onDragEnter: jest.fn(),
381
- onDragLeave: jest.fn()
382
- }
383
- const component = mount(<Dropzone {...props} />)
384
-
385
- // Using Proxy we'll emulate IE throwing when setting dataTransfer.dropEffect
386
- const eventProxy = {
387
- persist() {},
388
- preventDefault() {},
389
- stopPropagation() {},
390
- dataTransfer: new Proxy(
391
- {},
392
- {
393
- set: (target, prop) => {
394
- switch (prop) {
395
- case 'dropEffect':
396
- throw new Error('IE does not support setting {dropEffect}')
397
- default:
398
- break
399
- }
400
- }
401
- }
402
- )
403
- }
404
-
405
- // And using then we'll call the onDragOver with the proxy instead of event
406
- const instance = component.instance()
407
- const componentOnDragOver = instance.onDragOver
408
- const onDragOver = jest
409
- .spyOn(instance, 'onDragOver')
410
- .mockImplementation(() => componentOnDragOver(eventProxy))
411
-
412
- component.simulate('dragStart', createDtWithFiles(files))
413
- await flushPromises(component)
414
- expect(props.onDragStart).toHaveBeenCalled()
415
-
416
- component.simulate('dragEnter', createDtWithFiles(files))
417
- await flushPromises(component)
418
- expect(props.onDragEnter).toHaveBeenCalled()
419
-
420
- component.simulate('dragLeave', createDtWithFiles(files))
421
- await flushPromises(component)
422
- expect(props.onDragLeave).toHaveBeenCalled()
423
-
424
- // It should not throw the error
425
- component.simulate('dragOver', createDtWithFiles(files))
426
- await flushPromises(component)
427
- expect(onDragOver).not.toThrow()
428
- })
429
-
430
810
  it('should not call onDrag* if there are no files', async () => {
431
811
  const props = {
432
812
  onDragStart: jest.fn(),
@@ -438,7 +818,15 @@ describe('Dropzone', () => {
438
818
  onDropRejected: jest.fn()
439
819
  }
440
820
 
441
- const component = mount(<Dropzone {...props} />)
821
+ const component = mount(
822
+ <Dropzone {...props}>
823
+ {({ getRootProps, getInputProps }) => (
824
+ <div {...getRootProps()}>
825
+ <input {...getInputProps()} />
826
+ </div>
827
+ )}
828
+ </Dropzone>
829
+ )
442
830
 
443
831
  await component.simulate('dragStart', createDtWithTextTypes())
444
832
  await flushPromises(component)
@@ -474,7 +862,15 @@ describe('Dropzone', () => {
474
862
  onDropRejected: jest.fn()
475
863
  }
476
864
 
477
- const component = mount(<Dropzone {...props} />)
865
+ const component = mount(
866
+ <Dropzone {...props}>
867
+ {({ getRootProps, getInputProps }) => (
868
+ <div {...getRootProps()}>
869
+ <input {...getInputProps()} />
870
+ </div>
871
+ )}
872
+ </Dropzone>
873
+ )
478
874
 
479
875
  await component.simulate('dragStart', createDtWithFiles([]))
480
876
  await flushPromises(component)
@@ -500,7 +896,16 @@ describe('Dropzone', () => {
500
896
  })
501
897
 
502
898
  it('should set proper dragActive state on dragEnter', async () => {
503
- const component = mount(<Dropzone>{props => <DummyChildComponent {...props} />}</Dropzone>)
899
+ const component = mount(
900
+ <Dropzone>
901
+ {({ getRootProps, getInputProps, ...restProps }) => (
902
+ <div {...getRootProps()}>
903
+ <input {...getInputProps()} />
904
+ <DummyChildComponent {...restProps} />
905
+ </div>
906
+ )}
907
+ </Dropzone>
908
+ )
504
909
  component.simulate('dragEnter', createDtWithFiles(files))
505
910
 
506
911
  const updatedDropzone = await flushPromises(component)
@@ -513,7 +918,14 @@ describe('Dropzone', () => {
513
918
 
514
919
  it('should set proper dragReject state on dragEnter', async () => {
515
920
  const dropzone = mount(
516
- <Dropzone accept="image/*">{props => <DummyChildComponent {...props} />}</Dropzone>
921
+ <Dropzone accept="image/*">
922
+ {({ getRootProps, getInputProps, ...restProps }) => (
923
+ <div {...getRootProps()}>
924
+ <input {...getInputProps()} />
925
+ <DummyChildComponent {...restProps} />
926
+ </div>
927
+ )}
928
+ </Dropzone>
517
929
  )
518
930
  dropzone.simulate('dragEnter', createDtWithFiles(files.concat(images)))
519
931
  const updatedDropzone = await flushPromises(dropzone)
@@ -523,10 +935,15 @@ describe('Dropzone', () => {
523
935
  expect(child).toHaveProp('isDragReject', true)
524
936
  })
525
937
 
526
- it('should set proper dragAccept state if multiple is false', async () => {
938
+ it('should set proper dragActive state if multiple is false', async () => {
527
939
  const dropzone = mount(
528
940
  <Dropzone accept="image/*" multiple={false}>
529
- {props => <DummyChildComponent {...props} />}
941
+ {({ getRootProps, getInputProps, ...rest }) => (
942
+ <div {...getRootProps()}>
943
+ <input {...getInputProps()} />
944
+ <DummyChildComponent {...rest} />
945
+ </div>
946
+ )}
530
947
  </Dropzone>
531
948
  )
532
949
  dropzone.simulate('dragEnter', createDtWithFiles(files))
@@ -540,7 +957,12 @@ describe('Dropzone', () => {
540
957
  it('should set proper dragAccept state if multiple is false', async () => {
541
958
  const dropzone = mount(
542
959
  <Dropzone accept="image/*" multiple={false}>
543
- {props => <DummyChildComponent {...props} />}
960
+ {({ getRootProps, getInputProps, ...rest }) => (
961
+ <div {...getRootProps()}>
962
+ <input {...getInputProps()} />
963
+ <DummyChildComponent {...rest} />
964
+ </div>
965
+ )}
544
966
  </Dropzone>
545
967
  )
546
968
  dropzone.simulate('dragEnter', createDtWithFiles(images))
@@ -551,149 +973,34 @@ describe('Dropzone', () => {
551
973
  expect(child).toHaveProp('isDragReject', true)
552
974
  })
553
975
 
554
- it('should set activeClassName properly', async () => {
555
- const dropzone = mount(
556
- <Dropzone accept="image/*" activeClassName="👏" multiple={false}>
557
- {props => <DummyChildComponent {...props} />}
558
- </Dropzone>
559
- )
560
- dropzone.simulate('dragEnter', createDtWithFiles(images))
561
- const updatedDropzone = await flushPromises(dropzone)
562
- const child = updatedDropzone.find(DummyChildComponent)
563
- expect(child).toHaveProp('isDragActive', true)
564
- expect(
565
- dropzone
566
- .children()
567
- .first()
568
- .hasClass('👏')
569
- ).toBe(true)
570
- })
571
-
572
- it('should set rejectClassName properly', async () => {
573
- const dropzone = mount(
574
- <Dropzone accept="image/*" rejectClassName="👎" multiple={false}>
575
- {props => <DummyChildComponent {...props} />}
576
- </Dropzone>
577
- )
578
- dropzone.simulate('dragEnter', createDtWithFiles(images))
579
- const updatedDropzone = await flushPromises(dropzone)
580
- const child = updatedDropzone.find(DummyChildComponent)
581
- expect(child).toHaveProp('isDragReject', true)
582
- expect(
583
- dropzone
584
- .children()
585
- .first()
586
- .hasClass('👎')
587
- ).toBe(true)
588
- })
589
-
590
- it('should set acceptClassName properly', async () => {
976
+ it('should keep dragging active when leaving from arbitrary node', async () => {
977
+ const arbitraryOverlay = mount(<div />)
591
978
  const dropzone = mount(
592
- <Dropzone accept="image/*" acceptClassName="👍" className="foo" multiple={false}>
593
- {props => <DummyChildComponent {...props} />}
594
- </Dropzone>
595
- )
596
- dropzone.simulate('dragEnter', createDtWithFiles(images))
597
- const updatedDropzone = await flushPromises(dropzone)
598
- const child = updatedDropzone.find(DummyChildComponent)
599
- expect(child).toHaveProp('isDragAccept', true)
600
- expect(
601
- updatedDropzone
602
- .children()
603
- .first()
604
- .hasClass('👍')
605
- ).toBe(true)
606
- })
607
-
608
- it('should set disabledClassName properly', () => {
609
- const dropzone = render(
610
- <Dropzone disabled disabledClassName="🤐">
611
- {props => <DummyChildComponent {...props} />}
979
+ <Dropzone>
980
+ {({ getRootProps, getInputProps, ...rest }) => (
981
+ <div {...getRootProps()}>
982
+ <input {...getInputProps()} />
983
+ <DummyChildComponent {...rest} />
984
+ </div>
985
+ )}
612
986
  </Dropzone>
613
987
  )
614
- expect(dropzone.hasClass('🤐')).toBe(true)
615
- })
616
-
617
- it('should keep dragging active when leaving from arbitrary node', async () => {
618
- const arbitraryOverlay = mount(<div />)
619
- const dropzone = mount(<Dropzone>{props => <DummyChildComponent {...props} />}</Dropzone>)
620
988
  await dropzone.simulate('dragEnter', createDtWithFiles(images))
621
989
  dropzone.simulate('dragLeave', { target: arbitraryOverlay })
622
990
  expect(dropzone.state('isDragActive')).toBe(true)
623
991
  expect(dropzone.state('draggedFiles').length > 0).toBe(true)
624
992
  })
625
993
 
626
- it('should apply default active style on drag enter if file data cannot be accessed', async () => {
627
- const dropzone = mount(<Dropzone />)
628
- await dropzone.simulate('dragEnter', createDtWithFiles([]))
629
- await flushPromises(dropzone)
630
- const mainDiv = dropzone.find('div').at(0)
631
- expect(mainDiv).toHaveProp('style', {
632
- position: 'relative',
633
- ...styles.default,
634
- ...styles.active
635
- })
636
- })
637
-
638
- it('should apply acceptStyle if multiple is false and single file', async () => {
639
- const dropzone = mount(
640
- <Dropzone
641
- accept="image/*"
642
- multiple={false}
643
- acceptStyle={acceptStyle}
644
- rejectStyle={rejectStyle}
645
- >
646
- {props => <DummyChildComponent {...props} />}
647
- </Dropzone>
648
- )
649
- dropzone.simulate('dragEnter', createDtWithFiles([images[0]]))
650
- const updatedDropzone = await flushPromises(dropzone)
651
- const mainDiv = updatedDropzone.find('div').at(0)
652
- expect(mainDiv).toHaveProp('style', { position: 'relative', ...acceptStyle })
653
- })
654
-
655
- it('should apply rejectStyle if multiple is false and single bad file type', async () => {
656
- const dropzone = mount(
657
- <Dropzone
658
- accept="image/*"
659
- multiple={false}
660
- acceptStyle={acceptStyle}
661
- rejectStyle={rejectStyle}
662
- >
663
- {props => <DummyChildComponent {...props} />}
664
- </Dropzone>
665
- )
666
- dropzone.simulate('dragEnter', createDtWithFiles([files[0]]))
667
- const updatedDropzone = await flushPromises(dropzone)
668
- const mainDiv = updatedDropzone.find('div').at(0)
669
- expect(mainDiv).toHaveProp('style', { position: 'relative', ...rejectStyle })
670
- })
671
-
672
- it('should apply acceptStyle + rejectStyle if multiple is false and multiple good file types', async () => {
673
- const dropzone = mount(
674
- <Dropzone
675
- accept="image/*"
676
- multiple={false}
677
- acceptStyle={acceptStyle}
678
- rejectStyle={rejectStyle}
679
- >
680
- {props => <DummyChildComponent {...props} />}
681
- </Dropzone>
682
- )
683
- dropzone.simulate('dragEnter', createDtWithFiles(images))
684
- const updatedDropzone = await flushPromises(dropzone)
685
- const mainDiv = updatedDropzone.find('div').at(0)
686
- const expectedStyle = {
687
- position: 'relative',
688
- ...acceptStyle,
689
- ...rejectStyle
690
- }
691
- expect(mainDiv).toHaveProp('style', expectedStyle)
692
- })
693
-
694
994
  it('should set proper dragActive state if accept prop changes mid-drag', async () => {
695
995
  const dropzone = mount(
696
- <Dropzone accept="image/*">{props => <DummyChildComponent {...props} />}</Dropzone>
996
+ <Dropzone accept="image/*">
997
+ {({ getRootProps, getInputProps, ...rest }) => (
998
+ <div {...getRootProps()}>
999
+ <input {...getInputProps()} />
1000
+ <DummyChildComponent {...rest} />
1001
+ </div>
1002
+ )}
1003
+ </Dropzone>
697
1004
  )
698
1005
  dropzone.simulate('dragEnter', createDtWithFiles(images))
699
1006
  const updatedDropzone = await flushPromises(dropzone)
@@ -710,15 +1017,14 @@ describe('Dropzone', () => {
710
1017
  it('should expose state to children', async () => {
711
1018
  const dropzone = mount(
712
1019
  <Dropzone accept="image/*">
713
- {({ isDragActive, isDragAccept, isDragReject }) => {
714
- if (isDragReject) {
715
- return `${isDragActive && 'Active but'} Reject`
716
- }
717
- if (isDragAccept) {
718
- return `${isDragActive && 'Active and'} Accept`
719
- }
720
- return 'Empty'
721
- }}
1020
+ {({ getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject }) => (
1021
+ <div {...getRootProps()}>
1022
+ <input {...getInputProps()} />
1023
+ {isDragReject && `${isDragActive && 'Active but'} Reject`}
1024
+ {isDragAccept && `${isDragActive && 'Active and'} Accept`}
1025
+ {!isDragActive && 'Empty'}
1026
+ </div>
1027
+ )}
722
1028
  </Dropzone>
723
1029
  )
724
1030
  expect(dropzone.text()).toEqual('Empty')
@@ -728,20 +1034,23 @@ describe('Dropzone', () => {
728
1034
  expect(dropzone.text()).toEqual('Active but Reject')
729
1035
  })
730
1036
 
731
- it('should reset the dragAccept/dragReject state when leaving after a child goes away', async () => {
1037
+ it('should reset the dragActive/dragReject state when leaving after a child goes away', async () => {
732
1038
  const DragActiveComponent = () => <p>Accept</p>
733
1039
  const ChildComponent = () => <p>Child component content</p>
734
1040
  const dropzone = mount(
735
1041
  <Dropzone>
736
- {({ isDragAccept, isDragReject }) => {
737
- if (isDragReject) {
738
- return 'Rejected'
739
- }
740
- if (isDragAccept) {
741
- return <DragActiveComponent isDragAccept={isDragAccept} isDragReject={isDragReject} />
742
- }
743
- return <ChildComponent isDragAccept={isDragAccept} isDragReject={isDragReject} />
744
- }}
1042
+ {({ getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject }) => (
1043
+ <div {...getRootProps()}>
1044
+ <input {...getInputProps()} />
1045
+ {isDragReject && 'Rejected'}
1046
+ {isDragAccept && (
1047
+ <DragActiveComponent isDragAccept={isDragAccept} isDragReject={isDragReject} />
1048
+ )}
1049
+ {!isDragActive && (
1050
+ <ChildComponent isDragAccept={isDragAccept} isDragReject={isDragReject} />
1051
+ )}
1052
+ </div>
1053
+ )}
745
1054
  </Dropzone>
746
1055
  )
747
1056
  const child = dropzone.find(ChildComponent)
@@ -761,21 +1070,43 @@ describe('Dropzone', () => {
761
1070
  })
762
1071
  })
763
1072
 
764
- it('should expose open func to children', () => {
765
- const subject = mount(
766
- <Dropzone disableClick>
767
- {({ open }) => (
768
- <button type="button" onClick={open}>
769
- Open
770
- </button>
771
- )}
772
- </Dropzone>
773
- )
1073
+ describe('open() fn', () => {
1074
+ it('should be exposed to children', () => {
1075
+ const subject = mount(
1076
+ <Dropzone disableClick>
1077
+ {({ getRootProps, getInputProps, open }) => (
1078
+ <div {...getRootProps()}>
1079
+ <input {...getInputProps()} />
1080
+ <button type="button" onClick={open}>
1081
+ Open
1082
+ </button>
1083
+ </div>
1084
+ )}
1085
+ </Dropzone>
1086
+ )
1087
+
1088
+ const click = jest.spyOn(subject.instance().input, 'click')
1089
+ subject.find('button').simulate('click')
774
1090
 
775
- const click = jest.spyOn(subject.instance().fileInputEl, 'click')
776
- subject.find('button').simulate('click')
1091
+ expect(click).toHaveBeenCalled()
1092
+ })
777
1093
 
778
- expect(click).toHaveBeenCalled()
1094
+ it('should do nothing if the <input> is missing', () => {
1095
+ const dropzone = mount(
1096
+ <Dropzone>
1097
+ {({ getRootProps, open }) => (
1098
+ <div {...getRootProps()}>
1099
+ <button type="button" onClick={open}>
1100
+ Open
1101
+ </button>
1102
+ </div>
1103
+ )}
1104
+ </Dropzone>
1105
+ )
1106
+
1107
+ const fn = () => dropzone.find('button').simulate('click')
1108
+ expect(fn).not.toThrow()
1109
+ })
779
1110
  })
780
1111
 
781
1112
  it('invokes onDop cb when native file section occurs', async () => {
@@ -785,7 +1116,15 @@ describe('Dropzone', () => {
785
1116
  onDropRejected: jest.fn()
786
1117
  }
787
1118
 
788
- const component = mount(<Dropzone {...props} />)
1119
+ const component = mount(
1120
+ <Dropzone {...props}>
1121
+ {({ getRootProps, getInputProps }) => (
1122
+ <div {...getRootProps()}>
1123
+ <input {...getInputProps()} />
1124
+ </div>
1125
+ )}
1126
+ </Dropzone>
1127
+ )
789
1128
 
790
1129
  const input = component.find('input')
791
1130
  const evt = {
@@ -811,7 +1150,14 @@ describe('Dropzone', () => {
811
1150
 
812
1151
  it('should update the acceptedFiles/rejectedFiles state', async () => {
813
1152
  let dropzone = mount(
814
- <Dropzone accept="image/*">{props => <DummyChildComponent {...props} />}</Dropzone>
1153
+ <Dropzone accept="image/*">
1154
+ {({ getRootProps, getInputProps, ...restProps }) => (
1155
+ <div {...getRootProps()}>
1156
+ <input {...getInputProps()} />
1157
+ <DummyChildComponent {...restProps} />
1158
+ </div>
1159
+ )}
1160
+ </Dropzone>
815
1161
  )
816
1162
  dropzone.simulate('drop', createDtWithFiles(files))
817
1163
  dropzone = await flushPromises(dropzone)
@@ -825,7 +1171,16 @@ describe('Dropzone', () => {
825
1171
  })
826
1172
 
827
1173
  it('should reset the dragActive/dragReject state', async () => {
828
- let dropzone = mount(<Dropzone>{props => <DummyChildComponent {...props} />}</Dropzone>)
1174
+ let dropzone = mount(
1175
+ <Dropzone>
1176
+ {({ getRootProps, getInputProps, ...restProps }) => (
1177
+ <div {...getRootProps()}>
1178
+ <input {...getInputProps()} />
1179
+ <DummyChildComponent {...restProps} />
1180
+ </div>
1181
+ )}
1182
+ </Dropzone>
1183
+ )
829
1184
  dropzone.simulate('dragEnter', createDtWithFiles(files))
830
1185
  dropzone = await flushPromises(dropzone)
831
1186
  expect(dropzone.find(DummyChildComponent)).toHaveProp('isDragActive', true)
@@ -837,40 +1192,89 @@ describe('Dropzone', () => {
837
1192
  })
838
1193
 
839
1194
  it('should reject invalid file when multiple is false', async () => {
840
- const dropzone = mount(<Dropzone accept="image/*" onDrop={onDrop} multiple={false} />)
1195
+ const dropzone = mount(
1196
+ <Dropzone accept="image/*" onDrop={onDrop} multiple={false}>
1197
+ {({ getRootProps, getInputProps }) => (
1198
+ <div {...getRootProps()}>
1199
+ <input {...getInputProps()} />
1200
+ </div>
1201
+ )}
1202
+ </Dropzone>
1203
+ )
841
1204
  await dropzone.simulate('drop', createDtWithFiles(files))
842
1205
  expect(onDrop).toHaveBeenCalledWith([], files, expectedEvent)
843
1206
  })
844
1207
 
845
1208
  it('should allow single files to be dropped if multiple is false', async () => {
846
- const dropzone = mount(<Dropzone accept="image/*" onDrop={onDrop} multiple={false} />)
1209
+ const dropzone = mount(
1210
+ <Dropzone accept="image/*" onDrop={onDrop} multiple={false}>
1211
+ {({ getRootProps, getInputProps }) => (
1212
+ <div {...getRootProps()}>
1213
+ <input {...getInputProps()} />
1214
+ </div>
1215
+ )}
1216
+ </Dropzone>
1217
+ )
847
1218
 
848
1219
  await dropzone.simulate('drop', createDtWithFiles([images[0]]))
849
1220
  expect(onDrop).toHaveBeenCalledWith([images[0]], [], expectedEvent)
850
1221
  })
851
1222
 
852
1223
  it('should reject multiple files to be dropped if multiple is false', async () => {
853
- const dropzone = mount(<Dropzone accept="image/*" onDrop={onDrop} multiple={false} />)
1224
+ const dropzone = mount(
1225
+ <Dropzone accept="image/*" onDrop={onDrop} multiple={false}>
1226
+ {({ getRootProps, getInputProps }) => (
1227
+ <div {...getRootProps()}>
1228
+ <input {...getInputProps()} />
1229
+ </div>
1230
+ )}
1231
+ </Dropzone>
1232
+ )
854
1233
 
855
1234
  await dropzone.simulate('drop', createDtWithFiles(images))
856
1235
  expect(onDrop).toHaveBeenCalledWith([], images, expectedEvent)
857
1236
  })
858
1237
 
859
1238
  it('should take all dropped files if multiple is true', async () => {
860
- const dropzone = mount(<Dropzone onDrop={onDrop} multiple />)
1239
+ const dropzone = mount(
1240
+ <Dropzone onDrop={onDrop} multiple>
1241
+ {({ getRootProps, getInputProps }) => (
1242
+ <div {...getRootProps()}>
1243
+ <input {...getInputProps()} />
1244
+ </div>
1245
+ )}
1246
+ </Dropzone>
1247
+ )
861
1248
  await dropzone.simulate('drop', createDtWithFiles(images))
862
1249
  expect(onDrop).toHaveBeenCalledWith(images, [], expectedEvent)
863
1250
  })
864
1251
 
865
1252
  it('should set this.isFileDialogActive to false', async () => {
866
- const dropzone = mount(<Dropzone />)
1253
+ const dropzone = mount(
1254
+ <Dropzone>
1255
+ {({ getRootProps, getInputProps }) => (
1256
+ <div {...getRootProps()}>
1257
+ <input {...getInputProps()} />
1258
+ </div>
1259
+ )}
1260
+ </Dropzone>
1261
+ )
867
1262
  dropzone.instance().isFileDialogActive = true
868
1263
  await dropzone.simulate('drop', createDtWithFiles(files))
869
1264
  expect(dropzone.instance().isFileDialogActive).toEqual(false)
870
1265
  })
871
1266
 
872
1267
  it('should always call onDrop callback with accepted and rejected arguments', async () => {
873
- const dropzone = mount(<Dropzone onDrop={onDrop} accept="image/*" />)
1268
+ const dropzone = mount(
1269
+ <Dropzone onDrop={onDrop} accept="image/*">
1270
+ {({ getRootProps, getInputProps }) => (
1271
+ <div {...getRootProps()}>
1272
+ <input {...getInputProps()} />
1273
+ </div>
1274
+ )}
1275
+ </Dropzone>
1276
+ )
1277
+
874
1278
  await dropzone.simulate('drop', createDtWithFiles(files))
875
1279
  expect(onDrop).toHaveBeenCalledWith([], files, expectedEvent)
876
1280
  onDrop.mockClear()
@@ -884,7 +1288,16 @@ describe('Dropzone', () => {
884
1288
  })
885
1289
 
886
1290
  it('should call onDropAccepted callback if some files were accepted', async () => {
887
- const dropzone = mount(<Dropzone onDropAccepted={onDropAccepted} accept="image/*" />)
1291
+ const dropzone = mount(
1292
+ <Dropzone onDropAccepted={onDropAccepted} accept="image/*">
1293
+ {({ getRootProps, getInputProps }) => (
1294
+ <div {...getRootProps()}>
1295
+ <input {...getInputProps()} />
1296
+ </div>
1297
+ )}
1298
+ </Dropzone>
1299
+ )
1300
+
888
1301
  await dropzone.simulate('drop', createDtWithFiles(files))
889
1302
  expect(onDropAccepted).not.toHaveBeenCalled()
890
1303
  onDropAccepted.mockClear()
@@ -898,7 +1311,16 @@ describe('Dropzone', () => {
898
1311
  })
899
1312
 
900
1313
  it('should call onDropRejected callback if some files were rejected', async () => {
901
- const dropzone = mount(<Dropzone onDropRejected={onDropRejected} accept="image/*" />)
1314
+ const dropzone = mount(
1315
+ <Dropzone onDropRejected={onDropRejected} accept="image/*">
1316
+ {({ getRootProps, getInputProps }) => (
1317
+ <div {...getRootProps()}>
1318
+ <input {...getInputProps()} />
1319
+ </div>
1320
+ )}
1321
+ </Dropzone>
1322
+ )
1323
+
902
1324
  await dropzone.simulate('drop', createDtWithFiles(images))
903
1325
  expect(onDropRejected).not.toHaveBeenCalled()
904
1326
  onDropRejected.mockClear()
@@ -918,7 +1340,13 @@ describe('Dropzone', () => {
918
1340
  onDropAccepted={onDropAccepted}
919
1341
  onDropRejected={onDropRejected}
920
1342
  accept="image/*"
921
- />
1343
+ >
1344
+ {({ getRootProps, getInputProps }) => (
1345
+ <div {...getRootProps()}>
1346
+ <input {...getInputProps()} />
1347
+ </div>
1348
+ )}
1349
+ </Dropzone>
922
1350
  )
923
1351
  await dropzone.simulate('drop', createDtWithFiles(files))
924
1352
  expect(onDrop).toHaveBeenCalledWith([], files, expectedEvent)
@@ -933,7 +1361,13 @@ describe('Dropzone', () => {
933
1361
  onDropAccepted={onDropAccepted}
934
1362
  onDropRejected={onDropRejected}
935
1363
  accept="image/*"
936
- />
1364
+ >
1365
+ {({ getRootProps, getInputProps }) => (
1366
+ <div {...getRootProps()}>
1367
+ <input {...getInputProps()} />
1368
+ </div>
1369
+ )}
1370
+ </Dropzone>
937
1371
  )
938
1372
 
939
1373
  await dropzone.simulate('drop', createDtWithFiles(images))
@@ -949,7 +1383,13 @@ describe('Dropzone', () => {
949
1383
  onDropAccepted={onDropAccepted}
950
1384
  onDropRejected={onDropRejected}
951
1385
  accept="image/*"
952
- />
1386
+ >
1387
+ {({ getRootProps, getInputProps }) => (
1388
+ <div {...getRootProps()}>
1389
+ <input {...getInputProps()} />
1390
+ </div>
1391
+ )}
1392
+ </Dropzone>
953
1393
  )
954
1394
  const bogusImages = [createFile('bogus.gif', 1234, 'application/x-moz-file')]
955
1395
 
@@ -961,7 +1401,13 @@ describe('Dropzone', () => {
961
1401
 
962
1402
  it('accepts all dropped files and images when no accept prop is specified', async () => {
963
1403
  const dropzone = mount(
964
- <Dropzone onDrop={onDrop} onDropAccepted={onDropAccepted} onDropRejected={onDropRejected} />
1404
+ <Dropzone onDrop={onDrop} onDropAccepted={onDropAccepted} onDropRejected={onDropRejected}>
1405
+ {({ getRootProps, getInputProps }) => (
1406
+ <div {...getRootProps()}>
1407
+ <input {...getInputProps()} />
1408
+ </div>
1409
+ )}
1410
+ </Dropzone>
965
1411
  )
966
1412
  await dropzone.simulate('drop', createDtWithFiles(files.concat(images)))
967
1413
  expect(onDrop).toHaveBeenCalledWith(files.concat(images), [], expectedEvent)
@@ -976,7 +1422,13 @@ describe('Dropzone', () => {
976
1422
  onDropAccepted={onDropAccepted}
977
1423
  onDropRejected={onDropRejected}
978
1424
  maxSize={1111}
979
- />
1425
+ >
1426
+ {({ getRootProps, getInputProps }) => (
1427
+ <div {...getRootProps()}>
1428
+ <input {...getInputProps()} />
1429
+ </div>
1430
+ )}
1431
+ </Dropzone>
980
1432
  )
981
1433
 
982
1434
  await dropzone.simulate('drop', createDtWithFiles(files))
@@ -992,7 +1444,13 @@ describe('Dropzone', () => {
992
1444
  onDropAccepted={onDropAccepted}
993
1445
  onDropRejected={onDropRejected}
994
1446
  maxSize={1111}
995
- />
1447
+ >
1448
+ {({ getRootProps, getInputProps }) => (
1449
+ <div {...getRootProps()}>
1450
+ <input {...getInputProps()} />
1451
+ </div>
1452
+ )}
1453
+ </Dropzone>
996
1454
  )
997
1455
  await dropzone.simulate('drop', createDtWithFiles(images))
998
1456
  expect(onDrop).toHaveBeenCalledWith([], images, expectedEvent)
@@ -1007,7 +1465,13 @@ describe('Dropzone', () => {
1007
1465
  onDropAccepted={onDropAccepted}
1008
1466
  onDropRejected={onDropRejected}
1009
1467
  minSize={1112}
1010
- />
1468
+ >
1469
+ {({ getRootProps, getInputProps }) => (
1470
+ <div {...getRootProps()}>
1471
+ <input {...getInputProps()} />
1472
+ </div>
1473
+ )}
1474
+ </Dropzone>
1011
1475
  )
1012
1476
  await dropzone.simulate('drop', createDtWithFiles(files))
1013
1477
  expect(onDrop).toHaveBeenCalledWith([], files, expectedEvent)
@@ -1022,7 +1486,13 @@ describe('Dropzone', () => {
1022
1486
  onDropAccepted={onDropAccepted}
1023
1487
  onDropRejected={onDropRejected}
1024
1488
  minSize={1112}
1025
- />
1489
+ >
1490
+ {({ getRootProps, getInputProps }) => (
1491
+ <div {...getRootProps()}>
1492
+ <input {...getInputProps()} />
1493
+ </div>
1494
+ )}
1495
+ </Dropzone>
1026
1496
  )
1027
1497
  await dropzone.simulate('drop', createDtWithFiles(images))
1028
1498
  expect(onDrop).toHaveBeenCalledWith(images, [], expectedEvent)
@@ -1032,7 +1502,13 @@ describe('Dropzone', () => {
1032
1502
 
1033
1503
  it('accepts all dropped files and images when no size prop is specified', async () => {
1034
1504
  const dropzone = mount(
1035
- <Dropzone onDrop={onDrop} onDropAccepted={onDropAccepted} onDropRejected={onDropRejected} />
1505
+ <Dropzone onDrop={onDrop} onDropAccepted={onDropAccepted} onDropRejected={onDropRejected}>
1506
+ {({ getRootProps, getInputProps }) => (
1507
+ <div {...getRootProps()}>
1508
+ <input {...getInputProps()} />
1509
+ </div>
1510
+ )}
1511
+ </Dropzone>
1036
1512
  )
1037
1513
  await dropzone.simulate('drop', createDtWithFiles(files.concat(images)))
1038
1514
  expect(onDrop).toHaveBeenCalledWith(files.concat(images), [], expectedEvent)
@@ -1052,7 +1528,15 @@ describe('Dropzone', () => {
1052
1528
 
1053
1529
  it('should not invoke onFileDialogCancel everytime window receives focus', () => {
1054
1530
  const onFileDialogCancel = jest.fn()
1055
- mount(<Dropzone id="on-cancel-example" onFileDialogCancel={onFileDialogCancel} />)
1531
+ mount(
1532
+ <Dropzone onFileDialogCancel={onFileDialogCancel}>
1533
+ {({ getRootProps, getInputProps }) => (
1534
+ <div id="on-cancel-example" {...getRootProps()}>
1535
+ <input {...getInputProps()} />
1536
+ </div>
1537
+ )}
1538
+ </Dropzone>
1539
+ )
1056
1540
  // Simulated DOM event - onfocus
1057
1541
  document.body.addEventListener('focus', () => {})
1058
1542
  const evt = document.createEvent('HTMLEvents')
@@ -1064,12 +1548,12 @@ describe('Dropzone', () => {
1064
1548
 
1065
1549
  it('should not invoke onFileDialogCancel if input does not exist', () => {
1066
1550
  const onFileDialogCancel = jest.fn()
1067
- const component = mount(
1068
- <Dropzone id="on-cancel-example" onFileDialogCancel={onFileDialogCancel} />
1551
+ mount(
1552
+ <Dropzone onFileDialogCancel={onFileDialogCancel}>
1553
+ {({ getRootProps }) => <div id="on-cancel-example" {...getRootProps()} />}
1554
+ </Dropzone>
1069
1555
  )
1070
1556
 
1071
- component.instance().setRefs(null)
1072
-
1073
1557
  document.body.addEventListener('focus', () => {})
1074
1558
  const evt = document.createEvent('HTMLEvents')
1075
1559
  evt.initEvent('focus', false, true)
@@ -1081,7 +1565,13 @@ describe('Dropzone', () => {
1081
1565
  it('should invoke onFileDialogCancel when window receives focus via cancel button and there were no files selected', () => {
1082
1566
  const onFileDialogCancel = jest.fn()
1083
1567
  const component = mount(
1084
- <Dropzone className="dropzone-content" onFileDialogCancel={onFileDialogCancel} />
1568
+ <Dropzone onFileDialogCancel={onFileDialogCancel}>
1569
+ {({ getRootProps, getInputProps }) => (
1570
+ <div className="dropzone-content" {...getRootProps()}>
1571
+ <input {...getInputProps()} />
1572
+ </div>
1573
+ )}
1574
+ </Dropzone>
1085
1575
  )
1086
1576
 
1087
1577
  // Test / invoke the click event
@@ -1103,7 +1593,13 @@ describe('Dropzone', () => {
1103
1593
  it('should not invoke onFileDialogCancel when window receives focus via cancel button and there were files selected', () => {
1104
1594
  const onFileDialogCancel = jest.fn()
1105
1595
  const component = mount(
1106
- <Dropzone className="dropzone-content" onFileDialogCancel={onFileDialogCancel} />
1596
+ <Dropzone onFileDialogCancel={onFileDialogCancel}>
1597
+ {({ getRootProps, getInputProps }) => (
1598
+ <div className="dropzone-content" {...getRootProps()}>
1599
+ <input {...getInputProps()} />
1600
+ </div>
1601
+ )}
1602
+ </Dropzone>
1107
1603
  )
1108
1604
 
1109
1605
  // Test / invoke the click event
@@ -1129,7 +1625,15 @@ describe('Dropzone', () => {
1129
1625
  })
1130
1626
 
1131
1627
  it('should restore isFileDialogActive to false after the FileDialog was closed', () => {
1132
- const component = mount(<Dropzone />)
1628
+ const component = mount(
1629
+ <Dropzone>
1630
+ {({ getRootProps, getInputProps }) => (
1631
+ <div {...getRootProps()}>
1632
+ <input {...getInputProps()} />
1633
+ </div>
1634
+ )}
1635
+ </Dropzone>
1636
+ )
1133
1637
 
1134
1638
  component.simulate('click')
1135
1639
 
@@ -1163,18 +1667,28 @@ describe('Dropzone', () => {
1163
1667
  onDropRejected={onInnerDropRejected}
1164
1668
  accept="image/*"
1165
1669
  >
1166
- {({ isDragActive, isDragReject }) => {
1167
- if (isDragReject) return <InnerDragRejected />
1168
- if (isDragActive) return <InnerDragAccepted />
1169
- return <p>No drag</p>
1170
- }}
1670
+ {({ getRootProps, getInputProps, isDragAccept, isDragReject, isDragActive }) => (
1671
+ <div {...getRootProps()}>
1672
+ <input {...getInputProps()} />
1673
+ {isDragReject && <InnerDragRejected />}
1674
+ {isDragAccept && <InnerDragAccepted />}
1675
+ {!isDragActive && <p>No drag</p>}
1676
+ </div>
1677
+ )}
1171
1678
  </Dropzone>
1172
1679
  )
1173
1680
 
1174
1681
  describe('dropping on the inner dropzone', () => {
1175
1682
  it('does dragEnter on both dropzones', async () => {
1176
1683
  const outerDropzone = mount(
1177
- <Dropzone accept="image/*">{props => <InnerDropzone {...props} />}</Dropzone>
1684
+ <Dropzone accept="image/*">
1685
+ {({ getRootProps, getInputProps, ...restProps }) => (
1686
+ <div {...getRootProps()}>
1687
+ <input {...getInputProps()} />
1688
+ <InnerDropzone {...restProps} />
1689
+ </div>
1690
+ )}
1691
+ </Dropzone>
1178
1692
  )
1179
1693
  outerDropzone.find(InnerDropzone).simulate('dragEnter', createDtWithFiles(images))
1180
1694
  const updatedOuterDropzone = await flushPromises(outerDropzone)
@@ -1194,7 +1708,12 @@ describe('Dropzone', () => {
1194
1708
  onDropRejected={onOuterDropRejected}
1195
1709
  accept="image/*"
1196
1710
  >
1197
- {props => <InnerDropzone {...props} />}
1711
+ {({ getRootProps, getInputProps, ...restProps }) => (
1712
+ <div {...getRootProps()}>
1713
+ <input {...getInputProps()} />
1714
+ <InnerDropzone {...restProps} />
1715
+ </div>
1716
+ )}
1198
1717
  </Dropzone>
1199
1718
  )
1200
1719
 
@@ -1221,7 +1740,12 @@ describe('Dropzone', () => {
1221
1740
  onDropRejected={onOuterDropRejected}
1222
1741
  accept="image/*"
1223
1742
  >
1224
- {props => <InnerDropzone {...props} />}
1743
+ {({ getRootProps, getInputProps, ...restProps }) => (
1744
+ <div {...getRootProps()}>
1745
+ <input {...getInputProps()} />
1746
+ <InnerDropzone {...restProps} />
1747
+ </div>
1748
+ )}
1225
1749
  </Dropzone>
1226
1750
  )
1227
1751
 
@@ -1254,12 +1778,23 @@ describe('Dropzone', () => {
1254
1778
  onDragOver={evt => evt.stopPropagation()}
1255
1779
  onDragLeave={evt => evt.stopPropagation()}
1256
1780
  onDrop={(accepted, rejected, evt) => evt.stopPropagation()}
1257
- />
1781
+ >
1782
+ {({ getRootProps, getInputProps }) => (
1783
+ <div {...getRootProps()}>
1784
+ <input {...getInputProps()} />
1785
+ </div>
1786
+ )}
1787
+ </Dropzone>
1258
1788
  )
1259
1789
 
1260
1790
  const outerDropzone = mount(
1261
1791
  <Dropzone {...parentProps}>
1262
- <InnerDropzone />
1792
+ {({ getRootProps, getInputProps, ...restProps }) => (
1793
+ <div {...getRootProps()}>
1794
+ <input {...getInputProps()} />
1795
+ <InnerDropzone {...restProps} />
1796
+ </div>
1797
+ )}
1263
1798
  </Dropzone>
1264
1799
  )
1265
1800
 
@@ -1285,14 +1820,30 @@ describe('Dropzone', () => {
1285
1820
 
1286
1821
  describe('behavior', () => {
1287
1822
  it('does not throw an error when html is dropped instead of files and multiple is false', () => {
1288
- const dropzone = mount(<Dropzone multiple={false} />)
1823
+ const dropzone = mount(
1824
+ <Dropzone multiple={false}>
1825
+ {({ getRootProps, getInputProps }) => (
1826
+ <div {...getRootProps()}>
1827
+ <input {...getInputProps()} />
1828
+ </div>
1829
+ )}
1830
+ </Dropzone>
1831
+ )
1289
1832
 
1290
1833
  const fn = () => dropzone.simulate('drop', createDtWithFiles([]))
1291
1834
  expect(fn).not.toThrow()
1292
1835
  })
1293
1836
 
1294
1837
  it('does not allow actions when disabled props is true', () => {
1295
- const dropzone = mount(<Dropzone disabled />)
1838
+ const dropzone = mount(
1839
+ <Dropzone disabled>
1840
+ {({ getRootProps, getInputProps }) => (
1841
+ <div {...getRootProps()}>
1842
+ <input {...getInputProps()} />
1843
+ </div>
1844
+ )}
1845
+ </Dropzone>
1846
+ )
1296
1847
 
1297
1848
  const open = jest.spyOn(dropzone.instance(), 'open')
1298
1849
  dropzone.simulate('click')
@@ -1300,7 +1851,15 @@ describe('Dropzone', () => {
1300
1851
  })
1301
1852
 
1302
1853
  it('when toggle disabled props, Dropzone works as expected', () => {
1303
- const dropzone = mount(<Dropzone disabled />)
1854
+ const dropzone = mount(
1855
+ <Dropzone disabled>
1856
+ {({ getRootProps, getInputProps }) => (
1857
+ <div {...getRootProps()}>
1858
+ <input {...getInputProps()} />
1859
+ </div>
1860
+ )}
1861
+ </Dropzone>
1862
+ )
1304
1863
  const open = jest.spyOn(dropzone.instance(), 'open')
1305
1864
 
1306
1865
  dropzone.setProps({ disabled: false })
@@ -1316,7 +1875,12 @@ describe('Dropzone', () => {
1316
1875
  }
1317
1876
  let dropzone = mount(
1318
1877
  <Dropzone accept="image/*" onDrop={onDrop}>
1319
- {props => <DummyChildComponent {...props} />}
1878
+ {({ getRootProps, getInputProps, ...rest }) => (
1879
+ <div {...getRootProps()}>
1880
+ <input {...getInputProps()} />
1881
+ <DummyChildComponent {...rest} />
1882
+ </div>
1883
+ )}
1320
1884
  </Dropzone>
1321
1885
  )
1322
1886
  setState = jest.spyOn(dropzone.instance(), 'setState')
@@ -1324,6 +1888,43 @@ describe('Dropzone', () => {
1324
1888
  dropzone = await flushPromises(dropzone)
1325
1889
  expect(setState).not.toHaveBeenCalled()
1326
1890
  })
1891
+
1892
+ it('sets {tabindex} to 0 if the component is not disabled', async () => {
1893
+ const dropzone = mount(
1894
+ <Dropzone>
1895
+ {({ getRootProps, getInputProps }) => (
1896
+ <div {...getRootProps()}>
1897
+ <input {...getInputProps()} />
1898
+ </div>
1899
+ )}
1900
+ </Dropzone>
1901
+ )
1902
+ expect(
1903
+ dropzone
1904
+ .children()
1905
+ .first()
1906
+ .prop('tabIndex')
1907
+ ).toBe(0)
1908
+ })
1909
+
1910
+ it('sets {tabindex} to -1 if the component is disabled', async () => {
1911
+ const dropzone = mount(
1912
+ <Dropzone>
1913
+ {({ getRootProps, getInputProps }) => (
1914
+ <div {...getRootProps()}>
1915
+ <input {...getInputProps()} />
1916
+ </div>
1917
+ )}
1918
+ </Dropzone>
1919
+ )
1920
+ dropzone.setProps({ disabled: true })
1921
+ expect(
1922
+ dropzone
1923
+ .children()
1924
+ .first()
1925
+ .prop('tabIndex')
1926
+ ).toBe(-1)
1927
+ })
1327
1928
  })
1328
1929
 
1329
1930
  describe('plugin integration', () => {
@@ -1337,7 +1938,15 @@ describe('Dropzone', () => {
1337
1938
  onDrop: jest.fn()
1338
1939
  }
1339
1940
 
1340
- const dropzone = mount(<Dropzone {...props} />)
1941
+ const dropzone = mount(
1942
+ <Dropzone {...props}>
1943
+ {({ getRootProps, getInputProps }) => (
1944
+ <div {...getRootProps()}>
1945
+ <input {...getInputProps()} />
1946
+ </div>
1947
+ )}
1948
+ </Dropzone>
1949
+ )
1341
1950
 
1342
1951
  const data = JSON.stringify({ ping: true })
1343
1952
  const file = new File([data], name, {
@@ -1388,7 +1997,15 @@ describe('Dropzone', () => {
1388
1997
  onDrop: jest.fn()
1389
1998
  }
1390
1999
 
1391
- const dropzone = mount(<Dropzone {...props} />)
2000
+ const dropzone = mount(
2001
+ <Dropzone {...props}>
2002
+ {({ getRootProps, getInputProps }) => (
2003
+ <div {...getRootProps()}>
2004
+ <input {...getInputProps()} />
2005
+ </div>
2006
+ )}
2007
+ </Dropzone>
2008
+ )
1392
2009
 
1393
2010
  const items = [
1394
2011
  {