@evg-b/evg-ui
Version:
EVG-UI library inspired by Material Design.
368 lines (313 loc) • 13.3 kB
JavaScript
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;