@useinsider/guido 3.7.0-beta.24a845f → 3.7.0-beta.24bdfa3

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 (42) hide show
  1. package/dist/@types/config/schemas.js +70 -66
  2. package/dist/composables/usePreviewMode.js +15 -14
  3. package/dist/composables/useRecommendationPreview.js +100 -0
  4. package/dist/config/compiler/utils/recommendationCompilerUtils.js +90 -82
  5. package/dist/config/migrator/recommendation/htmlBuilder.js +59 -58
  6. package/dist/config/migrator/recommendation/settingsMapper.js +38 -33
  7. package/dist/extensions/Blocks/Items/block.js +11 -16
  8. package/dist/extensions/Blocks/Recommendation/block.js +59 -43
  9. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +41 -32
  10. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +369 -288
  11. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +84 -72
  12. package/dist/extensions/Blocks/Recommendation/controls/main/pricePlacement.js +133 -0
  13. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +68 -66
  14. package/dist/extensions/Blocks/Recommendation/iconsRegistry.js +21 -7
  15. package/dist/extensions/Blocks/Recommendation/recommendation.css.js +64 -4
  16. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +7 -5
  17. package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +101 -72
  18. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +31 -30
  19. package/dist/extensions/Blocks/Recommendation/templates/index.js +9 -7
  20. package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +74 -59
  21. package/dist/extensions/Blocks/Recommendation/templates/list/template.js +21 -21
  22. package/dist/extensions/Blocks/Recommendation/templates/utils.js +88 -57
  23. package/dist/src/@types/config/schemas.d.ts +16 -0
  24. package/dist/src/composables/useConfig.d.ts +4 -0
  25. package/dist/src/composables/useRecommendationPreview.d.ts +10 -0
  26. package/dist/src/composables/useRecommendationPreview.test.d.ts +1 -0
  27. package/dist/src/config/migrator/recommendation/settingsMapper.d.ts +1 -1
  28. package/dist/src/extensions/Blocks/Items/block.d.ts +0 -1
  29. package/dist/src/extensions/Blocks/Recommendation/block.d.ts +10 -0
  30. package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +29 -3
  31. package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -1
  32. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +3 -1
  33. package/dist/src/extensions/Blocks/Recommendation/controls/main/pricePlacement.d.ts +59 -0
  34. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +2 -0
  35. package/dist/src/extensions/Blocks/Recommendation/templates/grid/elementRenderer.d.ts +16 -0
  36. package/dist/src/extensions/Blocks/Recommendation/templates/grid/template.d.ts +4 -4
  37. package/dist/src/extensions/Blocks/Recommendation/templates/list/elementRenderer.d.ts +13 -0
  38. package/dist/src/extensions/Blocks/Recommendation/templates/list/template.d.ts +3 -2
  39. package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +33 -1
  40. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +15 -0
  41. package/dist/src/stores/config.d.ts +36 -0
  42. package/package.json +1 -1
@@ -1,70 +1,75 @@
1
1
  import { CURRENT_CONFIG_VERSION as s, DEFAULT_CURRENCY as i } from "../../../extensions/Blocks/Recommendation/constants/defaultConfig.js";
