react-dropzone 15.0.0 → 16.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.
Files changed (47) hide show
  1. package/README.md +3 -3
  2. package/dist/index.cjs +1077 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.js +1046 -2
  5. package/dist/index.js.map +1 -0
  6. package/package.json +62 -161
  7. package/typings/tests/tsconfig.json +12 -11
  8. package/.babelrc.js +0 -28
  9. package/.codeclimate.yml +0 -15
  10. package/.editorconfig +0 -13
  11. package/.eslintignore +0 -3
  12. package/.eslintrc +0 -37
  13. package/.gitpod.yml +0 -6
  14. package/.husky/commit-msg +0 -5
  15. package/.husky/pre-commit +0 -5
  16. package/.nvmrc +0 -1
  17. package/.releaserc.json +0 -27
  18. package/CHANGELOG.md +0 -9
  19. package/commitlint.config.js +0 -1
  20. package/dist/es/index.js +0 -1051
  21. package/dist/es/package.json +0 -1
  22. package/dist/es/utils/index.js +0 -366
  23. package/examples/.eslintrc +0 -5
  24. package/examples/accept/README.md +0 -144
  25. package/examples/basic/README.md +0 -70
  26. package/examples/class-component/README.md +0 -45
  27. package/examples/drag-overlay/README.md +0 -132
  28. package/examples/events/README.md +0 -164
  29. package/examples/file-dialog/README.md +0 -90
  30. package/examples/forms/README.md +0 -69
  31. package/examples/maxFiles/README.md +0 -58
  32. package/examples/no-jsx/README.md +0 -32
  33. package/examples/pintura/README.md +0 -146
  34. package/examples/plugins/README.md +0 -55
  35. package/examples/previews/README.md +0 -86
  36. package/examples/styling/README.md +0 -126
  37. package/examples/theme.css +0 -37
  38. package/examples/validator/README.md +0 -68
  39. package/rollup.config.js +0 -33
  40. package/src/.eslintrc +0 -37
  41. package/src/__snapshots__/index.spec.js.snap +0 -3
  42. package/src/index.spec.js +0 -3838
  43. package/src/utils/index.spec.js +0 -625
  44. package/styleguide.config.js +0 -107
  45. package/testSetup.js +0 -8
  46. package/typings/.eslintrc +0 -28
  47. /package/src/{index.js → index.jsx} +0 -0
