@shopgate/engage
Version:
Shopgate's ENGAGE library.
38 lines • 7.78 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,{Component}from'react';import PropTypes from'prop-types';import debounce from'lodash/debounce';import I18n from'@shopgate/pwa-common/components/I18n';import RippleButton from'@shopgate/pwa-ui-shared/RippleButton';import{themeConfig}from'@shopgate/pwa-common/helpers/config';import styles from"./style";var variables=themeConfig.variables;/**
* The height of one row.
* @type {number}
*/export var CHIP_ROW_HEIGHT=34;/**
* The minimum width that a chip should have.
* @type {number}
*/export var CHIP_MINIMUM_WIDTH=60;/**
* The ChipLayout component.
*/var ChipLayout=/*#__PURE__*/function(_Component){function ChipLayout(){var _this2;_classCallCheck(this,ChipLayout);for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++){args[_key]=arguments[_key];}_this2=_callSuper(this,ChipLayout,[].concat(args));/**
* Debounced, eg. layout effect
*/_defineProperty(_this2,"processHiddenElementsDebounced",debounce(_this2.processHiddenElements,50));return _this2;}_inherits(ChipLayout,_Component);return _createClass(ChipLayout,[{key:"componentDidMount",value:/**
* When the component mounts we need to initially process all children.
*/function componentDidMount(){this.processHiddenElementsDebounced();}/**
* Eveyry time pathname or other prop changes this callback is called.
* This funtion will start processing hidden elements in order to check if "more" button
* should be rendered.
*
* It must be done on every prop change, including the pathname.
* Sometimes this component is rendered invisible, then since `.processHiddenElements` uses
* refs.clientHeight it would always be zero.
*/},{key:"componentDidUpdate",value:function componentDidUpdate(){this.processHiddenElementsDebounced();}/**
* Returns the maximum height the container should have.
* @returns {number}
*/},{key:"maxContentHeight",get:function get(){// 8 -> container padding.
return CHIP_ROW_HEIGHT*this.props.maxRows+8;}/**
* Returns the more button styles.
* @return {string} The store button class name.
*/},{key:"moreButtonStyles",get:function get(){if(this.props.invertMoreButton){return styles.moreButtonInverted;}return styles.moreButton;}/**
* Loops through all children to make sure the more button appears if there is too much content.
*/},{key:"processHiddenElements",value:function processHiddenElements(){var _this3=this;if(!this.containerRef){return;}// Find out if there are overflowing elements.
var lastVisibleElement=0;var showMoreButton=this.containerRef.scrollHeight>this.containerRef.clientHeight;var containerHeight=this.containerRef.clientHeight;var chips=Array.from(this.layoutRef.children);this.moreButtonRef.style.display=showMoreButton?'block':'none';this.layoutRef.style.minHeight=showMoreButton?"".concat(this.maxContentHeight,"px"):'0px';// If the more button is not visible we don't need to process anything.
if(!showMoreButton){return;}// Hide or show chips that are hidden due to overflow.
chips.forEach(function(child,index){var isVisible=child.offsetTop+child.clientHeight<containerHeight;child.setAttribute('style',"display: ".concat(isVisible?'flex':'none',";"));if(isVisible){lastVisibleElement=index;}});// Hide the more button if previous assumption was incorrect.
if(lastVisibleElement===chips.length-1){this.moreButtonRef.style.display='none';return;}// Hide elements so that the 'more button' has enough space.
chips.slice(0,lastVisibleElement+1).reverse().every(function(element){var offsetBottom=element.offsetTop+element.clientHeight;if(_this3.moreButtonRef.offsetTop>offsetBottom){return true;}var buttonSpaceRequired=_this3.moreButtonRef.clientWidth+variables.gap.big;var elementRight=_this3.containerRef.clientWidth-(element.offsetLeft+element.clientWidth);var spaceDiff=buttonSpaceRequired-elementRight;var remainingChipWidth=element.clientWidth-spaceDiff;if(remainingChipWidth>CHIP_MINIMUM_WIDTH){element.setAttribute('style',"max-width: ".concat(remainingChipWidth,"px"));return false;}if(element.offsetTop!==chips[lastVisibleElement].offsetTop){element.setAttribute('style','display: none');return false;}element.setAttribute('style','display: none');return true;});}},{key:"render",value:/**
* Renders the component.
* @returns {JSX}
*/function render(){var _this4=this;return React.createElement("div",{ref:function ref(element){_this4.containerRef=element;},className:"".concat(styles.container(this.maxContentHeight)," engage__chip-layout")},React.createElement("div",{ref:function ref(element){_this4.layoutRef=element;},className:styles.layout},this.props.children),React.createElement("div",{ref:function ref(element){_this4.moreButtonRef=element;},className:styles.moreButtonWrapper},React.createElement(RippleButton,{fill:true,type:"plain",className:this.moreButtonStyles,onClick:this.props.handleMoreButton},React.createElement(I18n.Text,{string:this.props.moreLabel}))));}}]);}(Component);_defineProperty(ChipLayout,"defaultProps",{children:null,handleMoreButton:function handleMoreButton(){},invertMoreButton:false,maxRows:2,moreLabel:'more',pathname:''});export default ChipLayout;