@shopgate/engage 7.25.1-beta.1 → 7.25.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/a11y/components/Section/index.js +1 -1
  2. package/cart/components/PaymentBar/PaymentBarContent.js +2 -2
  3. package/cart/components/PaymentBar/PaymentBarContent.style.js +1 -1
  4. package/components/Footer/Footer.js +23 -4
  5. package/components/Footer/Footer.style.js +7 -1
  6. package/components/ScrollHeader/index.js +2 -2
  7. package/components/View/components/Content/index.js +1 -1
  8. package/core/helpers/updateLegacyNavigationBar.js +2 -3
  9. package/core/hooks/index.js +1 -1
  10. package/core/hooks/useScroll.js +7 -0
  11. package/package.json +7 -7
  12. package/product/components/RelationsSlider/RelationsSliderContent.js +1 -1
  13. package/product/components/RelationsSlider/style.js +1 -1
  14. package/components/Footer/constants.js +0 -1
  15. package/components/Footer/helpers.js +0 -75
  16. package/core/hooks/useLongPress.js +0 -37
  17. package/core/hooks/useScrollDirectionChange.js +0 -33
  18. package/development/action-creators/index.js +0 -1
  19. package/development/action-creators/settings.js +0 -9
  20. package/development/action-creators/storage.js +0 -6
  21. package/development/components/DevelopmentTools/DevelopmentTools.js +0 -6
  22. package/development/components/DevelopmentTools/Shortcuts.js +0 -4
  23. package/development/components/DevelopmentTools/hooks.js +0 -8
  24. package/development/components/DevelopmentTools/index.js +0 -1
  25. package/development/components/SimulatedInsets/SimulatedInsetBottom.js +0 -7
  26. package/development/components/SimulatedInsets/SimulatedInsetTop.js +0 -12
  27. package/development/components/SimulatedInsets/SimulatedInsets.js +0 -6
  28. package/development/components/SimulatedInsets/index.js +0 -1
  29. package/development/components/index.js +0 -1
  30. package/development/constants/actionTypes.js +0 -1
  31. package/development/constants/index.js +0 -1
  32. package/development/reducers/index.js +0 -1
  33. package/development/reducers/settings.js +0 -10
  34. package/development/reducers/storage.js +0 -9
  35. package/development/selectors/index.js +0 -1
  36. package/development/selectors/settings.js +0 -21
  37. package/development/selectors/storage.js +0 -16
  38. package/development/streams/index.js +0 -1
  39. package/development/streams/insets.js +0 -4
  40. package/development/subscriptions/index.js +0 -6
