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.
- package/README.md +3 -3
- package/dist/index.cjs +1077 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +1046 -2
- package/dist/index.js.map +1 -0
- package/package.json +62 -161
- package/typings/tests/tsconfig.json +12 -11
- package/.babelrc.js +0 -28
- package/.codeclimate.yml +0 -15
- package/.editorconfig +0 -13
- package/.eslintignore +0 -3
- package/.eslintrc +0 -37
- package/.gitpod.yml +0 -6
- package/.husky/commit-msg +0 -5
- package/.husky/pre-commit +0 -5
- package/.nvmrc +0 -1
- package/.releaserc.json +0 -27
- package/CHANGELOG.md +0 -9
- package/commitlint.config.js +0 -1
- package/dist/es/index.js +0 -1051
- package/dist/es/package.json +0 -1
- package/dist/es/utils/index.js +0 -366
- package/examples/.eslintrc +0 -5
- package/examples/accept/README.md +0 -144
- package/examples/basic/README.md +0 -70
- package/examples/class-component/README.md +0 -45
- package/examples/drag-overlay/README.md +0 -132
- package/examples/events/README.md +0 -164
- package/examples/file-dialog/README.md +0 -90
- package/examples/forms/README.md +0 -69
- package/examples/maxFiles/README.md +0 -58
- package/examples/no-jsx/README.md +0 -32
- package/examples/pintura/README.md +0 -146
- package/examples/plugins/README.md +0 -55
- package/examples/previews/README.md +0 -86
- package/examples/styling/README.md +0 -126
- package/examples/theme.css +0 -37
- package/examples/validator/README.md +0 -68
- package/rollup.config.js +0 -33
- package/src/.eslintrc +0 -37
- package/src/__snapshots__/index.spec.js.snap +0 -3
- package/src/index.spec.js +0 -3838
- package/src/utils/index.spec.js +0 -625
- package/styleguide.config.js +0 -107
- package/testSetup.js +0 -8
- package/typings/.eslintrc +0 -28
- /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
|
-
```
|
package/examples/forms/README.md
DELETED
|
@@ -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
|
-
```
|