@@ -1,132 +0,0 @@
1
- # isDragGlobal Example
2
-
3
- The `isDragGlobal` state is `true` when files are being dragged anywhere on the document, before they reach the dropzone. This allows you to show visual feedback (like a full-page overlay) to indicate where files can be dropped.
4
-
5
- ## Simple Example
6
-
7
- ```jsx harmony
8
- import React from 'react';
9
- import {useDropzone} from 'react-dropzone';
10
-
11
- function DragOverlay() {
12
- const {
13
- getRootProps,
14
- getInputProps,
15
- isDragGlobal,
16
- isDragActive,
17
- isDragAccept,
18
- isDragReject,
19
- acceptedFiles
20
- } = useDropzone({
21
- accept: {
22
- 'image/*': ['.png', '.jpg', '.jpeg', '.gif']
23
- }
24
- });
25
-
26
- const files = acceptedFiles.map(file => (
27
- <li key={file.path}>
28
- {file.path} - {file.size} bytes
29
- </li>
30
- ));
31
-
32
- return (
33
- <div style={{ minHeight: '100vh', padding: '20px' }}>
34
- {/* Global overlay shown when dragging anywhere on the page */}
35
- {isDragGlobal && !isDragActive && (
36
- <div style={{
37
- position: 'fixed',
38
- top: 0,
39
- left: 0,
40
- right: 0,
41
- bottom: 0,
42
- backgroundColor: 'rgba(0, 123, 255, 0.1)',
43
- border: '3px dashed #007bff',
44
- pointerEvents: 'none',
45
- display: 'flex',
46
- alignItems: 'center',
47
- justifyContent: 'center',
48
- zIndex: 1000,
49
- }}>
50
- <h2 style={{ color: '#007bff' }}>Drop files anywhere on this page...</h2>
51
- </div>
52
- )}
53
-
54
- <section className="container">
55
- <div {...getRootProps({
56
- className: 'dropzone',
57
- style: {
58
- border: '2px dashed #ccc',
59
- borderRadius: '8px',
60
- padding: '40px',
61
- textAlign: 'center',
62
- backgroundColor: isDragAccept ? '#d4edda' : isDragReject ? '#f8d7da' : 'white',
63
- transition: 'all 0.2s',
64
- }
65
- })}>
66
- <input {...getInputProps()} />
67
-
68
- {/* Status indicators */}
69
- {isDragGlobal && !isDragActive && (
70
- <p style={{ color: '#007bff', fontWeight: 'bold' }}>
71
- 🌐 Drag detected on page!
72
- </p>
73
- )}
74
-
75
- {isDragActive && !isDragAccept && !isDragReject && (
76
- <p style={{ color: '#6c757d' }}>Drop files here...</p>
77
- )}
78
-
79
- {isDragAccept && (
80
- <p style={{ color: '#28a745', fontWeight: 'bold' }}>
81
- ✅ Drop to upload these files
82
- </p>
83
- )}
84
-
85
- {isDragReject && (
86
- <p style={{ color: '#dc3545', fontWeight: 'bold' }}>
87
- ❌ Some files will be rejected
88
- </p>
89
- )}
90
-
91
- {!isDragGlobal && !isDragActive && (
92
- <p>Drag 'n' drop images here, or click to select files</p>
93
- )}
94
- </div>
95
-
96
- <aside>
97
- <h4>Accepted files</h4>
98
- <ul>{files}</ul>
99
- </aside>
100
- </section>
101
- </div>
102
- );
103
- }
104
-
105
- <DragOverlay />
106
- ```
107
-
108
- ## State Transitions
109
-
110
- The `isDragGlobal` state provides early feedback about drag operations:
111
-
112
- 1. **`isDragGlobal: false`** - No drag operation detected
113
- 2. **`isDragGlobal: true`** - Files are being dragged anywhere on the document
114
- - This is set when `dragenter` fires on the document with files
115
- 3. **`isDragActive: true`** - Files are being dragged over the dropzone
116
- - Takes precedence when you want to show different feedback
117
- 4. **`isDragAccept: true`** / **`isDragReject: true`** - Files are validated
118
- - Indicates whether the dragged files meet the dropzone criteria
119
-
120
- ## Use Cases
121
-
122
- - **Full-page overlays**: Show a visual indicator across the entire page when drag starts
123
- - **Multi-dropzone highlighting**: Highlight all available dropzones when files are detected
124
- - **Early user feedback**: Provide immediate visual feedback before users reach the target dropzone
125
- - **Improved UX**: Make it clear that the application accepts drag and drop
126
-
127
- ## Events
128
-
129
- `isDragGlobal` is reset to `false` when:
130
- - Drag leaves the document (`dragleave` on all elements)
131
- - Files are dropped anywhere (`drop` event)
132
- - Drag operation is cancelled (`dragend` event, e.g., user presses ESC)
@@ -1,164 +0,0 @@
1
- If you'd like to prevent drag events propagation from the child to parent, you can use the `{noDragEventsBubbling}` property on the child:
2
- ```jsx harmony
3
- import React from 'react';
4
- import {useDropzone} from 'react-dropzone';
5
-
6
- function OuterDropzone(props) {
7
- const {getRootProps} = useDropzone({
8
- // Note how this callback is never invoked if drop occurs on the inner dropzone
9
- onDrop: files => console.log(files)
10
- });
11
-
12
- return (
13
- <div className="container">
14
- <div {...getRootProps({className: 'dropzone'})}>
15
- <InnerDropzone />
16
- <p>Outer dropzone</p>
17
- </div>
18
- </div>
19
- );
20
- }
21
-
22
- function InnerDropzone(props) {
23
- const {getRootProps} = useDropzone({noDragEventsBubbling: true});
24
- return (
25
- <div {...getRootProps({className: 'dropzone'})}>
26
- <p>Inner dropzone</p>
27
- </div>
28
- );
29
- }
30
-
31
- <OuterDropzone />
32
- ```
33
-
34
- Note that internally we use `event.stopPropagation()` to achieve the behavior illustrated above, but this comes with its own [drawbacks](https://javascript.info/bubbling-and-capturing#stopping-bubbling).
35
-
36
- If you'd like to selectively turn off the default dropzone behavior for `onClick`, use the `{noClick}` property:
37
- ```jsx harmony
38
- import React from 'react';
39
- import {useDropzone} from 'react-dropzone';
40
-
41
- function DropzoneWithoutClick(props) {
42
- const {getRootProps, getInputProps, acceptedFiles} = useDropzone({noClick: true});
43
- const files = acceptedFiles.map(file => <li key={file.path}>{file.path}</li>);
44
-
45
- return (
46
- <section className="container">
47
- <div {...getRootProps({className: 'dropzone'})}>
48
- <input {...getInputProps()} />
49
- <p>Dropzone without click events</p>
50
- </div>
51
- <aside>
52
- <h4>Files</h4>
53
- <ul>{files}</ul>
54
- </aside>
55
- </section>
56
- );
57
- }
58
-
59
- <DropzoneWithoutClick />
60
- ```
61
-
62
- If you'd like to selectively turn off the default dropzone behavior for `onKeyDown`, `onFocus` and `onBlur`, use the `{noKeyboard}` property:
63
- ```jsx harmony
64
- import React from 'react';
65
- import {useDropzone} from 'react-dropzone';
66
-
67
- function DropzoneWithoutKeyboard(props) {
68
- const {getRootProps, getInputProps, acceptedFiles} = useDropzone({noKeyboard: true});
69
- const files = acceptedFiles.map(file => <li key={file.path}>{file.path}</li>);
70
-
71
- return (
72
- <section className="container">
73
- <div {...getRootProps({className: 'dropzone'})}>
74
- <input {...getInputProps()} />
75
- <p>Dropzone without keyboard events</p>
76
- <em>(SPACE/ENTER and focus events are disabled)</em>
77
- </div>
78
- <aside>
79
- <h4>Files</h4>
80
- <ul>{files}</ul>
81
- </aside>
82
- </section>
83
- );
84
- }
85
-
86
- <DropzoneWithoutKeyboard />
87
- ```
88
-
89
- Or you can prevent the default behavior for both click and keyboard events if you omit the input:
90
- ```jsx harmony
91
- import React from 'react';
92
- import {useDropzone} from 'react-dropzone';
93
-
94
- function DropzoneWithoutClick(props) {
95
- const {getRootProps, acceptedFiles} = useDropzone();
96
- const files = acceptedFiles.map(file => <li key={file.path}>{file.path}</li>);
97
-
98
- return (
99
- <section className="container">
100
- <div {...getRootProps({className: 'dropzone'})}>
101
- <p>Dropzone without click events</p>
102
- </div>
103
- <aside>
104
- <h4>Files</h4>
105
- <ul>{files}</ul>
106
- </aside>
107
- </section>
108
- );
109
- }
110
-
111
- <DropzoneWithoutClick />
112
- ```
113
-
114
- **NOTE** If the browser supports the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) and you've set the `useFsAccessApi` to true, removing the `<input>` has no effect.
115
-
116
- If you'd like to selectively turn off the default dropzone behavior for drag events, use the `{noDrag}` property:
117
- ```jsx harmony
118
- import React from 'react';
119
- import {useDropzone} from 'react-dropzone';
120
-
121
- function DropzoneWithoutDrag(props) {
122
- const {getRootProps, getInputProps, acceptedFiles} = useDropzone({noDrag: true});
123
- const files = acceptedFiles.map(file => <li key={file.path}>{file.path}</li>);
124
-
125
- return (
126
- <section className="container">
127
- <div {...getRootProps({className: 'dropzone'})}>
128
- <input {...getInputProps()} />
129
- <p>Dropzone with no drag events</p>
130
- <em>(Drag 'n' drop is disabled)</em>
131
- </div>
132
- <aside>
133
- <h4>Files</h4>
134
- <ul>{files}</ul>
135
- </aside>
136
- </section>
137
- );
138
- }
139
-
140
- <DropzoneWithoutDrag />
141
- ```
142
-
143
- Keep in mind that if you provide your own callback handlers as well and use `event.stopPropagation()`, it will prevent the default dropzone behavior:
144
- ```jsx harmony
145
- import React from 'react';
146
- import Dropzone from 'react-dropzone';
147
-
148
- // Note that there will be nothing logged when files are dropped
149
- <Dropzone onDrop={files => console.log(files)}>
150
- {({getRootProps, getInputProps}) => (
151
- <div className="container">
152
- <div
153
- {...getRootProps({
154
- className: 'dropzone',
155
- onDrop: event => event.stopPropagation()
156
- })}
157
- >
158
- <input {...getInputProps()} />
159
- <p>Drag 'n' drop some files here, or click to select files</p>
160
- </div>
161
- </div>
162
- )}
163
- </Dropzone>
164
- ```
@@ -1,90 +0,0 @@
1
- You can programmatically invoke the default OS file prompt; just use the `open` method returned by the hook.
2
-
3
- **Note** that for security reasons most browsers require popups and dialogues to originate from a direct user interaction (i.e. click).
4
-
5
- If you are calling `open()` asynchronously, there’s a good chance it’s going to be blocked by the browser. So if you are calling `open()` asynchronously, be sure there is no more than *1000ms* delay between user interaction and `open()` call.
6
-
7
- Due to the lack of official docs on this (at least we haven’t found any. If you know one, feel free to open PR), there is no guarantee that **allowed delay duration** will not be changed in later browser versions. Since implementations may differ between different browsers, avoid calling open asynchronously if possible.
8
-
9
- ```jsx harmony
10
- import React from 'react';
11
- import {useDropzone} from 'react-dropzone';
12
-
13
- function Dropzone(props) {
14
- const {getRootProps, getInputProps, open, acceptedFiles} = useDropzone({
15
- // Disable click and keydown behavior
16
- noClick: true,
17
- noKeyboard: true
18
- });
19
-
20
- const files = acceptedFiles.map(file => (
21
- <li key={file.path}>
22
- {file.path} - {file.size} bytes
23
- </li>
24
- ));
25
-
26
- return (
27
- <div className="container">
28
- <div {...getRootProps({className: 'dropzone'})}>
29
- <input {...getInputProps()} />
30
- <p>Drag 'n' drop some files here</p>
31
- <button type="button" onClick={open}>
32
- Open File Dialog
33
- </button>
34
- </div>
35
- <aside>
36
- <h4>Files</h4>
37
- <ul>{files}</ul>
38
- </aside>
39
- </div>
40
- );
41
- }
42
-
43
- <Dropzone />
44
- ```
45
-
46
- Or use the `ref` exposed by the `<Dropzone>` component:
47
-
48
- ```jsx harmony
49
- import React, {createRef} from 'react';
50
- import Dropzone from 'react-dropzone';
51
-
52
- const dropzoneRef = createRef();
53
- const openDialog = () => {
54
- // Note that the ref is set async,
55
- // so it might be null at some point
56
- if (dropzoneRef.current) {
57
- dropzoneRef.current.open()
58
- }
59
- };
60
-
61
- // Disable click and keydown behavior on the <Dropzone>
62
- <Dropzone ref={dropzoneRef} noClick noKeyboard>
63
- {({getRootProps, getInputProps, acceptedFiles}) => {
64
- return (
65
- <div className="container">
66
- <div {...getRootProps({className: 'dropzone'})}>
67
- <input {...getInputProps()} />
68
- <p>Drag 'n' drop some files here</p>
69
- <button
70
- type="button"
71
- onClick={openDialog}
72
- >
73
- Open File Dialog
74
- </button>
75
- </div>
76
- <aside>
77
- <h4>Files</h4>
78
- <ul>
79
- {acceptedFiles.map(file => (
80
- <li key={file.path}>
81
- {file.path} - {file.size} bytes
82
- </li>
83
- ))}
84
- </ul>
85
- </aside>
86
- </div>
87
- );
88
- }}
89
- </Dropzone>
90
- ```
@@ -1,69 +0,0 @@
1
- React-dropzone does not submit the files in form submissions by default.
2
-
3
- If you need this behavior, you can add a hidden file input, and set the files into it.
4
-
5
-
6
- ```jsx harmony
7
- import React, {useRef} from 'react';
8
- import {useDropzone} from 'react-dropzone';
9
-
10
- function Dropzone(props) {
11
- const {required, name} = props;
12
-
13
- const hiddenInputRef = useRef(null);
14
-
15
- const {getRootProps, getInputProps, open, acceptedFiles} = useDropzone({
16
- onDrop: (incomingFiles) => {
17
- if (hiddenInputRef.current) {
18
- // Note the specific way we need to munge the file into the hidden input
19
- // https://stackoverflow.com/a/68182158/1068446
20
- const dataTransfer = new DataTransfer();
21
- incomingFiles.forEach((v) => {
22
- dataTransfer.items.add(v);
23
- });
24
- hiddenInputRef.current.files = dataTransfer.files;
25
- }
26
- }
27
- });
28
-
29
- const files = acceptedFiles.map(file => (
30
- <li key={file.path}>
31
- {file.path} - {file.size} bytes
32
- </li>
33
- ));
34
-
35
- return (
36
- <div className="container">
37
- <div {...getRootProps({className: 'dropzone'})}>
38
- {/*
39
- Add a hidden file input
40
- Best to use opacity 0, so that the required validation message will appear on form submission
41
- */}
42
- <input type ="file" name={name} required={required} style ={{opacity: 0}} ref={hiddenInputRef}/>
43
- <input {...getInputProps()} />
44
- <p>Drag 'n' drop some files here</p>
45
- <button type="button" onClick={open}>
46
- Open File Dialog
47
- </button>
48
- </div>
49
- <aside>
50
- <h4>Files</h4>
51
- <ul>{files}</ul>
52
- </aside>
53
- </div>
54
- );
55
- }
56
-
57
-
58
- <form onSubmit={(e) => {
59
- e.preventDefault();
60
-
61
- // Now get the form data as you regularly would
62
- const formData = new FormData(e.currentTarget);
63
- const file = formData.get("my-file");
64
- alert(file.name);
65
- }}>
66
- <Dropzone name ="my-file" required/>
67
- <button type="submit">Submit</button>
68
- </form>
69
- ```
@@ -1,58 +0,0 @@
1
- By providing `maxFiles` prop you can limit how many files the dropzone accepts.
2
-
3
- **Note** that this prop is enabled when the `multiple` prop is enabled.
4
- The default value for this prop is 0, which means there's no limitation to how many files are accepted.
5
-
6
-
7
- ```jsx harmony
8
- import React from 'react';
9
- import {useDropzone} from 'react-dropzone';
10
-
11
- function AcceptMaxFiles(props) {
12
- const {
13
- acceptedFiles,
14
- fileRejections,
15
- getRootProps,
16
- getInputProps
17
- } = useDropzone({
18
- maxFiles:2
19
- });
20
-
21
- const acceptedFileItems = acceptedFiles.map(file => (
22
- <li key={file.path}>
23
- {file.path} - {file.size} bytes
24
- </li>
25
- ));
26
-
27
- const fileRejectionItems = fileRejections.map(({ file, errors }) => {
28
- return (
29
- <li key={file.path}>
30
- {file.path} - {file.size} bytes
31
- <ul>
32
- {errors.map(e => <li key={e.code}>{e.message}</li>)}
33
- </ul>
34
-
35
- </li>
36
- )
37
- });
38
-
39
-
40
- return (
41
- <section className="container">
42
- <div {...getRootProps({ className: 'dropzone' })}>
43
- <input {...getInputProps()} />
44
- <p>Drag 'n' drop some files here, or click to select files</p>
45
- <em>(2 files are the maximum number of files you can drop here)</em>
46
- </div>
47
- <aside>
48
- <h4>Accepted files</h4>
49
- <ul>{acceptedFileItems}</ul>
50
- <h4>Rejected files</h4>
51
- <ul>{fileRejectionItems}</ul>
52
- </aside>
53
- </section>
54
- );
55
- }
56
-
57
- <AcceptMaxFiles />
58
- ```
@@ -1,32 +0,0 @@
1
- If you'd like to use [react without JSX](https://reactjs.org/docs/react-without-jsx.html) you can:
2
-
3
- ```js harmony
4
- import React, {useCallback, useState} from 'react';
5
- import {useDropzone} from 'react-dropzone';
6
-
7
- const e = React.createElement
8
-
9
- function Basic () {
10
- const [files, setFiles] = useState([]);
11
- const onDrop = useCallback(files => setFiles(files), [setFiles]);
12
-
13
- const {getRootProps, getInputProps} = useDropzone({onDrop});
14
-
15
- const fileList = files.map(
16
- file => React.createElement('li', {key: file.name}, `${file.name} - ${file.size} bytes`)
17
- );
18
-
19
- return e('section', {className: 'container'}, [
20
- e('div', getRootProps({className: 'dropzone', key: 'dropzone'}), [
21
- e('input', getInputProps({key: 'input'})),
22
- e('p', {key: 'desc'}, "Drag 'n' drop some files here, or click to select files")
23
- ]),
24
- e('aside', {key: 'filesContainer'}, [
25
- e('h4', {key: 'title'}, 'Files'),
26
- e('ul', {key: 'fileList'}, fileList)
27
- ])
28
- ]);
29
- }
30
-
31
- Basic()
32
- ```
@@ -1,146 +0,0 @@
1
- If you'd like to integrate the dropzone with the [Pintura](https://pqina.nl/pintura/?ref=react-dropzone) image editor, you just need to pass either of the selected images to the `openDefaultEditor()` method exported by Pintura:
2
-
3
- ```jsx static
4
- import React, { useState, useEffect } from 'react';
5
-
6
- // React Dropzone
7
- import { useDropzone } from 'react-dropzone';
8
-
9
- // Pintura Image Editor
10
- import 'pintura/pintura.css';
11
- import { openDefaultEditor } from 'pintura';
12
-
13
- // Based on the default React Dropzone image thumbnail example
14
- // The `thumbButton` style positions the edit button in the bottom right corner of the thumbnail
15
- const thumbsContainer = {
16
- display: 'flex',
17
- flexDirection: 'row',
18
- flexWrap: 'wrap',
19
- marginTop: 16,
20
- padding: 20,
21
- };
22
-
23
- const thumb = {
24
- position: 'relative',
25
- display: 'inline-flex',
26
- borderRadius: 2,
27
- border: '1px solid #eaeaea',
28
- marginBottom: 8,
29
- marginRight: 8,
30
- width: 100,
31
- height: 100,
32
- padding: 4,
33
- boxSizing: 'border-box',
34
- };
35
-
36
- const thumbInner = {
37
- display: 'flex',
38
- minWidth: 0,
39
- overflow: 'hidden',
40
- };
41
-
42
- const img = {
43
- display: 'block',
44
- width: 'auto',
45
- height: '100%',
46
- };
47
-
48
- const thumbButton = {
49
- position: 'absolute',
50
- right: 10,
51
- bottom: 10,
52
- };
53
-
54
- // This function is called when the user taps the edit button.
55
- // It opens the editor and returns the modified file when done
56
- const editImage = (image, done) => {
57
- const imageFile = image.pintura ? image.pintura.file : image;
58
- const imageState = image.pintura ? image.pintura.data : {};
59
-
60
- const editor = openDefaultEditor({
61
- src: imageFile,
62
- imageState,
63
- });
64
-
65
- editor.on('close', () => {
66
- // the user cancelled editing the image
67
- });
68
-
69
- editor.on('process', ({ dest, imageState }) => {
70
- Object.assign(dest, {
71
- pintura: { file: imageFile, data: imageState },
72
- });
73
- done(dest);
74
- });
75
- };
76
-
77
- function App() {
78
- const [files, setFiles] = useState([]);
79
- const { getRootProps, getInputProps } = useDropzone({
80
- accept: {
81
- 'image/*': [],
82
- },
83
- onDrop: (acceptedFiles) => {
84
- setFiles(
85
- acceptedFiles.map((file) =>
86
- Object.assign(file, {
87
- preview: URL.createObjectURL(file),
88
- })
89
- )
90
- );
91
- },
92
- });
93
-
94
- const thumbs = files.map((file, index) => (
95
- <div style={thumb} key={file.name}>
96
- <div style={thumbInner}>
97
- <img src={file.preview} style={img} alt="" />
98
- </div>
99
- <button
100
- style={thumbButton}
101
- onClick={() =>
102
- editImage(file, (output) => {
103
- const updatedFiles = [...files];
104
-
105
- // replace original image with new image
106
- updatedFiles[index] = output;
107
-
108
- // revoke preview URL for old image
109
- if (file.preview) URL.revokeObjectURL(file.preview);
110
-
111
- // set new preview URL
112
- Object.assign(output, {
113
- preview: URL.createObjectURL(output),
114
- });
115
-
116
- // update view
117
- setFiles(updatedFiles);
118
- })
119
- }
120
- >
121
- Edit
122
- </button>
123
- </div>
124
- ));
125
-
126
- useEffect(
127
- () => () => {
128
- // Make sure to revoke the Object URL to avoid memory leaks
129
- files.forEach((file) => URL.revokeObjectURL(file.preview));
130
- },
131
- [files]
132
- );
133
-
134
- return (
135
- <section className="container">
136
- <div {...getRootProps({ className: 'dropzone' })}>
137
- <input {...getInputProps()} />
138
- <p>Drag 'n' drop some files here, or click to select files</p>
139
- </div>
140
- <aside style={thumbsContainer}>{thumbs}</aside>
141
- </section>
142
- );
143
- }
144
-
145
- export default App;
146
- ```