-
-
Save chrise86/1a8a76476bb88249801ceb3491fde20e to your computer and use it in GitHub Desktop.
HTML5 Drag and Drop React Component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$primary: blue; | |
$secondary: red; | |
.drop-it-wrap{ | |
width: 100%; | |
border: 5px dashed #ececec; | |
height: 250px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
cursor: pointer; | |
.loader{ | |
display: none; | |
} | |
&.uploading{ | |
.loader{ | |
display: block; | |
} | |
.default{ | |
display: none; | |
} | |
} | |
&.active{ | |
border-color: $primary; | |
} | |
&:hover{ | |
border: 5px dashed darken(#ececec, 10%); | |
} | |
} | |
.drop-it-input{ | |
position: absolute; | |
top: -99999999px; | |
} | |
@keyframes disco { | |
0% { | |
background: $primary; | |
} | |
100% { | |
background: $secondary; | |
} | |
} | |
.batch { | |
cursor: crosshair; | |
&.uploading { | |
animation: disco .1s infinite alternate; | |
} | |
background: #ffffff; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {PropTypes} from 'react'; | |
import classNames from 'classnames'; | |
class BatchDropZone extends React.Component { | |
static propTypes = { | |
// function that recieves an array of files | |
receiveFiles: PropTypes.func.isRequired, | |
// if single is set then file input will NOT be multiple | |
single: PropTypes.bool, | |
// text message that will appear in drop zone | |
copy: PropTypes.string, | |
className: PropTypes.string, | |
} | |
constructor() { | |
super(); | |
this.state = {}; | |
this.handleDragOver = this.handleDragOver.bind(this); | |
this.handleDrop = this.handleDrop.bind(this); | |
this.handleDragLeave = this.handleDragLeave.bind(this); | |
this.handleClick = this.handleClick.bind(this); | |
} | |
handleDragOver(e) { | |
e.preventDefault(); | |
if (this.state.inDropZone) | |
return; | |
this.setState({inDropZone: true}); | |
} | |
handleDrop(e) { | |
e.preventDefault(); | |
const { dataTransfer } = e; | |
const files = []; | |
if (dataTransfer.items) { | |
for (let i = this.props.single ? dataTransfer.items.length - 1 : 0; i < dataTransfer.items.length; i ++) { | |
if (dataTransfer.items[i].kind == "file") { | |
let file = dataTransfer.items[i].getAsFile(); | |
files.push(file); | |
} | |
} | |
} else { | |
for (let i = this.props.single ? dataTransfer.files.length - 1 : 0; i < dataTransfer.files.length; i ++) { | |
files.push(dataTransfer.files[i]); | |
} | |
} | |
this.setState({ | |
uploading: true | |
}); | |
setTimeout(() => { | |
this.setState({ | |
uploading: false | |
}); | |
this.props.receiveFiles(files); | |
}, 1000); | |
} | |
handleDragLeave() { | |
if (!this.state.inDropZone) | |
return; | |
this.setState({inDropZone: false}); | |
} | |
handleClick() { | |
this.refs.fileInput.click(); | |
} | |
handleFilesFromInput(e) { | |
let files = []; | |
Array.from(e.currentTarget.files).forEach(file => { | |
files.push(file); | |
}); | |
this.props.receiveFiles(files); | |
} | |
render() { | |
let classes = classNames(`drop-it-wrap batch ${this.props.className || ''}`, { | |
'active': this.state.inDropZone, | |
'uploading': this.state.uploading | |
}); | |
const dropEvents = { | |
onDrop: this.handleDrop, | |
onDragOver: this.handleDragOver, | |
onDragLeave: this.handleDragLeave, | |
onClick: this.handleClick | |
}; | |
let err; | |
if(this.state.error){ | |
err = ( | |
<div className="notification danger"> | |
{this.state.error} | |
</div> | |
); | |
} | |
const fileInputAttrs = { | |
ref: 'fileInput', | |
type: 'file', | |
onChange: this.handleFilesFromInput.bind(this), | |
style: { position: 'absolute', left: -99999999 }, | |
}; | |
if (!this.props.single) { | |
fileInputAttrs.multiple = true; | |
} | |
return ( | |
<div style={{width:'100%', height: '100%'}}> | |
{err} | |
<div className={classes} {...dropEvents}> | |
<div className="loader"> | |
Processing ... | |
</div> | |
<input {...fileInputAttrs} /> | |
<div className="default"> | |
{this.props.copy || 'Drop image files here or click'} | |
</div> | |
</div> | |
</div> | |
); | |
} | |
} | |
export default BatchDropZone; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import DropZone from './DropZone'; | |
export const readAsBase64 = (file) => { | |
return new Promise((resolve, reject) => { | |
let reader = new FileReader(); | |
reader.addEventListener('load', () => { | |
resolve({file, dataURL: reader.result}); | |
}); | |
reader.readAsDataURL(file); | |
}); | |
} | |
export default DropZone; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment