@useinsider/guido 2.1.0-beta.f869a80 → 2.1.0-beta.f9ab899

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 (75) hide show
  1. package/dist/@types/config/schemas.js +1 -1
  2. package/dist/components/organisms/base/Toaster.vue.js +4 -4
  3. package/dist/components/organisms/base/Toaster.vue2.js +12 -9
  4. package/dist/components/organisms/email-preview/desktop-preview/EmailSizeIndicator.vue.js +5 -5
  5. package/dist/components/organisms/email-preview/desktop-preview/EmailSizeIndicator.vue2.js +2 -2
  6. package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +13 -11
  7. package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +23 -54
  8. package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue.js +5 -7
  9. package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue2.js +21 -34
  10. package/dist/components/organisms/extensions/recommendation/Filters.vue.js +11 -11
  11. package/dist/components/organisms/extensions/recommendation/Filters.vue2.js +36 -48
  12. package/dist/components/organisms/extensions/recommendation/LogicAdapter.vue2.js +9 -11
  13. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue.js +1 -1
  14. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue2.js +19 -19
  15. package/dist/composables/useRecommendation.js +9 -9
  16. package/dist/composables/useStripo.js +25 -23
  17. package/dist/composables/useVersionHistoryApi.js +1 -1
  18. package/dist/config/i18n/en/index.js +11 -0
  19. package/dist/config/i18n/en/labels.json.js +7 -0
  20. package/dist/config/i18n/en/toasters.json.js +56 -0
  21. package/dist/config/i18n/en/tooltips.json.js +82 -0
  22. package/dist/config/i18n/index.js +7 -0
  23. package/dist/config/migrator/itemsBlockMigrator.js +65 -64
  24. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +36 -33
  25. package/dist/extensions/Blocks/Recommendation/constants/layout.js +16 -14
  26. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +13 -12
  27. package/dist/extensions/Blocks/Recommendation/controls/button/index.js +9 -9
  28. package/dist/extensions/Blocks/Recommendation/controls/image/index.js +1 -1
  29. package/dist/extensions/Blocks/Recommendation/controls/layout/index.js +37 -27
  30. package/dist/extensions/Blocks/Recommendation/controls/main/algorithm.js +16 -16
  31. package/dist/extensions/Blocks/Recommendation/controls/main/currency.js +30 -32
  32. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +177 -125
  33. package/dist/extensions/Blocks/Recommendation/controls/main/locale.js +9 -9
  34. package/dist/extensions/Blocks/Recommendation/controls/main/productLayout.js +46 -38
  35. package/dist/extensions/Blocks/Recommendation/controls/main/shuffle.js +16 -16
  36. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +269 -215
  37. package/dist/extensions/Blocks/Recommendation/controls/name/index.js +10 -10
  38. package/dist/extensions/Blocks/Recommendation/controls/name/textTrim.js +5 -5
  39. package/dist/extensions/Blocks/Recommendation/controls/oldPrice/index.js +14 -14
  40. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/index.js +9 -9
  41. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textAfter.js +3 -3
  42. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textBefore.js +1 -1
  43. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/index.js +9 -9
  44. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textAfter.js +3 -3
  45. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textBefore.js +3 -3
  46. package/dist/extensions/Blocks/Recommendation/controls/price/index.js +3 -3
  47. package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +225 -102
  48. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +123 -128
  49. package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +8 -8
  50. package/dist/extensions/Blocks/Unsubscribe/block.js +29 -29
  51. package/dist/extensions/Blocks/Unsubscribe/control.js +12 -9
  52. package/dist/extensions/Blocks/Unsubscribe/elements/preview.js +13 -11
  53. package/dist/extensions/Blocks/Unsubscribe/styles.css.js +31 -1
  54. package/dist/guido.css +1 -1
  55. package/dist/src/components/organisms/extensions/recommendation/FilterItem.vue.d.ts +0 -1
  56. package/dist/src/components/organisms/extensions/recommendation/Filters.vue.d.ts +1 -17
  57. package/dist/src/config/i18n/en/index.d.ts +1 -0
  58. package/dist/src/config/i18n/index.d.ts +16 -0
  59. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +6 -0
  60. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +3 -3
  61. package/dist/src/extensions/Blocks/Recommendation/constants/layout.d.ts +6 -2
  62. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +6 -1
  63. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +33 -15
  64. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +24 -14
  65. package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +49 -17
  66. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +3 -18
  67. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +8 -0
  68. package/dist/src/extensions/Blocks/Unsubscribe/control.d.ts +1 -0
  69. package/dist/static/styles/components/notification.css.js +18 -0
  70. package/dist/static/styles/components/tools.css.js +6 -2
  71. package/dist/static/styles/variables.css.js +2 -0
  72. package/dist/stores/unsubscribe.js +37 -34
  73. package/package.json +1 -1
  74. package/dist/extensions/Blocks/Recommendation/validation/filterSchema.js +0 -29
  75. package/dist/src/extensions/Blocks/Recommendation/validation/filterSchema.d.ts +0 -15
