Skip to content

Commit c9733d7

Browse files
authored
Merge pull request #420 from plotly/dropzone-improvements
UX improvements drop zone
2 parents c8bfcd6 + da46415 commit c9733d7

File tree

2 files changed

+57
-53
lines changed

2 files changed

+57
-53
lines changed

src/components/widgets/Dropzone.js

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ class Dropzone extends Component {
1313
};
1414

1515
this.validFiletypes = {
16-
image: _('jpeg/jpg, svg, png, gif, bmp, webp'),
16+
image: _(
17+
'image/jpeg, image/jpg, image/svg, image/png, image/gif, image/bmp, image/webp'
18+
),
1719
};
1820

1921
this.onDrop = this.onDrop.bind(this);
@@ -40,7 +42,7 @@ class Dropzone extends Component {
4042
componentWillMount() {
4143
const _ = this.props.localize;
4244

43-
if (this.props.fileType && this.props.value && this.props.value !== '') {
45+
if (this.props.value && this.props.value !== '') {
4446
this.setState({content: this.renderSuccess(this.props.value)});
4547
return;
4648
}
@@ -50,7 +52,7 @@ class Dropzone extends Component {
5052
<div className="dropzone-container__message">
5153
<p>
5254
{_('Drop the ') +
53-
(this.props.fileType ? this.props.fileType : _('file')) +
55+
this.props.fileType +
5456
_(
5557
' to upload here or click to choose a file from your computer.'
5658
)}
@@ -59,7 +61,9 @@ class Dropzone extends Component {
5961
{this.props.fileType === 'image' ? (
6062
<p>
6163
{_('Supported formats are: ') +
62-
this.validFiletypes[this.props.fileType] +
64+
this.validFiletypes[this.props.fileType]
65+
.split('image/')
66+
.join('') +
6367
'.'}
6468
</p>
6569
) : null}
@@ -70,15 +74,18 @@ class Dropzone extends Component {
7074

7175
onLoad(e) {
7276
const _ = this.props.localize;
77+
const supportedFileTypes =
78+
this.props.fileType === 'image'
79+
? this.validFiletypes[this.props.fileType].split('image/').join('')
80+
: this.validFiletypes[this.props.fileType];
81+
7382
const parsingError = (
7483
<div className="dropzone-container__message">
7584
<p>{_('Yikes! An error occurred while parsing this file.')}</p>
7685
<p>
77-
{this.props.fileType
78-
? _('Try again with a supported file format: ') +
79-
this.validFiletypes[this.props.fileType] +
80-
'.'
81-
: _('Try again.')}
86+
{_('Try again with a supported file format: ') +
87+
supportedFileTypes +
88+
'.'}
8289
</p>
8390
</div>
8491
);
@@ -98,69 +105,62 @@ class Dropzone extends Component {
98105
}
99106
}
100107

101-
onDrop(file) {
108+
onDrop(accepted, rejected) {
102109
const _ = this.props.localize;
103110
const reader = new FileReader();
104111

105-
const invalidFileTypeMessage = this.props.fileType ? (
106-
<div className="dropzone-container__message">
107-
<p>
108-
{_("Yikes! This doesn't look like a valid ") +
109-
this.props.fileType +
110-
_('to us. ')}
111-
</p>
112-
<p>
113-
{_('Try again with a ') +
114-
this.validFiletypes[this.props.fileType] +
115-
'.'}
116-
</p>
117-
</div>
118-
) : (
119-
_('Unsupported file format!')
120-
);
112+
if (accepted.length) {
113+
if (accepted.length > 1) {
114+
this.setState({
115+
content: (
116+
<div className="dropzone-container__message">
117+
<p>{_('Yikes! You can only upload one file at a time.')}</p>
118+
<p>
119+
{_(
120+
'To upload multiple files, create multiple files and upload them individually.'
121+
)}
122+
</p>
123+
</div>
124+
),
125+
});
126+
return;
127+
}
128+
this.setState({content: _('Loading...')});
129+
reader.onload = e => this.onLoad(e);
130+
if (this.props.fileType === 'image') {
131+
reader.readAsDataURL(accepted[0]);
132+
}
133+
}
134+
135+
if (rejected.length) {
136+
const supportedFileTypes =
137+
this.props.fileType === 'image'
138+
? this.validFiletypes[this.props.fileType].split('image/').join('')
139+
: this.validFiletypes[this.props.fileType];
121140

122-
if (file.length > 1) {
123141
this.setState({
124142
content: (
125143
<div className="dropzone-container__message">
126-
<p>{_('Yikes! You can only upload one file at a time.')}</p>
127144
<p>
128-
{_(
129-
'To upload multiple files, create multiple files and upload them individually.'
130-
)}
145+
{_("Yikes! This doesn't look like a valid ") +
146+
this.props.fileType +
147+
_(' to us. ')}
131148
</p>
149+
<p>{_('Try again with a ') + supportedFileTypes + ' file.'}</p>
132150
</div>
133151
),
134152
});
135-
return;
136-
}
137-
138-
this.setState({content: _('Loading...')});
139-
140-
reader.onload = e => this.onLoad(e);
141-
142-
if (this.props.fileType === 'image') {
143-
if (
144-
['.jpeg', '.jpg', '.svg', '.png', '.gif', '.bmp', '.webp'].some(ext =>
145-
file[0].name.endsWith(ext)
146-
)
147-
) {
148-
reader.readAsDataURL(file[0]);
149-
} else {
150-
this.setState({
151-
content: invalidFileTypeMessage,
152-
});
153-
}
154153
}
155154
}
156155

157156
render() {
158157
return (
159158
<Drop
160-
ref="dzone"
159+
accept={this.validFiletypes[this.props.fileType]}
161160
onDrop={this.onDrop}
162161
className="dropzone-container"
163162
activeClassName="dropzone-container--active"
163+
rejectClassName="dropzone-container--rejected"
164164
>
165165
<div className="dropzone-container__content">{this.state.content}</div>
166166
</Drop>
@@ -170,7 +170,7 @@ class Dropzone extends Component {
170170

171171
Dropzone.propTypes = {
172172
localize: PropTypes.func,
173-
fileType: PropTypes.string,
173+
fileType: PropTypes.string.isRequired,
174174
onUpdate: PropTypes.func,
175175
value: PropTypes.any,
176176
};

src/styles/components/widgets/_dropzone.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@
2727
&__image {
2828
width: 100%;
2929
height: 100%;
30-
background-size: cover;
30+
background-size: contain;
3131
background-position: center;
3232
position: relative;
3333
}
3434

3535
&--active {
3636
border-color: var(--color-dodger);
3737
}
38+
39+
&--rejected {
40+
border-color: red;
41+
}
3842
}

0 commit comments

Comments
 (0)