vviinn-widgets 2.222.0 → 2.223.0

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 (46) hide show
  1. package/dist/cjs/{index-RlbsyJJk.js → index-DZw3p4dq.js} +1 -1
  2. package/dist/cjs/{search.store-D4WiAMcl.js → search.store-Bh2_GSpU.js} +2 -1
  3. package/dist/cjs/vviinn-button_6.cjs.entry.js +1 -1
  4. package/dist/cjs/vviinn-camera_12.cjs.entry.js +152 -43
  5. package/dist/cjs/vviinn-carousel_10.cjs.entry.js +2 -53
  6. package/dist/cjs/vviinn-shop-the-look.cjs.entry.js +1 -1
  7. package/dist/cjs/vviinn-text-search.cjs.entry.js +1 -1
  8. package/dist/collection/components/vviinn-cropper/helpers/cropperOcrGate.js +36 -0
  9. package/dist/collection/components/vviinn-cropper/helpers/hasSelectedOcrFilter.js +4 -0
  10. package/dist/collection/components/vviinn-cropper/vviinn-cropper.js +108 -38
  11. package/dist/collection/components/vviinn-filters/vviinn-extended-filters.js +2 -2
  12. package/dist/collection/components/vviinn-results/vviinn-results.js +78 -3
  13. package/dist/esm/{index-CEzGPs5u.js → index-DQQYIioG.js} +1 -1
  14. package/dist/esm/{search.store-Cgs5icgA.js → search.store-lTerE9Yh.js} +2 -2
  15. package/dist/esm/vviinn-button_6.entry.js +1 -1
  16. package/dist/esm/vviinn-camera_12.entry.js +152 -43
  17. package/dist/esm/vviinn-carousel_10.entry.js +2 -53
  18. package/dist/esm/vviinn-shop-the-look.entry.js +1 -1
  19. package/dist/esm/vviinn-text-search.entry.js +1 -1
  20. package/dist/storybook/helpers/industryToken.js +6 -8
  21. package/dist/types/components/vviinn-cropper/helpers/cropperOcrGate.d.ts +19 -0
  22. package/dist/types/components/vviinn-cropper/helpers/hasSelectedOcrFilter.d.ts +2 -0
  23. package/dist/types/components/vviinn-cropper/vviinn-cropper.d.ts +14 -0
  24. package/dist/types/components/vviinn-filters/vviinn-extended-filters.d.ts +51 -0
  25. package/dist/types/components/vviinn-results/vviinn-results.d.ts +1 -1
  26. package/dist/vviinn-widgets/p-08d39cc9.entry.js +1 -0
  27. package/dist/vviinn-widgets/{p-df4365fb.entry.js → p-1e2f9b9f.entry.js} +1 -1
  28. package/dist/vviinn-widgets/{p-c1eac87b.entry.js → p-3daed25b.entry.js} +1 -1
  29. package/{www/build/p-Cxd6yzhY.js → dist/vviinn-widgets/p-CJAxBbhA.js} +1 -1
  30. package/dist/vviinn-widgets/{p-B246LK7U.js → p-DhCqK4d8.js} +1 -1
  31. package/dist/vviinn-widgets/{p-818a1e53.entry.js → p-eb579723.entry.js} +1 -1
  32. package/{www/build/p-df9a1d66.entry.js → dist/vviinn-widgets/p-f9f4e909.entry.js} +1 -1
  33. package/dist/vviinn-widgets/vviinn-widgets.esm.js +1 -1
  34. package/package.json +1 -1
  35. package/www/build/p-08d39cc9.entry.js +1 -0
  36. package/www/build/{p-df4365fb.entry.js → p-1e2f9b9f.entry.js} +1 -1
  37. package/www/build/{p-c1eac87b.entry.js → p-3daed25b.entry.js} +1 -1
  38. package/www/build/{p-e969c76d.js → p-4f556dc3.js} +1 -1
  39. package/{dist/vviinn-widgets/p-Cxd6yzhY.js → www/build/p-CJAxBbhA.js} +1 -1
  40. package/www/build/{p-B246LK7U.js → p-DhCqK4d8.js} +1 -1
  41. package/www/build/{p-818a1e53.entry.js → p-eb579723.entry.js} +1 -1
  42. package/{dist/vviinn-widgets/p-df9a1d66.entry.js → www/build/p-f9f4e909.entry.js} +1 -1
  43. package/www/build/vviinn-widgets.esm.js +1 -1
  44. package/www/index.html +1 -1
  45. package/dist/vviinn-widgets/p-0b7e8e2e.entry.js +0 -1
  46. package/www/build/p-0b7e8e2e.entry.js +0 -1
@@ -1,8 +1,8 @@
1
1
  import { h, r as registerInstance, c as createEvent, H as Host, g as getElement, F as Fragment } from './index-B89nCb_F.js';
2
2
  import { _ as _functionExports, E as EitherExports, f as fold, b as fromImage, a as divideOnSized, e as isLeft, m as match, O as OptionExports } from './Rectangle-dmgo4KMB.js';
3
- import { t as toFile, c as makeUploadFileRequest, w as getImageSizes, v as version, f as campaignTypeNames, h as addIfNotEmpty, m as makeVisualSearchRequest, u as useSearchStore, x as checkImageType, g as getAcceptableFileFormats, d as setTextSearchQuery, y as resetStore, j as makeTextSearchRequest, z as makeProductListingPageRequest, A as checkDeviceType, p as parseStringToExcluded } from './search.store-Cgs5icgA.js';
3
+ import { t as toFile, c as makeUploadFileRequest, w as extractSelectedFilters, x as getImageSizes, v as version, f as campaignTypeNames, h as addIfNotEmpty, m as makeVisualSearchRequest, u as useSearchStore, y as checkImageType, g as getAcceptableFileFormats, d as setTextSearchQuery, z as resetStore, j as makeTextSearchRequest, A as makeProductListingPageRequest, B as checkDeviceType, p as parseStringToExcluded } from './search.store-lTerE9Yh.js';
4
4
  import { s as slotChangeListener, a as addEventListenersWithSignal, p as productCardSlotNames, v as vprIconSlotName, f as findSlotElements, g as getSlotNames, b as setElementInteractivity, S as SlotSkeleton } from './index-C1-PYhS4.js';
5
- import { g as getRemoveFilterAriaLabel, F as FilterIconClose, P as PlusIcon, R as RESULTS_CALCULATED_COLUMNS_CSS_VAR, c as createWidgetEvent, a as createFilterEvent, v as v4, b as createAddToBasketEvent, d as createAddToWishlistEvent, e as createResultEventByType, f as createProductEventByType, h as getCustomLabels, t as triggerFilter, i as triggerRemoveIntervalFilter, j as announceToScreenReader, s as syncRequestFilters, k as isSubFilterActive, l as RenderFilterButton, m as getIntervalLabel, n as createImageSearchEvent } from './index-CEzGPs5u.js';
5
+ import { g as getRemoveFilterAriaLabel, F as FilterIconClose, P as PlusIcon, R as RESULTS_CALCULATED_COLUMNS_CSS_VAR, c as createWidgetEvent, a as createFilterEvent, v as v4, b as createAddToBasketEvent, d as createAddToWishlistEvent, e as createResultEventByType, f as createProductEventByType, h as getCustomLabels, t as triggerFilter, i as triggerRemoveIntervalFilter, j as announceToScreenReader, s as syncRequestFilters, k as isSubFilterActive, l as RenderFilterButton, m as getIntervalLabel, n as createImageSearchEvent } from './index-DQQYIioG.js';
6
6
  import { i as instance, t as trackEvent, a as isTrackingEnabled, d as defaultConfig } from './store-BJxQCbNV.js';
7
7
  import { M as MIN_SEARCH_AREA_SIZE, S as SUPPORTED_ASPECT_RATIO, a as MIN_IMAGE_SIDE_FOR_CROPPER, C as Cropper, c as cropperOptions, g as getCropBoxData, i as isCropBoxChangeMinimal, D as DEFAULT_IMAGE_SIZE } from './cropperUtils-CkB6bG3L.js';
