vviinn-widgets 2.221.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 (49) hide show
  1. package/dist/cjs/{index-sL3iGA57.js → index-DZw3p4dq.js} +1 -1
  2. package/dist/cjs/{search.store-C-fS-eJR.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 +259 -107
  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/collection/components/vviinn-suggestions/helpers.js +27 -10
  14. package/dist/collection/components/vviinn-suggestions/render-helpers.js +42 -15
  15. package/dist/esm/{index-D5yWioO8.js → index-DQQYIioG.js} +1 -1
  16. package/dist/esm/{search.store-C8LIDQfX.js → search.store-lTerE9Yh.js} +2 -2
  17. package/dist/esm/vviinn-button_6.entry.js +1 -1
  18. package/dist/esm/vviinn-camera_12.entry.js +259 -107
  19. package/dist/esm/vviinn-carousel_10.entry.js +2 -53
  20. package/dist/esm/vviinn-shop-the-look.entry.js +1 -1
  21. package/dist/esm/vviinn-text-search.entry.js +1 -1
  22. package/dist/storybook/helpers/industryToken.js +6 -8
  23. package/dist/types/components/vviinn-cropper/helpers/cropperOcrGate.d.ts +19 -0
  24. package/dist/types/components/vviinn-cropper/helpers/hasSelectedOcrFilter.d.ts +2 -0
  25. package/dist/types/components/vviinn-cropper/vviinn-cropper.d.ts +14 -0
  26. package/dist/types/components/vviinn-filters/vviinn-extended-filters.d.ts +51 -0
  27. package/dist/types/components/vviinn-results/vviinn-results.d.ts +1 -1
  28. package/dist/types/components/vviinn-suggestions/helpers.d.ts +1 -0
  29. package/dist/vviinn-widgets/p-08d39cc9.entry.js +1 -0
  30. package/dist/vviinn-widgets/{p-07211a51.entry.js → p-1e2f9b9f.entry.js} +1 -1
  31. package/dist/vviinn-widgets/{p-95423f25.entry.js → p-3daed25b.entry.js} +1 -1
  32. package/dist/vviinn-widgets/{p-DTASrq1W.js → p-CJAxBbhA.js} +1 -1
  33. package/dist/vviinn-widgets/{p-BpHXy3Gg.js → p-DhCqK4d8.js} +1 -1
  34. package/dist/vviinn-widgets/{p-f46ad1fd.entry.js → p-eb579723.entry.js} +1 -1
  35. package/{www/build/p-f48452fd.entry.js → dist/vviinn-widgets/p-f9f4e909.entry.js} +1 -1
  36. package/dist/vviinn-widgets/vviinn-widgets.esm.js +1 -1
  37. package/package.json +1 -1
  38. package/www/build/p-08d39cc9.entry.js +1 -0
  39. package/www/build/{p-07211a51.entry.js → p-1e2f9b9f.entry.js} +1 -1
  40. package/www/build/{p-95423f25.entry.js → p-3daed25b.entry.js} +1 -1
  41. package/www/build/{p-2d5777fa.js → p-4f556dc3.js} +1 -1
  42. package/www/build/{p-DTASrq1W.js → p-CJAxBbhA.js} +1 -1
  43. package/www/build/{p-BpHXy3Gg.js → p-DhCqK4d8.js} +1 -1
  44. package/www/build/{p-f46ad1fd.entry.js → p-eb579723.entry.js} +1 -1
  45. package/{dist/vviinn-widgets/p-f48452fd.entry.js → www/build/p-f9f4e909.entry.js} +1 -1
  46. package/www/build/vviinn-widgets.esm.js +1 -1
  47. package/www/index.html +1 -1
  48. package/dist/vviinn-widgets/p-e7b0a5b9.entry.js +0 -1
  49. package/www/build/p-e7b0a5b9.entry.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import { h } from './index-B89nCb_F.js';
2
- import { h as addIfNotEmpty, p as parseStringToExcluded, n as isValueMatch, o as isIntervalMatch, q as valueToString, r as extractFilterValue } from './search.store-C8LIDQfX.js';
2
+ import { h as addIfNotEmpty, p as parseStringToExcluded, n as isValueMatch, o as isIntervalMatch, q as valueToString, r as extractFilterValue } from './search.store-lTerE9Yh.js';
3
3
  import { i as instance } from './store-BJxQCbNV.js';
4
4
 
5
5
  const PlusIcon = () => (h("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: "plus-icon", "aria-hidden": "true" },
@@ -8596,7 +8596,7 @@ const encodeToBase64UTF8 = (str) => {
8596
8596
  return btoa(String.fromCharCode.apply(null, utf8Array));
8597
8597
  };
8598
8598
 
8599
- const version = "2.221.0";
8599
+ const version = "2.223.0";
8600
8600
 
8601
8601
  const appStateGlobalDefaults = {
8602
8602
  excluded: null,
@@ -8893,4 +8893,4 @@ const makeAutoSuggestRequest = async (store, query, token, apiPath, onCompletion
8893
8893
  }), mapLeft((error) => error))();
8894
8894
  };
8895
8895
 
8896
- export { checkDeviceType as A, isMobile as B, fromString as C, fold as D, _ArrayExports as _, makeVisualSearchByUrlRequest as a, imageFromFileTask as b, makeUploadFileRequest as c, setTextSearchQuery as d, makeAutoSuggestRequest as e, campaignTypeNames as f, getAcceptableFileFormats as g, addIfNotEmpty as h, isDesktop as i, makeTextSearchRequest as j, getAcceptableFileFormatsForDisplay as k, searchState as l, makeVisualSearchRequest as m, isValueMatch as n, isIntervalMatch as o, parseStringToExcluded as p, valueToString as q, extractFilterValue as r, shopTheLookState as s, toFile as t, useSearchStore as u, version as v, getImageSizes as w, checkImageType as x, resetStore as y, makeProductListingPageRequest as z };
8896
+ export { makeProductListingPageRequest as A, checkDeviceType as B, isMobile as C, fromString as D, fold as E, _ArrayExports as _, makeVisualSearchByUrlRequest as a, imageFromFileTask as b, makeUploadFileRequest as c, setTextSearchQuery as d, makeAutoSuggestRequest as e, campaignTypeNames as f, getAcceptableFileFormats as g, addIfNotEmpty as h, isDesktop as i, makeTextSearchRequest as j, getAcceptableFileFormatsForDisplay as k, searchState as l, makeVisualSearchRequest as m, isValueMatch as n, isIntervalMatch as o, parseStringToExcluded as p, valueToString as q, extractFilterValue as r, shopTheLookState as s, toFile as t, useSearchStore as u, version as v, extractSelectedFilters as w, getImageSizes as x, checkImageType as y, resetStore as z };
@@ -1,6 +1,6 @@
1
1
  import { h, r as registerInstance, H as Host, c as createEvent, g as getElement, F as Fragment } from './index-B89nCb_F.js';
2
2
  import { i as instance } from './store-BJxQCbNV.js';
3
- import { k as getAcceptableFileFormatsForDisplay, f as campaignTypeNames, h as addIfNotEmpty, l as searchState, u as useSearchStore, v as version } from './search.store-C8LIDQfX.js';
3
+ import { k as getAcceptableFileFormatsForDisplay, f as campaignTypeNames, h as addIfNotEmpty, l as searchState, u as useSearchStore, v as version } from './search.store-lTerE9Yh.js';
4
4
  import { s as slotChangeListener, a as addEventListenersWithSignal } from './index-C1-PYhS4.js';
5
5
  import { S as SecondaryActionIcon } from './SecondaryActionIcon-D4f3aMUD.js';
6
6
  import { m as modalParts, c as carouselParts, p as productCardParts, r as recommendationsParts, i as initializeLocale } from './index-BCrstDkj.js';
@@ -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-C8LIDQfX.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-D5yWioO8.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();
360
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;
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
  }
