@shopgate/pwa-common
Version:
Common library for the Shopgate Connect PWA.
262 lines (251 loc) • 9.18 kB
JavaScript
import _createClass from "@babel/runtime/helpers/createClass";
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { logger } from '@shopgate/pwa-core/helpers';
import styles from "./style";
import RangeSliderHandle from "./components/Handle";
import { generateLinearEasingCallback, generateExponentialEasingCallback, getRangeStyle, getTouchPositionX, getAbsoluteValue, getRelativeValue } from "./helper";
/**
* The range slider component.
* @deprecated Will be remove in v7.0.0.
* Please use `import { RangeSlider } from '@shopgate/engage/components'` instead.
*/
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
let RangeSlider = /*#__PURE__*/function (_Component) {
/**
* Constructor
* @param {Object} props The component properties
*/
function RangeSlider(props) {
var _this;
_this = _Component.call(this, props) || this;
/**
* Processes touch start events on handles.
* @param {Object} event The touch event
* @param {number} index The index of the touched handle.
*/
_this.handleTouchStart = (event, index) => {
_this.draggedHandle = index;
// Calculate the relative offset to the handles center
const handleDOMElement = event.target;
// Get the handles bounding rectangle ...
const handleRect = handleDOMElement.getBoundingClientRect();
// ... and calculate its absolute center.
const handleCenterX = handleRect.left + handleDOMElement.offsetWidth / 2;
// Store the signed distanced between the current touch offset and the handle center.
_this.touchOffset = getTouchPositionX(event) - handleCenterX;
};
/**
* Processes move events on handles.
* @param {Object} event The touch event
*/
_this.handleTouchMove = event => {
if (_this.props.min === _this.props.max) {
return;
}
if (_this.draggedHandle === null) {
return;
}
const {
offsetWidth,
offsetLeft
} = _this.domElement;
// Calculate the absolute offset where the element was touched...
let deltaX = getTouchPositionX(event) - offsetLeft - _this.touchOffset;
// ...and convert it into a relative value between [0...1].
deltaX = Math.max(0, Math.min(1, deltaX / offsetWidth));
const stateUpdate = {};
if (_this.draggedHandle === 1) {
// Right handle dragged
if (_this.state.rangeMin < deltaX) {
stateUpdate.rangeMax = Math.min(1, deltaX);
_this.draggedHandlePixelOffset = Math.abs(stateUpdate.rangeMax - _this.state.rangeMax);
} else {
// Not in valid range, swap handles
_this.draggedHandle = 0;
stateUpdate.rangeMax = _this.state.rangeMin;
stateUpdate.rangeMin = deltaX;
_this.draggedHandlePixelOffset = Math.abs(stateUpdate.rangeMin - _this.state.rangeMin);
}
} else if (_this.draggedHandle === 0) {
// Left handle dragged
if (_this.state.rangeMax > deltaX) {
stateUpdate.rangeMin = Math.max(0, deltaX);
_this.draggedHandlePixelOffset = Math.abs(stateUpdate.rangeMin - _this.state.rangeMin);
} else {
// Not in valid range, swap handles
_this.draggedHandle = 1;
stateUpdate.rangeMin = _this.state.rangeMax;
stateUpdate.rangeMax = deltaX;
_this.draggedHandlePixelOffset = Math.abs(stateUpdate.rangeMax - _this.state.rangeMax);
}
}
_this.draggedHandlePixelOffset *= _this.domElement.offsetWidth;
_this.setState(stateUpdate, _this.triggerChangeCallback);
};
/**
* Processes global touch end events for handles.
* @param {Object} e The touch event
*/
_this.handleTouchEnd = () => {
_this.touchOffset = 0;
_this.draggedHandle = null;
};
/**
* Processes outer range touch end events.
* @param {Object} event The touch event
*/
_this.handleRangeTouch = event => {
const {
offsetWidth,
offsetLeft
} = _this.domElement;
const dx = (getTouchPositionX(event) - offsetLeft) / offsetWidth;
const d0 = Math.abs(_this.state.rangeMin - dx);
const d1 = Math.abs(_this.state.rangeMax - dx);
if (d0 < d1) {
_this.draggedHandle = 0;
} else {
_this.draggedHandle = 1;
}
_this.handleTouchMove(event);
};
logger.warn('===== RangeSlider deprecated =====\nThe RangeSlider component and it\'s related components (@shopgate/pwa-common/component/RangeSlider) are deprecated and will be removed in @shopgate/engage v7.0.0.\nPlease use: import { RangeSlider } from \'@shopgate/engage/components\'.\n===================================');
_this.draggedHandle = null; // 0 for left handle, 1 for right handle or null
_this.domElement = null;
_this.touchOffset = 0;
_this.draggedHandlePixelOffset = 0; // The absolute pixel delta of the last handle move event.
_this.state = _this.getRange(props);
return _this;
}
/**
* Sets the global event listeners when component mounts.
*/
_inheritsLoose(RangeSlider, _Component);
var _proto = RangeSlider.prototype;
_proto.componentDidMount = function componentDidMount() {
document.addEventListener('touchend', this.handleTouchEnd);
document.addEventListener('touchmove', this.handleTouchMove);
}
/**
* Updates the component properties.
* @param {Object} newProps The new component properties.
*/;
_proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(newProps) {
this.setState(this.getRange(newProps));
}
/**
* Removes the global event listeners when component unmounts.
*/;
_proto.componentWillUnmount = function componentWillUnmount() {
document.removeEventListener('touchend', this.handleTouchEnd);
document.removeEventListener('touchmove', this.handleTouchMove);
}
/**
* Get the easing function.
*/;
/**
* Get range min and max from props.
* @param {Object} props The component props.
* @returns {Object} The new state
*/
_proto.getRange = function getRange(props) {
const {
value,
min,
max
} = props;
return {
rangeMin: this.invertedEase(getRelativeValue(value[0], min, max)),
rangeMax: this.invertedEase(getRelativeValue(value[1], min, max))
};
};
/**
* Calls the change callback in case of a state update.
*/
_proto.triggerChangeCallback = function triggerChangeCallback() {
const {
value,
onChange,
min,
max
} = this.props;
if (!onChange) {
return;
}
const newRange = [getAbsoluteValue(this.ease(this.state.rangeMin), min, max, true), getAbsoluteValue(this.ease(this.state.rangeMax), min, max, true)];
if (newRange !== value) {
onChange(newRange);
}
}
/**
* Creates a new handle component.
* @param {number} index The index of the component. Must be either 0 or 1.
* @returns {JSX}
*/;
_proto.makeHandle = function makeHandle(index) {
return /*#__PURE__*/_jsx(RangeSliderHandle, {
index: index,
onTouchStart: this.handleTouchStart,
active: this.draggedHandle === index,
classNames: this.props.classNames
});
}
/**
* Renders the component.
* @returns {JSX}
*/;
_proto.render = function render() {
// Calculate the animation speed.
const animationSpeed = Math.round(1000 / this.props.animationSpeed * this.draggedHandlePixelOffset);
const rangeStyle = getRangeStyle(this.state.rangeMin, this.state.rangeMax, animationSpeed > 10 ? animationSpeed : 0);
return /*#__PURE__*/_jsx("div", {
className: `${this.props.classNames.container || ''} common__range-slider`,
onTouchStart: this.handleRangeTouch,
children: /*#__PURE__*/_jsx("div", {
className: `${this.props.classNames.outerRange || ''} ${styles.outerRange}`,
ref: ref => {
this.domElement = ref;
},
children: /*#__PURE__*/_jsxs("div", {
className: `${this.props.classNames.range || ''} ${styles.range}`,
style: rangeStyle,
children: [this.makeHandle(0), this.makeHandle(1)]
})
})
});
};
return _createClass(RangeSlider, [{
key: "ease",
get: function () {
return {
linear: generateLinearEasingCallback(this.props.resolution),
exponential: generateExponentialEasingCallback(this.props.factor)
}[this.props.easing];
}
/**
* Get the function to invert an eased value to it's original value.
*/
}, {
key: "invertedEase",
get: function () {
return {
linear: generateLinearEasingCallback(this.props.resolution),
exponential: generateExponentialEasingCallback(1 / this.props.factor)
}[this.props.easing];
}
}]);
}(Component);
RangeSlider.defaultProps = {
animationSpeed: 500,
classNames: {},
easing: 'linear',
factor: 2,
max: 100,
min: 0,
resolution: 1,
value: [0, 100],
onChange: null
};
export default RangeSlider;