@@ -1,4 +1,4 @@
1
- var _excluded=["title","titleParams","children"];function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}import React,{useRef,useState,useMemo,useLayoutEffect}from'react';import PropTypes from'prop-types';import kebabCase from'lodash/kebabCase';import{I18n}from'@shopgate/engage/components';import{VisuallyHidden}from"../index";/**
1
+ var _excluded=["title","titleParams","children"];function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}import React,{useRef,useState,useMemo,useLayoutEffect}from'react';import PropTypes from'prop-types';import kebabCase from'lodash/kebabCase';import{I18n}from'@shopgate/engage/components';import VisuallyHidden from"../VisuallyHidden";/**
2
2
  * Checks the section ref has suitable child nodes.
3
3
  * @param {Object} ref A React ref.
4
4
  * @param {string} headlineId The ID of the section headline.
@@ -1,4 +1,4 @@
1
- import*as React from'react';import PropTypes from'prop-types';import classNames from'classnames';import Grid from'@shopgate/pwa-common/components/Grid';import{SurroundPortals}from'@shopgate/engage/components';import{CART_PAYMENT_BAR,CART_PAYMENT_BAR_TOTALS}from'@shopgate/pwa-common-commerce/cart/constants/Portals';import PaymentBarShippingCost from"./PaymentBarShippingCost";import PaymentBarDiscounts from"./PaymentBarDiscounts";import PaymentBarTax from"./PaymentBarTax";import PaymentBarSubTotal from"./PaymentBarSubTotal";import PaymentBarGrandTotal from"./PaymentBarGrandTotal";import PaymentBarCheckoutButton from"./PaymentBarCheckoutButton";import PaymentBarPromotionCoupons from"./PaymentBarPromotionCoupons";import PaymentBarAppliedPromotions from"./PaymentBarAppliedPromotions";import{wrapper,container,checkoutButtonContainer,checkoutButton}from"./PaymentBarContent.style";/**
1
+ import*as React from'react';import PropTypes from'prop-types';import Grid from'@shopgate/pwa-common/components/Grid';import{SurroundPortals}from'@shopgate/engage/components';import{CART_PAYMENT_BAR,CART_PAYMENT_BAR_TOTALS}from'@shopgate/pwa-common-commerce/cart/constants/Portals';import PaymentBarShippingCost from"./PaymentBarShippingCost";import PaymentBarDiscounts from"./PaymentBarDiscounts";import PaymentBarTax from"./PaymentBarTax";import PaymentBarSubTotal from"./PaymentBarSubTotal";import PaymentBarGrandTotal from"./PaymentBarGrandTotal";import PaymentBarCheckoutButton from"./PaymentBarCheckoutButton";import PaymentBarPromotionCoupons from"./PaymentBarPromotionCoupons";import PaymentBarAppliedPromotions from"./PaymentBarAppliedPromotions";import{wrapper,container,checkoutButtonContainer,checkoutButton}from"./PaymentBarContent.style";/**
2
2
  * The PaymentBarContent component.
3
3
  * @returns {JSX}
4
- */function PaymentBarContent(_ref){var showSeparator=_ref.showSeparator;return React.createElement("div",{className:classNames(wrapper,'theme__cart__payment-bar')},React.createElement(SurroundPortals,{portalName:CART_PAYMENT_BAR},React.createElement(Grid,{className:container},React.createElement(SurroundPortals,{portalName:CART_PAYMENT_BAR_TOTALS},React.createElement(PaymentBarSubTotal,{showSeparator:showSeparator}),React.createElement(PaymentBarAppliedPromotions,{showSeparator:showSeparator}),React.createElement(PaymentBarPromotionCoupons,{showSeparator:showSeparator}),React.createElement(PaymentBarDiscounts,{showSeparator:showSeparator}),React.createElement(PaymentBarShippingCost,{showSeparator:showSeparator}),React.createElement(PaymentBarTax,{showSeparator:showSeparator}),React.createElement(PaymentBarGrandTotal,{showSeparator:showSeparator}))),React.createElement("div",{className:checkoutButtonContainer},React.createElement("div",{className:checkoutButton},React.createElement(PaymentBarCheckoutButton,null)))));}PaymentBarContent.defaultProps={showSeparator:true};export default PaymentBarContent;
4
+ */function PaymentBarContent(_ref){var showSeparator=_ref.showSeparator;return React.createElement("div",{className:wrapper},React.createElement(SurroundPortals,{portalName:CART_PAYMENT_BAR},React.createElement(Grid,{className:container},React.createElement(SurroundPortals,{portalName:CART_PAYMENT_BAR_TOTALS},React.createElement(PaymentBarSubTotal,{showSeparator:showSeparator}),React.createElement(PaymentBarAppliedPromotions,{showSeparator:showSeparator}),React.createElement(PaymentBarPromotionCoupons,{showSeparator:showSeparator}),React.createElement(PaymentBarDiscounts,{showSeparator:showSeparator}),React.createElement(PaymentBarShippingCost,{showSeparator:showSeparator}),React.createElement(PaymentBarTax,{showSeparator:showSeparator}),React.createElement(PaymentBarGrandTotal,{showSeparator:showSeparator}))),React.createElement("div",{className:checkoutButtonContainer},React.createElement("div",{className:checkoutButton},React.createElement(PaymentBarCheckoutButton,null)))));}PaymentBarContent.defaultProps={showSeparator:true};export default PaymentBarContent;
@@ -1 +1 @@
1
- import{css}from'glamor';import{isIOSTheme}from'@shopgate/engage/core';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var colors=themeConfig.colors,variables=themeConfig.variables,shadows=themeConfig.shadows;export var wrapper=css({background:colors.light,boxShadow:shadows.cart.paymentBar,position:'relative',zIndex:2,paddingBottom:'var(--safe-area-inset-bottom)'});export var container=css({padding:isIOSTheme()?variables.gap.small:variables.gap.big,paddingBottom:0,lineHeight:1.45,flexWrap:'wrap',flexDirection:'column',minWidth:'auto'}).toString();export var checkoutButton=css({display:'flex',justifyContent:'flex-end',flexDirection:'column'});export var checkoutButtonContainer=css({background:colors.light,alignItems:'center',padding:isIOSTheme()?variables.gap.small:variables.gap.big,position:'relative',zIndex:2});export var spacer=css({width:isIOSTheme()?27:32,order:1,flexShrink:0}).toString();
1
+ import{css}from'glamor';import{isIOSTheme}from'@shopgate/engage/core';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var colors=themeConfig.colors,variables=themeConfig.variables,shadows=themeConfig.shadows;export var wrapper=css({background:colors.light,boxShadow:shadows.cart.paymentBar,position:'relative',zIndex:2});export var container=css({padding:isIOSTheme()?variables.gap.small:variables.gap.big,paddingBottom:0,lineHeight:1.45,flexWrap:'wrap',flexDirection:'column',minWidth:'auto'}).toString();export var checkoutButton=css({display:'flex',justifyContent:'flex-end',flexDirection:'column'});export var checkoutButtonContainer=css({background:colors.light,alignItems:'center',padding:isIOSTheme()?variables.gap.small:variables.gap.big,position:'relative',zIndex:2});export var spacer=css({width:isIOSTheme()?27:32,order:1,flexShrink:0}).toString();
@@ -1,5 +1,24 @@
1
- import React,{useRef,useEffect,useCallback}from'react';import PropTypes from'prop-types';import classNames from'classnames';import{UIEvents}from'@shopgate/engage/core/events';import{getAbsoluteHeight}from'@shopgate/engage/core/helpers';import{SHEET_EVENTS}from'@shopgate/engage/components';import*as classes from"./Footer.style";import{handleSafeAreaInsets,updateFooterHeight}from"./helpers";import{APP_FOOTER_ID,DATA_IGNORED}from"./constants";/**
1
+ 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 Portal from'@shopgate/pwa-common/components/Portal';import UIEvents from'@shopgate/pwa-core/emitters/ui';import{APP_FOOTER_CONTENT_BEFORE,APP_FOOTER_CONTENT_AFTER}from'@shopgate/pwa-common/constants/Portals';import{getAbsoluteHeight,getStyle}from'@shopgate/pwa-common/helpers/dom';import{SHEET_EVENTS}from'@shopgate/pwa-ui-shared/Sheet';import{footer,updateInsetBackgroundColor,updateFooterHeight}from"./Footer.style";var APP_FOOTER_ID='AppFooter';var DATA_IGNORED='data-footer-inset-update-ignore';/**
2
2
  * The footer component.
3
- * @param {Object} props The component props.
4
- * @returns {JSX.Element}
5
- */var Footer=function Footer(_ref){var children=_ref.children;var footerRef=useRef(null);var performFooterUpdate=useCallback(function(){handleSafeAreaInsets(footerRef.current);updateFooterHeight(getAbsoluteHeight(footerRef.current));},[]);var handleShow=useCallback(function(){updateFooterHeight(getAbsoluteHeight(footerRef.current));},[]);var handleHide=useCallback(function(){updateFooterHeight(0);},[]);useEffect(function(){UIEvents.addListener(SHEET_EVENTS.OPEN,handleHide);UIEvents.addListener(SHEET_EVENTS.CLOSE,handleShow);return function(){UIEvents.removeListener(SHEET_EVENTS.OPEN,handleHide);UIEvents.removeListener(SHEET_EVENTS.CLOSE,handleShow);};},[handleHide,handleShow]);useEffect(function(){performFooterUpdate();var observer=new MutationObserver(function(mutations){var update=mutations.filter(function(mutation){return mutation.target.getAttribute(DATA_IGNORED)!=='true';}).length>0;if(update){performFooterUpdate();}});observer.observe(footerRef.current,{childList:true,subtree:true,attributes:true,attributeFilter:['style','class']});return function(){observer.disconnect();};},[performFooterUpdate]);return React.createElement("div",{className:classNames(classes.footer,'engage__footer')},React.createElement("div",{id:APP_FOOTER_ID,ref:footerRef},children));};Footer.defaultProps={children:null};export default Footer;
3
+ */var Footer=/*#__PURE__*/function(_PureComponent){function Footer(){var _this2;_classCallCheck(this,Footer);for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++){args[_key]=arguments[_key];}_this2=_callSuper(this,Footer,[].concat(args));_defineProperty(_this2,"ref",React.createRef());/** Perform hide action */_defineProperty(_this2,"hide",function(){if(_this2.ref.current){updateFooterHeight(0);}});/** Perform show action */_defineProperty(_this2,"show",function(){if(_this2.ref.current){updateFooterHeight(getAbsoluteHeight(_this2.ref.current));}});return _this2;}_inherits(Footer,_PureComponent);return _createClass(Footer,[{key:"componentDidMount",value:function componentDidMount(){var _this3=this;this.performFooterUpdate();var observer=new MutationObserver(function(mutations){var update=mutations.filter(function(mutation){return mutation.target.getAttribute(DATA_IGNORED)!=='true';}).length>0;if(update){_this3.performFooterUpdate();}});observer.observe(this.ref.current,{attributes:true,childList:true,subtree:true});UIEvents.addListener(SHEET_EVENTS.OPEN,this.hide);UIEvents.addListener(SHEET_EVENTS.CLOSE,this.show);}/** @inheritDoc */},{key:"componentWillUnmount",value:function componentWillUnmount(){UIEvents.removeListener(SHEET_EVENTS.OPEN,this.hide);UIEvents.removeListener(SHEET_EVENTS.CLOSE,this.show);}},{key:"getInsetBackgroundColor",value:/**
4
+ * Retrieves the background color for the footer inset.
5
+ * @param {NodeList} elements The DOM elements to inspect.
6
+ * @returns {string|null}
7
+ */function getInsetBackgroundColor(elements){var _this4=this;/**
8
+ * The background color of the bottom inset needs to identical to the last entry of the footer.
9
+ * So we loop backwards to the elements to find the first visible one.
10
+ */var color=Array.from(elements).reverse().reduce(function(result,element){var ignore=element.getAttribute(DATA_IGNORED)==='true';if(result||ignore){// Nothing to do, since the color was already determined or the element can be ignored.
11
+ return result;}if(element.id===APP_FOOTER_ID){// Inspect core portal.
12
+ return _this4.getInsetBackgroundColor(element.children);}if('clientHeight'in element){// Take the background color of the last visible element from the end of the footer.
13
+ return getStyle(element,'backgroundColor');}// Nothing happened within this loop - proceed with the next one.
14
+ return result;},null);if(color==='rgba(0, 0, 0, 0)'||color==='transparent'){return null;}return color||null;}},{key:"performFooterUpdate",value:/**
15
+ * Performs an update of the footer: background color, height.
16
+ */function performFooterUpdate(){if(this.ref.current){updateFooterHeight(getAbsoluteHeight(this.ref.current));updateInsetBackgroundColor(this.getInsetBackgroundColor(this.ref.current.children));}}/**
17
+ * Checks if the footer has visible content.
18
+ * @returns {boolean}
19
+ */},{key:"hasVisibleContent",value:function hasVisibleContent(){if(this.ref.current){var elements=this.ref.current.parentElement.querySelectorAll("div.".concat(footer.toString()," > *:not(#").concat(APP_FOOTER_ID,"), #").concat(APP_FOOTER_ID," > *"));return Array.from(elements).filter(function(element){return element.getAttribute(DATA_IGNORED)!=='true'&&element.clientHeight>0;}).length>0;}return false;}/**
20
+ * @returns {JSX}
21
+ */},{key:"render",value:function render(){return React.createElement("div",{className:"".concat(footer," engage__footer"),ref:this.ref},React.createElement(Portal,{name:APP_FOOTER_CONTENT_BEFORE}),React.createElement("div",{id:APP_FOOTER_ID},this.props.children),React.createElement(Portal,{name:APP_FOOTER_CONTENT_AFTER}));}}]);}(PureComponent);_defineProperty(Footer,"defaultProps",{children:null/**
22
+ * Sets up the DOM Mutation Observer to take care that the footer inset always has the correct
23
+ * background color, which matches the background color of the last element within the footer.
24
+ */});export default Footer;
@@ -1 +1,7 @@
1
- function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{css}from'glamor';import{useScrollContainer}from'@shopgate/engage/core/helpers';export var footer=css(_extends({bottom:0,flexShrink:1,position:'relative',zIndex:1},!useScrollContainer()?{position:'sticky'}:{}));
1
+ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{css}from'glamor';import{useScrollContainer}from'@shopgate/engage/core/helpers/scrollContainer';var style=document.documentElement.style;/**
2
+ * Updates the background color of the bottom inset.
3
+ * @param {string} color The new background color
4
+ */export var updateInsetBackgroundColor=function updateInsetBackgroundColor(color){if(style.getPropertyValue('--footer-inset-background-color')!==color){style.setProperty('--footer-inset-background-color',color);}};/**
5
+ * Update the footer height
6
+ * @param {number} height height
7
+ */export var updateFooterHeight=function updateFooterHeight(height){var inset=Number(style.getPropertyValue('--safe-area-inset-bottom').replace(/\D/g,''));var footerHeight="".concat(inset+height,"px");if(style.getPropertyValue('--footer-height')!==footerHeight){style.setProperty('--footer-height',footerHeight);}};export var footer=css(_extends({bottom:0,flexShrink:1,position:'relative',zIndex:1},!useScrollContainer()?{position:'sticky'}:{},{':after':{backgroundColor:'var(--footer-inset-background-color, var(--page-background-color))',height:'var(--safe-area-inset-bottom)',content:' ',display:'inherit',position:'relative',zIndex:15}}));
@@ -1,5 +1,5 @@
1
- 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;}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import React,{useState}from'react';import PropTypes from'prop-types';import classNames from'classnames';import{useScrollDirectionChange}from'@shopgate/engage/core/hooks';import{root,scrolledIn,scrolledOut,transition}from"./style";/**
1
+ 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;}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import React,{useState,useCallback,useEffect}from'react';import PropTypes from'prop-types';import classNames from'classnames';import{viewScroll$}from'@shopgate/engage/core/streams';import{root,scrolledIn,scrolledOut,transition}from"./style";/**
2
2
  * Scroll Header component
3
3
  * @param {Object} props props
4
4
  * @returns {JSX}
5
- */function ScrollHeader(_ref){var className=_ref.className,children=_ref.children,hideOnScroll=_ref.hideOnScroll,scrollOffset=_ref.scrollOffset;var _useState=useState(false),_useState2=_slicedToArray(_useState,2),shouldHideHeader=_useState2[0],setShouldHideHeader=_useState2[1];useScrollDirectionChange({enabled:hideOnScroll,offset:scrollOffset,onScrollDown:function onScrollDown(){setShouldHideHeader(true);},onScrollUp:function onScrollUp(){setShouldHideHeader(false);}});return React.createElement("div",{className:classNames(root,transition,className,_defineProperty(_defineProperty({},scrolledIn,!shouldHideHeader),scrolledOut,shouldHideHeader))},children);}ScrollHeader.defaultProps={className:null,hideOnScroll:true,scrollOffset:100};export default ScrollHeader;
5
+ */function ScrollHeader(_ref){var className=_ref.className,children=_ref.children,hideOnScroll=_ref.hideOnScroll,scrollOffset=_ref.scrollOffset;var _useState=useState(false),_useState2=_slicedToArray(_useState,2),shouldHideHeader=_useState2[0],setShouldHideHeader=_useState2[1];var onScroll=useCallback(function(scrollEvent){var scrollTop=scrollEvent.scrollTop,scrolled=scrollEvent.scrolled,scrollOut=scrollEvent.scrollOut,scrollIn=scrollEvent.scrollIn;if(!scrolled){return;}if(!shouldHideHeader&&scrollOut&&scrollTop>=scrollOffset){setShouldHideHeader(true);}if(shouldHideHeader&&scrollIn){setShouldHideHeader(false);}},[scrollOffset,shouldHideHeader]);useEffect(function(){if(hideOnScroll){var subscription=viewScroll$.subscribe(onScroll);return function(){return subscription.unsubscribe();};}return undefined;});return React.createElement("div",{className:classNames(root,transition,className,_defineProperty(_defineProperty({},scrolledIn,!shouldHideHeader),scrolledOut,shouldHideHeader))},children);}ScrollHeader.defaultProps={className:null,hideOnScroll:true,scrollOffset:100};export default ScrollHeader;
@@ -23,6 +23,6 @@ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<argum
23
23
  * Removes the keyboardWillChange listener.
