Skip to content

Commit c0f5140

Browse files
author
jonisaa
committed
#2 Added DropZone component
1 parent e96df7c commit c0f5140

File tree

3 files changed

+268
-2
lines changed

3 files changed

+268
-2
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@
2828
},
2929
"homepage": "https://github.com/redux-autoform/redux-autoform-bootstrap-ui#readme",
3030
"dependencies": {
31+
"attr-accept": "^1.0.3",
3132
"bootstrap": "^3.3.6",
3233
"font-awesome": "^4.6.3",
3334
"isomorphic-fetch": "^2.2.1",
3435
"react": "^15.1.0",
3536
"react-bootstrap": "^0.30.0",
3637
"react-dom": "^15.2.1",
37-
"react-dropzone": "^3.5.3",
3838
"react-select-plus": "^1.0.0-beta14.patch1",
3939
"react-widgets": "^3.4.2",
4040
"redux-autoform-utils": "^1.0.3",

src/components/common/DropZone.js

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import accepts from 'attr-accept';
2+
import React, { Component, PropTypes } from 'react';
3+
4+
export default class DropZone extends Component {
5+
static propTypes = {
6+
// Overriding drop behavior
7+
onDrop: PropTypes.func,
8+
onDropAccepted: PropTypes.func,
9+
onDropRejected: PropTypes.func,
10+
11+
// Overriding drag behavior
12+
onDragStart: PropTypes.func,
13+
onDragEnter: PropTypes.func,
14+
onDragLeave: PropTypes.func,
15+
16+
children: PropTypes.node, // Contents of the dropzone
17+
style: PropTypes.object, // CSS styles to apply
18+
activeStyle: PropTypes.object, // CSS styles to apply when drop will be accepted
19+
rejectStyle: PropTypes.object, // CSS styles to apply when drop will be rejected
20+
className: PropTypes.string, // Optional className
21+
activeClassName: PropTypes.string, // className for accepted state
22+
rejectClassName: PropTypes.string, // className for rejected state
23+
24+
disablePreview: PropTypes.bool, // Enable/disable preview generation
25+
disableClick: PropTypes.bool, // Disallow clicking on the dropzone container to open file dialog
26+
27+
inputProps: PropTypes.object, // Pass additional attributes to the <input type="file"/> tag
28+
multiple: PropTypes.bool, // Allow dropping multiple files
29+
accept: PropTypes.string, // Allow specific types of files. See https://github.com/okonet/attr-accept for more information
30+
name: PropTypes.string // name attribute for the input tag
31+
};
32+
33+
34+
static defaultProps = {
35+
disablePreview: false,
36+
disableClick: false,
37+
multiple: true
38+
};
39+
40+
state = {
41+
isDragActive: false
42+
};
43+
44+
componentDidMount() {
45+
this.enterCounter = 0;
46+
}
47+
48+
onDragStart = (e) => {
49+
if (this.props.onDragStart) {
50+
this.props.onDragStart.call(this, e);
51+
}
52+
};
53+
54+
onDragEnter = (e) => {
55+
const {onDragEnter} = this.props;
56+
57+
e.preventDefault();
58+
59+
// Count the dropzone and any children that are entered.
60+
++this.enterCounter;
61+
62+
// This is tricky. During the drag even the dataTransfer.files is null
63+
// But Chrome implements some drag store, which is accesible via dataTransfer.items
64+
const dataTransferItems = e.dataTransfer && e.dataTransfer.items ? e.dataTransfer.items : [];
65+
66+
// Now we need to convert the DataTransferList to Array
67+
const allFilesAccepted = this.allFilesAccepted(Array.prototype.slice.call(dataTransferItems));
68+
69+
this.setState({
70+
isDragActive: allFilesAccepted,
71+
isDragReject: !allFilesAccepted
72+
});
73+
74+
if (onDragEnter) {
75+
onDragEnter.call(this, e);
76+
}
77+
};
78+
79+
onDragOver = (e) => {
80+
e.preventDefault();
81+
e.stopPropagation();
82+
return false;
83+
};
84+
85+
onDragLeave = (e) => {
86+
const {onDragLeave} = this.props;
87+
88+
e.preventDefault();
89+
90+
// Only deactivate once the dropzone and all children was left.
91+
if (--this.enterCounter > 0) {
92+
return;
93+
}
94+
95+
this.setState({
96+
isDragActive: false,
97+
isDragReject: false
98+
});
99+
100+
if (onDragLeave) {
101+
onDragLeave.call(this, e);
102+
}
103+
};
104+
105+
onDrop = (e) => {
106+
const {onDrop, onDropAccepted, onDropRejected} = this.props;
107+
108+
e.preventDefault();
109+
110+
// Reset the counter along with the drag on a drop.
111+
this.enterCounter = 0;
112+
113+
this.setState({
114+
isDragActive: false,
115+
isDragReject: false
116+
});
117+
118+
const droppedFiles = e.dataTransfer ? e.dataTransfer.files : e.target.files;
119+
const max = this.props.multiple ? droppedFiles.length : Math.min(droppedFiles.length, 1);
120+
const files = [];
121+
122+
for (let i = 0; i < max; i++) {
123+
const file = droppedFiles[i];
124+
// We might want to disable the preview creation to support big files
125+
if (!this.props.disablePreview) {
126+
file.preview = window.URL.createObjectURL(file);
127+
}
128+
129+
files.push(file);
130+
}
131+
132+
if (this.allFilesAccepted(files)) {
133+
if (onDrop) {
134+
onDrop.call(this, files, e);
135+
}
136+
137+
if (onDropAccepted) {
138+
onDropAccepted.call(this, files, e);
139+
}
140+
} else {
141+
if (onDropRejected) {
142+
onDropRejected.call(this, files, e);
143+
}
144+
}
145+
};
146+
147+
onClick = () => {
148+
if (!this.props.disableClick) {
149+
this.open();
150+
}
151+
};
152+
153+
allFilesAccepted(files) {
154+
return files.every(file => accepts(file, this.props.accept));
155+
}
156+
157+
open() {
158+
this.fileInputEl.value = null;
159+
this.fileInputEl.click();
160+
}
161+
162+
render() {
163+
const {
164+
accept,
165+
activeClassName,
166+
inputProps,
167+
multiple,
168+
name,
169+
rejectClassName,
170+
...rest
171+
} = this.props;
172+
173+
let {
174+
activeStyle,
175+
className,
176+
rejectStyle,
177+
style,
178+
...props // eslint-disable-line prefer-const
179+
} = rest;
180+
181+
const {isDragActive, isDragReject} = this.state;
182+
183+
className = className || '';
184+
185+
if (isDragActive && activeClassName) {
186+
className += ' ' + activeClassName;
187+
}
188+
if (isDragReject && rejectClassName) {
189+
className += ' ' + rejectClassName;
190+
}
191+
192+
if (!className && !style && !activeStyle && !rejectStyle) {
193+
style = {
194+
width: 200,
195+
height: 200,
196+
borderWidth: 2,
197+
borderColor: '#666',
198+
borderStyle: 'dashed',
199+
borderRadius: 5
200+
};
201+
activeStyle = {
202+
borderStyle: 'solid',
203+
backgroundColor: '#eee'
204+
};
205+
rejectStyle = {
206+
borderStyle: 'solid',
207+
backgroundColor: '#ffdddd'
208+
};
209+
}
210+
211+
let appliedStyle;
212+
if (activeStyle && isDragActive) {
213+
appliedStyle = {
214+
...style,
215+
...activeStyle
216+
};
217+
} else if (rejectStyle && isDragReject) {
218+
appliedStyle = {
219+
...style,
220+
...rejectStyle
221+
};
222+
} else {
223+
appliedStyle = {
224+
...style
225+
};
226+
}
227+
228+
const inputAttributes = {
229+
accept,
230+
type: 'file',
231+
style: {display: 'none'},
232+
multiple: multiple,
233+
ref: el => this.fileInputEl = el, // eslint-disable-line
234+
onChange: this.onDrop
235+
};
236+
237+
if (name && name.length) {
238+
inputAttributes.name = name;
239+
}
240+
241+
// Remove custom properties before passing them to the wrapper div element
242+
const customProps = ['disablePreview', 'disableClick', 'onDropAccepted', 'onDropRejected'];
243+
const divProps = {...props};
244+
customProps.forEach(prop => delete divProps[prop]);
245+
246+
return (
247+
<div
248+
className={className}
249+
style={appliedStyle}
250+
{...divProps/* expand user provided props first so event handlers are never overridden */}
251+
onClick={this.onClick}
252+
onDragStart={this.onDragStart}
253+
onDragEnter={this.onDragEnter}
254+
onDragOver={this.onDragOver}
255+
onDragLeave={this.onDragLeave}
256+
onDrop={this.onDrop}
257+
>
258+
{this.props.children}
259+
<input
260+
{...inputProps/* expand user provided inputProps first so inputAttributes override them */}
261+
{...inputAttributes}
262+
multiple/>
263+
</div>
264+
);
265+
}
266+
}

src/components/field/FileUpload.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Component, PropTypes } from 'react';
2-
import DropZone from 'react-dropzone';
2+
import DropZone from '../common/DropZone';
33

44
export default class FileUpload extends Component {
55
static propTypes = {

0 commit comments

Comments
 (0)