UNPKG

@evg-b/evg-ui

Version:

EVG-UI library inspired by Material Design.

368 lines (313 loc) 13.3 kB
import _extends from '@babel/runtime/helpers/extends'; import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties'; import _defineProperty from '@babel/runtime/helpers/defineProperty'; import _classCallCheck from '@babel/runtime/helpers/classCallCheck'; import _createClass from '@babel/runtime/helpers/createClass'; import _assertThisInitialized from '@babel/runtime/helpers/assertThisInitialized'; import _inherits from '@babel/runtime/helpers/inherits'; import _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn'; import _getPrototypeOf from '@babel/runtime/helpers/getPrototypeOf'; import React from 'react'; import PropTypes from 'prop-types'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } var moveCoordTemp = { startItXorY: '', itXorY: '', startDirection: '', // top | bottom | left | right direction: '', // top | bottom | left | right startX: 0, startY: 0, startTime: 0, nowX: 0, nowY: 0, shiftX: 0, shiftY: 0, deltaX: 0, deltaY: 0, inertia: false }; var prevDeltaTemp = { x: 0, y: 0 }; var EventSettings = { capture: true, // запускаемся на погружении passive: false }; var directionX = { '-1': 'left', '1': 'right' }; var directionY = { '-1': 'top', '1': 'bottom' }; /** * Вычисляет взаимодействие с компонентом в двумерной координатной плоскости. * С его помощью можно вычислять начало, конец, реальное положение, инерцию жестов. Используется во многих компонентах. */ var TouchDriver = /*#__PURE__*/function (_React$Component) { _inherits(TouchDriver, _React$Component); var _super = _createSuper(TouchDriver); function TouchDriver(props) { var _this; _classCallCheck(this, TouchDriver); _this = _super.call(this, props); _this.slip = 0; _this.slipSensitivity = 2; _this.touchRef = _this.props.innerRef || /*#__PURE__*/React.createRef(); _this.isTouch = /*#__PURE__*/React.createRef(false); _this.prevDelta = /*#__PURE__*/React.createRef(); _this.moveCoord = /*#__PURE__*/React.createRef(); _this.moveCoordInit = _this.moveCoordInit.bind(_assertThisInitialized(_this)); _this.getInCoord = _this.getInCoord.bind(_assertThisInitialized(_this)); _this.moveStartMouseOrTouch = _this.moveStartMouseOrTouch.bind(_assertThisInitialized(_this)); _this.move = _this.move.bind(_assertThisInitialized(_this)); _this.moveDetectEnd = _this.moveDetectEnd.bind(_assertThisInitialized(_this)); _this.moveHome = _this.moveHome.bind(_assertThisInitialized(_this)); return _this; } _createClass(TouchDriver, [{ key: "componentDidMount", value: function componentDidMount() { this.moveCoordInit(); // mouse this.touchRef.current.addEventListener('mousedown', this.moveStartMouseOrTouch, EventSettings); window.addEventListener('mousemove', this.move, EventSettings); window.addEventListener('mouseup', this.moveDetectEnd, EventSettings); // touch this.touchRef.current.addEventListener('touchstart', this.moveStartMouseOrTouch, EventSettings); this.touchRef.current.addEventListener('touchmove', this.move, EventSettings); this.touchRef.current.addEventListener('touchend', this.moveDetectEnd, EventSettings); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { // mouse this.touchRef.current.removeEventListener('mousedown', this.moveStartMouseOrTouch, EventSettings); window.removeEventListener('mousemove', this.move, EventSettings); window.removeEventListener('mouseup', this.moveDetectEnd, EventSettings); // touch this.touchRef.current.removeEventListener('touchstart', this.moveStartMouseOrTouch, EventSettings); this.touchRef.current.removeEventListener('touchmove', this.move, EventSettings); this.touchRef.current.removeEventListener('touchend', this.moveDetectEnd, EventSettings); } }, { key: "moveCoordInit", value: function moveCoordInit() { this.moveCoord.current = _objectSpread({}, moveCoordTemp); this.prevDelta.current = _objectSpread({}, prevDeltaTemp); this.slip = 0; } }, { key: "getInCoord", value: function getInCoord(e) { var tch_ref = this.touchRef.current; var clientX = 0, clientY = 0; // 1 - находим координаты нажатия относительно экрана switch (e.type) { case 'mousedown': case 'mousemove': case 'mouseup': clientX = e.clientX; clientY = e.clientY; break; case 'touchstart': case 'touchmove': case 'touchend': clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; break; // case 'wheel': // break } // 2 - находим координаты ref родителя относительно экрана var _tch_ref$getBoundingC = tch_ref.getBoundingClientRect(), x = _tch_ref$getBoundingC.x, y = _tch_ref$getBoundingC.y; // 3 - в итоге получаем координаты нажатия внутри родительского элемента var nowX, nowY; if (this.props.autoMove) { nowX = clientX; nowY = clientY; } else { nowX = clientX - x; nowY = clientY - y; } return { nowX: nowX, nowY: nowY }; } }, { key: "moveStartMouseOrTouch", value: function moveStartMouseOrTouch(e) { var moveCoord_ref = this.moveCoord.current; // if (moveCoord_ref.startTime !== 0) { // console.log('dubleClick!!!') // } var moveStart = this.props.moveStart; this.isTouch.current = true; var _this$getInCoord = this.getInCoord(e), nowX = _this$getInCoord.nowX, nowY = _this$getInCoord.nowY; moveCoord_ref.startX = nowX; moveCoord_ref.startY = nowY; moveCoord_ref.nowX = nowX; moveCoord_ref.nowY = nowY; moveCoord_ref.startTime = Date.now(); moveStart && moveStart(moveCoord_ref); } }, { key: "move", value: function move(e) { var _this$props = this.props, moveXY = _this$props.moveXY, autoMove = _this$props.autoMove, scrollable = _this$props.scrollable; !scrollable && e.preventDefault(); var mc = this.moveCoord.current; var prevDelta = this.prevDelta.current; var tch_ref = this.touchRef.current; if (this.isTouch.current) { var _this$getInCoord2 = this.getInCoord(e), nowX = _this$getInCoord2.nowX, nowY = _this$getInCoord2.nowY; // формируем дельты if (mc.nowX !== 0) { mc.deltaX = nowX - mc.nowX; } if (mc.nowY !== 0) { mc.deltaY = nowY - mc.nowY; } mc.nowX = nowX; mc.nowY = nowY; if (mc.deltaX === mc.deltaY && mc.nowX !== 0 && mc.nowY !== 0) { mc.deltaY = prevDelta.y; mc.deltaX = prevDelta.x; } prevDelta = { x: mc.deltaX, y: mc.deltaY }; mc.itXorY = Math.abs(mc.deltaX) > Math.abs(mc.deltaY) ? 'x' : 'y'; mc.direction = mc.itXorY === 'x' ? directionX[Math.sign(mc.deltaX)] : directionY[Math.sign(mc.deltaY)]; if (this.slip === this.slipSensitivity && mc.startItXorY === '' && mc.startDirection === '') { mc.startItXorY = mc.itXorY; mc.startDirection = mc.direction; } else if (this.slip < this.slipSensitivity + 1) { this.slip = this.slip + 1; } mc.shiftX = mc.nowX - mc.startX; mc.shiftY = mc.nowY - mc.startY; if (autoMove) { tch_ref.style.transform = "translate3d(".concat(mc.shiftX, "px, ").concat(mc.shiftY, "px, 0px)"); tch_ref.style.transition = "transform 0ms"; } else { moveXY && moveXY(mc); } } } }, { key: "moveDetectEnd", value: function moveDetectEnd() { var moveEnd = this.props.moveEnd; var moveCoord_ref = this.moveCoord.current; if (moveCoord_ref.startTime === 0) { // выходим если событие End пришло не от нашего объекта return; } var sensitivityTime = 300; if (Date.now() - moveCoord_ref.startTime < sensitivityTime && moveCoord_ref.shiftX !== 0 && moveCoord_ref.shiftY !== 0) { moveCoord_ref.inertia = true; } this.isTouch.current = false; if (this.props.autoMove) { this.moveHome(); } else { moveEnd && moveEnd(moveCoord_ref); } this.moveCoordInit(); } }, { key: "moveHome", value: function moveHome() { var tch_ref = this.touchRef.current; tch_ref.style.transform = "translate3d(0px, 0px, 0px)"; tch_ref.style.transition = "transform 200ms ease"; } }, { key: "render", value: function render() { var _this$props2 = this.props, children = _this$props2.children, _this$props2$componen = _this$props2.component, Component = _this$props2$componen === void 0 ? 'div' : _this$props2$componen; _this$props2.innerRef; _this$props2.autoMove; _this$props2.touchpad; _this$props2.scrollable; _this$props2.moveStart; _this$props2.moveXY; _this$props2.moveEnd; var otherProps = _objectWithoutProperties(_this$props2, ["children", "component", "innerRef", "autoMove", "touchpad", "scrollable", "moveStart", "moveXY", "moveEnd"]); return /*#__PURE__*/React.createElement(Component, _extends({ ref: this.touchRef }, otherProps), children); } }]); return TouchDriver; }(React.Component); TouchDriver.propTypes = { /** * Это контент между открывающим и закрывающим тегом компонента. */ children: PropTypes.node, /** * Объект содержит jss стили компонента. */ classes: PropTypes.object, /** * Чтобы указать CSS классы, используйте этот атрибут. */ className: PropTypes.string, /** * Корневой узел. Это HTML элемент или компонент. */ component: PropTypes.elementType, /** * ref ссылка компонента. */ innerRef: PropTypes.object, /** * Если true, компонент перемещается сам. */ autoMove: PropTypes.bool, /** * Если true, не останавливает нативный скролл при движении на поверхности TouchDriver. */ scrollable: PropTypes.bool, /** * Если true, учитывается движение по touchpad. */ touchpad: PropTypes.bool, /** * Вызывается при касании к области внутри компонента. */ moveStart: PropTypes.func, /** * Вызывается при движении курсора или пальца по области и за ее пределами. * Если до этого сработал moveStart. */ moveXY: PropTypes.func, /** * Вызывается при окончании движения. */ moveEnd: PropTypes.func }; TouchDriver.defaultProps = { component: 'div', autoMove: false, touchpad: false, scrollable: false }; export default TouchDriver;