react-dropzone 16.0.0 → 18.0.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/README.md CHANGED
@@ -1,6 +1,9 @@
1
- ![react-dropzone logo](https://raw.githubusercontent.com/react-dropzone/react-dropzone/master/logo/logo.png)
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/react-dropzone/.github/main/brand/assets/logo.png" alt="react-dropzone logo" width="120" />
3
+ </p>
2
4
 
3
5
  # react-dropzone
6
+
4
7
  [![npm](https://img.shields.io/npm/v/react-dropzone.svg?style=flat-square)](https://www.npmjs.com/package/react-dropzone)
5
8
  ![Tests](https://img.shields.io/github/actions/workflow/status/react-dropzone/react-dropzone/test.yml?branch=master&style=flat-square&label=tests)
6
9
  [![codecov](https://img.shields.io/codecov/c/gh/react-dropzone/react-dropzone/master.svg?style=flat-square)](https://codecov.io/gh/react-dropzone/react-dropzone)
@@ -13,49 +16,48 @@ Simple React hook to create a HTML5-compliant drag'n'drop zone for files.
13
16
 
14
17
  Documentation and examples at https://react-dropzone.js.org. Source code at https://github.com/react-dropzone/react-dropzone/.
15
18
 
16
-
17
19
  ## Installation
20
+
18
21
  Install it from npm. `react-dropzone` ships as ESM and CommonJS with TypeScript types included, and works with any modern bundler ([Vite](https://vite.dev/), [webpack](https://webpack.js.org/), [Rspack](https://rspack.rs/), etc.).
19
22
 
20
23
  ```bash
21
24
  npm install react-dropzone
22
25
  ```
26
+
23
27
  or:
28
+
24
29
  ```bash
25
30
  yarn add react-dropzone
26
31
  ```
27
32
 
28
-
29
33
  ## Usage
34
+
30
35
  You can either use the hook:
31
36
 
32
37
  ```jsx static
33
- import React, {useCallback} from 'react'
34
- import {useDropzone} from 'react-dropzone'
38
+ import React, {useCallback} from "react";
39
+ import {useDropzone} from "react-dropzone";
35
40
 
36
41
  function MyDropzone() {
37
42
  const onDrop = useCallback(acceptedFiles => {
38
43
  // Do something with the files
39
- }, [])
40
- const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
44
+ }, []);
45
+ const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop});
41
46
 
42
47
  return (
43
48
  <div {...getRootProps()}>
44
49
  <input {...getInputProps()} />
45
- {
46
- isDragActive ?
47
- <p>Drop the files here ...</p> :
48
- <p>Drag 'n' drop some files here, or click to select files</p>
49
- }
50
+ {isDragActive ? <p>Drop the files here ...</p> : <p>Drag 'n' drop some files here, or click to select files</p>}
50
51
  </div>
51
- )
52
+ );
52
53
  }
53
54
  ```
54
55
 
55
56
  Or the wrapper component for the hook:
57
+
56
58
  ```jsx static
57
- import React from 'react'
58
- import Dropzone from 'react-dropzone'
59
+ import React from "react";
60
+ import Dropzone from "react-dropzone";
59
61
 
60
62
  <Dropzone onDrop={acceptedFiles => console.log(acceptedFiles)}>
61
63
  {({getRootProps, getInputProps}) => (
@@ -66,71 +68,72 @@ import Dropzone from 'react-dropzone'
66
68
  </div>
67
69
  </section>
68
70
  )}
69
- </Dropzone>
71
+ </Dropzone>;
70
72
  ```
71
73
 
72
74
  If you want to access file contents you have to use the [FileReader API](https://developer.mozilla.org/en-US/docs/Web/API/FileReader):
73
75
 
74
76
  ```jsx static
75
- import React, {useCallback} from 'react'
76
- import {useDropzone} from 'react-dropzone'
77
+ import React, {useCallback} from "react";
78
+ import {useDropzone} from "react-dropzone";
77
79
 
78
80
  function MyDropzone() {
79
- const onDrop = useCallback((acceptedFiles) => {
80
- acceptedFiles.forEach((file) => {
81
- const reader = new FileReader()
81
+ const onDrop = useCallback(acceptedFiles => {
82
+ acceptedFiles.forEach(file => {
83
+ const reader = new FileReader();
82
84
 
83
- reader.onabort = () => console.log('file reading was aborted')
84
- reader.onerror = () => console.log('file reading has failed')
85
+ reader.onabort = () => console.log("file reading was aborted");
86
+ reader.onerror = () => console.log("file reading has failed");
85
87
  reader.onload = () => {
86
- // Do whatever you want with the file contents
87
- const binaryStr = reader.result
88
- console.log(binaryStr)
89
- }
90
- reader.readAsArrayBuffer(file)
91
- })
92
-
93
- }, [])
94
- const {getRootProps, getInputProps} = useDropzone({onDrop})
88
+ // Do whatever you want with the file contents
89
+ const binaryStr = reader.result;
90
+ console.log(binaryStr);
91
+ };
92
+ reader.readAsArrayBuffer(file);
93
+ });
94
+ }, []);
95
+ const {getRootProps, getInputProps} = useDropzone({onDrop});
95
96
 
96
97
  return (
97
98
  <div {...getRootProps()}>
98
99
  <input {...getInputProps()} />
99
100
  <p>Drag 'n' drop some files here, or click to select files</p>
100
101
  </div>
101
- )
102
+ );
102
103
  }
103
104
  ```
104
105
 
105
-
106
106
  ## Dropzone Props Getters
107
+
107
108
  The dropzone property getters are just two functions that return objects with properties which you need to use to create the drag 'n' drop zone.
108
109
  The root properties can be applied to whatever element you want, whereas the input properties must be applied to an `<input>`:
110
+
109
111
  ```jsx static
110
- import React from 'react'
111
- import {useDropzone} from 'react-dropzone'
112
+ import React from "react";
113
+ import {useDropzone} from "react-dropzone";
112
114
 
113
115
  function MyDropzone() {
114
- const {getRootProps, getInputProps} = useDropzone()
116
+ const {getRootProps, getInputProps} = useDropzone();
115
117
 
116
118
  return (
117
119
  <div {...getRootProps()}>
118
120
  <input {...getInputProps()} />
119
121
  <p>Drag 'n' drop some files here, or click to select files</p>
120
122
  </div>
121
- )
123
+ );
122
124
  }
123
125
  ```
124
126
 
125
127
  Note that whatever other props you want to add to the element where the props from `getRootProps()` are set, you should always pass them through that function rather than applying them on the element itself.
126
128
  This is in order to avoid your props being overridden (or overriding the props returned by `getRootProps()`):
129
+
127
130
  ```jsx static
128
131
  <div
129
132
  {...getRootProps({
130
133
  onClick: event => console.log(event),
131
- role: 'button',
132
- 'aria-label': 'drag and drop area',
133
- ...
134
+ role: "button",
135
+ "aria-label": "drag and drop area"
136
+ // ...and any other props
134
137
  })}
135
138
  />
136
139
  ```
@@ -138,57 +141,62 @@ This is in order to avoid your props being overridden (or overriding the props r
138
141
  In the example above, the provided `{onClick}` handler will be invoked before the internal one, therefore, internal callbacks can be prevented by simply using [stopPropagation](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation).
139
142
  See [Events](https://react-dropzone.js.org#events) for more examples.
140
143
 
141
- *Important*: if you omit rendering an `<input>` and/or binding the props from `getInputProps()`, opening a file dialog will not be possible.
144
+ _Important_: if you omit rendering an `<input>` and/or binding the props from `getInputProps()`, opening a file dialog will not be possible.
142
145
 
143
146
  ## Refs
147
+
144
148
  Both `getRootProps` and `getInputProps` accept a custom `refKey` (defaults to `ref`) as one of the attributes passed down in the parameter.
145
149
 
146
150
  This can be useful when the element you're trying to apply the props from either one of those fns does not expose a reference to the element, e.g:
147
151
 
148
152
  ```jsx static
149
- import React from 'react'
150
- import {useDropzone} from 'react-dropzone'
153
+ import React from "react";
154
+ import {useDropzone} from "react-dropzone";
151
155
  // NOTE: After v4.0.0, styled components exposes a ref using forwardRef,
152
156
  // therefore, no need for using innerRef as refKey
153
- import styled from 'styled-components'
157
+ import styled from "styled-components";
154
158
 
155
159
  const StyledDiv = styled.div`
156
160
  // Some styling here
157
- `
161
+ `;
158
162
  function Example() {
159
- const {getRootProps, getInputProps} = useDropzone()
160
- <StyledDiv {...getRootProps({ refKey: 'innerRef' })}>
161
- <input {...getInputProps()} />
162
- <p>Drag 'n' drop some files here, or click to select files</p>
163
- </StyledDiv>
163
+ const {getRootProps, getInputProps} = useDropzone();
164
+ return (
165
+ <StyledDiv {...getRootProps({refKey: "innerRef"})}>
166
+ <input {...getInputProps()} />
167
+ <p>Drag 'n' drop some files here, or click to select files</p>
168
+ </StyledDiv>
169
+ );
164
170
  }
165
171
  ```
166
172
 
167
173
  If you're working with [Material UI v4](https://v4.mui.com/) and would like to apply the root props on some component that does not expose a ref, use [RootRef](https://v4.mui.com/api/root-ref/):
168
174
 
169
175
  ```jsx static
170
- import React from 'react'
171
- import {useDropzone} from 'react-dropzone'
172
- import RootRef from '@material-ui/core/RootRef'
176
+ import React from "react";
177
+ import {useDropzone} from "react-dropzone";
178
+ import RootRef from "@material-ui/core/RootRef";
173
179
 
174
180
  function PaperDropzone() {
175
- const {getRootProps, getInputProps} = useDropzone()
176
- const {ref, ...rootProps} = getRootProps()
181
+ const {getRootProps, getInputProps} = useDropzone();
182
+ const {ref, ...rootProps} = getRootProps();
177
183
 
178
- <RootRef rootRef={ref}>
179
- <Paper {...rootProps}>
180
- <input {...getInputProps()} />
181
- <p>Drag 'n' drop some files here, or click to select files</p>
182
- </Paper>
183
- </RootRef>
184
+ return (
185
+ <RootRef rootRef={ref}>
186
+ <Paper {...rootProps}>
187
+ <input {...getInputProps()} />
188
+ <p>Drag 'n' drop some files here, or click to select files</p>
189
+ </Paper>
190
+ </RootRef>
191
+ );
184
192
  }
185
193
  ```
186
194
 
187
195
  **IMPORTANT**: do not set the `ref` prop on the elements where `getRootProps()`/`getInputProps()` props are set, instead, get the refs from the hook itself:
188
196
 
189
197
  ```jsx static
190
- import React from 'react'
191
- import {useDropzone} from 'react-dropzone'
198
+ import React from "react";
199
+ import {useDropzone} from "react-dropzone";
192
200
 
193
201
  function Refs() {
194
202
  const {
@@ -196,21 +204,23 @@ function Refs() {
196
204
  getInputProps,
197
205
  rootRef, // Ref to the `<div>`
198
206
  inputRef // Ref to the `<input>`
199
- } = useDropzone()
200
- <div {...getRootProps()}>
201
- <input {...getInputProps()} />
202
- <p>Drag 'n' drop some files here, or click to select files</p>
203
- </div>
207
+ } = useDropzone();
208
+ return (
209
+ <div {...getRootProps()}>
210
+ <input {...getInputProps()} />
211
+ <p>Drag 'n' drop some files here, or click to select files</p>
212
+ </div>
213
+ );
204
214
  }
205
215
  ```
206
216
 
207
217
  If you're using the `<Dropzone>` component, though, you can set the `ref` prop on the component itself which will expose the `{open}` prop that can be used to open the file dialog programmatically:
208
218
 
209
219
  ```jsx static
210
- import React, {createRef} from 'react'
211
- import Dropzone from 'react-dropzone'
220
+ import React, {createRef} from "react";
221
+ import Dropzone from "react-dropzone";
212
222
 
213
- const dropzoneRef = createRef()
223
+ const dropzoneRef = createRef();
214
224
 
215
225
  <Dropzone ref={dropzoneRef}>
216
226
  {({getRootProps, getInputProps}) => (
@@ -219,101 +229,103 @@ const dropzoneRef = createRef()
219
229
  <p>Drag 'n' drop some files here, or click to select files</p>
220
230
  </div>
221
231
  )}
222
- </Dropzone>
232
+ </Dropzone>;
223
233
 
224
- dropzoneRef.open()
234
+ dropzoneRef.open();
225
235
  ```
226
236
 
227
-
228
237
  ## Testing
238
+
229
239
  `react-dropzone` makes some of its drag 'n' drop callbacks asynchronous to enable promise based `getFilesFromEvent()` functions. In order to test components that use this library, you need to use the [react-testing-library](https://github.com/testing-library/react-testing-library):
240
+
230
241
  ```js static
231
- import React from 'react'
232
- import Dropzone from 'react-dropzone'
233
- import {act, fireEvent, render} from '@testing-library/react'
242
+ import React from "react";
243
+ import Dropzone from "react-dropzone";
244
+ import {act, fireEvent, render} from "@testing-library/react";
234
245
 
235
- test('invoke onDragEnter when dragenter event occurs', async () => {
236
- const file = new File([
237
- JSON.stringify({ping: true})
238
- ], 'ping.json', { type: 'application/json' })
239
- const data = mockData([file])
240
- const onDragEnter = jest.fn()
246
+ test("invoke onDragEnter when dragenter event occurs", async () => {
247
+ const file = new File([JSON.stringify({ping: true})], "ping.json", {type: "application/json"});
248
+ const data = mockData([file]);
249
+ const onDragEnter = jest.fn();
241
250
 
242
251
  const ui = (
243
252
  <Dropzone onDragEnter={onDragEnter}>
244
- {({ getRootProps, getInputProps }) => (
253
+ {({getRootProps, getInputProps}) => (
245
254
  <div {...getRootProps()}>
246
255
  <input {...getInputProps()} />
247
256
  </div>
248
257
  )}
249
258
  </Dropzone>
250
- )
251
- const { container } = render(ui)
252
-
253
- await act(
254
- () => fireEvent.dragEnter(
255
- container.querySelector('div'),
256
- data,
257
- )
258
259
  );
259
- expect(onDragEnter).toHaveBeenCalled()
260
- })
260
+ const {container} = render(ui);
261
+
262
+ await act(() => fireEvent.dragEnter(container.querySelector("div"), data));
263
+ expect(onDragEnter).toHaveBeenCalled();
264
+ });
261
265
 
262
266
  function mockData(files) {
263
267
  return {
264
268
  dataTransfer: {
265
269
  files,
266
270
  items: files.map(file => ({
267
- kind: 'file',
271
+ kind: "file",
268
272
  type: file.type,
269
273
  getAsFile: () => file
270
274
  })),
271
- types: ['Files']
275
+ types: ["Files"]
272
276
  }
273
- }
277
+ };
274
278
  }
275
279
  ```
276
280
 
277
281
  **NOTE**: using [Enzyme](https://airbnb.io/enzyme) for testing is not supported at the moment, see [#2011](https://github.com/airbnb/enzyme/issues/2011).
278
282
 
279
- More examples for this can be found in `react-dropzone`'s own [test suites](https://github.com/react-dropzone/react-dropzone/blob/master/src/index.spec.jsx).
283
+ More examples for this can be found in `react-dropzone`'s own [test suites](https://github.com/react-dropzone/react-dropzone/blob/master/src/index.spec.tsx).
280
284
 
281
285
  ## Caveats
286
+
282
287
  ### Required React Version
283
- React [16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) or above is required because we use [hooks](https://reactjs.org/docs/hooks-intro.html) (the lib itself is a hook).
288
+
289
+ React [18](https://react.dev/blog/2022/03/29/react-v18) or above is required because we use [hooks](https://react.dev/reference/react/hooks) (the lib itself is a hook).
284
290
 
285
291
  ### File Paths
292
+
286
293
  Files returned by the hook or passed as arg to the `onDrop` cb won't have the properties `path` or `fullPath`.
287
294
  For more inf check [this SO question](https://stackoverflow.com/a/23005925/2275818) and [this issue](https://github.com/react-dropzone/react-dropzone/issues/477).
288
295
 
289
296
  ### Not a File Uploader
297
+
290
298
  This lib is not a file uploader; as such, it does not process files or provide any way to make HTTP requests to some server; if you're looking for that, checkout [filepond](https://pqina.nl/filepond) or [uppy.io](https://uppy.io/).
291
299
 
292
300
  ### Using \<label\> as Root
301
+
293
302
  If you use [\<label\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label) as the root element, the file dialog will be opened twice; see [#1107](https://github.com/react-dropzone/react-dropzone/issues/1107) why. To avoid this, use `noClick`:
303
+
294
304
  ```jsx static
295
- import React, {useCallback} from 'react'
296
- import {useDropzone} from 'react-dropzone'
305
+ import React, {useCallback} from "react";
306
+ import {useDropzone} from "react-dropzone";
297
307
 
298
308
  function MyDropzone() {
299
- const {getRootProps, getInputProps} = useDropzone({noClick: true})
309
+ const {getRootProps, getInputProps} = useDropzone({noClick: true});
300
310
 
301
311
  return (
302
312
  <label {...getRootProps()}>
303
313
  <input {...getInputProps()} />
304
314
  </label>
305
- )
315
+ );
306
316
  }
307
317
  ```
308
318
 
309
319
  ### Using open() on Click
320
+
310
321
  If you bind a click event on an inner element and use `open()`, it will trigger a click on the root element too, resulting in the file dialog opening twice. To prevent this, use the `noClick` on the root:
322
+
311
323
  ```jsx static
312
- import React, {useCallback} from 'react'
313
- import {useDropzone} from 'react-dropzone'
324
+ import React, {useCallback} from "react";
325
+ import {useDropzone} from "react-dropzone";
314
326
 
315
327
  function MyDropzone() {
316
- const {getRootProps, getInputProps, open} = useDropzone({noClick: true})
328
+ const {getRootProps, getInputProps, open} = useDropzone({noClick: true});
317
329
 
318
330
  return (
319
331
  <div {...getRootProps()}>
@@ -322,18 +334,19 @@ function MyDropzone() {
322
334
  Open
323
335
  </button>
324
336
  </div>
325
- )
337
+ );
326
338
  }
327
339
  ```
328
340
 
329
341
  ### File Dialog Cancel Callback
342
+
330
343
  The `onFileDialogCancel()` cb is unstable in most browsers, meaning, there's a good chance of it being triggered even though you have selected files.
331
344
 
332
345
  We rely on using a timeout of `300ms` after the window is focused (the window `onfocus` event is triggered when the file select dialog is closed) to check if any files were selected and trigger `onFileDialogCancel` if none were selected.
333
346
 
334
347
  As one can imagine, this doesn't really work if there's a lot of files or large files as by the time we trigger the check, the browser is still processing the files and no `onchange` events are triggered yet on the input. Check [#1031](https://github.com/react-dropzone/react-dropzone/issues/1031) for more info.
335
348
 
336
- Fortunately, there's the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), which is currently a working draft and some browsers support it (see [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker#browser_compatibility)), that provides a reliable way to prompt the user for file selection and capture cancellation.
349
+ Fortunately, there's the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), which is currently a working draft and some browsers support it (see [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker#browser_compatibility)), that provides a reliable way to prompt the user for file selection and capture cancellation.
337
350
 
338
351
  Also keep in mind that the FS access API can only be used in [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).
339
352
 
@@ -348,23 +361,25 @@ What this essentially does is that it will use the [showOpenFilePicker](https://
348
361
  In contrast, the traditional way (when the `useFsAccessApi` is not set to `true` or not specified) uses an `<input type="file">` (see [docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file)) on which a click event is triggered.
349
362
 
350
363
  With the use of the file system access API enabled, there's a couple of caveats to keep in mind:
364
+
351
365
  1. The users will not be able to select directories
352
366
  2. It requires the app to run in a [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts)
353
367
  3. In [Electron](https://www.electronjs.org/), the path may not be set (see [#1249](https://github.com/react-dropzone/react-dropzone/issues/1249))
354
368
 
355
369
  ## Supported Browsers
356
- We use [browserslist](https://github.com/browserslist/browserslist) config to state the browser support for this lib, so check it out on [browserslist.dev](https://browserslist.dev/?q=ZGVmYXVsdHM%3D).
357
370
 
371
+ We use [browserslist](https://github.com/browserslist/browserslist) config to state the browser support for this lib, so check it out on [browserslist.dev](https://browserslist.dev/?q=ZGVmYXVsdHM%3D).
358
372
 
359
373
  ## Need image editing?
374
+
360
375
  React Dropzone integrates perfectly with [Pintura Image Editor](https://pqina.nl/pintura/?ref=react-dropzone), creating a modern image editing experience. Pintura supports crop aspect ratios, resizing, rotating, cropping, annotating, filtering, and much more.
361
376
 
362
377
  Checkout the [Pintura integration example](https://codesandbox.io/s/react-dropzone-pintura-40xh4?file=/src/App.js).
363
378
 
364
-
365
379
  ## Support
366
380
 
367
381
  ### Backers
382
+
368
383
  Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/react-dropzone#backer)]
369
384
 
370
385
  <a href="https://opencollective.com/react-dropzone/backer/0/website" target="_blank"><img src="https://opencollective.com/react-dropzone/backer/0/avatar.svg"></a>
@@ -398,8 +413,8 @@ Support us with a monthly donation and help us continue our activities. [[Become
398
413
  <a href="https://opencollective.com/react-dropzone/backer/28/website" target="_blank"><img src="https://opencollective.com/react-dropzone/backer/28/avatar.svg"></a>
399
414
  <a href="https://opencollective.com/react-dropzone/backer/29/website" target="_blank"><img src="https://opencollective.com/react-dropzone/backer/29/avatar.svg"></a>
400
415
 
401
-
402
416
  ### Sponsors
417
+
403
418
  Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/react-dropzone#sponsor)]
404
419
 
405
420
  <a href="https://opencollective.com/react-dropzone/sponsor/0/website" target="_blank"><img src="https://opencollective.com/react-dropzone/sponsor/0/avatar.svg"></a>
@@ -433,12 +448,14 @@ Become a sponsor and get your logo on our README on Github with a link to your s
433
448
  <a href="https://opencollective.com/react-dropzone/sponsor/28/website" target="_blank"><img src="https://opencollective.com/react-dropzone/sponsor/28/avatar.svg"></a>
434
449
  <a href="https://opencollective.com/react-dropzone/sponsor/29/website" target="_blank"><img src="https://opencollective.com/react-dropzone/sponsor/29/avatar.svg"></a>
435
450
 
436
-
437
451
  ### Hosting
452
+
438
453
  [react-dropzone.js.org](https://react-dropzone.js.org/) hosting provided by [netlify](https://www.netlify.com/).
439
454
 
440
455
  ## Contribute
456
+
441
457
  Checkout the organization [CONTRIBUTING.md](https://github.com/react-dropzone/.github/blob/main/CONTRIBUTING.md).
442
458
 
443
459
  ## License
460
+
444
461
  MIT