@@ -1442,6 +1551,72 @@ ${e}</tr>
1442
1551
  `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let r=this.parser.parseInline(n),i=J(e);if(i===null)return r;e=i;let s='<a href="'+e+'"';return t&&(s+=' title="'+O(t)+'"'),s+=">"+r+"</a>",s}image({href:e,title:t,text:n,tokens:r}){r&&(n=this.parser.parseInline(r,this.parser.textRenderer));let i=J(e);if(i===null)return O(n);e=i;let s=`<img src="${e}" alt="${O(n)}"`;return t&&(s+=` title="${O(t)}"`),s+=">",s}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var $=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class u{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new $;}static parse(e,t){return new u(t).parse(e)}static parseInline(e,t){return new u(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let n=0;n<e.length;n++){let r=e[n];if(this.options.extensions?.renderers?.[r.type]){let s=r,a=this.options.extensions.renderers[s.type].call({parser:this},s);if(a!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(s.type)){t+=a||"";continue}}let i=r;switch(i.type){case "space":{t+=this.renderer.space(i);break}case "hr":{t+=this.renderer.hr(i);break}case "heading":{t+=this.renderer.heading(i);break}case "code":{t+=this.renderer.code(i);break}case "table":{t+=this.renderer.table(i);break}case "blockquote":{t+=this.renderer.blockquote(i);break}case "list":{t+=this.renderer.list(i);break}case "checkbox":{t+=this.renderer.checkbox(i);break}case "html":{t+=this.renderer.html(i);break}case "def":{t+=this.renderer.def(i);break}case "paragraph":{t+=this.renderer.paragraph(i);break}case "text":{t+=this.renderer.text(i);break}default:{let s='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(s),"";throw new Error(s)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n="";for(let r=0;r<e.length;r++){let i=e[r];if(this.options.extensions?.renderers?.[i.type]){let a=this.options.extensions.renderers[i.type].call({parser:this},i);if(a!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(i.type)){n+=a||"";continue}}let s=i;switch(s.type){case "escape":{n+=t.text(s);break}case "html":{n+=t.html(s);break}case "link":{n+=t.link(s);break}case "image":{n+=t.image(s);break}case "checkbox":{n+=t.checkbox(s);break}case "strong":{n+=t.strong(s);break}case "em":{n+=t.em(s);break}case "codespan":{n+=t.codespan(s);break}case "br":{n+=t.br(s);break}case "del":{n+=t.del(s);break}case "text":{n+=t.text(s);break}default:{let a='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(a),"";throw new Error(a)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(){return this.block?x.lex:x.lexInline}provideParser(){return this.block?b.parse:b.parseInline}};var D=class{defaults=M();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=$;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let r of e)switch(n=n.concat(t.call(this,r)),r.type){case "table":{let i=r;for(let s of i.header)n=n.concat(this.walkTokens(s.tokens,t));for(let s of i.rows)for(let a of s)n=n.concat(this.walkTokens(a.tokens,t));break}case "list":{let i=r;n=n.concat(this.walkTokens(i.items,t));break}default:{let i=r;this.defaults.extensions?.childTokens?.[i.type]?this.defaults.extensions.childTokens[i.type].forEach(s=>{let a=i[s].flat(1/0);n=n.concat(this.walkTokens(a,t));}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let r={...n};if(r.async=this.defaults.async||r.async||false,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let s=t.renderers[i.name];s?t.renderers[i.name]=function(...a){let o=i.renderer.apply(this,a);return o===false&&(o=s.apply(this,a)),o}:t.renderers[i.name]=i.renderer;}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let s=t[i.level];s?s.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]));}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens);}),r.extensions=t),n.renderer){let i=this.defaults.renderer||new y(this.defaults);for(let s in n.renderer){if(!(s in i))throw new Error(`renderer '${s}' does not exist`);if(["options","parser"].includes(s))continue;let a=s,o=n.renderer[a],l=i[a];i[a]=(...p)=>{let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c||""};}r.renderer=i;}if(n.tokenizer){let i=this.defaults.tokenizer||new w(this.defaults);for(let s in n.tokenizer){if(!(s in i))throw new Error(`tokenizer '${s}' does not exist`);if(["options","rules","lexer"].includes(s))continue;let a=s,o=n.tokenizer[a],l=i[a];i[a]=(...p)=>{let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c};}r.tokenizer=i;}if(n.hooks){let i=this.defaults.hooks||new P;for(let s in n.hooks){if(!(s in i))throw new Error(`hook '${s}' does not exist`);if(["options","block"].includes(s))continue;let a=s,o=n.hooks[a],l=i[a];P.passThroughHooks.has(s)?i[a]=p=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(s))return (async()=>{let d=await o.call(i,p);return l.call(i,d)})();let c=o.call(i,p);return l.call(i,c)}:i[a]=(...p)=>{if(this.defaults.async)return (async()=>{let d=await o.apply(i,p);return d===false&&(d=await l.apply(i,p)),d})();let c=o.apply(i,p);return c===false&&(c=l.apply(i,p)),c};}r.hooks=i;}if(n.walkTokens){let i=this.defaults.walkTokens,s=n.walkTokens;r.walkTokens=function(a){let o=[];return o.push(s.call(this,a)),i&&(o=o.concat(i.call(this,a))),o};}this.defaults={...this.defaults,...r};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,r)=>{let i={...r},s={...this.defaults,...i},a=this.onError(!!s.silent,!!s.async);if(this.defaults.async===true&&i.async===false)return a(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return a(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return a(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(s.hooks&&(s.hooks.options=s,s.hooks.block=e),s.async)return (async()=>{let o=s.hooks?await s.hooks.preprocess(n):n,p=await(s.hooks?await s.hooks.provideLexer():e?x.lex:x.lexInline)(o,s),c=s.hooks?await s.hooks.processAllTokens(p):p;s.walkTokens&&await Promise.all(this.walkTokens(c,s.walkTokens));let h=await(s.hooks?await s.hooks.provideParser():e?b.parse:b.parseInline)(c,s);return s.hooks?await s.hooks.postprocess(h):h})().catch(a);try{s.hooks&&(n=s.hooks.preprocess(n));let l=(s.hooks?s.hooks.provideLexer():e?x.lex:x.lexInline)(n,s);s.hooks&&(l=s.hooks.processAllTokens(l)),s.walkTokens&&this.walkTokens(l,s.walkTokens);let c=(s.hooks?s.hooks.provideParser():e?b.parse:b.parseInline)(l,s);return s.hooks&&(c=s.hooks.postprocess(c)),c}catch(o){return a(o)}}}onError(e,t){return n=>{if(n.message+=`
