UNPKG

@shopgate/pwa-common

Version:

Common library for the Shopgate Connect PWA.

262 lines (251 loc) • 9.18 kB
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;