@useinsider/guido 2.1.0-beta.42f5dfa → 2.1.0-beta.486ee9c

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 (112) hide show
  1. package/README.md +36 -0
  2. package/dist/@types/config/schemas.js +70 -65
  3. package/dist/components/Guido.vue.js +1 -1
  4. package/dist/components/Guido.vue2.js +69 -58
  5. package/dist/components/organisms/base/Toaster.vue.js +4 -4
  6. package/dist/components/organisms/base/Toaster.vue2.js +12 -9
  7. package/dist/components/organisms/email-preview/desktop-preview/EmailSizeIndicator.vue.js +5 -5
  8. package/dist/components/organisms/email-preview/desktop-preview/EmailSizeIndicator.vue2.js +2 -2
  9. package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +11 -13
  10. package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +54 -23
  11. package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue.js +7 -5
  12. package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue2.js +34 -21
  13. package/dist/components/organisms/extensions/recommendation/Filters.vue.js +11 -11
  14. package/dist/components/organisms/extensions/recommendation/Filters.vue2.js +48 -36
  15. package/dist/components/organisms/extensions/recommendation/LogicAdapter.vue2.js +11 -9
  16. package/dist/components/organisms/header/HeaderWrapper.vue.js +9 -9
  17. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue.js +1 -1
  18. package/dist/components/organisms/unsubscribe/UnsubscribePageSelection.vue2.js +19 -19
  19. package/dist/composables/useBlocksConfig.js +26 -16
  20. package/dist/composables/useHtmlValidator.js +107 -119
  21. package/dist/composables/useRecommendation.js +9 -9
  22. package/dist/composables/useStripo.js +25 -23
  23. package/dist/composables/useVersionHistoryApi.js +1 -1
  24. package/dist/config/compiler/utils/recommendationCompilerUtils.js +28 -23
  25. package/dist/config/i18n/en/index.js +11 -0
  26. package/dist/config/i18n/en/labels.json.js +7 -0
  27. package/dist/config/i18n/en/toasters.json.js +56 -0
  28. package/dist/config/i18n/en/tooltips.json.js +82 -0
  29. package/dist/config/i18n/index.js +7 -0
  30. package/dist/config/migrator/itemsBlockMigrator.js +127 -122
  31. package/dist/config/migrator/recommendationMigrator.js +1 -1
  32. package/dist/enums/defaults.js +8 -4
  33. package/dist/extensions/Blocks/Recommendation/block.js +26 -23
  34. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +37 -33
  35. package/dist/extensions/Blocks/Recommendation/constants/layout.js +16 -12
  36. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +15 -11
  37. package/dist/extensions/Blocks/Recommendation/controls/button/index.js +9 -9
  38. package/dist/extensions/Blocks/Recommendation/controls/image/index.js +1 -1
  39. package/dist/extensions/Blocks/Recommendation/controls/layout/index.js +41 -29
  40. package/dist/extensions/Blocks/Recommendation/controls/main/algorithm.js +16 -16
  41. package/dist/extensions/Blocks/Recommendation/controls/main/currency.js +30 -32
  42. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +217 -94
  43. package/dist/extensions/Blocks/Recommendation/controls/main/locale.js +9 -9
  44. package/dist/extensions/Blocks/Recommendation/controls/main/productLayout.js +97 -39
  45. package/dist/extensions/Blocks/Recommendation/controls/main/shuffle.js +16 -16
  46. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +304 -209
  47. package/dist/extensions/Blocks/Recommendation/controls/mobileLayout/cssRules.js +21 -0
  48. package/dist/extensions/Blocks/Recommendation/controls/name/index.js +10 -10
  49. package/dist/extensions/Blocks/Recommendation/controls/name/textTrim.js +5 -5
  50. package/dist/extensions/Blocks/Recommendation/controls/oldPrice/index.js +14 -14
  51. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/index.js +9 -9
  52. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textAfter.js +3 -3
  53. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textBefore.js +1 -1
  54. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/index.js +9 -9
  55. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textAfter.js +3 -3
  56. package/dist/extensions/Blocks/Recommendation/controls/omnibusPrice/textBefore.js +13 -13
  57. package/dist/extensions/Blocks/Recommendation/controls/price/index.js +3 -3
  58. package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +223 -99
  59. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +237 -140
  60. package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +27 -32
  61. package/dist/extensions/Blocks/Recommendation/templates/grid/migration.js +1 -1
  62. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +27 -30
  63. package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +22 -27
  64. package/dist/extensions/Blocks/Recommendation/templates/utils.js +50 -38
  65. package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +8 -8
  66. package/dist/extensions/Blocks/Recommendation/validation/filterSchema.js +29 -0
  67. package/dist/extensions/Blocks/Unsubscribe/block.js +29 -29
  68. package/dist/extensions/Blocks/Unsubscribe/control.js +12 -9
  69. package/dist/extensions/Blocks/Unsubscribe/elements/preview.js +13 -11
  70. package/dist/extensions/Blocks/Unsubscribe/styles.css.js +31 -1
  71. package/dist/extensions/ModulesTabIcons/extension.js +17 -0
  72. package/dist/guido.css +1 -1
  73. package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +257 -187
  74. package/dist/services/recommendationApi.js +11 -9
  75. package/dist/services/stripoApi.js +20 -17
  76. package/dist/src/@types/config/schemas.d.ts +8 -0
  77. package/dist/src/components/organisms/extensions/recommendation/FilterItem.vue.d.ts +1 -0
  78. package/dist/src/components/organisms/extensions/recommendation/Filters.vue.d.ts +17 -1
  79. package/dist/src/composables/useConfig.d.ts +4 -0
  80. package/dist/src/config/i18n/en/index.d.ts +1 -0
  81. package/dist/src/config/i18n/index.d.ts +16 -0
  82. package/dist/src/enums/defaults.d.ts +4 -0
  83. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +6 -0
  84. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +3 -3
  85. package/dist/src/extensions/Blocks/Recommendation/constants/layout.d.ts +12 -2
  86. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +12 -1
  87. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +50 -11
  88. package/dist/src/extensions/Blocks/Recommendation/controls/main/productLayout.d.ts +22 -4
  89. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +36 -16
  90. package/dist/src/extensions/Blocks/Recommendation/controls/mobileLayout/cssRules.d.ts +29 -0
  91. package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +50 -17
  92. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +26 -2
  93. package/dist/src/extensions/Blocks/Recommendation/templates/grid/migration.d.ts +1 -1
  94. package/dist/src/extensions/Blocks/Recommendation/templates/grid/template.d.ts +1 -1
  95. package/dist/src/extensions/Blocks/Recommendation/templates/index.d.ts +4 -0
  96. package/dist/src/extensions/Blocks/Recommendation/templates/list/migration.d.ts +1 -1
  97. package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +12 -3
  98. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +14 -0
  99. package/dist/src/extensions/Blocks/Recommendation/validation/filterSchema.d.ts +15 -0
  100. package/dist/src/extensions/Blocks/Unsubscribe/control.d.ts +1 -0
  101. package/dist/src/extensions/ModulesTabIcons/extension.d.ts +2 -0
  102. package/dist/src/stores/config.d.ts +36 -0
  103. package/dist/static/styles/components/notification.css.js +19 -0
  104. package/dist/static/styles/components/tools.css.js +6 -2
  105. package/dist/static/styles/components/version-history.css.js +10 -2
  106. package/dist/static/styles/components/wide-panel.css.js +18 -2
  107. package/dist/static/styles/customEditorStyle.css.js +59 -31
  108. package/dist/static/styles/variables.css.js +2 -0
  109. package/dist/static/templates/empty/index.html.js +74 -0
  110. package/dist/static/templates/empty/style.css.js +779 -0
  111. package/dist/stores/unsubscribe.js +37 -34
  112. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
