@shopgate/pwa-common 7.30.0-alpha.7 → 7.30.0-alpha.8

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 (306) hide show
  1. package/App.js +48 -6
  2. package/action-creators/app/index.js +75 -12
  3. package/action-creators/app/spec.js +96 -1
  4. package/action-creators/client/index.js +27 -5
  5. package/action-creators/client/spec.js +44 -1
  6. package/action-creators/error/index.js +15 -3
  7. package/action-creators/index.js +9 -1
  8. package/action-creators/menu/index.js +23 -4
  9. package/action-creators/menu/spec.js +37 -1
  10. package/action-creators/modal/index.js +15 -3
  11. package/action-creators/modal/spec.js +26 -1
  12. package/action-creators/page/index.js +24 -4
  13. package/action-creators/page/spec.js +38 -1
  14. package/action-creators/router/index.js +48 -7
  15. package/action-creators/url/index.js +24 -4
  16. package/action-creators/url/spec.js +45 -1
  17. package/action-creators/user/index.js +90 -13
  18. package/action-creators/user/spec.js +186 -2
  19. package/actions/app/handleDeepLink.js +11 -2
  20. package/actions/app/handleLink.js +62 -6
  21. package/actions/app/handlePushNotification.js +32 -4
  22. package/actions/app/handleUniversalLink.js +11 -2
  23. package/actions/app/registerLinkEvents.js +24 -3
  24. package/actions/client/fetchClientInformation.js +26 -2
  25. package/actions/menu/fetchMenu.js +23 -2
  26. package/actions/modal/closeModal.js +18 -2
  27. package/actions/modal/promiseMap.js +3 -1
  28. package/actions/modal/showModal.js +54 -8
  29. package/actions/page/fetchPageConfig.js +69 -2
  30. package/actions/page/getPageConfig.js +6 -2
  31. package/actions/page/index.js +1 -1
  32. package/actions/router/historyPop.js +12 -2
  33. package/actions/router/historyPopToRoute.js +27 -2
  34. package/actions/router/historyPush.js +12 -2
  35. package/actions/router/historyRedirect.js +21 -2
  36. package/actions/router/historyReplace.js +20 -3
  37. package/actions/router/historyReset.js +11 -2
  38. package/actions/router/historyResetTo.js +12 -2
  39. package/actions/router/index.js +17 -1
  40. package/actions/router/routeDidPop.js +11 -2
  41. package/actions/router/routeDidPush.js +13 -2
  42. package/actions/router/routeDidReplace.js +11 -2
  43. package/actions/router/routeDidReset.js +11 -2
  44. package/actions/router/routeDidUpdate.js +10 -2
  45. package/actions/router/routeWillPop.js +11 -2
  46. package/actions/router/routeWillPush.js +13 -2
  47. package/actions/router/routeWillReplace.js +11 -2
  48. package/actions/router/routeWillReset.js +11 -2
  49. package/actions/router/windowOpenOverride.js +10 -2
  50. package/actions/user/fetchRegisterUrl.js +36 -2
  51. package/actions/user/fetchUser.js +29 -3
  52. package/actions/user/getUser.js +6 -2
  53. package/actions/user/index.js +1 -1
  54. package/actions/user/login.js +76 -9
  55. package/actions/user/logout.js +30 -2
  56. package/collections/AuthRoutes.js +73 -14
  57. package/collections/Configuration.js +54 -7
  58. package/collections/EmbeddedMedia.js +84 -11
  59. package/collections/PersistedReducers.js +41 -6
  60. package/collections/Redirects.js +103 -17
  61. package/collections/index.js +5 -1
  62. package/collections/media-providers/MediaProvider.js +151 -26
  63. package/collections/media-providers/Vimeo.js +113 -19
  64. package/collections/media-providers/YouTube.js +74 -14
  65. package/collections/media-providers/index.js +3 -1
  66. package/collections/media-providers/style.js +52 -2
  67. package/components/Backdrop/index.js +95 -6
  68. package/components/Backdrop/spec.js +23 -1
  69. package/components/Backdrop/style.js +11 -2
  70. package/components/Button/index.js +47 -5
  71. package/components/Button/spec.js +36 -1
  72. package/components/Button/style.js +6 -1
  73. package/components/Checkbox/index.js +126 -32
  74. package/components/Checkbox/spec.js +94 -3
  75. package/components/Consume/helpers/buildParams.js +13 -2
  76. package/components/Consume/index.js +14 -2
  77. package/components/CountdownTimer/index.js +115 -17
  78. package/components/CountdownTimer/spec.js +126 -12
  79. package/components/Drawer/index.js +131 -16
  80. package/components/Drawer/spec.js +76 -1
  81. package/components/Drawer/style.js +37 -1
  82. package/components/Dropdown/index.js +65 -6
  83. package/components/Dropdown/style.js +4 -1
  84. package/components/Dropdown/transitions.js +34 -1
  85. package/components/Ellipsis/index.js +16 -2
  86. package/components/Ellipsis/spec.js +13 -1
  87. package/components/EmbeddedMedia/index.js +56 -6
  88. package/components/EmbeddedMedia/spec.js +52 -3
  89. package/components/ErrorBoundary/connector.js +9 -2
  90. package/components/ErrorBoundary/index.js +43 -7
  91. package/components/Grid/components/Item/index.js +40 -4
  92. package/components/Grid/components/Item/spec.js +23 -1
  93. package/components/Grid/components/Item/style.js +17 -3
  94. package/components/Grid/index.js +36 -4
  95. package/components/Grid/spec.js +23 -1
  96. package/components/Grid/style.js +11 -2
  97. package/components/HtmlSanitizer/connector.js +24 -3
  98. package/components/HtmlSanitizer/index.js +104 -12
  99. package/components/HtmlSanitizer/spec.js +207 -6
  100. package/components/I18n/components/FormatDate/index.js +26 -2
  101. package/components/I18n/components/FormatDate/spec.js +46 -1
  102. package/components/I18n/components/FormatNumber/index.js +34 -2
  103. package/components/I18n/components/FormatNumber/spec.js +41 -2
  104. package/components/I18n/components/FormatPrice/index.js +32 -2
  105. package/components/I18n/components/FormatPrice/spec.js +46 -1
  106. package/components/I18n/components/FormatTime/index.js +26 -2
  107. package/components/I18n/components/FormatTime/spec.js +43 -2
  108. package/components/I18n/components/I18nProvider/index.js +52 -9
  109. package/components/I18n/components/I18nProvider/spec.js +39 -1
  110. package/components/I18n/components/Placeholder/index.js +8 -2
  111. package/components/I18n/components/Placeholder/spec.js +30 -1
  112. package/components/I18n/components/Translate/index.js +68 -7
  113. package/components/I18n/components/Translate/spec.js +30 -1
  114. package/components/I18n/index.js +16 -1
  115. package/components/Icon/index.js +25 -2
  116. package/components/Icon/style.js +6 -1
  117. package/components/Image/Image.js +176 -19
  118. package/components/Image/ImageInner.js +48 -2
  119. package/components/Image/index.js +1 -1
  120. package/components/Image/style.js +29 -2
  121. package/components/InfiniteContainer/index.js +381 -49
  122. package/components/InfiniteContainer/spec.js +199 -10
  123. package/components/Input/components/DateInput.js +262 -6
  124. package/components/Input/components/MultiLineInput.js +98 -12
  125. package/components/Input/components/SimpleInput.js +207 -31
  126. package/components/Input/index.js +32 -3
  127. package/components/Input/spec.js +122 -1
  128. package/components/KeyboardConsumer/index.js +48 -7
  129. package/components/Link/connector.js +7 -1
  130. package/components/Link/index.js +96 -11
  131. package/components/Link/spec.js +56 -1
  132. package/components/Link/style.js +10 -1
  133. package/components/List/components/Item/index.js +35 -3
  134. package/components/List/components/Item/style.js +16 -1
  135. package/components/List/index.js +20 -2
  136. package/components/List/spec.js +31 -1
  137. package/components/Loading/index.js +6 -2
  138. package/components/Modal/index.js +38 -3
  139. package/components/Modal/style.js +36 -1
  140. package/components/ModalContainer/connector.js +17 -3
  141. package/components/ModalContainer/index.js +36 -3
  142. package/components/ModalContainer/spec.js +105 -5
  143. package/components/Picker/components/Button/index.js +34 -2
  144. package/components/Picker/components/Button/style.js +19 -1
  145. package/components/Picker/components/List/index.js +33 -2
  146. package/components/Picker/components/List/style.js +17 -1
  147. package/components/Picker/components/Modal/index.js +60 -7
  148. package/components/Picker/components/Modal/style.js +78 -1
  149. package/components/Picker/index.js +167 -21
  150. package/components/Picker/spec.js +83 -2
  151. package/components/Portal/index.js +130 -19
  152. package/components/ProductCharacteristics/connector.js +33 -4
  153. package/components/ProductCharacteristics/context.js +2 -1
  154. package/components/ProductCharacteristics/helpers/index.js +135 -21
  155. package/components/ProductCharacteristics/index.js +266 -31
  156. package/components/RangeSlider/components/Handle/index.js +25 -2
  157. package/components/RangeSlider/components/Handle/style.js +14 -1
  158. package/components/RangeSlider/helper.js +43 -8
  159. package/components/RangeSlider/index.js +228 -38
  160. package/components/RangeSlider/style.js +14 -1
  161. package/components/Route/RouteNotFound.js +46 -3
  162. package/components/Route/index.js +78 -10
  163. package/components/Router/connector.js +9 -2
  164. package/components/Router/index.js +237 -31
  165. package/components/ScannerContainer/connector.js +9 -2
  166. package/components/ScannerContainer/index.js +42 -6
  167. package/components/Select/components/Item/index.js +20 -4
  168. package/components/Select/components/Item/style.js +4 -1
  169. package/components/Select/index.js +149 -28
  170. package/components/Select/spec.js +86 -2
  171. package/components/Select/style.js +17 -1
  172. package/components/SelectBox/components/Item/index.js +47 -5
  173. package/components/SelectBox/components/Item/style.js +7 -1
  174. package/components/SelectBox/index.js +173 -17
  175. package/components/SelectBox/spec.js +59 -3
  176. package/components/SelectBox/style.js +18 -1
  177. package/components/Slider/index.js +6 -2
  178. package/components/SurroundPortals/index.js +26 -2
  179. package/components/Swiper/components/SwiperItem/index.js +28 -4
  180. package/components/Swiper/components/SwiperItem/spec.js +17 -1
  181. package/components/Swiper/components/SwiperItem/styles.js +5 -1
  182. package/components/Swiper/index.js +210 -18
  183. package/components/Swiper/styles.js +75 -7
  184. package/components/Toaster/index.js +10 -2
  185. package/components/Transition/index.js +89 -13
  186. package/components/Widgets/components/Widget/index.js +52 -4
  187. package/components/Widgets/components/Widget/spec.js +68 -3
  188. package/components/Widgets/components/Widget/style.js +21 -3
  189. package/components/Widgets/components/WidgetGrid/index.js +52 -7
  190. package/components/Widgets/components/WidgetGrid/spec.js +46 -2
  191. package/components/Widgets/components/WidgetGrid/style.js +8 -1
  192. package/components/Widgets/helpers/shouldShowWidget.js +44 -7
  193. package/components/Widgets/index.js +127 -15
  194. package/components/Widgets/spec.js +213 -6
  195. package/components/index.js +9 -1
  196. package/constants/ActionTypes.js +97 -19
  197. package/constants/Configuration.js +12 -2
  198. package/constants/Device.js +29 -2
  199. package/constants/DisplayOptions.js +8 -1
  200. package/constants/MenuIDs.js +2 -1
  201. package/constants/ModalTypes.js +1 -1
  202. package/constants/PageIDs.js +1 -1
  203. package/constants/Pipelines.js +7 -1
  204. package/constants/Portals.js +136 -3
  205. package/constants/Registration.js +3 -1
  206. package/constants/RoutePaths.js +13 -2
  207. package/constants/Tracking.js +3 -1
  208. package/constants/client.js +6 -1
  209. package/constants/ui.js +2 -1
  210. package/constants/user.js +6 -2
  211. package/context/index.js +33 -3
  212. package/helpers/config/index.js +139 -21
  213. package/helpers/config/mock.js +200 -8
  214. package/helpers/config/theme.js +50 -4
  215. package/helpers/data/index.js +204 -29
  216. package/helpers/data/spec.js +187 -7
  217. package/helpers/date/index.js +58 -6
  218. package/helpers/date/spec.js +92 -1
  219. package/helpers/dom/index.js +48 -11
  220. package/helpers/environment/index.js +14 -2
  221. package/helpers/html/decodeHTML.js +7 -1
  222. package/helpers/html/handleDOM.js +172 -21
  223. package/helpers/html/parseHTML.js +67 -12
  224. package/helpers/i18n/getDateFormatter.js +23 -4
  225. package/helpers/i18n/getNumberFormatter.js +32 -4
  226. package/helpers/i18n/getPriceFormatter.js +38 -4
  227. package/helpers/i18n/getTimeFormatter.js +23 -4
  228. package/helpers/i18n/getTranslator.js +62 -8
  229. package/helpers/i18n/index.js +5 -1
  230. package/helpers/i18n/mergeTranslations.js +36 -9
  231. package/helpers/i18n/messageCache.js +3 -1
  232. package/helpers/legacy/index.js +47 -9
  233. package/helpers/modal/withShowModal.js +13 -2
  234. package/helpers/portals/portalCollection.js +28 -6
  235. package/helpers/portals/routePortals.js +12 -1
  236. package/helpers/redux/compareObjects.js +7 -2
  237. package/helpers/redux/generateResultHash.js +36 -3
  238. package/helpers/redux/generateSortedHash.js +7 -2
  239. package/helpers/redux/hasExpired.js +10 -2
  240. package/helpers/redux/index.js +7 -1
  241. package/helpers/redux/mutable.js +143 -24
  242. package/helpers/redux/shouldFetchData.js +46 -10
  243. package/helpers/redux/shouldFetchFilters.js +17 -4
  244. package/helpers/router/index.js +49 -5
  245. package/helpers/style/index.js +43 -4
  246. package/helpers/style/spec.js +108 -2
  247. package/helpers/tracking/index.js +52 -9
  248. package/helpers/validation/index.js +39 -12
  249. package/helpers/validation/spec.js +10 -1
  250. package/package.json +3 -3
  251. package/providers/index.js +4 -1
  252. package/providers/loading/context.js +2 -1
  253. package/providers/loading/index.js +137 -22
  254. package/providers/toast/context.js +2 -1
  255. package/providers/toast/index.js +105 -11
  256. package/reducers/client/connectivity.js +22 -2
  257. package/reducers/client/index.js +7 -1
  258. package/reducers/client/info.js +27 -2
  259. package/reducers/index.js +23 -4
  260. package/reducers/menu/index.js +5 -1
  261. package/reducers/menu/menusById.js +41 -2
  262. package/reducers/modal/index.js +14 -2
  263. package/reducers/page/index.js +68 -5
  264. package/reducers/router/index.js +48 -2
  265. package/reducers/url/index.js +42 -3
  266. package/reducers/user/data.js +27 -2
  267. package/reducers/user/index.js +7 -1
  268. package/reducers/user/login.js +65 -2
  269. package/selectors/client.js +138 -21
  270. package/selectors/history.js +49 -11
  271. package/selectors/menu.js +34 -6
  272. package/selectors/modal.js +15 -4
  273. package/selectors/page.js +25 -4
  274. package/selectors/router.js +154 -30
  275. package/selectors/url.js +25 -4
  276. package/selectors/user.js +90 -13
  277. package/store/index.js +60 -6
  278. package/store/middelwares/logger.js +7 -1
  279. package/store/middelwares/streams.js +19 -2
  280. package/streams/app.js +60 -8
  281. package/streams/client.js +8 -2
  282. package/streams/error.js +14 -3
  283. package/streams/index.js +6 -1
  284. package/streams/interval.js +6 -2
  285. package/streams/main.js +27 -2
  286. package/streams/router.js +45 -8
  287. package/streams/user.js +89 -15
  288. package/streams/view.js +97 -25
  289. package/styles/reset/form.js +57 -5
  290. package/styles/reset/index.js +6 -1
  291. package/styles/reset/media.js +22 -1
  292. package/styles/reset/root.js +33 -1
  293. package/styles/reset/table.js +10 -1
  294. package/styles/reset/typography.js +26 -1
  295. package/subscriptions/app.js +148 -17
  296. package/subscriptions/error.js +292 -13
  297. package/subscriptions/helpers/buildRegisterUrl.js +25 -6
  298. package/subscriptions/helpers/clearUpInAppBrowser.js +14 -3
  299. package/subscriptions/helpers/handleLinks.js +267 -25
  300. package/subscriptions/helpers/pipeline.js +12 -1
  301. package/subscriptions/history.js +34 -6
  302. package/subscriptions/index.js +25 -4
  303. package/subscriptions/menu.js +22 -5
  304. package/subscriptions/mock.js +39 -7
  305. package/subscriptions/router.js +336 -23
  306. package/subscriptions/user.js +93 -3