1443
1552
  Please report this to https://github.com/markedjs/marked.`,e){let r="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(r):r}if(t)return Promise.reject(n);throw n}}};var L=new D;function g(u,e){return L.parse(u,e)}g.options=g.setOptions=function(u){return L.setOptions(u),g.defaults=L.defaults,G(g.defaults),g};g.getDefaults=M;g.defaults=T;g.use=function(...u){return L.use(...u),g.defaults=L.defaults,G(g.defaults),g};g.walkTokens=function(u,e){return L.walkTokens(u,e)};g.parseInline=L.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=$;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;
1444
1553
 
1554
+ const toggleFilterInSet = (appliedFilters, suggestionText) => {
1555
+ const newAppliedFilters = new Set(appliedFilters);
1556
+ if (newAppliedFilters.has(suggestionText)) {
1557
+ newAppliedFilters.delete(suggestionText);
1558
+ }
1559
+ else {
1560
+ newAppliedFilters.add(suggestionText);
1561
+ }
1562
+ return newAppliedFilters;
1563
+ };
1564
+ const formatIntervalKey = (column, start, end) => `${column}:${start}-${end}`;
1565
+ const extractActiveFilterValues = (activeFilters) => {
1566
+ const activeValues = new Set();
1567
+ activeFilters.forEach((filter) => {
1568
+ if (!Array.isArray(filter.values))
1569
+ return;
1570
+ filter.values.forEach((v) => {
1571
+ // Interval values are `{start, end}` objects; categorical values are strings.
1572
+ if (v !== null && typeof v === "object" && "start" in v) {
1573
+ activeValues.add(formatIntervalKey(filter.column, v.start, v.end));
1574
+ }
1575
+ else {
1576
+ activeValues.add(`${filter.column}:${String(v)}`);
1577
+ }
1578
+ });
1579
+ });
1580
+ return activeValues;
1581
+ };
1582
+ const syncSuggestionFilters = (activeFilters, stream) => {
1583
+ var _a, _b, _c;
1584
+ const activeValues = extractActiveFilterValues(activeFilters);
1585
+ const updatedAppliedFilters = new Set();
1586
+ if (!(stream === null || stream === void 0 ? void 0 : stream.items))
1587
+ return updatedAppliedFilters;
1588
+ for (const item of stream.items) {
1589
+ if (item.role !== "assistant" || !item.parts)
1590
+ continue;
1591
+ for (const part of item.parts) {
1592
+ if (!((_a = part.text) === null || _a === void 0 ? void 0 : _a.annotations))
1593
+ continue;
1594
+ for (const annotation of part.text.annotations) {
1595
+ if (!((_c = (_b = annotation.interactions) === null || _b === void 0 ? void 0 : _b.dynamicFilters) === null || _c === void 0 ? void 0 : _c.length))
1596
+ continue;
1597
+ for (const filter of annotation.interactions.dynamicFilters) {
1598
+ if (filter.type === "categorical" && "values" in filter) {
1599
+ filter.values.forEach((value) => {
1600
+ if (activeValues.has(`${filter.column}:${String(value.value)}`)) {
1601
+ updatedAppliedFilters.add(`${filter.column}:${value.value}`);
1602
+ }
1603
+ });
1604
+ }
1605
+ else if (filter.type === "interval" && "selectedValues" in filter) {
1606
+ filter.selectedValues.forEach((interval) => {
1607
+ const key = formatIntervalKey(filter.column, interval.start, interval.end);
1608
+ if (activeValues.has(key)) {
1609
+ updatedAppliedFilters.add(key);
1610
+ }
1611
+ });
1612
+ }
1613
+ }
1614
+ }
1615
+ }
1616
+ }
1617
+ return updatedAppliedFilters;
1618
+ };
1619
+
1445
1620
  const extractDataItems = (annotation) => annotation.data.items;
