vviinn-widgets 2.0.0 → 2.2.1

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 (106) hide show
  1. package/dist/cjs/Handler-d1a8a86a.js +329 -0
  2. package/dist/cjs/{app-globals-de6924b5.js → app-globals-d0251be8.js} +1 -1
  3. package/dist/cjs/cropper-handler.cjs.entry.js +27 -0
  4. package/dist/cjs/customized-slots-14b77e4a.js +53 -0
  5. package/dist/cjs/{cropper-handler_28.cjs.entry.js → highlight-box_22.cjs.entry.js} +48 -437
  6. package/dist/{esm/Array-e81cf4a3.js → cjs/imageSearch.store-d9ed1a5b.js} +10009 -3391
  7. package/dist/cjs/{index-7adce49f.js → index-141137b2.js} +14 -362
  8. package/dist/cjs/{index-8a276115.js → index-a5e15a0c.js} +7 -1
  9. package/dist/cjs/loader.cjs.js +3 -3
  10. package/dist/cjs/vviinn-carousel_5.cjs.entry.js +1232 -0
  11. package/dist/cjs/vviinn-error.cjs.entry.js +19 -0
  12. package/dist/cjs/vviinn-preloader.cjs.entry.js +26 -0
  13. package/dist/cjs/vviinn-vps-button.cjs.entry.js +43 -0
  14. package/dist/cjs/vviinn-vps-widget.cjs.entry.js +97 -0
  15. package/dist/cjs/vviinn-widgets.cjs.js +3 -3
  16. package/dist/collection/collection-manifest.json +2 -0
  17. package/dist/collection/components/vviinn-carousel/vviinn-carousel.css +22 -18
  18. package/dist/collection/components/vviinn-carousel/vviinn-carousel.js +78 -68
  19. package/dist/collection/components/vviinn-icons/index.js +4 -0
  20. package/dist/collection/components/vviinn-product-card/render-helpers.js +4 -4
  21. package/dist/collection/components/vviinn-product-card/vviinn-product-card.css +5 -6
  22. package/dist/collection/components/vviinn-product-card/vviinn-product-card.js +26 -5
  23. package/dist/collection/components/vviinn-vpr-button/recommendations-sidebar/recommendations-sidebar.css +238 -0
  24. package/dist/collection/components/vviinn-vpr-button/recommendations-sidebar/recommendations-sidebar.js +200 -0
  25. package/dist/collection/components/vviinn-vpr-button/stories/kek.stories.js +18 -0
  26. package/dist/collection/components/vviinn-vpr-button/vviinn-vpr-button.css +35 -0
  27. package/dist/collection/components/vviinn-vpr-button/vviinn-vpr-button.js +149 -0
  28. package/dist/collection/components/vviinn-vpr-widget/vviinn-vpr-vidget.js +148 -28
  29. package/dist/collection/components/vviinn-vpr-widget/vviinn-vpr-widget.css +31 -8
  30. package/dist/esm/Handler-639a4cb3.js +308 -0
  31. package/dist/esm/{app-globals-0a626970.js → app-globals-b6113170.js} +1 -1
  32. package/dist/esm/cropper-handler.entry.js +23 -0
  33. package/dist/esm/customized-slots-a952fb80.js +50 -0
  34. package/dist/esm/{cropper-handler_28.entry.js → highlight-box_22.entry.js} +21 -404
  35. package/dist/{cjs/Array-cce2fde8.js → esm/imageSearch.store-4ca31230.js} +8705 -2137
  36. package/dist/esm/{index-e77e65ae.js → index-017f18de.js} +6 -2
  37. package/dist/esm/{index-0ccfcee5.js → index-3e85e294.js} +14 -362
  38. package/dist/esm/loader.js +3 -3
  39. package/dist/esm/vviinn-carousel_5.entry.js +1224 -0
  40. package/dist/esm/vviinn-error.entry.js +15 -0
  41. package/dist/esm/vviinn-preloader.entry.js +22 -0
  42. package/dist/esm/vviinn-vps-button.entry.js +39 -0
  43. package/dist/esm/vviinn-vps-widget.entry.js +93 -0
  44. package/dist/esm/vviinn-widgets.js +3 -3
  45. package/dist/types/campaign/Campaign.d.ts +1 -1
  46. package/dist/types/components/vviinn-carousel/vviinn-carousel.d.ts +13 -7
  47. package/dist/types/components/vviinn-icons/index.d.ts +2 -0
  48. package/dist/types/components/vviinn-product-card/render-helpers.d.ts +3 -2
  49. package/dist/types/components/vviinn-product-card/vviinn-product-card.d.ts +2 -0
  50. package/dist/types/components/vviinn-vpr-button/recommendations-sidebar/recommendations-sidebar.d.ts +25 -0
  51. package/dist/types/components/vviinn-vpr-button/stories/kek.stories.d.ts +7 -0
  52. package/dist/types/components/vviinn-vpr-button/vviinn-vpr-button.d.ts +14 -0
  53. package/dist/types/components/vviinn-vpr-widget/vviinn-vpr-vidget.d.ts +36 -8
  54. package/dist/types/components.d.ts +62 -10
  55. package/dist/vviinn-widgets/p-0ed1ef7e.entry.js +1 -0
  56. package/dist/vviinn-widgets/{p-6c4fd1db.js → p-16e49514.js} +1 -1
  57. package/dist/vviinn-widgets/p-3da18d7f.js +1 -0
  58. package/dist/vviinn-widgets/p-62a1b042.entry.js +1 -0
  59. package/dist/vviinn-widgets/p-68900093.entry.js +1 -0
  60. package/dist/vviinn-widgets/p-6c4c240d.entry.js +1 -0
  61. package/dist/vviinn-widgets/p-95e53d99.entry.js +1 -0
  62. package/dist/vviinn-widgets/p-9fee20e7.entry.js +1 -0
  63. package/dist/vviinn-widgets/p-d7894eaf.js +1 -0
  64. package/dist/vviinn-widgets/p-db0be4cd.js +1 -0
  65. package/dist/vviinn-widgets/p-eb15116d.entry.js +1 -0
  66. package/dist/vviinn-widgets/{p-489aee23.js → p-f00fddbb.js} +1 -1
  67. package/dist/vviinn-widgets/p-f582db5c.js +1 -0
  68. package/dist/vviinn-widgets/vviinn-widgets.esm.js +1 -1
  69. package/package.json +3 -1
  70. package/www/build/p-0ed1ef7e.entry.js +1 -0
  71. package/www/build/{p-6c4fd1db.js → p-16e49514.js} +1 -1
  72. package/www/build/p-1cc0cdfd.js +1 -0
  73. package/www/build/p-3da18d7f.js +1 -0
  74. package/www/build/p-62a1b042.entry.js +1 -0
  75. package/www/build/p-68900093.entry.js +1 -0
  76. package/www/build/p-6c4c240d.entry.js +1 -0
  77. package/www/build/p-95e53d99.entry.js +1 -0
  78. package/www/build/p-9fee20e7.entry.js +1 -0
  79. package/www/build/p-a67898be.css +1 -0
  80. package/www/build/p-d7894eaf.js +1 -0
  81. package/www/build/p-db0be4cd.js +1 -0
  82. package/www/build/p-eb15116d.entry.js +1 -0
  83. package/www/build/{p-489aee23.js → p-f00fddbb.js} +1 -1
  84. package/www/build/p-f582db5c.js +1 -0
  85. package/www/build/vviinn-widgets.esm.js +1 -1
  86. package/www/index.html +177 -8
  87. package/dist/cjs/imageSearch.store-39fce56c.js +0 -6926
  88. package/dist/cjs/vviinn-carousel.cjs.entry.js +0 -222
  89. package/dist/cjs/vviinn-vpr-widget.cjs.entry.js +0 -106
  90. package/dist/esm/imageSearch.store-b887ff78.js +0 -6893
  91. package/dist/esm/vviinn-carousel.entry.js +0 -218
  92. package/dist/esm/vviinn-vpr-widget.entry.js +0 -102
  93. package/dist/vviinn-widgets/p-2bf74c28.js +0 -1
  94. package/dist/vviinn-widgets/p-3063e23a.js +0 -1
  95. package/dist/vviinn-widgets/p-9145c82e.entry.js +0 -1
  96. package/dist/vviinn-widgets/p-ddcac3f8.js +0 -1
  97. package/dist/vviinn-widgets/p-f05da9f1.entry.js +0 -1
  98. package/dist/vviinn-widgets/p-f12f823d.entry.js +0 -1
  99. package/www/build/p-2bf74c28.js +0 -1
  100. package/www/build/p-3063e23a.js +0 -1
  101. package/www/build/p-9145c82e.entry.js +0 -1
  102. package/www/build/p-cbae3071.js +0 -125
  103. package/www/build/p-ddcac3f8.js +0 -1
  104. package/www/build/p-e0153ae2.css +0 -6
  105. package/www/build/p-f05da9f1.entry.js +0 -1
  106. package/www/build/p-f12f823d.entry.js +0 -1