@@ -29,12 +29,42 @@ const n = `/* Unsubscribe Extension Styles */
29
29
  display: flex;
30
30
  align-items: center;
31
31
  justify-content: center;
32
+ position: relative;
32
33
  }
33
34
 
34
- .unsubscribe-preview-image {
35
+ .unsubscribe-preview-image-container .unsubscribe-preview-image {
35
36
  object-fit: cover;
36
37
  width: 100%;
37
38
  height: auto;
39
+ display: none;
40
+ }
41
+
42
+ .unsubscribe-preview-image-container.is-loaded .unsubscribe-preview-image {
43
+ display: block;
44
+ }
45
+
46
+ .unsubscribe-preview-image-container.is-loaded .unsubscribe-preview-loader {
47
+ display: none;
48
+ }
49
+
50
+ /* Loading shimmer */
51
+ .unsubscribe-preview-loader {
52
+ width: 100%;
53
+ height: 200px;
54
+ border-radius: 4px;
55
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
56
+ background-size: 200% 100%;
57
+ animation: unsubscribe-shimmer 1.5s infinite;
58
+ }
59
+
60
+ @keyframes unsubscribe-shimmer {
61
+ 0% {
62
+ background-position: 200% 0;
63
+ }
64
+
65
+ 100% {
66
+ background-position: -200% 0;
67
+ }
38
68
  }
39
69
  `;
40
70
  export {
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- .gap-16[data-v-3b53a736],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-913a3417] .in-progress-wrapper__progress p span:last-child{display:none!important}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.editor-actions[data-v-17dd4d8b]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-16abb398]{position:relative;width:100%;height:calc(100vh - 128px)}.guido-editor__container[data-v-16abb398]{width:100%;height:calc(100vh - 128px)}.guido-editor__no-header[data-v-16abb398]{height:calc(100vh - 75px)}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-a86fc486]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-a86fc486]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-a86fc486]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-a86fc486]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-a86fc486]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-d3c52b44] .vueperslides__bullets,[data-v-dd1a237a] .vueperslides__bullets{pointer-events:none!important}[data-v-dd1a237a] .vueperslides__parallax-wrapper{height:110px!important}[data-v-a408dcea] .vueperslides__bullets{pointer-events:none!important}[data-v-a408dcea] .vueperslides__parallax-wrapper{height:110px!important}
1
+ .gap-16[data-v-6562e38c],.gap-16[data-v-1ccb6d4a]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-079d2bf7] .in-progress-wrapper__progress p span:last-child{display:none!important}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.editor-actions[data-v-17dd4d8b]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-16abb398]{position:relative;width:100%;height:calc(100vh - 128px)}.guido-editor__container[data-v-16abb398]{width:100%;height:calc(100vh - 128px)}.guido-editor__no-header[data-v-16abb398]{height:calc(100vh - 75px)}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-df672485]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-df672485]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-df672485]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-df672485]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-df672485]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-d3c52b44] .vueperslides__bullets,[data-v-dd1a237a] .vueperslides__bullets{pointer-events:none!important}[data-v-dd1a237a] .vueperslides__parallax-wrapper{height:110px!important}[data-v-a408dcea] .vueperslides__bullets{pointer-events:none!important}[data-v-a408dcea] .vueperslides__parallax-wrapper{height:110px!important}
@@ -3,7 +3,6 @@ type __VLS_Props = {
3
3
  filter: Filter;
4
4
  index: number;
5
5
  hasLogicAdapter?: boolean;
6
- submitted: boolean;
7
6
  };