24
24
  */},{key:"componentWillUnmount",value:function componentWillUnmount(){var scrollTop;if(this.ref.current===window){scrollTop=window.scrollY;}else{scrollTop=this.ref.current.scrollTop;}router.update(this.context.id,{scrollTop:scrollTop},false);event.removeCallback(EVENT_KEYBOARD_WILL_CHANGE,this.handleKeyboardChange);}/**
25
25
  * @returns {Object}
26
- */},{key:"style",get:function get(){var noScrollOnKeyboard=this.props.noScrollOnKeyboard;var keyboardHeight=this.state.keyboardHeight;var overflow='inherit';if(this.scrollContainer){overflow=noScrollOnKeyboard&&keyboardHeight>0?'hidden':'auto';}return{overflow:overflow,paddingBottom:"calc(var(--page-content-offset-bottom) + ".concat(keyboardHeight,"px)")};}},{key:"render",value:/**
26
+ */},{key:"style",get:function get(){var noScrollOnKeyboard=this.props.noScrollOnKeyboard;var keyboardHeight=this.state.keyboardHeight;var overflow='inherit';if(this.scrollContainer){overflow=noScrollOnKeyboard&&keyboardHeight>0?'hidden':'auto';}return{overflow:overflow,paddingBottom:"calc(var(--tabbar-height) + ".concat(keyboardHeight,"px)")};}},{key:"render",value:/**
27
27
  * @return {JSX.Element}
28
28
  */function render(){return React.createElement(Swipeable,{onSwiped:this.handleSwipe,flickThreshold:0.6,delta:10},React.createElement("article",{className:"".concat(styles," engage__view__content ").concat(this.props.className),ref:this.scrollContainer?this.ref:null,style:this.style,role:"none"},React.createElement(Helmet,{title:appConfig.shopName}),React.createElement(Above,null),React.createElement(ResponsiveContainer,{breakpoint:">xs",webOnly:true},this.props.visible?React.createElement("div",{id:"PageHeaderBelow"}):null),React.createElement(ConditionalWrapper,{condition:!this.props.noContentPortal,wrapper:function wrapper(children){return React.createElement(SurroundPortals,{portalName:VIEW_CONTENT},children);}},this.props.children),React.createElement(Below,null)));}}],[{key:"getDerivedStateFromProps",value:function getDerivedStateFromProps(props,state){if(props.visible||state.keyboardHeight===0){return null;}return{keyboardHeight:0};}}]);}(Component);_defineProperty(ViewContent,"contextType",RouteContext);_defineProperty(ViewContent,"defaultProps",{className:'',children:null,noScrollOnKeyboard:false,noContentPortal:false,noKeyboardListener:false});export default(function(props){return React.createElement(RouteContext.Consumer,null,function(_ref2){var visible=_ref2.visible,_ref2$pattern=_ref2.pattern,pattern=_ref2$pattern===void 0?'':_ref2$pattern,_ref2$is=_ref2.is404,is404=_ref2$is===void 0?false:_ref2$is;return React.createElement(ViewContent,_extends({},props,{visible:visible,className:"route_".concat(is404?'404':pattern.replace(/[:/]/g,'_'))}));});});
@@ -1,7 +1,6 @@
1
- function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import Color from'color';import{isAvailable,StatusBar}from'@shopgate/native-modules';import{broadcastEvent}from'@shopgate/engage/core/commands';import{isDev}from'@shopgate/engage/core/helpers';import{UIEvents}from'@shopgate/engage/core/events';/**
1
+ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import Color from'color';import{isAvailable,StatusBar}from'@shopgate/native-modules';import broadcastEvent from'@shopgate/pwa-core/commands/broadcastEvent';/**
2
2
  * Updates the styles of the navigation bar of iOS devices.
3
3
  * @param {Object} options Options for the status bar.
4
4
  */export var updateLegacyNavigationBar=function updateLegacyNavigationBar(){var options=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};var targetTab=options.targetTab||'main';var isDefault=options.isDefault;var styles=_extends({},options.color&&{color:options.color},{},options.background&&{background:options.background},{},options.buttonColor&&{buttonColor:options.buttonColor},{},options.buttonColorDisabled&&{buttonColorDisabled:options.buttonColorDisabled},{},options.statusBarBackground&&{statusBarBackground:options.statusBarBackground});if(!styles.statusBarBackground&&styles.background){styles.statusBarBackground=styles.background;}var statusBarStyle;if(options.statusBarStyle){statusBarStyle=options.statusBarStyle;}else if(styles.statusBarBackground){statusBarStyle=Color(styles.statusBarBackground).isDark()?'light':'dark';}// Status bar update via native-modules deactivated for now since it doesn't work
5
5
  // reliable when opening a page inside the In-App-Browser.
6
- if(false&&isAvailable()){var style=statusBarStyle==='dark'?'dark-content':'light-content';StatusBar.setBarStyle({style:style});if(styles.statusBarBackground){StatusBar.setBackgroundColor({color:styles.statusBarBackground});}return;}var payload=_extends({},statusBarStyle&&{statusBarStyle:statusBarStyle},{},isDefault&&{isDefault:isDefault},{targetTab:targetTab,styles:styles});broadcastEvent({event:'updateNavigationBarStyle',parameters:[payload]});if(isDev){// Dispatch the payload in dev as regular event, so that simulated top inset can adopt the color
7
- UIEvents.emit('devInternalUpdateStatusBarStyle',payload);}};
6
+ if(false&&isAvailable()){var style=statusBarStyle==='dark'?'dark-content':'light-content';StatusBar.setBarStyle({style:style});if(styles.statusBarBackground){StatusBar.setBackgroundColor({color:styles.statusBarBackground});}return;}broadcastEvent({event:'updateNavigationBarStyle',parameters:[_extends({},statusBarStyle&&{statusBarStyle:statusBarStyle},{},isDefault&&{isDefault:isDefault},{targetTab:targetTab,styles:styles})]});};
@@ -1 +1 @@
1
- export{useAsyncMemo}from"./useAsyncMemo";export{useRoute}from"./useRoute";export{useTheme}from"./useTheme";export{useApp}from"./useApp";export{useCurrentProduct}from"./useCurrentProduct";export{useNavigation}from"./useNavigation";export{usePageConfig}from"./usePageConfig";export{usePageSettings}from"./usePageSettings";export{useWidgetConfig}from"./useWidgetConfig";export{useWidgetSettings}from"./useWidgetSettings";export{useWidgetStyles}from"./useWidgetStyles";export*from"./html";export{default as useScrollDirectionChange}from"./useScrollDirectionChange";export{default as useLongPress}from"./useLongPress";export{usePrevious}from"./usePrevious";export{useResponsiveValue}from'@shopgate/engage/components/ResponsiveContainer/hooks';
1
+ export{useAsyncMemo}from"./useAsyncMemo";export{useRoute}from"./useRoute";export{useTheme}from"./useTheme";export{useApp}from"./useApp";export{useCurrentProduct}from"./useCurrentProduct";export{useNavigation}from"./useNavigation";export{usePageConfig}from"./usePageConfig";export{usePageSettings}from"./usePageSettings";export{useWidgetConfig}from"./useWidgetConfig";export{useWidgetSettings}from"./useWidgetSettings";export{useWidgetStyles}from"./useWidgetStyles";export*from"./html";export{useScroll}from"./useScroll";export{usePrevious}from"./usePrevious";export{useResponsiveValue}from'@shopgate/engage/components/ResponsiveContainer/hooks';
@@ -0,0 +1,7 @@
1
+ import _throttle from"lodash/throttle";function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import{useEffect,useState,useCallback}from'react';/**
2
+ *
3
+ * @param {Function} callback callback
4
+ * @param {Object} [element] element
5
+ */export function useScroll(callback,element){var _useState=useState(0),_useState2=_slicedToArray(_useState,2),setScrollPosition=_useState2[1];var previousScrollTop=0;/**
6
+ * Scroll handler
7
+ */var handleDocumentScroll=useCallback(_throttle(function(){var container=element||document.documentElement||document.body;var currentScrollTop=container.scrollY===undefined?container.scrollTop:container.scrollY;setScrollPosition(function(previousPosition){previousScrollTop=previousPosition;return currentScrollTop;});callback({previousScrollTop:previousScrollTop,currentScrollTop:currentScrollTop});},250),[setScrollPosition,element,callback]);useEffect(function(){(element||window).addEventListener('scroll',handleDocumentScroll);return function(){return(element||window).removeEventListener('scroll',handleDocumentScroll);};},[handleDocumentScroll,element]);}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/engage",
3
- "version": "7.25.1-beta.1",
3
+ "version": "7.25.1-beta.2",
4
4
  "description": "Shopgate's ENGAGE library.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Shopgate <support@shopgate.com>",
@@ -16,12 +16,12 @@
16
16
  ],