@@ -0,0 +1,1232 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const index = require('./index-141137b2.js');
6
+ const imageSearch_store = require('./imageSearch.store-d9ed1a5b.js');
7
+ const index$1 = require('./index-a5e15a0c.js');
8
+ const Handler = require('./Handler-d1a8a86a.js');
9
+
10
+ const vviinnCarouselCss = ":host{--vviinn-progressbar-width:0;--vviinn-carousel-item-width:150px;--vviinn-carousel-columns-internal:var(--vviinn-carousel-columns, 4);--vviinn-carousel-image-width-system:140px}.body{display:flex;position:relative;width:var(--vviinn-carousel-content-width);flex-direction:column}.content-wrapper *{box-sizing:border-box}.content-wrapper{overflow-y:hidden;overflow-x:auto;flex-grow:1}.bullets{margin-top:16px;display:flex;flex-direction:row;grid-gap:24px;justify-content:center}.bullet{width:10px;height:10px;background:#E0E0E0;border-radius:50%;cursor:pointer}.bullet.active{background:#161616}.content:not(.show-scrollbar),.content.grid{scrollbar-color:#fff0 #fff0}.content:not(.show-scrollbar)::-webkit-scrollbar,.content.grid::-webkit-scrollbar{opacity:0}.content{display:flex;flex-direction:row;grid-gap:8px;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;overflow-y:hidden;overflow-x:auto;flex-grow:1;padding-bottom:16px}.content.left>*{scroll-snap-align:start}.content.right>*{scroll-snap-align:end}:host(.continuity) button{border-radius:2px}:host(.grid) button{border-radius:50%}button{align-items:center;background-color:white;border:none;box-shadow:0px 2px 6px rgba(0, 0, 0, 0.15);cursor:pointer;display:grid;height:40px;justify-items:center;position:absolute;top:calc(50% - 20px);width:40px;z-index:1;padding:0;margin:0}button.prev svg{transform:rotate(180deg);margin-left:-5px}.prev{left:0}.next{right:0}.items-group{display:grid;grid-gap:16px;grid-template-columns:repeat(var(--vviinn-carousel-columns-internal), 1fr);min-width:100%}vviinn-product-card::part(price-container){text-align:center}:host(.classic) vviinn-product-card::part(title),:host(.classic) vviinn-product-card::part(brand),:host(.classic) vviinn-product-card::part(type){text-align:center}@media (max-width: 480px){:host(.modern) button{display:none}.items-group{grid-template-columns:repeat(2, 1fr)}}";
11
+
12
+ const COLUMNS_NUMBER_CSS_VAR = "--vviinn-carousel-columns-internal";
13
+ const CAROUSEL_WIDTH_CSS_VAR = "--vviinn-carousel-content-width";
14
+ const CAROUSEL_IMAGE_WIDTH_CSS_VAR = "--vviinn-carousel-image-width";
15
+ const CONTENT_GROUP_CSS_CLASS = "items-group";
16
+ let VviinnCarousel = class {
17
+ constructor(hostRef) {
18
+ index.registerInstance(this, hostRef);
19
+ this.moveDirection = "right";
20
+ this.contentGroups = [];
21
+ this.activeContentGroup = 0;
22
+ this.mode = "continuity";
23
+ this.imageWidth = 140;
24
+ this.showScroll = true;
25
+ this.recommendations = [];
26
+ this.columns = 0;
27
+ this.resizeObserver = new ResizeObserver(() => this.handleResize());
28
+ this.mutationObserver = new MutationObserver(() => this.cloneSlottedContent());
29
+ }
30
+ connectedCallback() {
31
+ this.setItemWidth();
32
+ }
33
+ disconnectedCallback() {
34
+ this.resizeObserver.disconnect();
35
+ }
36
+ componentDidLoad() {
37
+ this.setWidth();
38
+ this.processScrollbarWidth();
39
+ this.columns = this.getColumnsNumber();
40
+ const slot = this.el.querySelector(".content");
41
+ this.mutationObserver.observe(slot, { subtree: true, childList: true });
42
+ this.resizeObserver.observe(this.getHostParent());
43
+ }
44
+ getItemWidthFromDocument() {
45
+ return parseInt(getComputedStyle(document.body).getPropertyValue(CAROUSEL_IMAGE_WIDTH_CSS_VAR));
46
+ }
47
+ setItemWidth() {
48
+ const widthInDocument = this.getItemWidthFromDocument();
49
+ const itemWidth = isNaN(widthInDocument)
50
+ ? this.imageWidth
51
+ : widthInDocument;
52
+ this.el.style.setProperty(CAROUSEL_IMAGE_WIDTH_CSS_VAR, `${itemWidth}px`);
53
+ }
54
+ getContentClassMap() {
55
+ return {
56
+ content: true,
57
+ [this.moveDirection]: true,
58
+ [this.mode]: true,
59
+ "show-scrollbar": this.showScroll
60
+ };
61
+ }
62
+ handleResize() {
63
+ this.setWidth();
64
+ this.processScrollbarWidth();
65
+ this.setItemWidth();
66
+ const newColumns = this.getColumnsNumber();
67
+ if (newColumns !== this.columns) {
68
+ this.columns = newColumns;
69
+ }
70
+ }
71
+ calculateMoveStep() {
72
+ const contentWidths = this.getContent().map((el) => el.getBoundingClientRect().width);
73
+ const sum = contentWidths.reduce((acc, val) => acc + val, 0);
74
+ return sum / contentWidths.length;
75
+ }
76
+ getHostParent() {
77
+ const parent = this.el.parentNode;
78
+ return parent.host.parentElement;
79
+ }
80
+ setWidth() {
81
+ const parent = this.getHostParent();
82
+ if (!parent)
83
+ return;
84
+ const parentStyles = getComputedStyle(parent);
85
+ const parentWidth = parent.getBoundingClientRect().width;
86
+ const width = parentWidth -
87
+ (parseInt(parentStyles["padding-right"]) +
88
+ parseInt(parentStyles["padding-left"]));
89
+ this.el.style.setProperty(CAROUSEL_WIDTH_CSS_VAR, `${width}px`);
90
+ }
91
+ getParent() {
92
+ const parentNode = this.el.parentNode;
93
+ const host = parentNode.host;
94
+ return host.parentElement;
95
+ }
96
+ cloneSlottedContent() {
97
+ this.setWidth();
98
+ }
99
+ getActiveGroupIndex() {
100
+ var _a, _b;
101
+ const contentNodeLeft = (_b = (_a = this.getContentNode()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) === null || _b === void 0 ? void 0 : _b.left;
102
+ if (!contentNodeLeft)
103
+ return 0;
104
+ const groups = this.getContentGroups();
105
+ const groupsPositions = groups.map((g) => g.getBoundingClientRect().left);
106
+ const indexedPositions = groupsPositions
107
+ .map((value, index) => [value, index])
108
+ .filter((x) => x[0] >= 0);
109
+ return indexedPositions.length > 0 ? indexedPositions[0][1] : 0;
110
+ }
111
+ getContentNode() {
112
+ return this.el.querySelector(".content");
113
+ }
114
+ getContent() {
115
+ const children = this.getContentNode().children;
116
+ return Array.from(children).map((c) => c);
117
+ }
118
+ getColumnsNumber() {
119
+ const styleSheet = getComputedStyle(this.el);
120
+ const columnsInCss = styleSheet.getPropertyValue(COLUMNS_NUMBER_CSS_VAR);
121
+ return parseInt(columnsInCss);
122
+ }
123
+ getContentGroups() {
124
+ return Array.from(this.el.querySelectorAll(`.${CONTENT_GROUP_CSS_CLASS}`));
125
+ }
126
+ showNext() {
127
+ this.moveDirection = "right";
128
+ const contentContainer = this.getContentNode();
129
+ requestAnimationFrame(() => {
130
+ contentContainer.scrollTo({
131
+ top: 0,
132
+ left: contentContainer.scrollLeft + this.calculateMoveStep(),
133
+ behavior: "smooth",
134
+ });
135
+ });
136
+ }
137
+ showPrev() {
138
+ this.moveDirection = "left";
139
+ const contentContainer = this.getContentNode();
140
+ requestAnimationFrame(() => {
141
+ contentContainer.scrollTo({
142
+ top: 0,
143
+ left: contentContainer.scrollLeft - this.calculateMoveStep(),
144
+ behavior: "smooth",
145
+ });
146
+ });
147
+ }
148
+ scroll(index) {
149
+ const contentContainer = this.getContentNode();
150
+ requestAnimationFrame(() => {
151
+ contentContainer.scrollTo({
152
+ top: 0,
153
+ left: this.calculateMoveStep() * index,
154
+ behavior: "smooth",
155
+ });
156
+ });
157
+ }
158
+ processScrollbarWidth() {
159
+ const target = this.getContentNode();
160
+ const scrollRatio = (target.scrollLeft + target.clientWidth) / target.scrollWidth;
161
+ const scrolledWidth = target.clientWidth * scrollRatio;
162
+ this.el.style.setProperty("--vviinn-progressbar-width", `${scrolledWidth}px`);
163
+ this.activeContentGroup = this.getActiveGroupIndex();
164
+ }
165
+ showBullets() {
166
+ return this.mode === "grid" && this.showScroll;
167
+ }
168
+ showScrollbar() {
169
+ return this.mode === "continuity" && this.showScroll;
170
+ }
171
+ getClassMap() {
172
+ return {
173
+ [this.mode]: true,
174
+ "show-scrollbar": this.showScrollbar(),
175
+ };
176
+ }
177
+ renderRecommendation(recommendation) {
178
+ return (index.h("vviinn-product-card", { part: "product-part", productId: recommendation.productId, productTitle: recommendation.title, deeplink: recommendation.deeplink, image: recommendation.image.thumbnail, brand: recommendation.brand, imageWidth: this.imageWidth, imageRatio: 1, price: recommendation.price.actual, salePrice: recommendation.price.sale, responsive: this.mode === "grid", dimmedBackground: this.mode === "continuity" }));
179
+ }
180
+ renderRecommendationGroup(elements) {
181
+ return index.h("div", { class: CONTENT_GROUP_CSS_CLASS }, elements);
182
+ }
183
+ renderRecommendationGroups(elements) {
184
+ return elements.map((el) => this.renderRecommendationGroup(el));
185
+ }
186
+ renderRecommendations() {
187
+ return this.mode === "grid"
188
+ ? this.renderGrid()
189
+ : this.renderRecommendationsElements();
190
+ }
191
+ renderRecommendationsElements() {
192
+ return this.recommendations.map((r) => this.renderRecommendation(r));
193
+ }
194
+ renderGrid() {
195
+ const recommendations = this.renderRecommendationsElements();
196
+ const grouppedContent = imageSearch_store._Array.chunksOf(this.getColumnsNumber())(recommendations);
197
+ return this.renderRecommendationGroups(grouppedContent);
198
+ }
199
+ renderBullets() {
200
+ const numberOfBullets = Math.ceil(this.recommendations.length / this.getColumnsNumber());
201
+ const bulletsArray = Array.from(Array(numberOfBullets).keys());
202
+ return bulletsArray.map((index$1) => (index.h("div", { class: {
203
+ bullet: true,
204
+ active: this.activeContentGroup === index$1,
205
+ }, onClick: () => this.scroll(index$1) })));
206
+ }
207
+ render() {
208
+ return (index.h(index.Host, { class: this.getClassMap() }, index.h("div", { class: Object.assign({ body: true }, this.getClassMap()) }, index.h("button", { class: "prev", onClick: () => this.showPrev() }, index.h(index$1.ChevronIcon, null)), index.h("div", { class: this.getContentClassMap(), onScroll: () => this.processScrollbarWidth() }, this.renderRecommendations()), index.h("button", { class: "next", onClick: () => this.showNext() }, index.h(index$1.ChevronIcon, null))), this.showBullets() ? (index.h("div", { class: "bullets" }, this.renderBullets())) : ("")));
209
+ }
210
+ get el() { return index.getElement(this); }
211
+ };
212
+ VviinnCarousel.style = vviinnCarouselCss;
213
+
214
+ class GtagAnalytics {
215
+ sendImpression(product) {
216
+ var _a, _b, _c;
217
+ gtag('event', 'view_item_list', {
218
+ items: [
219
+ {
220
+ id: product.productId,
221
+ name: product.title,
222
+ brand: (_a = product.brand) !== null && _a !== void 0 ? _a : '',
223
+ category: (_b = product.productType) !== null && _b !== void 0 ? _b : '',
224
+ list_name: 'VI VPR View',
225
+ price: Math.min(...[product.price.actual, (_c = product.price.sale) !== null && _c !== void 0 ? _c : Infinity])
226
+ }
227
+ ]
228
+ });
229
+ return undefined;
230
+ }
231
+ sendClick(product) {
232
+ var _a, _b, _c;
233
+ gtag('event', 'select_content', {
234
+ content_type: 'product',
235
+ items: [
236
+ {
237
+ id: product.productId,
238
+ name: product.title,
239
+ brand: (_a = product.brand) !== null && _a !== void 0 ? _a : '',
240
+ category: (_b = product.productType) !== null && _b !== void 0 ? _b : '',
241
+ list_name: 'VI VPR View',
242
+ price: Math.min(...[product.price.actual, (_c = product.price.sale) !== null && _c !== void 0 ? _c : Infinity])
243
+ }
244
+ ]
245
+ });
246
+ return undefined;
247
+ }
248
+ }
249
+
250
+ class GAnalytics {
251
+ constructor() {
252
+ ga('require', 'ec');
253
+ }
254
+ convertProduct(product) {
255
+ var _a, _b, _c;
256
+ return {
257
+ id: product.productId,
258
+ name: product.title,
259
+ brand: (_a = product.brand) !== null && _a !== void 0 ? _a : '',
260
+ category: (_b = product.productType) !== null && _b !== void 0 ? _b : '',
261
+ list: 'VI VPR View',
262
+ price: Math.min(...[product.price.actual, (_c = product.price.sale) !== null && _c !== void 0 ? _c : Infinity])
263
+ };
264
+ }
265
+ sendImpression(product) {
266
+ ga('ec:addImpression', this.convertProduct(product));
267
+ return undefined;
268
+ }
269
+ sendClick(product) {
270
+ var _a, _b, _c;
271
+ ga('ec:addProduct', {
272
+ id: product.productId,
273
+ name: product.title,
274
+ brand: (_a = product.brand) !== null && _a !== void 0 ? _a : '',
275
+ category: (_b = product.productType) !== null && _b !== void 0 ? _b : '',
276
+ price: Math.min(...[product.price.actual, (_c = product.price.sale) !== null && _c !== void 0 ? _c : Infinity])
277
+ });
278
+ ga('ec:setAction', 'click', { list: 'VI VPR View' });
279
+ return undefined;
280
+ }
281
+ }
282
+
283
+ const getGtagAnalytics = () => imageSearch_store._function.pipe(imageSearch_store.Option.fromNullable(window.gtag), imageSearch_store.Option.map(() => new GtagAnalytics()));
284
+ const getCommonAnalytics = () => imageSearch_store._function.pipe(imageSearch_store.Option.fromNullable(window.ga), imageSearch_store.Option.map(() => new GAnalytics()));
285
+ const analyticsMonoid = imageSearch_store.Option.getMonoid(imageSearch_store.Semigroup.first());
286
+ const getAnalyticsModule = analyticsMonoid.concat(getGtagAnalytics(), getCommonAnalytics());
287
+
288
+ const FIT_EXPR = /fit\/\d+\//;
289
+ const containsFit = (url) => {
290
+ return imageSearch_store._function.pipe(url.match(FIT_EXPR), imageSearch_store.Either.fromNullable(url), imageSearch_store.Either.map(() => url));
291
+ };
292
+ const processWidth = (url, size) => {
293
+ return imageSearch_store._function.pipe(containsFit(url), imageSearch_store.Either.map((url) => url.replace(FIT_EXPR, `fit/${size}/`)), imageSearch_store.Either.getOrElse(() => url));
294
+ };
295
+ const Linked = (props, child) => props.deeplink ? (index.h("a", { class: props.part, part: props.part, href: props.deeplink }, child)) : (child);
296
+ const FormattedPrice = (props) => {
297
+ var _a;
298
+ const locale = props.locale;
299
+ const formattedPrice = new Intl.NumberFormat(locale, {
300
+ minimumFractionDigits: 2,
301
+ }).format(props.price);
302
+ const fullPrice = `${(_a = props.prefix) !== null && _a !== void 0 ? _a : ""} ${formattedPrice} ${props.currency}`;
303
+ return (index.h("span", { class: "price-amount", part: "price-amount" }, fullPrice));
304
+ };
305
+ const Price = (props) => {
306
+ const priceEl = (index.h(FormattedPrice, { prefix: props.prefix, currency: props.currency, price: props.price, locale: props.locale }));
307
+ return (index.h("span", { class: "price-container", part: "price-container" }, props.salePrice ? ([
308
+ index.h("span", { class: "price-sale", part: "price-sale" },
309
+ index.h(FormattedPrice, { prefix: props.prefix, currency: props.currency, price: props.salePrice, locale: props.locale })),
310
+ index.h("span", { class: "price-outdated", part: "price-outdated" }, priceEl),
311
+ ]) : (index.h("span", { class: "price-regular", part: "price-regular" }, priceEl))));
312
+ };
313
+ const Image = (props, onLoadEnd = () => undefined) => (index.h("picture", null,
314
+ index.h("img", { loading: props.lazy ? "lazy" : "eager", part: "image", class: "image", width: props.width, height: props.height, src: processWidth(props.src, props.width), alt: props.title, onLoad: onLoadEnd })));
315
+ const ResponsiveImage = (props, onLoadEnd = () => undefined) => (index.h("picture", null,
316
+ index.h("img", { loading: props.lazy ? "lazy" : "eager", part: "image", class: "image responsive", src: processWidth(props.src, props.width), alt: props.title, onLoad: onLoadEnd })));
317
+
318
+ const vviinnProductCardCss = ":host{align-items:center;display:flex;flex-direction:column;gap:8px;height:100%}.price-container{display:flex;flex-direction:column}.price-sale,.price-regular{font-style:normal;font-weight:normal;font-size:16px;line-height:24px;color:#161616}.price-outdated{font-style:normal;font-weight:normal;font-size:16px;line-height:24px;color:#757575;text-decoration:line-through}.product-type{word-wrap:anywhere}.image{display:grid;align-content:center;-o-object-position:50% 50%;object-position:50% 50%;-o-object-fit:contain;object-fit:contain;text-align:center;box-sizing:border-box}img.responsive{width:100%;height:auto;aspect-ratio:1}.brand,.type{display:none}.title{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:#161616;display:-webkit-box;font-size:16px;font-style:normal;font-weight:500;line-height:24px;margin-bottom:8px;overflow:hidden}.deeplink{text-decoration:none}.image-link{display:contents}picture{position:relative;width:100%}:host(.dimmed) picture::before{content:\"\";width:100%;height:100%;box-sizing:border-box;background:#f7f7f7;display:block;top:0;left:0;position:absolute;mix-blend-mode:multiply}";
319
+
320
+ let VviinnProductCard = class {
321
+ constructor(hostRef) {
322
+ index.registerInstance(this, hostRef);
323
+ this.recommendationLoad = index.createEvent(this, "recommendationLoad", 7);
324
+ this.recommendationView = index.createEvent(this, "recommendationView", 7);
325
+ this.recommendationClick = index.createEvent(this, "recommendationClick", 7);
326
+ this.productImageLoaded = index.createEvent(this, "productImageLoaded", 7);
327
+ this.currency = undefined;
328
+ this.imageRatio = 1;
329
+ this.imageWidth = 200;
330
+ this.locale = undefined;
331
+ this.pricePrefix = undefined;
332
+ this.responsive = false;
333
+ this.dimmedBackground = false;
334
+ this.imageLoaded = false;
335
+ this.intersectionObserver = new IntersectionObserver(this.intersectionCallback.bind(this), { threshold: 1.0 });
336
+ }
337
+ intersectionCallback(data) {
338
+ if (data.some((entry) => entry.isIntersecting)) {
339
+ imageSearch_store._function.pipe(getAnalyticsModule, imageSearch_store.Option.map((analytics) => analytics.sendImpression(this.getProduct())));
340
+ this.recommendationView.emit(this.productId);
341
+ this.intersectionObserver.disconnect();
342
+ }
343
+ }
344
+ componentDidLoad() {
345
+ this.recommendationLoad.emit(this.productId);
346
+ this.intersectionObserver.observe(this.el);
347
+ const links = this.el.shadowRoot.querySelectorAll("a");
348
+ links.forEach((link) => link.addEventListener("mousedown", (event) => {
349
+ this.recommendationClick.emit(this.productId);
350
+ if (window.ga) {
351
+ event.preventDefault();
352
+ }
353
+ imageSearch_store._function.pipe(getAnalyticsModule, imageSearch_store.Option.match(() => null, (analytics) => analytics.sendClick(this.getProduct())));
354
+ if (window.ga) {
355
+ ga("send", "event", "UX", "click", "Results", {
356
+ hitCallback: function () {
357
+ document.location.href = this.deeplink;
358
+ },
359
+ });
360
+ }
361
+ }));
362
+ }
363
+ getProduct() {
364
+ return imageSearch_store.imageSearchState.results.find((r) => r.productId === this.productId);
365
+ }
366
+ renderImage() {
367
+ const props = {
368
+ width: this.imageWidth,
369
+ height: this.imageWidth * this.imageRatio,
370
+ src: this.image,
371
+ title: this.productTitle,
372
+ lazy: false,
373
+ };
374
+ return this.responsive
375
+ ? ResponsiveImage(props, () => this.kek())
376
+ : Image(props, () => this.kek());
377
+ }
378
+ kek() {
379
+ this.productImageLoaded.emit(this.productId);
380
+ }
381
+ render() {
382
+ var _a, _b, _c;
383
+ return (index.h(index.Host, { part: "product-card", class: { dimmed: this.dimmedBackground }, exportparts: "brand, currency, deeplink, image, image-link, price-amount, price-container, price-outdated, price-prefix, price-regular, price-sale, title" }, index.h(Linked, { deeplink: this.deeplink, part: "image-link" }, this.renderImage()), index.h(Linked, { deeplink: this.deeplink, part: "deeplink" }, index.h("span", { class: "title", part: "title" }, this.productTitle)), index.h("span", { class: "brand", part: "brand" }, this.brand), index.h("span", { class: "type", part: "type" }, this.productType), index.h(Price, { prefix: (_a = this.pricePrefix) !== null && _a !== void 0 ? _a : imageSearch_store.state.pricePrefix, currency: (_b = this.currency) !== null && _b !== void 0 ? _b : imageSearch_store.state.currencySign, price: this.price, salePrice: this.salePrice, locale: (_c = this.locale) !== null && _c !== void 0 ? _c : imageSearch_store.state.locale })));
384
+ }
385
+ get el() { return index.getElement(this); }
386
+ };
387
+ VviinnProductCard.style = vviinnProductCardCss;
388
+
389
+ const recommendationsSidebarCss = ":host{--vviinn-carousel-columns:0;box-sizing:border-box;display:block;display:flex;height:100vh;left:0;position:fixed;top:0;transition:background 0.1s ease-in-out;width:100vw}:host(.open){background:rgba(0, 0, 0, 0.2)}:host(.bottom){flex-direction:column;justify-content:end}:host(.right){flex-direction:row;justify-content:flex-end}header{position:relative;text-align:center;padding:32px}header.contains-source-img{display:grid;justify-items:center;grid-gap:12px}img.source-image{width:64px;height:64px;border-radius:50%;box-shadow:0px 2px 4px rgba(0, 0, 0, 0.15);padding:8px}:host(.right) header{box-shadow:0px 2px 6px rgba(0, 0, 0, 0.1)}main{padding:0 24px}:host(.right) main{overflow:auto}.sidebar{background:white;box-sizing:border-box;display:flex;flex-direction:column}:host(.bottom.idle) .sidebar,:host(.bottom.closed) .sidebar{transform:translateY(100%)}:host(.bottom.closed) .sidebar{-webkit-animation-name:slideOutFromBottom;animation-name:slideOutFromBottom;-webkit-animation-duration:0.5s;animation-duration:0.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}:host(.bottom.open) .sidebar{-webkit-animation-name:slideInFromBottom;animation-name:slideInFromBottom;-webkit-animation-duration:0.5s;animation-duration:0.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}:host(.right.idle) .sidebar{transform:translateX(100%)}:host(.right.closed) .sidebar{-webkit-animation-name:slideOutFromRight;animation-name:slideOutFromRight;-webkit-animation-duration:0.5s;animation-duration:0.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}:host(.right.open) .sidebar{-webkit-animation-name:slideInFromRight;animation-name:slideInFromRight;-webkit-animation-duration:0.5s;animation-duration:0.5s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}:host(.right) .sidebar{max-width:480px}:host(.right) vviinn-vpr-widget::part(recommendations-grid){display:grid;grid-template-columns:repeat(2, 1fr);grid-gap:24px}:host(.right) vviinn-vpr-widget{overflow:auto}:host(.right) vviinn-vpr-widget::part(image){border:none}.title{font-style:normal;font-weight:500;font-size:28px;line-height:40px;text-align:center;color:#000000}vviinn-vpr-widget::part(title),vviinn-vpr-widget::part(brand),vviinn-vpr-widget::part(type){text-align:left}vviinn-vpr-widget::part(price-container){align-self:start}.close-sidebar{background:transparent;border:none;cursor:pointer;margin:0;padding:0;position:absolute;right:24px;top:24px}@-webkit-keyframes slideInFromBottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes slideInFromBottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@-webkit-keyframes slideOutFromBottom{from{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes slideOutFromBottom{from{transform:translateY(0)}to{transform:translateY(100%)}}@-webkit-keyframes slideInFromRight{from{transform:translateX(100%)}to{transform:translateX(0)}}@keyframes slideInFromRight{from{transform:translateX(100%)}to{transform:translateX(0)}}@-webkit-keyframes slideOutFromRight{from{transform:translateX(0)}to{transform:translateX(100%)}}@keyframes slideOutFromRight{from{transform:translateX(0)}to{transform:translateX(100%)}}";
390
+
391
+ let RecommendationsSidebar = class {
392
+ constructor(hostRef) {
393
+ index.registerInstance(this, hostRef);
394
+ this.modalClosed = index.createEvent(this, "modalClosed", 7);
395
+ this.position = "bottom";
396
+ this.sourceImage = null;
397
+ this.widgetScrollbar = false;
398
+ this.state = "idle";
399
+ }
400
+ bodyClickListener(event) {
401
+ const { clientX, clientY } = event;
402
+ const sidebarRect = this.getSidebarRectangle();
403
+ if (!sidebarRect)
404
+ return;
405
+ const inLeftBound = clientX >= sidebarRect.left;
406
+ const inRightBound = clientX <= sidebarRect.right;
407
+ const inTopBound = clientY >= sidebarRect.top;
408
+ const inBottomBound = clientY <= sidebarRect.bottom;
409
+ const inBound = inLeftBound && inRightBound && inTopBound && inBottomBound;
410
+ if (!inBound) {
411
+ this.state = "closed";
412
+ }
413
+ }
414
+ getClassMap() {
415
+ return {
416
+ [this.position]: true,
417
+ [this.state]: true,
418
+ };
419
+ }
420
+ getSidebarRectangle() {
421
+ var _a;
422
+ return (_a = this.el.shadowRoot.querySelector("aside")) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
423
+ }
424
+ render() {
425
+ return (index.h(index.Host, { class: this.getClassMap() }, index.h("aside", { class: "sidebar", part: "body", onAnimationEnd: (e) => this.handleAnimationEnd(e) }, index.h("header", { class: { "contains-source-img": this.isSourceImageValid() }, part: "sidebar-header" }, this.isSourceImageValid() ? this.renderSourceImage() : null, index.h("span", { class: "title", part: "title" }, this.sidebarTitle), index.h("button", { class: "close-sidebar", onClick: () => (this.state = "closed") }, index.h(index$1.CrossIcon, null))), index.h("main", { part: "sidebar-content" }, index.h("vviinn-vpr-widget", { exportparts: "brand, currency, deeplink, image, image-link, price-amount, price-container, price-outdated, price-prefix, price-regular, price-sale, title: product-title", token: this.token, productId: this.productId, imageWidth: 300, blockTitle: "", mode: this.position === "bottom" ? "continuity" : "grid", useCarousel: this.position === "bottom", onRecommendationsLoaded: () => (this.state = "open"), showScroll: this.widgetScrollbar })))));
426
+ }
427
+ renderSourceImage() {
428
+ return (index.h("img", { class: "source-image", part: "source-image", src: this.sourceImage }));
429
+ }
430
+ isSourceImageValid() {
431
+ var _a;
432
+ return ((_a = this.sourceImage) === null || _a === void 0 ? void 0 : _a.length) > 0;
433
+ }
434
+ handleAnimationEnd({ animationName }) {
435
+ const isClosingAnimation = animationName.includes("slideOut");
436
+ if (!isClosingAnimation)
437
+ return;
438
+ this.modalClosed.emit();
439
+ }
440
+ get el() { return index.getElement(this); }
441
+ };
442
+ RecommendationsSidebar.style = recommendationsSidebarCss;
443
+
444
+ const vviinnVprButtonCss = ":host{display:block}.open-button{align-items:center;background:rgba(255, 255, 255, 0.8);border-radius:50%;border:none;box-shadow:0px 2px 6px rgba(0, 0, 0, 0.15);box-sizing:border-box;cursor:pointer;display:grid;height:40px;justify-items:center;padding:0;width:40px;transition:all 0.25s ease-in-out}.open-button:hover{box-shadow:0px 2px 6px rgba(0, 0, 0, 0.25)}.open-button:focus{border:2px solid rgba(15, 98, 254, 0.5);outline:none}.open-button:active{background:#F4F4F4;outline:none}";
445
+
446
+ let VviinnVprButton = class {
447
+ constructor(hostRef) {
448
+ index.registerInstance(this, hostRef);
449
+ this.position = "bottom";
450
+ this.sourceImage = null;
451
+ this.sidebarTitle = "Visually similar products";
452
+ this.modalScrollbar = false;
453
+ }
454
+ render() {
455
+ return (index.h(index.Host, null, index.h("button", { class: "open-button", part: "button", onClick: () => this.handleClick() }, index.h("slot", null, index.h(index$1.VisualSearchIcon, null)))));
456
+ }
457
+ handleClick() {
458
+ const sidebar = document.createElement("vviinn-recommendations-sidebar");
459
+ sidebar.sidebarTitle = this.sidebarTitle;
460
+ sidebar.productId = this.productId;
461
+ sidebar.token = this.token;
462
+ sidebar.position = this.position;
463
+ sidebar.sourceImage = this.sourceImage;
464
+ sidebar.widgetScrollbar = this.modalScrollbar;
465
+ sidebar.addEventListener("modalClosed", () => {
466
+ document.body.removeChild(sidebar);
467
+ });
468
+ document.body.append(sidebar);
469
+ }
470
+ };
471
+ VviinnVprButton.style = vviinnVprButtonCss;
472
+
473
+ const createBearerString = (x) => `Bearer ${x}`;
474
+ const createAuthedHeader = (x) => new Headers({
475
+ Authorization: x,
476
+ });
477
+ const createFetchAuthOptions = (x) => {
478
+ return {
479
+ headers: x,
480
+ };
481
+ };
482
+ const createBearAuthedHeader = imageSearch_store._function.flow(createBearerString, createAuthedHeader, createFetchAuthOptions);
483
+
484
+ const isVPR = (c) => c._tag === "VPR";
485
+ function fold(onVPR, onVCS) {
486
+ return (c) => (isVPR(c) ? onVPR() : onVCS());
487
+ }
488
+ function fromString(s) {
489
+ return s === "VPR" ? { _tag: "VPR" } : { _tag: "VCS" };
490
+ }
491
+
492
+ const sequenceToEither = imageSearch_store.sequenceT(imageSearch_store.Apply);
493
+ const apiGet = (path, data = {}) => Handler.pipe(sequenceToEither(imageSearch_store.getApiPath(), imageSearch_store.createInitGetRequest), imageSearch_store.fromEither, imageSearch_store.chainW(imageSearch_store.makeRequest(path, data)));
494
+
495
+ const getVPRRecommendations = (productId) => (options) => {
496
+ const url = `product/${productId}/similar-products`;
497
+ return apiGet(url, options);
498
+ };
499
+
500
+ const getVCSRecommendations = (productId) => (options) => {
501
+ const url = `product/${productId}/cross-selling-products`;
502
+ return apiGet(url, options);
503
+ };
504
+
505
+ const getRecommendationsService = (campaignType) => imageSearch_store._function.pipe(fromString(campaignType), fold(() => getVPRRecommendations, () => getVCSRecommendations));
506
+
507
+ function isFunction(value) {
508
+ return typeof value === 'function';
509
+ }
510
+
511
+ function createErrorClass(createImpl) {
512
+ const _super = (instance) => {
513
+ Error.call(instance);
514
+ instance.stack = new Error().stack;
515
+ };
516
+ const ctorFunc = createImpl(_super);
517
+ ctorFunc.prototype = Object.create(Error.prototype);
518
+ ctorFunc.prototype.constructor = ctorFunc;
519
+ return ctorFunc;
520
+ }
521
+
522
+ const UnsubscriptionError = createErrorClass((_super) => function UnsubscriptionErrorImpl(errors) {
523
+ _super(this);
524
+ this.message = errors
525
+ ? `${errors.length} errors occurred during unsubscription:
526
+ ${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\n ')}`
527
+ : '';
528
+ this.name = 'UnsubscriptionError';
529
+ this.errors = errors;
530
+ });
531
+
532
+ function arrRemove(arr, item) {
533
+ if (arr) {
534
+ const index = arr.indexOf(item);
535
+ 0 <= index && arr.splice(index, 1);
536
+ }
537
+ }
538
+
539
+ class Subscription {
540
+ constructor(initialTeardown) {
541
+ this.initialTeardown = initialTeardown;
542
+ this.closed = false;
543
+ this._parentage = null;
544
+ this._finalizers = null;
545
+ }
546
+ unsubscribe() {
547
+ let errors;
548
+ if (!this.closed) {
549
+ this.closed = true;
550
+ const { _parentage } = this;
551
+ if (_parentage) {
552
+ this._parentage = null;
553
+ if (Array.isArray(_parentage)) {
554
+ for (const parent of _parentage) {
555
+ parent.remove(this);
556
+ }
557
+ }
558
+ else {
559
+ _parentage.remove(this);
560
+ }
561
+ }
562
+ const { initialTeardown: initialFinalizer } = this;
563
+ if (isFunction(initialFinalizer)) {
564
+ try {
565
+ initialFinalizer();
566
+ }
567
+ catch (e) {
568
+ errors = e instanceof UnsubscriptionError ? e.errors : [e];
569
+ }
570
+ }
571
+ const { _finalizers } = this;
572
+ if (_finalizers) {
573
+ this._finalizers = null;
574
+ for (const finalizer of _finalizers) {
575
+ try {
576
+ execFinalizer(finalizer);
577
+ }
578
+ catch (err) {
579
+ errors = errors !== null && errors !== void 0 ? errors : [];
580
+ if (err instanceof UnsubscriptionError) {
581
+ errors = [...errors, ...err.errors];
582
+ }
583
+ else {
584
+ errors.push(err);
585
+ }
586
+ }
587
+ }
588
+ }
589
+ if (errors) {
590
+ throw new UnsubscriptionError(errors);
591
+ }
592
+ }
593
+ }
594
+ add(teardown) {
595
+ var _a;
596
+ if (teardown && teardown !== this) {
597
+ if (this.closed) {
598
+ execFinalizer(teardown);
599
+ }
600
+ else {
601
+ if (teardown instanceof Subscription) {
602
+ if (teardown.closed || teardown._hasParent(this)) {
603
+ return;
604
+ }
605
+ teardown._addParent(this);
606
+ }
607
+ (this._finalizers = (_a = this._finalizers) !== null && _a !== void 0 ? _a : []).push(teardown);
608
+ }
609
+ }
610
+ }
611
+ _hasParent(parent) {
612
+ const { _parentage } = this;
613
+ return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));
614
+ }
615
+ _addParent(parent) {
616
+ const { _parentage } = this;
617
+ this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;
618
+ }
619
+ _removeParent(parent) {
620
+ const { _parentage } = this;
621
+ if (_parentage === parent) {
622
+ this._parentage = null;
623
+ }
624
+ else if (Array.isArray(_parentage)) {
625
+ arrRemove(_parentage, parent);
626
+ }
627
+ }
628
+ remove(teardown) {
629
+ const { _finalizers } = this;
630
+ _finalizers && arrRemove(_finalizers, teardown);
631
+ if (teardown instanceof Subscription) {
632
+ teardown._removeParent(this);
633
+ }
634
+ }
635
+ }
636
+ Subscription.EMPTY = (() => {
637
+ const empty = new Subscription();
638
+ empty.closed = true;
639
+ return empty;
640
+ })();
641
+ const EMPTY_SUBSCRIPTION = Subscription.EMPTY;
642
+ function isSubscription(value) {
643
+ return (value instanceof Subscription ||
644
+ (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe)));
645
+ }
646
+ function execFinalizer(finalizer) {
647
+ if (isFunction(finalizer)) {
648
+ finalizer();
649
+ }
650
+ else {
651
+ finalizer.unsubscribe();
652
+ }
653
+ }
654
+
655
+ const config = {
656
+ onUnhandledError: null,
657
+ onStoppedNotification: null,
658
+ Promise: undefined,
659
+ useDeprecatedSynchronousErrorHandling: false,
660
+ useDeprecatedNextContext: false,
661
+ };
662
+
663
+ const timeoutProvider = {
664
+ setTimeout(handler, timeout, ...args) {
665
+ const { delegate } = timeoutProvider;
666
+ if (delegate === null || delegate === void 0 ? void 0 : delegate.setTimeout) {
667
+ return delegate.setTimeout(handler, timeout, ...args);
668
+ }
669
+ return setTimeout(handler, timeout, ...args);
670
+ },
671
+ clearTimeout(handle) {
672
+ const { delegate } = timeoutProvider;
673
+ return ((delegate === null || delegate === void 0 ? void 0 : delegate.clearTimeout) || clearTimeout)(handle);
674
+ },
675
+ delegate: undefined,
676
+ };
677
+
678
+ function reportUnhandledError(err) {
679
+ timeoutProvider.setTimeout(() => {
680
+ const { onUnhandledError } = config;
681
+ if (onUnhandledError) {
682
+ onUnhandledError(err);
683
+ }
684
+ else {
685
+ throw err;
686
+ }
687
+ });
688
+ }
689
+
690
+ function noop() { }
691
+
692
+ const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined))();
693
+ function errorNotification(error) {
694
+ return createNotification('E', undefined, error);
695
+ }
696
+ function nextNotification(value) {
697
+ return createNotification('N', value, undefined);
698
+ }
699
+ function createNotification(kind, value, error) {
700
+ return {
701
+ kind,
702
+ value,
703
+ error,
704
+ };
705
+ }
706
+
707
+ function errorContext(cb) {
708
+ {
709
+ cb();
710
+ }
711
+ }
712
+
713
+ class Subscriber extends Subscription {
714
+ constructor(destination) {
715
+ super();
716
+ this.isStopped = false;
717
+ if (destination) {
718
+ this.destination = destination;
719
+ if (isSubscription(destination)) {
720
+ destination.add(this);
721
+ }
722
+ }
723
+ else {
724
+ this.destination = EMPTY_OBSERVER;
725
+ }
726
+ }
727
+ static create(next, error, complete) {
728
+ return new SafeSubscriber(next, error, complete);
729
+ }
730
+ next(value) {
731
+ if (this.isStopped) {
732
+ handleStoppedNotification(nextNotification(value), this);
733
+ }
734
+ else {
735
+ this._next(value);
736
+ }
737
+ }
738
+ error(err) {
739
+ if (this.isStopped) {
740
+ handleStoppedNotification(errorNotification(err), this);
741
+ }
742
+ else {
743
+ this.isStopped = true;
744
+ this._error(err);
745
+ }
746
+ }
747
+ complete() {
748
+ if (this.isStopped) {
749
+ handleStoppedNotification(COMPLETE_NOTIFICATION, this);
750
+ }
751
+ else {
752
+ this.isStopped = true;
753
+ this._complete();
754
+ }
755
+ }
756
+ unsubscribe() {
757
+ if (!this.closed) {
758
+ this.isStopped = true;
759
+ super.unsubscribe();
760
+ this.destination = null;
761
+ }
762
+ }
763
+ _next(value) {
764
+ this.destination.next(value);
765
+ }
766
+ _error(err) {
767
+ try {
768
+ this.destination.error(err);
769
+ }
770
+ finally {
771
+ this.unsubscribe();
772
+ }
773
+ }
774
+ _complete() {
775
+ try {
776
+ this.destination.complete();
777
+ }
778
+ finally {
779
+ this.unsubscribe();
780
+ }
781
+ }
782
+ }
783
+ const _bind = Function.prototype.bind;
784
+ function bind(fn, thisArg) {
785
+ return _bind.call(fn, thisArg);
786
+ }
787
+ class ConsumerObserver {
788
+ constructor(partialObserver) {
789
+ this.partialObserver = partialObserver;
790
+ }
791
+ next(value) {
792
+ const { partialObserver } = this;
793
+ if (partialObserver.next) {
794
+ try {
795
+ partialObserver.next(value);
796
+ }
797
+ catch (error) {
798
+ handleUnhandledError(error);
799
+ }
800
+ }
801
+ }
802
+ error(err) {
803
+ const { partialObserver } = this;
804
+ if (partialObserver.error) {
805
+ try {
806
+ partialObserver.error(err);
807
+ }
808
+ catch (error) {
809
+ handleUnhandledError(error);
810
+ }
811
+ }
812
+ else {
813
+ handleUnhandledError(err);
814
+ }
815
+ }
816
+ complete() {
817
+ const { partialObserver } = this;
818
+ if (partialObserver.complete) {
819
+ try {
820
+ partialObserver.complete();
821
+ }
822
+ catch (error) {
823
+ handleUnhandledError(error);
824
+ }
825
+ }
826
+ }
827
+ }
828
+ class SafeSubscriber extends Subscriber {
829
+ constructor(observerOrNext, error, complete) {
830
+ super();
831
+ let partialObserver;
832
+ if (isFunction(observerOrNext) || !observerOrNext) {
833
+ partialObserver = {
834
+ next: observerOrNext !== null && observerOrNext !== void 0 ? observerOrNext : undefined,
835
+ error: error !== null && error !== void 0 ? error : undefined,
836
+ complete: complete !== null && complete !== void 0 ? complete : undefined,
837
+ };
838
+ }
839
+ else {
840
+ let context;
841
+ if (this && config.useDeprecatedNextContext) {
842
+ context = Object.create(observerOrNext);
843
+ context.unsubscribe = () => this.unsubscribe();
844
+ partialObserver = {
845
+ next: observerOrNext.next && bind(observerOrNext.next, context),
846
+ error: observerOrNext.error && bind(observerOrNext.error, context),
847
+ complete: observerOrNext.complete && bind(observerOrNext.complete, context),
848
+ };
849
+ }
850
+ else {
851
+ partialObserver = observerOrNext;
852
+ }
853
+ }
854
+ this.destination = new ConsumerObserver(partialObserver);
855
+ }
856
+ }
857
+ function handleUnhandledError(error) {
858
+ {
859
+ reportUnhandledError(error);
860
+ }
861
+ }
862
+ function defaultErrorHandler(err) {
863
+ throw err;
864
+ }
865
+ function handleStoppedNotification(notification, subscriber) {
866
+ const { onStoppedNotification } = config;
867
+ onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));
868
+ }
869
+ const EMPTY_OBSERVER = {
870
+ closed: true,
871
+ next: noop,
872
+ error: defaultErrorHandler,
873
+ complete: noop,
874
+ };
875
+
876
+ const observable = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();
877
+
878
+ function identity(x) {
879
+ return x;
880
+ }
881
+
882
+ function pipeFromArray(fns) {
883
+ if (fns.length === 0) {
884
+ return identity;
885
+ }
886
+ if (fns.length === 1) {
887
+ return fns[0];
888
+ }
889
+ return function piped(input) {
890
+ return fns.reduce((prev, fn) => fn(prev), input);
891
+ };
892
+ }
893
+
894
+ class Observable {
895
+ constructor(subscribe) {
896
+ if (subscribe) {
897
+ this._subscribe = subscribe;
898
+ }
899
+ }
900
+ lift(operator) {
901
+ const observable = new Observable();
902
+ observable.source = this;
903
+ observable.operator = operator;
904
+ return observable;
905
+ }
906
+ subscribe(observerOrNext, error, complete) {
907
+ const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);
908
+ errorContext(() => {
909
+ const { operator, source } = this;
910
+ subscriber.add(operator
911
+ ?
912
+ operator.call(subscriber, source)
913
+ : source
914
+ ?
915
+ this._subscribe(subscriber)
916
+ :
917
+ this._trySubscribe(subscriber));
918
+ });
919
+ return subscriber;
920
+ }
921
+ _trySubscribe(sink) {
922
+ try {
923
+ return this._subscribe(sink);
924
+ }
925
+ catch (err) {
926
+ sink.error(err);
927
+ }
928
+ }
929
+ forEach(next, promiseCtor) {
930
+ promiseCtor = getPromiseCtor(promiseCtor);
931
+ return new promiseCtor((resolve, reject) => {
932
+ const subscriber = new SafeSubscriber({
933
+ next: (value) => {
934
+ try {
935
+ next(value);
936
+ }
937
+ catch (err) {
938
+ reject(err);
939
+ subscriber.unsubscribe();
940
+ }
941
+ },
942
+ error: reject,
943
+ complete: resolve,
944
+ });
945
+ this.subscribe(subscriber);
946
+ });
947
+ }
948
+ _subscribe(subscriber) {
949
+ var _a;
950
+ return (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber);
951
+ }
952
+ [observable]() {
953
+ return this;
954
+ }
955
+ pipe(...operations) {
956
+ return pipeFromArray(operations)(this);
957
+ }
958
+ toPromise(promiseCtor) {
959
+ promiseCtor = getPromiseCtor(promiseCtor);
960
+ return new promiseCtor((resolve, reject) => {
961
+ let value;
962
+ this.subscribe((x) => (value = x), (err) => reject(err), () => resolve(value));
963
+ });
964
+ }
965
+ }
966
+ Observable.create = (subscribe) => {
967
+ return new Observable(subscribe);
968
+ };
969
+ function getPromiseCtor(promiseCtor) {
970
+ var _a;
971
+ return (_a = promiseCtor !== null && promiseCtor !== void 0 ? promiseCtor : config.Promise) !== null && _a !== void 0 ? _a : Promise;
972
+ }
973
+ function isObserver(value) {
974
+ return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);
975
+ }
976
+ function isSubscriber(value) {
977
+ return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));
978
+ }
979
+
980
+ const ObjectUnsubscribedError = createErrorClass((_super) => function ObjectUnsubscribedErrorImpl() {
981
+ _super(this);
982
+ this.name = 'ObjectUnsubscribedError';
983
+ this.message = 'object unsubscribed';
984
+ });
985
+
986
+ class Subject extends Observable {
987
+ constructor() {
988
+ super();
989
+ this.closed = false;
990
+ this.currentObservers = null;
991
+ this.observers = [];
992
+ this.isStopped = false;
993
+ this.hasError = false;
994
+ this.thrownError = null;
995
+ }
996
+ lift(operator) {
997
+ const subject = new AnonymousSubject(this, this);
998
+ subject.operator = operator;
999
+ return subject;
1000
+ }
1001
+ _throwIfClosed() {
1002
+ if (this.closed) {
1003
+ throw new ObjectUnsubscribedError();
1004
+ }
1005
+ }
1006
+ next(value) {
1007
+ errorContext(() => {
1008
+ this._throwIfClosed();
1009
+ if (!this.isStopped) {
1010
+ if (!this.currentObservers) {
1011
+ this.currentObservers = Array.from(this.observers);
1012
+ }
1013
+ for (const observer of this.currentObservers) {
1014
+ observer.next(value);
1015
+ }
1016
+ }
1017
+ });
1018
+ }
1019
+ error(err) {
1020
+ errorContext(() => {
1021
+ this._throwIfClosed();
1022
+ if (!this.isStopped) {
1023
+ this.hasError = this.isStopped = true;
1024
+ this.thrownError = err;
1025
+ const { observers } = this;
1026
+ while (observers.length) {
1027
+ observers.shift().error(err);
1028
+ }
1029
+ }
1030
+ });
1031
+ }
1032
+ complete() {
1033
+ errorContext(() => {
1034
+ this._throwIfClosed();
1035
+ if (!this.isStopped) {
1036
+ this.isStopped = true;
1037
+ const { observers } = this;
1038
+ while (observers.length) {
1039
+ observers.shift().complete();
1040
+ }
1041
+ }
1042
+ });
1043
+ }
1044
+ unsubscribe() {
1045
+ this.isStopped = this.closed = true;
1046
+ this.observers = this.currentObservers = null;
1047
+ }
1048
+ get observed() {
1049
+ var _a;
1050
+ return ((_a = this.observers) === null || _a === void 0 ? void 0 : _a.length) > 0;
1051
+ }
1052
+ _trySubscribe(subscriber) {
1053
+ this._throwIfClosed();
1054
+ return super._trySubscribe(subscriber);
1055
+ }
1056
+ _subscribe(subscriber) {
1057
+ this._throwIfClosed();
1058
+ this._checkFinalizedStatuses(subscriber);
1059
+ return this._innerSubscribe(subscriber);
1060
+ }
1061
+ _innerSubscribe(subscriber) {
1062
+ const { hasError, isStopped, observers } = this;
1063
+ if (hasError || isStopped) {
1064
+ return EMPTY_SUBSCRIPTION;
1065
+ }
1066
+ this.currentObservers = null;
1067
+ observers.push(subscriber);
1068
+ return new Subscription(() => {
1069
+ this.currentObservers = null;
1070
+ arrRemove(observers, subscriber);
1071
+ });
1072
+ }
1073
+ _checkFinalizedStatuses(subscriber) {
1074
+ const { hasError, thrownError, isStopped } = this;
1075
+ if (hasError) {
1076
+ subscriber.error(thrownError);
1077
+ }
1078
+ else if (isStopped) {
1079
+ subscriber.complete();
1080
+ }
1081
+ }
1082
+ asObservable() {
1083
+ const observable = new Observable();
1084
+ observable.source = this;
1085
+ return observable;
1086
+ }
1087
+ }
1088
+ Subject.create = (destination, source) => {
1089
+ return new AnonymousSubject(destination, source);
1090
+ };
1091
+ class AnonymousSubject extends Subject {
1092
+ constructor(destination, source) {
1093
+ super();
1094
+ this.destination = destination;
1095
+ this.source = source;
1096
+ }
1097
+ next(value) {
1098
+ var _a, _b;
1099
+ (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.next) === null || _b === void 0 ? void 0 : _b.call(_a, value);
1100
+ }
1101
+ error(err) {
1102
+ var _a, _b;
1103
+ (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.call(_a, err);
1104
+ }
1105
+ complete() {
1106
+ var _a, _b;
1107
+ (_b = (_a = this.destination) === null || _a === void 0 ? void 0 : _a.complete) === null || _b === void 0 ? void 0 : _b.call(_a);
1108
+ }
1109
+ _subscribe(subscriber) {
1110
+ var _a, _b;
1111
+ return (_b = (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber)) !== null && _b !== void 0 ? _b : EMPTY_SUBSCRIPTION;
1112
+ }
1113
+ }
1114
+
1115
+ const vviinnVprWidgetCss = ":host{display:grid;grid-gap:1rem;width:100%}:host(:not(.loaded)){position:absolute;visibility:hidden}:host(.grid) vviinn-product-card::part(image){border:1px solid #DDDDDD;width:100%}h2{margin:0}vviinn-product-card::part(price-container){align-self:flex-start;text-align:left;display:flex}.results{display:grid;grid-gap:1rem}.visually-hidden{position:absolute;top:0;left:0;z-index:-1;height:0;width:0}h2{margin:0}:host(.grid) h2{justify-content:center}:host(.grid) vviinn-product-card::part(image){min-width:100%}:host(.grid) vviinn-product-card::part(image-link){width:100%}:host(.grid) vviinn-product-card::part(title),:host(.grid) vviinn-product-card::part(brand),:host(.grid) vviinn-product-card::part(type){text-align:center}:host(.grid) vviinn-product-card::part(price-container){align-self:center}:host(.continuity) vviinn-product-card::part(title),:host(.continuity) vviinn-product-card::part(brand),:host(.continuity) vviinn-product-card::part(type),:host(.continuity) vviinn-product-card::part(deeplink){text-align:left;max-width:unset;align-self:start}";
1116
+
1117
+ let VviinnVprWidget = class {
1118
+ constructor(hostRef) {
1119
+ index.registerInstance(this, hostRef);
1120
+ this.recommendationsLoaded = index.createEvent(this, "recommendationsLoaded", 7);
1121
+ /** Title for recommendations widget */
1122
+ this.blockTitle = "Recommended products";
1123
+ /** Ratio of each recommended product image */
1124
+ this.imageRatio = 1;
1125
+ /** Width of each recommended product image */
1126
+ this.imageWidth = 300;
1127
+ /** Currency sign will shown after price */
1128
+ this.currencySign = "€";
1129
+ /** Use slider or grid view */
1130
+ this.mode = "continuity";
1131
+ /** Campaign type */
1132
+ this.campaignType = "VPR";
1133
+ /** Locale for currency formatting */
1134
+ this.locale = "de-DE";
1135
+ /** @internal */
1136
+ this.apiPath = "https://api.vviinn.com";
1137
+ /** @internal */
1138
+ this.useCarousel = true;
1139
+ this.showScroll = true;
1140
+ this.cssUrl = null;
1141
+ this.recommendations = [];
1142
+ this.loaded = false;
1143
+ this.productImageLoadedSubject = new Subject();
1144
+ }
1145
+ handleProductIdChange() {
1146
+ this.getRecommendations();
1147
+ }
1148
+ handleCampaignTypeChange() {
1149
+ this.getRecommendations();
1150
+ }
1151
+ handleApiPathChange(newPath) {
1152
+ imageSearch_store.state$1.apiPath = newPath;
1153
+ this.getRecommendations();
1154
+ }
1155
+ lol({ detail }) {
1156
+ this.productImageLoadedSubject.next(detail);
1157
+ }
1158
+ connectedCallback() {
1159
+ imageSearch_store.state$1.apiPath = this.apiPath;
1160
+ imageSearch_store.state$1.currencySign = this.currencySign;
1161
+ imageSearch_store.state$1.locale = this.locale;
1162
+ }
1163
+ async componentWillLoad() {
1164
+ imageSearch_store.state$1.pricePrefix = this.pricePrefix;
1165
+ imageSearch_store.state$1.currencySign = this.currencySign;
1166
+ this.getRecommendations();
1167
+ }
1168
+ async getRecommendations() {
1169
+ if (this.productId === undefined || this.token === undefined)
1170
+ return;
1171
+ const campaignType = this.campaignType.length > 0 ? this.campaignType : "VPR";
1172
+ const headers = createBearAuthedHeader(this.token);
1173
+ const request = imageSearch_store._function.pipe(imageSearch_store.TaskEither.of(getRecommendationsService(campaignType)), imageSearch_store.TaskEither.ap(imageSearch_store.TaskEither.of(this.productId)), imageSearch_store.TaskEither.ap(imageSearch_store.TaskEither.of(headers)), imageSearch_store.TaskEither.flatten);
1174
+ const runRequest = await request();
1175
+ imageSearch_store._function.pipe(runRequest, imageSearch_store.Either.fold((error) => this.handleError(error), (data) => this.handleRecommendationsSucces(data)));
1176
+ }
1177
+ handleError(error) {
1178
+ console.log("ERROR:", error);
1179
+ }
1180
+ handleRecommendationsSucces(data) {
1181
+ var _a;
1182
+ this.recommendations = (_a = data === null || data === void 0 ? void 0 : data.extended) !== null && _a !== void 0 ? _a : data;
1183
+ imageSearch_store.imageSearchState.results = this.recommendations;
1184
+ this.loaded = true;
1185
+ //this.recommendationsLoaded.emit();
1186
+ this.productIds = this.recommendations.map(r => r.productId);
1187
+ this.productImageLoadedSubject.subscribe((id) => {
1188
+ this.productIds = this.productIds.filter(x => x !== id);
1189
+ if (this.productIds.length === 0) {
1190
+ this.recommendationsLoaded.emit();
1191
+ }
1192
+ });
1193
+ }
1194
+ isExternalCSS() {
1195
+ return this.cssUrl && this.cssUrl.length > 0;
1196
+ }
1197
+ renderExternalCSS() {
1198
+ return this.isExternalCSS() ? (index.h("link", { href: this.cssUrl, rel: "stylesheet" })) : ("");
1199
+ }
1200
+ render() {
1201
+ return (index.h(index.Host, { class: {
1202
+ loaded: this.loaded,
1203
+ empty: this.recommendations.length == 0,
1204
+ [this.mode]: true,
1205
+ }, "aria-hidden": this.loaded ? "false" : "true" }, this.renderExternalCSS(), index.h("style", null, imageSearch_store.state$1.fallbackStyles), index.h("h2", { part: "recommendations-title" }, this.blockTitle), this.useCarousel ? this.renderCarousel() : this.renderResults()));
1206
+ }
1207
+ renderRecommendation(recommendation) {
1208
+ return (index.h("vviinn-product-card", { part: "product-part", productId: recommendation.productId, productTitle: recommendation.title, deeplink: recommendation.deeplink, image: recommendation.image.thumbnail, brand: recommendation.brand, imageWidth: this.imageWidth, imageRatio: 1, price: recommendation.price.actual, salePrice: recommendation.price.sale, responsive: this.mode === "grid", dimmedBackground: this.useDimmedBackgroundInCard() }));
1209
+ }
1210
+ useDimmedBackgroundInCard() {
1211
+ return this.mode === "continuity" || !this.useCarousel;
1212
+ }
1213
+ renderResults() {
1214
+ return (index.h("div", { class: "recommendations-grid", part: "recommendations-grid" }, this.recommendations.map((r) => this.renderRecommendation(r))));
1215
+ }
1216
+ renderCarousel() {
1217
+ return (index.h("vviinn-carousel", { mode: this.mode, imageWidth: this.imageWidth, showScroll: this.showScroll, recommendations: this.recommendations }));
1218
+ }
1219
+ get el() { return index.getElement(this); }
1220
+ static get watchers() { return {
1221
+ "productId": ["handleProductIdChange"],
1222
+ "campaignType": ["handleCampaignTypeChange"],
1223
+ "apiPath": ["handleApiPathChange"]
1224
+ }; }
1225
+ };
1226
+ VviinnVprWidget.style = vviinnVprWidgetCss;
1227
+
1228
+ exports.vviinn_carousel = VviinnCarousel;
1229
+ exports.vviinn_product_card = VviinnProductCard;
1230
+ exports.vviinn_recommendations_sidebar = RecommendationsSidebar;
1231
+ exports.vviinn_vpr_button = VviinnVprButton;
1232
+ exports.vviinn_vpr_widget = VviinnVprWidget;