@shopgate/engage
Version:
Shopgate's ENGAGE library.
54 lines • 10.8 kB
JavaScript
function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){_typeof=function _typeof(obj){return typeof obj;};}else{_typeof=function _typeof(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};}return _typeof(obj);}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor;}function _callSuper(_this,derived,args){function isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{return!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}));}catch(e){return false;}}derived=_getPrototypeOf(derived);return _possibleConstructorReturn(_this,isNativeReflectConstruct()?Reflect.construct(derived,args||[],_getPrototypeOf(_this).constructor):derived.apply(_this,args));}function _possibleConstructorReturn(self,call){if(call&&(_typeof(call)==="object"||typeof call==="function")){return call;}return _assertThisInitialized(self);}function _assertThisInitialized(self){if(self===void 0){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}function _getPrototypeOf(o){_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf:function _getPrototypeOf(o){return o.__proto__||Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function");}subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:true,configurable:true}});if(superClass)_setPrototypeOf(subClass,superClass);}function _setPrototypeOf(o,p){_setPrototypeOf=Object.setPrototypeOf||function _setPrototypeOf(o,p){o.__proto__=p;return o;};return _setPrototypeOf(o,p);}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React,{PureComponent}from'react';import PropTypes from'prop-types';import cxs from'classnames';import styles from"./style";import Handle from"./components/Handle";import{isTouchDevice}from"../../core";import{generateLinearEasingCallback,generateExponentialEasingCallback,getRangeStyle,getTouchPositionX,getAbsoluteValue,getRelativeValue}from"./helper";/**
* The range slider component.
*/var RangeSlider=/*#__PURE__*/function(_PureComponent){/**
* Constructor
* @param {Object} props The component properties
*/function RangeSlider(props){var _this2;_classCallCheck(this,RangeSlider);_this2=_callSuper(this,RangeSlider,[props]);/**
* Processes touch start events on handles.
* @param {Object} event The touch event
* @param {number} index The index of the touched handle.
*/_defineProperty(_this2,"handleTouchStart",function(event,index){_this2.addEventListeners();_this2.draggedHandle=index;// Calculate the relative offset to the handles center
var handleDOMElement=event.target;// Get the handles bounding rectangle ...
var handleRect=handleDOMElement.getBoundingClientRect();// ... and calculate its absolute center.
var handleCenterX=handleRect.left+handleDOMElement.offsetWidth/2;// Store the signed distanced between the current touch offset and the handle center.
_this2.touchOffset=getTouchPositionX(event)-handleCenterX;});/**
* Processes move events on handles.
* @param {Object} event The touch event
*/_defineProperty(_this2,"handleTouchMove",function(event){if(_this2.props.min===_this2.props.max){return;}if(_this2.draggedHandle===null){return;}var _this2$domElement$cur=_this2.domElement.current.getBoundingClientRect(),offsetWidth=_this2$domElement$cur.width,offsetLeft=_this2$domElement$cur.left;// Calculate the absolute offset where the element was touched...
var deltaX=getTouchPositionX(event)-offsetLeft-_this2.touchOffset;// ...and convert it into a relative value between [0...1].
deltaX=Math.max(0,Math.min(1,deltaX/offsetWidth));var stateUpdate={};if(_this2.draggedHandle===1){// Right handle dragged
if(_this2.state.rangeMin<deltaX){stateUpdate.rangeMax=Math.min(1,deltaX);_this2.draggedHandlePixelOffset=Math.abs(stateUpdate.rangeMax-_this2.state.rangeMax);}else{// Not in valid range, swap handles
_this2.draggedHandle=0;stateUpdate.rangeMax=_this2.state.rangeMin;stateUpdate.rangeMin=deltaX;_this2.draggedHandlePixelOffset=Math.abs(stateUpdate.rangeMin-_this2.state.rangeMin);}}else if(_this2.draggedHandle===0){// Left handle dragged
if(_this2.state.rangeMax>deltaX){stateUpdate.rangeMin=Math.max(0,deltaX);_this2.draggedHandlePixelOffset=Math.abs(stateUpdate.rangeMin-_this2.state.rangeMin);}else{// Not in valid range, swap handles
_this2.draggedHandle=1;stateUpdate.rangeMin=_this2.state.rangeMax;stateUpdate.rangeMax=deltaX;_this2.draggedHandlePixelOffset=Math.abs(stateUpdate.rangeMax-_this2.state.rangeMax);}}_this2.draggedHandlePixelOffset*=offsetWidth;_this2.setState(stateUpdate,_this2.triggerChangeCallback);});/**
* Processes global touch end events for handles.
* @param {Object} e The touch event
*/_defineProperty(_this2,"handleTouchEnd",function(){_this2.removeEventListeners();_this2.touchOffset=0;_this2.draggedHandle=null;});/**
* Processes outer range touch end events.
* @param {Object} event The touch event
*/_defineProperty(_this2,"handleRangeTouch",function(event){var _this2$domElement$cur2=_this2.domElement.current.getBoundingClientRect(),offsetWidth=_this2$domElement$cur2.width,offsetLeft=_this2$domElement$cur2.left;var dx=(getTouchPositionX(event)-offsetLeft)/offsetWidth;var d0=Math.abs(_this2.state.rangeMin-dx);var d1=Math.abs(_this2.state.rangeMax-dx);if(d0<d1){_this2.draggedHandle=0;}else{_this2.draggedHandle=1;}_this2.handleTouchMove(event);});/**
* Processes the input field values.
* @param {Object} event The change event.
*/_defineProperty(_this2,"handleInputChange",function(event){var max=_this2.props.max;var _event$target=event.target,value=_event$target.value,id=_event$target.id;var delta=Math.max(0,Math.min(1,value/(max/100)));var state=id==='price_from'?{rangeMin:delta}:{rangeMax:delta};_this2.setState(state);});_this2.draggedHandle=null;// 0 for left handle, 1 for right handle or null
_this2.domElement=React.createRef();_this2.touchOffset=0;_this2.draggedHandlePixelOffset=0;// The absolute pixel delta of the last handle move event.
_this2.state=_this2.getRange(props);_this2.useMouseEvents=!isTouchDevice();return _this2;}/**
* Updates the component properties.
* @param {Object} newProps The new component properties.
*/_inherits(RangeSlider,_PureComponent);return _createClass(RangeSlider,[{key:"UNSAFE_componentWillReceiveProps",value:function UNSAFE_componentWillReceiveProps(newProps){this.setState(this.getRange(newProps));}/**
* Get the easing function.
*/},{key:"ease",get:function get(){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 get(){return{linear:generateLinearEasingCallback(this.props.resolution),exponential:generateExponentialEasingCallback(1/this.props.factor)}[this.props.easing];}/**
* Adds event listeners
*/},{key:"addEventListeners",value:function addEventListeners(){if(this.useMouseEvents){document.addEventListener('mouseup',this.handleTouchEnd);document.addEventListener('mousemove',this.handleTouchMove);}else{document.addEventListener('touchend',this.handleTouchEnd);document.addEventListener('touchmove',this.handleTouchMove);}}/**
* Removes event listeners
*/},{key:"removeEventListeners",value:function removeEventListeners(){if(this.useMouseEvents){document.removeEventListener('mouseup',this.handleTouchEnd);document.removeEventListener('mousemove',this.handleTouchMove);}else{document.removeEventListener('touchend',this.handleTouchEnd);document.removeEventListener('touchmove',this.handleTouchMove);}}/**
* Get range min and max from props.
* @param {Object} props The component props.
* @returns {Object} The new state
*/},{key:"getRange",value:function getRange(props){var value=props.value,min=props.min,max=props.max;return{rangeMin:this.invertedEase(getRelativeValue(value[0],min,max)),rangeMax:this.invertedEase(getRelativeValue(value[1],min,max))};}},{key:"triggerChangeCallback",value:/**
* Calls the change callback in case of a state update.
*/function triggerChangeCallback(){var _this$props=this.props,value=_this$props.value,onChange=_this$props.onChange,min=_this$props.min,max=_this$props.max;if(!onChange){return;}var newRange=[getAbsoluteValue(this.ease(this.state.rangeMin),min,max,true),getAbsoluteValue(this.ease(this.state.rangeMax),min,max,true)];if(newRange!==value){onChange(newRange);}}/**
* Renders the component.
* @returns {JSX}
*/},{key:"render",value:function render(){var _this$props2=this.props,classNames=_this$props2.classNames,animationSpeed=_this$props2.animationSpeed;var speed=Math.round(1000/animationSpeed*this.draggedHandlePixelOffset);var rangeStyle=getRangeStyle(this.state.rangeMin,this.state.rangeMax,speed>10?speed:0);return React.createElement("div",{className:cxs(classNames.container,'engage__range-slider'),onMouseDown:this.handleRangeTouch,"aria-hidden":true},React.createElement("div",{className:cxs(classNames.outerRange,styles.outerRange),ref:this.domElement},React.createElement("div",{className:cxs(classNames.range,styles.range),style:rangeStyle},React.createElement(Handle,{index:0,onTouchStart:this.handleTouchStart,active:this.draggedHandle===0,classNames:classNames,useMouseEvents:this.useMouseEvents}),React.createElement(Handle,{index:1,onTouchStart:this.handleTouchStart,active:this.draggedHandle===1,classNames:classNames,useMouseEvents:this.useMouseEvents}))));}}]);}(PureComponent);_defineProperty(RangeSlider,"defaultProps",{animationSpeed:500,classNames:{},easing:'linear',factor:2,max:100,min:0,resolution:1,value:[0,100],onChange:null});export default RangeSlider;