1446
1621
  const findMatchingFilterValue = (item, filter) => {
1447
1622
  if (filter.type !== "categorical" ||
@@ -1462,18 +1637,38 @@ const applyFiltersForItems = (dataItems, interactions, currentRequestFilters, ha
1462
1637
  let updatedFilters = currentRequestFilters;
1463
1638
  if (dataItems.length === 0) {
1464
1639
  for (const filter of filters) {
1465
- if (filter.type !== "categorical" || !("values" in filter))
1466
- continue;
1467
- for (const filterValue of filter.values) {
1468
- updatedFilters = triggerFilter({
1469
- filterValue: filterValue,
1470
- selectedFilter: filter,
1471
- requestFilters: updatedFilters,
1472
- vviinnFilterTriggered: handlers.vviinnFilterTriggered,
1473
- vviinnFiltersChanged: handlers.vviinnFiltersChanged,
1474
- el: handlers.el,
1475
- isTriggeredByVpsWidget: handlers.isTriggeredByVpsWidget,
1476
- });
1640
+ if (filter.type === "categorical" && "values" in filter) {
1641
+ for (const filterValue of filter.values) {
1642
+ updatedFilters = triggerFilter({
1643
+ filterValue: filterValue,
1644
+ selectedFilter: filter,
1645
+ requestFilters: updatedFilters,
1646
+ vviinnFilterTriggered: handlers.vviinnFilterTriggered,
1647
+ vviinnFiltersChanged: handlers.vviinnFiltersChanged,
1648
+ el: handlers.el,
1649
+ isTriggeredByVpsWidget: handlers.isTriggeredByVpsWidget,
1650
+ });
1651
+ }
1652
+ }
1653
+ else if (filter.type === "interval" && "selectedValues" in filter) {
1654
+ // A suggestion chip represents one specific range to toggle, not a slider.
1655
+ // The backend emits `full === selectedValues[0]`, which would make
1656
+ // `isFullRangeInterval` read every click as "cleared to the full range"
1657
+ // (deselect-only). Neutralize `full` so the shared toggle logic selects /
1658
+ // deselects this exact interval by value match. Only the object passed to
1659
+ // `triggerFilter` is affected; `value` still carries the real interval.
1660
+ const chipFilter = Object.assign(Object.assign({}, filter), { full: { start: undefined, end: undefined } });
1661
+ for (const interval of filter.selectedValues) {
1662
+ updatedFilters = triggerFilter({
1663
+ filterValue: { interval },
1664
+ selectedFilter: chipFilter,
1665
+ requestFilters: updatedFilters,
1666
+ vviinnFilterTriggered: handlers.vviinnFilterTriggered,
1667
+ vviinnFiltersChanged: handlers.vviinnFiltersChanged,
1668
+ el: handlers.el,
1669
+ isTriggeredByVpsWidget: handlers.isTriggeredByVpsWidget,
1670
+ });
1671
+ }
1477
1672
  }
1478
1673
  }
1479
1674
  return updatedFilters;
@@ -1522,9 +1717,15 @@ const splitContentByLocators = (content, annotations) => {
1522
1717
  };
1523
1718
  const getAnnotationFilterKeys = (annotation) => {
1524
1719
  var _a, _b, _c;
1525
- return (_c = (_b = (_a = annotation.interactions) === null || _a === void 0 ? void 0 : _a.dynamicFilters) === null || _b === void 0 ? void 0 : _b.flatMap((filter) => "values" in filter
1526
- ? filter.values.map((v) => `${filter.column}:${v.value}`)
1527
- : [])) !== null && _c !== void 0 ? _c : [];
1720
+ return (_c = (_b = (_a = annotation.interactions) === null || _a === void 0 ? void 0 : _a.dynamicFilters) === null || _b === void 0 ? void 0 : _b.flatMap((filter) => {
1721
+ if (filter.type === "categorical" && "values" in filter) {
1722
+ return filter.values.map((v) => `${filter.column}:${v.value}`);
1723
+ }
1724
+ if (filter.type === "interval" && "selectedValues" in filter) {
1725
+ return filter.selectedValues.map((interval) => formatIntervalKey(filter.column, interval.start, interval.end));
1726
+ }
1727
+ return [];
1728
+ })) !== null && _c !== void 0 ? _c : [];
1528
1729
  };
1529
1730
  const getAnnotationDeeplink = (annotation) => {
1530
1731
  for (const item of annotation.data.items) {
@@ -1551,55 +1752,6 @@ const renderAnnotatedContent = (content, annotations, onAnnotationClick, applied
1551
1752
  };
1552
1753
  const renderInfoText = (content, key) => (h("div", { class: "suggestion-info-text", part: "suggestion-info-text", key: key, innerHTML: g.parse(content) }));
1553
1754
 
1554
- const toggleFilterInSet = (appliedFilters, suggestionText) => {
1555
- const newAppliedFilters = new Set(appliedFilters);
1556
- if (newAppliedFilters.has(suggestionText)) {
1557
- newAppliedFilters.delete(suggestionText);
1558
- }
1559
- else {
1560
- newAppliedFilters.add(suggestionText);
1561
- }
1562
- return newAppliedFilters;
1563
- };
1564
- const extractActiveFilterValues = (activeFilters) => {
1565
- const activeValues = new Set();
1566
- activeFilters.forEach((filter) => {
1567
- if (Array.isArray(filter.values)) {
1568
- filter.values.forEach((v) => activeValues.add(`${filter.column}:${String(v)}`));
1569
- }
1570
- });
1571
- return activeValues;
1572
- };
1573
- const syncSuggestionFilters = (activeFilters, stream) => {
1574
- var _a, _b, _c;
1575
- const activeValues = extractActiveFilterValues(activeFilters);
1576
- const updatedAppliedFilters = new Set();
1577
- if (!(stream === null || stream === void 0 ? void 0 : stream.items))
1578
- return updatedAppliedFilters;
1579
- for (const item of stream.items) {
1580
- if (item.role !== "assistant" || !item.parts)
1581
- continue;
1582
- for (const part of item.parts) {
1583
- if (!((_a = part.text) === null || _a === void 0 ? void 0 : _a.annotations))
1584
- continue;
1585
- for (const annotation of part.text.annotations) {
1586
- if (!((_c = (_b = annotation.interactions) === null || _b === void 0 ? void 0 : _b.dynamicFilters) === null || _c === void 0 ? void 0 : _c.length))
1587
- continue;
1588
- for (const filter of annotation.interactions.dynamicFilters) {
1589
- if (filter.type !== "categorical" || !("values" in filter))
1590
- continue;
1591
- filter.values.forEach((value) => {
1592
- if (activeValues.has(`${filter.column}:${String(value.value)}`)) {
1593
- updatedAppliedFilters.add(`${filter.column}:${value.value}`);
1594
- }
1595
- });
1596
- }
1597
- }
1598
- }
1599
- }
1600
- return updatedAppliedFilters;
1601
- };
1602
-
1603
1755
  const vviinnSuggestionsCss = ":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:contents}.container{display:flex;flex-direction:column;gap:var(--spacing-150);font-family:var(--font-family, var(--font-family-base));padding-right:var(--spacing-100);line-height:normal}.header{display:flex;align-items:center;gap:var(--spacing-100)}.icon{font-size:20px}.title{margin:0;font-size:var(--font-size-headline);line-height:var(--line-height-headline);font-weight:600;color:var(--color-text-primary)}.suggestions-wrapper{display:flex;flex-direction:column;gap:var(--spacing-100);width:100%}.suggestions-list{list-style:none;margin:0;padding:0;padding-right:var(--spacing-100);display:flex;align-items:center;gap:var(--spacing-100);flex-wrap:wrap;font-size:var(--font-size-label)}.suggestion-item{display:contents}.suggestion-link{background:none;border:none;color:var(--color-primary-500);text-decoration:underline;cursor:pointer;font-size:inherit;line-height:inherit;padding:0;margin:0}.suggestion-link:hover{color:var(--color-primary-600)}.suggestion-link:focus{outline:2px solid var(--color-primary-500);outline-offset:2px;border-radius:2px}.suggestion-filter-button{background:none;border:none;cursor:pointer;display:flex;align-items:center;height:36px;padding:var(--spacing-75);gap:var(--spacing-50);white-space:nowrap;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)}.suggestion-filter-button:hover{background-color:var(--surface-bg-color-01-hover)}.suggestion-filter-button.active{background:var(--surface-bg-color-inverse);color:var(--color-text-inverse)}.suggestion-info-text{font-size:var(--font-size-label);color:var(--color-text-primary)}.suggestion-info-text *{font-size:var(--font-size-label);margin:0}";
1604
1756
 
1605
1757
  const VviinnSuggestions = class {