UNPKG

wix-style-react

Version:
192 lines (164 loc) 5.25 kB
import React from 'react'; import PropTypes from 'prop-types'; import shallowEqual from 'shallowequal'; import DraggableSource from './components/DraggableSource'; import DraggableTarget from './components/DraggableTarget'; import DraggableManager from './components/DraggableManager'; export class Draggable extends React.Component { state = { delayed: false, }; delayTimer = null; shouldComponentUpdate( { listOfPropsThatAffectItems, ...nextProps }, nextState, ) { const { listOfPropsThatAffectItems: prevListOfPropsThatAffectItems, ...prevProps } = this.props; if ( !shallowEqual(nextProps, prevProps) || !shallowEqual(listOfPropsThatAffectItems, prevListOfPropsThatAffectItems) ) { return true; } if (!shallowEqual(nextState, this.state)) { return true; } return false; } componentWillUnmount() { this.resetDelayTimer(); } resetDelayState = () => { if (!!this.props.delay) { this.setState({ delayed: false }); this.resetDelayTimer(); } }; resetDelayTimer = () => { clearTimeout(this.delayTimer); this.delayTimer = null; }; countDelay = () => { if (!!this.props.delay) { this.setState({ delayed: true }); this.resetDelayTimer(); this.delayTimer = setTimeout( () => this.setState({ delayed: false }), this.props.delay, ); } }; onDragStart = ({ id, index, containerId, groupName, item }) => { if (this.props.onDragStart) { this.props.onDragStart({ id, index, containerId, groupName, item }); } this.resetDelayTimer(); }; onDragEnd = ({ id, index, containerId, groupName, item }) => { if (this.props.onDragEnd) { this.props.onDragEnd({ id, index, containerId, groupName, item }); } this.resetDelayState(); }; canDrag = ({ id, index, containerId, groupName, item }) => { const canDragByDelay = !!this.props.delay ? !this.state.delayed : true; const propsCanDrag = this.props.canDrag ? this.props.canDrag({ id, index, containerId, groupName, item, }) : true; if (!canDragByDelay) { this.resetDelayState(); } return canDragByDelay && propsCanDrag; }; render() { const { hasDragged, ...restProps } = this.props; return ( <DraggableTarget {...restProps}> <div onMouseDown={this.countDelay} onMouseUp={this.resetDelayState} data-hook="delay-wrapper" > <DraggableSource {...restProps} ignoreMouseEvents={hasDragged} onDragStart={this.onDragStart} onDragEnd={this.onDragEnd} canDrag={this.canDrag} delayed={!!this.props.delay && this.state.delayed} /> </div> </DraggableTarget> ); } } Draggable.defaultProps = { droppable: true, }; Draggable.propTypes = { /** indicates if element can be drop at this place */ droppable: PropTypes.bool, /** decide whether to render a handle using `connectHandle` (see below) */ withHandle: PropTypes.bool, /** uniq id of container that contain current draggable item */ containerId: PropTypes.string, /* name of group between inside of each dnd is allowed */ groupName: PropTypes.string, /* custom renderer for item */ renderItem: PropTypes.func, /* position of item in container items array */ index: PropTypes.number, /* uniq id of an item */ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), /* model that represent item */ item: PropTypes.object, /** callback when item was moved out from current container to another container */ onMoveOut: PropTypes.func, /** callback when item was dropped in a new location */ onDrop: PropTypes.func, /** callback when item is hovered*/ onHover: PropTypes.func, /** callback for drag start */ onDragStart: PropTypes.func, /** callback for drag end */ onDragEnd: PropTypes.func, /** visual positioning shifting for an element (transform: translate) without moving it from its real position at DOM (left, top) */ shift: PropTypes.arrayOf(PropTypes.number), /** flag that indicates that there's an item being dragged */ hasDragged: PropTypes.bool, /** sets draggable item node & additional info for animation positions calculations */ setWrapperNode: PropTypes.func, /** animation duration in ms, default = 0 - disabled */ animationDuration: PropTypes.number, /** animation timing function, default = linear */ animationTiming: PropTypes.string, /** callback that could prevent item from dragging */ canDrag: PropTypes.func, delay: PropTypes.number, /** In case that you are using some external props inside of renderItems method, you need to define them here. renderItem = ({ item }) => <div key={item.id}>{this.props.myAwesomeProp}</div> render() { return ( <SortableList ... listOfPropsThatAffectItems={[this.props.myAwesomeProp]} /> ) } */ listOfPropsThatAffectItems: PropTypes.array, }; Draggable.Item = Draggable; Draggable.Manager = DraggableManager; export default Draggable;