8
7
  declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<__VLS_Props>, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {
9
8
  "delete-filter": (filter: Filter) => void;
@@ -1,18 +1,2 @@
1
- type __VLS_Props = {
2
- submitted: boolean;
3
- };
4
- declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<__VLS_Props>, {
5
- switchToGroup: (groupId: number) => void;
6
- }, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {
7
- "reset-validation": () => void;
8
- }, string, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_Props>>>, {}>;
1
+ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
9
2
  export default _default;
10
- type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
11
- type __VLS_TypePropsToOption<T> = {
12
- [K in keyof T]-?: {} extends Pick<T, K> ? {
13
- type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
14
- } : {
15
- type: import('vue').PropType<T[K]>;
16
- required: true;
17
- };
18
- };
@@ -0,0 +1 @@
1
+ export declare const en: Record<string, string>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Stripo Editor Translation Overrides
3
+ *
4
+ * Custom translations for Stripo editor UI elements.
5
+ * Each language has its own folder with categorized JSON files.
6
+ *
7
+ * Reference: https://email-static.useinsider.com/guido/{version}/assets/i18n/en.json
8
+ * @module config/i18n
9
+ */
10
+ /**
11
+ * Combined locale patch for Stripo editor initialization.
12
+ * Maps language codes to their translation overrides.
13
+ */
14
+ export declare const localePatch: {
15
+ en: Record<string, string>;
16
+ };
@@ -41,6 +41,12 @@ export declare const DEFAULT_VISIBILITY: Record<string, boolean>;
41
41
  * All other code should import and use this constant.
42
42
  */
43
43
  export declare const DEFAULT_NODE_CONFIG: RecommendationNodeConfig;
44
+ /**
45
+ * Algorithm IDs to exclude from the recommendation algorithm dropdown.
46
+ * These algorithms will not be shown as options regardless of API response.
47
+ * View Together and Purchase Together algorithms are disabled because these require product id.
48
+ */
49
+ export declare const EXCLUDED_ALGORITHM_IDS: number[];
44
50
  /**
45
51
  * Current configuration version
46
52
  * Increment this when making breaking changes to the schema
@@ -8,6 +8,6 @@
8
8
  */
9
9
  export { RecommendationBlockId } from './blockIds';
10
10
  export { RecommendationControlId } from './controlIds';
11
- export { CONTAINER_SELECTOR, DESKTOP_CONTAINER_SELECTOR, MOBILE_CONTAINER_SELECTOR, CURRENCY_ATTR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, } from './selectors';
12
- export { LAYOUT_VALUES, LAYOUT_OPTIONS, DEFAULT_PRODUCTS_PER_ROW, DEFAULT_CARDS_IN_ROW, DEFAULT_MOBILE_CARDS_IN_ROW, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_PRODUCTS_PER_ROW, MAX_MOBILE_PRODUCTS_PER_ROW, MIN_MOBILE_PRODUCTS_PER_ROW, DEFAULT_COLUMN_SPACING, DEFAULT_ROW_SPACING, MIN_SPACING, MAX_SPACING, SPACING_STEP, } from './layout';
13
- export { DEFAULT_NODE_CONFIG, DEFAULT_CURRENCY, DEFAULT_COMPOSITION, DEFAULT_VISIBILITY, CURRENT_CONFIG_VERSION, } from './defaultConfig';
11
+ export { BLOCK_ROOT_SELECTOR, CONTAINER_SELECTOR, DESKTOP_CONTAINER_SELECTOR, MOBILE_CONTAINER_SELECTOR, CURRENCY_ATTR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, } from './selectors';
12
+ export { LAYOUT_VALUES, LAYOUT_OPTIONS, DEFAULT_PRODUCTS_PER_ROW, DEFAULT_CARDS_IN_ROW, DEFAULT_MOBILE_CARDS_IN_ROW, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_PRODUCTS_PER_ROW, MAX_MOBILE_PRODUCTS_PER_ROW, MIN_MOBILE_PRODUCTS_PER_ROW, DEFAULT_COLUMN_SPACING, DEFAULT_ROW_SPACING, DEFAULT_MOBILE_COLUMN_SPACING, DEFAULT_MOBILE_ROW_SPACING, MIN_SPACING, MAX_SPACING, SPACING_STEP, } from './layout';
13
+ export { DEFAULT_NODE_CONFIG, DEFAULT_CURRENCY, DEFAULT_COMPOSITION, DEFAULT_VISIBILITY, CURRENT_CONFIG_VERSION, EXCLUDED_ALGORITHM_IDS, } from './defaultConfig';
@@ -31,8 +31,12 @@ export declare const MAX_MOBILE_PRODUCTS_PER_ROW = 2;
31
31
  export declare const MIN_MOBILE_PRODUCTS_PER_ROW = 1;
32
32
  /** Default column spacing between product cards (5px on each side = 10px total) */
33
33
  export declare const DEFAULT_COLUMN_SPACING = 10;
34
- /** Default row spacing between product rows */
35
- export declare const DEFAULT_ROW_SPACING = 20;
34
+ /** Default row spacing between product rows (matches spacer height in template) */
35
+ export declare const DEFAULT_ROW_SPACING = 10;
36
+ /** Default mobile column spacing between product cards */
37
+ export declare const DEFAULT_MOBILE_COLUMN_SPACING = 10;
38
+ /** Default mobile row spacing between product rows (matches spacer height in template) */
39
+ export declare const DEFAULT_MOBILE_ROW_SPACING = 10;
36
40
  /** Minimum spacing value */
37
41
  export declare const MIN_SPACING = 0;
38
42
  /** Maximum spacing value */
@@ -1,9 +1,14 @@
1
1
  /**
2
2
  * CSS selectors and data attributes used across the Recommendation extension
3
3
  */
4
+ /**
5
+ * Block root selector — common ancestor of both desktop and mobile containers.
6
+ * Used across attribute controls so edits apply to BOTH containers simultaneously.
7
+ */
8
+ export declare const BLOCK_ROOT_SELECTOR = ".ins-recommendation-v3-block-v2";
4
9
  /**
5
10
  * Container selector for the product container element
6
- * Used across controls to target elements within the recommendation block
11
+ * Used in product regeneration logic where container-specific scoping is needed
7
12
  */
8
13
  export declare const CONTAINER_SELECTOR = ".ins-recommendation-product-container";
9
14
  /** Desktop product container selector */
@@ -25,18 +25,13 @@ export declare class RecommendationBlockControl extends CommonControl {
25
25
  getId(): string;
26
26
  getTemplate(): string;
27
27
  onRender(): Promise<void>;
28
- /**
29
- * Immediately regenerate products with styles (no debounce)
30
- * Used for initial load after fetch completes
31
- */
32
- private _regenerateWithProducts;
33
28
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
34
29
  onDestroy(): void;
35
30
  /**
36
31
  * Initialize all sub-controls with the shared API context
37
32
  * Each sub-control manages its own form values and event listeners
38
33
  */
39
- _initializeSubControls(): void;
34
+ private _initializeSubControls;
40
35
  /**
41
36
  * Syncs persisted node config into the Pinia store's block state.
42
37
  *
@@ -50,11 +45,26 @@ export declare class RecommendationBlockControl extends CommonControl {
50
45
  */
51
46
  private _syncNodeConfigToStore;
52
47
  /**
53
- * Fetches initial data for a block (filters, algorithms, products).
48
+ * Fetches initial data for a block in three phases:
49
+ * 1. Shared reference data (algorithms, currencies, filters) — parallel
50
+ * 2. Smart defaults for new blocks (currency, algorithm) — sequential
51
+ * 3. Product data with correct defaults — sequential
52
+ *
54
53
  * Shared by onRender() and onTemplateNodeUpdated() to avoid duplication.
55
54
  * Marks the block as initialized to prevent redundant fetches on re-selection.
56
55
  */
57
56
  private _fetchBlockData;
57
+ /**
58
+ * Applies smart defaults for newly dropped blocks.
59
+ *
60
+ * For new blocks (config still matches hardcoded defaults), validates that
61
+ * the default currency and algorithm are available from the API response.
62
+ * If not, falls back to the first available option.
63
+ *
64
+ * Saved templates with user-customized config are left unchanged because
65
+ * their values won't match the hardcoded defaults.
66
+ */
67
+ private _applySmartDefaults;
58
68
  /**
59
69
  * Reads the recommendation-id attribute from the block element within the node
60
70
  */
@@ -64,8 +74,15 @@ export declare class RecommendationBlockControl extends CommonControl {
64
74
  */
65
75
  private _debouncedFetchProducts;
66
76
  /**
67
- * Debounced regeneration when products arrive from API
68
- * Tries in-place update first to preserve styles, falls back to full regeneration
77
+ * Debounced content update when products arrive from API.
78
+ *
79
+ * Tries in-place update first (preserves user-applied styles) — this succeeds
80
+ * when the product count matches the DOM (algorithm/locale/currency changes).
81
+ *
82
+ * Falls back to full regeneration when product count differs from DOM — this
83
+ * happens after "Number of Products" changes where the DOM still has the old
84
+ * count. The store pads products to the configured size, so in-place only
85
+ * fails when the size actually changed.
69
86
  */
70
87
  private _debouncedRegenerateWithProducts;
71
88
  /**
@@ -74,11 +91,12 @@ export declare class RecommendationBlockControl extends CommonControl {
74
91
  * Uses configVersion counter (incremented only by patchCurrentBlockConfig)
75
92
  * to distinguish user-initiated config changes from internal mutations
76
93
  * (e.g., fetchRecommendationCreateData setting preferred currency).
94
+ *
95
+ * Tracks currentRecommendationId to detect block switches. When the user
96
+ * selects a different recommendation block, the proxy getters (e.g.,
97
+ * recommendationProducts) return the new block's data — a different array
98
+ * reference that would be falsely detected as "new products arrived".
99
+ * We skip that tick and update tracking references instead.
77
100
  */
78
- _listenStateUpdates(): void;
79
- /**
80
- * Persists the current filter state from Pinia store to the Stripo node config.
81
- * This ensures filters survive template save/reload cycles.
82
- */
83
- private _persistFiltersToNodeConfig;
101
+ private _listenStateUpdates;
84
102
  }
@@ -75,8 +75,12 @@ export interface ReapplySpacingOptions {
75
75
  documentModifier: DocumentModifier;
76
76
  }
77
77
  /**
78
- * Reapplies spacing values from data attributes after product regeneration
79
- * This ensures spacing persists when products are regenerated
78
+ * Reapplies spacing values after product regeneration.
79
+ * Desktop spacing applies only to the desktop container;
80
+ * mobile spacing applies only to the mobile container.
81
+ *
82
+ * Reads values from node config (primary) with data-attribute fallback
83
+ * for backward compatibility with pre-nodeConfig templates.
80
84
  * @param options - Configuration options
81
85
  */
82
86
  export declare function reapplySpacing(options: ReapplySpacingOptions): void;
@@ -112,6 +116,17 @@ export interface RegenerateWithStylesOptions extends Omit<RegenerateProductRowsO
112
116
  * @param options - Configuration options for regeneration
113
117
  */
114
118
  export declare function regenerateProductRowsWithStyles(options: RegenerateWithStylesOptions): void;
119
+ /**
120
+ * Adjusts a products array to a target size.
121
+ * Used by ProductLayoutControl to synchronously match products to the new size
122
+ * before regeneration, avoiding the race condition where the store still holds
123
+ * products from the previous (stale) fetch.
124
+ *
125
+ * - More products than target → truncate
126
+ * - Fewer products than target → pad with dummy products
127
+ * - Exact match → return as-is
128
+ */
129
+ export declare function adjustProductsToSize(products: RecommendationProduct[], targetSize: number): RecommendationProduct[];
115
130
  type PriceKey = 'price' | 'original_price' | 'discount';
116
131
  /**
117
132
  * Formats a product price using current currency settings
@@ -149,16 +164,11 @@ export interface UpdateProductContentInPlaceOptions {
149
164
  * Updates product content in-place without regenerating HTML structure.
150
165
  * Preserves all user-applied styles by only touching dynamic content.
151
166
  *
152
- * This is the preferred method when:
153
- * - Product data changed but count remains the same
154
- * - Currency/locale changed (prices need reformatting)
167
+ * Scopes element queries to the desktop container to avoid double-counting
168
+ * mobile container elements (both containers share identical block IDs).
169
+ * After updating desktop, also updates mobile container to keep them in sync.
155
170
  *
156
- * Uses setText() on text nodes instead of setInnerHtml() to preserve
157
- * Stripo's internal node references and avoid cursor/selection tracking issues.
158
- *
159
- * Falls back to false when:
160
- * - Product count changed (need to add/remove elements)
161
- * - Cannot find required elements
171
+ * Falls back to false when product count changed (need to add/remove elements).
162
172
  * @param options - Configuration options
163
173
  * @returns true if in-place update was successful, false to fall back to full regeneration
164
174
  */
@@ -171,13 +181,13 @@ export interface UpdatePricesInPlaceOptions {
171
181
  * Updates only price displays in-place (for currency changes).
172
182
  * This is a lightweight update when only formatting changes, not product data.
173
183
  *
184
+ * Scopes element queries to the desktop container to avoid double-counting
185
+ * mobile container elements. After updating desktop, also updates mobile.
186
+ *
174
187
  * Perfect for:
175
188
  * - Currency symbol change
176
189
  * - Currency alignment change
177
190
  * - Decimal/thousand separator changes
178
- *
179
- * Uses setText() on text nodes instead of setInnerHtml() to preserve
180
- * Stripo's internal node references and avoid cursor/selection tracking issues.
181
191
  * @param options - Configuration options
182
192
  * @returns true if update was successful, false otherwise
183
193
  */
@@ -5,16 +5,20 @@
5
5
  * - Column spacing: horizontal gap between cards in the same row
6
6
  * - Row spacing: vertical gap between different rows
7
7
  *
8
+ * Desktop and mobile have independent spacing controls that toggle
9
+ * visibility based on Stripo's editor preview mode (desktop/mobile).
10
+ *
8
11
  * Configuration is stored via node config (persists with template).
9
12
  * Actual spacing is applied to DOM elements via inline styles.
10
13
  */
11
- import { ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
14
+ import { type ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
12
15
  import { CommonControl } from '../../../common-control';
13
16
  export declare const SPACING_CONTROL_ID = "recommendation-spacing-control";
14
17
  /**
15
18
  * Control for managing spacing between product cards
16
19
  * - Column spacing: horizontal gap between cards in the same row
17
20
  * - Row spacing: vertical gap between different rows
21
+ * - Separate controls for desktop and mobile with device-mode toggling
18
22
  */
19
23
  export declare class SpacingControl extends CommonControl {
20
24
  private store;
@@ -25,17 +29,27 @@ export declare class SpacingControl extends CommonControl {
25
29
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
26
30
  onDestroy(): void;
27
31
  /**
28
- * Updates column spacing visibility based on layout orientation
29
- * Column spacing is hidden for list layout (products are stacked vertically)
30
- * Reads from node config first, falls back to store then DOM
32
+ * Checks if the editor is currently in mobile preview mode
33
+ * using Stripo's EditorStatePropertyType API.
34
+ */
35
+ _isMobileMode(): boolean;
36
+ /**
37
+ * Updates spacing control visibility based on layout orientation, editor mode,
38
+ * and products-per-row count.
39
+ * - List layout: hide column spacing (products are full-width)
40
+ * - Desktop mode: show desktop spacing, hide mobile spacing
41
+ * - Mobile mode: show mobile spacing, hide desktop spacing
42
+ * - 1 product per row: hide column spacing (no gap between single column)
31
43
  */
32
- _updateColumnSpacingVisibility(): void;
44
+ _updateSpacingVisibility(): void;
33
45
  /**
34
- * Reads spacing values from node config first, falls back to DOM styles
46
+ * Reads spacing values from node config first, falls back to DOM styles.
47
+ * DOM fallback is only used for legacy templates that lack node config.
35
48
  */
36
49
  _setFormValues(): void;
37
50
  /**
38
51
  * Gets stored column spacing from the first attribute row cell's padding.
52
+ * Scoped to the desktop container for accurate readings.
39
53
  * For grid layout: cells inside .recommendation-attribute-row have padding applied.
40
54
  * For list layout: the parent of .product-card-wrapper has the padding.
41
55
  * The padding is applied as "0 {halfSpacing}px", so we extract and multiply by 2.
@@ -43,27 +57,33 @@ export declare class SpacingControl extends CommonControl {
43
57
  _getStoredColumnSpacing(): number;
44
58
  /**
45
59
  * Gets stored row spacing from the first spacer element's height style
60
+ * Scoped to the desktop container for accurate readings.
46
61
  */
47
62
  _getStoredRowSpacing(): number;
48
63
  /**
49
- * Handles column spacing changes.
50
- * For grid layout: applies horizontal padding to all cells inside attribute rows.
51
- * For list layout: applies padding to parent of product card wrappers.
64
+ * Handles column spacing changes for desktop.
65
+ * Applies horizontal padding only to the desktop container elements.
52
66
  */
53
67
  _onColumnSpacingChange(spacing: number): void;
54
68
  /**
55
- * Handles row spacing changes
56
- * Applies height to all spacer elements between product rows
69
+ * Handles row spacing changes for desktop.
70
+ * Applies height only to spacer elements in the desktop container.
57
71
  */
58
72
  _onRowSpacingChange(spacing: number): void;
59
73
  /**
60
- * Stores column spacing value in block data attribute
74
+ * Handles column spacing changes for mobile.
75
+ * Applies horizontal padding only to the mobile container elements.
61
76
  */
62
- _storeColumnSpacing(spacing: number): void;
77
+ _onMobileColumnSpacingChange(spacing: number): void;
63
78
  /**
64
- * Stores row spacing value in block data attribute
79
+ * Handles row spacing changes for mobile.
80
+ * Applies height only to spacer elements in the mobile container.
65
81
  */
66
- _storeRowSpacing(spacing: number): void;
82
+ _onMobileRowSpacingChange(spacing: number): void;
83
+ /**
84
+ * Stores a spacing value as a data attribute on the block root element
85
+ */
86
+ _storeDataAttribute(attr: string, spacing: number): void;
67
87
  _listenToFormUpdates(): void;
68
88
  /**
69
89
  * Debounced version of _onColumnSpacingChange
@@ -72,12 +92,24 @@ export declare class SpacingControl extends CommonControl {
72
92
  _debouncedOnColumnSpacingChange: import("@vueuse/shared").PromisifyFn<(spacing: number) => void>;
73
93
  /**
74
94
  * Debounced version of _onRowSpacingChange
75
- * Prevents excessive DOM updates when user rapidly adjusts the counter
76
95
  */
77
96
  _debouncedOnRowSpacingChange: import("@vueuse/shared").PromisifyFn<(spacing: number) => void>;
97
+ /**
98
+ * Debounced version of _onMobileColumnSpacingChange
99
+ */
100
+ _debouncedOnMobileColumnSpacingChange: import("@vueuse/shared").PromisifyFn<(spacing: number) => void>;
101
+ /**
102
+ * Debounced version of _onMobileRowSpacingChange
103
+ */
104
+ _debouncedOnMobileRowSpacingChange: import("@vueuse/shared").PromisifyFn<(spacing: number) => void>;
78
105
  /**
79
106
  * Subscribe to store orientation changes
80
- * Updates column spacing visibility when layout changes via the layout control
107
+ * Updates spacing visibility when layout changes via the layout control
81
108
  */
82
109
  _subscribeToOrientationChanges(): void;
110
+ /**
111
+ * Subscribes to editor preview mode changes via Stripo API.
112
+ * Toggles which spacing controls (desktop/mobile) are visible.
113
+ */
114
+ _subscribeToEditorModeChanges(): void;
83
115
  }
@@ -31,8 +31,6 @@ interface PerBlockState {
31
31
  filterGroup: number;
32
32
  /** Whether initial API data (filters, algorithms, products) has been fetched for this block */
33
33
  isInitialized: boolean;
34
- /** Snapshot of filters taken when the drawer opens, used to revert on cancel */
35
- filterSnapshot: Filter[] | null;
36
34
  }
37
35
  interface StoreState {
38
36
  recommendationCampaignUrls: Record<string, string>;
@@ -127,9 +125,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
127
125
  configVersion: number;
128
126
  } & import("pinia").PiniaCustomStateProperties<StoreState>): number;
129
127
  hasFilters(): boolean;
130
- hasValidFilters(): boolean;
131
128
  getFilterGroupCount(): number;
132
- getUniqueFilterGroups(): number[];
133
129
  getActivePredictiveAlgorithms: (state: {
134
130
  recommendationCampaignUrls: Record<string, string>;
135
131
  activePredictiveAlgorithms: number[];
@@ -207,35 +203,24 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
207
203
  patchCurrentBlockConfig(updates: Partial<PerBlockConfigs>, options?: {
208
204
  triggerRefetch?: boolean;
209
205
  }): void;
210
- /**
211
- * Creates a filter with the first available attribute and operator pre-selected.
212
- */
213
- createDefaultFilter(filterGroup: number, filterNumber: number): Filter;
214
206
  /**
215
207
  * Opens the filter selection drawer for the current block.
216
- * Saves a snapshot of current filters for cancel/revert.
217
- * If no filters exist, initializes with a default filter
208
+ * If no filters exist, initializes with a default empty filter
218
209
  * so the user has a starting point for input.
219
210
  */
220
211
  openFilterDrawer(): void;
221
212
  /**
222
- * Closes the filter selection drawer for the current block.
223
- * Called after successful apply — discards the snapshot.
213
+ * Closes the filter selection drawer for the current block
224
214
  */
225
215
  closeFilterDrawer(): void;
226
- /**
227
- * Cancels the filter selection drawer and reverts filters
228
- * to the snapshot taken when the drawer was opened.
229
- */
230
- cancelFilterDrawer(): void;
231
216
  fetchRecommendationCreateData(): Promise<void>;
232
217
  fetchRecommendationFilters(): Promise<void>;
233
218
  addFilterGroup(filterGroup: number): void;
234
- deleteFilterGroup(groupId: number): void;
235
219
  updateFilter(updatedFilter: Filter): void;
236
220
  deleteFilter(filter: Filter): void;
237
221
  addFilter(filter: Filter): void;
238
222
  generateFilterQuery(): string;
239
223
  fetchRecommendationProducts(): Promise<void>;
224
+ _doFetchProducts(): Promise<void>;
240
225
  }>;
241
226
  export {};
@@ -106,6 +106,14 @@ export interface RecommendationNodeConfig {
106
106
  * Vertical spacing between product rows in pixels
107
107
  */
108
108
  rowSpacing: number;
109
+ /**
110
+ * Horizontal spacing between product cards on mobile in pixels (grid layout only)
111
+ */
112
+ mobileColumnSpacing: number;
113
+ /**
114
+ * Vertical spacing between product rows on mobile in pixels
115
+ */
116
+ mobileRowSpacing: number;
109
117
  /**
110
118
  * Order of card elements from top to bottom
111
119
  * Array of ATTR_PRODUCT_* constants
@@ -17,6 +17,7 @@ export declare class UnsubscribeControl extends Control {
17
17
  private _onButtonClick;
18
18
  private _onPrevClick;
19
19
  private _onNextClick;
20
+ private _loadAndUpdatePreview;
20
21
  private _updatePreview;
21
22
  private _updateCounter;
22
23
  private _getPreview;
@@ -17,6 +17,24 @@ ue-notifications-container .alert-message-wrapper {
17
17
  padding: 16px 24px;
18
18
  }
19
19
 
20
+ ue-notifications-container .alert-message-wrapper.info,
21
+ ue-notifications-container .alert-message-wrapper.loader {
22
+ background-color: var(--guido-color-background-toaster-info) !important;
23
+ color: inherit;
24
+ }
25
+
26
+ .alert-message-wrapper .alert-message-main {
27
+ align-items: center;
28
+ }
29
+
30
+ ue-notifications-container ue-caption .caption {
31
+ color: var(--guido-color-white) !important;
32
+ }
33
+
34
+ ue-block-thumb-hint {
35
+ text-align: left;
36
+ }
37
+
20
38
  ue-notifications-container .alert-message-wrapper .alert-message-main .alert-message-content {
21
39
  width: calc(100% - 64px);
22
40
  }
@@ -1,4 +1,4 @@
1
- const o = `ue-emoji .emoji-tabs .active-smile-tab {
1
+ const e = `ue-emoji .emoji-tabs .active-smile-tab {
2
2
  border-color: var(--guido-color-primary-500);
3
3
  }
4
4
 
@@ -17,7 +17,11 @@ ue-insert-table .template-cell {
17
17
  border: 1px solid var(--guido-color-gray-300);
18
18
  box-shadow: var(--guido-box-shadow);
19
19
  }
20
+
21
+ .ue-popover.dark-tiny {
22
+ text-align: left !important;
23
+ }
20
24
  `;
21
25
  export {
22
- o as default
26
+ e as default
23
27
  };
@@ -10,6 +10,7 @@ const o = `:host {
10
10
  --guido-color-gray-1: #F0F0F0;
11
11
  --guido-color-gray-0: #F9F9F9;
12
12
  --guido-color-neutral-800: #222938;
13
+ --guido-color-neutral-700: #2C3546;
13
14
  --guido-color-neutral-200: #DCDFE6;
14
15
  --guido-color-neutral-100: #EFF2F4;
15
16
  --guido-color-danger-300: #e84342;
@@ -25,6 +26,7 @@ const o = `:host {
25
26
  --guido-color-border-onpage-message-error: var(--guido-color-danger-500);
26
27
  --guido-color-background-toaster-success: #128745;
27
28
  --guido-color-background-toaster-error: var(--guido-color-danger-500);
29
+ --guido-color-background-toaster-info: var(--guido-color-neutral-700);
28
30
  --guido-color-background-toaster-warn: #D37400;
29
31
  }
30
32
  `;