diff --git a/snippets/FileDrop.md b/snippets/FileDrop.md new file mode 100644 index 000000000..c64075fee --- /dev/null +++ b/snippets/FileDrop.md @@ -0,0 +1,117 @@ +### FileDrop + +Renders a file drag and drop component for a single file. + +Create a ref called `dropRef` for this component. +Initialize `state.drag` and `state.filename` to `false` and `''` respectively. +The variables `dragCounter` and `state.drag` are used to determine if a file is being dragged, while `state.filename` is used to store the dropped file's name. +Create the `handleDrag`, `handleDragIn`, `handleDragOut` and `handleDrop` methods to handle drag and drop functionality, bind them to the component's context. +Each of the methods will handle a specific event, the listeners for which are created and removed in `componentDidMount` and `componentWillUnmount` respectively. +`handleDrag` prevents the browser from opening the dragged file, `handleDragIn` and `handleDragOut` handle the dragged file entering and exiting the component, while `handleDrop` handles the file being dropped and passes it to `this.props.handleDrop`. +In the `render()` method, create an appropriately styled `
` and use `state.drag` and `state.filename` to determine its contents and style. +Finally, bind the `ref` of the created `
` to `dropRef`. + + +```css +.filedrop { + min-height: 120px; + border: 3px solid #D3D3D3; + text-align: center; + font-size: 24px; + padding: 32px; + border-radius: 4px; +} + +.filedrop.drag { + border: 3px dashed #1E90FF; +} + +.filedrop.ready { + border: 3px solid #32CD32; +} +``` + +```jsx +class FileDrop extends React.Component { + constructor(props) { + super(props); + this.dropRef = React.createRef(); + this.state = { + drag: false, + filename: '' + } + this.handleDrag = this.handleDrag.bind(this); + this.handleDragIn = this.handleDragIn.bind(this); + this.handleDragOut = this.handleDragOut.bind(this); + this.handleDrop = this.handleDrop.bind(this); + } + + handleDrag(e) { + e.preventDefault(); + e.stopPropagation(); + } + + handleDragIn(e) { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter++; + if (e.dataTransfer.items && e.dataTransfer.items.length > 0) + this.setState({ drag: true }); + } + + handleDragOut(e) { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter--; + if (this.dragCounter === 0) + this.setState({ drag: false }); + } + + handleDrop(e) { + e.preventDefault(); + e.stopPropagation(); + this.setState({ drag: false }); + if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { + this.props.handleDrop(e.dataTransfer.files[0]); + this.setState({ filename : e.dataTransfer.files[0].name}); + e.dataTransfer.clearData(); + this.dragCounter = 0; + } + } + + componentDidMount() { + let div = this.dropRef.current; + div.addEventListener('dragenter', this.handleDragIn); + div.addEventListener('dragleave', this.handleDragOut); + div.addEventListener('dragover', this.handleDrag); + div.addEventListener('drop', this.handleDrop); + } + + componentWillUnmount() { + let div = this.dropRef.current; + div.removeEventListener('dragenter', this.handleDragIn); + div.removeEventListener('dragleave', this.handleDragOut); + div.removeEventListener('dragover', this.handleDrag); + div.removeEventListener('drop', this.handleDrop); + } + + render() { + return ( +
+ {this.state.filename && !this.state.drag ? +
{this.state.filename}
+ :
Drop files here!
+ } +
+ ) + } +} +``` + +```jsx +ReactDOM.render(, document.getElementById('root')); +``` + + + +