2
- import { DEFAULT_CARDS_IN_ROW as m, DEFAULT_MOBILE_ROW_SPACING as p, DEFAULT_MOBILE_COLUMN_SPACING as f, DEFAULT_ROW_SPACING as S, DEFAULT_COLUMN_SPACING as d, DEFAULT_MOBILE_CARDS_IN_ROW as u } from "../../../extensions/Blocks/Recommendation/constants/layout.js";
3
- import { mapLegacyStrategy as c } from "../../../extensions/Blocks/Recommendation/utils/legacyStrategyMap.js";
4
- function l(t) {
2
+ import { DEFAULT_CARDS_IN_ROW as m, DEFAULT_MOBILE_ROW_SPACING as p, DEFAULT_MOBILE_COLUMN_SPACING as d, DEFAULT_ROW_SPACING as f, DEFAULT_COLUMN_SPACING as S, DEFAULT_MOBILE_CARDS_IN_ROW as a } from "../../../extensions/Blocks/Recommendation/constants/layout.js";
3
+ import { mapLegacyStrategy as l } from "../../../extensions/Blocks/Recommendation/utils/legacyStrategyMap.js";
4
+ function c(t) {
5
5
  return t === "0" || t === 0 ? "before" : "after";
6
6
  }
7
- function _(t) {
7
+ function I(t) {
8
8
  if (typeof t == "number" && Number.isFinite(t))
9
9
  return t;
10
10
  if (typeof t == "string") {
11
- const n = parseInt(t);
12
- if (!Number.isNaN(n))
13
- return n;
11
+ const o = parseInt(t);
12
+ if (!Number.isNaN(o))
13
+ return o;
14
14
  }
15
15
  return i.decimalCount;
16
16
  }
17
- function I(t) {
17
+ function _(t) {
18
18
  return t === "." || t === "," || t === " " || t === "" ? t : ",";
19
19
  }
20
- function A(t) {
20
+ function N(t) {
21
21
  return t === "." || t === "," || t === " " ? t : ".";
22
22
  }
23
- function N(t) {
23
+ function A(t) {
24
24
  if (!t || typeof t != "object")
25
25
  return { ...i };
26
- const n = t, o = n.value ?? n.name ?? i.code, r = n.symbol ?? o;
26
+ const o = t, n = o.value ?? o.name ?? i.code, r = o.symbol ?? n;
27
27
  return {
28
- code: o,
28
+ code: n,
29
29
  symbol: r,
30
- alignment: l(n.alignment),
31
- decimalCount: _(n.decimalCount),
32
- decimalSeparator: A(n.decimalSeparator),
33
- thousandSeparator: I(n.thousandSeparator)
30
+ alignment: c(o.alignment),
31
+ decimalCount: I(o.decimalCount),
32
+ decimalSeparator: N(o.decimalSeparator),
33
+ thousandSeparator: _(o.thousandSeparator)
34
34
  };
35
35
  }
36
- function R(t) {
36
+ function L(t) {
37
37
  return t === "horizontal" || t === "list" ? "list" : "grid";
38
38
  }
39
- function b(t) {
40
- return c(t) || "mostPopular";
39
+ function R(t) {
40
+ return l(t) || "mostPopular";
41
41
  }
42
- function D(t, n, o) {
43
- const r = n.rowCount ?? t.cardsInRow ?? m, a = n.totalCount ?? (typeof t.size == "string" ? parseInt(t.size) : t.size) ?? 6;
42
+ function U(t, o, n) {
43
+ const r = o.rowCount ?? t.cardsInRow ?? m, u = o.totalCount ?? (typeof t.size == "string" ? parseInt(t.size) : t.size) ?? 6;
44
44
  return {
45
- recommendationId: o,
46
- strategy: b(t.strategy),
45
+ recommendationId: n,
46
+ strategy: R(t.strategy),
47
47
  productIds: (t.productIds ?? []).map((e) => String(e)),
48
- size: String(a),
48
+ size: String(u),
49
49
  shuffleProducts: !!t.shuffleProducts,
50
50
  language: t.language ?? "en_US",
51
- currency: N(t.currencySettings),
51
+ currency: A(t.currencySettings),
52
52
  filters: (t.filters ?? []).map((e) => ({ ...e })),
53
- layout: R(t.orientation ?? n.orientation),
53
+ layout: L(t.orientation ?? o.orientation),
54
54
  cardsInRow: r,
55
- mobileCardsInRow: u,
55
+ mobileCardsInRow: a,
56
56
  mobileLayoutEnabled: !1,
57
- previousMobileCardsInRow: u,
58
- columnSpacing: d,
59
- rowSpacing: S,
60
- mobileColumnSpacing: f,
57
+ previousMobileCardsInRow: a,
58
+ columnSpacing: S,
59
+ rowSpacing: f,
60
+ mobileColumnSpacing: d,
61
61
  mobileRowSpacing: p,
62
62
  omnibusPrice: { textBefore: "", textAfter: "" },
63
63
  omnibusDiscount: { textBefore: "", textAfter: "" },
64
+ // Preserve the legacy price-placement toggles. Absent legacy keys map to
65
+ // `false`, matching the legacy default (prices inline, original price not
66
+ // gated). New Guido blocks default differently (see DEFAULT_NODE_CONFIG).
67
+ priceMovedToNextLine: !!t.isPriceMovedToNextLine,
68
+ priceHideIfSameAsDiscounted: !!t.isPriceDeletedForZeroSale,
64
69
  configVersion: s
65
70
  };
66
71
  }
67
72
  export {
68
- N as mapCurrency,
69
- D as mapSettings
73
+ A as mapCurrency,
74
+ U as mapSettings
70
75
  };
@@ -1,12 +1,12 @@
1
1
  import { BlockId as g } from "../../../enums/block.js";
2
- import { useOnboardingStore as u } from "../../../stores/onboarding.js";
3
- import { getMigrationBannerHtml as p } from "../../../utils/migrationBannerHtml.js";
4
- import { Block as f, BlockCompositionType as I, ModificationDescription as o } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ import { useOnboardingStore as p } from "../../../stores/onboarding.js";
3
+ import { getMigrationBannerHtml as f } from "../../../utils/migrationBannerHtml.js";
4
+ import { Block as u, BlockCompositionType as I, ModificationDescription as o } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
5
  import { SETTINGS_ENUMS as a, DefaultConfigValues as i } from "./enums/settingsEnums.js";
6
6
  import { getDefaultTemplate as C } from "./template.js";
7
7
  import { getItemsBlockContainer as y, getItemsBlockConfig as b, getDefaultItemsBlockConfig as h } from "./utils/nodeConfigUtils.js";
8
8
  const c = g.Items;
9
- class E extends f {
9
+ class E extends u {
10
10
  getId() {
11
11
  return c;
12
12
  }
@@ -23,7 +23,7 @@ class E extends f {
23
23
  return this.api.translate("Items lets you display personalized products based on user behavior.");
24
24
  }
25
25
  getSettingsPanelTitleHtml() {
26
- return p(
26
+ return f(
27
27
  c,
28
28
  this.api.translate("Items"),
29
29
  this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Items block and test your message to ensure it works properly.")
@@ -42,23 +42,18 @@ class E extends f {
42
42
  allowInnerBlocksDND() {
43
43
  return !1;
44
44
  }
45
- // Stripo's Block default is false. Items keeps its full config in nodeConfig
46
- // (esd-ext-config), so a saved module is self-contained and restores on re-drop.
47
- canBeSavedAsModule() {
48
- return !0;
49
- }
50
45
  onCreated(n) {
51
46
  const l = this.api.getDocumentModifier(), r = this.api.getDocumentRootCssNode();
52
47
  r.querySelector('[product-attr="imageSrc"] img') || l.modifyCss(r).appendRule('[product-attr="imageSrc"] img {object-fit: contain;}');
53
- const t = y(n);
54
- if (!t)
48
+ const e = y(n);
49
+ if (!e)
55
50
  return;
56
- const s = t.getNodeConfig(), m = s && Object.keys(s).length > 0, e = b(n);
57
- if (e != null && e.initialized)
58
- m ? e.blockInstanceId || this.api.getDocumentModifier().modifyHtml(t).setNodeConfig({ ...e, blockInstanceId: String(Date.now()) }).apply(new o("Assign block instance ID to block")) : this.api.getDocumentModifier().modifyHtml(t).setNodeConfig(e).apply(new o("Migrate legacy config to nodeConfig"));
51
+ const s = e.getNodeConfig(), m = s && Object.keys(s).length > 0, t = b(n);
52
+ if (t != null && t.initialized)
53
+ m ? t.blockInstanceId || this.api.getDocumentModifier().modifyHtml(e).setNodeConfig({ ...t, blockInstanceId: String(Date.now()) }).apply(new o("Assign block instance ID to block")) : this.api.getDocumentModifier().modifyHtml(e).setNodeConfig(t).apply(new o("Migrate legacy config to nodeConfig"));
59
54
  else {
60
55
  const d = h();
61
- this.api.getDocumentModifier().modifyHtml(t).setNodeConfig(d).apply(new o("Initialize Items block with default configuration")), u().startOnboarding("itemsOnboarding");
56
+ this.api.getDocumentModifier().modifyHtml(e).setNodeConfig(d).apply(new o("Initialize Items block with default configuration")), p().startOnboarding("itemsOnboarding");
62
57
  }
63
58
  }
64
59
  }
@@ -1,24 +1,24 @@
1
- var k = Object.defineProperty;
2
- var y = (a, r, t) => r in a ? k(a, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[r] = t;
3
- var d = (a, r, t) => y(a, typeof r != "symbol" ? r + "" : r, t);
1
+ var D = Object.defineProperty;
2
+ var y = (a, c, t) => c in a ? D(a, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[c] = t;
3
+ var h = (a, c, t) => y(a, typeof c != "symbol" ? c + "" : c, t);
4
4
  import { BlockId as B } from "../../../enums/block.js";
5
- import { getMigrationBannerHtml as D } from "../../../utils/migrationBannerHtml.js";
6
- import { Block as R, BlockCompositionType as C, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
- import { regenerateMobileProductRows as b } from "./controls/main/utils.js";
8
- import { ensureMobileCssRulesExist as p, setMobileLayoutOptOut as f, hasMobileLayoutOptOut as A } from "./controls/mobileLayout/cssRules.js";
9
- import { RecommendationConfigService as c } from "./services/configService.js";
10
- import { useRecommendationExtensionStore as g } from "./store/recommendation.js";
11
- import { getDefaultTemplate as E } from "./templates/grid/template.js";
12
- const _ = B.Recommendation, m = "recommendation-block-v2", u = "recommendation-id";
13
- let I = !1;
14
- class q extends R {
5
+ import { getMigrationBannerHtml as R } from "../../../utils/migrationBannerHtml.js";
6
+ import { Block as b, BlockCompositionType as A, ModificationDescription as g } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
+ import { regenerateMobileProductRows as C } from "./controls/main/utils.js";
8
+ import { ensureMobileCssRulesExist as p, setMobileLayoutOptOut as f, hasMobileLayoutOptOut as E } from "./controls/mobileLayout/cssRules.js";
9
+ import { RecommendationConfigService as s } from "./services/configService.js";
10
+ import { useRecommendationExtensionStore as d } from "./store/recommendation.js";
11
+ import { getDefaultTemplate as S } from "./templates/grid/template.js";
12
+ const _ = B.Recommendation, m = "recommendation-block-v2", u = "recommendation-id", I = "hide-price";
13
+ let k = !1;
14
+ class q extends b {
15
15
  constructor() {
16
16
  super();
17
17
  /**
18
18
  * Stores the ID generated in getTemplate() so onCreated() can reuse it.
19
19
  * This avoids generating a new (different) ID in onCreated().
20
20
  */
21
- d(this, "_pendingBlockId", null);
21
+ h(this, "_pendingBlockId", null);
22
22
  }
23
23
  getId() {
24
24
  return _;
@@ -27,7 +27,7 @@ class q extends R {
27
27
  return "recommendation-icon";
28
28
  }
29
29
  getBlockCompositionType() {
30
- return C.CONTAINER;
30
+ return A.CONTAINER;
31
31
  }
32
32
  getName() {
33
33
  return this.api.translate("Recommendation Block");
@@ -38,7 +38,7 @@ class q extends R {
38
38
  );
39
39
  }
40
40
  getSettingsPanelTitleHtml() {
41
- return D(
41
+ return R(
42
42
  _,
43
43
  this.api.translate("Recommendation Block"),
44
44
  this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
@@ -47,11 +47,8 @@ class q extends R {
47
47
  allowInnerBlocksDND() {
48
48
  return !1;
49
49
  }
50
- // Full config persists in nodeConfig (esd-ext-config) and is rebuilt at
51
- // compile time by hydrateRecommendationStoreFromRawHtml, so a saved module
52
- // restores its campaign/layout/styles when re-dropped into another email.
53
50
  canBeSavedAsModule() {
54
- return !0;
51
+ return !1;
55
52
  }
56
53
  /**
57
54
  * Returns the template HTML for a new recommendation block.
@@ -62,7 +59,7 @@ class q extends R {
62
59
  */
63
60
  getTemplate() {
64
61
  const t = this._generateNextId();
65
- return this._pendingBlockId = t, E(t);
62
+ return this._pendingBlockId = t, S(t);
66
63
  }
67
64
  /**
68
65
  * Called when a new block is dropped into the template
@@ -85,20 +82,20 @@ class q extends R {
85
82
  }
86
83
  const i = this._pendingBlockId ?? this._generateNextId();
87
84
  this._pendingBlockId = null, this._assignRecommendationId(t, i);
88
- const { config: n, wasFreshDrop: o } = c.initializeConfig(
85
+ const { config: n, wasFreshDrop: o } = s.initializeConfig(
89
86
  this.api,
90
87
  t,
91
88
  { recommendationId: i }
92
- ), s = g();
93
- if (s.setCurrentBlock(i), o) {
89
+ ), r = d();
90
+ if (r.setCurrentBlock(i), this._stampHidePrice(t, n.priceHideIfSameAsDiscounted), o) {
94
91
  p(this.api);
95
92
  const l = this._getBlockElement(t);
96
- l && (f(this.api, l, !0), b({
93
+ l && (f(this.api, l, !0), C({
97
94
  currentNode: t,
98
95
  documentModifier: this.api.getDocumentModifier()
99
96
  }));
100
97
  }
101
- s.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 });
98
+ r.patchCurrentBlockConfig({ language: n.language }, { triggerRefetch: !1 });
102
99
  }
103
100
  /**
104
101
  * Called when the document changes or template is loaded
@@ -111,20 +108,20 @@ class q extends R {
111
108
  if (!(!t || !("getNodeConfig" in t))) {
112
109
  if (!this._getRecommendationId(t)) {
113
110
  const e = this._generateNextId();
114
- this._assignRecommendationId(t, e), c.hasConfig(t) && c.updateConfig(
111
+ this._assignRecommendationId(t, e), s.hasConfig(t) && s.updateConfig(
115
112
  this.api,
116
113
  t,
117
114
  { recommendationId: e },
118
115
  "Assign recommendation ID to legacy block"
119
116
  );
120
117
  }
121
- this._healLingeringDuplicate(t), c.needsMigration(t) && this._migrateFromLegacy(t);
118
+ this._healLingeringDuplicate(t), s.needsMigration(t) && this._migrateFromLegacy(t), this._healHidePriceAttr(t);
122
119
  try {
123
- I || (p(this.api), I = !0);
124
- const e = c.getConfig(t), i = this._getBlockElement(t);
120
+ k || (p(this.api), k = !0);
121
+ const e = s.getConfig(t), i = this._getBlockElement(t);
125
122
  if (i) {
126
123
  const n = !e.mobileLayoutEnabled;
127
- A(i) !== n && f(this.api, i, n);
124
+ E(i) !== n && f(this.api, i, n);
128
125
  }
129
126
  } catch {
130
127
  }
@@ -138,7 +135,7 @@ class q extends R {
138
135
  */
139
136
  onDelete(t) {
140
137
  const e = this._getRecommendationId(t);
141
- e && g().removeBlockState(e);
138
+ e && d().removeBlockState(e);
142
139
  }
143
140
  /**
144
141
  * Generates the next unique recommendation ID by scanning all existing blocks
@@ -150,8 +147,8 @@ class q extends R {
150
147
  const e = this.api.getDocumentRoot();
151
148
  e && "querySelectorAll" in e && e.querySelectorAll(`.${m}`).forEach((n) => {
152
149
  if ("getAttribute" in n) {
153
- const o = n.getAttribute(u), s = o ? parseInt(o) : 0;
154
- s > t && (t = s);
150
+ const o = n.getAttribute(u), r = o ? parseInt(o) : 0;
151
+ r > t && (t = r);
155
152
  }
156
153
  });
157
154
  } catch {
@@ -185,13 +182,13 @@ class q extends R {
185
182
  const o = this._getBlockElement(t);
186
183
  if (!o)
187
184
  return;
188
- let s = -1;
185
+ let r = -1;
189
186
  for (let l = 0; l < n.length; l++)
190
187
  if (n[l] === o) {
191
- s = l;
188
+ r = l;
192
189
  break;
193
190
  }
194
- if (s <= 0)
191
+ if (r <= 0)
195
192
  return;
196
193
  this._reassignDuplicateId(t, e);
197
194
  } catch {
@@ -211,7 +208,7 @@ class q extends R {
211
208
  }
212
209
  /** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
213
210
  _handleDuplicate(t, e) {
214
- const i = this._reassignDuplicateId(t, e), n = g();
211
+ const i = this._reassignDuplicateId(t, e), n = d();
215
212
  n.cloneBlockState(e, i), n.setCurrentBlock(i);
216
213
  }
217
214
  /**
@@ -227,7 +224,7 @@ class q extends R {
227
224
  */
228
225
  _reassignDuplicateId(t, e) {
229
226
  const i = this._generateNextId(), n = this._getBlockElement(t);
230
- return this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), c.hasConfig(t) && c.updateConfig(
227
+ return this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), s.hasConfig(t) && s.updateConfig(
231
228
  this.api,
232
229
  t,
233
230
  { recommendationId: i },
@@ -244,8 +241,8 @@ class q extends R {
244
241
  _reassignInstanceClass(t, e, i) {
245
242
  if (!("getAttribute" in t))
246
243
  return;
247
- const n = `ins-recommendation-v3-block-${e}`, o = `ins-recommendation-v3-block-${i}`, s = this.api.getDocumentModifier();
248
- s.modifyHtml(t).removeClass(n).setClass(o), s.apply(new h(
244
+ const n = `ins-recommendation-v3-block-${e}`, o = `ins-recommendation-v3-block-${i}`, r = this.api.getDocumentModifier();
245
+ r.modifyHtml(t).removeClass(n).setClass(o), r.apply(new g(
249
246
  `Reassign recommendation instance class ${n} -> ${o}`
250
247
  ));
251
248
  }
@@ -260,7 +257,26 @@ class q extends R {
260
257
  if (!i)
261
258
  return;
262
259
  const n = this.api.getDocumentModifier();
263
- n.modifyHtml(i).setAttribute(u, e.toString()), n.apply(new h(`Assign recommendation ID ${e}`));
260
+ n.modifyHtml(i).setAttribute(u, e.toString()), n.apply(new g(`Assign recommendation ID ${e}`));
261
+ }
262
+ /**
263
+ * Stamps the `hide-price` attribute (read by email-service at send time) on
264
+ * the block element from the config flag.
265
+ */
266
+ _stampHidePrice(t, e) {
267
+ const i = this._getBlockElement(t);
268
+ i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(I, String(e)).apply(new g("Stamp hide-price"));
269
+ }
270
+ /**
271
+ * Stamps `hide-price` from config only when the block lacks the attribute —
272
+ * heals templates saved before this feature without dirtying current ones.
273
+ */
274
+ _healHidePriceAttr(t) {
275
+ const e = this._getBlockElement(t);
276
+ if (!e || !("getAttribute" in e) || e.getAttribute(I) !== null)
277
+ return;
278
+ const { priceHideIfSameAsDiscounted: i } = s.getConfig(t);
279
+ this._stampHidePrice(t, i);
264
280
  }
265
281
  /**
266
282
  * Gets the recommendation-id from a block node
@@ -290,7 +306,7 @@ class q extends R {
290
306
  * Migrate configuration from legacy format
291
307
  */
292
308
  _migrateFromLegacy(t) {
293
- c.migrateFromDataAttributes(this.api, t);
309
+ s.migrateFromDataAttributes(this.api, t);
294
310
  }
295
311
  }
296
312
  export {
@@ -1,34 +1,34 @@
1
- import { DEFAULT_COLUMN_SPACING as R, DEFAULT_ROW_SPACING as U, DEFAULT_MOBILE_ROW_SPACING as i, DEFAULT_MOBILE_COLUMN_SPACING as s, DEFAULT_MOBILE_CARDS_IN_ROW as o, DEFAULT_CARDS_IN_ROW as C } from "./layout.js";
2
- import { ATTR_PRODUCT_IMAGE as _, ATTR_PRODUCT_NAME as e, ATTR_PRODUCT_OLD_PRICE as t, ATTR_PRODUCT_PRICE as T, ATTR_PRODUCT_OMNIBUS_PRICE as r, ATTR_PRODUCT_OMNIBUS_DISCOUNT as I, ATTR_PRODUCT_BUTTON as n } from "./selectors.js";
3
- const O = {
1
+ import { DEFAULT_COLUMN_SPACING as n, DEFAULT_ROW_SPACING as s, DEFAULT_MOBILE_ROW_SPACING as R, DEFAULT_MOBILE_COLUMN_SPACING as U, DEFAULT_MOBILE_CARDS_IN_ROW as e, DEFAULT_CARDS_IN_ROW as C } from "./layout.js";
2
+ import { ATTR_PRODUCT_IMAGE as o, ATTR_PRODUCT_NAME as t, ATTR_PRODUCT_OLD_PRICE as _, ATTR_PRODUCT_PRICE as T, ATTR_PRODUCT_OMNIBUS_PRICE as r, ATTR_PRODUCT_OMNIBUS_DISCOUNT as i, ATTR_PRODUCT_BUTTON as I } from "./selectors.js";
3
+ const D = {
4
4
  code: "USD",
5
5
  symbol: "USD",
6
6
  alignment: "after",
7
7
  decimalCount: 2,
8
8
  decimalSeparator: ".",
9
9
  thousandSeparator: ","
10
- }, D = {
10
+ }, O = {
11
11
  textBefore: "",
12
12
  textAfter: ""
13
- }, A = {
13
+ }, a = {
14
14
  textBefore: "",
15
15
  textAfter: ""
16
- }, a = [
17
- _,
18
- e,
16
+ }, A = [
17
+ o,
19
18
  t,
19
+ _,
20
20
  T,
21
21
  r,
22
- I,
23
- n
24
- ], E = {
25
- [_]: !0,
26
- [e]: !0,
27
- [T]: !0,
22
+ i,
23
+ I
24
+ ], c = {
25
+ [o]: !0,
28
26
  [t]: !0,
27
+ [T]: !0,
28
+ [_]: !0,
29
29
  [r]: !1,
30
- [I]: !1,
31
- [n]: !0
30
+ [i]: !1,
31
+ [I]: !0
32
32
  }, l = {
33
33
  // Settings
34
34
  strategy: "mostPopular",
@@ -36,36 +36,45 @@ const O = {
36
36
  size: "6",
37
37
  shuffleProducts: !1,
38
38
  language: "en_US",
39
- currency: O,
39
+ currency: D,
40
40
  filters: [],
41
41
  // Layout
42
42
  layout: "grid",
43
43
  cardsInRow: C,
44
- mobileCardsInRow: o,
44
+ mobileCardsInRow: e,
45
45
  mobileLayoutEnabled: !1,
46
- previousMobileCardsInRow: o,
47
- columnSpacing: R,
48
- rowSpacing: U,
49
- mobileColumnSpacing: s,
50
- mobileRowSpacing: i,
46
+ previousMobileCardsInRow: e,
47
+ columnSpacing: n,
48
+ rowSpacing: s,
49
+ mobileColumnSpacing: U,
50
+ mobileRowSpacing: R,
51
51
  // Composition
52
- composition: a,
53
- visibility: E,
52
+ composition: A,
53
+ visibility: c,
54
54
  // Element settings
55
- omnibusPrice: D,
56
- omnibusDiscount: A,
55
+ omnibusPrice: O,
56
+ omnibusDiscount: a,
57
57
  textTrimming: !1,
58
+ // Price placement (block-level, affects all cards)
59
+ // Default ON = current stacked look, so existing templates are unaffected.
60
+ priceMovedToNextLine: !0,
61
+ // Default OFF: the original price always shows; the user opts in to hide it
62
+ // when it equals the sale price. Mirrors email-service's `hide-price` default
63
+ // of "false" (the actual hiding happens server-side at send).
64
+ priceHideIfSameAsDiscounted: !1,
58
65
  // Meta
66
+ // Version NOT bumped: mergeWithDefaults() backfills the two new fields from
67
+ // defaults, so no data transform (and no needsMigration trigger) is required.
59
68
  configVersion: 1,
60
69
  recommendationId: 0
61
70
  }, N = [11, 12], m = 1;
62
71
  export {
63
72
  m as CURRENT_CONFIG_VERSION,
64
- a as DEFAULT_COMPOSITION,
65
- O as DEFAULT_CURRENCY,
73
+ A as DEFAULT_COMPOSITION,
74
+ D as DEFAULT_CURRENCY,
66
75
  l as DEFAULT_NODE_CONFIG,
67
- A as DEFAULT_OMNIBUS_DISCOUNT,
68
- D as DEFAULT_OMNIBUS_PRICE,
69
- E as DEFAULT_VISIBILITY,
76
+ a as DEFAULT_OMNIBUS_DISCOUNT,
77
+ O as DEFAULT_OMNIBUS_PRICE,
78
+ c as DEFAULT_VISIBILITY,
70
79
  N as EXCLUDED_ALGORITHM_IDS
71
80
  };