UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

178 lines (177 loc) 6.23 kB
import _ from 'lodash'; import React from 'react'; import PropTypes from 'react-peek/prop-types'; import { lucidClassNames } from '../../util/style-helpers'; import { omitProps, } from '../../util/component-types'; const cx = lucidClassNames.bind('&-DragCaptureZone'); const { func, string } = PropTypes; class DragCaptureZone extends React.Component { constructor() { super(...arguments); this.elementRef = React.createRef(); this.state = { pageX: 0, pageY: 0, }; this.handleDrag = (event) => { let pageX; let pageY; /* istanbul ignore next */ if ('touches' in event) { pageX = event.touches[0].pageX; pageY = event.touches[0].pageY; } else { pageX = event.pageX; pageY = event.pageY; } event.preventDefault(); this.props.onDrag({ dX: pageX - this.state.pageX, dY: pageY - this.state.pageY, pageX, pageY, }, { event, props: this.props, }); }; this.handleMouseDragStart = (event) => { const pageX = event.pageX; const pageY = event.pageY; window.document.addEventListener('mousemove', this.handleDrag); window.document.addEventListener('mouseup', this.handleDragEnd); event.preventDefault(); this.props.onDragStart({ dX: 0, dY: 0, pageX, pageY, }, { event, props: this.props, }); this.setState({ pageX, pageY, }); }; this.handleTouchDragStart = (event) => { const pageX = event.touches[0].pageX; const pageY = event.touches[0].pageY; event.preventDefault(); this.props.onDragStart({ dX: 0, dY: 0, pageX, pageY, }, { event, props: this.props, }); this.setState({ pageX, pageY, }); }; this.handleDragEnd = (event) => { let pageX; let pageY; /* istanbul ignore next */ if ('changedTouches' in event) { pageX = event.changedTouches[0].pageX; pageY = event.changedTouches[0].pageY; } else { pageX = event.pageX; pageY = event.pageY; } window.document.removeEventListener('mousemove', this.handleDrag); window.document.removeEventListener('mouseup', this.handleDragEnd); event.preventDefault(); this.props.onDragEnd({ dX: pageX - this.state.pageX, dY: pageY - this.state.pageY, pageX, pageY, }, { event, props: this.props, }); this.setState({ pageX: 0, pageY: 0, }); }; this.handleDragCancel = (event) => { this.props.onDragCancel({ event, props: this.props, }); this.setState({ pageX: 0, pageY: 0, }); }; } componentDidMount() { //add event listeners directly on the DOM element to allow preventDefault //calls which are not honored due to react's event delegation //reference: https://github.com/facebook/react/issues/8968 if (this.elementRef.current) { this.elementRef.current.addEventListener('touchmove', this.handleDrag); this.elementRef.current.addEventListener('touchend', this.handleDragEnd); this.elementRef.current.addEventListener('touchcancel', this.handleDragCancel); } } componentWillUnmount() { if (this.elementRef.current) { this.elementRef.current.removeEventListener('touchmove', this.handleDrag); this.elementRef.current.removeEventListener('touchend', this.handleDragEnd); this.elementRef.current.removeEventListener('touchcancel', this.handleDragCancel); } window.document.removeEventListener('mousemove', this.handleDrag); window.document.removeEventListener('mouseup', this.handleDragEnd); } render() { return (React.createElement("div", Object.assign({}, omitProps(this.props, undefined, _.keys(DragCaptureZone.propTypes)), { className: cx('&', this.props.className), key: 'DragCaptureZone', onMouseDown: this.handleMouseDragStart, onTouchStart: this.handleTouchDragStart, ref: this.elementRef }))); } } DragCaptureZone.displayName = 'DragCaptureZone'; DragCaptureZone.peek = { description: ` This is a helper component used to capture mouse events to determine when the user starts, is and stops dragging. `, categories: ['utility'], }; DragCaptureZone.propTypes = { className: string ` Appended to the component-specific class names set on the root element. `, onDrag: func ` Called as the user drags the mouse. Signature: \`({ dx, dy, pageX, pageY }, { event, props }) => {}\` `, onDragEnd: func ` Called when the user releases the mouse button after having dragged. Signature: \`({ dx, dy, pageX, pageY }, { event, props }) => {}\` `, onDragStart: func ` Called when the user presses the mouse button down while over the component. Signature: \`({ dx, dy, pageX, pageY }, { event, props }) => {}\` `, onDragCancel: func ` Called when the drag event is canceled due to user interaction. For example: if a system alert pops up during a touch event. Signature: \`({ event, props }) => {}\` `, }; DragCaptureZone.defaultProps = { onDrag: _.noop, onDragEnd: _.noop, onDragStart: _.noop, onDragCancel: _.noop, }; export default DragCaptureZone;