@@ -1,12 +1,41 @@
1
- import{connect}from'react-redux';import{router}from'@shopgate/pwa-common/helpers/router';import isEqual from'lodash/isEqual';import{getProductVariants}from'@shopgate/pwa-common-commerce/product/selectors/product';/**
1
+ import { connect } from 'react-redux';
2
+ import { router } from '@shopgate/pwa-common/helpers/router';
3
+ import isEqual from 'lodash/isEqual';
4
+ import { getProductVariants } from '@shopgate/pwa-common-commerce/product/selectors/product';
5
+
6
+ /**
2
7
  * Maps the contents of the state to the component props.
3
8
  * @param {Object} state The current application state.
4
9
  * @param {Object} props The component props.
5
10
  * @return {Object} The extended component props.
6
- */var mapStateToProps=function mapStateToProps(state,props){return{variants:getProductVariants(state,props)};};/**
11
+ */
12
+ const mapStateToProps = (state, props) => ({
13
+ variants: getProductVariants(state, props)
14
+ });
15
+
16
+ /**
7
17
  * @return {Object}
8
- */var mapDispatchToProps=function mapDispatchToProps(){return{navigate:function navigate(productId){var route=router.getCurrentRoute();router.update(route.id,{productId:productId});}};};/**
18
+ */
19
+ const mapDispatchToProps = () => ({
20
+ navigate: productId => {
21
+ const route = router.getCurrentRoute();
22
+ router.update(route.id, {
23
+ productId
24
+ });
25
+ }
26
+ });
27
+
28
+ /**
9
29
  * @param {Object} next The next component props.
10
30
  * @param {Object} prev The previous component props.
11
31
  * @returns {boolean}
12
- */var areStatePropsEqual=function areStatePropsEqual(next,prev){if(!prev.variants&&next.variants||!isEqual(prev.variants,next.variants)){return false;}return true;};export default connect(mapStateToProps,mapDispatchToProps,null,{areStatePropsEqual:areStatePropsEqual});
32
+ */
33
+ const areStatePropsEqual = (next, prev) => {
34
+ if (!prev.variants && next.variants || !isEqual(prev.variants, next.variants)) {
35
+ return false;
36
+ }
37
+ return true;
38
+ };
39
+ export default connect(mapStateToProps, mapDispatchToProps, null, {
40
+ areStatePropsEqual
41
+ });
@@ -1 +1,2 @@
1
- import React from'react';export default React.createContext();
1
+ import React from 'react';
2
+ export default /*#__PURE__*/React.createContext();
@@ -1,19 +1,48 @@
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 _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 isMatch from'lodash/isMatch';import appConfig from'@shopgate/pwa-common/helpers/config';var variantSelectionMode=appConfig.variantSelectionMode,_appConfig$product=appConfig.product,_appConfig$product2=_appConfig$product===void 0?{}:_appConfig$product,variantPreselect=_appConfig$product2.variantPreselect;var preselectVariant=variantPreselect||parseInt(variantSelectionMode,10)===1;/**
1
+ import "core-js/modules/es.array.reduce.js";
2
+ import isMatch from 'lodash/isMatch';
3
+ import appConfig from '@shopgate/pwa-common/helpers/config';
4
+ const {
5
+ variantSelectionMode,
6
+ product: {
7
+ variantPreselect
8
+ } = {}
9
+ } = appConfig;
10
+ const preselectVariant = variantPreselect || parseInt(variantSelectionMode, 10) === 1;
11
+
12
+ /**
2
13
  * Returns the index of a particular characteristic from a set of characteristics.
3
14
  * @param {Array} characteristics The characteristics of a product.
4
15
  * @param {number} characteristicId The id of the characteristic to find.
5
16
  * @return {number}
6
- */export function findSelectionIndex(characteristics,characteristicId){return characteristics.findIndex(function(_char){return _char.id===characteristicId;});}/**
17
+ */
18
+ export function findSelectionIndex(characteristics, characteristicId) {
19
+ return characteristics.findIndex(char => char.id === characteristicId);
20
+ }
21
+
22
+ /**
7
23
  * Returns true if the characteristic at the given index is the next characteristic to be selected.
8
24
  * @param {Array} characteristics The characteristics of a product.
9
25
  * @param {number} index The index of the characteristic to check.
10
26
  * @return {boolean}
11
- */export function isCharacteristicEnabled(characteristics,index){if(index===0){return true;}return!!Object.values(characteristics)[index-1];}/**
27
+ */
28
+ export function isCharacteristicEnabled(characteristics, index) {
29
+ if (index === 0) {
30
+ return true;
31
+ }
32
+ return !!Object.values(characteristics)[index - 1];
33
+ }
34
+
35
+ /**
12
36
  * Returns the selected value by characteristic ID.
13
37
  * @param {string} charId The characteristic ID.
14
38
  * @param {Object} characteristics The already selected characteristics.
15
39
  * @return {string|null}
16
- */export function getSelectedValue(charId,characteristics){return characteristics[charId]?characteristics[charId]:null;}/**
40
+ */
41
+ export function getSelectedValue(charId, characteristics) {
42
+ return characteristics[charId] ? characteristics[charId] : null;
43
+ }
44
+
45
+ /**
17
46
  * Prepares the new state after a selection has been made.
18
47
  * @param {string} id The selection ID
19
48
  * @param {string} value The selection value.
@@ -21,28 +50,113 @@ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj
21
50
  * @param {Array} characteristics The characteristics of a product.
22
51
  * @param {Array} products All available products.
23
52
  * @return {Object}
24
- */export function prepareState(id,value,selections,characteristics,products){var updateValid=!!characteristics.find(function(_ref){var cId=_ref.id,values=_ref.values;if(cId!==id){return false;}return!!values.find(function(_ref2){var vId=_ref2.id;return vId===value;});});if(!updateValid){// Input parameters are invalid.
25
- return selections;}// Merge the just changed value into the previous selection.
26
- var currentSelection=_extends({},selections,_defineProperty({},id,value));/**
53
+ */
54
+ export function prepareState(id, value, selections, characteristics, products) {
55
+ const updateValid = !!characteristics.find(({
56
+ id: cId,
57
+ values
58
+ }) => {
59
+ if (cId !== id) {
60
+ return false;
61
+ }
62
+ return !!values.find(({
63
+ id: vId
64
+ }) => vId === value);
65
+ });
66
+ if (!updateValid) {
67
+ // Input parameters are invalid.
68
+ return selections;
69
+ }
70
+
71
+ // Merge the just changed value into the previous selection.
72
+ const currentSelection = {
73
+ ...selections,
74
+ [id]: value
75
+ };
76
+
77
+ /**
27
78
  * Determine if there are products for the current user selection.
28
- */var matches=products.filter(function(product){return isMatch(product.characteristics,currentSelection);});if(matches.length===1){// Product found for the current selection.
29
- return _extends({},matches[0].characteristics);}if(!selections[id]){// Changed value wasn't set before.
30
- return currentSelection;}// Find the current index.
31
- var index=findSelectionIndex(characteristics,id);/**
79
+ */
80
+ const matches = products.filter(product => isMatch(product.characteristics, currentSelection));
81
+ if (matches.length === 1) {
82
+ // Product found for the current selection.
83
+ return {
84
+ ...matches[0].characteristics
85
+ };
86
+ }
87
+ if (!selections[id]) {
88
+ // Changed value wasn't set before.
89
+ return currentSelection;
90
+ }
91
+
92
+ // Find the current index.
93
+ const index = findSelectionIndex(characteristics, id);
94
+
95
+ /**
32
96
  * When the given index is the same as the complete set
33
97
  * of characteristics then there is nothing to reset.
34
- */if(index===characteristics.length-1){return currentSelection;}// Find the selections after the given index.
35
- var after=characteristics.slice(index+1);// Delete the found selections.
36
- after.forEach(function(item){delete currentSelection[item.id];});return currentSelection;}/**
98
+ */
99
+ if (index === characteristics.length - 1) {
100
+ return currentSelection;
101
+ }
102
+
103
+ // Find the selections after the given index.
104
+ const after = characteristics.slice(index + 1);
105
+
106
+ // Delete the found selections.
107
+ after.forEach(item => {
108
+ delete currentSelection[item.id];
109
+ });
110
+ return currentSelection;
111
+ }
112
+ /**
37
113
  * Preselect characteristics for variant
38
114
  * or pre-select the first available product
39
115
  * @param {string} [variantId=null] The selected variant
40
116
  * @param {{products: Object[], characteristics: Object[]}} [variants=null] All possible variants.
41
117
  * @return {Object}
42
- */export function selectCharacteristics(_ref3){var variantId=_ref3.variantId,_ref3$variants=_ref3.variants,variants=_ref3$variants===void 0?{}:_ref3$variants;if(!variants||!variants.products||!variants.products.length){return{};}if(variantId){var variant=variants.products.find(function(product){return product.id===variantId;})||{};return _extends({},variant.characteristics);}// If product has only 1 variant preselect no matter if "preselect" is chosen or not.
43
- if(variants.products.length===1){return _extends({},variants.products[0].characteristics);}// Pre-selection is off
44
- if(!preselectVariant){return{};}// Find the first selectable product by characteristics
45
- return variants.characteristics.reduce(function(acc,_char2){// Find the first char value with selectable products
46
- var firstVal=_char2.values.find(function(val){// eslint-disable-next-line extra-rules/no-single-line-objects
47
- var source=_extends({},acc,_defineProperty({},_char2.id,val.id));return variants.products.filter(function(p){return isMatch(p.characteristics,source);}).length>0;});if(!firstVal){return acc;}// eslint-disable-next-line extra-rules/no-single-line-objects
48
- return _extends({},acc,_defineProperty({},_char2.id,firstVal.id));},{});}
118
+ */
119
+ export function selectCharacteristics({
120
+ variantId,
121
+ variants = {}
122
+ }) {
123
+ if (!variants || !variants.products || !variants.products.length) {
124
+ return {};
125
+ }
126
+ if (variantId) {
127
+ const variant = variants.products.find(product => product.id === variantId) || {};
128
+ return {
129
+ ...variant.characteristics
130
+ };
131
+ }
132
+ // If product has only 1 variant preselect no matter if "preselect" is chosen or not.
133
+ if (variants.products.length === 1) {
134
+ return {
135
+ ...variants.products[0].characteristics
136
+ };
137
+ }
138
+ // Pre-selection is off
139
+ if (!preselectVariant) {
140
+ return {};
141
+ }
142
+ // Find the first selectable product by characteristics
143
+ return variants.characteristics.reduce((acc, char) => {
144
+ // Find the first char value with selectable products
145
+ const firstVal = char.values.find(val => {
146
+ // eslint-disable-next-line extra-rules/no-single-line-objects
147
+ const source = {
148
+ ...acc,
149
+ [char.id]: val.id
150
+ };
151
+ return variants.products.filter(p => isMatch(p.characteristics, source)).length > 0;
152
+ });
153
+ if (!firstVal) {
154
+ return acc;
155
+ }
156
+ // eslint-disable-next-line extra-rules/no-single-line-objects
157
+ return {
158
+ ...acc,
159
+ [char.id]: firstVal.id
160
+ };
161
+ }, {});
162
+ }
@@ -1,38 +1,273 @@
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 _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 _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor;}function _callSuper(_this,derived,args){function isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{return!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}));}catch(e){return false;}}derived=_getPrototypeOf(derived);return _possibleConstructorReturn(_this,isNativeReflectConstruct()?Reflect.construct(derived,args||[],_getPrototypeOf(_this).constructor):derived.apply(_this,args));}function _possibleConstructorReturn(self,call){if(call&&(_typeof(call)==="object"||typeof call==="function")){return call;}return _assertThisInitialized(self);}function _assertThisInitialized(self){if(self===void 0){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return self;}function _getPrototypeOf(o){_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf:function _getPrototypeOf(o){return o.__proto__||Object.getPrototypeOf(o);};return _getPrototypeOf(o);}function _inherits(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function");}subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:true,configurable:true}});if(superClass)_setPrototypeOf(subClass,superClass);}function _setPrototypeOf(o,p){_setPrototypeOf=Object.setPrototypeOf||function _setPrototypeOf(o,p){o.__proto__=p;return o;};return _setPrototypeOf(o,p);}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React,{Component}from'react';import PropTypes from'prop-types';import isMatch from'lodash/isMatch';import{broadcastLiveMessage}from'@shopgate/engage/a11y';import{responsiveCondition}from'@shopgate/engage/styles';import connect from"./connector";import VariantsContext from"./context";import{isCharacteristicEnabled,getSelectedValue,prepareState,selectCharacteristics}from"./helpers";/**
1
+ import React, { Component } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import isMatch from 'lodash/isMatch';
4
+ import { broadcastLiveMessage } from '@shopgate/engage/a11y';
5
+ import { responsiveCondition } from '@shopgate/engage/styles';
6
+ import connect from "./connector";
7
+ import VariantsContext from "./context";
8
+ import { isCharacteristicEnabled, getSelectedValue, prepareState, selectCharacteristics } from "./helpers";
9
+
10
+ /**
2
11
  * The ProductCharacteristics component.
3
12
  * @deprecated Please use the component via
4
13
  * `import { ProductCharacteristics } from '@shopgate/engage/product'`
5
- */var ProductCharacteristics=/*#__PURE__*/function(_Component){function ProductCharacteristics(_props){var _this2;_classCallCheck(this,ProductCharacteristics);_this2=_callSuper(this,ProductCharacteristics,[_props]);/**
6
- * Sets the refs to the characteristics selects.
7
- * @param {Object} props The props to check against.
8
- */_defineProperty(_this2,"setRefs",function(props){var variants=props.variants;if(variants){variants.characteristics.forEach(function(_char){_this2.refsStore[_char.id]=React.createRef();});}});/**
9
- * Checks if all selections have been made.
10
- * @return {boolean}
11
- */_defineProperty(_this2,"checkSelection",function(){var characteristics=_this2.state.characteristics;var _this2$props=_this2.props,variants=_this2$props.variants,variantId=_this2$props.variantId;if(!variants){return true;}var filteredValues=Object.keys(characteristics).filter(function(key){return!!characteristics[key];});var selected=!!(filteredValues.length===variants.characteristics.length&&variantId);if(!selected){var firstUnselected=_this2.findUnselectedCharacteristic();if(firstUnselected){var ref=_this2.refsStore[firstUnselected.id];// Focus the item for screen readers and broadcast a related live message.
12
- ref.current.focus();var option=ref.current.innerText;broadcastLiveMessage('product.pick_option_first',{params:{option:option}});if(responsiveCondition('>xs',{webOnly:true})){ref.current.scrollIntoView({behavior:'smooth',block:'center'});}else{ref.current.scrollIntoView({behavior:'smooth'});}_this2.setState({highlight:firstUnselected.id});}}return selected;});_defineProperty(_this2,"checkSelectedCharacteristics",function(){var characteristics=_this2.state.characteristics;var _this2$props2=_this2.props,variantId=_this2$props2.variantId,variants=_this2$props2.variants,finishTimeout=_this2$props2.finishTimeout;if(!variants){return;}var filteredValues=Object.keys(characteristics).filter(function(key){return!!characteristics[key];});if(filteredValues.length!==variants.characteristics.length){return;}var products=variants.products.filter(function(product){return isMatch(product.characteristics,characteristics);});if(!products.length){return;}if(products[0].id===variantId){return;}setTimeout(function(){_this2.props.navigate(products[0].id);},finishTimeout);});/**
13
- * Stores a selected characteristic into the local state.
14
- * @param {Object} selection The selected item.
15
- */_defineProperty(_this2,"handleSelection",function(selection){var _this2$props3=_this2.props,variants=_this2$props3.variants,setCharacteristics=_this2$props3.setCharacteristics;var id=selection.id,value=selection.value;_this2.setState(function(_ref){var characteristics=_ref.characteristics;var state=prepareState(id,value,characteristics,variants.characteristics,variants.products);setCharacteristics(state);return{characteristics:_extends({},state),highlight:null};},_this2.checkSelectedCharacteristics);});/**
16
- * @param {Object} selections The selections stored in the state.
17
- * @param {string} charId The current characteristic ID.
18
- * @param {Array} values The characteristic values.
19
- * @param {number} charIndex The characteristic index.
20
- * @param {string|null} selectedValue selectedValue
21
- * @return {Array}
22
- */_defineProperty(_this2,"buildValues",function(selections,charId,values,charIndex,selectedValue){// If this is the first characteristic then all values are selectable.
23
- if(charIndex===0){return values.map(function(value){return _extends({},value,{selectable:true,selected:selectedValue===value.id});});}var variants=_this2.props.variants;var subset={};Object.keys(selections).forEach(function(item,index){if(index<charIndex){subset[item]=selections[item];}});// Filter products that match or partially match the current characteristic selection.
24
- var products=variants.products.filter(function(_ref2){var characteristics=_ref2.characteristics;return isMatch(characteristics,subset);});// Check if any of the values are present inside any of the matching products.
25
- return values.map(function(value){var selectable=products.some(function(_ref3){var characteristics=_ref3.characteristics;return isMatch(characteristics,_defineProperty({},charId,value.id));});return _extends({},value,{selectable:selectable,selected:selectedValue===value.id});});});/**
26
- * Resets the highlight state
27
- */_defineProperty(_this2,"resetHighlight",function(){_this2.setState({highlight:null});});_this2.refsStore={};_this2.state={highlight:null,characteristics:selectCharacteristics(_props)};_this2.setRefs(_props);_props.conditioner.addConditioner('product-variants',_this2.checkSelection);return _this2;}/** @inheritDoc */_inherits(ProductCharacteristics,_Component);return _createClass(ProductCharacteristics,[{key:"componentDidMount",value:function componentDidMount(){this.checkSelectedCharacteristics();}/**
14
+ */
15
+ class ProductCharacteristics extends Component {
16
+ /**
17
+ * @param {Object} props The component props.
18
+ */
19
+ constructor(_props) {
20
+ super(_props);
21
+ /**
22
+ * Sets the refs to the characteristics selects.
23
+ * @param {Object} props The props to check against.
24
+ */
25
+ this.setRefs = props => {
26
+ const {
27
+ variants
28
+ } = props;
29
+ if (variants) {
30
+ variants.characteristics.forEach(char => {
31
+ this.refsStore[char.id] = /*#__PURE__*/React.createRef();
32
+ });
33
+ }
34
+ };
35
+ /**
36
+ * Checks if all selections have been made.
37
+ * @return {boolean}
38
+ */
39
+ this.checkSelection = () => {
40
+ const {
41
+ characteristics
42
+ } = this.state;
43
+ const {
44
+ variants,
45
+ variantId
46
+ } = this.props;
47
+ if (!variants) {
48
+ return true;
49
+ }
50
+ const filteredValues = Object.keys(characteristics).filter(key => !!characteristics[key]);
51
+ const selected = !!(filteredValues.length === variants.characteristics.length && variantId);
52
+ if (!selected) {
53
+ const firstUnselected = this.findUnselectedCharacteristic();
54
+ if (firstUnselected) {
55
+ const ref = this.refsStore[firstUnselected.id];
56
+
57
+ // Focus the item for screen readers and broadcast a related live message.
58
+ ref.current.focus();
59
+ const option = ref.current.innerText;
60
+ broadcastLiveMessage('product.pick_option_first', {
61
+ params: {
62
+ option
63
+ }
64
+ });
65
+ if (responsiveCondition('>xs', {
66
+ webOnly: true
67
+ })) {
68
+ ref.current.scrollIntoView({
69
+ behavior: 'smooth',
70
+ block: 'center'
71
+ });
72
+ } else {
73
+ ref.current.scrollIntoView({
74
+ behavior: 'smooth'
75
+ });
76
+ }
77
+ this.setState({
78
+ highlight: firstUnselected.id
79
+ });
80
+ }
81
+ }
82
+ return selected;
83
+ };
84
+ this.checkSelectedCharacteristics = () => {
85
+ const {
86
+ characteristics
87
+ } = this.state;
88
+ const {
89
+ variantId,
90
+ variants,
91
+ finishTimeout
92
+ } = this.props;
93
+ if (!variants) {
94
+ return;
95
+ }
96
+ const filteredValues = Object.keys(characteristics).filter(key => !!characteristics[key]);
97
+ if (filteredValues.length !== variants.characteristics.length) {
98
+ return;
99
+ }
100
+ const products = variants.products.filter(product => isMatch(product.characteristics, characteristics));
101
+ if (!products.length) {
102
+ return;
103
+ }
104
+ if (products[0].id === variantId) {
105
+ return;
106
+ }
107
+ setTimeout(() => {
108
+ this.props.navigate(products[0].id);
109
+ }, finishTimeout);
110
+ };
111
+ /**
112
+ * Stores a selected characteristic into the local state.
113
+ * @param {Object} selection The selected item.
114
+ */
115
+ this.handleSelection = selection => {
116
+ const {
117
+ variants,
118
+ setCharacteristics
119
+ } = this.props;
120
+ const {
121
+ id,
122
+ value
123
+ } = selection;
124
+ this.setState(({
125
+ characteristics
126
+ }) => {
127
+ const state = prepareState(id, value, characteristics, variants.characteristics, variants.products);
128
+ setCharacteristics(state);
129
+ return {
130
+ characteristics: {
131
+ ...state
132
+ },
133
+ highlight: null
134
+ };
135
+ }, this.checkSelectedCharacteristics);
136
+ };
137
+ /**
138
+ * @param {Object} selections The selections stored in the state.
139
+ * @param {string} charId The current characteristic ID.
140
+ * @param {Array} values The characteristic values.
141
+ * @param {number} charIndex The characteristic index.
142
+ * @param {string|null} selectedValue selectedValue
143
+ * @return {Array}
144
+ */
145
+ this.buildValues = (selections, charId, values, charIndex, selectedValue) => {
146
+ // If this is the first characteristic then all values are selectable.
147
+ if (charIndex === 0) {
148
+ return values.map(value => ({
149
+ ...value,
150
+ selectable: true,
151
+ selected: selectedValue === value.id
152
+ }));
153
+ }
154
+ const {
155
+ variants
156
+ } = this.props;
157
+ const subset = {};
158
+ Object.keys(selections).forEach((item, index) => {
159
+ if (index < charIndex) {
160
+ subset[item] = selections[item];
161
+ }
162
+ });
163
+
164
+ // Filter products that match or partially match the current characteristic selection.
165
+ const products = variants.products.filter(({
166
+ characteristics
167
+ }) => isMatch(characteristics, subset));
168
+
169
+ // Check if any of the values are present inside any of the matching products.
170
+ return values.map(value => {
171
+ const selectable = products.some(({
172
+ characteristics
173
+ }) => isMatch(characteristics, {
174
+ [charId]: value.id
175
+ }));
176
+ return {
177
+ ...value,
178
+ selectable,
179
+ selected: selectedValue === value.id
180
+ };
181
+ });
182
+ };
183
+ /**
184
+ * Resets the highlight state
185
+ */
186
+ this.resetHighlight = () => {
187
+ this.setState({
188
+ highlight: null
189
+ });
190
+ };
191
+ this.refsStore = {};
192
+ this.state = {
193
+ highlight: null,
194
+ characteristics: selectCharacteristics(_props)
195
+ };
196
+ this.setRefs(_props);
197
+ _props.conditioner.addConditioner('product-variants', this.checkSelection);
198
+ }
199
+
200
+ /** @inheritDoc */
201
+ componentDidMount() {
202
+ this.checkSelectedCharacteristics();
203
+ }
204
+
205
+ /**
28
206
  * @param {Object} nextProps The next component props.
29
- */},{key:"UNSAFE_componentWillReceiveProps",value:function UNSAFE_componentWillReceiveProps(nextProps){if(!this.props.variants&&nextProps.variants){// Initialize refs and characteristics when the variants prop was updated with a valid value.
30
- this.setRefs(nextProps);this.setState({characteristics:selectCharacteristics(nextProps)},this.checkSelectedCharacteristics);}}},{key:"findUnselectedCharacteristic",value:/**
207
+ */
208
+ UNSAFE_componentWillReceiveProps(nextProps) {
209
+ if (!this.props.variants && nextProps.variants) {
210
+ // Initialize refs and characteristics when the variants prop was updated with a valid value.
211
+ this.setRefs(nextProps);
212
+ this.setState({
213
+ characteristics: selectCharacteristics(nextProps)
214
+ }, this.checkSelectedCharacteristics);
215
+ }
216
+ }
217
+ /**
31
218
  * Finds the first unselected characteristic.
32
219
  * @return {Object|null}
33
- */function findUnselectedCharacteristic(){var characteristics=this.state.characteristics;var unselected=this.props.variants.characteristics.filter(function(_char2){return!characteristics.hasOwnProperty(_char2.id);});if(unselected.length){return unselected[0];}return null;}/**
220
+ */
221
+ findUnselectedCharacteristic() {
222
+ const {
223
+ characteristics
224
+ } = this.state;
225
+ const unselected = this.props.variants.characteristics.filter(char => !characteristics.hasOwnProperty(char.id));
226
+ if (unselected.length) {
227
+ return unselected[0];
228
+ }
229
+ return null;
230
+ }
231
+
232
+ /**
34
233
  * @return {JSX}
35
- */},{key:"render",value:function render(){var _this3=this;var characteristics=this.state.characteristics;var variants=this.props.variants;if(!variants){return null;}return React.createElement(VariantsContext.Provider,{value:this.state},variants.characteristics.map(function(_char3,index){var disabled=!isCharacteristicEnabled(characteristics,index);var selected=getSelectedValue(_char3.id,characteristics);var values=_this3.buildValues(characteristics,_char3.id,_char3.values,index,selected);return _this3.props.render({charRef:_this3.refsStore[_char3.id],disabled:disabled,highlight:_this3.state.highlight===_char3.id,id:_char3.id,key:_char3.id,label:_char3.label,swatch:!!_char3.swatch,// BETA
36
- select:_this3.handleSelection,selected:selected,values:values,resetHighlight:_this3.resetHighlight});}));}}]);}(Component);_defineProperty(ProductCharacteristics,"defaultProps",{finishTimeout:0,variantId:null,variants:null/**
37
- * @param {Object} props The component props.
38
- */});export default connect(ProductCharacteristics);
234
+ */
235
+ render() {
236
+ const {
237
+ characteristics
238
+ } = this.state;
239
+ const {
240
+ variants
241
+ } = this.props;
242
+ if (!variants) {
243
+ return null;
244
+ }
245
+ return /*#__PURE__*/React.createElement(VariantsContext.Provider, {
246
+ value: this.state
247
+ }, variants.characteristics.map((char, index) => {
248
+ const disabled = !isCharacteristicEnabled(characteristics, index);
249
+ const selected = getSelectedValue(char.id, characteristics);
250
+ const values = this.buildValues(characteristics, char.id, char.values, index, selected);
251
+ return this.props.render({
252
+ charRef: this.refsStore[char.id],
253
+ disabled,
254
+ highlight: this.state.highlight === char.id,
255
+ id: char.id,
256
+ key: char.id,
257
+ label: char.label,
258
+ swatch: !!char.swatch,
259
+ // BETA
260
+ select: this.handleSelection,
261
+ selected,
262
+ values,
263
+ resetHighlight: this.resetHighlight
264
+ });
265
+ }));
266
+ }
267
+ }
268
+ ProductCharacteristics.defaultProps = {
269
+ finishTimeout: 0,
270
+ variantId: null,
271
+ variants: null
272
+ };
273
+ export default connect(ProductCharacteristics);
@@ -1,4 +1,8 @@
1
- import React from'react';import PropTypes from'prop-types';import styles from"./style";/**
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styles from "./style";
4
+
5
+ /**
2
6
  * The range slider handle component.
3
7
  * @param {Object} props The component properties
4
8
  * @param {boolean} props.active Whether this handle is currently touched or was recently touched.
@@ -6,4 +10,23 @@ import React from'react';import PropTypes from'prop-types';import styles from"./
6
10
  * @param {Function} props.onTouchStart The touch start event callback.
7
11
  * @param {Object} props.classNames (Optional) An additional style classes for the handle.
8
12
  * @returns {JSX}
9
- */var RangeSliderHandle=function RangeSliderHandle(_ref){var active=_ref.active,index=_ref.index,_onTouchStart=_ref.onTouchStart,classNames=_ref.classNames;return React.createElement("div",{className:"".concat(classNames.handleOuter||''," ").concat(styles),style:{zIndex:Number(active)||0},onTouchStart:function onTouchStart(event){return _onTouchStart(event,index);}},React.createElement("div",{className:classNames.handleInner||''}));};RangeSliderHandle.defaultProps={active:false,classNames:{}};export default RangeSliderHandle;
13
+ */
14
+ const RangeSliderHandle = ({
15
+ active,
16
+ index,
17
+ onTouchStart,
18
+ classNames
19
+ }) => /*#__PURE__*/React.createElement("div", {
20
+ className: `${classNames.handleOuter || ''} ${styles}`,
21
+ style: {
22
+ zIndex: Number(active) || 0
23
+ },
24
+ onTouchStart: event => onTouchStart(event, index)
25
+ }, /*#__PURE__*/React.createElement("div", {
26
+ className: classNames.handleInner || ''
27
+ }));
28
+ RangeSliderHandle.defaultProps = {
29
+ active: false,
30
+ classNames: {}
31
+ };
32
+ export default RangeSliderHandle;
@@ -1 +1,14 @@
1
- import{css}from'glamor';export default css({top:'50%',position:'absolute',':first-child':{left:0,transform:'translate(-50%, -50%)'},':last-child':{left:'auto',right:0,transform:'translate(50%, -50%)'}});
1
+ import { css } from 'glamor';
2
+ export default css({
3
+ top: '50%',
4
+ position: 'absolute',
5
+ ':first-child': {
6
+ left: 0,
7
+ transform: 'translate(-50%, -50%)'
8
+ },
9
+ ':last-child': {
10
+ left: 'auto',
11
+ right: 0,
12
+ transform: 'translate(50%, -50%)'
13
+ }
14
+ });