8
8
  import { r as renderExternalCSS } from './cssUrlHelper-Byz4s-MD.js';
@@ -244,6 +244,46 @@ const ValidateCropBoxData = (cropBoxData) => {
244
244
  return result;
245
245
  };
246
246
 
247
+ const MODALITY_COLUMN = "modality";
248
+ const OCR_VALUE = "OCR";
249
+ const hasSelectedOcrFilter = (dynamicFilters) => extractSelectedFilters(dynamicFilters !== null && dynamicFilters !== void 0 ? dynamicFilters : []).some((filter) => filter.column === MODALITY_COLUMN && filter.values.includes(OCR_VALUE));
250
+
251
+ /**
252
+ * Decides whether the cropper must be hidden because an OCR filter is active.
253
+ * Once the user adjusts the crop box the cropper stays regardless of OCR.
254
+ * Engagement resets whenever a different image is loaded.
255
+ */
256
+ class CropperOcrGate {
257
+ constructor() {
258
+ this.engaged = false;
259
+ this.lastImage = null;
260
+ this.awaitingFilters = false;
261
+ }
262
+ /** Re-arm OCR gating for a freshly loaded image. */
263
+ onImage(image) {
264
+ if (image === this.lastImage)
265
+ return;
266
+ this.lastImage = image;
267
+ this.engaged = false;
268
+ this.awaitingFilters = true;
269
+ }
270
+ /** Fresh dynamicFilters for the current image have arrived. */
271
+ onFreshFilters() {
272
+ this.awaitingFilters = false;
273
+ }
274
+ /** Mark that the user started working with the cropper. */
275
+ onUserAdjust() {
276
+ this.engaged = true;
277
+ }
278
+ /** True when the cropper should be hidden. */
279
+ isGated(dynamicFilters, isSearchLoading = false) {
280
+ // Defer while the image's search is still resolving, to avoid a flash.
281
+ if (this.awaitingFilters && isSearchLoading)
282
+ return true;
283
+ return !this.engaged && hasSelectedOcrFilter(dynamicFilters);
284
+ }
285
+ }
286
+
247
287
  const VviinnCropper = class {
248
288
  constructor(hostRef) {
249
289
  registerInstance(this, hostRef);
@@ -266,6 +306,45 @@ const VviinnCropper = class {
266
306
  this.showInWidget = false;
267
307
  this.cropper = null;
268
308
  this.selectedDetectedObject = null;
309
+ this.imageElement = null;
310
+ this.gate = new CropperOcrGate();
311
+ this.destroyCropper = () => {
312
+ var _a;
313
+ (_a = this.cropper) === null || _a === void 0 ? void 0 : _a.destroy();
314
+ this.cropper = null;
315
+ };
316
+ this.clearCropSelection = () => {
317
+ this.state.searchArea = null;
318
+ this.state.croppedImageUrl = null;
319
+ this.selectedDetectedObject = null;
320
+ };
321
+ /** Tear down the cropper and drop any applied crop. */
322
+ this.discardCrop = () => {
323
+ this.destroyCropper();
324
+ this.clearCropSelection();
325
+ };
326
+ this.resetCropperState = () => {
327
+ this.discardCrop();
328
+ this.state.image = null;
329
+ };
330
+ /** Show or hide the cropper to match the current OCR gate decision. */
331
+ this.reconcileCropper = () => {
332
+ // Trust the fresh filters even before the image DOM is ready.
333
+ this.gate.onFreshFilters();
334
+ if (!this.state.image || !this.imageElement || !this.state.imageBounds)
335
+ return;
336
+ if (this.gate.isGated(this.state.dynamicFilters)) {
337
+ // Drop only the frame, keep the region/object so OCR searches within it.
338
+ this.destroyCropper();
339
+ return;
340
+ }
341
+ // Guard geometry here so initCropper doesn't re-emit the aspect-ratio error on every filter change.
342
+ if (!this.cropper &&
343
+ this.hasSupportedAspectRatio() &&
344
+ this.hasSupportedSize()) {
345
+ this.initCropper(this.imageElement);
346
+ }
347
+ };
269
348
  this.initPreloadedImage = () => {
270
349
  var _a;
271
350
  if (this.showInWidget && this.state.image) {
@@ -289,14 +368,12 @@ const VviinnCropper = class {
289
368
  cleanLocalStorage();
290
369
  };
291
370
  this.resetStateHandler = ({ detail, }) => {
292
- var _a, _b;
371
+ var _a;
293
372
  if (this.skipStateChanges(detail.isTriggeredByVpsWidget))
294
373
  return;
295
- this.selectedDetectedObject = null;
296
374
  (_a = this.state.image) === null || _a === void 0 ? void 0 : _a.setAttribute("src", "");
297
375
  this.state.detectedObjects = [];
298
- this.state.image = null;
299
- (_b = this.cropper) === null || _b === void 0 ? void 0 : _b.destroy();
376
+ this.resetCropperState();
300
377
  cleanLocalStorage();
301
378
  };
302
379
  this.resetCropAreaHandler = ({ detail, }) => {
@@ -304,9 +381,7 @@ const VviinnCropper = class {
304
381
  if (this.skipStateChanges(detail.isTriggeredByVpsWidget))
305
382
  return;
306
383
  (_a = this.cropper) === null || _a === void 0 ? void 0 : _a.reset();
307
- this.state.searchArea = null;
308
- this.state.croppedImageUrl = null;
309
- this.selectedDetectedObject = null;
384
+ this.clearCropSelection();
310
385
  this.vviinnImageCrop.emit({
311
386
  isTriggeredByVpsWidget: this.showInWidget,
312
387
  });
@@ -334,32 +409,62 @@ const VviinnCropper = class {
334
409
  this.cropper.replace(this.state.image.src);
335
410
  };
336
411
  this.loadImage = () => {
337
- const renderedImageElement = this.el.shadowRoot.querySelector("img");
338
- if (this.state.image) {
339
- let data = {};
340
- if (this.cropper) {
341
- data = this.cropper.getData(true);
342
- this.cropper.destroy();
343
- }
344
- const imageBounds = fromImage(renderedImageElement);
345
- const { width, height } = imageBounds;
346
- this.vviinnCropperLoadImage.emit({
347
- imageBounds,
348
- });
349
- this.state.imageBounds = imageBounds;
350
- if (width / height < SUPPORTED_ASPECT_RATIO ||
351
- height / width < SUPPORTED_ASPECT_RATIO) {
352
- this.vviinnCropperAspectRatioError.emit(true);
353
- return;
354
- }
355
- if (width < MIN_IMAGE_SIDE_FOR_CROPPER ||
356
- height < MIN_IMAGE_SIDE_FOR_CROPPER) {
357
- return;
358
- }
359
- this.cropper = new Cropper(renderedImageElement, Object.assign(Object.assign({}, cropperOptions), { cropstart: this.cropStart, cropend: this.cropEnd, ready: () => this.cropper.reset(), data }));
412
+ var _a;
413
+ if (!this.state.image)
414
+ return;
415
+ const renderedImageElement = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector("img");
416
+ if (!renderedImageElement)
417
+ return;
418
+ this.imageElement = renderedImageElement;
419
+ this.gate.onImage(this.state.image);
420
+ let data = {};
421
+ if (this.cropper) {
422
+ data = this.cropper.getData(true);
423
+ this.destroyCropper();
424
+ }
425
+ const imageBounds = fromImage(renderedImageElement);
426
+ this.vviinnCropperLoadImage.emit({
427
+ imageBounds,
428
+ });
429
+ this.state.imageBounds = imageBounds;
430
+ const isSearchLoading = this.state.searchStatus === "loading";
431
+ if (this.gate.isGated(this.state.dynamicFilters, isSearchLoading)) {
432
+ this.discardCrop();
433
+ // Still surface aspect-ratio errors while hidden — geometry matters regardless.
434
+ this.checkAspectRatio();
435
+ return;
360
436
  }
437
+ this.initCropper(renderedImageElement, data);
438
+ };
439
+ this.hasSupportedAspectRatio = () => {
440
+ if (!this.state.imageBounds)
441
+ return false;
442
+ const { width, height } = this.state.imageBounds;
443
+ return (width / height >= SUPPORTED_ASPECT_RATIO &&
444
+ height / width >= SUPPORTED_ASPECT_RATIO);
445
+ };
446
+ this.hasSupportedSize = () => {
447
+ if (!this.state.imageBounds)
448
+ return false;
449
+ const { width, height } = this.state.imageBounds;
450
+ return (width >= MIN_IMAGE_SIDE_FOR_CROPPER &&
451
+ height >= MIN_IMAGE_SIDE_FOR_CROPPER);
452
+ };
453
+ this.checkAspectRatio = () => {
454
+ if (this.hasSupportedAspectRatio())
455
+ return true;
456
+ this.vviinnCropperAspectRatioError.emit(true);
457
+ return false;
458
+ };
459
+ this.initCropper = (imageElement, data = {}) => {
460
+ if (!imageElement)
461
+ return;
462
+ if (!this.checkAspectRatio() || !this.hasSupportedSize())
463
+ return;
464
+ this.cropper = new Cropper(imageElement, Object.assign(Object.assign({}, cropperOptions), { cropstart: this.cropStart, cropend: this.cropEnd, ready: () => { var _a; return (_a = this.cropper) === null || _a === void 0 ? void 0 : _a.reset(); }, data }));
361
465
  };
362
466
  this.cropStart = () => {
467
+ this.gate.onUserAdjust();
363
468
  this.startEndCropBoxData = getCropBoxData(this.cropper);
364
469
  };
365
470
  this.cropEnd = () => {
@@ -385,9 +490,10 @@ const VviinnCropper = class {
385
490
  !this.showAspectRatioError;
386
491
  }
387
492
  connectedCallback() {
388
- const { state, storeName } = useSearchStore(this.showInWidget);
493
+ const { state, storeName, onChange } = useSearchStore(this.showInWidget);
389
494
  this.state = state;
390
495
  this.storeName = storeName;
496
+ this.disposeStoreListener = onChange("dynamicFilters", this.reconcileCropper);
391
497
  this.initPreloadedImage();
392
498
  this.eventAbortController = new AbortController();
393
499
  const { signal } = this.eventAbortController;
@@ -398,10 +504,13 @@ const VviinnCropper = class {
398
504
  ], signal);
399
505
  }
400
506
  disconnectedCallback() {
401
- var _a, _b, _c;
507
+ var _a, _b;
402
508
  (_a = this.eventAbortController) === null || _a === void 0 ? void 0 : _a.abort();
403
- (_c = (_b = this.cropper) === null || _b === void 0 ? void 0 : _b.destroy) === null || _c === void 0 ? void 0 : _c.call(_b);
404
- this.state.image = null;
509
+ (_b = this.disposeStoreListener) === null || _b === void 0 ? void 0 : _b.call(this);
510
+ this.destroyCropper();
511
+ // "never" keeps no image across mounts, so clear it from the shared store.
512
+ if (this.saveImageMode === "never")
513
+ this.state.image = null;
405
514
  }
406
515
  selectDetectedObject({ detail }) {
407
516
  this.selectedDetectedObject = detail.detectedObject;
@@ -434,14 +543,14 @@ const VviinnCropper = class {
434
543
  }
435
544
  render() {
436
545
  var _a;
437
- return (h(Host, { key: 'ae2656d0782e723ffe5c8ba9ad6074db55e219c0', class: {
546
+ return (h(Host, { key: 'b50ccb5595b27ef6673ff9d9350fc30359a6f7ce', class: {
438
547
  "show-in-widget": this.showInWidget,
439
548
  active: !!this.state.image,
440
- } }, renderExternalCSS(this.cssUrl), h("div", { key: '0c547762649ddc68aa2755681c6637ec1556b315', class: "container" }, this.state.image && (h("div", { key: '811e79aaf4ee1144c8c6ce0017300ba9aeda8803', class: "image-container", style: {
549
+ } }, renderExternalCSS(this.cssUrl), h("div", { key: 'efd816ed4e19082091567714fee4ef40efe9a6c4', class: "container" }, this.state.image && (h("div", { key: '13f35758ba243eb73513e17375daca8431538383', class: "image-container", style: {
441
550
  width: `${this.width.toString()}px`,
442
551
  overflow: "hidden",
443
- } }, h("img", { key: '458474fa006a1397daa335fb9ee50477ab0e62ce', decoding: "async", width: this.width, height: this.height, src: this.state.image.src, draggable: false, onLoad: this.loadImage, alt: instance.t("a11y.cropperImage") }), (_a = this.state.detectedObjects) === null || _a === void 0 ? void 0 :
444
- _a.map((object) => (h("vviinn-detected-object", { detectedObject: object, selectedDetectedObject: this.selectedDetectedObject, basicEventData: this.basicEventData, imageBounds: this.state.imageBounds, showInWidget: this.showInWidget }))))), this.showPreloader() && (h("div", { key: 'd002cf170858ae7e5a46ca0f36bc64a425990119', class: "image-preloader" }, h("vviinn-preloader", { key: '2867876e7f492364528636d4b77dc4c7f80bee71' }))))));
552
+ } }, h("img", { key: '7525aae0654325fb25c88106a9ee1fface11a62e', decoding: "async", width: this.width, height: this.height, src: this.state.image.src, draggable: false, onLoad: this.loadImage, alt: instance.t("a11y.cropperImage") }), (_a = this.state.detectedObjects) === null || _a === void 0 ? void 0 :
553
+ _a.map((object) => (h("vviinn-detected-object", { detectedObject: object, selectedDetectedObject: this.selectedDetectedObject, basicEventData: this.basicEventData, imageBounds: this.state.imageBounds, showInWidget: this.showInWidget }))))), this.showPreloader() && (h("div", { key: 'b89ad46bda5279b77f4fe258f7a6d4af08f81c29', class: "image-preloader" }, h("vviinn-preloader", { key: '34f55578c05321480d7e3d8141a4638df8aad08b' }))))));
445
554
  }
446
555
  get el() { return getElement(this); }
447
556
  };
@@ -1038,13 +1147,13 @@ const VviinnResults = class {
1038
1147
  render() {
1039
1148
  var _a;
1040
1149
  const resultsLength = this.getResults().length;
1041
- return (h(Host, { key: '0767d0c21dee72b9a0f09a80dfe2ca7c375e4d50', id: "results-block", class: {
1150
+ return (h(Host, { key: 'd62957bb1294f3a62e14fa9a3eb97c7ef6007eae', id: "results-block", class: {
1042
1151
  "show-in-widget": this.showInWidget,
1043
1152
  "matching-discovery": this.oneClickDiscoveryMode === "append-slider",
1044
- }, exportparts: `${productCardParts}, ${listCardParts}, ${contentCardParts}, ${productCardsGridPart}` }, renderExternalCSS(this.cssUrl), h("div", { key: 'bfd01f2bf39be84501ce0cf42f5672acda3e500b', class: "nothing-found" }, this.getCurrentErrorType() && (h("vviinn-error", { key: 'ce077ad92253c7727a509567571d821ebda6dbd4', errorType: this.getCurrentErrorType(), handler: this.resetWidgetState, hasBackground: this.showInWidget, searchType: this.state.searchType }))), h("div", { key: 'dc63984664328f04abe6011aa0db856cb862f37c', class: {
1153
+ }, exportparts: `${productCardParts}, ${listCardParts}, ${contentCardParts}, ${productCardsGridPart}` }, renderExternalCSS(this.cssUrl), h("div", { key: '69f7a38dc02f42c357dbae8cf154ecb78380f270', class: "nothing-found" }, this.getCurrentErrorType() && (h("vviinn-error", { key: 'd78ed9f6d777d7ec1686b10b709deee018c4391e', errorType: this.getCurrentErrorType(), handler: this.resetWidgetState, hasBackground: this.showInWidget, searchType: this.state.searchType }))), h("div", { key: 'be3db62dcfd508b6f60036454d3c825d6c27f5ae', class: {
1045
1154
  hidden: this.showAspectRatioError || resultsLength === 0,
1046
1155
  products: true,
1047
- }, part: productCardsGridPart, id: "vviinn-results-products" }, resultsLength > 0 && this.renderResults(), h("div", { key: '2e39c5d65c5c7981c0b9a93dfe97ad62165a25b4', id: "one-click-discovery-append", style: {
1156
+ }, part: productCardsGridPart, id: "vviinn-results-products" }, resultsLength > 0 && this.renderResults(), h("div", { key: '88d3d2d5880806b9e24799694cc540de676d17f8', id: "one-click-discovery-append", style: {
1048
1157
  order: ((_a = this.oneClickDiscoveryAppendIndex) !== null && _a !== void 0 ? _a : resultsLength).toString(),
1049
1158
  } }))));
1050
1159
  }
@@ -1,8 +1,8 @@
1
1
  import { h, r as registerInstance, c as createEvent, f as forceUpdate, F as Fragment, H as Host, g as getElement } from './index-B89nCb_F.js';
2
- import { f as campaignTypeNames, h as addIfNotEmpty, _ as _ArrayExports, u as useSearchStore, B as isMobile, C as fromString, D as fold, v as version } from './search.store-Cgs5icgA.js';
2
+ import { f as campaignTypeNames, h as addIfNotEmpty, _ as _ArrayExports, u as useSearchStore, C as isMobile, D as fromString, E as fold, v as version } from './search.store-lTerE9Yh.js';
3
3
  import { X as has, Y as tuple, _ as _functionExports, g as requireSemigroup, O as OptionExports, v as pipe$1, N as chainW, Z as makeRequest, L as fromEither, $ as resolveApiPath, a0 as createInitPostRequest, a1 as Apply, a2 as TaskEitherExports, E as EitherExports } from './Rectangle-dmgo4KMB.js';
4
4
  import { i as instance, d as defaultConfig, t as trackEvent, a as isTrackingEnabled } from './store-BJxQCbNV.js';
5
- import { S as SET_MODE_IMAGE_WIDTH_CSS_VAR, C as CONTENT_GROUP_CSS_CLASS, o as CAROUSEL_IMAGE_WIDTH_CSS_VAR, p as CAROUSEL_CONTENT_WIDTH_CSS_VAR, R as RESULTS_CALCULATED_COLUMNS_CSS_VAR, q as CAROUSEL_COLUMNS_CSS_VAR, D as DEFAULT_COLUMNS_NUMBER, h as getCustomLabels, r as SCROLL_POSITION_TOLERANCE, u as triggerResetFilters, t as triggerFilter, j as announceToScreenReader, m as getIntervalLabel, w as isPriceFilter, k as isSubFilterActive, l as RenderFilterButton, s as syncRequestFilters, P as PlusIcon, x as CUSTOM_LABELS_DELIMITER, v as v4, c as createWidgetEvent, e as createResultEventByType, b as createAddToBasketEvent, d as createAddToWishlistEvent, f as createProductEventByType, y as getRecommendationsBody } from './index-CEzGPs5u.js';
5
+ import { S as SET_MODE_IMAGE_WIDTH_CSS_VAR, C as CONTENT_GROUP_CSS_CLASS, o as CAROUSEL_IMAGE_WIDTH_CSS_VAR, p as CAROUSEL_CONTENT_WIDTH_CSS_VAR, R as RESULTS_CALCULATED_COLUMNS_CSS_VAR, q as CAROUSEL_COLUMNS_CSS_VAR, D as DEFAULT_COLUMNS_NUMBER, h as getCustomLabels, r as SCROLL_POSITION_TOLERANCE, u as triggerResetFilters, t as triggerFilter, j as announceToScreenReader, m as getIntervalLabel, w as isPriceFilter, k as isSubFilterActive, l as RenderFilterButton, s as syncRequestFilters, P as PlusIcon, x as CUSTOM_LABELS_DELIMITER, v as v4, c as createWidgetEvent, e as createResultEventByType, b as createAddToBasketEvent, d as createAddToWishlistEvent, f as createProductEventByType, y as getRecommendationsBody } from './index-DQQYIioG.js';
6
6
  import { P as PRODUCT_CARD_IMAGE_WIDTH, D as DISCOVERY_WIDGET_IMAGE_RESOLUTION_WIDTH, c as PRODUCT_CARD_IMAGE_RESOLUTION_WIDTH } from './constants-rqiiCPBX.js';
7
7
  import { s as slotChangeListener, a as addEventListenersWithSignal, i as isElementInSelector, S as SlotSkeleton } from './index-C1-PYhS4.js';
8
8
  import { o as energyLabelParts, i as initializeLocale, j as extendedFiltersParts, h as filtersParts, q as imageParts, e as contentCardParts, l as listCardParts, p as productCardParts, t as priceRangeParts } from './index-BCrstDkj.js';
@@ -654,57 +654,6 @@ const filterOptionsBySearch = (filterOptions, searchTerm) => {
654
654
 
655
655
  const vviinnFiltersCss$2 = ":host{--font-family-base:Inter, system-ui, sans-serif;--font-family-mono:monospace;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--font-size-display:32px;--font-size-title:24px;--font-size-headline:18px;--font-size-label-large:16px;--font-size-label:14px;--font-size-body-large:16px;--font-size-body:14px;--font-size-caption:12px;--line-height-display:40px;--line-height-title:32px;--line-height-headline:24px;--line-height-label-large:24px;--line-height-label:20px;--line-height-body-large:24px;--line-height-body:20px;--line-height-caption:16px;--letter-spacing-title:0px;--letter-spacing-headline:0px;--letter-spacing-label-large:0px;--letter-spacing-label:0px;--letter-spacing-body-large:0px;--letter-spacing-body:0px;--letter-spacing-caption:0px;--font-weight-400:400;--font-weight-500:500;--font-weight-600:600;--font-weight-700:700;--spacing-none:0px;--spacing-25:2px;--spacing-50:4px;--spacing-75:6px;--spacing-100:8px;--spacing-125:10px;--spacing-150:12px;--spacing-200:16px;--spacing-250:20px;--spacing-300:24px;--spacing-400:32px;--spacing-500:40px;--spacing-600:48px;--border-radius-none:0px;--border-radius-25:2px;--border-radius-50:4px;--border-radius-100:8px;--border-radius-150:12px;--border-radius-200:16px;--border-radius-300:24px;--border-radius-400:32px;--border-radius-full:9999px;--stroke-width-none:0px;--stroke-width-25:1px;--stroke-width-50:2px;--stroke-width-75:3px;--stroke-width-100:4px;--stroke-width-150:6px;--stroke-width-200:8px;--stroke-width-300:12px;--product-card-widget-min-width:135px;--product-card-results-min-width:250px;--image-set-mode-min-width:155px;--source-card-set-mode-max-width:500px;--filter-blur-none:0px;--filter-blur-100:8px;--filter-blur-150:12px;--filter-blur-200:16px;--color-bg-base:#ffffff;--color-bg-inverse:#161616;--color-border-00:#ffffff;--color-border-01:#f4f4f4;--color-border-02:#e0e0e0;--color-border-03:#c6c6c6;--color-border-inverse-00:#161616;--color-border-inverse-01:#393939;--color-field-01:#ffffff;--color-field-02:#f4f4f4;--color-icon-primary:#161616;--color-icon-secondary:#525252;--color-icon-helper:#8d8d8d;--color-icon-on-color:#ffffff;--color-icon-inverse:#ffffff;--color-icon-disabled:#16161640;--color-text-primary:#161616;--color-text-secondary:#707070;--color-text-helper:#8d8d8d;--color-text-placeholder:#a8a8a8;--color-text-on-color:#ffffff;--color-text-inverse:#ffffff;--color-text-disabled:#16161640;--button-bg-color-primary:#000000;--button-bg-color-primary-hover:#161616;--button-bg-color-primary-active:#1e1e1e;--button-bg-color-secondary:#f4f4f4;--button-bg-color-secondary-hover:#e0e0e0;--button-bg-color-secondary-active:#c6c6c6;--button-bg-color-ghost-hover:#f4f4f4;--button-bg-color-ghost-active:#eaeaea;--button-bg-color-frosted:#6f6f6f66;--button-bg-color-frosted-hover:#6f6f6f80;--button-bg-color-frosted-active:#6f6f6f99;--button-bg-color-disabled:#e0e0e0;--button-bg-color-positive:#dcfce7;--surface-bg-color-01:#f4f4f4;--surface-bg-color-01-hover:#eaeaea;--surface-bg-color-01-active:#e0e0e0;--surface-bg-color-02:#ffffff;--surface-bg-color-inverse:#262626;--surface-bg-color-inverse-hover:#303030;--surface-bg-color-inverse-active:#393939;--surface-bg-color-disabled:#e0e0e0;--surface-bg-color-shadow-01:#dddddd;--surface-bg-color-shadow-02:#c6c6c6;--chip-bg-color-primary:#161616;--chip-bg-color-primary-hover:#1e1e1e;--chip-bg-color-primary-active:#262626;--chip-bg-color-subtle:#f4f4f4;--chip-bg-color-subtle-hover:#eaeaea;--chip-bg-color-subtle-active:#e0e0e0;--chip-bg-color-outline-hover:#f4f4f4;--chip-bg-color-outline-active:#eaeaea;--label-bg-color-accent:#ff3944;--sidebar-animation-duration-default:0.5s;--search-modal-animation-duration-default:0.25s;--search-modal-animation-duration-mobile-default:0.35s;}:host{display:block;font-family:var(--font-family, var(--font-family-base));font-style:normal;display:contents;}.filters-modal-list,.sub-filters-wrapper,.main-filters-list,.filters-modal-sub-list,.selected-filters-wrapper{list-style:none;margin:0;padding:0}.main-filters-list{padding:var(--spacing-25);gap:var(--spacing-25);border-radius:8px;background:var(--surface-bg-color-01);display:inline-flex}vviinn-range-filter{width:100%;max-width:500px;padding-bottom:var(--spacing-150)}.filters-search-input-container{position:relative;box-sizing:border-box;width:100%;display:flex;align-items:center}.filters-search-icon{position:absolute;left:var(--spacing-100);color:var(--color-icon-helper);z-index:1;pointer-events:none;display:flex;align-items:center;justify-content:center}.filters-search-input{width:100%;padding:var(--spacing-100) var(--spacing-100) var(--spacing-100)\n var(--spacing-500);border:none;background:var(--color-bg-base);font-family:var(--font-family, var(--font-family-base));font-size:var(--font-size-body);font-weight:var(--font-weight-400);line-height:var(--line-height-body);color:var(--color-text-primary);box-sizing:border-box;outline:none}.filters-search-input::-moz-placeholder{color:var(--color-text-placeholder)}.filters-search-input::placeholder{color:var(--color-text-placeholder)}.filters-modal-main-button,.filters-sub-button,.filters-main-button,.filters-modal-close,.filters-sub-button-selected{font-family:var(--font-family, var(--font-family-base));cursor:pointer;border:none}.filters-sub-button,.filters-main-button{font-size:var(--font-size-body);font-weight:var(--font-weight-400);line-height:var(--line-height-body);letter-spacing:var(--letter-spacing-body);display:flex;justify-content:center;align-items:center;border-radius:6px}.filters-main-button{padding:var(--spacing-100);color:var(--color-text-secondary);background:none;transition:background 0.15s,\n color 0.15s}.filters-main-button.active,.filters-main-button:hover{background:var(--surface-bg-color-02);color:var(--color-text-primary)}.sub-filters-wrapper,.selected-filters-wrapper{gap:var(--spacing-100);display:flex;flex-direction:row;overflow-x:auto;scrollbar-width:thin}.sub-filters-wrapper{align-items:center;gap:var(--spacing-100);margin:16px -2px 0}.sub-filters-wrapper>li{padding:2px}.selected-filters-wrapper{align-items:center;gap:var(--spacing-100);flex-wrap:wrap}.filters-sub-button{color:var(--color-text-primary);background:var(--surface-bg-color-01);padding:var(--spacing-100);gap:var(--spacing-25);height:100%}.filters-sub-button>span,.filters-sub-button-selected>span{display:inline-flex;justify-content:center;align-items:center;gap:var(--spacing-25);white-space:nowrap}.filters-sub-button>span>span,.filters-sub-button-selected>span>span{padding:var(--spacing-25)}.filters-sub-button:hover{background:var(--surface-bg-color-01-hover)}.filters-sub-button:disabled{cursor:not-allowed;background:var(--surface-bg-color-disabled);color:var(--color-text-disabled)}.filters-more-button{display:flex;padding:var(--spacing-100);gap:var(--spacing-50);border-radius:var(--border-radius-100);align-items:flex-start;background-color:var(--button-bg-color-secondary);transition:background-color 0.1s;border:none;cursor:pointer}.filters-more-button:hover{background-color:var(--button-bg-color-secondary-hover)}.filters-modal-wrapper{display:flex;flex-direction:column;background:#ffffff}.filters-modal.button,.filters-modal.modal{display:none;position:fixed;top:0;bottom:0;right:0;left:0;z-index:99999;background-color:rgba(0, 0, 0, 0.5)}.filters-modal.button .filters-modal-wrapper{position:fixed;top:0;bottom:0;right:0;width:420px;z-index:99999;border-radius:var(--border-radius-400) var(--border-radius-none)\n var(--border-radius-none) var(--border-radius-400)}.filters-modal.preview{display:block}.filters-modal.open{display:block}.filters-modal-header{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;color:var(--color-text-primary);text-align:center;border-bottom:1px solid var(--color-border-01)}.filters-modal-header.show-header-content{min-height:64px}.filters-modal-title{margin:0;padding:0;font-size:var(--font-size-headline);font-weight:var(--font-weight-500);line-height:var(--line-height-headline);letter-spacing:var(--letter-spacing-headline)}.filters-modal-no-filters-message{font-size:var(--font-size-caption);color:var(--color-text-secondary);font-weight:var(--font-weight-500);line-height:var(--line-height-caption);letter-spacing:var(--letter-spacing-caption);text-align:center;padding:var(--spacing-300) var(--spacing-200);display:flex;align-items:center;justify-content:center}.filters-modal-main{overflow-y:auto;scrolbar-width:thin}.filters-modal-list{margin:var(--spacing-50) 0 0 var(--spacing-300)}.filters-modal-list>li{padding-right:var(--spacing-300)}.filters-modal:not(.preview-inline) .filters-modal-list>li:not(:last-child) .filters-modal-main-button-wrapper{border-bottom:1px solid var(--color-border-01)}.filters-modal-main-button{position:relative;width:100%;background:none;text-align:left;padding:var(--spacing-200) 0;color:var(--color-text-primary);font-size:var(--font-size-label-large);font-weight:var(--font-weight-500);line-height:var(--line-height-label-large);letter-spacing:var(--letter-spacing-label-large)}.filters-modal-main-button>svg{position:absolute;right:0;top:var(--spacing-200);color:var(--color-icon-helper);transform:rotate(90deg)}.filters-modal-main-button:hover>svg{color:var(--color-icon-primary);transition:color 0.2s}.filters-modal-main-button-wrapper.open .filters-modal-main-button>svg{transform:rotate(-90deg);color:var(--color-icon-primary)}.filters-modal-sub-list{display:none}.filters-modal-main-button-wrapper.open .filters-modal-sub-list{display:flex;align-items:center;flex-wrap:wrap;gap:8px;padding-bottom:var(--spacing-150)}.filters-modal-sub-list>li{display:contents}.filters-modal-close{position:absolute;color:#6f6f6f;right:var(--spacing-100);top:var(--spacing-200);cursor:pointer;background:none}.filters-modal-close:hover{color:#000}.filters-modal.preview .filters-modal-close{display:none}.filters-more-modal-button{background:none;border:none;cursor:pointer;display:flex;align-items:center;height:36px;padding:var(--spacing-75);gap:var(--spacing-50);border-radius:var(--border-radius-100);background-color:var(--surface-bg-color-01);transition:background-color 0.1s;font-family:var(--font-family, var(--font-family-base));font-size:var(--font-size-label);color:var(--color-text-primary)}.filters-more-modal-button.custom:not(.clickable){cursor:default}.filters-more-modal-button:hover{background-color:var(--surface-bg-color-01-hover)}.filters-more-modal-button.active{background:var(--surface-bg-color-inverse);color:var(--color-text-inverse)}.filters-more-modal-button.active .filters-option-icon-wrapper{border-color:var(--color-bg-base);background-color:var(--color-bg-base);color:var(--color-icon-primary)}.filters-more-modal-button>span{white-space:nowrap;padding:var(--spacing-25)}.filters-more-modal-button:disabled{cursor:not-allowed;opacity:0.5}.filters-more-modal-button img{box-sizing:border-box;-o-object-fit:cover;object-fit:cover;-o-object-position:center;object-position:center;border-radius:var(--border-radius-full);border:1px solid var(--color-border-01)}.filters-modal-actions{border-top:1px solid var(--color-border-01);padding:var(--spacing-125);z-index:10;border-radius:0px 0px 0px 32px}.filters-modal-apply,.filters-modal-reset{font-family:var(--font-family, var(--font-family-base))}.filters-modal-apply{cursor:pointer;width:100%;border:none;margin-bottom:20px;display:flex;padding:var(--spacing-150);justify-content:center;align-items:center;gap:var(--spacing-50);align-self:stretch;color:var(--color-text-inverse);text-align:center;border-radius:var(--border-radius-150);background:var(--button-bg-color-primary);font-size:var(--font-size-label-large);font-weight:var(--font-weight-500);line-height:var(--line-height-label-large);letter-spacing:var(--letter-spacing-label-large)}.filters-modal-apply:disabled{background:var(--button-bg-color-disabled);color:var(--color-text-disabled)}.filters-modal-reset{background:none;border:none;cursor:pointer;display:block;text-align:center;width:100%;padding:var(--spacing-125) 0;color:var(--color-text-secondary);text-align:center;font-size:var(--font-size-label);font-weight:var(--font-weight-500);line-height:var(--line-height-label);letter-spacing:var(--letter-spacing-label)}.filters-modal-reset:hover{color:var(--color-text-primary)}.selected-filters-wrapper>li .filters-sub-button-selected{border-radius:var(--border-radius-100);background:var(--surface-bg-color-inverse);display:flex;align-items:center;justify-content:center;cursor:pointer;padding:var(--spacing-100)}.selected-filters-wrapper>li.hidden{display:none}.filters-sub-button-selected{display:flex;align-items:center;gap:var(--spacing-25);background:var(--surface-bg-color-inverse);border-radius:var(--border-radius-100);color:var(--color-text-inverse);text-overflow:ellipsis;font-size:var(--font-size-body);font-weight:var(--font-weight-400);line-height:var(--line-height-body);letter-spacing:var(--letter-spacing-body);padding:var(--spacing-100)}.filters-sub-button-color-dot{box-sizing:border-box;width:24px;height:24px;border-radius:var(--border-radius-full);border:var(--stroke-width-50) solid var(--color-border-01)}.selected-filters-wrapper .filters-sub-button-selected{width:24px;height:24px;border:none}.filters-option-icon-wrapper{display:flex;box-sizing:border-box;align-items:center;justify-content:center;border-radius:4px;border:2px solid #e0e0e0;background:#fff;width:20px;height:20px}.filters-modal-main-button-added-options{color:var(--color-text-secondary);text-overflow:ellipsis;padding-right:var(--spacing-100);font-size:var(--font-size-body);font-weight:var(--font-weight-400);line-height:var(--line-height-body);letter-spacing:var(--letter-spacing-body)}.filters-modal-main-button-added-options>span::after{content:\", \"}.filters-modal-main-button-added-options>span:last-child::after{content:\"\"}.filters-modal.preview-inline,.filters-modal.preview-inline .filters-modal-wrapper,.filters-modal.preview-inline .filters-modal-main{overflow:visible}.filters-modal.preview-inline .filters-modal-header,.filters-modal.preview-inline .filters-modal-actions{display:none}.filters-modal.preview-inline .filters-modal-list{margin:0;flex-direction:row;gap:var(--spacing-100);display:flex;flex-wrap:wrap}.filters-modal.preview-inline .extended-filters-row{box-sizing:border-box;padding-right:0;border-radius:var(--border-radius-100);background:var(--surface-bg-color-01)}.filters-modal.preview-inline .filters-modal-main-button{width:100%;display:flex;align-items:center;padding:var(--spacing-75);gap:var(--spacing-25);justify-content:space-between;font-size:var(--font-size-body);font-weight:var(--font-weight-400)}.filters-modal.preview-inline .filters-modal-main-button>svg{position:static}.filters-modal.preview-inline .extended-filters-row{position:relative}.filters-modal.preview-inline .filters-search-container{max-height:225px;width:-moz-max-content;width:max-content;min-width:140px;height:-moz-fit-content;height:fit-content;overflow:hidden;position:absolute;display:flex;flex-direction:column;flex-wrap:nowrap;align-items:stretch;padding:0;top:calc(100% + var(--spacing-75));left:0;right:0;z-index:1000;border-radius:var(--border-radius-150);border:1px solid var(--color-border-01);background-color:var(--color-bg-base);box-shadow:0 4px 8px 0 rgba(0, 0, 0, 0.1);box-sizing:border-box}.filters-modal.preview-inline .filters-search-input-container{position:sticky;top:0;background-color:var(--color-bg-base);padding:var(--spacing-50);border-bottom:1px solid var(--color-border-01);z-index:1}.filters-modal.preview-inline .filters-modal-sub-list{position:static;border:none;background:none;box-shadow:none;padding:var(--spacing-50);margin:0;max-height:165px;width:100%;box-sizing:border-box;display:flex;flex-direction:column;flex-wrap:nowrap;align-items:flex-start;gap:8px;overflow-y:auto;scrollbar-width:thin}.filters-modal.preview-inline .align-right .filters-search-container{left:auto;right:0}.filters-modal.preview-inline .filters-more-modal-button{width:100%;gap:var(--spacing-150);background-color:var(--color-bg-base)}.filters-modal.preview-inline .filters-option-icon-wrapper{margin-left:auto}.filters-modal.preview-inline .filters-more-modal-button:hover{background-color:var(--surface-bg-color-01-hover)}.filters-modal.preview-inline .filters-more-modal-button.active{color:var(--color-text-primary)}.filters-modal.preview-inline .filters-more-modal-button.active .filters-option-icon-wrapper{border-color:var(--color-bg-inverse);background-color:var(--color-bg-inverse);color:var(--color-icon-inverse)}.filters-modal.preview-inline .filters-modal-sub-list:has(vviinn-range-filter){padding:0 var(--spacing-75);width:220px;max-height:unset}.filters-modal.preview-inline vviinn-range-filter{width:100%}@media (max-width: 768px){.sub-filters-wrapper,.selected-filters-wrapper{flex-wrap:unset;overflow-x:auto;scrollbar-width:none;padding-bottom:0}.sub-filters-wrapper,.selected-filters-wrapper{-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none}.sub-filters-wrapper::-webkit-scrollbar,.selected-filters-wrapper::-webkit-scrollbar{display:none}:host(.show-in-widget) .selected-filters-container{overflow-x:auto;width:100%}:host(.show-in-widget) .selected-filters-wrapper{padding:0 var(--spacing-300)}.filters-modal.button .filters-modal-wrapper,.filters-modal.modal .filters-modal-wrapper{width:100%;border-radius:24px 24px 0px 0px}.filters-modal.button .filters-modal-wrapper{top:10%}.filters-modal.modal .filters-modal-wrapper{position:fixed;width:100%;height:calc(100% - 64px);bottom:0;transform:translateY(-64px)}.filters-modal.modal .filters-modal-header{font-size:var(--font-size-body-large)}.filters-modal.modal .filters-modal-main{padding-bottom:120px}vviinn-range-filter{max-width:unset}:host(.show-in-widget.primary-filters) vviinn-range-filter{max-width:calc(100% - 48px);transform:translateX(24px)}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}";
656
656
 
657
- /**
658
- * @slot vviinn-extended-filters-title - Text on widget's header.
659
- * @slot vviinn-extended-filters-apply - Title of Apply Button.
660
- * @slot vviinn-extended-filters-reset - Title of Reset Button.
661
- * @slot vviinn-extended-filters-no-filters - Message shown when no filters are available.
662
- * @slot vviinn-filters-search-icon - Custom icon for the search input.
663
- * @slot vviinn-range-filter-from-label - Label text for the "From" input field in range filters.
664
- * @slot vviinn-range-filter-to-label - Label text for the "To" input field in range filters.
665
- *
666
- * @part extended-filters-modal - Modal itself.
667
- * @part extended-filters-modal-wrapper - Wrapper for the modal.
668
- * @part extended-filters-header - Header of the modal.
669
- * @part extended-filters-title - Title heading (h2) of the modal.
670
- * @part extended-filters-modal-close - Close button of the modal.
671
- * @part extended-filters-no-filters - No filters message container.
672
- * @part extended-filters-main - Wrapper for the main modal content.
673
- * @part extended-filters-list - List of filters.
674
- * @part extended-filters-row - Row of the filters.
675
- * @part extended-filters-row-wrapper - Wrapper for the row.
676
- * @part extended-filters-main-button - Main button of the row.
677
- * @part extended-filters-selected-wrapper - Wrapper for the selected options.
678
- * @part extended-filters-sub-list - List of sub filters.
679
- * @part extended-filters-actions - Wrapper for the actions.
680
- * @part extended-filters-apply - Apply button.
681
- * @part extended-filters-reset - Reset button.
682
- *
683
- * @part filters-search-container - Container wrapping search input and filter list.
684
- * @part filters-search-input-container - Container for the search input with icon.
685
- * @part filters-search-icon - Icon wrapper for the search input.
686
- * @part filters-search-input - Search input field.
687
- *
688
- * @part filters-sub-row - Row of the sub filters.
689
- * @part filters-option-button - Button of the sub filter.
690
- * @part filters-option-image - Image of the sub filter.
691
- * @part filters-option-color-dot - Color Dot of the sub filter.
692
- * @part filters-option-text - Text of the sub filter.
693
- * @part filters-option-icon-wrapper - Icon Wrapper of the sub filter.
694
- *
695
- * @part histogram - Wrapper itself.
696
- * @part histogram-bar - Bar of the histogram.
697
- * @part histogram-range-container - Container for the range sliders.
698
- * @part histogram-sliders-control - Container for the range sliders control.
699
- * @part histogram-from-slider - Slider for the minimum value.
700
- * @part histogram-to-slider - Slider for the maximum value.
701
- * @part histogram-label-wrapper - Wrapper for the labels/inputs.
702
- * @part histogram-label - Label for the histogram (when showIntervalInputs is false).
703
- * @part histogram-input-container - Container for the input field (when showIntervalInputs is true).
704
- * @part histogram-input-label - Label text for the input (From/Till).
705
- * @part histogram-from-input - Input field for the minimum value.
706
- * @part histogram-to-input - Input field for the maximum value.
707
- */
708
657
  const FILTER_OPTIONS_INITIAL_COUNT = 8;
709
658
  const FILTER_OPTIONS_STEP_COUNT = 5;
710
659
  const VviinnExtendedFilters = class {
@@ -2,7 +2,7 @@ import { h, r as registerInstance, c as createEvent, H as Host, g as getElement
2
2
  import { a as divideOnSized, E as EitherExports } from './Rectangle-dmgo4KMB.js';
3
3
  import { C as Cropper, c as cropperOptions, g as getCropBoxData, i as isCropBoxChangeMinimal } from './cropperUtils-CkB6bG3L.js';
4
4
  import { g as getSwiperStyles, c as configureSwiperElement, r as register, e as extractSlideIndex, s as setupIntersectionObserver } from './swiper-element-Er2KrWw1.js';
5
- import { i as isDesktop$1, s as shopTheLookState, m as makeVisualSearchRequest, a as makeVisualSearchByUrlRequest, b as imageFromFileTask, c as makeUploadFileRequest, g as getAcceptableFileFormats } from './search.store-Cgs5icgA.js';
5
+ import { i as isDesktop$1, s as shopTheLookState, m as makeVisualSearchRequest, a as makeVisualSearchByUrlRequest, b as imageFromFileTask, c as makeUploadFileRequest, g as getAcceptableFileFormats } from './search.store-lTerE9Yh.js';
6
6
  import { S as SecondaryActionIcon } from './SecondaryActionIcon-D4f3aMUD.js';
7
7
  import { i as initializeLocale, a as shopTheLookParts } from './index-BCrstDkj.js';
8
8
  import { d as defaultConfig } from './store-BJxQCbNV.js';
@@ -1,6 +1,6 @@
1
1
  import { h, r as registerInstance, c as createEvent, H as Host, g as getElement } from './index-B89nCb_F.js';
2
2
  import { _ as _functionExports, f as fold } from './Rectangle-dmgo4KMB.js';
3
- import { d as setTextSearchQuery, e as makeAutoSuggestRequest, v as version, f as campaignTypeNames, h as addIfNotEmpty, j as makeTextSearchRequest, u as useSearchStore } from './search.store-Cgs5icgA.js';
3
+ import { d as setTextSearchQuery, e as makeAutoSuggestRequest, v as version, f as campaignTypeNames, h as addIfNotEmpty, j as makeTextSearchRequest, u as useSearchStore } from './search.store-lTerE9Yh.js';
4
4
  import { s as slotChangeListener, f as findSlotElements } from './index-C1-PYhS4.js';
5
5
  import { i as instance, d as defaultConfig } from './store-BJxQCbNV.js';
6
6
  import { i as initializeLocale, b as searchBarParts, s as searchModalFirstScreenParts } from './index-BCrstDkj.js';
@@ -9,10 +9,9 @@ const data = {
9
9
  filterValue: "Möbel > Schränke & Regale",
10
10
  description: "company: 'vviinn', site: 'widgets.vviinn.home&living'",
11
11
  shopTheLookImageUrls: [
12
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/home_01.jpg",
13
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/home_02.jpg",
14
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/home_03.jpg",
15
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/home_04.jpg",
12
+ "https://cdn.vviinn.com/assets/merchant/default/shop-the-look-v2/home_01v2.jpg",
13
+ "https://cdn.vviinn.com/assets/merchant/default/shop-the-look-v2/home_02v2.jpg",
14
+ "https://cdn.vviinn.com/assets/merchant/default/shop-the-look-v2/home_03v2.jpg",
16
15
  ],
17
16
  },
18
17
  fashion: {
@@ -23,10 +22,9 @@ const data = {
23
22
  filterValue: "Beauty > Düfte",
24
23
  description: "company: 'Vviinn Demo Company', site: 'widgets.vviinn.fashion'",
25
24
  shopTheLookImageUrls: [
26
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/fashion_01.jpg",
27
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/fashion_02.jpg",
28
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/fashion_03.jpg",
29
- "https://cdn.vviinn.com/assets/merchant/default/shop-the-look/fashion_04.jpg",
25
+ "https://cdn.vviinn.com/assets/merchant/default/shop-the-look-v2/fashion_01v2.jpg",
26
+ "https://cdn.vviinn.com/assets/merchant/default/shop-the-look-v2/fashion_02v2.jpg",
27
+ "https://cdn.vviinn.com/assets/merchant/default/shop-the-look-v2/fashion_03v2.jpg",
30
28
  ],
31
29
  },
32
30
  "manufacturer-spare-parts": {
@@ -0,0 +1,19 @@
1
+ import { ResponseDynamicFilterItem } from "../../../interfaces";
2
+ /**
3
+ * Decides whether the cropper must be hidden because an OCR filter is active.
4
+ * Once the user adjusts the crop box the cropper stays regardless of OCR.
5
+ * Engagement resets whenever a different image is loaded.
6
+ */
7
+ export declare class CropperOcrGate {
8
+ private engaged;
9
+ private lastImage;
10
+ private awaitingFilters;
11
+ /** Re-arm OCR gating for a freshly loaded image. */
12
+ onImage(image: HTMLImageElement | null): void;
13
+ /** Fresh dynamicFilters for the current image have arrived. */
14
+ onFreshFilters(): void;
15
+ /** Mark that the user started working with the cropper. */
16
+ onUserAdjust(): void;
17
+ /** True when the cropper should be hidden. */
18
+ isGated(dynamicFilters: ResponseDynamicFilterItem[] | undefined, isSearchLoading?: boolean): boolean;
19
+ }
@@ -0,0 +1,2 @@
1
+ import { ResponseDynamicFilterItem } from "../../../interfaces";
2
+ export declare const hasSelectedOcrFilter: (dynamicFilters: ResponseDynamicFilterItem[] | undefined) => boolean;
@@ -44,8 +44,18 @@ export declare class VviinnCropper {
44
44
  private storeName?;
45
45
  private startEndCropBoxData?;
46
46
  private eventAbortController?;
47
+ private disposeStoreListener?;
48
+ private imageElement;
49
+ private gate;
47
50
  connectedCallback(): void;
48
51
  disconnectedCallback(): void;
52
+ private destroyCropper;
53
+ private clearCropSelection;
54
+ /** Tear down the cropper and drop any applied crop. */
55
+ private discardCrop;
56
+ private resetCropperState;
57
+ /** Show or hide the cropper to match the current OCR gate decision. */
58
+ private reconcileCropper;
49
59
  private initPreloadedImage;
50
60
  private resetStateHandler;
51
61
  private resetCropAreaHandler;
@@ -56,6 +66,10 @@ export declare class VviinnCropper {
56
66
  selectDetectedObject({ detail }: CustomEvent<SelectObjectEventData>): void;
57
67
  imageCropHandler({ detail }: CustomEvent<TriggerSourceEventData>): void;
58
68
  private loadImage;
69
+ private hasSupportedAspectRatio;
70
+ private hasSupportedSize;
71
+ private checkAspectRatio;
72
+ private initCropper;
59
73
  private cropStart;
60
74
  private cropEnd;
61
75
  private showPreloader;
@@ -2,6 +2,57 @@ import { EventEmitter } from "../../stencil-public-runtime";
2
2
  import { ResponseDynamicFilterItem, RequestDynamicFilterItem } from "../../campaign/VPRCampaignService";
3
3
  import { Locale } from "../../locale";
4
4
  import { ChangedFiltersEventData, DynamicFilterTrackingData, TriggerSourceEventData } from "../../recommendation/events";
5
+ /**
6
+ * @slot vviinn-extended-filters-title - Text on widget's header.
7
+ * @slot vviinn-extended-filters-apply - Title of Apply Button.
8
+ * @slot vviinn-extended-filters-reset - Title of Reset Button.
9
+ * @slot vviinn-extended-filters-no-filters - Message shown when no filters are available.
10
+ * @slot vviinn-filters-search-icon - Custom icon for the search input.
11
+ * @slot vviinn-range-filter-from-label - Label text for the "From" input field in range filters.
12
+ * @slot vviinn-range-filter-to-label - Label text for the "To" input field in range filters.
13
+ *
14
+ * @part extended-filters-modal - Modal itself.
15
+ * @part extended-filters-modal-wrapper - Wrapper for the modal.
16
+ * @part extended-filters-header - Header of the modal.
17
+ * @part extended-filters-title - Title heading (h2) of the modal.
18
+ * @part extended-filters-modal-close - Close button of the modal.
19
+ * @part extended-filters-no-filters - No filters message container.
20
+ * @part extended-filters-main - Wrapper for the main modal content.
21
+ * @part extended-filters-list - List of filters.
22
+ * @part extended-filters-row - Row of the filters.
23
+ * @part extended-filters-row-wrapper - Wrapper for the row.
24
+ * @part extended-filters-main-button - Main button of the row.
25
+ * @part extended-filters-selected-wrapper - Wrapper for the selected options.
26
+ * @part extended-filters-sub-list - List of sub filters.
27
+ * @part extended-filters-actions - Wrapper for the actions.
28
+ * @part extended-filters-apply - Apply button.
29
+ * @part extended-filters-reset - Reset button.
30
+ *
31
+ * @part filters-search-container - Container wrapping search input and filter list.
32
+ * @part filters-search-input-container - Container for the search input with icon.
33
+ * @part filters-search-icon - Icon wrapper for the search input.
34
+ * @part filters-search-input - Search input field.
35
+ *
36
+ * @part filters-sub-row - Row of the sub filters.
37
+ * @part filters-option-button - Button of the sub filter.
38
+ * @part filters-option-image - Image of the sub filter.
39
+ * @part filters-option-color-dot - Color Dot of the sub filter.
40
+ * @part filters-option-text - Text of the sub filter.
41
+ * @part filters-option-icon-wrapper - Icon Wrapper of the sub filter.
42
+ *
43
+ * @part histogram - Wrapper itself.
44
+ * @part histogram-bar - Bar of the histogram.
45
+ * @part histogram-range-container - Container for the range sliders.
46
+ * @part histogram-sliders-control - Container for the range sliders control.
47
+ * @part histogram-from-slider - Slider for the minimum value.
48
+ * @part histogram-to-slider - Slider for the maximum value.
49
+ * @part histogram-label-wrapper - Wrapper for the labels/inputs.
50
+ * @part histogram-label - Label for the histogram (when showIntervalInputs is false).
51
+ * @part histogram-input-container - Container for the input field (when showIntervalInputs is true).
52
+ * @part histogram-input-label - Label text for the input (From/Till).
53
+ * @part histogram-from-input - Input field for the minimum value.
54
+ * @part histogram-to-input - Input field for the maximum value.
55
+ */
5
56
  export declare class VviinnExtendedFilters {
6
57
  el: HTMLElement;
7
58
  mode: "button" | "preview" | "preview-inline" | "modal";
@@ -2,6 +2,7 @@ import { EventEmitter } from "../../stencil-public-runtime";
2
2
  import { BasicEventData, Locale, Recommendation } from "../../components";
3
3
  import { ChangedFiltersEventData, ProductCardEvent, ProductCardEventData, TextSearchEventData, TriggerSourceEventData } from "../../recommendation/events";
4
4
  import { OneClickDiscoveryMode } from "../../widget/types";
5
+ export type ReplaceSlotsContentInParent = (childrenElement?: HTMLElement) => void;
5
6
  /**
6
7
  * @part products - Products container.
7
8
  * @part product-card - Product Card itself.
@@ -77,7 +78,6 @@ import { OneClickDiscoveryMode } from "../../widget/types";
77
78
  * @slot vviinn-custom-label-4 - Custom label with index 4.
78
79
  * @slot vviinn-image-placeholder-icon - Icon or content for the image placeholder.
79
80
  */
80
- export type ReplaceSlotsContentInParent = (childrenElement?: HTMLElement) => void;
81
81
  export declare class VviinnResults {
82
82
  el: HTMLElement;
83
83
  /** Recommended product renders on the page */