- import { useHttp as a } from "../composables/useHttp.js";
2
- import { URLS as s } from "../enums/extensions/recommendationBlock.js";
3
- const u = () => {
4
- const { get: o } = a();
1
+ import { useHttp as c } from "../composables/useHttp.js";
2
+ import { URLS as m } from "../enums/extensions/recommendationBlock.js";
3
+ const f = () => {
4
+ const { get: o } = c();
5
5
  return {
6
6
  fetchRecommendationCreateData: async () => {
7
7
  try {
@@ -18,13 +18,15 @@ const u = () => {
18
18
  throw console.error("fetchRecommendationFilters error:", e), e;
19
19
  }
20
20
  },
21
- fetchRecommendationProducts: async (e, c) => {
21
+ fetchRecommendationProducts: async (e, a) => {
22
22
  var n;
23
23
  try {
24
- const t = decodeURIComponent(new URLSearchParams(Object.entries(c)).toString());
24
+ const t = decodeURIComponent(new URLSearchParams(Object.entries(a)).toString());
25
25
  console.debug("🏁 Recommendation API Query:", t);
26
- const r = await o(
27
- `${s.RECOMMENDATION_API_URL}/v2/${e}?${t}`
26
+ const { get: s } = c({
27
+ headers: {}
28
+ }), r = await s(
29
+ `${m.RECOMMENDATION_API_URL}/v2/${e}?${t}`
28
30
  );
29
31
  return ((n = r == null ? void 0 : r.data) == null ? void 0 : n.data) ?? [];
30
32
  } catch (t) {
@@ -34,5 +36,5 @@ const u = () => {
34
36
  };
35
37
  };
36
38
  export {
37
- u as useRecommendationApi
39
+ f as useRecommendationApi
38
40
  };
@@ -1,44 +1,47 @@
1
- import { useHttp as m } from "../composables/useHttp.js";
2
- import { useToaster as i } from "../composables/useToaster.js";
3
- import { MAX_DEFAULT_TEMPLATE_ID as p } from "../enums/defaults.js";
4
- const y = () => {
5
- const { get: r } = m(), { handleError: o } = i();
1
+ import { useHttp as l } from "../composables/useHttp.js";
2
+ import { useToaster as u } from "../composables/useToaster.js";
3
+ import { MAX_DEFAULT_TEMPLATE_ID as d } from "../enums/defaults.js";
4
+ import f from "../static/templates/empty/index.html.js";
5
+ import g from "../static/templates/empty/style.css.js";
6
+ const D = () => {
7
+ const { get: o } = l(), { handleError: a } = u();
6
8
  return {
7
9
  getToken: async () => {
8
10
  try {
9
- const t = Number(localStorage.getItem("ins-guido-test-instance")), { data: e } = await r(`/stripo/get-user-token?test=${t}`);
11
+ const t = Number(localStorage.getItem("ins-guido-test-instance")), { data: e } = await o(`/stripo/get-user-token?test=${t}`);
10
12
  return e.body.token;
11
13
  } catch (t) {
12
- return o(t, "Failed to fetch token"), "";
14
+ return a(t, "Failed to fetch token"), "";
13
15
  }
14
16
  },
15
17
  getCustomFonts: async () => {
16
18
  try {
17
- const { data: t = [] } = await r("/stripo/get-partner-custom-fonts");
19
+ const { data: t = [] } = await o("/stripo/get-partner-custom-fonts");
18
20
  return t.map((e) => ({
19
21
  ...e,
20
22
  active: !0
21
23
  }));
22
24
  } catch (t) {
23
- return o(t, "Failed to fetch custom fonts"), [];
25
+ return a(t, "Failed to fetch custom fonts"), [];
24
26
  }
25
27
  },
26
28
  getDefaultTemplate: async () => {
27
29
  const t = {
28
- html: "",
29
- css: ""
30
+ html: f,
31
+ css: g
30
32
  };
31
33
  try {
32
- const c = new URLSearchParams(window.location.search).get("default-template"), s = c ? parseInt(c) : 0, l = s >= 1 && s <= p ? s : 0, { data: n } = await r(
33
- `/stripo/default-template/${l}`
34
- ), a = typeof n == "string" ? JSON.parse(n) : n;
35
- return !a || typeof a != "object" || !("html" in a) || !("css" in a) ? t : a;
34
+ const e = new URLSearchParams(window.location.search), c = e.get("default-template"), p = e.get("master"), s = c ? parseInt(c) : 0, m = s >= 1 && s <= d ? s : 0;
35
+ if (!m && !p)
36
+ return t;
37
+ const i = `/stripo/default-template/${m}`, { data: n } = await o(i), r = typeof n == "string" ? JSON.parse(n) : n;
38
+ return !r || typeof r != "object" || !("html" in r) || !("css" in r) ? t : r;
36
39
  } catch (e) {
37
- return o(e, "Failed to fetch default template"), t;
40
+ return a(e, "Failed to fetch default template"), t;
38
41
  }
39
42
  }
40
43
  };
41
44
  };
42
45
  export {
43
- y as useStripoApi
46
+ D as useStripoApi
44
47
  };
@@ -129,6 +129,10 @@ export declare const EditorSchema: v.ObjectSchema<{
129
129
  readonly senderName: "";
130
130
  readonly subject: "";
131
131
  }>;
132
+ /** Folder name for user-saved modules (used by Stripo plugin panel for path construction) */
133
+ readonly savedModulesFolderName: v.OptionalSchema<v.StringSchema<undefined>, "savedModules">;
134
+ /** Folder name for default/prebuilt modules (used by Stripo plugin panel for path construction) */
135
+ readonly defaultModulesFolderName: v.OptionalSchema<v.StringSchema<undefined>, "defaultModules">;
132
136
  }, undefined>;
133
137
  /**
134
138
  * UI configuration - visual elements and layout
@@ -441,6 +445,10 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
441
445
  readonly senderName: "";
442
446
  readonly subject: "";
443
447
  }>;
448
+ /** Folder name for user-saved modules (used by Stripo plugin panel for path construction) */
449
+ readonly savedModulesFolderName: v.OptionalSchema<v.StringSchema<undefined>, "savedModules">;
450
+ /** Folder name for default/prebuilt modules (used by Stripo plugin panel for path construction) */
451
+ readonly defaultModulesFolderName: v.OptionalSchema<v.StringSchema<undefined>, "defaultModules">;
444
452
  }, undefined>, {}>;
445
453
  /** UI configuration */
446
454
  readonly ui: v.OptionalSchema<v.ObjectSchema<{
@@ -3,6 +3,7 @@ type __VLS_Props = {
3
3
  filter: Filter;
4
4
  index: number;
5
5
  hasLogicAdapter?: boolean;
6
+ submitted: boolean;
6
7
  };
7
8
  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, {
8
9
  "delete-filter": (filter: Filter) => void;
@@ -1,2 +1,18 @@
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<{}>>, {}>;
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>>>, {}>;
2
9
  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
+ };
@@ -41,6 +41,8 @@ export declare const useConfig: () => {
41
41
  senderName: string;
42
42
  subject: string;
43
43
  };
44
+ savedModulesFolderName: string;
45
+ defaultModulesFolderName: string;
44
46
  };
45
47
  ui: {
46
48
  showHeader: boolean;
@@ -130,6 +132,8 @@ export declare const useConfig: () => {
130
132
  senderName: string;
131
133
  subject: string;
132
134
  };
135
+ savedModulesFolderName: string;
136
+ defaultModulesFolderName: string;
133
137
  } | null>;
134
138
  ui: import("vue").ComputedRef<{
135
139
  showHeader: boolean;
@@ -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
+ };
@@ -9,3 +9,7 @@ export declare const TemplateTypes: {
9
9
  export declare const EditorType: number;
10
10
  export declare const MAX_DEFAULT_TEMPLATE_ID = 13;
11
11
  export declare const ProductIds: Record<string, number>;
12
+ export declare const ModuleFolderDefaults: {
13
+ readonly SAVED_MODULES: "savedModules";
14
+ readonly DEFAULT_MODULES: "defaultModules";
15
+ };
@@ -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, 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, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_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, MOBILE_ROW_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';
@@ -23,10 +23,20 @@ export declare const MIN_PRODUCT_COUNT = 1;
23
23
  export declare const MAX_PRODUCTS_PER_ROW = 4;
24
24
  /** Minimum number of products per row in grid layout */
25
25
  export declare const MIN_PRODUCTS_PER_ROW = 1;
26
+ /** Default number of products per row on mobile */
27
+ export declare const DEFAULT_MOBILE_CARDS_IN_ROW = 1;
28
+ /** Maximum products per row on mobile */
29
+ export declare const MAX_MOBILE_PRODUCTS_PER_ROW = 2;
30
+ /** Minimum products per row on mobile */
31
+ export declare const MIN_MOBILE_PRODUCTS_PER_ROW = 1;
26
32
  /** Default column spacing between product cards (5px on each side = 10px total) */
27
33
  export declare const DEFAULT_COLUMN_SPACING = 10;
28
- /** Default row spacing between product rows */
29
- 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;
30
40
  /** Minimum spacing value */
31
41
  export declare const MIN_SPACING = 0;
32
42
  /** Maximum spacing value */
@@ -1,11 +1,22 @@
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 = ".recommendation-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";
14
+ /** Desktop product container selector */
15
+ export declare const DESKTOP_CONTAINER_SELECTOR = ".ins-recommendation-desktop-container";
16
+ /** Mobile product container selector */
17
+ export declare const MOBILE_CONTAINER_SELECTOR = ".ins-recommendation-mobile-container";
18
+ /** Mobile row wrapper — the <tr> that wraps the mobile container <td>/<table> */
19
+ export declare const MOBILE_ROW_SELECTOR = ".ins-recommendation-mobile-row";
9
20
  /**
10
21
  * Currency HTML attributes set on the block element
11
22
  * These are read by the HTML compiler at runtime to format prices
@@ -16,7 +16,6 @@ export * from './utils';
16
16
  export declare class RecommendationBlockControl extends CommonControl {
17
17
  private store;
18
18
  private storeUnsubscription;
19
- private initializedBlocks;
20
19
  private algorithmControl;
21
20
  private localeControl;
22
21
  private currencyControl;
@@ -26,24 +25,46 @@ export declare class RecommendationBlockControl extends CommonControl {
26
25
  getId(): string;
27
26
  getTemplate(): string;
28
27
  onRender(): Promise<void>;
29
- /**
30
- * Immediately regenerate products with styles (no debounce)
31
- * Used for initial load after fetch completes
32
- */
33
- private _regenerateWithProducts;
34
28
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
35
29
  onDestroy(): void;
36
30
  /**
37
31
  * Initialize all sub-controls with the shared API context
38
32
  * Each sub-control manages its own form values and event listeners
39
33
  */
40
- _initializeSubControls(): void;
34
+ private _initializeSubControls;
35
+ /**
36
+ * Syncs persisted node config into the Pinia store's block state.
37
+ *
38
+ * setCurrentBlock() creates a default entry (USD, en_US, mostPopular).
39
+ * For saved templates, the real config lives in the node (e.g., TRY, tr_TR).
40
+ * This method reads it and patches the store so fetchRecommendationProducts()
41
+ * uses the correct values.
42
+ *
43
+ * Uses triggerRefetch: false because the fetch hasn't happened yet —
44
+ * values are being prepared for the upcoming initial fetch.
45
+ */
46
+ private _syncNodeConfigToStore;
41
47
  /**
42
- * 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
+ *
43
53
  * Shared by onRender() and onTemplateNodeUpdated() to avoid duplication.
44
54
  * Marks the block as initialized to prevent redundant fetches on re-selection.
45
55
  */
46
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;
47
68
  /**
48
69
  * Reads the recommendation-id attribute from the block element within the node
49
70
  */
@@ -53,8 +74,15 @@ export declare class RecommendationBlockControl extends CommonControl {
53
74
  */
54
75
  private _debouncedFetchProducts;
55
76
  /**
56
- * Debounced regeneration when products arrive from API
57
- * 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.
58
86
  */
59
87
  private _debouncedRegenerateWithProducts;
60
88
  /**
@@ -63,6 +91,17 @@ export declare class RecommendationBlockControl extends CommonControl {
63
91
  * Uses configVersion counter (incremented only by patchCurrentBlockConfig)
64
92
  * to distinguish user-initiated config changes from internal mutations
65
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.
100
+ */
101
+ private _listenStateUpdates;
102
+ /**
103
+ * Persists the current filter state from Pinia store to the Stripo node config.
104
+ * This ensures filters survive template save/reload cycles.
66
105
  */
67
- _listenStateUpdates(): void;
106
+ private _persistFiltersToNodeConfig;
68
107
  }
@@ -3,9 +3,13 @@
3
3
  *
4
4
  * Handles product display configuration:
5
5
  * - Number of products to show
6
- * - Products per row (hidden for list layout)
6
+ * - Products per row on desktop (hidden for list layout)
7
+ * - Products per row on mobile (hidden for list layout)
7
8
  * - Triggers product row regeneration on changes
8
9
  *
10
+ * Desktop/mobile counters swap visibility based on editor mode
11
+ * (detected via Stripo's EditorStatePropertyType.previewDeviceMode).
12
+ *
9
13
  * Configuration is stored via node config (persists with template).
10
14
  */
11
15
  import type { ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
@@ -13,6 +17,7 @@ import { CommonControl } from '../../../common-control';
13
17
  export declare const PRODUCT_LAYOUT_CONTROL_ID = "recommendation-product-layout-control";
14
18
  /**
15
19
  * Control for configuring product count and layout density
20
+ * Includes both desktop and mobile "products per row" counters
16
21
  */
17
22
  export declare class ProductLayoutControl extends CommonControl {
18
23
  private store;
@@ -24,13 +29,26 @@ export declare class ProductLayoutControl extends CommonControl {
24
29
  onDestroy(): void;
25
30
  _setFormValues(): void;
26
31
  /**
27
- * Updates "Products in One Row" visibility based on layout orientation
28
- * This control is hidden for list layout (products always take full width)
29
- * Reads from node config first, falls back to 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 counter visibility based on layout orientation and editor mode.
38
+ * - List layout: hide both counters (products always full-width)
39
+ * - Grid + desktop mode: show desktop counter, hide mobile counter
40
+ * - Grid + mobile mode: show mobile counter, hide desktop counter
30
41
  */
31
42
  _updateProductsInRowVisibility(): void;
43
+ /**
44
+ * Subscribes to editor preview mode changes via Stripo API.
45
+ * When the user switches between desktop/mobile preview, toggles
46
+ * which "Products in One Row" counter is visible.
47
+ */
48
+ _subscribeToEditorModeChanges(): void;
32
49
  _onProductCountChange(value: string): void;
33
50
  _onProductsInRowChange(value: number): void;
51
+ _onMobileCardsInRowChange(value: number): void;
34
52
  _regenerateProductRows(): void;
35
53
  _debouncedRegenerateProductRows: import("@vueuse/shared").PromisifyFn<() => void>;
36
54
  _listenToFormUpdates(): void;
@@ -58,8 +58,18 @@ export interface RegenerateProductRowsOptions {
58
58
  layout?: Orientation;
59
59
  }
60
60
  /**
61
- * Regenerates product rows based on current store configuration
62
- * Reads products, layout, and composition from store/DOM and rebuilds the HTML
61
+ * Regenerates only the mobile product container rows.
62
+ * Used when mobile-specific settings change (mobileCardsInRow)
63
+ * or when the desktop container is regenerated (to keep both in sync).
64
+ *
65
+ * For list layout: hides the mobile row entirely (list is inherently responsive).
66
+ * For grid layout: shows the mobile row and populates it.
67
+ */
68
+ export declare function regenerateMobileProductRows(options: Omit<RegenerateProductRowsOptions, 'afterRegenerate'>): void;
69
+ /**
70
+ * Regenerates product rows in the desktop container based on current store configuration.
71
+ * Also regenerates the mobile container to keep both in sync.
72
+ * Reads products, layout, and composition from store/DOM and rebuilds the HTML.
63
73
  * @param options - Configuration options for regeneration
64
74
  */
65
75
  export declare function regenerateProductRows(options: RegenerateProductRowsOptions): void;
@@ -68,8 +78,12 @@ export interface ReapplySpacingOptions {
68
78
  documentModifier: DocumentModifier;
69
79
  }
70
80
  /**
71
- * Reapplies spacing values from data attributes after product regeneration
72
- * This ensures spacing persists when products are regenerated
81
+ * Reapplies spacing values after product regeneration.
82
+ * Desktop spacing applies only to the desktop container;
83
+ * mobile spacing applies only to the mobile container.
84
+ *
85
+ * Reads values from node config (primary) with data-attribute fallback
86
+ * for backward compatibility with pre-nodeConfig templates.
73
87
  * @param options - Configuration options
74
88
  */
75
89
  export declare function reapplySpacing(options: ReapplySpacingOptions): void;
@@ -105,6 +119,17 @@ export interface RegenerateWithStylesOptions extends Omit<RegenerateProductRowsO
105
119
  * @param options - Configuration options for regeneration
106
120
  */
107
121
  export declare function regenerateProductRowsWithStyles(options: RegenerateWithStylesOptions): void;
122
+ /**
123
+ * Adjusts a products array to a target size.
124
+ * Used by ProductLayoutControl to synchronously match products to the new size
125
+ * before regeneration, avoiding the race condition where the store still holds
126
+ * products from the previous (stale) fetch.
127
+ *
128
+ * - More products than target → truncate
129
+ * - Fewer products than target → pad with dummy products
130
+ * - Exact match → return as-is
131
+ */
132
+ export declare function adjustProductsToSize(products: RecommendationProduct[], targetSize: number): RecommendationProduct[];
108
133
  type PriceKey = 'price' | 'original_price' | 'discount';
109
134
  /**
110
135
  * Formats a product price using current currency settings
@@ -142,16 +167,11 @@ export interface UpdateProductContentInPlaceOptions {
142
167
  * Updates product content in-place without regenerating HTML structure.
143
168
  * Preserves all user-applied styles by only touching dynamic content.
144
169
  *
145
- * This is the preferred method when:
146
- * - Product data changed but count remains the same
147
- * - Currency/locale changed (prices need reformatting)
148
- *
149
- * Uses setText() on text nodes instead of setInnerHtml() to preserve
150
- * Stripo's internal node references and avoid cursor/selection tracking issues.
170
+ * Scopes element queries to the desktop container to avoid double-counting
171
+ * mobile container elements (both containers share identical block IDs).
172
+ * After updating desktop, also updates mobile container to keep them in sync.
151
173
  *
152
- * Falls back to false when:
153
- * - Product count changed (need to add/remove elements)
154
- * - Cannot find required elements
174
+ * Falls back to false when product count changed (need to add/remove elements).
155
175
  * @param options - Configuration options
156
176
  * @returns true if in-place update was successful, false to fall back to full regeneration
157
177
  */
@@ -164,13 +184,13 @@ export interface UpdatePricesInPlaceOptions {
164
184
  * Updates only price displays in-place (for currency changes).
165
185
  * This is a lightweight update when only formatting changes, not product data.
166
186
  *
187
+ * Scopes element queries to the desktop container to avoid double-counting
188
+ * mobile container elements. After updating desktop, also updates mobile.
189
+ *
167
190
  * Perfect for:
168
191
  * - Currency symbol change
169
192
  * - Currency alignment change
170
193
  * - Decimal/thousand separator changes
171
- *
172
- * Uses setText() on text nodes instead of setInnerHtml() to preserve
173
- * Stripo's internal node references and avoid cursor/selection tracking issues.
174
194
  * @param options - Configuration options
175
195
  * @returns true if update was successful, false otherwise
176
196
  */
@@ -0,0 +1,29 @@
1
+ /**
2
+ * CSS rules for mobile grid layout visibility switching
3
+ *
4
+ * Follows the modifyCss pattern from textTrim control.
5
+ * Rules are injected into the document's stylesheet via modifyCss
6
+ * so they appear in the compiled HTML export.
7
+ */
8
+ import type { ImmutableCssNode } from '@stripoinc/ui-editor-extensions';
9
+ import { ModificationDescription } from '@stripoinc/ui-editor-extensions';
10
+ /** CSS class for desktop product container */
11
+ export declare const CSS_CLASS_DESKTOP_CONTAINER = "ins-recommendation-desktop-container";
12
+ /** CSS class for mobile product container */
13
+ export declare const CSS_CLASS_MOBILE_CONTAINER = "ins-recommendation-mobile-container";
14
+ interface CssModifierApi {
15
+ getDocumentRootCssNode: () => ImmutableCssNode | null;
16
+ getDocumentModifier: () => {
17
+ modifyCss: (node: ImmutableCssNode) => {
18
+ appendRule: (rule: string) => void;
19
+ };
20
+ apply: (desc: ModificationDescription) => void;
21
+ };
22
+ }
23
+ /**
24
+ * Ensures mobile layout CSS rules exist in the document stylesheet.
25
+ * Only adds rules if they don't already exist (prevents duplicates across multiple blocks).
26
+ * Follows the same pattern as textTrim's _ensureCssRulesExist().
27
+ */
28
+ export declare function ensureMobileCssRulesExist(api: CssModifierApi): void;
29
+ export {};