Skip to content

Instantly share code, notes, and snippets.

@obonyojimmy
Last active April 11, 2018 22:01
Show Gist options
  • Save obonyojimmy/d29b6e771d0818b48cf91224d42310db to your computer and use it in GitHub Desktop.
Save obonyojimmy/d29b6e771d0818b48cf91224d42310db to your computer and use it in GitHub Desktop.
[WIP] Drag n' Drop File Upload with React
var D = React.DOM;
var FileInput = React.createClass({
getInitialState: function(){
return {
active: false,
target: false,
hover: false
};
},
componentDidMount: function(){
var self = this;
window.addEventListener('dragover', self.dropTarget);
window.addEventListener('dragleave', self.dropLeave);
window.addEventListener('drop', self.handleDrop);
},
componentWillUnmount: function(){
var self = this;
window.removeEventListener('dragover', self.dropTarget);
window.removeEventListener('dragleave', self.dropLeave);
window.removeEventListener('drop', self.handleDrop);
},
handleChange: function(e){
var file = e.target.files[0];
this.props.onFileChange({
file: file,
name: file.name,
type: file.type
});
},
dropTarget: function(e){
var self = this;
if (!self.state.active) {
self.setState({
target: true
});
}
},
dropLeave: function(e) {
var self = this;
if(e.screenX === 0 && e.screenY === 0) { // Checks for if the leave event is when leaving the window
self.setState({
target: false
});
}
},
handleDrop: function(e){
e.preventDefault();
e.stopPropagation();
var self = this;
var uploadObj = {
target: e.nativeEvent.dataTransfer
};
self.setState({
target: false,
hover: false
});
self.handleChange(uploadObj);
},
handleDragEnter: function(e) {
e.preventDefault();
e.stopPropagation();
var self = this;
if (!self.state.active) {
self.setState({
hover: true
});
}
},
handleDragLeave: function(e) {
var self = this;
self.setState({
hover: false
});
},
handleDragOver: function(e){
e.preventDefault();
},
getClassNames: function(){
var classes = [];
if(this.state.target) {
classes.push('target');
}
if(this.state.hover) {
classes.push('hover')
}
return classes.join(' ');
},
render: function(){
var self = this;
var classNames = self.getClassNames();
return D.div({
className: 'file-container'
}, [
D.input({
className: "file-input " + classNames,
name: "upload",
type: "file",
ref: "upload",
onChange: self.handleChange,
onDrop: self.handleDrop,
onDragEnter: self.handleDragEnter,
onDragOver: self.handleDragOver,
onDragLeave: self.handleDragLeave
})
]);
}
});
var FilePreview = React.createClass({
getChild: function(){
var self = this;
var child = [];
if( self.props.type.indexOf("image") > -1 ) {
child.push(
D.img({
className: "preview-img",
src: self.props.file
})
);
} else {
child.push(
D.p({
className: "preview-name"
}, self.props.name)
);
}
child.push(
D.button({
className: "remove-file",
onClick: self.props.handleFileRemove
}, "Remove File")
);
return child;
},
render: function(){
var child = this.getChild();
return D.div({
className: "file-preview"
}, child);
}
});
var App = React.createClass({
getInitialState: function(){
return {
previewing: false,
reset: false
};
},
handleFile: function(fileObj){
var self = this;
var reader = new FileReader();
self.fileName = fileObj.name;
self.fileType = fileObj.type;
reader.onload = function(e) {
self.file = reader.result;
self.setState({
previewing: true
});
}
reader.readAsDataURL(fileObj.file);
self.setState({
reset: true
});
},
resetFile: function(){
var self = this;
self.setState({
previewing: false,
reset: true
});
setTimeout(function(){
self.setState({
reset: false
});
}, 100);
},
getChildren: function(){
var self = this;
var childrenArr = [];
if(!self.state.reset){
childrenArr.push(
React.createElement(FileInput, {
onFileChange: self.handleFile
})
);
}
if(self.state.previewing){
childrenArr.push(
React.createElement(FilePreview, {
file: self.file,
name: self.fileName,
type: self.fileType,
handleFileRemove: self.resetFile
})
);
}
return childrenArr;
},
render: function(){
var children = this.getChildren();
return D.div({
className: "app"
}, children);
}
});
React.render(React.createElement(App, null), document.body);
<script src="https://fb.me/react-0.12.2.js"></script>
@import "bourbon";
.app {
margin: 2em auto;
max-width: 80%;
text-align: center;
}
.file-container {
position: relative;
}
.file-input {
border: 4px dashed rgba(black, 0);
height: 2em;
transition: all 0.5s $ease-in-out-quint;
width: 50%;
}
.file-preview {
margin: 2em 0;
}
.target {
border-color: rgba(black, 0.5);
height: 5em;
position: relative;
width: 100%;
&::after {
background: white;
content: "Drop That Heavy File Here.";
font-size: 1.5em;
font-weight: 500;
height: 100%;
left: 0;
line-height: 1.5;
position: absolute;
text-align: center;
top: 0;
width: 100%;
}
&.hover {
border-color: black;
}
}

[WIP] Drag n' Drop File Upload with React

Working on another UI challenge with React. This time I'm attempting to create an efficient file input that accepts drag n' drop uploads with validation and feedback. I also need to make sure it works in at least IE10.

I may create some custom styling for the file input but that is not the focus of this demo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment