@shopgate/engage 7.28.0 → 7.29.0-alpha.10

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 (167) hide show
  1. package/category/components/CategoryImage/index.js +1 -1
  2. package/category/components/CategoryList/index.js +7 -3
  3. package/category/components/CategoryList/style.js +1 -1
  4. package/components/ResponsiveContainer/breakpoints.js +2 -2
  5. package/components/SheetList/components/Item/index.js +7 -7
  6. package/components/Typography/Typography.d.ts +132 -0
  7. package/components/Typography/Typography.js +11 -0
  8. package/components/Typography/index.js +1 -0
  9. package/components/View/components/Content/index.js +4 -1
  10. package/components/View/components/Content/style.js +1 -1
  11. package/components/View/context.js +1 -1
  12. package/components/index.js +2 -2
  13. package/core/constants/index.js +8 -2
  14. package/core/constants/merchantSettings.js +1 -1
  15. package/core/constants/shopSettings.js +1 -1
  16. package/core/contexts/ThemeResourcesContext.d.ts +10 -1
  17. package/core/contexts/ThemeResourcesContext.js +1 -1
  18. package/core/helpers/scrollContainer.js +2 -2
  19. package/core/hocs/withThemeResources.js +4 -1
  20. package/core/hooks/events/index.js +1 -1
  21. package/core/hooks/events/useLongPress.js +1 -1
  22. package/core/hooks/events/usePressHandler.js +38 -0
  23. package/core/hooks/useThemeResources.js +6 -5
  24. package/core/providers/ThemeResourcesProvider.js +9 -5
  25. package/core/reducers/merchantSettings.js +1 -1
  26. package/core/reducers/shopSettings.js +1 -1
  27. package/core/selectors/index.js +1 -1
  28. package/core/selectors/merchantSettings.js +5 -2
  29. package/core/selectors/shopSettings.js +5 -2
  30. package/development/action-creators/settings.js +6 -2
  31. package/development/components/ClientInformation/ClientInformation.js +5 -0
  32. package/development/components/ClientInformation/actions.js +4 -0
  33. package/development/components/ClientInformation/index.js +1 -0
  34. package/development/components/DevelopmentSettings/DevelopmentSettings.js +9 -0
  35. package/development/components/DevelopmentSettings/index.js +1 -0
  36. package/development/components/DevelopmentTools/hooks.js +2 -2
  37. package/development/components/index.js +1 -1
  38. package/development/constants/actionTypes.js +1 -1
  39. package/development/reducers/settings.js +3 -3
  40. package/development/selectors/settings.js +4 -1
  41. package/locations/subscriptions.js +2 -2
  42. package/package.json +9 -7
  43. package/page/action-creators/index.js +22 -0
  44. package/page/components/ResponsiveWidgetImage/ResponsiveWidgetImage.js +7 -0
  45. package/page/components/ResponsiveWidgetImage/index.js +1 -0
  46. package/page/components/WidgetHeadline/WidgetHeadline.js +7 -0
  47. package/page/components/WidgetHeadline/index.js +1 -0
  48. package/page/components/WidgetRichText/WidgetRichText.js +6 -0
  49. package/page/components/WidgetRichText/index.js +1 -0
  50. package/page/components/Widgets/Overlay.js +51 -0
  51. package/page/components/Widgets/Tooltip.js +22 -0
  52. package/page/components/Widgets/Widget.js +17 -0
  53. package/page/components/Widgets/WidgetContext.d.ts +42 -0
  54. package/page/components/Widgets/WidgetContext.js +9 -0
  55. package/page/components/Widgets/WidgetProvider.js +8 -0
  56. package/page/components/Widgets/Widgets.js +11 -0
  57. package/page/components/Widgets/WidgetsPreviewContext.js +9 -0
  58. package/page/components/Widgets/WidgetsPreviewProvider.js +8 -0
  59. package/page/components/Widgets/constants.js +4 -0
  60. package/page/components/Widgets/events.js +23 -0
  61. package/page/components/Widgets/helpers.js +23 -0
  62. package/page/components/Widgets/hooks.js +69 -0
  63. package/page/components/Widgets/index.js +1 -0
  64. package/page/components/Widgets/types.d.ts +132 -0
  65. package/page/components/index.js +1 -1
  66. package/page/constants/actionTypes.js +1 -0
  67. package/page/constants/index.js +5 -1
  68. package/page/helpers/index.d.ts +55 -0
  69. package/page/helpers/index.js +17 -0
  70. package/page/hooks/index.d.ts +60 -0
  71. package/page/hooks/index.js +37 -0
  72. package/page/index.js +1 -2
  73. package/page/reducers/index.js +15 -0
  74. package/page/selectors/index.js +56 -2
  75. package/page/subscriptions/index.js +4 -0
  76. package/page/widgets/CategoryList/CategoryList.js +4 -0
  77. package/page/widgets/CategoryList/hooks.js +16 -0
  78. package/page/widgets/CategoryList/index.js +1 -0
  79. package/page/widgets/CategoryList/selectors.js +8 -0
  80. package/page/widgets/HTML/HTML.js +5 -0
  81. package/page/widgets/HTML/hooks.js +12 -0
  82. package/page/widgets/HTML/index.js +1 -0
  83. package/page/widgets/Headline/Headline.js +4 -0
  84. package/page/widgets/Headline/index.js +1 -0
  85. package/page/widgets/HeroBanner/HeroBanner.js +3 -0
  86. package/page/widgets/HeroBanner/hooks.js +14 -0
  87. package/page/widgets/HeroBanner/index.js +1 -0
  88. package/page/widgets/Image/Image.js +4 -0
  89. package/page/widgets/Image/hooks.js +19 -0
  90. package/page/widgets/Image/index.js +1 -0
  91. package/page/widgets/ImageRow/ImageRow.js +4 -0
  92. package/page/widgets/ImageRow/hooks.js +15 -0
  93. package/page/widgets/ImageRow/index.js +1 -0
  94. package/page/widgets/ImageSlider/ImageSlider.js +4 -0
  95. package/page/widgets/ImageSlider/hooks.js +33 -0
  96. package/page/widgets/ImageSlider/index.js +1 -0
  97. package/page/widgets/Placeholder/Placeholder.js +5 -0
  98. package/page/widgets/Placeholder/hooks.js +12 -0
  99. package/page/widgets/Placeholder/index.js +1 -0
  100. package/page/widgets/ProductList/ProductList.js +5 -0
  101. package/page/widgets/ProductList/hooks.js +21 -0
  102. package/page/widgets/ProductList/index.js +1 -0
  103. package/page/widgets/ProductSlider/ProductSlider.js +5 -0
  104. package/page/widgets/ProductSlider/hooks.js +24 -0
  105. package/page/widgets/ProductSlider/index.js +1 -0
  106. package/page/widgets/RichText/RichText.js +3 -0
  107. package/page/widgets/RichText/hooks.js +10 -0
  108. package/page/widgets/RichText/index.js +1 -0
  109. package/page/widgets/index.js +1 -0
  110. package/page/widgets/widgets.json +35 -0
  111. package/product/components/ProductCard/index.js +1 -1
  112. package/product/components/ProductGrid/components/Item/components/ItemDetails/index.js +8 -0
  113. package/product/components/ProductGrid/components/Item/components/ItemDetails/spec.js +1 -0
  114. package/product/components/ProductGrid/components/Item/components/ItemDiscount/index.js +5 -0
  115. package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/index.js +5 -0
  116. package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/spec.js +1 -0
  117. package/product/components/ProductGrid/components/Item/components/ItemImage/index.js +5 -0
  118. package/product/components/ProductGrid/components/Item/components/ItemImage/spec.js +1 -0
  119. package/product/components/ProductGrid/components/Item/components/ItemName/index.js +5 -0
  120. package/product/components/ProductGrid/components/Item/components/ItemName/spec.js +1 -0
  121. package/product/components/ProductGrid/components/Item/components/ItemPrice/index.js +5 -0
  122. package/product/components/ProductGrid/components/Item/components/ItemPrice/spec.js +1 -0
  123. package/product/components/ProductGrid/components/Item/index.js +7 -0
  124. package/product/components/ProductGrid/components/Iterator/index.js +5 -0
  125. package/product/components/ProductGrid/components/Layout/index.js +5 -0
  126. package/product/components/ProductGrid/index.js +22 -0
  127. package/product/components/ProductGrid/spec.js +1 -0
  128. package/product/components/ProductGridPrice/index.js +1 -1
  129. package/product/components/ProductSlider/index.js +4 -4
  130. package/product/components/index.js +1 -1
  131. package/styles/helpers/color.js +23 -0
  132. package/styles/helpers/index.js +1 -1
  133. package/styles/helpers/setPageBackgroundColor.js +2 -2
  134. package/styles/index.d.ts +17 -0
  135. package/styles/index.js +1 -1
  136. package/styles/theme/createTheme/createBreakpoints.d.ts +114 -0
  137. package/styles/theme/createTheme/createBreakpoints.js +41 -0
  138. package/styles/theme/createTheme/createPalette.d.ts +36 -0
  139. package/styles/theme/createTheme/createPalette.js +4 -0
  140. package/styles/theme/createTheme/createSpacing.d.ts +23 -0
  141. package/styles/theme/createTheme/createSpacing.js +14 -0
  142. package/styles/theme/createTheme/createTypography.d.ts +55 -0
  143. package/styles/theme/createTheme/createTypography.js +23 -0
  144. package/styles/theme/createTheme/index.d.ts +41 -0
  145. package/styles/theme/createTheme/index.js +5 -0
  146. package/styles/theme/createTheme/transitions.d.ts +100 -0
  147. package/styles/theme/createTheme/transitions.js +26 -0
  148. package/styles/theme/createTheme/zIndex.d.ts +12 -0
  149. package/styles/theme/createTheme/zIndex.js +3 -0
  150. package/styles/theme/hooks/index.d.ts +4 -0
  151. package/styles/theme/hooks/index.js +1 -0
  152. package/styles/theme/hooks/useActiveBreakpoint.d.ts +18 -0
  153. package/styles/theme/hooks/useActiveBreakpoint.js +4 -0
  154. package/styles/theme/hooks/useMediaQuery.d.ts +33 -0
  155. package/styles/theme/hooks/useMediaQuery.js +20 -0
  156. package/styles/theme/hooks/useResponsiveValue.d.ts +27 -0
  157. package/styles/theme/hooks/useResponsiveValue.js +4 -0
  158. package/styles/theme/hooks/useTheme.d.ts +8 -0
  159. package/styles/theme/hooks/useTheme.js +4 -0
  160. package/styles/theme/index.d.ts +8 -0
  161. package/styles/theme/index.js +1 -0
  162. package/styles/theme/providers/ActiveBreakpointProvider.d.ts +21 -0
  163. package/styles/theme/providers/ActiveBreakpointProvider.js +13 -0
  164. package/styles/theme/providers/ThemeProvider.d.ts +18 -0
  165. package/styles/theme/providers/ThemeProvider.js +7 -0
  166. package/styles/tss/index.js +3 -0
  167. package/tracking/selectors/cookieConsent.js +2 -2
@@ -0,0 +1,3 @@
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;}import React from'react';import{ConditionalWrapper,Link}from'@shopgate/engage/components';import{WidgetRichText,ResponsiveWidgetImage}from'@shopgate/engage/page/components';import{makeStyles}from'@shopgate/engage/styles';import{useHeroBannerWidget}from"./hooks";var useStyles=makeStyles()(function(theme){return{link:{width:'100%'},content:_defineProperty({width:'100%',position:'relative',display:'flex',alignItems:'center',minHeight:300},theme.breakpoints.up('md'),{minHeight:400}),richText:{position:'relative',zIndex:2,padding:theme.spacing(2)},image:{position:'absolute',width:'100%',height:'100%',top:0,left:0,objectFit:'cover',zIndex:0,pointerEvents:'none'}};});/**
2
+ * @returns {JSX.Element}
3
+ */var HeroBanner=function HeroBanner(){var _useHeroBannerWidget=useHeroBannerWidget(),text=_useHeroBannerWidget.text,backgroundImage=_useHeroBannerWidget.backgroundImage,link=_useHeroBannerWidget.link;var _useStyles=useStyles(),cx=_useStyles.cx,classes=_useStyles.classes;return React.createElement(ConditionalWrapper,{condition:!!link,wrapper:function wrapper(children){return React.createElement(Link,{href:link,className:cx(classes.link)},children);}},React.createElement("div",{className:cx(classes.content)},React.createElement(WidgetRichText,{content:text,className:cx(classes.richText)}),React.createElement(ResponsiveWidgetImage,{src:backgroundImage===null||backgroundImage===void 0?void 0:backgroundImage.url,alt:backgroundImage===null||backgroundImage===void 0?void 0:backgroundImage.alt,className:cx(classes.image)})));};export default HeroBanner;
@@ -0,0 +1,14 @@
1
+ import{useWidget}from'@shopgate/engage/page/hooks';/**
2
+ * @typedef {Object} HeroBanner
3
+ * @property {string} text Banner text content
4
+ * @property {Object} backgroundImage Banner background image
5
+ * @property {string} backgroundImage.url Banner background image URL
6
+ * @property {string} backgroundImage.alt Banner background image alt text
7
+ * @property {string} link Optional banner link
8
+ */ /**
9
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
10
+ * .useWidget<HeroBanner> >} UseWidgetReturnType
11
+ */ // eslint-disable-next-line valid-jsdoc
12
+ /**
13
+ * Hook to access the Image widget configuration and data.
14
+ */export var useHeroBannerWidget=function useHeroBannerWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;return config;};
@@ -0,0 +1 @@
1
+ export{default}from"./HeroBanner";
@@ -0,0 +1,4 @@
1
+ import React from'react';import{makeStyles}from'@shopgate/engage/styles';import{Link,ConditionalWrapper}from'@shopgate/engage/components';import{ResponsiveWidgetImage}from'@shopgate/engage/page/components';import{useImageWidget}from"./hooks";var useStyles=makeStyles()(function(){return{link:{},image:{width:'100%'}};});/**
2
+ * The ImageWidget is used to display a image.
3
+ * @returns {JSX.Element}
4
+ */var Image=function Image(){var _useStyles=useStyles(),cx=_useStyles.cx,classes=_useStyles.classes;var _useImageWidget=useImageWidget(),link=_useImageWidget.link,altText=_useImageWidget.altText,url=_useImageWidget.url;if(!url)return null;return React.createElement(ConditionalWrapper,{condition:!!link,wrapper:function wrapper(children){return React.createElement(Link,{href:link,className:cx(classes.link)},children);}},React.createElement(ResponsiveWidgetImage,{src:url,alt:altText,className:cx(classes.image)}));};export default Image;
@@ -0,0 +1,19 @@
1
+ import{useWidget}from'@shopgate/engage/page/hooks';import{useResponsiveValue}from'@shopgate/engage/styles';/**
2
+ * @typedef {Object} ImageWidgetConfig
3
+ * @property {Object} image The image object.
4
+ * @property {string} image.url The image URL.
5
+ * @property {string} [image.altText] The image alt text.
6
+ * @property {Object} imageWide The wide image object.
7
+ * @property {string} imageWide.url The wide image URL.
8
+ * @property {string} [imageWide.altText] The wide image alt text.
9
+ * @property {boolean} [useImageWide] Whether to use the wide image on
10
+ * medium and larger screens.
11
+ * @property {string} [link] The link URL.
12
+ */ /**
13
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
14
+ * .useWidget<ImageWidgetConfig> >} UseWidgetReturnType
15
+ */ // eslint-disable-next-line valid-jsdoc
16
+ /**
17
+ * Hook to access the Image widget configuration and data.
18
+ * Handles responsive image URLs and alt texts.
19
+ */export var useImageWidget=function useImageWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;var _ref=config||{},image=_ref.image,imageWide=_ref.imageWide,link=_ref.link,useImageWide=_ref.useImageWide;var resolved=useResponsiveValue({xs:{url:image===null||image===void 0?void 0:image.url,altText:image===null||image===void 0?void 0:image.altText},md:{url:useImageWide&&(imageWide===null||imageWide===void 0?void 0:imageWide.url)?imageWide.url:image===null||image===void 0?void 0:image.url,altText:useImageWide&&(imageWide===null||imageWide===void 0?void 0:imageWide.altText)?imageWide.altText:image===null||image===void 0?void 0:image.altText}});return{url:resolved.url,altText:resolved.altText,link:link};};
@@ -0,0 +1 @@
1
+ export{default}from"./Image";
@@ -0,0 +1,4 @@
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;}import React from'react';import{makeStyles}from'@shopgate/engage/styles';import{Link,ConditionalWrapper,Grid}from'@shopgate/engage/components';import{useImageRowWidget}from"./hooks";import ResponsiveWidgetImage from"../../components/ResponsiveWidgetImage";var useStyles=makeStyles()(function(theme,_ref){var imageSpacing=_ref.imageSpacing;return{imageContainer:{width:'100%',display:'flex',overflowX:'hidden',alignItems:'flex-start',flexWrap:'wrap',gap:"".concat(imageSpacing,"px")},image:{maxWidth:'100%',height:'auto',flexShrink:1,display:'block',width:'100%',objectFit:'contain'},itemContainerDense:_defineProperty(_defineProperty({},theme.breakpoints.down('md'),{flex:"1 1 calc(33% - ".concat(imageSpacing,"px)")}),theme.breakpoints.up('md'),{flex:"1 1 calc(16% - ".concat(imageSpacing,"px)")}),itemContainerDefault:_defineProperty(_defineProperty({},theme.breakpoints.down('md'),{flex:"1 1 calc(50% - ".concat(imageSpacing,"px)")}),theme.breakpoints.up('md'),{flex:"1 1 calc(25% - ".concat(imageSpacing,"px)")}),itemContainerNoWrap:{flex:' 1 1 0%'}};});/**
2
+ * The ImageRowWidget is used to display images in one or more rows.
3
+ * @returns {JSX.Element}
4
+ */var ImageRow=function ImageRow(){var _useImageRowWidget=useImageRowWidget(),images=_useImageRowWidget.images,imageWrapping=_useImageRowWidget.imageWrapping,imageSpacing=_useImageRowWidget.imageSpacing;var _useStyles=useStyles({imageSpacing:imageSpacing}),cx=_useStyles.cx,classes=_useStyles.classes;if(images.length===0)return null;return React.createElement(Grid,{className:cx(classes.imageContainer),component:"div"},images.map(function(img){return React.createElement(Grid.Item,{key:img.url,component:"div",className:cx(_defineProperty(_defineProperty(_defineProperty({},classes.itemContainerDefault,imageWrapping==='responsiveDefault'),classes.itemContainerDense,imageWrapping==='responsiveDense'),classes.itemContainerNoWrap,imageWrapping==='responsiveNoWrap'))},React.createElement(ConditionalWrapper,{condition:!!img.link,wrapper:function wrapper(children){return React.createElement(Link,{href:img.link,className:cx(classes.image)},children);}},React.createElement(ResponsiveWidgetImage,{src:img.url,alt:img.altText,className:cx(classes.image)})));}));};export default ImageRow;
@@ -0,0 +1,15 @@
1
+ import{useWidget}from'@shopgate/engage/page/hooks';import{useMemo}from'react';/**
2
+ * @typedef {Object} ImageRowWidgetConfig
3
+ * @property {Array} images The images array.
4
+ * @property {string} imageWrapping The imageWrapping setting,
5
+ * one of: responsiveDefault | responsiveDense | responsiveNoWrap.
6
+ * @property {string} [link] The optional link URL.
7
+ * @property {number} [imageSpacing] An optional gap between images (in pixels).
8
+ */ /**
9
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
10
+ * .useWidget<ImageRowWidgetConfig> >} UseWidgetReturnType
11
+ */ // eslint-disable-next-line valid-jsdoc
12
+ /**
13
+ * Hook to access the Image row widget configuration and data.
14
+ * Handles responsive image URLs and alt texts.
15
+ */export var useImageRowWidget=function useImageRowWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;var _ref=config||{},_ref$images=_ref.images,images=_ref$images===void 0?[]:_ref$images,imageWrapping=_ref.imageWrapping,_ref$imageSpacing=_ref.imageSpacing,imageSpacing=_ref$imageSpacing===void 0?0:_ref$imageSpacing;var mappedImages=useMemo(function(){return images.map(function(_ref2){var image=_ref2.image,link=_ref2.link;var _ref3=image||{},url=_ref3.url,altText=_ref3.altText;return{url:url,altText:altText,link:link};}).filter(function(img){return img.url;});},[images]);return{images:mappedImages,imageWrapping:imageWrapping,imageSpacing:imageSpacing};};
@@ -0,0 +1 @@
1
+ export{default}from"./ImageRow";
@@ -0,0 +1,4 @@
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 from'react';import{makeStyles}from'@shopgate/engage/styles';import{Swiper,Link,ConditionalWrapper}from'@shopgate/engage/components';import{ResponsiveWidgetImage}from'@shopgate/engage/page/components';import{useImageSliderWidget}from"./hooks";var useStyles=makeStyles()({image:{width:'100%'}});/**
2
+ * The ImageSliderWidget is used to display an image slider.
3
+ * @returns {JSX.Element}
4
+ */var ImageSliderWidget=function ImageSliderWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _useImageSliderWidget=useImageSliderWidget(),slides=_useImageSliderWidget.slides,swiperProps=_useImageSliderWidget.swiperProps;if(slides.length===0){return null;}return React.createElement(Swiper,_extends({indicators:true},swiperProps),slides.map(function(slide){if(!slide.image.url){return null;}return React.createElement(Swiper.Item,{key:slide.image.url},React.createElement(ConditionalWrapper,{condition:!!slide.link,wrapper:function wrapper(children){return React.createElement(Link,{href:slide.link},children);}},React.createElement(ResponsiveWidgetImage,{className:classes.image,src:slide.image.url,alt:slide.image.altText||''})));}));};export default ImageSliderWidget;
@@ -0,0 +1,33 @@
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);}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{useMemo}from'react';import{useWidget}from'@shopgate/engage/page/hooks';import{useTheme}from'@shopgate/engage/styles';/**
2
+ * @typedef {import('swiper/react').SwiperProps} SwiperCmpProps
3
+ */ /**
4
+ * @typedef {Object} ImageSliderImageData
5
+ * @property {string} url The image URL.
6
+ * @property {string} [altText] The image alt text.
7
+ */ /**
8
+ * @typedef {Object} ImageSliderImage
9
+ * @property {ImageSliderImageData} image The image data object.
10
+ * @property {string} [link] The link URL.
11
+ */ /**
12
+ * @typedef {Object} ImageWidgetConfig
13
+ * @property {ImageSliderImage[]} images The image objects.
14
+ * @property {boolean} slideAutomatic Whether the slider should automatically slide.
15
+ * @property {boolean} endlessSlider Whether the slider should loop endlessly.
16
+ * @property {number} sliderSpeed The speed (in ms) for the slider autoplay.
17
+ * @property {"default"|"dense"|"custom"} slidesPerView
18
+ * @property {number} slidesPerViewCustomSmall Slides per view for small screens.
19
+ * @property {number} slidesPerViewCustomMedium Slides per view for medium screens.
20
+ * @property {number} slidesPerViewCustomLarge Slides per view for large screens.
21
+ * @property {number} imageSpacing Optional gap between image slides (in pixels).
22
+ */ /**
23
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
24
+ * .useWidget<ImageWidgetConfig> >} UseWidgetReturnType
25
+ */ // eslint-disable-next-line valid-jsdoc
26
+ /**
27
+ * Hook to access the ImageSlider widget configuration and data.
28
+ */export var useImageSliderWidget=function useImageSliderWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config,isPreview=_useWidget.isPreview;var theme=useTheme();var images=config.images,slideAutomatic=config.slideAutomatic,endlessSlider=config.endlessSlider,sliderSpeed=config.sliderSpeed,slidesPerView=config.slidesPerView,slidesPerViewCustomSmall=config.slidesPerViewCustomSmall,slidesPerViewCustomMedium=config.slidesPerViewCustomMedium,slidesPerViewCustomLarge=config.slidesPerViewCustomLarge,imageSpacing=config.imageSpacing;/**
29
+ * @type {SwiperCmpProps}
30
+ */var swiperProps=useMemo(function(){var slidesPerViewSmall=1.0;var slidesPerViewMedium=1.3;var slidesPerViewLarge=1.6;if(slidesPerView==='dense'){slidesPerViewSmall=1.3;slidesPerViewMedium=1.8;slidesPerViewLarge=2.3;}else if(slidesPerView==='custom'){slidesPerViewSmall=slidesPerViewCustomSmall;slidesPerViewMedium=slidesPerViewCustomMedium;slidesPerViewLarge=slidesPerViewCustomLarge;}var breakpoints=_defineProperty(_defineProperty({},theme.breakpoints.values.sm,{slidesPerView:slidesPerViewMedium}),theme.breakpoints.values.md,{slidesPerView:slidesPerViewLarge});return _extends({autoplay:slideAutomatic?{delay:sliderSpeed}:false,loop:endlessSlider,slidesPerView:slidesPerViewSmall,breakpoints:breakpoints,spaceBetween:imageSpacing},isPreview?{// Improves interaction with the slider in the CMS preview iframe
31
+ touchStartPreventDefault:true,// Create a component key from breakpoint settings to force remount on breakpoint change.
32
+ // This fixes issues with the Swiper when breakpoint settings change during runtime.
33
+ key:JSON.stringify(_extends({slidesPerView:slidesPerView,spaceBetween:imageSpacing},breakpoints))}:{});},[isPreview,slidesPerView,slideAutomatic,sliderSpeed,endlessSlider,theme.breakpoints.values,slidesPerViewCustomMedium,slidesPerViewCustomLarge,slidesPerViewCustomSmall,imageSpacing]);return{slides:images.filter(function(img){var _img$image;return img===null||img===void 0?void 0:(_img$image=img.image)===null||_img$image===void 0?void 0:_img$image.url;}),swiperProps:swiperProps};};
@@ -0,0 +1 @@
1
+ export{default}from"./ImageSlider";
@@ -0,0 +1,5 @@
1
+ import React from'react';import{makeStyles}from'@shopgate/engage/styles';import{usePlaceholderWidget}from"./hooks";var useStyles=makeStyles()(function(theme){return{root:{padding:theme.spacing(2),minHeight:200},name:{fontSize:14},pre:{background:'#f7f9fc',border:'1px solid #dbdde2',borderRadius:8,color:'#000',fontSize:10,overflowY:'auto',padding:theme.spacing(1)}};});/**
2
+ * The PlaceholderWidget component is used to display a placeholder for widget types that
3
+ * are not implemented yet.
4
+ * @returns {JSX.Element}
5
+ */var PlaceholderWidget=function PlaceholderWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _usePlaceholderWidget=usePlaceholderWidget(),code=_usePlaceholderWidget.code,name=_usePlaceholderWidget.name,config=_usePlaceholderWidget.config,layout=_usePlaceholderWidget.layout,visibility=_usePlaceholderWidget.visibility;return React.createElement("div",{className:classes.root},React.createElement("div",{className:classes.name},name),React.createElement("pre",{className:classes.pre},JSON.stringify({code:code,config:config,layout:layout,visibility:visibility},null,2)));};export default PlaceholderWidget;
@@ -0,0 +1,12 @@
1
+ import{useWidget}from'@shopgate/engage/page/hooks';/**
2
+ * @typedef {Object} PlaceholderWidgetConfig
3
+ * @property {string} foo Example property for the widget configuration.
4
+ * @property {number} bar Another example property for the widget configuration.
5
+ */ /**
6
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
7
+ * .useWidget<PlaceholderWidgetConfig> >} HookReturnType
8
+ */ /**
9
+ * Local example hook to demonstrate how to extend the useWidget hook with a custom type for
10
+ * the widget configuration.
11
+ * @returns {HookReturnType}
12
+ */export var usePlaceholderWidget=function usePlaceholderWidget(){return useWidget();};
@@ -0,0 +1 @@
1
+ export{default}from"./Placeholder";
@@ -0,0 +1,5 @@
1
+ import React from'react';import{ActionButton,I18n}from'@shopgate/engage/components';import{ProductGrid}from'@shopgate/engage/product/components';import{useWidgetProducts}from'@shopgate/engage/page/hooks';import{makeStyles}from'@shopgate/engage/styles';import{useProductListWidget}from"./hooks";import WidgetHeadline from"../../components/WidgetHeadline";var useStyles=makeStyles()({root:{// Prevent that the ActionButton margin messes with the layout of the sibling widgets
2
+ overflow:'hidden'},grid:{'&&':{marginTop:0}}});/**
3
+ * The ProductListWidget is used to display product lists.
4
+ * @returns {JSX.Element}
5
+ */var ProductListWidget=function ProductListWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _useProductListWidget=useProductListWidget(),productsSearchType=_useProductListWidget.productsSearchType,productsSearchValue=_useProductListWidget.productsSearchValue,sort=_useProductListWidget.sort,productCount=_useProductListWidget.productCount,showLoadMore=_useProductListWidget.showLoadMore,flags=_useProductListWidget.flags,showHeadline=_useProductListWidget.showHeadline,headline=_useProductListWidget.headline;var _useWidgetProducts=useWidgetProducts({type:productsSearchType,value:productsSearchValue,limit:productCount,sort:sort}),fetchNext=_useWidgetProducts.fetchNext,hasNext=_useWidgetProducts.hasNext,isFetching=_useWidgetProducts.isFetching,results=_useWidgetProducts.results;return React.createElement("div",{className:classes.root},showHeadline&&headline&&results.length?React.createElement(WidgetHeadline,{headline:headline}):null,React.createElement(ProductGrid,{products:results,flags:flags,scope:"widgets",infiniteLoad:false,className:classes.grid}),hasNext&&showLoadMore&&React.createElement(ActionButton,{loading:isFetching,onClick:fetchNext},React.createElement(I18n.Text,{string:"common.load_more"})));};export default ProductListWidget;
@@ -0,0 +1,21 @@
1
+ import _camelCase from"lodash/camelCase";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{useMemo}from'react';import{useWidget}from'@shopgate/engage/page/hooks';import{getProductSearchParamsFromProductsInputConfig}from'@shopgate/engage/page/helpers';/**
2
+ * @typedef {import('@shopgate/engage/page/helpers')
3
+ * .ProductsWidgetInputConfig} ProductsWidgetInputConfig
4
+ */ /**
5
+ * @typedef {Object} ProductListWidgetConfig
6
+ * @property {ProductsWidgetInputConfig} products The products configuration for the widget.
7
+ * @property {number} productCount The number of products to display in the widget
8
+ * @property {"relevance" | "PriceDesc" | "PriceAsc"} sort Sort order for the products
9
+ * @property {boolean} loadMoreButton Whether to display a "Load more" button
10
+ * @property {boolean} showName Whether to display product names
11
+ * @property {boolean} showPrice Whether to display product prices
12
+ * @property {boolean} showRating Whether to display product ratings
13
+ * @property {boolean} [showHeadline] Whether to show the headline.
14
+ * @property {Object} [headline] The headline to be displayed.
15
+ */ /**
16
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
17
+ * .useWidget<ProductListWidgetConfig> >} UseWidgetReturnType
18
+ */ // eslint-disable-next-line valid-jsdoc
19
+ /**
20
+ * Hook to access the Product List widget configuration.
21
+ */export var useProductListWidget=function useProductListWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;var products=config.products,productCount=config.productCount,sort=config.sort,_config$loadMoreButto=config.loadMoreButton,loadMoreButton=_config$loadMoreButto===void 0?false:_config$loadMoreButto,_config$showName=config.showName,showName=_config$showName===void 0?false:_config$showName,_config$showPrice=config.showPrice,showPrice=_config$showPrice===void 0?false:_config$showPrice,_config$showRating=config.showRating,showRating=_config$showRating===void 0?false:_config$showRating,_config$showHeadline=config.showHeadline,showHeadline=_config$showHeadline===void 0?false:_config$showHeadline,headline=config.headline;var productSearchParams=useMemo(function(){return getProductSearchParamsFromProductsInputConfig(products);},[products]);var flags=useMemo(function(){return{name:showName,price:showPrice,reviews:showRating};},[showName,showPrice,showRating]);return _extends({},productSearchParams,{sort:_camelCase(sort),productCount:productCount,showLoadMore:loadMoreButton,flags:flags,showHeadline:showHeadline,headline:headline});};
@@ -0,0 +1 @@
1
+ export{default}from"./ProductList";
@@ -0,0 +1,5 @@
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);}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,{useMemo}from'react';import{ProductSlider}from'@shopgate/engage/product/components';import{useWidgetProducts}from'@shopgate/engage/page/hooks';import{useTheme}from'@shopgate/engage/styles';import{useProductSliderWidget}from"./hooks";import WidgetHeadline from"../../components/WidgetHeadline";/**
2
+ * The ProductSliderWidget is used to display a product slider.
3
+ * @returns {JSX.Element}
4
+ */var ProductSliderWidget=function ProductSliderWidget(){var _useProductSliderWidg=useProductSliderWidget(),productsSearchType=_useProductSliderWidg.productsSearchType,productsSearchValue=_useProductSliderWidg.productsSearchValue,sort=_useProductSliderWidg.sort,productCount=_useProductSliderWidg.productCount,swiperProps=_useProductSliderWidg.swiperProps,productItemProps=_useProductSliderWidg.productItemProps,isPreview=_useProductSliderWidg.isPreview,showHeadline=_useProductSliderWidg.showHeadline,headline=_useProductSliderWidg.headline;var _useWidgetProducts=useWidgetProducts({type:productsSearchType,value:productsSearchValue,limit:productCount,sort:sort}),results=_useWidgetProducts.results;var theme=useTheme();var productIds=useMemo(function(){return results===null||results===void 0?void 0:results.map(function(result){return result.id;});},[results]);if(!productIds||!productIds.length){return null;}return React.createElement(React.Fragment,null,showHeadline&&headline&&productIds.length?React.createElement(WidgetHeadline,{headline:headline}):null,React.createElement(ProductSlider,_extends({productIds:productIds,scope:"widgets",productItemProps:productItemProps,slidesPerView:2.3// Improves interaction with the slider in the CMS preview iframe
5
+ },isPreview?{touchStartPreventDefault:true}:{},{breakpoints:_defineProperty(_defineProperty(_defineProperty({},theme.breakpoints.values.sm,{slidesPerView:3.3}),theme.breakpoints.values.md,{slidesPerView:4.3}),theme.breakpoints.values.lg,{slidesPerView:5.3})},swiperProps)));};export default ProductSliderWidget;
@@ -0,0 +1,24 @@
1
+ import _camelCase from"lodash/camelCase";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{useMemo}from'react';import{useWidget}from'@shopgate/engage/page/hooks';import{getProductSearchParamsFromProductsInputConfig}from'@shopgate/engage/page/helpers';/**
2
+ * @typedef {import('@shopgate/engage/page/helpers')
3
+ * .ProductsWidgetInputConfig} ProductsWidgetInputConfig
4
+ */ /**
5
+ * @typedef {Object} ProductSliderWidgetConfig
6
+ * @property {ProductsWidgetInputConfig} products The products configuration for the widget.
7
+ * @property {number} productCount The number of products to display in the widget.
8
+ * @property {"relevance" | "priceDesc" | "priceAsc"} sort Sort order for the products.
9
+ * @property {boolean} [showName] Whether to display product names.
10
+ * @property {boolean} [showPrice] Whether to display product prices.
11
+ * @property {boolean} [showRating] Whether to display product ratings.
12
+ * @property {boolean} [slideAutomatic] Whether the slider should automatically slide.
13
+ * @property {boolean} [endlessSlider] Whether the slider should loop endlessly.
14
+ * @property {number} [sliderSpeed] The speed (in ms) for the slider autoplay.
15
+ * @property {boolean} [isPreview] Whether the widget is in preview mode.
16
+ * @property {boolean} [showHeadline] Whether to show the headline.
17
+ * @property {Object} [headline] The headline to be displayed.
18
+ */ /**
19
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
20
+ * .useWidget<ProductSliderWidgetConfig> >} UseWidgetReturnType
21
+ */ // eslint-disable-next-line valid-jsdoc
22
+ /**
23
+ * Hook to access the Product Slider widget configuration.
24
+ */export var useProductSliderWidget=function useProductSliderWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config,isPreview=_useWidget.isPreview;var products=config.products,productCount=config.productCount,sort=config.sort,_config$showName=config.showName,showName=_config$showName===void 0?false:_config$showName,_config$showPrice=config.showPrice,showPrice=_config$showPrice===void 0?false:_config$showPrice,_config$showRating=config.showRating,showRating=_config$showRating===void 0?false:_config$showRating,_config$slideAutomati=config.slideAutomatic,slideAutomatic=_config$slideAutomati===void 0?true:_config$slideAutomati,_config$endlessSlider=config.endlessSlider,endlessSlider=_config$endlessSlider===void 0?true:_config$endlessSlider,_config$sliderSpeed=config.sliderSpeed,sliderSpeed=_config$sliderSpeed===void 0?7000:_config$sliderSpeed,_config$showHeadline=config.showHeadline,showHeadline=_config$showHeadline===void 0?false:_config$showHeadline,headline=config.headline;var productSearchParams=useMemo(function(){return getProductSearchParamsFromProductsInputConfig(products);},[products]);var swiperProps=useMemo(function(){return{autoplay:slideAutomatic,delay:sliderSpeed,loop:endlessSlider};},[slideAutomatic,sliderSpeed,endlessSlider]);var productItemProps=useMemo(function(){return{hideName:!showName,hidePrice:!showPrice,hideRating:!showRating};},[showName,showPrice,showRating]);return _extends({},productSearchParams,{sort:_camelCase(sort),productCount:productCount,swiperProps:swiperProps,productItemProps:productItemProps,isPreview:isPreview,showHeadline:showHeadline,headline:headline});};
@@ -0,0 +1 @@
1
+ export{default}from"./ProductSlider";
@@ -0,0 +1,3 @@
1
+ import React from'react';import{makeStyles}from'@shopgate/engage/styles';import{WidgetRichText}from'@shopgate/engage/page/components';import{useRichTextWidget}from"./hooks";var useStyles=makeStyles()(function(theme){return{root:{padding:theme.spacing(1)}};});/**
2
+ * @returns {JSX.Element}
3
+ */var RichText=function RichText(){var _useRichTextWidget=useRichTextWidget(),richText=_useRichTextWidget.richText;var _useStyles=useStyles(),cx=_useStyles.cx,classes=_useStyles.classes;if(!richText)return null;return React.createElement(WidgetRichText,{content:richText,className:cx(classes.root)});};export default RichText;
@@ -0,0 +1,10 @@
1
+ import{useWidget}from'@shopgate/engage/page/hooks';/**
2
+ * @typedef {Object} RichTextWidgetConfig
3
+ * @property {string} text The rich text content.
4
+ */ /**
5
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
6
+ * .useWidget<RichTextWidgetConfig> >} UseWidgetReturnType
7
+ */ // eslint-disable-next-line valid-jsdoc
8
+ /**
9
+ * Hook to access the Image widget configuration and data.
10
+ */export var useRichTextWidget=function useRichTextWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;return{richText:config===null||config===void 0?void 0:config.text};};
@@ -0,0 +1 @@
1
+ export{default}from"./RichText";
@@ -0,0 +1 @@
1
+ export{default as PlaceholderWidget}from"./Placeholder";export{default as ProductListWidget}from"./ProductList";export{default as CategoryListWidget}from"./CategoryList";export{default as HtmlWidget}from"./HTML";export{default as ProductSliderWidget}from"./ProductSlider";export{default as HeadlineWidget}from"./Headline";export{default as ImageWidget}from"./Image";export{default as ImageRowWidget}from"./ImageRow";export{default as ImageSliderWidget}from"./ImageSlider";export{default as RichTextWidget}from"./RichText";export{default as HeroBannerWidget}from"./HeroBanner";
@@ -0,0 +1,35 @@
1
+ {
2
+ "@shopgate/widgets/productListWidget": {
3
+ "path": "@shopgate/engage/page/widgets/ProductList"
4
+ },
5
+ "@shopgate/widgets/categoryListWidget": {
6
+ "path": "@shopgate/engage/page/widgets/CategoryList"
7
+ },
8
+ "@shopgate/widgets/productSliderWidget": {
9
+ "path": "@shopgate/engage/page/widgets/ProductSlider"
10
+ },
11
+ "@shopgate/widgets/htmlWidget": {
12
+ "path": "@shopgate/engage/page/widgets/HTML"
13
+ },
14
+ "@shopgate/widgets/headlineWidget": {
15
+ "path": "@shopgate/engage/page/widgets/Headline"
16
+ },
17
+ "@shopgate/widgets/imageWidget": {
18
+ "path": "@shopgate/engage/page/widgets/Image"
19
+ },
20
+ "@shopgate/widgets/imageRowWidget": {
21
+ "path": "@shopgate/engage/page/widgets/ImageRow"
22
+ },
23
+ "@shopgate/widgets/imageSliderWidget": {
24
+ "path": "@shopgate/engage/page/widgets/ImageSlider"
25
+ },
26
+ "@shopgate/widgets/richTextWidget": {
27
+ "path": "@shopgate/engage/page/widgets/RichText"
28
+ },
29
+ "@shopgate/widgets/heroBannerWidget": {
30
+ "path": "@shopgate/engage/page/widgets/HeroBanner"
31
+ },
32
+ "@shopgate/widgetsInternal/Placeholder": {
33
+ "path": "@shopgate/engage/page/widgets/Placeholder"
34
+ }
35
+ }
@@ -8,7 +8,7 @@ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<argum
8
8
  * @param {number} props.titleRows The max number of rows for the product title.
9
9
  * @param {string} props.url Optional alternative url for the product link
10
10
  * @return {JSX.Element}
11
- */function ProductCard(props){var product=props.product,hidePrice=props.hidePrice,hideRating=props.hideRating,hideName=props.hideName,titleRows=props.titleRows,url=props.url;var _useProductListType=useProductListType(),meta=_useProductListType.meta;var _getProductImageSetti=getProductImageSettings(),gridResolutions=_getProductImageSetti.ListImage;var _useWidgetSettings=useWidgetSettings('@shopgate/engage/rating'),_useWidgetSettings$sh=_useWidgetSettings.showEmptyRatingStars,showEmptyRatingStars=_useWidgetSettings$sh===void 0?false:_useWidgetSettings$sh;var showRatings=useMemo(function(){var _product$rating;if(!hideRating&&(product===null||product===void 0?void 0:(_product$rating=product.rating)===null||_product$rating===void 0?void 0:_product$rating.average)>0){return true;}if(!hideRating&&showEmptyRatingStars&&(product===null||product===void 0?void 0:product.rating)){return true;}return false;},[hideRating,product,showEmptyRatingStars]);return React.createElement(Link,{className:"engage__product-card",href:url||getProductRoute(product.id),itemProp:"item",itemScope:true,itemType:"http://schema.org/Product",tabIndex:0,state:_extends({},meta)},isBeta()&&product.featuredMedia?React.createElement(FeaturedMedia,{type:product.featuredMedia.type,url:product.featuredMedia.url,altText:product.featuredMedia.altText}):React.createElement(ProductImage,{src:product.featuredImageBaseUrl,resolutions:gridResolutions,alt:product.name,itemProp:"image"}),React.createElement(ProductBadges,{location:location,productId:product.id},!!(!hidePrice&&product.price.discount)&&React.createElement("div",{className:styles.badgeWrapper},React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_DISCOUNT,portalProps:{productId:product.id}},React.createElement(DiscountBadge,{text:"-".concat(product.price.discount,"%")})))),!(hidePrice&&hideRating)&&React.createElement("div",{className:"".concat(styles.details," engage__product-card__information")},showRatings&&React.createElement(RatingStars,{value:product.rating.average}),React.createElement(Swatches,{productId:product.id}),!hideName&&React.createElement(ProductName,{name:product.name,className:styles.title,testId:"Productname: ".concat(product.name),itemProp:"name",rows:titleRows||3}),React.createElement(MapPriceHint,{productId:product.id}),React.createElement(OrderQuantityHint,{productId:product.id}),!hidePrice&&React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_PRICE,portalProps:{productId:product.id,location:location}},React.createElement(ProductGridPrice,{product:product}))));}/**
11
+ */function ProductCard(props){var product=props.product,hidePrice=props.hidePrice,hideRating=props.hideRating,hideName=props.hideName,titleRows=props.titleRows,url=props.url;var _useProductListType=useProductListType(),meta=_useProductListType.meta;var _getProductImageSetti=getProductImageSettings(),gridResolutions=_getProductImageSetti.ListImage;var _useWidgetSettings=useWidgetSettings('@shopgate/engage/rating'),_useWidgetSettings$sh=_useWidgetSettings.showEmptyRatingStars,showEmptyRatingStars=_useWidgetSettings$sh===void 0?false:_useWidgetSettings$sh;var showRatings=useMemo(function(){var _product$rating;if(!hideRating&&(product===null||product===void 0?void 0:(_product$rating=product.rating)===null||_product$rating===void 0?void 0:_product$rating.average)>0){return true;}if(!hideRating&&showEmptyRatingStars&&(product===null||product===void 0?void 0:product.rating)){return true;}return false;},[hideRating,product,showEmptyRatingStars]);return React.createElement(Link,{className:"engage__product-card",href:url||getProductRoute(product.id),itemProp:"item",itemScope:true,itemType:"http://schema.org/Product",tabIndex:0,state:_extends({},meta)},isBeta()&&product.featuredMedia?React.createElement(FeaturedMedia,{type:product.featuredMedia.type,url:product.featuredMedia.url,altText:product.featuredMedia.altText}):React.createElement(ProductImage,{src:product.featuredImageBaseUrl,resolutions:gridResolutions,alt:product.name,itemProp:"image"}),React.createElement(ProductBadges,{location:location,productId:product.id},!!(!hidePrice&&product.price.discount)&&React.createElement("div",{className:styles.badgeWrapper},React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_DISCOUNT,portalProps:{productId:product.id}},React.createElement(DiscountBadge,{text:"-".concat(product.price.discount,"%")})))),!(hidePrice&&hideRating&&hideName)&&React.createElement("div",{className:"".concat(styles.details," engage__product-card__information")},showRatings&&React.createElement(RatingStars,{value:product.rating.average}),React.createElement(Swatches,{productId:product.id}),!hideName&&React.createElement(ProductName,{name:product.name,className:styles.title,testId:"Productname: ".concat(product.name),itemProp:"name",rows:titleRows||3}),React.createElement(MapPriceHint,{productId:product.id}),React.createElement(OrderQuantityHint,{productId:product.id}),!hidePrice&&React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_PRICE,portalProps:{productId:product.id,location:location}},React.createElement(ProductGridPrice,{product:product}))));}/**
12
12
  * After a refactoring of the Theme API ProductCard component, this component replaced a
13
13
  * sub-component of the ProductCard.
14
14
  * The original implementation exposed a couple of sub-components that don't exist in the new
@@ -0,0 +1,8 @@
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,{useMemo,memo}from'react';import PropTypes from'prop-types';import{MapPriceHint,OrderQuantityHint,EffectivityDates,Swatches,AVAILABILITY_STATE_OK,AVAILABILITY_STATE_ALERT,getProductRoute}from'@shopgate/engage/product';import{hasNewServices as checkHasNewServices,i18n}from'@shopgate/engage/core/helpers';import{Availability,Link}from'@shopgate/engage/components';import{StockInfoLists}from'@shopgate/engage/locations/components';import{makeStyles}from'@shopgate/engage/styles';import ItemName from"../ItemName";import ItemPrice from"../ItemPrice";var useStyles=makeStyles()({root:{lineHeight:1.2,':not(:empty)':{padding:'12px 0 16px'}},quantityHint:{paddingTop:8}});/**
2
+ * The Product Grid Item Detail component.
3
+ * @param {Object} props The component props.
4
+ * @param {Object} props.product The product.
5
+ * @param {Object} props.display The display object.
6
+ * @param {Object} [props.productListTypeMeta] Optional meta object with data from the product list
7
+ * @returns {JSX.Element}
8
+ */var ItemDetails=function ItemDetails(_ref){var product=_ref.product,display=_ref.display,productListTypeMeta=_ref.productListTypeMeta;var productId=product.id,_product$name=product.name,name=_product$name===void 0?null:_product$name,_product$stock=product.stock,stock=_product$stock===void 0?null:_product$stock;var _useStyles=useStyles(),classes=_useStyles.classes,cx=_useStyles.cx;var hasNewServices=useMemo(function(){return checkHasNewServices();},[]);if(display&&!display.name&&!display.price&&!display.reviews){return null;}return React.createElement(Link,{className:cx(classes.root,'theme__product-grid__item__item-details'),tabIndex:0,href:getProductRoute(productId),state:_extends({title:product.name},productListTypeMeta)},React.createElement(Swatches,{productId:productId}),React.createElement(ItemName,{display:display,productId:productId,name:name}),React.createElement(MapPriceHint,{productId:productId}),React.createElement(OrderQuantityHint,{productId:productId,className:classes.quantityHint}),React.createElement(EffectivityDates,{productId:productId}),hasNewServices&&React.createElement(React.Fragment,null,React.createElement(Availability,{state:!stock||stock.orderable?AVAILABILITY_STATE_OK:AVAILABILITY_STATE_ALERT,text:i18n.text('product.available.not'),showWhenAvailable:false}),React.createElement(StockInfoLists,{product:product})),React.createElement(ItemPrice,{product:product,display:display}));};ItemDetails.defaultProps={display:null,productListTypeMeta:null};export default memo(ItemDetails);
@@ -0,0 +1 @@
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 from'react';import{shallow}from'enzyme';import{hasNewServices}from'@shopgate/engage/core/helpers';import{Availability}from'@shopgate/engage/components';import{StockInfoLists}from'@shopgate/engage/locations/components';import ItemDetails from"./index";jest.mock('@shopgate/engage/product',function(){return{MapPriceHint:function MapPriceHint(){return null;},OrderQuantityHint:function OrderQuantityHint(){return null;},EffectivityDates:function EffectivityDates(){return null;},Swatches:function Swatches(){return null;},AVAILABILITY_STATE_OK:'AVAILABILITY_STATE_OK',AVAILABILITY_STATE_ALERT:'AVAILABILITY_STATE_ALERT',getProductRoute:jest.fn(function(productId){return"link-to-product/".concat(productId);})};});jest.mock('@shopgate/engage/locations/components',function(){return{StockInfoLists:function StockInfoLists(){return null;}};});jest.mock('@shopgate/engage/core/helpers',function(){return{hasNewServices:jest.fn().mockReturnValue(false),i18n:{text:function text(str){return str;}}};});jest.mock('@shopgate/engage/components');jest.mock('@shopgate/engage/core',function(){return{isIOSTheme:jest.fn().mockReturnValue(true),hasWebBridge:jest.fn().mockReturnValue(false),i18n:{text:function text(_text){return _text;}}};});jest.mock("../ItemName");jest.mock("../ItemPrice");describe('<ItemDetails />',function(){var props={product:{id:'1234',name:'Foo',price:{}}};var display={name:false,price:false,reviews:false};it('should render with minimal props',function(){var wrapper=shallow(React.createElement(ItemDetails,props));expect(wrapper).toMatchSnapshot();expect(wrapper.find(Availability).exists()).toBe(false);expect(wrapper.find(StockInfoLists).exists()).toBe(false);});it('should render additional components with new services',function(){hasNewServices.mockReturnValueOnce(true);var wrapper=shallow(React.createElement(ItemDetails,props));expect(wrapper).toMatchSnapshot();expect(wrapper.find(Availability).exists()).toBe(true);expect(wrapper.find(StockInfoLists).exists()).toBe(true);});it('should not render with display props set',function(){var wrapper=shallow(React.createElement(ItemDetails,_extends({},props,{display:display})));expect(wrapper).toBeEmptyRender();});});
@@ -0,0 +1,5 @@
1
+ import React,{memo,useMemo}from'react';import PropTypes from'prop-types';import{SurroundPortals,DiscountBadge}from'@shopgate/engage/components';import{PRODUCT_ITEM_DISCOUNT}from'@shopgate/engage/category';import{makeStyles}from'@shopgate/engage/styles';var useStyles=makeStyles()({root:{minWidth:40}});/**
2
+ * The item discount component
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX.Element|null}
5
+ */var ItemDiscount=function ItemDiscount(_ref){var productId=_ref.productId,discount=_ref.discount;var _useStyles=useStyles(),classes=_useStyles.classes,cx=_useStyles.cx;var portalProps=useMemo(function(){return{productId:productId};},[productId]);if(!discount){return null;}return React.createElement("div",{className:cx(classes.root,'theme__product-grid__item__item-discount')},React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_DISCOUNT,portalProps:portalProps},React.createElement(DiscountBadge,{text:"-".concat(discount,"%")})));};ItemDiscount.defaultProps={discount:null};export default memo(ItemDiscount);
@@ -0,0 +1,5 @@
1
+ import React,{memo,useMemo}from'react';import PropTypes from'prop-types';import{useSelector}from'react-redux';import{SurroundPortals,FavoritesButton}from'@shopgate/engage/components';import{PRODUCT_ITEM_FAVORITES_BUTTON}from'@shopgate/engage/category';import{isRelativeProductOnList}from'@shopgate/engage/favorites';import{getLoadWishlistOnAppStartEnabled}from'@shopgate/engage/core';import{makeStyles}from'@shopgate/engage/styles';var useStyles=makeStyles()({root:{position:'absolute',top:0,right:16,left:'auto',transform:'translate3d(0, -50%, 0)'}});/**
2
+ * The item favorites button component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX.Element}
5
+ */var ItemFavoritesButton=function ItemFavoritesButton(_ref){var productId=_ref.productId;var _useStyles=useStyles(),classes=_useStyles.classes;var loadWishlistOnAppStartEnabled=useSelector(getLoadWishlistOnAppStartEnabled);var isOnWishlist=useSelector(function(state){return isRelativeProductOnList(state,{productId:productId});});var isFavorite=useMemo(function(){return!loadWishlistOnAppStartEnabled?false:isOnWishlist;},[isOnWishlist,loadWishlistOnAppStartEnabled]);var portalProps=useMemo(function(){return{productId:productId};},[productId]);return React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_FAVORITES_BUTTON,portalProps:portalProps},React.createElement("div",{className:classes.root,"data-test-id":"favorites"},React.createElement(FavoritesButton,{active:isFavorite,productId:productId,noShadow:true,removeWithRelatives:true})));};export default memo(ItemFavoritesButton);
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import{combineReducers}from'redux';import{Provider}from'react-redux';import{createMockStore}from'@shopgate/pwa-common/store';import favorites from'@shopgate/pwa-common-commerce/favorites/reducers';import ItemFavoritesButton from"./index";jest.mock('@shopgate/engage/components');var store=createMockStore(combineReducers({favorites:favorites}));describe('<ItemFavoritesButton />',function(){it('should not render when its not a favorite',function(){var wrapper=shallow(React.createElement(Provider,{store:store},React.createElement(ItemFavoritesButton,{productId:"1234"})));expect(wrapper).toMatchSnapshot();});it('should render if its a favorite',function(){var wrapper=shallow(React.createElement(Provider,{store:store},React.createElement(ItemFavoritesButton,{productId:"1234",isFavorite:true})));expect(wrapper).toMatchSnapshot();});});
@@ -0,0 +1,5 @@
1
+ import React,{useMemo,memo}from'react';import PropTypes from'prop-types';import{SurroundPortals}from'@shopgate/engage/components';import{PRODUCT_ITEM_IMAGE}from'@shopgate/engage/category/constants';import{getProductImageSettings,ProductImage}from'@shopgate/engage/product';var _getProductImageSetti=getProductImageSettings(),gridResolutions=_getProductImageSetti.ListImage;/**
2
+ * The item image component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX.Element}
5
+ */var ItemImage=function ItemImage(_ref){var productId=_ref.productId,name=_ref.name,imageUrl=_ref.imageUrl;var portalProps=useMemo(function(){return{productId:productId};},[productId]);return React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_IMAGE,portalProps:portalProps},React.createElement(ProductImage,{alt:name,src:imageUrl,resolutions:gridResolutions,itemProp:"image"}));};ItemImage.defaultProps={imageUrl:null,name:null};export default memo(ItemImage);
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import ItemImage from"./index";jest.mock('@shopgate/engage/components',function(){return{ProductImage:function ProductImage(){return null;}};});describe('<ItemImage />',function(){it('should render',function(){var wrapper=shallow(React.createElement(ItemImage,{productId:"1234",imageUrl:"http://www.google.com",name:"FooBar"}));expect(wrapper).toMatchSnapshot();});});
@@ -0,0 +1,5 @@
1
+ import React,{memo,useMemo}from'react';import PropTypes from'prop-types';import{PRODUCT_ITEM_NAME,PRODUCT_ITEM_NAME_BEFORE,PRODUCT_ITEM_NAME_AFTER}from'@shopgate/engage/category/constants';import{Portal}from'@shopgate/engage/components';import{ProductName}from'@shopgate/engage/product';import{makeStyles}from'@shopgate/engage/styles';var useStyles=makeStyles()({root:{fontWeight:'500',lineHeight:1.15,marginTop:1,wordBreak:['keep-all','break-word'],hyphens:'auto'}});/**
2
+ * The item name component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX.Element|null}
5
+ */var ItemName=function ItemName(_ref){var display=_ref.display,productId=_ref.productId,name=_ref.name;var _useStyles=useStyles(),classes=_useStyles.classes,cx=_useStyles.cx;var portalProps=useMemo(function(){return{productId:productId,display:display};},[display,productId]);if(display&&!display.name){return React.createElement(React.Fragment,null,React.createElement(Portal,{name:PRODUCT_ITEM_NAME_BEFORE,props:portalProps}),React.createElement(Portal,{name:PRODUCT_ITEM_NAME_AFTER,props:portalProps}));}return React.createElement(ProductName,{name:name,className:cx(classes.root,'theme__product-grid__item__item-name'),portalName:PRODUCT_ITEM_NAME,portalProps:portalProps,testId:"Productname: ".concat(name)});};ItemName.defaultProps={display:null,name:null};export default memo(ItemName);
@@ -0,0 +1 @@
1
+ import React from'react';import{shallow}from'enzyme';import ItemName from"./index";jest.mock('@shopgate/engage/product',function(){return{ProductName:function ProductName(){return null;}};});var props={productId:'1234',name:'Foo'};describe('<ItemName />',function(){it('should render with minimal props',function(){var wrapper=shallow(React.createElement(ItemName,props));expect(wrapper).toMatchSnapshot();});});
@@ -0,0 +1,5 @@
1
+ import React,{memo,useMemo}from'react';import PropTypes from'prop-types';import{SurroundPortals}from'@shopgate/engage/components';import{PRODUCT_ITEM_PRICE}from'@shopgate/engage/category';import{ProductGridPrice}from'@shopgate/engage/product';/**
2
+ * The item price component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX.Element|null}
5
+ */var ItemPrice=function ItemPrice(_ref){var display=_ref.display,product=_ref.product;var productId=product.id;var portalProps=useMemo(function(){return{productId:productId,location:'productGrid'};},[productId]);if(display&&!display.price){return null;}return React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_PRICE,portalProps:portalProps},React.createElement(ProductGridPrice,{product:product}));};ItemPrice.defaultProps={display:null};export default memo(ItemPrice);
@@ -0,0 +1 @@
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 from'react';import{shallow}from'enzyme';import ItemPrice from"./index";jest.mock('@shopgate/engage/product',function(){return{ProductGridPrice:function ProductGridPrice(){return null;}};});jest.mock('@shopgate/engage/components',function(){return{Portal:function Portal(_ref){var children=_ref.children;return children;}};});jest.mock('@shopgate/engage/category',function(){return{PRODUCT_ITEM_PRICE:'PRODUCT_ITEM_PRICE',PRODUCT_ITEM_PRICE_AFTER:'PRODUCT_ITEM_PRICE_AFTER',PRODUCT_ITEM_PRICE_BEFORE:'PRODUCT_ITEM_PRICE_BEFORE'};});var props={product:{id:'1234',price:{}}};var display={price:false};describe('<ItemPrice />',function(){it('should render with minimal props',function(){var wrapper=shallow(React.createElement(ItemPrice,props));expect(wrapper).toMatchSnapshot();});it('should not render with display props set',function(){var wrapper=shallow(React.createElement(ItemPrice,_extends({},props,{display:display})));expect(wrapper).toBeEmptyRender();});});
@@ -0,0 +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 React,{memo}from'react';import PropTypes from'prop-types';import{isBeta}from'@shopgate/engage/core';import{getProductRoute,FeaturedMedia,ProductBadges}from'@shopgate/engage/product';import{Link}from'@shopgate/engage/components';import{useProductListType}from'@shopgate/engage/product/hooks';import{themeConfig}from'@shopgate/engage';import{makeStyles}from'@shopgate/engage/styles';import ItemImage from"./components/ItemImage";import ItemDiscount from"./components/ItemDiscount";import ItemFavoritesButton from"./components/ItemFavoritesButton";import ItemDetails from"./components/ItemDetails";var colors=themeConfig.colors;var useStyles=makeStyles()(function(theme,_ref){var display=_ref.display;return{root:{position:'relative',display:'flex',flexDirection:'column',background:colors.light,height:'100%'},itemDetails:_extends({position:'relative'},display&&!display.name&&!display.price&&!display.reviews&&{paddingBottom:30})};});/**
2
+ * The Product Grid Item component.
3
+ * @param {Object} props The component props.
4
+ * @param {Object} props.product The product.
5
+ * @param {Object} props.display The display object.
6
+ * @return {JSX.Element}
7
+ */var Item=function Item(_ref2){var product=_ref2.product,display=_ref2.display;var _useStyles=useStyles({display:display}),classes=_useStyles.classes,cx=_useStyles.cx;var _useProductListType=useProductListType(),meta=_useProductListType.meta;return React.createElement("div",{className:cx(classes.root,'theme__product-grid__item')},React.createElement(Link,{role:"none",href:getProductRoute(product.id),state:_extends({title:product.name},meta)},isBeta()&&product.featuredMedia?React.createElement(FeaturedMedia,{type:product.featuredMedia.type,url:product.featuredMedia.url}):React.createElement(ItemImage,{productId:product.id,name:product.name,imageUrl:product.featuredImageBaseUrl})),React.createElement(ProductBadges,{location:"productGrid",productId:product.id},React.createElement(ItemDiscount,{productId:product.id,discount:product.price.discount||null})),React.createElement("div",{className:classes.itemDetails},React.createElement(ItemDetails,{product:product,display:display,productListTypeMeta:meta}),React.createElement(ItemFavoritesButton,{productId:product.id})));};Item.defaultProps={display:null};export default memo(Item);
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import{Grid,SurroundPortals}from'@shopgate/engage/components';import{PRODUCT_ITEM}from'@shopgate/engage/category';import{ProductListEntryProvider}from'@shopgate/engage/product';import Item from"../Item";/**
2
+ * The Product Grid Iterator component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX}
5
+ */var Iterator=function Iterator(props){var portalProps={productId:props.id};var id=props.id,display=props.display;return React.createElement(Grid.Item,{key:id,"data-test-id":props.name,className:"theme__product-grid__item__container"},React.createElement(ProductListEntryProvider,{productId:props.id},React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM,portalProps:portalProps},React.createElement(Item,{product:props,display:display}))));};Iterator.defaultProps={display:null,name:null};export default Iterator;
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import{Grid}from'@shopgate/engage/components';import{makeStyles}from'@shopgate/engage/styles';var useStyles=makeStyles()(function(theme,_ref){var columns=_ref.columns;return{root:{padding:'0 16px',':not(:empty)':{marginTop:16},display:'grid',gridGap:'0 16px',gridTemplateColumns:"repeat(".concat(columns,", 1fr)")}};});/**
2
+ * The product grid layout component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX}
5
+ */var Layout=function Layout(_ref2){var children=_ref2.children,columns=_ref2.columns,className=_ref2.className;var _useStyles=useStyles({columns:columns}),classes=_useStyles.classes,cx=_useStyles.cx;return React.createElement(Grid,{wrap:true,className:cx(classes.root,className,'theme__product-grid'),"data-test-id":"productGrid"},children);};Layout.defaultProps={className:null,children:null};export default Layout;
@@ -0,0 +1,22 @@
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,{useContext}from'react';import PropTypes from'prop-types';import{ViewContext,InfiniteContainer,LoadingIndicator}from'@shopgate/engage/components';import{ProductListTypeProvider}from'@shopgate/engage/product';import{ITEMS_PER_LOAD}from'@shopgate/engage/core/constants';import{useResponsiveValue}from'@shopgate/engage/styles';import Iterator from"./components/Iterator";import Layout from"./components/Layout";export var WIDGET_ID='@shopgate/engage/product/ProductGrid';/**
2
+ * The Product Grid component.
3
+ * @param {Object} props The component props.
4
+ * @param {Array} props.products The list of products to display.
5
+ * @param {string} props.scope Optional scope of the component. Will be used as subType property of
6
+ * the ProductListTypeContext and is intended as a description in which "context" the component is
7
+ * used.
8
+ * @param {Object} props.meta Optional metadata for the product list type context.
9
+ * @param {Object} props.flags The flags object.
10
+ * @param {boolean} props.flags.name Whether to display product names.
11
+ * @param {boolean} props.flags.price Whether to display product prices.
12
+ * @param {boolean} props.flags.reviews Whether to display rating stars.
13
+ * @param {boolean} props.infiniteLoad Whether the grid should support infinite loading.
14
+ * @param {Function} props.handleGetProducts Callback function that's invoked to load more products
15
+ * when infinite loading is enabled.
16
+ * @param {number} props.totalProductCount The total number of products. Needed when infinite
17
+ * loading is enabled.
18
+ * @param {string} props.requestHash The hash for the current request. Needed when infinite loading
19
+ * is enabled
20
+ * @param {string} props.className Optional class name for the grid container
21
+ * @returns {JSX.Element}
22
+ */var ProductGrid=function ProductGrid(_ref){var flags=_ref.flags,infiniteLoad=_ref.infiniteLoad,handleGetProducts=_ref.handleGetProducts,products=_ref.products,totalProductCount=_ref.totalProductCount,requestHash=_ref.requestHash,scope=_ref.scope,meta=_ref.meta,className=_ref.className;var _useContext=useContext(ViewContext),getContentRef=_useContext.getContentRef;var columns=useResponsiveValue({xs:2,md:4});if(!infiniteLoad){return React.createElement(Layout,{columns:columns,className:className},React.createElement(ProductListTypeProvider,{type:"productGrid",subType:scope,meta:meta},products.map(function(product){return React.createElement(Iterator,_extends({display:flags,id:product.id,key:product.id},product));})));}return React.createElement(ProductListTypeProvider,{type:"productGrid",subType:scope,meta:meta},React.createElement(InfiniteContainer,{containerRef:getContentRef(),wrapper:function wrapper(props){return React.createElement(Layout,_extends({columns:columns,className:className},props));},iterator:Iterator,loader:handleGetProducts,items:products,columns:columns,loadingIndicator:React.createElement(LoadingIndicator,null),totalItems:totalProductCount,initialLimit:ITEMS_PER_LOAD,limit:ITEMS_PER_LOAD,requestHash:requestHash,enablePromiseBasedLoading:true}));};ProductGrid.defaultProps={flags:null,handleGetProducts:function handleGetProducts(){},infiniteLoad:true,products:null,requestHash:null,totalProductCount:null,scope:null,meta:null,className:null};export default ProductGrid;
@@ -0,0 +1 @@
1
+ import React from'react';import{mount}from'enzyme';import ProductGrid from'.';global.console.error=jest.fn();jest.mock('@shopgate/engage/core',function(){return{hasWebBridge:jest.fn(function(){return false;}),isIOSTheme:jest.fn(function(){return false;}),withForwardedRef:jest.fn(),withCurrentProduct:jest.fn(),useWidgetSettings:jest.fn().mockReturnValue({})};});jest.mock('@shopgate/engage/components',function(){var _jest$requireActual=jest.requireActual('@shopgate/engage/components/View/context'),ViewContext=_jest$requireActual.ViewContext;return{ViewContext:ViewContext,InfiniteContainer:function InfiniteContainer(){return null;},Grid:function Grid(){return null;}};});jest.mock("./components/Iterator",function(){return function Iterator(){return null;};});jest.mock('@shopgate/engage/product',function(){return{ProductListTypeProvider:function ProductListTypeProvider(_ref){var children=_ref.children;return children;},ProductListEntryProvider:function ProductListEntryProvider(_ref2){var children=_ref2.children;return children;}};});describe('<ProductGrid />',function(){it('should render with the InfiniteContainer',function(){var wrapper=mount(React.createElement(ProductGrid,{products:[]}));expect(wrapper).toMatchSnapshot();expect(wrapper.find('InfiniteContainer').exists()).toBe(true);expect(wrapper.find('Layout').exists()).toBe(false);});it('should render the original layout',function(){var wrapper=mount(React.createElement(ProductGrid,{infiniteLoad:false,products:[]}));expect(wrapper).toMatchSnapshot();expect(wrapper.find('InfiniteContainer').exists()).toBe(false);expect(wrapper.find('Layout').exists()).toBe(true);});});
@@ -2,5 +2,5 @@ import React,{Fragment}from'react';import PropTypes from'prop-types';import{Grid
2
2
  * The ProductGridPrice component is supposed to be used to display prices at product grids. It
3
3
  * renders a row with the current price and a strike price when present. As same as the price info.
4
4
  * @param {Object} product A product entity.
5
- * @return {JSX}
5
+ * @return {JSX.Element}
6
6
  */var ProductGridPrice=function ProductGridPrice(_ref){var product=_ref.product;var price=product.price;return React.createElement(Fragment,null,React.createElement(Grid,{className:"".concat(styles.priceWrapper," engage__product__product-grid-price"),wrap:true},React.createElement(Grid.Item,{grow:1},React.createElement(Price,{currency:price.currency,discounted:!!price.discount,unitPrice:price.unitPrice,unitPriceMin:price.unitPriceMin})),price.msrp>0&&price.unitPrice!==price.msrp&&React.createElement(Grid.Item,null,React.createElement(PriceStriked,{className:styles.strikedPrice,value:price.msrp,currency:price.currency})),!price.msrp&&price.unitPriceStriked>0&&price.unitPrice!==price.unitPriceStriked&&React.createElement(Grid.Item,null,React.createElement(PriceStriked,{className:styles.strikedPrice,value:price.unitPriceStriked,currency:price.currency}))),React.createElement(PriceInfo,{product:product,className:styles.basicPrice,wrapper:function wrapper(children){return React.createElement(Grid,null,React.createElement(Grid.Item,null,children));}}));};export default withPriceCalculation(ProductGridPrice);
@@ -1,5 +1,5 @@
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 from'react';import PropTypes from'prop-types';import{useWidgetSettings}from'@shopgate/engage/core';import{useThemeComponents}from'@shopgate/engage/core/hooks';import{Swiper}from'@shopgate/engage/components';import{ProductListTypeProvider,ProductListEntryProvider}from'@shopgate/engage/product/providers';import{container,items}from"./style";export var WIDGET_ID='@shopgate/engage/product/ProductSlider';/**
1
+ var _excluded=["autoplay","className","delay","productIds","snap","scope","meta","productItemProps","item"];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 _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 from'react';import PropTypes from'prop-types';import{useWidgetSettings}from'@shopgate/engage/core';import{useThemeComponents}from'@shopgate/engage/core/hooks';import{Swiper}from'@shopgate/engage/components';import{ProductListTypeProvider,ProductListEntryProvider}from'@shopgate/engage/product/providers';import{container,items}from"./style";export var WIDGET_ID='@shopgate/engage/product/ProductSlider';/**
2
2
  * @param {Object} props The component props.
3
- * @returns {JSX}
4
- */function ProductSlider(props){var autoplay=props.autoplay,className=props.className,delay=props.delay,productIds=props.productIds,snap=props.snap,scope=props.scope,meta=props.meta;var widgetSettings=useWidgetSettings(WIDGET_ID)||{};var _ref=props.slidesPerView?props:widgetSettings,_ref$slidesPerView=_ref.slidesPerView,slidesPerView=_ref$slidesPerView===void 0?2.3:_ref$slidesPerView;// ProductSlider items are rendered with the ProductCard component provided by the theme.
5
- var _useThemeComponents=useThemeComponents(),ProductCard=_useThemeComponents.ProductCard;var Item=props.item||ProductCard;return React.createElement(ProductListTypeProvider,{type:"productSlider",subType:scope,meta:meta},React.createElement(Swiper,_extends({},autoplay&&{autoplay:{delay:delay}},{className:"".concat(className," engage__product__product-slider"),controls:false,indicators:false,loop:false,freeMode:!snap,slidesPerView:slidesPerView}),productIds.map(function(id){return React.createElement(Swiper.Item,{key:id,className:container},React.createElement(ProductListEntryProvider,{productId:id},React.createElement(Item,{productId:id,style:items})));})));}ProductSlider.WIDGET_ID=WIDGET_ID;ProductSlider.defaultProps={autoplay:false,className:null,delay:10,item:null,slidesPerView:null,snap:false,scope:null,meta:null};export default ProductSlider;
3
+ * @returns {JSX.Element}
4
+ */function ProductSlider(props){var autoplay=props.autoplay,className=props.className,delay=props.delay,productIds=props.productIds,snap=props.snap,scope=props.scope,meta=props.meta,productItemProps=props.productItemProps,item=props.item,swiperProps=_objectWithoutProperties(props,_excluded);var widgetSettings=useWidgetSettings(WIDGET_ID)||{};var _ref=props.slidesPerView?props:widgetSettings,_ref$slidesPerView=_ref.slidesPerView,slidesPerView=_ref$slidesPerView===void 0?2.3:_ref$slidesPerView;// ProductSlider items are rendered with the ProductCard component provided by the theme.
5
+ var _useThemeComponents=useThemeComponents(),ProductCard=_useThemeComponents.ProductCard;var Item=item||ProductCard;return React.createElement(ProductListTypeProvider,{type:"productSlider",subType:scope,meta:meta},React.createElement(Swiper,_extends({},autoplay&&{autoplay:{delay:delay}},{className:"".concat(className," engage__product__product-slider"),controls:false,indicators:false,freeMode:!snap},swiperProps,{slidesPerView:slidesPerView}),productIds.map(function(id){return React.createElement(Swiper.Item,{key:id,className:container},React.createElement(ProductListEntryProvider,{productId:id},React.createElement(Item,_extends({productId:id,style:items},productItemProps))));})));}ProductSlider.WIDGET_ID=WIDGET_ID;ProductSlider.defaultProps={autoplay:false,className:null,delay:10,item:null,meta:null,productItemProps:null,scope:null,slidesPerView:null,snap:false};export default ProductSlider;
@@ -1 +1 @@
1
- export*from"./Availability";export{default as Characteristics}from"./Characteristics";export{default as Description}from"./Description";export{default as EffectivityDates}from"./EffectivityDates";export{default as MapPriceHint}from"./MapPriceHint";export*from"./Media";export{default as MediaSlider}from"./MediaSlider";export{default as Options}from"./Options";export{SelectOption,TextOption}from"./Options";export{default as OrderQuantityHint}from"./OrderQuantityHint";export{default as PriceDifference}from"./PriceDifference";export*from"./PriceInfo";export{default as ProductBadges}from"./ProductBadges";export{default as ProductCard}from"./ProductCard";export{default as ProductCharacteristics}from"./ProductCharacteristics";export{default as ProductDiscountBadge}from"./ProductDiscountBadge";export{default as ProductGridPrice}from"./ProductGridPrice";export{default as ProductImage}from"./ProductImage";export{default as ProductList}from"./ProductList";export*from"./ProductName";export{default as ProductProperties}from"./ProductProperties/ProductProperties";export{default as ProductSlider}from"./ProductSlider";export*from"./ProductVariants";export{default as QuantityPicker}from"./QuantityPicker";export{default as Rating}from"./Rating";export*from"./RelationsSlider";export*from"./Swatch";export*from"./Swatches";export*from"./UnitQuantityPicker";export{default as FilterBar}from"./FilterBar";export{default as ProductFilters}from"./ProductFilters";
1
+ export*from"./Availability";export{default as Characteristics}from"./Characteristics";export{default as Description}from"./Description";export{default as EffectivityDates}from"./EffectivityDates";export{default as MapPriceHint}from"./MapPriceHint";export*from"./Media";export{default as MediaSlider}from"./MediaSlider";export{default as Options}from"./Options";export{SelectOption,TextOption}from"./Options";export{default as OrderQuantityHint}from"./OrderQuantityHint";export{default as PriceDifference}from"./PriceDifference";export*from"./PriceInfo";export{default as ProductBadges}from"./ProductBadges";export{default as ProductCard}from"./ProductCard";export{default as ProductCharacteristics}from"./ProductCharacteristics";export{default as ProductDiscountBadge}from"./ProductDiscountBadge";export{default as ProductGrid}from"./ProductGrid";export{default as ProductGridPrice}from"./ProductGridPrice";export{default as ProductImage}from"./ProductImage";export{default as ProductList}from"./ProductList";export*from"./ProductName";export{default as ProductProperties}from"./ProductProperties/ProductProperties";export{default as ProductSlider}from"./ProductSlider";export*from"./ProductVariants";export{default as QuantityPicker}from"./QuantityPicker";export{default as Rating}from"./Rating";export*from"./RelationsSlider";export*from"./Swatch";export*from"./Swatches";export*from"./UnitQuantityPicker";export{default as FilterBar}from"./FilterBar";export{default as ProductFilters}from"./ProductFilters";
@@ -0,0 +1,23 @@
1
+ // Import the Color constructor from the color.js package
2
+ import Color from'color';/**
3
+ * Converts any valid input color to an RGBA CSS string.
4
+ * If the input color already contains an alpha channel (< 1), that alpha is preserved.
5
+ * Otherwise, the provided `opacity` is applied.
6
+ *
7
+ * @param {string} inputColor any CSS‐valid color string (hex, rgb(), hsl(), etc.)
8
+ * @param {number} [opacity=1] fallback alpha (0–1) to use if `inputColor` has no alpha
9
+ * @returns {string} "rgba(r, g, b, a)" string
10
+ *
11
+ * @example
12
+ * toRgba('#ff0000') // → "rgba(255, 0, 0, 1)"
13
+ * toRgba('#ff0000', 0.5) // → "rgba(255, 0, 0, 0.5)"
14
+ * toRgba('rgba(10,20,30,0.2)', 0.9) // → "rgba(10, 20, 30, 0.2)"
15
+ * toRgba('hsl(120, 100%, 50%)') // → "rgba(0, 255, 0, 1)"
16
+ * toRgba('blue', 0.3) // → "rgba(0, 0, 255, 0.3)"
17
+ */export function colorToRgba(inputColor){var opacity=arguments.length>1&&arguments[1]!==undefined?arguments[1]:1;// Parse the input into a Color instance
18
+ var parsed=Color(inputColor);// Extract the alpha channel from the parsed color (default is 1 if none was provided)
19
+ var inputAlpha=parsed.alpha();// Determine which alpha to use:
20
+ // - If the parsed color already had alpha < 1, keep that.
21
+ // - Otherwise, use the provided opacity value.
22
+ var finalAlpha=inputAlpha<1?inputAlpha:opacity;// Set the computed alpha and return as "rgba(r, g, b, a)" string
23
+ return parsed.alpha(finalAlpha).rgb().string();}
@@ -1 +1 @@
1
- export{getCSSCustomProp,setCSSCustomProp}from"./cssCustomProperties";export{updatePageInsets}from"./updatePageInsets";export{setPageBackgroundColor}from"./setPageBackgroundColor";export{setPageContentWidth}from"./setPageContentWidth";export{setViewportHeight}from"./setViewportHeight";export{toggleBodyScroll}from"./toggleBodyScroll";export{initCSSCustomProps,initCSSCustomPropsFallback}from"./initCSSCustomProperties";export{loadCustomStyles}from"./loadCustomStyles";export{responsiveMediaQuery}from"../../components/ResponsiveContainer/mediaQuery";export{responsiveCondition}from"../../components/ResponsiveContainer/condition";
1
+ export{getCSSCustomProp,setCSSCustomProp}from"./cssCustomProperties";export{updatePageInsets}from"./updatePageInsets";export{setPageBackgroundColor}from"./setPageBackgroundColor";export{setPageContentWidth}from"./setPageContentWidth";export{setViewportHeight}from"./setViewportHeight";export{toggleBodyScroll}from"./toggleBodyScroll";export{initCSSCustomProps,initCSSCustomPropsFallback}from"./initCSSCustomProperties";export{loadCustomStyles}from"./loadCustomStyles";export*from"./color";export{responsiveMediaQuery}from"../../components/ResponsiveContainer/mediaQuery";export{responsiveCondition}from"../../components/ResponsiveContainer/condition";
@@ -1,5 +1,5 @@
1
- import{themeConfig}from'@shopgate/pwa-common/helpers/config';import{hasWebBridge}from'@shopgate/engage/core/helpers';import{setCSSCustomProp}from"./cssCustomProperties";var defaultBackgroundColor=themeConfig.colors.light;/**
1
+ import{themeConfig}from'@shopgate/pwa-common/helpers/config';import{hasWebBridge}from'@shopgate/engage/core/helpers';import{IS_PAGE_PREVIEW_ACTIVE}from'@shopgate/engage/page/constants';import{setCSSCustomProp}from"./cssCustomProperties";var defaultBackgroundColor=themeConfig.colors.light;/**
2
2
  * Updates the page background color.
3
3
  * @param {string} color The new background color.
4
4
  */export var setPageBackgroundColor=function setPageBackgroundColor(){var color=arguments.length>0&&arguments[0]!==undefined?arguments[0]:defaultBackgroundColor;// Curbside website changes never its background color
5
- if(!hasWebBridge()){setCSSCustomProp('--page-background-color',color);}};
5
+ if(!hasWebBridge()||IS_PAGE_PREVIEW_ACTIVE){setCSSCustomProp('--page-background-color',color);}};