17
17
  "dependencies": {
18
18
  "@shopgate/native-modules": "^1.0.0-beta.22",
19
- "@shopgate/pwa-common": "7.25.1-beta.1",
20
- "@shopgate/pwa-common-commerce": "7.25.1-beta.1",
21
- "@shopgate/pwa-core": "7.25.1-beta.1",
22
- "@shopgate/pwa-ui-ios": "7.25.1-beta.1",
23
- "@shopgate/pwa-ui-material": "7.25.1-beta.1",
24
- "@shopgate/pwa-ui-shared": "7.25.1-beta.1",
19
+ "@shopgate/pwa-common": "7.25.1-beta.2",
20
+ "@shopgate/pwa-common-commerce": "7.25.1-beta.2",
21
+ "@shopgate/pwa-core": "7.25.1-beta.2",
22
+ "@shopgate/pwa-ui-ios": "7.25.1-beta.2",
23
+ "@shopgate/pwa-ui-material": "7.25.1-beta.2",
24
+ "@shopgate/pwa-ui-shared": "7.25.1-beta.2",
25
25
  "@stripe/react-stripe-js": "^1.16.5",
26
26
  "@stripe/stripe-js": "^1.3.1",
27
27
  "@virtuous/conductor": "~2.5.0",
@@ -1,4 +1,4 @@
1
1
  import React,{useEffect,memo}from'react';import PropTypes from'prop-types';import{Swiper,Card}from'@shopgate/engage/components';import ProductCard from"../ProductCard";import RelationsSheet from"./RelationsSheet";import{useWidgetSettings,useCurrentProduct}from"../../../core";import connect from"./RelationsSlider.connector";import{WIDGET_ID}from"./constants";import*as styles from"./style";/**
2
2
  * @param {Object} props The component props.
3
3
  * @returns {JSX}
4
- */var RelationsSliderContent=memo(function(_ref){var _ref$products=_ref.products,products=_ref$products.products,productsCount=_ref$products.productsCount,getRelations=_ref.getRelations;var _useWidgetSettings=useWidgetSettings(WIDGET_ID),headline=_useWidgetSettings.headline,hidePrice=_useWidgetSettings.hidePrice,hideRating=_useWidgetSettings.hideRating,titleRows=_useWidgetSettings.titleRows,showMoreButton=_useWidgetSettings.showMoreButton,type=_useWidgetSettings.type,_useWidgetSettings$sl=_useWidgetSettings.slidesPerView,slidesPerView=_useWidgetSettings$sl===void 0?2.3:_useWidgetSettings$sl;var _useCurrentProduct=useCurrentProduct(),productId=_useCurrentProduct.productId;useEffect(function(){getRelations();},[getRelations]);if(products.length===0){return null;}return React.createElement("div",{className:styles.container},!!headline&&React.createElement("h3",{className:styles.headline},headline),!!showMoreButton&&productsCount>10&&React.createElement(RelationsSheet,{limit:100,productId:productId,type:type}),React.createElement(Swiper,{slidesPerView:slidesPerView,classNames:{container:styles.sliderContainer}},products.map(function(product){return React.createElement(Swiper.Item,{key:product.id},React.createElement(Card,{className:styles.card},React.createElement(ProductCard,{product:product,hidePrice:hidePrice,hideName:false,hideRating:hideRating,titleRows:titleRows})));})));});RelationsSliderContent.defaultProps={products:{products:[],productsCount:0}};export default connect(RelationsSliderContent);
4
+ */var RelationsSliderContent=memo(function(_ref){var _ref$products=_ref.products,products=_ref$products.products,productsCount=_ref$products.productsCount,getRelations=_ref.getRelations;var _useWidgetSettings=useWidgetSettings(WIDGET_ID),headline=_useWidgetSettings.headline,hidePrice=_useWidgetSettings.hidePrice,hideRating=_useWidgetSettings.hideRating,titleRows=_useWidgetSettings.titleRows,showMoreButton=_useWidgetSettings.showMoreButton,type=_useWidgetSettings.type,_useWidgetSettings$sl=_useWidgetSettings.slidesPerView,slidesPerView=_useWidgetSettings$sl===void 0?2.3:_useWidgetSettings$sl;var _useCurrentProduct=useCurrentProduct(),productId=_useCurrentProduct.productId;useEffect(function(){getRelations();},[getRelations]);if(products.length===0){return null;}return React.createElement("div",{className:styles.container},!!headline&&React.createElement("h3",{className:styles.headline},headline),!!showMoreButton&&productsCount>10&&React.createElement(RelationsSheet,{limit:100,productId:productId,type:type}),React.createElement(Swiper,{slidesPerView:slidesPerView,classNames:{container:styles.sliderContainer}},products.map(function(product){return React.createElement(Swiper.Item,{key:product.id,className:styles.sliderItem},React.createElement(Card,{className:styles.card},React.createElement(ProductCard,{product:product,hidePrice:hidePrice,hideName:false,hideRating:hideRating,titleRows:titleRows})));})));});RelationsSliderContent.defaultProps={products:{products:[],productsCount:0}};export default connect(RelationsSliderContent);
@@ -1 +1 @@
1
- import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables;export var container=css({position:'relative'});export var headline=css({fontSize:'1rem',fontWeight:500,padding:"0 ".concat(variables.gap.big,"px ").concat(variables.gap.small,"px"),margin:0});export var sliderContainer=css({marginLeft:'auto',marginRight:'auto',position:'relative',padding:"".concat(variables.gap.small,"px 0 ").concat(variables.gap.big,"px")}).toString();export var card=css({height:'100%',margin:"0 ".concat(variables.gap.small,"px")}).toString();export var gridCard=css({height:'100%',margin:0}).toString();export var showMore=css({position:'absolute !important',top:"-".concat(variables.gap.small/2),right:0,padding:"".concat(variables.gap.small/2,"px 0 !important")}).toString();export var sheet=css({maxHeight:"calc(100vh - ".concat(variables.navigator.height,"px)")}).toString();export var gridItem=css({':nth-child(even)':{padding:'8px 0 8px 8px'},':nth-child(odd)':{padding:'8px 8px 8px 0'},':first-child':{padding:'0 8px 8px 0'},':nth-child(2)':{padding:'0 0 8px 8px'},padding:8,width:'50%'}).toString();
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables;export var container=css({position:'relative'});export var headline=css({fontSize:'1rem',fontWeight:500,padding:"0 ".concat(variables.gap.big,"px ").concat(variables.gap.small,"px"),margin:0});export var sliderContainer=css({marginLeft:'auto',marginRight:'auto',position:'relative',padding:"".concat(variables.gap.small,"px 0 ").concat(variables.gap.big,"px")}).toString();export var sliderItem=css({paddingBottom:10}).toString();export var card=css({height:'100%',margin:"0 ".concat(variables.gap.small,"px")}).toString();export var gridCard=css({height:'100%',margin:0}).toString();export var showMore=css({position:'absolute !important',top:"-".concat(variables.gap.small/2),right:0,padding:"".concat(variables.gap.small/2,"px 0 !important")}).toString();export var sheet=css({maxHeight:"calc(100vh - ".concat(variables.navigator.height,"px)")}).toString();export var gridItem=css({':nth-child(even)':{padding:'8px 0 8px 8px'},':nth-child(odd)':{padding:'8px 8px 8px 0'},':first-child':{padding:'0 8px 8px 0'},':nth-child(2)':{padding:'0 0 8px 8px'},padding:8,width:'50%'}).toString();
@@ -1 +0,0 @@
1
- export var APP_FOOTER_ID='AppFooter';export var DATA_IGNORED='data-footer-inset-update-ignore';
@@ -1,75 +0,0 @@
1
- import{logger,isDev}from'@shopgate/engage/core/helpers';import{DATA_IGNORED}from"./constants";/**
2
- * Determines if an element is visually present in the DOM.
3
- * Checks for display, visibility, opacity, and transform-based hiding.
4
- *
5
- * @param {HTMLElement} el The element to evaluate.
6
- * @returns {boolean} True if the element is visually visible; false otherwise.
7
- */export var isElementVisible=function isElementVisible(el){if(!el||!(el instanceof HTMLElement))return false;var style=window.getComputedStyle(el);if(style.display==='none'||style.visibility==='hidden'||parseFloat(style.opacity)===0)return false;var transform=style.transform;if(transform&&transform!=='none'){var match=transform.match(/translateY\((-?\d+)(px)?\)/);if(match){var translateY=parseInt(match[1],10);if(translateY>window.innerHeight)return false;}}return true;};/**
8
- * Finds the widest nested element inside a given container that has a background color
9
- * explicitly set via CSS (ignores transparent, inherited, or unset values), and returns
10
- * that background color.
11
- *
12
- * @param {HTMLElement} container The parent element to search within. Must be an actual DOM node.
13
- * @returns {string|null} The detected background color (e.g., "rgb(255, 0, 0)")
14
- */export var getElementBackgroundColor=function getElementBackgroundColor(container){if(!container){return null;}var widestElement=null;var maxWidth=-Infinity;/**
15
- * Recursively traverses the DOM tree starting from the given node,
16
- * tracking the widest element that has a background color explicitly set via CSS.
17
- *
18
- * @param {HTMLElement} node The DOM node to begin traversal from.
19
- */function walk(node){if(!(node instanceof HTMLElement))return;var style=window.getComputedStyle(node);var bgColor=style.backgroundColor;var isStyledColor=bgColor&&!['transparent','rgba(0, 0, 0, 0)','inherit','initial','unset'].includes(bgColor);var rect=node.getBoundingClientRect();if(isElementVisible(node)&&isStyledColor&&rect.width>maxWidth){maxWidth=rect.width;widestElement=node;}Array.from(node.children).forEach(walk);}walk(container);if(widestElement){var result=window.getComputedStyle(widestElement).backgroundColor;return result;}return null;};/**
20
- * Checks if any of the provided class names reference the custom property in any loaded stylesheet.
21
- *
22
- * @param {string[]} classList Array of class names to check.
23
- * @param {string} customProp The custom property to search for in the stylesheets.
24
- * @returns {boolean} True if any class rule uses the custom property.
25
- */var classNamesUseCustomProp=function classNamesUseCustomProp(classList,customProp){var allRules=Array.from(document.styleSheets).filter(function(sheet){try{return sheet.cssRules;}catch(e){return false;// Skip cross-origin or restricted stylesheets
26
- }}).flatMap(function(sheet){return Array.from(sheet.cssRules||[]);});// eslint-disable-next-line no-restricted-syntax
27
- var _iteratorNormalCompletion=true;var _didIteratorError=false;var _iteratorError=undefined;try{for(var _iterator=allRules[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){var rule=_step.value;// eslint-disable-next-line no-continue
28
- if(!rule.selectorText||!rule.cssText.includes("var(".concat(customProp,")")))continue;// eslint-disable-next-line no-restricted-syntax
29
- var _iteratorNormalCompletion2=true;var _didIteratorError2=false;var _iteratorError2=undefined;try{for(var _iterator2=classList[Symbol.iterator](),_step2;!(_iteratorNormalCompletion2=(_step2=_iterator2.next()).done);_iteratorNormalCompletion2=true){var className=_step2.value;if(rule.selectorText.includes(".".concat(className))){return true;}}}catch(err){_didIteratorError2=true;_iteratorError2=err;}finally{try{if(!_iteratorNormalCompletion2&&_iterator2["return"]!=null){_iterator2["return"]();}}finally{if(_didIteratorError2){throw _iteratorError2;}}}}}catch(err){_didIteratorError=true;_iteratorError=err;}finally{try{if(!_iteratorNormalCompletion&&_iterator["return"]!=null){_iterator["return"]();}}finally{if(_didIteratorError){throw _iteratorError;}}}return false;};/**
30
- * Checks if a single element uses the custom property via inline styles or class-based rules.
31
- *
32
- * @param {HTMLElement} el The element to check.
33
- * @param {string} customProp The CSS custom property to search for.
34
- * @returns {boolean} True if the element uses the custom property.
35
- */var elementUsesCustomProp=function elementUsesCustomProp(el,customProp){var _el$getAttribute;if(!(el instanceof Element))return false;var styleAttr=(_el$getAttribute=el.getAttribute)===null||_el$getAttribute===void 0?void 0:_el$getAttribute.call(el,'style');if(styleAttr&&styleAttr.includes("var(".concat(customProp,")"))){return true;}var classList=Array.from(el.classList||[]);return classList.length>0&&classNamesUseCustomProp(classList,customProp);};/**
36
- * Checks if an element or any of its descendants use the custom property.
37
- *
38
- * @param {HTMLElement} el The root element to inspect.
39
- * @param {string} customProp The CSS custom property to look for.
40
- * @returns {boolean} True if the element or any descendant uses the custom property.
41
- */var elementOrDescendantsUseCustomProp=function elementOrDescendantsUseCustomProp(el,customProp){// Check if the element itself uses the custom property
42
- if(elementUsesCustomProp(el,customProp))return true;var descendants=el.querySelectorAll('*');// eslint-disable-next-line no-restricted-syntax
43
- var _iteratorNormalCompletion3=true;var _didIteratorError3=false;var _iteratorError3=undefined;try{for(var _iterator3=descendants[Symbol.iterator](),_step3;!(_iteratorNormalCompletion3=(_step3=_iterator3.next()).done);_iteratorNormalCompletion3=true){var node=_step3.value;// eslint-disable-next-line no-continue
44
- if(!(node instanceof Element))continue;if(elementUsesCustomProp(node,customProp))return true;}}catch(err){_didIteratorError3=true;_iteratorError3=err;}finally{try{if(!_iteratorNormalCompletion3&&_iterator3["return"]!=null){_iterator3["return"]();}}finally{if(_didIteratorError3){throw _iteratorError3;}}}return false;};/**
45
- * Returns footer entries that do NOT have safe area insets applied,
46
- * either on themselves or in any of their descendants.
47
- *
48
- * @param {HTMLElement[]} footerElements The footer elements to check.
49
- * @returns {HTMLElement[]} An array of direct children that do not use safe area insets.
50
- */var getFooterEntriesWithoutSafeAreaInsets=function getFooterEntriesWithoutSafeAreaInsets(footerElements){return footerElements.filter(function(child){return!elementOrDescendantsUseCustomProp(child,'--safe-area-inset-bottom');});};/**
51
- * Searches for footer elements that do not have safe area insets applied, and adds a fallback.
52
- * @param {HTMLElement} footerEl The footer element whose children are to be checked.
53
- */export var handleSafeAreaInsets=function handleSafeAreaInsets(footerEl){if(!footerEl||!(footerEl instanceof HTMLElement)){return;}var directChildren=Array.from(footerEl.children);// Filter out elements that where already handled before
54
- var childrenToInspect=directChildren.filter(function(child){return child.getAttribute('data-has-safe-area-inset')!=='true';}).filter(function(child){return child.getAttribute(DATA_IGNORED)!=='true';});// Detect footer elements without safe area insets
55
- var childrenWithoutInsets=getFooterEntriesWithoutSafeAreaInsets(childrenToInspect);// Apply fallback and mark the elements as handled
56
- childrenWithoutInsets.forEach(function(child){child.style.setProperty('padding-bottom','var(--safe-area-inset-bottom)');child.style.setProperty('background-color',getElementBackgroundColor(child));child.setAttribute('data-has-safe-area-inset','true');});if(isDev&&childrenWithoutInsets.length>0){logger.warn('Footer elements without safe area insets detected. Please use the "--safe-area-inset-bottom" CSS custom property for bottom insets.',childrenWithoutInsets);}// Mark all other elements which already had insets as handled
57
- directChildren.filter(function(child){return childrenWithoutInsets.indexOf(child)===-1;}).forEach(function(child){if(!child.hasAttribute('data-has-safe-area-inset')){child.setAttribute('data-has-safe-area-inset','true');}});};var style=document.documentElement.style;/**
58
- * Update the footer height custom property
59
- * @param {number} height height
60
- */export var updateFooterHeight=function updateFooterHeight(height){// The TabBar is positioned with `position: fixed`, so it doesn’t contribute to the measured
61
- // height of the Footer. Additionally, it’s sometimes animated in/out, which makes dynamic
62
- // measurement via JavaScript more complex and error-prone.
63
- //
64
- // To simplify everything, we include the --tabbar-height CSS custom property to the calculation
65
- // of the --footer-height value.
66
- var footerHeight="max(".concat(height,"px, var(--tabbar-height, 0px))");if(style.getPropertyValue('--footer-height')!==footerHeight){style.setProperty('--footer-height',footerHeight);}// The View component wraps every app page and applies a bottom offset to centrally manage
67
- // safe area insets across screens.
68
- //
69
- // If the measured footer height is > 0px, it means the footer is rendering content that already
70
- // accounts for the safe area, so no additional offset is needed.
71
- //
72
- // If the measured footer height is 0px, the footer is either empty or only contains the tab bar
73
- // (which is measured via the CSS variable --footer-height). In that case, we still need to apply
74
- // an offset equal to the larger of the bottom safe area inset or the tab bar height.
75
- var pageContentOffset=height===0?'max(var(--footer-height), var(--safe-area-inset-bottom))':'0px';if(style.getPropertyValue('--page-content-offset-bottom')!==pageContentOffset){style.setProperty('--page-content-offset-bottom',pageContentOffset);}};
@@ -1,37 +0,0 @@
1
- import{useRef,useCallback}from'react';/**
2
- * Prevents the default context menu from appearing on long press.
3
- * @param {Object} e The event object.
4
- * @returns {void}
5
- */var preventContextMenu=function preventContextMenu(e){return e.preventDefault();};/**
6
- * Custom hook to handle long press interactions.
7
- *
8
- * @param {Function} callback - Function to call on long press.
9
- * @param {Object} [options={}] - Configuration and lifecycle callbacks.
10
- * @param {number} [options.threshold=1000] - Duration in milliseconds to trigger long press.
11
- * @param {Function} [options.onStart] - This function is called when the user starts pressing.
12
- * @param {Function} [options.onFinish] - This function is called when a long press event finishes
13
- * successfully (the user releases after the threshold).
14
- * @param {Function} [options.onCancel] - This function is called when a press event is cancelled
15
- * (the user releases before the threshold).
16
- *
17
- * @returns {Object} Event handlers to attach to an element.
18
- * @returns {Function} return.onMouseDown
19
- * @returns {Function} return.onTouchStart
20
- * @returns {Function} return.onMouseUp
21
- * @returns {Function} return.onMouseLeave
22
- * @returns {Function} return.onTouchEnd
23
- * @returns {Function} return.onContextMenu
24
- *
25
- * @example
26
- * const bind = useLongPress(
27
- * () => console.log('Long Pressed!'),
28
- * {
29
- * threshold: 2000,
30
- * onStart: () => console.log('Start'),
31
- * onFinish: () => console.log('Finish'),
32
- * onCancel: () => console.log('Cancel'),
33
- * }
34
- * );
35
- * <div {...bind}>Press and Hold</div>
36
- */function useLongPress(callback){var _ref=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{},_ref$threshold=_ref.threshold,threshold=_ref$threshold===void 0?1000:_ref$threshold,onStart=_ref.onStart,onFinish=_ref.onFinish,onCancel=_ref.onCancel;var timerRef=useRef(null);var triggeredRef=useRef(false);var start=useCallback(function(e){if(onStart)onStart(e);triggeredRef.current=false;timerRef.current=setTimeout(function(){callback(e);triggeredRef.current=true;if(onFinish)onFinish(e);},threshold);},[onStart,threshold,callback,onFinish]);var cancel=useCallback(function(e){clearTimeout(timerRef.current);if(!triggeredRef.current&&onCancel){onCancel(e);}},[onCancel]);return{onMouseDown:start,onTouchStart:start,onMouseUp:cancel,onMouseLeave:cancel,onTouchEnd:cancel,// prevents right-click or long-press menu
37
- onContextMenu:preventContextMenu};}export default useLongPress;
@@ -1,33 +0,0 @@
1
- var _excluded=["scrollIn","scrollOut","scrolled"],_excluded2=["scrollIn","scrollOut","scrolled"];function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}import{useEffect,useRef,useCallback}from'react';import{viewScroll$}from'@shopgate/engage/core/streams';/**
2
- * @typedef {Object} ViewScrollEvent
3
- * @property {Event} event The original scroll event object
4
- * @property {number} scrollTop Current vertical scroll position
5
- * @property {number} previousScrollTop Previous scrollTop value
6
- * @property {boolean} scrollDown True if scrolling down
7
- * @property {boolean} scrollUp True if scrolling up
8
- * @property {'up' | 'down' | null} direction Scroll direction
9
- */ /**
10
- * @callback ScrollCallback
11
- * @param {ViewScrollEvent} event
12
- * @returns {void}
13
- */ /**
14
- * A scroll hook that detects scroll direction changes (up/down) and
15
- * triggers the appropriate callbacks. Commonly used to show/hide
16
- * UI elements based on scroll behavior.
17
- *
18
- * @param {Object} params The hook parameters
19
- * @param {boolean} params.enabled Whether the hook is active
20
- * @param {number} [params.offset=100] ScrollTop threshold for down scroll triggers. When set,
21
- * onScrollDown will first be triggered when the scroll position is greater than this value.
22
- * @param {boolean} [params.onlyFireOnDirectionChange=true]
23
- * If true, callbacks fire only once per direction change
24
- * @param {ScrollCallback} [params.onScrollUp] Triggered on scroll up
25
- * @param {ScrollCallback} [params.onScrollDown] Triggered on scroll down past offset
26
- */function useScrollDirectionChange(_ref){var enabled=_ref.enabled,_ref$offset=_ref.offset,offset=_ref$offset===void 0?100:_ref$offset,_ref$onlyFireOnDirect=_ref.onlyFireOnDirectionChange,onlyFireOnDirectionChange=_ref$onlyFireOnDirect===void 0?true:_ref$onlyFireOnDirect,onScrollUp=_ref.onScrollUp,onScrollDown=_ref.onScrollDown;var lastDirectionRef=useRef(null);var downTriggeredRef=useRef(false);var upTriggeredRef=useRef(false);/**
27
- * Scroll event handler.
28
- * Uses `event.direction` and triggers callbacks accordingly.
29
- */var handleScroll=useCallback(/** @param {ViewScrollEvent} event The event */function(event){if(!enabled||!event.scrolled||!event.direction)return;var scrollTop=event.scrollTop,direction=event.direction;var prevDirection=lastDirectionRef.current;var directionChanged=direction!==prevDirection;// Store current direction and reset flags if direction changed
30
- if(directionChanged){lastDirectionRef.current=direction;if(direction==='down')downTriggeredRef.current=false;if(direction==='up')upTriggeredRef.current=false;}// 🔽 Handle downward scroll
31
- if(direction==='down'){var shouldFire=(!onlyFireOnDirectionChange||directionChanged||!downTriggeredRef.current)&&scrollTop>=offset;if(shouldFire&&typeof onScrollDown==='function'){downTriggeredRef.current=true;// Strip internal/legacy properties
32
- var scrollIn=event.scrollIn,scrollOut=event.scrollOut,scrolled=event.scrolled,publicEvent=_objectWithoutProperties(event,_excluded);onScrollDown(publicEvent);}}// 🔼 Handle upward scroll
33
- if(direction==='up'){var _shouldFire=!onlyFireOnDirectionChange||directionChanged||!upTriggeredRef.current;if(_shouldFire&&typeof onScrollUp==='function'){upTriggeredRef.current=true;var _scrollIn=event.scrollIn,_scrollOut=event.scrollOut,_scrolled=event.scrolled,_publicEvent=_objectWithoutProperties(event,_excluded2);onScrollUp(_publicEvent);}}},[enabled,offset,onlyFireOnDirectionChange,onScrollUp,onScrollDown]);useEffect(function(){if(!enabled)return undefined;var subscription=viewScroll$.subscribe(handleScroll);return function(){return subscription.unsubscribe();};},[enabled,handleScroll]);}export default useScrollDirectionChange;
@@ -1 +0,0 @@
1
- export*from"./settings";export*from"./storage";
@@ -1,9 +0,0 @@
1
- import{DEVELOPMENT_TOOLS_TOGGLE_INSETS,DEVELOPMENT_TOOLS_TOGGLE_INSET_HIGHLIGHT}from"../constants";/**
2
- * Toggles the simulation of iOS safe area insets.
3
- * @param {boolean} visible Whether the insets should be visible or not.
4
- * @returns {Object} The action object.
5
- */export var toggleInsets=function toggleInsets(){var visible=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;return{type:DEVELOPMENT_TOOLS_TOGGLE_INSETS,visible:visible};};/**
6
- * Toggles the highlighting of the simulated iOS safe area insets.
7
- * @param {boolean} visible Whether the insets should be visible or not.
8
- * @returns {Object} The action object.
9
- */export var toggleInsetHighlight=function toggleInsetHighlight(){var visible=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;return{type:DEVELOPMENT_TOOLS_TOGGLE_INSET_HIGHLIGHT,visible:visible};};
@@ -1,6 +0,0 @@
1
- import{DEVELOPMENT_TOOLS_UPDATE_STATUS_BAR_STYLE_STORAGE}from"../constants";/**
2
- * Updates the status bar style storage where latest payload from the updateNavigationBarStyle
3
- * app event is stored.
4
- * @param {boolean} style The event payload
5
- * @returns {Object} The action object.
6
- */export var updateStatusBarStyleStorage=function updateStatusBarStyleStorage(){var style=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};return{type:DEVELOPMENT_TOOLS_UPDATE_STATUS_BAR_STYLE_STORAGE,style:style};};
@@ -1,6 +0,0 @@
1
- import React,{memo}from'react';import PropTypes from'prop-types';import{isDev}from'@shopgate/engage/core/helpers';import Shortcuts from"./Shortcuts";import SimulatedInsets from"../SimulatedInsets";/**
2
- * Provides development tools for the app.
3
- * @param {Object} props The component props.
4
- * @param {React.ReactNode} props.children The child components.
5
- * @returns {JSX.Element}
6
- */var DevelopmentTools=function DevelopmentTools(_ref){var children=_ref.children;if(!isDev){return children;}return React.createElement(React.Fragment,null,React.createElement(Shortcuts,null),React.createElement(SimulatedInsets,null,children));};export default memo(DevelopmentTools);
@@ -1,4 +0,0 @@
1
- import{useSelector,useDispatch}from'react-redux';import{toggleInsets}from'@shopgate/engage/development/action-creators';import{getAreSimulatedInsetsInjected}from'@shopgate/engage/development/selectors';import{useShortcut}from"./hooks";/**
2
- * The Shortcuts component maps shortcuts to actions in development mode.
3
- * @returns {JSX.Element}
4
- */var Shortcuts=function Shortcuts(){var dispatch=useDispatch();var areInsetsInjected=useSelector(getAreSimulatedInsetsInjected);useShortcut('ctrl+i',function(){dispatch(toggleInsets(!areInsetsInjected));});return null;};export default Shortcuts;
@@ -1,8 +0,0 @@
1
- import{useEffect,useCallback}from'react';/**
2
- * Hook to handle a single keyboard shortcut.
3
- * Supports both 'cmd' (meta) and 'ctrl' keys explicitly.
4
- *
5
- * @param {string} shortcut - Shortcut string using mac-style notation, e.g. 'cmd+i'.
6
- * @param {Function} callback - Function to call when the shortcut is triggered.
7
- */export function useShortcut(shortcut,callback){var normalizeShortcut=useCallback(function(){return shortcut.toLowerCase().split('+').map(function(k){return k.trim();}).sort().join('+');},[shortcut]);var handleKeyDown=useCallback(function(event){var keys=[];if(event.ctrlKey)keys.push('ctrl');if(event.metaKey)keys.push('cmd');// Treat meta as cmd
8
- if(event.altKey)keys.push('alt');if(event.shiftKey)keys.push('shift');var key=event.key.toLowerCase();if(!['control','meta','alt','shift'].includes(key)){keys.push(key);}var pressed=keys.sort().join('+');if(pressed===normalizeShortcut()){event.preventDefault();callback(event);}},[callback,normalizeShortcut]);useEffect(function(){window.addEventListener('keydown',handleKeyDown);return function(){return window.removeEventListener('keydown',handleKeyDown);};},[handleKeyDown]);}
@@ -1 +0,0 @@
1
- export{default}from"./DevelopmentTools";
@@ -1,7 +0,0 @@
1
- var _excluded=["highlightInset","onClick"];function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}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;}function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}import React,{useMemo}from'react';import PropTypes from'prop-types';import classNames from'classnames';import{css}from'glamor';var classes={container:css({position:'fixed',bottom:0,display:'flex',justifyContent:'center',alignItems:'center',height:'var(--safe-area-inset-bottom)',width:'100%',zIndex:10000000,pointerEvents:'auto',transition:'background 0.2s ease'}),containerHighlight:css({background:'rgba(255, 0, 0, 0.7)'}),handle:css({width:120,height:3,borderRadius:3,background:'rgba(0, 0, 0, 0.4)',border:'1px solid rgba(255, 255, 255, 0.5)',boxSizing:'content-box'})};/**
2
- * Renders a simulated iOS bottom inset in development.
3
- * @param {Object} props The component props.
4
- * @param {boolean} props.highlightInset Whether the inset is highlighted.
5
- * @param {Function} props.onClick The function to call when the inset is clicked.
6
- * @returns {JSX.Element}
7
- */var SimulatedInsetBottom=function SimulatedInsetBottom(_ref){var highlightInset=_ref.highlightInset,onClick=_ref.onClick,props=_objectWithoutProperties(_ref,_excluded);var containerClasses=useMemo(function(){return classNames(classes.container,_defineProperty({},classes.containerHighlight,highlightInset));},[highlightInset]);return React.createElement("div",_extends({"aria-hidden":true,role:"presentation",className:containerClasses},props,{onClick:onClick}),React.createElement("div",{className:classes.handle}));};export default SimulatedInsetBottom;
@@ -1,12 +0,0 @@
1
- var _excluded=["highlightInset","onClick"];function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}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;}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}import React,{useState,useEffect,useMemo}from'react';import PropTypes from'prop-types';import classNames from'classnames';import{useSelector}from'react-redux';import{css}from'glamor';import{getStatusBarStyleStorage}from'@shopgate/engage/development/selectors';var classes={container:css({position:'fixed',top:0,display:'flex',justifyContent:'space-between',alignItems:'center',height:'var(--safe-area-inset-top)',width:'100%',zIndex:10000000,pointerEvents:'auto',transition:'background 0.2s ease',fontSize:'16px'}),containerHighlight:css({background:'rgba(255, 0, 0, 0.7)'}),styleLight:css({color:'white'}),styleDark:css({color:'black'}),styleNone:css({color:'transparent'}),info:css({flex:1,textAlign:'center',fontWeight:500}),notch:css({flex:1,background:'black',height:'calc(var(--safe-area-inset-top) - 16px)',maxWidth:150,borderRadius:16,border:'1px solid rgba(255, 255, 255, 0.5)'})};/**
2
- * Creates a human readable time string to mimic the iOS clock.
3
- * @returns {string} The current time in a human readable format.
4
- */var getTime=function getTime(){var now=new Date();return now.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'});};/**
5
- * Renders a simulated iOS top inset in development.
6
- * @param {Object} props The component props.
7
- * @param {boolean} props.highlightInset Whether the inset is highlighted.
8
- * @param {Function} props.onClick The function to call when the inset is clicked.
9
- * @returns {JSX.Element}
10
- */var SimulatedInsetTop=function SimulatedInsetTop(_ref){var highlightInset=_ref.highlightInset,onClick=_ref.onClick,props=_objectWithoutProperties(_ref,_excluded);// State to hold the current time string for the status bar
11
- var _useState=useState(getTime()),_useState2=_slicedToArray(_useState,2),time=_useState2[0],setTime=_useState2[1];// Effect to update the time on regular intervals
12
- useEffect(function(){var interval=setInterval(function(){setTime(getTime());},10*1000);return function(){return clearInterval(interval);};},[]);var _useSelector=useSelector(getStatusBarStyleStorage),statusBarStyle=_useSelector.statusBarStyle;var containerClasses=useMemo(function(){return classNames(classes.container,_defineProperty(_defineProperty(_defineProperty(_defineProperty({},classes.containerHighlight,highlightInset),classes.styleDark,statusBarStyle==='dark'),classes.styleLight,statusBarStyle==='light'),classes.styleNone,statusBarStyle==='none'));},[highlightInset,statusBarStyle]);return React.createElement("div",_extends({"aria-hidden":true,role:"presentation",className:classNames(containerClasses)},props,{onClick:onClick}),React.createElement("div",{className:classes.info},time),React.createElement("div",{className:classes.notch}),React.createElement("div",{className:classes.info},"5G"));};export default SimulatedInsetTop;
@@ -1,6 +0,0 @@
1
- function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import React,{useCallback}from'react';import{useSelector,useDispatch}from'react-redux';import PropTypes from'prop-types';import{useLongPress}from'@shopgate/engage/core/hooks';import{getAreSimulatedInsetsInjected,getIsInsetHighlightVisible}from'@shopgate/engage/development/selectors';import{toggleInsetHighlight,toggleInsets}from'@shopgate/engage/development/action-creators';import SimulatedInsetTop from"./SimulatedInsetTop";import SimulatedInsetBottom from"./SimulatedInsetBottom";/**
2
- * Simulates iOS insets in development mode.
3
- * @param {Object} props The component props.
4
- * @param {React.ReactNode} props.children The child components.
5
- * @returns {JSX.Element}
6
- */var SimulatedInsets=function SimulatedInsets(_ref){var children=_ref.children;var hasSimulatedSafeAreaInsets=useSelector(getAreSimulatedInsetsInjected);var dispatch=useDispatch();var highlightInset=useSelector(getIsInsetHighlightVisible);var handleClick=useCallback(function(){dispatch(toggleInsetHighlight(!highlightInset));},[dispatch,highlightInset]);var attrs=useLongPress(function(){dispatch(toggleInsets(!hasSimulatedSafeAreaInsets));});return React.createElement(React.Fragment,null,hasSimulatedSafeAreaInsets&&React.createElement(SimulatedInsetTop,_extends({onClick:handleClick,highlightInset:highlightInset},attrs)),children,hasSimulatedSafeAreaInsets&&React.createElement(SimulatedInsetBottom,_extends({onClick:handleClick,highlightInset:highlightInset},attrs)));};export default SimulatedInsets;
@@ -1 +0,0 @@
1
- export{default}from"./SimulatedInsets";
@@ -1 +0,0 @@
1
- export{default as DevelopmentTools}from"./DevelopmentTools";
@@ -1 +0,0 @@
1
- export var DEVELOPMENT_TOOLS_TOGGLE_INSETS='DEVELOPMENT_TOOLS_TOGGLE_INSETS';export var DEVELOPMENT_TOOLS_TOGGLE_INSET_HIGHLIGHT='DEVELOPMENT_TOOLS_TOGGLE_INSET_HIGHLIGHT';export var DEVELOPMENT_TOOLS_UPDATE_STATUS_BAR_STYLE_STORAGE='DEVELOPMENT_TOOLS_UPDATE_STATUS_BAR_STYLE_STORAGE';
@@ -1 +0,0 @@
1
- export*from"./actionTypes";
@@ -1 +0,0 @@
1
- import{combineReducers}from'redux';import settings from"./settings";import storage from"./storage";export default combineReducers({settings:settings,storage:storage});
@@ -1,10 +0,0 @@
1
- import{produce}from'immer';import{isDev}from'@shopgate/engage/core/helpers';import{DEVELOPMENT_TOOLS_TOGGLE_INSETS,DEVELOPMENT_TOOLS_TOGGLE_INSET_HIGHLIGHT}from"../constants";/**
2
- * @typedef {Object} DevToolsSettingsState
3
- * @property {boolean} showInsets
4
- * @property {boolean} showInsetHighlight
5
- */ /** @type DevToolsSettingsState */var initialState={showInsets:null,showInsetHighlight:false};/**
6
- * The reducer for all development tools settings related states.
7
- * @param {Object} state The application state.
8
- * @param {Object} action The redux action.
9
- * @returns {Object}
10
- */export default function settingsReducer(){var state=arguments.length>0&&arguments[0]!==undefined?arguments[0]:initialState;var action=arguments.length>1?arguments[1]:undefined;/* eslint-disable no-param-reassign */var producer=produce(/** @param {DevToolsSettingsState} draft The draft */function(draft){if(!isDev){return;}switch(action.type){case DEVELOPMENT_TOOLS_TOGGLE_INSETS:{draft.showInsets=action.visible;break;}case DEVELOPMENT_TOOLS_TOGGLE_INSET_HIGHLIGHT:{draft.showInsetHighlight=action.visible;break;}default:break;}});/* eslint-enable no-param-reassign */return producer(state);}
@@ -1,9 +0,0 @@
1
- import{produce}from'immer';import{isDev}from'@shopgate/engage/core/helpers';import{DEVELOPMENT_TOOLS_UPDATE_STATUS_BAR_STYLE_STORAGE}from"../constants";/**
2
- * @typedef {Object} DevToolsStorageState
3
- * @property {Object} statusBarStyle
4
- */ /** @type DevToolsStorageState */var initialState={statusBarStyle:{styles:{}}};/**
5
- * The reducer for all developer tools storage related states.
6
- * @param {Object} state The application state.
7
- * @param {Object} action The redux action.
8
- * @returns {Object}
9
- */export default function storageReducer(){var state=arguments.length>0&&arguments[0]!==undefined?arguments[0]:initialState;var action=arguments.length>1?arguments[1]:undefined;/* eslint-disable no-param-reassign */var producer=produce(/** @param {DevToolsStorageState} draft The draft */function(draft){if(!isDev){return;}switch(action.type){case DEVELOPMENT_TOOLS_UPDATE_STATUS_BAR_STYLE_STORAGE:{draft.statusBarStyle=action.style;break;}default:break;}});/* eslint-enable no-param-reassign */return producer(state);}
@@ -1 +0,0 @@
1
- export*from"./settings";export*from"./storage";
@@ -1,21 +0,0 @@
1
- import{createSelector}from'reselect';import MobileDetect from'mobile-detect';import{isDev as isDevelopment,hasSGJavaScriptBridge}from'@shopgate/engage/core/helpers';var md=new MobileDetect(navigator.userAgent);/**
2
- * Retrieves the development settings state from the store.
3
- * @param {Object} state The current application state.
4
- * @return {Object} The development settings state.
5
- */var getState=function getState(state){return state.development.settings;};/**
6
- * Creates a selector to determine if development mode is enabled.
7
- * @type {(state: any) => boolean}
8
- */export var getIsDev=createSelector(function(){return isDevelopment;});/**
9
- * Creates a selector to determine if the simulated iOS insets are supposed to be shown.
10
- * @type {(state: any) => boolean}
11
- */export var getAreInsetsVisible=createSelector(getIsDev,getState,function(isDev,settings){if(!isDev){return false;}return settings.showInsets;});/**
12
- * Creates a selector to determine if the inset highlight is visible.
13
- * @type {(state: any) => boolean}
14
- */export var getIsInsetHighlightVisible=createSelector(getIsDev,getState,function(isDev,settings){if(!isDev){return false;}return settings.showInsetHighlight;});/**
15
- * Creates a selector to check if simulated safe area insets are supposed to be injected.
16
- * @type {(state: any) => boolean}
17
- */export var getAreSimulatedInsetsInjected=createSelector(getIsDev,getAreInsetsVisible,function(isDev,insetsVisible){// No insets injected if the app is not in development mode.
18
- if(!isDev){return false;}// No insets injected if PWA is running inside the app
19
- if(hasSGJavaScriptBridge()){return false;}// If the state contains a bool value, respect is.
20
- if(typeof insetsVisible==='boolean'){return insetsVisible;}// Show insets on simulated iOS devices by default if insets decision is not set.
21
- return insetsVisible===null&&md.os()==='iOS';});
@@ -1,16 +0,0 @@
1
- import{createSelector}from'reselect';/**
2
- * Retrieves the development storage state from the store.
3
- * @param {Object} state The current application state.
4
- * @return {Object} The development storage state.
5
- */var getState=function getState(state){return state.development.storage;};/**
6
- * @typedef {Object} StatusBarStyleStyles
7
- * @property {string} statusBarBackground Current background color of the app bar
8
- */ /**
9
- * @typedef {Object} StatusBarStyle
10
- * @property {boolean} isDefault Whether the style is the default one which was initially applied
11
- * @property {"light"|"dark"} statusBarStyle The status style for the iOS status bar
12
- * @property {StatusBarStyleStyles} styles Additional styles for the status bar
13
- */ /**
14
- * Creates a selector that returns the current status bar style object from the storage.
15
- * @type {(state: any) => StatusBarStyle}
16
- */export var getStatusBarStyleStorage=createSelector(getState,function(state){return state.statusBarStyle;});
@@ -1 +0,0 @@
1
- export*from"./insets";
@@ -1,4 +0,0 @@
1
- import{main$}from'@shopgate/engage/core/streams';import{DEVELOPMENT_TOOLS_TOGGLE_INSETS}from"../constants";/**
2
- * Gets triggered after the simulated page insets were updated
3
- * @type {Observable}
4
- */export var simulatedPageInsetsDidUpdate$=main$.filter(function(_ref){var action=_ref.action;return action.type===DEVELOPMENT_TOOLS_TOGGLE_INSETS;});
@@ -1,6 +0,0 @@
1
- import{appWillStart$}from'@shopgate/engage/core/streams';import{UIEvents}from'@shopgate/engage/core/events';import{updateStatusBarStyleStorage}from'@shopgate/engage/development/action-creators';/**
2
- * Development subscriptions
3
- * @param {Function} subscribe The subscribe function
4
- */export default function development(subscribe){subscribe(appWillStart$,function(_ref){var dispatch=_ref.dispatch;// Listen for the app event which updates the status bar style and store it into the
5
- // development storage redux store.
6
- UIEvents.addListener('devInternalUpdateStatusBarStyle',function(event){dispatch(updateStatusBarStyleStorage(event));});});}