UNPKG

react-drag-and-drop

Version:
107 lines (102 loc) 3.81 kB
import React from 'react' import utils from './utils' function pickTypes(e) { return e.dataTransfer ? e.dataTransfer.types : [] } function filterProps(props) { let forbidden = ['types', 'className', 'enabled', 'wrapperComponent'] return Object.keys(props).reduce((p, c) => { if (!forbidden.includes(c)) { p[c] = props[c] } return p }, {}) } export default class Droppable extends React.Component { constructor(props) { super(props) this.state = { over : false } this.droppable = React.createRef() } render() { let Tag = 'div' let props = Object.assign({}, this.props) if (this.props.wrapperComponent) { Tag = this.props.wrapperComponent.type props = Object.assign(props, this.props.wrapperComponent.props) } let classes = 'Droppable'; if(props.className) classes+=` ${props.className}`; if (this.state.over) classes+=' over'; return ( <Tag ref={this.droppable} className={classes} {...filterProps(props)} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver.bind(this)} onDragEnter={this.onDragEnter.bind(this)} onDragLeave={this.onDragLeave.bind(this)} onDragExit={this.onDragLeave.bind(this)}> {props.children} </Tag> ) } onDragOver(e) { e.preventDefault() if (!this.allowed(pickTypes(e))) return if (typeof this.props.onDragOver === 'function') this.props.onDragOver(e) } onDragEnter(e) { e.preventDefault() if (this.state.over) return if (!this.allowed(pickTypes(e))) return if (typeof this.props.onDragEnter === 'function') this.props.onDragEnter(e) this.setState({ over : true }) } onDragLeave(e) { e.preventDefault() if (!this.allowed(pickTypes(e))) return let over = true if (e.clientX <= this.position.left || e.clientX >= this.position.right) over = false if (e.clientY <= this.position.top || e.clientY >= this.position.bottom) over = false if (over) return this.setState({ over : false }) if (typeof this.props.onDragLeave === 'function') this.props.onDragLeave(e) } onDrop(e) { e.preventDefault() if (!this.allowed(pickTypes(e))) return this.setState({ over : false }) let props = Object.assign({}, this.props) if (this.props.wrapperComponent) props = Object.assign(props, this.props.wrapperComponent.props) const data = !props.types ? null : [].concat(props.types).reduce((d, type) => { d[type] = e.dataTransfer.getData(type) return d },{}) if (typeof this.props.onDrop === 'function') this.props.onDrop(data, e) } allowed(attemptingTypes) { let props = Object.assign({}, this.props) if (this.props.wrapperComponent) props = Object.assign(props, this.props.wrapperComponent.props) if (!props.enabled) return false let _attemptingTypes = utils.toArray(attemptingTypes) if (!props.types) return true return [].concat(props.types).reduce((sum, type) => { if (_attemptingTypes.indexOf(type) >= 0) return true return sum }, false) } componentDidMount() { // TODO: Listen for window resize? var node = this.droppable.current this.position = { top : node.offsetTop+5, left : node.offsetLeft+5, right : node.offsetLeft+node.offsetWidth-5, bottom : node.offsetTop+node.offsetHeight-5 } } } Droppable.defaultProps = { enabled: true }