@useinsider/guido 3.20.0-beta.0849ec7 → 3.20.0-beta.12889e0

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.
@@ -1,9 +1,10 @@
1
- import { useConfig as g } from "../../../composables/useConfig.js";
2
- import { useRecommendation as O } from "../../../composables/useRecommendation.js";
3
- import { MOBILE_ROW_SELECTOR as q, MOBILE_CONTAINER_SELECTOR as M, CSS_CLASS_RECO_BUTTON as B } from "../../../extensions/Blocks/Recommendation/constants/selectors.js";
4
- import { useRecommendationExtensionStore as N } from "../../../extensions/Blocks/Recommendation/store/recommendation.js";
5
- import { isIgnoredRecommendationBlock as T } from "./recommendationIgnoreUtils.js";
6
- function L(t, r, e, o, c = "") {
1
+ import { useConfig as O } from "../../../composables/useConfig.js";
2
+ import { useRecommendation as q } from "../../../composables/useRecommendation.js";
3
+ import { MOBILE_ROW_SELECTOR as L, MOBILE_CONTAINER_SELECTOR as M, CSS_CLASS_RECO_BUTTON as P } from "../../../extensions/Blocks/Recommendation/constants/selectors.js";
4
+ import { useRecommendationExtensionStore as R } from "../../../extensions/Blocks/Recommendation/store/recommendation.js";
5
+ import { FLUID_IMAGE_MOBILE_RULE as T, getFluidImageStyleChanges as B } from "../../../utils/fluidImageStyle.js";
6
+ import { isIgnoredRecommendationBlock as N } from "./recommendationIgnoreUtils.js";
7
+ function D(t, r, e, o, c = "") {
7
8
  const i = `{{${c}${t}_${r}_${e}}}`, n = `{{${c}${t}_${r}_currency}}`;
8
9
  return o === "before" ? `${n} ${i}` : `${i} ${n}`;
9
10
  }
@@ -13,13 +14,13 @@ function _(t) {
13
14
  [r] = r.children;
14
15
  return r;
15
16
  }
16
- function A(t, r, e, o, c, i) {
17
+ function E(t, r, e, o, c, i) {
17
18
  switch (r) {
18
19
  case "productImage": {
19
20
  const n = t.querySelector("img");
20
21
  n && (n.setAttribute("src", `{{${i}${e}_${o}_image_url}}`), n.setAttribute("alt", `{{${i}${e}_${o}_name}}`));
21
22
  const s = t.querySelector("a");
22
- s && (s.setAttribute("href", `{{${i}${e}_${o}_url}}`), s.classList.add(B));
23
+ s && (s.setAttribute("href", `{{${i}${e}_${o}_url}}`), s.classList.add(P));
23
24
  break;
24
25
  }
25
26
  case "productName": {
@@ -33,7 +34,7 @@ function A(t, r, e, o, c, i) {
33
34
  case "productPrice":
34
35
  case "productOldPrice": {
35
36
  const n = (l, d) => {
36
- l && (_(l).textContent = L(
37
+ l && (_(l).textContent = D(
37
38
  e,
38
39
  o,
39
40
  d,
@@ -77,24 +78,24 @@ function A(t, r, e, o, c, i) {
77
78
  }
78
79
  }
79
80
  }
80
- const P = "name";
81
+ const w = "name";
81
82
  function b(t, r, e, o) {
82
- const c = `${o}${r}_${e}_${P}`;
83
+ const c = `${o}${r}_${e}_${w}`;
83
84
  return {
84
85
  open: t.createComment(`{% if ${c} and ${c} != "" %}`),
85
86
  close: t.createComment("{% endif %}")
86
87
  };
87
88
  }
88
- function R(t, r, e) {
89
+ function F(t, r, e) {
89
90
  return b(t, r, 0, e);
90
91
  }
91
- function D(t, r, e, o) {
92
+ function v(t, r, e, o) {
92
93
  if (!t.innerHTML.includes("{{"))
93
94
  return;
94
95
  const { open: c, close: i } = b(t.ownerDocument, r, e, o);
95
96
  t.insertBefore(c, t.firstChild), t.appendChild(i);
96
97
  }
97
- function w(t, r, e, o) {
98
+ function H(t, r, e, o) {
98
99
  var n, s;
99
100
  if (!t.innerHTML.includes("{{"))
100
101
  return;
@@ -106,36 +107,36 @@ function W(t, r, e, o) {
106
107
  i.querySelectorAll("[data-attribute-type]").forEach((a) => {
107
108
  const u = a.getAttribute("data-attribute-type") || "", l = a.querySelectorAll(".attribute-cell");
108
109
  l.length > 0 ? l.forEach((d) => {
109
- A(d, u, r, n, e, o);
110
- }) : A(a, u, r, n, e, o);
111
- }), w(i, r, n, o);
110
+ E(d, u, r, n, e, o);
111
+ }) : E(a, u, r, n, e, o);
112
+ }), H(i, r, n, o);
112
113
  });
113
114
  }
114
- function v(t, r, e, o) {
115
+ function G(t, r, e, o) {
115
116
  const c = t.querySelectorAll(".recommendation-product-row");
116
117
  if (!c.length)
117
118
  return;
118
119
  const [i] = c, n = i.querySelector("[data-attribute-type]"), s = n ? n.querySelectorAll(".attribute-cell").length : 1;
119
120
  c.forEach((a, u) => {
120
121
  a.querySelectorAll("[data-attribute-type]").forEach((d) => {
121
- const p = d.getAttribute("data-attribute-type") || "";
122
- d.querySelectorAll(".attribute-cell").forEach((f, m) => {
123
- const h = u * s + m;
124
- A(f, p, r, h, e, o), D(f, r, h, o);
122
+ const f = d.getAttribute("data-attribute-type") || "";
123
+ d.querySelectorAll(".attribute-cell").forEach((p, m) => {
124
+ const y = u * s + m;
125
+ E(p, f, r, y, e, o), v(p, r, y, o);
125
126
  });
126
127
  });
127
128
  });
128
129
  }
129
- function H(t, r, e, o) {
130
+ function U(t, r, e, o) {
130
131
  t.querySelectorAll(".ins-recommendation-product-container").forEach((i) => {
131
- v(i, r, e, o);
132
+ G(i, r, e, o);
132
133
  });
133
134
  }
134
- function F(t, r, e) {
135
+ function I(t, r, e) {
135
136
  const o = t.getAttribute("data-layout") || "grid", c = t.getAttribute("currency-alignment") || "after";
136
- o === "list" ? W(t, r, c, e) : H(t, r, c, e);
137
+ o === "list" ? W(t, r, c, e) : U(t, r, c, e);
137
138
  }
138
- function y(t, r, e) {
139
+ function S(t, r, e) {
139
140
  const o = new RegExp(`${r}\\s*:\\s*(\\d+)\\s*px`, "i"), c = t.match(o);
140
141
  return c ? parseInt(c[1]) : e;
141
142
  }
@@ -150,7 +151,7 @@ function C(t) {
150
151
  const e = (t.getAttribute("style") || "").match(/(?:^|[;\s])width\s*:\s*(\d+(?:\.\d+)?(?:px|%))/i);
151
152
  return e && $(e[1]) ? e[1] : null;
152
153
  }
153
- function G(t, r) {
154
+ function V(t, r) {
154
155
  let e = t.parentElement;
155
156
  for (; e && e !== r; ) {
156
157
  if (e.tagName === "TD" && C(e))
@@ -159,60 +160,74 @@ function G(t, r) {
159
160
  }
160
161
  return null;
161
162
  }
162
- function V(t) {
163
- const r = t.getAttribute("style") || "", e = y(r, "width", 600), o = y(r, "padding", 0) * 2, c = Math.max(0, e - o);
164
- c !== 0 && t.querySelectorAll("img.adapt-img").forEach((i) => {
165
- if (i.hasAttribute("width"))
163
+ function A(t) {
164
+ const r = B(
165
+ (e) => t.style.getPropertyValue(e),
166
+ t.getAttribute("width")
167
+ );
168
+ Object.entries(r).forEach(([e, o]) => t.style.setProperty(e, o));
169
+ }
170
+ function X(t) {
171
+ const r = t.getAttribute("style") || "", e = S(r, "width", 600), o = S(r, "padding", 0) * 2, c = Math.max(0, e - o);
172
+ t.querySelectorAll("img.adapt-img").forEach((i) => {
173
+ if (i.hasAttribute("width") || c === 0) {
174
+ A(i);
166
175
  return;
167
- const n = G(i, t);
168
- if (!n)
176
+ }
177
+ const n = V(i, t);
178
+ if (!n) {
179
+ A(i);
169
180
  return;
170
- const s = C(n), a = y(n.getAttribute("style") || "", "padding", 0) * 2, u = s.endsWith("%") ? Math.floor(c * parseFloat(s) / 100) : parseInt(s), l = Math.max(1, u - a);
171
- i.setAttribute("width", String(l));
172
- const d = i.getAttribute("style") || "";
173
- if (!/\bwidth\s*:\s*\d/i.test(d)) {
174
- const p = d && !d.trim().endsWith(";") ? "; " : "";
175
- i.setAttribute("style", `${d}${p}width: ${l}px`);
176
181
  }
182
+ const s = C(n), a = S(n.getAttribute("style") || "", "padding", 0) * 2, u = s.endsWith("%") ? Math.floor(c * parseFloat(s) / 100) : parseInt(s), l = Math.max(1, u - a);
183
+ i.setAttribute("width", String(l)), A(i);
177
184
  });
178
185
  }
179
- const E = "MSO_MOBILE_HIDE_START", U = "MSO_MOBILE_HIDE_END";
180
- function X(t, r) {
181
- t.querySelectorAll(q).forEach((e) => {
186
+ const j = /\.recommendation-block-v2\s+\.adapt-img/;
187
+ function x(t, r) {
188
+ const e = r.some((i) => i.querySelector("img.adapt-img")), o = Array.from(t.querySelectorAll("style")).some((i) => j.test(i.textContent ?? ""));
189
+ if (!e || o || !t.head)
190
+ return;
191
+ const c = t.createElement("style");
192
+ c.setAttribute("type", "text/css"), c.textContent = T, t.head.appendChild(c);
193
+ }
194
+ const g = "MSO_MOBILE_HIDE_START", Y = "MSO_MOBILE_HIDE_END";
195
+ function k(t, r) {
196
+ t.querySelectorAll(L).forEach((e) => {
182
197
  var i, n;
183
198
  const o = e.querySelector(M);
184
199
  if (!o || o.children.length === 0)
185
200
  return;
186
201
  const c = e.previousSibling;
187
- (c == null ? void 0 : c.nodeType) === Node.COMMENT_NODE && c.data === E || ((i = e.parentNode) == null || i.insertBefore(r.createComment(E), e), (n = e.parentNode) == null || n.insertBefore(r.createComment(U), e.nextSibling));
202
+ (c == null ? void 0 : c.nodeType) === Node.COMMENT_NODE && c.data === g || ((i = e.parentNode) == null || i.insertBefore(r.createComment(g), e), (n = e.parentNode) == null || n.insertBefore(r.createComment(Y), e.nextSibling));
188
203
  });
189
204
  }
190
- function j(t, r) {
205
+ function z(t, r) {
191
206
  const e = t.match(/<!DOCTYPE[^>]*>/i);
192
207
  return (e ? `${e[0]}
193
208
  ` : "") + r.documentElement.outerHTML;
194
209
  }
195
- function Q(t) {
210
+ function rt(t) {
196
211
  const r = t.replaceAll("{%", "<!--{%").replaceAll("%}", "%}-->"), e = new DOMParser().parseFromString(r, "text/html"), o = e.querySelectorAll(".recommendation-block-v2");
197
212
  if (!o.length)
198
213
  return t;
199
- const { buildCampaignUrl: c } = O(), i = N();
214
+ const { buildCampaignUrl: c } = q(), i = R();
200
215
  i.recommendationCampaignUrls = {};
201
- const { isFeatureEnabled: n } = g(), s = n("liquidSyntax") ? "reco_" : "";
216
+ const { isFeatureEnabled: n } = O(), s = n("liquidSyntax") ? "reco_" : "";
202
217
  return o.forEach((u) => {
203
- var d, p, S, f;
218
+ var d, f, h, p;
204
219
  const l = u.getAttribute("recommendation-id");
205
220
  if (l) {
206
- if ((d = u.parentNode) == null || d.insertBefore(e.createComment("REC_START"), u), (p = u.parentNode) == null || p.insertBefore(e.createComment("REC_END"), u.nextSibling), u.querySelectorAll('[data-visibility="0"]').forEach((m) => m.remove()), c(l), X(u, e), !T(u)) {
207
- F(u, l, s);
208
- const { open: m, close: h } = R(e, l, s);
209
- (S = u.parentNode) == null || S.insertBefore(m, u), (f = u.parentNode) == null || f.insertBefore(h, u.nextSibling);
221
+ if ((d = u.parentNode) == null || d.insertBefore(e.createComment("REC_START"), u), (f = u.parentNode) == null || f.insertBefore(e.createComment("REC_END"), u.nextSibling), u.querySelectorAll('[data-visibility="0"]').forEach((m) => m.remove()), c(l), k(u, e), !N(u)) {
222
+ I(u, l, s);
223
+ const { open: m, close: y } = F(e, l, s);
224
+ (h = u.parentNode) == null || h.insertBefore(m, u), (p = u.parentNode) == null || p.insertBefore(y, u.nextSibling);
210
225
  }
211
- V(u);
226
+ X(u);
212
227
  }
213
- }), j(r, e).replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}").replaceAll("&lt;!--{%", "{%").replaceAll("%}--&gt;", "%}");
228
+ }), x(e, Array.from(o)), z(r, e).replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}").replaceAll("&lt;!--{%", "{%").replaceAll("%}--&gt;", "%}");
214
229
  }
215
230
  export {
216
- L as formatPriceVariable,
217
- Q as prepareRecommendationBlocks
231
+ D as formatPriceVariable,
232
+ rt as prepareRecommendationBlocks
218
233
  };
@@ -1,39 +1,40 @@
1
- var y = Object.defineProperty;
2
- var A = (l, c, t) => c in l ? y(l, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[c] = t;
3
- var h = (l, c, t) => A(l, typeof c != "symbol" ? c + "" : c, t);
1
+ var A = Object.defineProperty;
2
+ var B = (a, c, t) => c in a ? A(a, c, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[c] = t;
3
+ var p = (a, c, t) => B(a, typeof c != "symbol" ? c + "" : c, t);
4
4
  import { useConfig as d } from "../../../composables/useConfig.js";
5
5
  import { BlockId as D } from "../../../enums/block.js";
6
+ import { getFluidImageStyleChanges as E } from "../../../utils/fluidImageStyle.js";
6
7
  import { getMigrationBannerHtml as C } from "../../../utils/migrationBannerHtml.js";
7
- import { Block as E, BlockCompositionType as S, ModificationDescription as p } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
8
- import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as O } from "./constants/defaultConfig.js";
8
+ import { Block as S, BlockCompositionType as N, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
9
+ import { CURRENT_CONFIG_VERSION as M, PRE_RRS_CONFIG_VERSION as O } from "./constants/defaultConfig.js";
9
10
  import { RECOMMENDATION_ID_ATTR as m } from "./constants/selectors.js";
10
- import { regenerateMobileProductRows as M } from "./controls/main/utils.js";
11
- import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as w } from "./controls/mobileLayout/cssRules.js";
12
- import { RecommendationConfigService as s } from "./services/configService.js";
13
- import { useRecommendationExtensionStore as g } from "./store/recommendation.js";
11
+ import { regenerateMobileProductRows as w } from "./controls/main/utils.js";
12
+ import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as k, hasMobileLayoutOptOut as H } from "./controls/mobileLayout/cssRules.js";
13
+ import { RecommendationConfigService as l } from "./services/configService.js";
14
+ import { useRecommendationExtensionStore as f } from "./store/recommendation.js";
14
15
  import { getDefaultTemplate as T } from "./templates/grid/template.js";
15
16
  import { useRecommendationBlockWarning as v } from "./useRecommendationBlockWarning.js";
16
- const k = D.Recommendation, u = "recommendation-block-v2", B = "hide-price";
17
+ const R = D.Recommendation, u = "recommendation-block-v2", y = "hide-price";
17
18
  let b = !1;
18
- class j extends E {
19
+ class Q extends S {
19
20
  constructor() {
20
21
  super();
21
22
  /**
22
23
  * Stores the ID generated in getTemplate() so onCreated() can reuse it.
23
24
  * This avoids generating a new (different) ID in onCreated().
24
25
  */
25
- h(this, "_pendingBlockId", null);
26
+ p(this, "_pendingBlockId", null);
26
27
  /** Ids already reset under their new name, so the deferred pass skips their stale snapshot. */
27
- h(this, "_resetSourceIds", /* @__PURE__ */ new Set());
28
+ p(this, "_resetSourceIds", /* @__PURE__ */ new Set());
28
29
  }
29
30
  getId() {
30
- return k;
31
+ return R;
31
32
  }
32
33
  getIcon() {
33
34
  return "recommendation-icon";
34
35
  }
35
36
  getBlockCompositionType() {
36
- return S.CONTAINER;
37
+ return N.CONTAINER;
37
38
  }
38
39
  getName() {
39
40
  return this.api.translate("Recommendation Block");
@@ -45,7 +46,7 @@ class j extends E {
45
46
  }
46
47
  getSettingsPanelTitleHtml() {
47
48
  return C(
48
- k,
49
+ R,
49
50
  this.api.translate("Recommendation Block"),
50
51
  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.")
51
52
  );
@@ -91,28 +92,28 @@ class j extends E {
91
92
  }
92
93
  const i = this._pendingBlockId ?? this._generateNextId();
93
94
  this._pendingBlockId = null, this._assignRecommendationId(t, i);
94
- const n = d().isFeatureEnabled("reusableRecommendationStrategy"), o = n && !s.hasConfig(t), { config: r, wasFreshDrop: a } = s.initializeConfig(
95
+ const n = d().isFeatureEnabled("reusableRecommendationStrategy"), o = n && !l.hasConfig(t), { config: r, wasFreshDrop: s } = l.initializeConfig(
95
96
  this.api,
96
97
  t,
97
98
  {
98
99
  recommendationId: i,
99
- configVersion: n ? N : O,
100
+ configVersion: n ? M : O,
100
101
  ...o ? { partnerName: d().partnerName.value } : {},
101
102
  // An RRS block picks a strategy, not an algorithm, and its algorithm control is
102
103
  // hidden. Keeping the `mostPopular` default would bake a most-popular feed URL
103
104
  // at save for a block the user never configured.
104
105
  ...o ? { strategy: "" } : {}
105
106
  }
106
- ), f = g();
107
- if (f.setCurrentBlock(i), this._stampHidePrice(t, r.priceHideIfSameAsDiscounted), a) {
107
+ ), g = f();
108
+ if (g.setCurrentBlock(i), this._stampHidePrice(t, r.priceHideIfSameAsDiscounted), s) {
108
109
  I(this.api);
109
110
  const _ = this._getBlockElement(t);
110
- _ && (R(this.api, _, !0), M({
111
+ _ && (k(this.api, _, !0), w({
111
112
  currentNode: t,
112
113
  documentModifier: this.api.getDocumentModifier()
113
114
  }));
114
115
  }
115
- f.patchCurrentBlockConfig({ language: r.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
116
+ g.patchCurrentBlockConfig({ language: r.language }, { triggerRefetch: !1 }), this._warnIfMultipleBlocks();
116
117
  }
117
118
  /**
118
119
  * Called when the document changes or template is loaded
@@ -125,20 +126,24 @@ class j extends E {
125
126
  if (!(!t || !("getNodeConfig" in t))) {
126
127
  if (!this._getRecommendationId(t)) {
127
128
  const e = this._generateNextId();
128
- this._assignRecommendationId(t, e), s.hasConfig(t) && s.updateConfig(
129
+ this._assignRecommendationId(t, e), l.hasConfig(t) && l.updateConfig(
129
130
  this.api,
130
131
  t,
131
132
  { recommendationId: e },
132
133
  "Assign recommendation ID to legacy block"
133
134
  );
134
135
  }
135
- this._healLingeringDuplicate(t), s.needsMigration(t) && this._migrateFromLegacy(t), this._healHidePriceAttr(t);
136
+ this._healLingeringDuplicate(t), l.needsMigration(t) && this._migrateFromLegacy(t), this._healHidePriceAttr(t);
137
+ try {
138
+ this._healFluidImages(t);
139
+ } catch {
140
+ }
136
141
  try {
137
142
  b || (I(this.api), b = !0);
138
- const e = s.getConfig(t), i = this._getBlockElement(t);
143
+ const e = l.getConfig(t), i = this._getBlockElement(t);
139
144
  if (i) {
140
145
  const n = !e.mobileLayoutEnabled;
141
- w(i) !== n && R(this.api, i, n);
146
+ H(i) !== n && k(this.api, i, n);
142
147
  }
143
148
  } catch {
144
149
  }
@@ -152,7 +157,7 @@ class j extends E {
152
157
  */
153
158
  onDelete(t) {
154
159
  const e = this._getRecommendationId(t);
155
- e && g().removeBlockState(e);
160
+ e && f().removeBlockState(e);
156
161
  }
157
162
  /**
158
163
  * Warns (dark advisory toaster) when the design holds more than one live
@@ -200,7 +205,7 @@ class j extends E {
200
205
  _scheduleArrivalReset(t) {
201
206
  d().isFeatureEnabled("reusableRecommendationStrategy") && setTimeout(() => {
202
207
  const e = this._getRecommendationId(t);
203
- e !== null && e > 0 && !this._resetSourceIds.delete(e) && g().resetArrivedBlock(e);
208
+ e !== null && e > 0 && !this._resetSourceIds.delete(e) && f().resetArrivedBlock(e);
204
209
  }, 0);
205
210
  }
206
211
  /**
@@ -231,9 +236,9 @@ class j extends E {
231
236
  if (!o)
232
237
  return;
233
238
  let r = -1;
234
- for (let a = 0; a < n.length; a++)
235
- if (n[a] === o) {
236
- r = a;
239
+ for (let s = 0; s < n.length; s++)
240
+ if (n[s] === o) {
241
+ r = s;
237
242
  break;
238
243
  }
239
244
  if (r <= 0)
@@ -256,7 +261,7 @@ class j extends E {
256
261
  }
257
262
  /** Assigns a fresh id to a duplicated block and syncs DOM, node config and store. */
258
263
  _handleDuplicate(t, e) {
259
- const i = this._reassignDuplicateId(t, e), n = g();
264
+ const i = this._reassignDuplicateId(t, e), n = f();
260
265
  n.cloneBlockState(e, i), n.setCurrentBlock(i), d().isFeatureEnabled("reusableRecommendationStrategy") && (this._resetSourceIds.add(e), n.resetArrivedBlock(i)), this._warnIfMultipleBlocks();
261
266
  }
262
267
  /**
@@ -272,7 +277,7 @@ class j extends E {
272
277
  */
273
278
  _reassignDuplicateId(t, e) {
274
279
  const i = this._generateNextId(), n = this._getBlockElement(t);
275
- return this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), s.hasConfig(t) && s.updateConfig(
280
+ return this._assignRecommendationId(t, i), n && this._reassignInstanceClass(n, e, i), l.hasConfig(t) && l.updateConfig(
276
281
  this.api,
277
282
  t,
278
283
  { recommendationId: i },
@@ -290,7 +295,7 @@ class j extends E {
290
295
  if (!("getAttribute" in t))
291
296
  return;
292
297
  const n = `ins-recommendation-v3-block-${e}`, o = `ins-recommendation-v3-block-${i}`, r = this.api.getDocumentModifier();
293
- r.modifyHtml(t).removeClass(n).setClass(o), r.apply(new p(
298
+ r.modifyHtml(t).removeClass(n).setClass(o), r.apply(new h(
294
299
  `Reassign recommendation instance class ${n} -> ${o}`
295
300
  ));
296
301
  }
@@ -305,7 +310,7 @@ class j extends E {
305
310
  if (!i)
306
311
  return;
307
312
  const n = this.api.getDocumentModifier();
308
- n.modifyHtml(i).setAttribute(m, e.toString()), n.apply(new p(`Assign recommendation ID ${e}`));
313
+ n.modifyHtml(i).setAttribute(m, e.toString()), n.apply(new h(`Assign recommendation ID ${e}`));
309
314
  }
310
315
  /**
311
316
  * Stamps the `hide-price` attribute (read by email-service at send time) on
@@ -313,7 +318,7 @@ class j extends E {
313
318
  */
314
319
  _stampHidePrice(t, e) {
315
320
  const i = this._getBlockElement(t);
316
- i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(B, String(e)).apply(new p("Stamp hide-price"));
321
+ i && this.api.getDocumentModifier().modifyHtml(i).setAttribute(y, String(e)).apply(new h("Stamp hide-price"));
317
322
  }
318
323
  /**
319
324
  * Stamps `hide-price` from config only when the block lacks the attribute —
@@ -321,11 +326,28 @@ class j extends E {
321
326
  */
322
327
  _healHidePriceAttr(t) {
323
328
  const e = this._getBlockElement(t);
324
- if (!e || !("getAttribute" in e) || e.getAttribute(B) !== null)
329
+ if (!e || !("getAttribute" in e) || e.getAttribute(y) !== null)
325
330
  return;
326
- const { priceHideIfSameAsDiscounted: i } = s.getConfig(t);
331
+ const { priceHideIfSameAsDiscounted: i } = l.getConfig(t);
327
332
  this._stampHidePrice(t, i);
328
333
  }
334
+ // Writes into the stored template too, which email-service compiles again.
335
+ // Applies only on a real change: an empty apply re-fires onDocumentChanged.
336
+ _healFluidImages(t) {
337
+ const e = this._getBlockElement(t);
338
+ if (!e || !("querySelectorAll" in e))
339
+ return;
340
+ const i = this.api.getDocumentModifier();
341
+ let n = !1;
342
+ e.querySelectorAll("img.adapt-img").forEach((o) => {
343
+ if (!("getStyle" in o) || !("getAttribute" in o))
344
+ return;
345
+ const r = E((s) => o.getStyle(s), o.getAttribute("width"));
346
+ Object.entries(r).forEach(([s, g]) => {
347
+ i.modifyHtml(o).setStyle(s, g), n = !0;
348
+ });
349
+ }), n && i.apply(new h("Make product images fluid"));
350
+ }
329
351
  /**
330
352
  * Gets the recommendation-id from a block node
331
353
  */
@@ -354,10 +376,10 @@ class j extends E {
354
376
  * Migrate configuration from legacy format
355
377
  */
356
378
  _migrateFromLegacy(t) {
357
- s.migrateFromDataAttributes(this.api, t);
379
+ l.migrateFromDataAttributes(this.api, t);
358
380
  }
359
381
  }
360
382
  export {
361
- k as BLOCK_ID,
362
- j as RecommendationBlock
383
+ R as BLOCK_ID,
384
+ Q as RecommendationBlock
363
385
  };
@@ -1,26 +1,30 @@
1
+ import { FLUID_IMAGE_MOBILE_RULE as u, FLUID_IMAGE_CLASS as m, FLUID_IMAGE_SELECTOR as p } from "../../../../../utils/fluidImageStyle.js";
1
2
  import { ModificationDescription as a } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
- const r = "ins-recommendation-desktop-container", l = "ins-recommendation-mobile-container", i = "ins-recommendation-list-layout", s = "ins-recommendation-no-mobile-layout", u = `.${l} { display: none; }`, m = `@media only screen and (max-width: 480px) { .${r} { display: none !important; } .${l} { display: table !important; } .${i} .${r} { display: table !important; } .${i} .${l}, .${i} .ins-recommendation-mobile-row { display: none !important; } .${i} .product-image-cell { width: 80px !important; } .${i} .product-image-cell img { max-width: 80px !important; } .${i} .button-cell { width: 80px !important; } .${i} .product-info-cell { padding: 5px 8px !important; } }`, d = `@media only screen and (max-width: 480px) { .${s} .${r} { display: table !important; } .${s} .${l}, .${s} .ins-recommendation-mobile-row { display: none !important; } }`, p = `.${l}`;
3
- function c(t, e) {
3
+ const r = "ins-recommendation-desktop-container", l = "ins-recommendation-mobile-container", i = "ins-recommendation-list-layout", s = "ins-recommendation-no-mobile-layout", d = `.${l} { display: none; }`, c = `@media only screen and (max-width: 480px) { .${r} { display: none !important; } .${l} { display: table !important; } .${i} .${r} { display: table !important; } .${i} .${l}, .${i} .ins-recommendation-mobile-row { display: none !important; } .${i} .product-image-cell { width: 80px !important; } .${i} .product-image-cell img { max-width: 80px !important; } .${i} .button-cell { width: 80px !important; } .${i} .product-info-cell { padding: 5px 8px !important; } }`, f = `@media only screen and (max-width: 480px) { .${s} .${r} { display: table !important; } .${s} .${l}, .${s} .ins-recommendation-mobile-row { display: none !important; } }`, _ = `.${l}`;
4
+ function S(t, e) {
4
5
  return !!t.querySelector(e);
5
6
  }
6
- function f(t) {
7
+ function y(t) {
7
8
  return t.querySelectorAll(`*${r}`).length > 0;
8
9
  }
9
- function y(t) {
10
+ function C(t) {
10
11
  return t.querySelectorAll(`*${s}`).length > 0;
11
12
  }
12
- function S(t) {
13
+ function E(t) {
14
+ return t.querySelectorAll(`*${m}`).some((e) => "getSelector" in e && typeof e.getSelector == "function" && e.getSelector() === p);
15
+ }
16
+ function I(t) {
13
17
  const e = t.getDocumentRootCssNode();
14
18
  if (!e)
15
19
  return;
16
20
  const o = t.getDocumentModifier();
17
21
  let n = !1;
18
- c(e, p) || (o.modifyCss(e).appendRule(u), n = !0), f(e) || (o.modifyCss(e).appendRule(m), n = !0), y(e) || (o.modifyCss(e).appendRule(d), n = !0), n && o.apply(new a("Add mobile layout CSS rules"));
22
+ S(e, _) || (o.modifyCss(e).appendRule(d), n = !0), y(e) || (o.modifyCss(e).appendRule(c), n = !0), C(e) || (o.modifyCss(e).appendRule(f), n = !0), E(e) || (o.modifyCss(e).appendRule(u), n = !0), n && o.apply(new a("Add mobile layout CSS rules"));
19
23
  }
20
- function C(t) {
24
+ function R(t) {
21
25
  return "hasClass" in t ? t.hasClass(s) : !1;
22
26
  }
23
- function O(t, e, o) {
27
+ function $(t, e, o) {
24
28
  const n = t.getDocumentModifier();
25
29
  o ? n.modifyHtml(e).setClass(s) : n.modifyHtml(e).removeClass(s), n.apply(
26
30
  new a(
@@ -32,7 +36,7 @@ export {
32
36
  r as CSS_CLASS_DESKTOP_CONTAINER,
33
37
  l as CSS_CLASS_MOBILE_CONTAINER,
34
38
  s as CSS_CLASS_NO_MOBILE_LAYOUT,
35
- S as ensureMobileCssRulesExist,
36
- C as hasMobileLayoutOptOut,
37
- O as setMobileLayoutOptOut
39
+ I as ensureMobileCssRulesExist,
40
+ R as hasMobileLayoutOptOut,
41
+ $ as setMobileLayoutOptOut
38
42
  };
@@ -1,6 +1,6 @@
1
1
  import { ATTR_PRODUCT_PRICE as l, ATTR_PRODUCT_OLD_PRICE as a, ATTR_CUSTOM_PREFIX as T, ATTR_PRODUCT_IMAGE as b, ATTR_PRODUCT_NAME as _, ATTR_PRODUCT_OMNIBUS_PRICE as C, ATTR_PRODUCT_OMNIBUS_DISCOUNT as A, ATTR_PRODUCT_BUTTON as p, PRODUCT_ATTRIBUTE_PREFIX as I } from "../constants/selectors.js";
2
2
  import { useRecommendationExtensionStore as L } from "../store/recommendation.js";
3
- import { compositionKeyToProductAttr as y, isDefaultProductAttr as f, bareAttributeName as S, findFilterByBareName as $, productAttrToCompositionKey as P } from "../utils/compositionKeys.js";
3
+ import { compositionKeyToProductAttr as y, isDefaultProductAttr as f, bareAttributeName as S, findFilterByBareName as $, productAttrToCompositionKey as h } from "../utils/compositionKeys.js";
4
4
  import { formatPrice as B } from "../utils/priceFormatter.js";
5
5
  import { buildTitleRows as k } from "./titleRows.js";
6
6
  function x() {
@@ -35,22 +35,22 @@ function J(t) {
35
35
  skip: n ? l : a
36
36
  };
37
37
  }
38
- function F(t) {
38
+ function w(t) {
39
39
  const e = Array.isArray(t) ? t[t.length - 1] : t;
40
40
  if (typeof e == "string")
41
41
  return e;
42
42
  if (typeof e == "number")
43
43
  return String(e);
44
44
  }
45
- function v(t, e) {
45
+ function F(t, e) {
46
46
  var o;
47
47
  return ((o = $(t, e)) == null ? void 0 : o.type) === "defaultAttribute";
48
48
  }
49
- function w(t, e) {
50
- return v(t, e) ? t : `${I}${t}`;
49
+ function v(t, e) {
50
+ return F(t, e) ? t : `${I}${t}`;
51
51
  }
52
52
  function Q(t) {
53
- return P(t);
53
+ return h(t);
54
54
  }
55
55
  const M = Symbol("customCellHtml");
56
56
  function Z(t, e, o = {}) {
@@ -59,16 +59,16 @@ function Z(t, e, o = {}) {
59
59
  return { ...t };
60
60
  const c = { ...t };
61
61
  return e.filter((i) => i.startsWith(T) && !c[i]).forEach((i) => {
62
- const s = y(i), r = f(s) ? w(s, o) : s, u = S(r), h = N(u), D = f(r);
62
+ const s = y(i), r = f(s) ? v(s, o) : s, u = S(r), R = N(u), D = f(r);
63
63
  c[i] = (d, U) => {
64
64
  var g;
65
- const O = D ? d[u] : (g = d.product_attributes) == null ? void 0 : g[u], E = F(O) ?? h;
65
+ const O = D ? d[u] : (g = d.product_attributes) == null ? void 0 : g[u], E = w(O) ?? R;
66
66
  return n(r, E, U);
67
67
  };
68
68
  }), c;
69
69
  }
70
70
  function tt(t, e, o = []) {
71
- const n = t.startsWith(T) ? P(S(y(t))) : t, i = n !== t && !o.includes(n) ? n : t, s = (r) => (r == null ? void 0 : r[t]) ?? (r == null ? void 0 : r[i]);
71
+ const n = t.startsWith(T) ? h(S(y(t))) : t, i = n !== t && !o.includes(n) ? n : t, s = (r) => (r == null ? void 0 : r[t]) ?? (r == null ? void 0 : r[i]);
72
72
  return {
73
73
  cellPadding: e.cellPadding,
74
74
  cardBackgroundColor: e.cardBackgroundColor,
@@ -135,14 +135,14 @@ function at(t, e) {
135
135
  function ut(t) {
136
136
  return t != null && t.buttonFitToContainer ? "es-button-border es-fw" : "es-button-border";
137
137
  }
138
- const dt = "display: block; max-width: 100%; height: auto;", gt = "border-width: 1px; background: rgb(217, 234, 211); border-color: rgb(106, 168, 79);", ft = "color: rgb(56, 118, 29); background: rgb(217, 234, 211); font-family: arial, 'helvetica neue', helvetica, sans-serif; font-size: 16px; font-weight: normal; line-height: 120%; mso-border-alt: 10px solid rgb(217, 234, 211); mso-padding-alt: 0;", R = "https://email-static.useinsider.com/stripo/modules/email-recommendation-v3/assets/images/image-placeholder.png";
138
+ const dt = "display: block; width: 100%; max-width: 100%; height: auto;", gt = "border-width: 1px; background: rgb(217, 234, 211); border-color: rgb(106, 168, 79);", ft = "color: rgb(56, 118, 29); background: rgb(217, 234, 211); font-family: arial, 'helvetica neue', helvetica, sans-serif; font-size: 16px; font-weight: normal; line-height: 120%; mso-border-alt: 10px solid rgb(217, 234, 211); mso-padding-alt: 0;", P = "https://email-static.useinsider.com/stripo/modules/email-recommendation-v3/assets/images/image-placeholder.png";
139
139
  function mt(t) {
140
- return !t || typeof t != "string" || t.trim() === "" ? R : t.startsWith("http://") ? t.replace("http://", "https://") : t;
140
+ return !t || typeof t != "string" || t.trim() === "" ? P : t.startsWith("http://") ? t.replace("http://", "https://") : t;
141
141
  }
142
142
  function Y(t) {
143
143
  return {
144
144
  name: "Product Name",
145
- image_url: R,
145
+ image_url: P,
146
146
  price: { USD: 18 },
147
147
  original_price: { USD: 20 },
148
148
  discount: { USD: 2 },
@@ -224,7 +224,7 @@ export {
224
224
  nt as DEFAULT_CARD_VISIBILITY,
225
225
  dt as DEFAULT_IMG_STYLE,
226
226
  W as DEFAULT_ROW_SPACING_PX,
227
- R as PLACEHOLDER_IMAGE,
227
+ P as PLACEHOLDER_IMAGE,
228
228
  V as bgColorFragment,
229
229
  tt as buildCellOptions,
230
230
  Z as buildElementRenderer,
@@ -234,7 +234,7 @@ export {
234
234
  m as formatProductPrice,
235
235
  x as getCurrentCurrencyConfig,
236
236
  Tt as getDefaultProducts,
237
- v as isDefaultAttribute,
237
+ F as isDefaultAttribute,
238
238
  q as isSamePrice,
239
239
  at as renderButtonLabel,
240
240
  it as renderStyledParagraph,
@@ -242,10 +242,10 @@ export {
242
242
  J as resolveInlinePriceOrder,
243
243
  lt as resolveOmnibusText,
244
244
  H as resolvePStyle,
245
- w as resolveProductAttrValue,
245
+ v as resolveProductAttrValue,
246
246
  st as resolveSegmentBgStyle,
247
247
  mt as sanitizeImageUrl,
248
248
  Q as toCustomCompositionKey,
249
249
  N as toDisplayName,
250
- F as toDisplayableAttributeValue
250
+ w as toDisplayableAttributeValue
251
251
  };
@@ -1,11 +1,12 @@
1
- import { extractWrapperTags as C } from "../../../../utils/preserveTextStyles.js";
1
+ import { getFluidImageStyleChanges as E } from "../../../../utils/fluidImageStyle.js";
2
+ import { extractWrapperTags as A } from "../../../../utils/preserveTextStyles.js";
2
3
  import { RecommendationBlockId as c } from "../constants/blockIds.js";
3
- import { DESKTOP_CONTAINER_SELECTOR as S, ATTR_PRODUCT_NAME as E, ATTR_PRODUCT_PRICE as p, ATTR_PRODUCT_OLD_PRICE as y, ATTR_PRODUCT_OMNIBUS_PRICE as A, ATTR_PRODUCT_OMNIBUS_DISCOUNT as R, ATTR_PRODUCT_BUTTON as P, ATTR_PRODUCT_IMAGE as q, ATTR_PRODUCT_ATTR as x } from "../constants/selectors.js";
4
- import { CSS_CLASS_TEXT_TRIM as v } from "../controls/shared/textTrimCssRules.js";
5
- import { toCustomCompositionKey as B } from "../templates/utils.js";
6
- import { resolveRowCompositionKey as U } from "./compositionKeys.js";
7
- import { hasQuerySelectorAll as _, hasGetAttribute as l, hasGetStyle as I, hasGetComputedStyle as N } from "./tagName.js";
8
- const s = [
4
+ import { DESKTOP_CONTAINER_SELECTOR as g, ATTR_PRODUCT_NAME as P, ATTR_PRODUCT_PRICE as b, ATTR_PRODUCT_OLD_PRICE as p, ATTR_PRODUCT_OMNIBUS_PRICE as R, ATTR_PRODUCT_OMNIBUS_DISCOUNT as _, ATTR_PRODUCT_BUTTON as q, ATTR_PRODUCT_IMAGE as x, ATTR_PRODUCT_ATTR as v } from "../constants/selectors.js";
5
+ import { CSS_CLASS_TEXT_TRIM as B } from "../controls/shared/textTrimCssRules.js";
6
+ import { toCustomCompositionKey as U } from "../templates/utils.js";
7
+ import { resolveRowCompositionKey as M } from "./compositionKeys.js";
8
+ import { hasQuerySelectorAll as I, hasGetAttribute as a, hasGetStyle as O, hasGetComputedStyle as N } from "./tagName.js";
9
+ const l = [
9
10
  "font-size",
10
11
  "font-family",
11
12
  "font-weight",
@@ -14,15 +15,15 @@ const s = [
14
15
  "text-align",
15
16
  "line-height",
16
17
  "text-decoration"
17
- ], M = [
18
+ ], D = [
18
19
  "background",
19
20
  "background-color",
20
21
  "border-width",
21
22
  "border-color",
22
23
  "border-style",
23
24
  "border-radius"
24
- ], D = [
25
- ...s,
25
+ ], w = [
26
+ ...l,
26
27
  "background",
27
28
  "background-color",
28
29
  // Stripo's Border Radius control writes the radius to the anchor too, not just the
@@ -39,48 +40,48 @@ const s = [
39
40
  "max-width",
40
41
  "border-radius",
41
42
  "margin"
42
- ], g = /* @__PURE__ */ new Set(["transparent", "rgba(0, 0, 0, 0)"]), L = [
43
- { attrKey: E, blockId: c.NAME, kind: "text" },
44
- { attrKey: p, blockId: c.PRICE, kind: "text" },
45
- { attrKey: y, blockId: c.OLD_PRICE, kind: "text" },
46
- { attrKey: A, blockId: c.OMNIBUS_PRICE, kind: "text" },
47
- { attrKey: R, blockId: c.OMNIBUS_DISCOUNT, kind: "text" },
48
- { attrKey: P, blockId: c.BUTTON, kind: "button" },
49
- { attrKey: q, blockId: c.IMAGE, kind: "image" }
43
+ ], S = /* @__PURE__ */ new Set(["transparent", "rgba(0, 0, 0, 0)"]), L = [
44
+ { attrKey: P, blockId: c.NAME, kind: "text" },
45
+ { attrKey: b, blockId: c.PRICE, kind: "text" },
46
+ { attrKey: p, blockId: c.OLD_PRICE, kind: "text" },
47
+ { attrKey: R, blockId: c.OMNIBUS_PRICE, kind: "text" },
48
+ { attrKey: _, blockId: c.OMNIBUS_DISCOUNT, kind: "text" },
49
+ { attrKey: q, blockId: c.BUTTON, kind: "button" },
50
+ { attrKey: x, blockId: c.IMAGE, kind: "image" }
50
51
  ];
51
- function O(t) {
52
+ function h(t) {
52
53
  return t && "getInnerHTML" in t && typeof t.getInnerHTML == "function" ? t.getInnerHTML().trim() : "";
53
54
  }
54
- function w(t) {
55
+ function K(t) {
55
56
  return t && "getInnerText" in t && typeof t.getInnerText == "function" ? t.getInnerText().trim() : "";
56
57
  }
57
- function a(t, e, r) {
58
- !e || !I(e) || r.forEach((n) => {
58
+ function s(t, e, r) {
59
+ !e || !O(e) || r.forEach((n) => {
59
60
  const o = e.getStyle(n);
60
61
  o && o !== "inherit" && o !== "initial" && (t[n] = o);
61
62
  });
62
63
  }
63
- function h(t) {
64
+ function y(t) {
64
65
  return Object.entries(t).map(([e, r]) => `${e}: ${r};`).join(" ");
65
66
  }
66
67
  function k(t) {
67
- if (!t || !I(t))
68
+ if (!t || !O(t))
68
69
  return;
69
70
  const e = t.getStyle("background-color") || t.getStyle("background");
70
- return e && !g.has(e) ? e : void 0;
71
+ return e && !S.has(e) ? e : void 0;
71
72
  }
72
- function b(t, e) {
73
+ function C(t, e) {
73
74
  const r = {};
74
- return a(r, t, e), h(r);
75
+ return s(r, t, e), y(r);
75
76
  }
76
- function K(t) {
77
+ function $(t) {
77
78
  const e = t.querySelector("p"), r = {};
78
- a(r, t, s), a(r, e, s), a(r, t.querySelector("strong"), s), a(r, t.querySelector("em"), s), a(r, t.querySelector("s"), s);
79
- const n = h(r), { openTags: o, closeTags: i } = C(O(e));
79
+ s(r, t, l), s(r, e, l), s(r, t.querySelector("strong"), l), s(r, t.querySelector("em"), l), s(r, t.querySelector("s"), l);
80
+ const n = y(r), { openTags: o, closeTags: i } = A(h(e));
80
81
  return !n && !o ? null : { pStyle: n || void 0, openTags: o, closeTags: i };
81
82
  }
82
- function $(t) {
83
- const e = t.querySelector(".es-button-border"), r = t.querySelector("a.es-button") ?? t.querySelector("a"), n = b(e, M), o = b(r, D), i = e && "getAttribute" in e ? e.getAttribute("class") ?? "" : "", u = /\bes-fw\b/.test(i), { openTags: T, closeTags: d } = C(O(r)), m = w(r);
83
+ function j(t) {
84
+ const e = t.querySelector(".es-button-border"), r = t.querySelector("a.es-button") ?? t.querySelector("a"), n = C(e, D), o = C(r, w), i = e && "getAttribute" in e ? e.getAttribute("class") ?? "" : "", u = /\bes-fw\b/.test(i), { openTags: T, closeTags: d } = A(h(r)), m = K(r);
84
85
  return !n && !o && !u && !T && !m ? null : {
85
86
  buttonBorderStyle: n || void 0,
86
87
  buttonAnchorStyle: o || void 0,
@@ -90,137 +91,140 @@ function $(t) {
90
91
  closeTags: d
91
92
  };
92
93
  }
93
- function H(t) {
94
- const e = b(t.querySelector("img"), G);
95
- return e ? { imgStyle: e } : null;
94
+ function F(t) {
95
+ const e = t.querySelector("img"), r = {};
96
+ if (s(r, e, G), !Object.keys(r).length)
97
+ return null;
98
+ const n = a(e) ? e.getAttribute("width") : null;
99
+ return Object.assign(r, E((o) => r[o], n)), { imgStyle: y(r) };
96
100
  }
97
- function F(t, e) {
98
- return e === "button" ? $(t) : e === "image" ? H(t) : K(t);
101
+ function H(t, e) {
102
+ return e === "button" ? j(t) : e === "image" ? F(t) : $(t);
99
103
  }
100
104
  function f(t, e) {
101
105
  if (!t || !("querySelector" in t))
102
106
  return;
103
- const r = t.querySelector(S) ?? t;
107
+ const r = t.querySelector(g) ?? t;
104
108
  if (L.forEach(({ attrKey: i, blockId: u, kind: T }) => {
105
109
  const d = r.querySelector(`[esd-extension-block-id="${u}"]`);
106
110
  d && e(d, i, T);
107
- }), !_(r))
111
+ }), !I(r))
108
112
  return;
109
113
  const n = /* @__PURE__ */ new Set();
110
114
  r.querySelectorAll(
111
115
  `[esd-extension-block-id="${c.CUSTOM_ATTRIBUTE}"]`
112
116
  ).forEach((i) => {
113
- const u = l(i) ? i.getAttribute(x) : null;
114
- !u || n.has(u) || (n.add(u), e(i, B(u), "text"));
117
+ const u = a(i) ? i.getAttribute(v) : null;
118
+ !u || n.has(u) || (n.add(u), e(i, U(u), "text"));
115
119
  });
116
120
  }
117
- function j(t) {
121
+ function X(t) {
118
122
  const e = {};
119
123
  return f(t, (r, n, o) => {
120
124
  if (!("querySelector" in r))
121
125
  return;
122
- const i = F(r, o);
126
+ const i = H(r, o);
123
127
  i && (e[n] = i);
124
128
  }), e;
125
129
  }
126
- function X(t) {
130
+ function z(t) {
127
131
  if (!t || !("querySelector" in t))
128
132
  return;
129
- const e = t.querySelector(S) ?? t, r = e.querySelector(".product-card-segment") ?? e.querySelector(".product-card-wrapper");
133
+ const e = t.querySelector(g) ?? t, r = e.querySelector(".product-card-segment") ?? e.querySelector(".product-card-wrapper");
130
134
  return k(r);
131
135
  }
132
- function z(t) {
136
+ function Q(t) {
133
137
  if (!t)
134
138
  return;
135
- const e = l(t) ? t.getAttribute("bgcolor") : null;
136
- if (e && !g.has(e))
139
+ const e = a(t) ? t.getAttribute("bgcolor") : null;
140
+ if (e && !S.has(e))
137
141
  return e;
138
142
  const r = k(t);
139
143
  if (r)
140
144
  return r;
141
145
  const n = N(t) ? t.getComputedStyle("background-color") : void 0;
142
- return n && !g.has(n) ? n : void 0;
146
+ return n && !S.has(n) ? n : void 0;
143
147
  }
144
- function Q(t) {
148
+ function V(t) {
145
149
  const e = {};
146
150
  return f(t, (r, n, o) => {
147
151
  if (o !== "text")
148
152
  return;
149
- const i = z(r);
153
+ const i = Q(r);
150
154
  i && (e[n] = i);
151
155
  }), e;
152
156
  }
153
- function V(t) {
157
+ function W(t) {
154
158
  const e = {};
155
159
  return f(t, (r, n, o) => {
156
160
  if (o === "image")
157
161
  return;
158
- const i = l(r) ? r.getAttribute("align") : null;
162
+ const i = a(r) ? r.getAttribute("align") : null;
159
163
  i && (e[n] = i);
160
164
  }), e;
161
165
  }
162
- const W = /^es-[pm]\d+[trbl]?$/;
163
- function Y(t) {
164
- const e = l(t) ? t.getAttribute("class") : null;
166
+ const Y = /^es-[pm]\d+[trbl]?$/;
167
+ function J(t) {
168
+ const e = a(t) ? t.getAttribute("class") : null;
165
169
  if (!e)
166
170
  return;
167
- const r = e.split(/\s+/).filter((n) => W.test(n) || n === v);
171
+ const r = e.split(/\s+/).filter((n) => Y.test(n) || n === B);
168
172
  return r.length ? r.join(" ") : void 0;
169
173
  }
170
- function J(t) {
174
+ function Z(t) {
171
175
  if (!t || !("querySelector" in t))
172
176
  return !1;
173
- const e = t.querySelector(S) ?? t, r = (n) => !!(n && "querySelector" in n && n.querySelector(".product-price") && n.querySelector(".product-old-price"));
174
- return r(e.querySelector(`[data-attribute-type="${p}"]`)) || r(e.querySelector(`[data-attribute-type="${y}"]`));
177
+ const e = t.querySelector(g) ?? t, r = (n) => !!(n && "querySelector" in n && n.querySelector(".product-price") && n.querySelector(".product-old-price"));
178
+ return r(e.querySelector(`[data-attribute-type="${b}"]`)) || r(e.querySelector(`[data-attribute-type="${p}"]`));
175
179
  }
176
- function Z(t) {
177
- const e = {}, r = J(t);
180
+ function tt(t) {
181
+ const e = {}, r = Z(t);
178
182
  return f(t, (n, o, i) => {
179
- if (i === "image" || r && (o === p || o === y))
183
+ if (i === "image" || r && (o === b || o === p))
180
184
  return;
181
- const u = Y(n);
185
+ const u = J(n);
182
186
  u && (e[o] = u);
183
187
  }), e;
184
188
  }
185
- function tt(t) {
189
+ function et(t) {
186
190
  const e = {};
187
191
  return f(t, (r, n) => {
188
- if (n !== A && n !== R || !l(r))
192
+ if (n !== R && n !== _ || !a(r))
189
193
  return;
190
194
  const o = r.getAttribute("data-text-before"), i = r.getAttribute("data-text-after");
191
195
  (o != null || i != null) && (e[n] = { before: o ?? void 0, after: i ?? void 0 });
192
196
  }), e;
193
197
  }
194
- function et(t) {
198
+ function rt(t) {
195
199
  const e = {};
196
200
  if (!t || !("querySelector" in t))
197
201
  return e;
198
- const r = t.querySelector(S) ?? t;
199
- return _(r) && r.querySelectorAll(".recommendation-attribute-row").forEach((n) => {
200
- if (!l(n))
202
+ const r = t.querySelector(g) ?? t;
203
+ return I(r) && r.querySelectorAll(".recommendation-attribute-row").forEach((n) => {
204
+ if (!a(n))
201
205
  return;
202
- const o = U(n), i = n.getAttribute("data-visibility");
206
+ const o = M(n), i = n.getAttribute("data-visibility");
203
207
  o && i != null && (e[o] = i !== "0");
204
208
  }), e;
205
209
  }
206
- function at(t) {
210
+ function ft(t) {
207
211
  return {
208
- styleTemplates: j(t),
209
- cardBackgroundColor: X(t),
210
- cellBackgroundColors: Q(t),
211
- cellAlignments: V(t),
212
- cellClasses: Z(t),
213
- omnibusTexts: tt(t),
214
- visibility: et(t)
212
+ styleTemplates: X(t),
213
+ cardBackgroundColor: z(t),
214
+ cellBackgroundColors: V(t),
215
+ cellAlignments: W(t),
216
+ cellClasses: tt(t),
217
+ omnibusTexts: et(t),
218
+ visibility: rt(t)
215
219
  };
216
220
  }
217
221
  export {
218
- j as captureAttributeStyleTemplates,
219
- X as captureCardBackgroundColor,
220
- V as captureCellAlignments,
221
- Q as captureCellBackgroundColors,
222
- Z as captureCellClasses,
223
- tt as captureOmnibusTexts,
224
- at as captureStyles,
225
- et as captureVisibility
222
+ X as captureAttributeStyleTemplates,
223
+ z as captureCardBackgroundColor,
224
+ W as captureCellAlignments,
225
+ V as captureCellBackgroundColors,
226
+ tt as captureCellClasses,
227
+ et as captureOmnibusTexts,
228
+ ft as captureStyles,
229
+ rt as captureVisibility
226
230
  };
@@ -1,21 +1,21 @@
1
1
  import "../constants/selectors.js";
2
2
  import { RRS_CONFIG_VERSION as m } from "../constants/defaultConfig.js";
3
- import { sanitizeProductIds as p, PRODUCT_ID_SEPARATOR as d } from "./productIds.js";
4
- const u = "manualMerchandising";
5
- function f({ strategyId: e, nodeConfigVersion: t }) {
3
+ import { sanitizeProductIds as p } from "./productIds.js";
4
+ const d = "manualMerchandising";
5
+ function N({ strategyId: e, nodeConfigVersion: t }) {
6
6
  return !e && t < m;
7
7
  }
8
8
  const o = (e) => {
9
9
  const t = String(e ?? "").trim();
10
10
  return /^[1-9]\d*$/.test(t) ? t : null;
11
11
  };
12
- function R({ campaignId: e, templateLibraryId: t }) {
12
+ function f({ campaignId: e, templateLibraryId: t }) {
13
13
  if (o(e))
14
14
  return { scope: "campaign" };
15
15
  const n = o(t);
16
16
  return n ? { scope: "template", templateId: n } : { scope: "campaign" };
17
17
  }
18
- function S({
18
+ function y({
19
19
  blockId: e,
20
20
  url: t,
21
21
  campaignId: n,
@@ -24,7 +24,7 @@ function S({
24
24
  productIds: s,
25
25
  target: r
26
26
  }) {
27
- const i = c === u ? p(s).split(d).filter(Boolean) : [];
27
+ const i = c === d ? p(s).split(",").filter(Boolean) : [];
28
28
  return {
29
29
  ...r.scope === "template" ? { templateId: Number.parseInt(r.templateId) } : {
30
30
  campaignId: Number.parseInt(n) || 0,
@@ -36,7 +36,7 @@ function S({
36
36
  };
37
37
  }
38
38
  export {
39
- S as buildLegacyMigrationPayload,
40
- f as isLegacyStrategyConfig,
41
- R as resolveMigrationTarget
39
+ y as buildLegacyMigrationPayload,
40
+ N as isLegacyStrategyConfig,
41
+ f as resolveMigrationTarget
42
42
  };
@@ -1,8 +1,6 @@
1
- const i = ",";
2
- function o(t) {
3
- return t.map((n) => String(n ?? "").trim()).filter(Boolean).join(",");
1
+ function n(t) {
2
+ return t.map((i) => String(i ?? "").trim()).filter(Boolean).join(",");
4
3
  }
5
4
  export {
6
- i as PRODUCT_ID_SEPARATOR,
7
- o as sanitizeProductIds
5
+ n as sanitizeProductIds
8
6
  };
@@ -137,6 +137,7 @@ export declare class RecommendationBlock extends Block {
137
137
  * heals templates saved before this feature without dirtying current ones.
138
138
  */
139
139
  private _healHidePriceAttr;
140
+ private _healFluidImages;
140
141
  /**
141
142
  * Gets the recommendation-id from a block node
142
143
  */
@@ -292,8 +292,11 @@ export declare function renderButtonLabel(label: string, template?: AttributeSty
292
292
  * class, not inline width, so we preserve the class across regeneration.
293
293
  */
294
294
  export declare function resolveButtonBorderClass(template?: AttributeStyleTemplate): string;
295
- /** Default inline style for the product image `<img>` (used when nothing is captured). */
296
- export declare const DEFAULT_IMG_STYLE = "display: block; max-width: 100%; height: auto;";
295
+ /**
296
+ * Default inline style for the product image `<img>` (used when nothing is captured).
297
+ * `width: 100%` is inline so the image shrinks even where the `.adapt-img` media rule is dropped.
298
+ */
299
+ export declare const DEFAULT_IMG_STYLE = "display: block; width: 100%; max-width: 100%; height: auto;";
297
300
  /** Default inline style for the button `<span class="es-button-border">`. */
298
301
  export declare const DEFAULT_BUTTON_BORDER_STYLE: string;
299
302
  /**
@@ -1,5 +1,3 @@
1
- /** Separator between product ids in the `sanitizeProductIds` output; split that output with it too. */
2
- export declare const PRODUCT_ID_SEPARATOR = ",";
3
1
  /**
4
2
  * Builds the request/URL `productId` value from raw product ID segments.
5
3
  * Trimming happens here — NOT on input change — so the user's in-progress
@@ -0,0 +1,7 @@
1
+ /** Reads one inline style property (Stripo `getStyle` or CSSOM `getPropertyValue`). */
2
+ export type StyleReader = (property: string) => string | null | undefined;
3
+ export type FluidImageStyleChanges = Partial<Record<'width' | 'max-width' | 'height', string>>;
4
+ export declare function getFluidImageStyleChanges(readStyle: StyleReader, widthAttr?: string | null): FluidImageStyleChanges;
5
+ export declare const FLUID_IMAGE_CLASS = "recommendation-block-v2";
6
+ export declare const FLUID_IMAGE_SELECTOR = ".recommendation-block-v2 .adapt-img";
7
+ export declare const FLUID_IMAGE_MOBILE_RULE: string;
@@ -0,0 +1,26 @@
1
+ const c = /^(\d+(?:\.\d+)?)px$/i;
2
+ function o(t) {
3
+ return (t ?? "").trim().toLowerCase();
4
+ }
5
+ function e(t) {
6
+ const n = o(t).match(c);
7
+ return n && parseFloat(n[1]) > 0 ? `${n[1]}px` : null;
8
+ }
9
+ function h(t) {
10
+ const n = (t ?? "").trim();
11
+ return /^\d+$/.test(n) && parseInt(n) > 0 ? `${parseInt(n)}px` : null;
12
+ }
13
+ function r(t, n) {
14
+ return e(t("width")) ?? e(t("max-width")) ?? h(n) ?? "100%";
15
+ }
16
+ function d(t, n) {
17
+ const i = {}, a = r(t, n);
18
+ return o(t("width")) !== "100%" && (i.width = "100%"), o(t("max-width")) !== a && (i["max-width"] = a), o(t("height")) || (i.height = "auto"), i;
19
+ }
20
+ const s = "recommendation-block-v2", m = `.${s} .adapt-img`, u = `@media only screen and (max-width: 600px) { ${m} { max-width: 100% !important; } }`;
21
+ export {
22
+ s as FLUID_IMAGE_CLASS,
23
+ u as FLUID_IMAGE_MOBILE_RULE,
24
+ m as FLUID_IMAGE_SELECTOR,
25
+ d as getFluidImageStyleChanges
26
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.20.0-beta.0849ec7",
3
+ "version": "3.20.0-beta.12889e0",
4
4
  "description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
5
5
  "main": "./dist/guido.umd.cjs",
6
6
  "module": "./dist/library.js",