@useinsider/guido 3.20.0-beta.11a0bde → 3.20.0-beta.30c96fc

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,6 +1,15 @@
1
1
  import { pairProductVariables as o } from "../../utils/pairProductVariables.js";
2
- import { wrapHiddenPriceTdsForOutlook as r, MSO_ITEMS_HIDE_START as e, MSO_ITEMS_HIDE_END as t } from "./utils/itemsCompilerUtils.js";
3
- const a = [
2
+ import { normalizeItemsBlockWidths as r, wrapHiddenPriceTdsForOutlook as e, MSO_ITEMS_HIDE_START as t, MSO_ITEMS_HIDE_END as s } from "./utils/itemsCompilerUtils.js";
3
+ const d = [
4
+ {
5
+ id: "normalize-items-block-widths",
6
+ // Runs before the other items rules so they see non-zero widths; not AMP-safe.
7
+ description: "Normalize zero Items card widths in the compiled email",
8
+ type: "custom",
9
+ processor: r,
10
+ priority: 55
11
+ // Before pair-product-variables (60)
12
+ },
4
13
  {
5
14
  id: "pair-product-variables",
6
15
  description: "Replace product default values with template variables",
@@ -16,7 +25,7 @@ const a = [
16
25
  // with safe placeholder comments and collapse them inline for web-engine Outlook.
17
26
  description: "Mark hidden Items price tds for Outlook conditional hiding",
18
27
  type: "custom",
19
- processor: r,
28
+ processor: e,
20
29
  priority: 65
21
30
  // After pair-product-variables (60), before outlook rules (70+)
22
31
  },
@@ -26,10 +35,10 @@ const a = [
26
35
  // and reco swap P100) keeps it out of every whitespace/comment-mangling pass.
27
36
  description: "Swap Items MSO markers into [if !mso] conditional comments",
28
37
  type: "custom",
29
- processor: (i) => i.replaceAll(`<!--${e}-->`, "<!--[if !mso]><!-- -->").replaceAll(`<!--${t}-->`, "<!--<![endif]-->"),
38
+ processor: (i) => i.replaceAll(`<!--${t}-->`, "<!--[if !mso]><!-- -->").replaceAll(`<!--${s}-->`, "<!--<![endif]-->"),
30
39
  priority: 101
31
40
  }
32
41
  ];
33
42
  export {
34
- a as itemsCompilerRules
43
+ d as itemsCompilerRules
35
44
  };
@@ -1,28 +1,55 @@
1
- const p = "MSO_ITEMS_HIDE_START", E = "MSO_ITEMS_HIDE_END", u = "mso-hide:all; max-height:0; overflow:hidden; font-size:0; line-height:0;", _ = ".ins-product-cart td.horizontal-price, .ins-product-cart td.vertical-price";
2
- function T(t) {
3
- if (!t.includes("vertical-price") || !t.includes("ins-product-cart"))
4
- return t;
5
- const i = t.replaceAll("{%", "<!--{%").replaceAll("%}", "%}-->"), r = new DOMParser().parseFromString(i, "text/html");
6
- let n = !1;
7
- if (r.querySelectorAll(_).forEach((e) => {
8
- var s, a;
9
- const o = e.getAttribute("style") || "";
1
+ import { PRODUCT_WRAPPER_SELECTOR as A, hasZeroWidthDeclaration as E, isZeroWidthValue as u, withWidthPin as h, PRODUCT_TD_SELECTOR as S, withoutZeroWidth as _ } from "../../../extensions/Blocks/Items/constants/cardWidth.js";
2
+ import { protectLiquid as m, restoreLiquid as y } from "../../../utils/liquidProtection.js";
3
+ const f = "MSO_ITEMS_HIDE_START", D = "MSO_ITEMS_HIDE_END", T = "mso-hide:all; max-height:0; overflow:hidden; font-size:0; line-height:0;", M = ".ins-product-cart td.horizontal-price, .ins-product-cart td.vertical-price";
4
+ function g(e) {
5
+ if (!e.includes("vertical-price") || !e.includes("ins-product-cart"))
6
+ return e;
7
+ const n = e.replaceAll("{%", "<!--{%").replaceAll("%}", "%}-->"), r = new DOMParser().parseFromString(n, "text/html");
8
+ let s = !1;
9
+ if (r.querySelectorAll(M).forEach((t) => {
10
+ var d, a;
11
+ const o = t.getAttribute("style") || "";
10
12
  if (!/display\s*:\s*none/i.test(o))
11
13
  return;
12
- const c = e.previousSibling;
13
- if (((c == null ? void 0 : c.nodeType) !== Node.COMMENT_NODE || c.data !== p) && ((s = e.parentNode) == null || s.insertBefore(r.createComment(p), e), (a = e.parentNode) == null || a.insertBefore(r.createComment(E), e.nextSibling)), !/mso-hide/i.test(o)) {
14
- const d = o.trim().endsWith(";") ? " " : "; ";
15
- e.setAttribute("style", `${o}${d}${u}`);
14
+ const l = t.previousSibling;
15
+ if (((l == null ? void 0 : l.nodeType) !== Node.COMMENT_NODE || l.data !== f) && ((d = t.parentNode) == null || d.insertBefore(r.createComment(f), t), (a = t.parentNode) == null || a.insertBefore(r.createComment(D), t.nextSibling)), !/mso-hide/i.test(o)) {
16
+ const p = o.trim().endsWith(";") ? " " : "; ";
17
+ t.setAttribute("style", `${o}${p}${T}`);
16
18
  }
17
- n = !0;
18
- }), !n)
19
- return t;
20
- const l = i.match(/<!DOCTYPE[^>]*>/i);
21
- return ((l ? `${l[0]}
19
+ s = !0;
20
+ }), !s)
21
+ return e;
22
+ const c = n.match(/<!DOCTYPE[^>]*>/i);
23
+ return ((c ? `${c[0]}
22
24
  ` : "") + r.documentElement.outerHTML).replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}").replaceAll("&lt;!--{%", "{%").replaceAll("%}--&gt;", "%}");
23
25
  }
26
+ function I(e) {
27
+ if (!e.includes("ins-product-wrapper") && !e.includes("ins-product-td"))
28
+ return e;
29
+ const n = new DOMParser().parseFromString(m(e), "text/html");
30
+ let r = !1;
31
+ if (n.querySelectorAll(A).forEach((i) => {
32
+ const t = i.getAttribute("style") || "";
33
+ if (!E(t) && !u(i.getAttribute("width")))
34
+ return;
35
+ const o = h(t);
36
+ o !== t && (i.setAttribute("style", o), r = !0), u(i.getAttribute("width")) && (i.setAttribute("width", "100%"), r = !0);
37
+ }), n.querySelectorAll(S).forEach((i) => {
38
+ const t = i.getAttribute("style") || "";
39
+ if (E(t)) {
40
+ const o = _(t);
41
+ o ? i.setAttribute("style", o) : i.removeAttribute("style"), r = !0;
42
+ }
43
+ u(i.getAttribute("width")) && (i.removeAttribute("width"), r = !0);
44
+ }), !r)
45
+ return e;
46
+ const s = e.match(/<!DOCTYPE[^>]*>/i), c = s ? `${s[0]}
47
+ ` : "";
48
+ return y(c + n.documentElement.outerHTML);
49
+ }
24
50
  export {
25
- E as MSO_ITEMS_HIDE_END,
26
- p as MSO_ITEMS_HIDE_START,
27
- T as wrapHiddenPriceTdsForOutlook
51
+ D as MSO_ITEMS_HIDE_END,
52
+ f as MSO_ITEMS_HIDE_START,
53
+ I as normalizeItemsBlockWidths,
54
+ g as wrapHiddenPriceTdsForOutlook
28
55
  };
@@ -1,84 +1,86 @@
1
- var q = Object.defineProperty;
2
- var v = (c, t, e) => t in c ? q(c, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[t] = e;
3
- var M = (c, t, e) => v(c, typeof t != "symbol" ? t + "" : t, e);
1
+ var B = Object.defineProperty;
2
+ var v = (n, t, e) => t in n ? B(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
+ var M = (n, t, e) => v(n, typeof t != "symbol" ? t + "" : t, e);
4
4
  import { BLOCK_ID as R } from "../../extensions/Blocks/Items/block.js";
5
+ import { hasZeroWidthDeclaration as L, withoutZeroWidth as x } from "../../extensions/Blocks/Items/constants/cardWidth.js";
5
6
  import { ItemInCartOptions as h, DefaultConfigValues as b, SETTINGS_ENUMS as _ } from "../../extensions/Blocks/Items/enums/settingsEnums.js";
6
- import { getDefaultTemplate as L } from "../../extensions/Blocks/Items/template.js";
7
- import { useTemplateStore as x } from "../../stores/template.js";
8
- function O() {
7
+ import { getDefaultTemplate as V } from "../../extensions/Blocks/Items/template.js";
8
+ import { useTemplateStore as O } from "../../stores/template.js";
9
+ import { protectLiquid as H, restoreLiquid as $ } from "../../utils/liquidProtection.js";
10
+ function F() {
9
11
  return String(Date.now() + Math.floor(Math.random() * 1e3));
10
12
  }
11
- function P(c) {
12
- return c ? {
13
+ function D(n) {
14
+ return n ? {
13
15
  CartItems: _.ITEMS_TYPE.CART_ITEMS,
14
16
  BrowsedItems: _.ITEMS_TYPE.BROWSED_ITEMS,
15
17
  PurchasedItems: _.ITEMS_TYPE.PURCHASED_ITEMS,
16
18
  CART_ITEMS: _.ITEMS_TYPE.CART_ITEMS,
17
19
  BROWSED_ITEMS: _.ITEMS_TYPE.BROWSED_ITEMS,
18
20
  PURCHASED_ITEMS: _.ITEMS_TYPE.PURCHASED_ITEMS
19
- }[c] || _.ITEMS_TYPE.CART_ITEMS : _.ITEMS_TYPE.CART_ITEMS;
21
+ }[n] || _.ITEMS_TYPE.CART_ITEMS : _.ITEMS_TYPE.CART_ITEMS;
20
22
  }
21
- function V(c) {
22
- return c.classList.contains("esd-browsed-items-block") ? _.ITEMS_TYPE.BROWSED_ITEMS : c.classList.contains("esd-purchased-items-block") ? _.ITEMS_TYPE.PURCHASED_ITEMS : _.ITEMS_TYPE.CART_ITEMS;
23
+ function U(n) {
24
+ return n.classList.contains("esd-browsed-items-block") ? _.ITEMS_TYPE.BROWSED_ITEMS : n.classList.contains("esd-purchased-items-block") ? _.ITEMS_TYPE.PURCHASED_ITEMS : _.ITEMS_TYPE.CART_ITEMS;
23
25
  }
24
- function D(c) {
26
+ function P(n) {
25
27
  var o;
26
- const t = (i, u) => i == null ? u : i === "1" || i === "true", e = (i, u) => i || u, a = c["data-type"] || c["data-source"], r = P(a), d = h[r];
27
- let n = c["data-cart_items_select_control_value"] || ((o = d == null ? void 0 : d[0]) == null ? void 0 : o.value) || b.cartItemsSelectControlValue;
28
- if (n && !n.includes("{{") && /^\d+$/.test(n)) {
29
- const i = parseInt(n) - 1, u = h[r];
30
- u && u[i] && (n = u[i].value);
28
+ const t = (i, d) => i == null ? d : i === "1" || i === "true", e = (i, d) => i || d, a = n["data-type"] || n["data-source"], r = D(a), u = h[r];
29
+ let c = n["data-cart_items_select_control_value"] || ((o = u == null ? void 0 : u[0]) == null ? void 0 : o.value) || b.cartItemsSelectControlValue;
30
+ if (c && !c.includes("{{") && /^\d+$/.test(c)) {
31
+ const i = parseInt(c) - 1, d = h[r];
32
+ d && d[i] && (c = d[i].value);
31
33
  }
32
34
  return {
33
35
  initialized: !0,
34
- blockInstanceId: e(c["data-block-instance-id"], O()),
36
+ blockInstanceId: e(n["data-block-instance-id"], F()),
35
37
  source: r,
36
38
  type: r,
37
- itemsSelectValue: n,
38
- orientation: c["data-card_orientation_control_value"] || _.ORIENTATION.VERTICAL,
39
- nameTrimming: t(c["data-product_name_control_trim"], !0),
40
- priceHideDiscount: t(c["data-product_price_control_nodup"], !0),
41
- priceFormatted: t(c["data-product_price_control_formated"], !0),
42
- priceSinglePrice: t(c["data-product_price_control_single_price"], !1),
39
+ itemsSelectValue: c,
40
+ orientation: n["data-card_orientation_control_value"] || _.ORIENTATION.VERTICAL,
41
+ nameTrimming: t(n["data-product_name_control_trim"], !0),
42
+ priceHideDiscount: t(n["data-product_price_control_nodup"], !0),
43
+ priceFormatted: t(n["data-product_price_control_formated"], !0),
44
+ priceSinglePrice: t(n["data-product_price_control_single_price"], !1),
43
45
  priceCurrencySymbol: e(
44
- c["data-product_price_control_currency_symbol"],
46
+ n["data-product_price_control_currency_symbol"],
45
47
  b.productPriceCurrencySymbolControlValue
46
48
  ),
47
49
  priceCurrencyLocation: e(
48
- c["data-product_price_currency_location"],
50
+ n["data-product_price_currency_location"],
49
51
  b.productPriceCurrencyLocationControlValue
50
52
  ),
51
- priceOrientation: c["data-product_original_price_control_orientation"] || "horizontal",
52
- quantityControlEnabled: t(c["data-product_quantity_control_enabled"], !0),
53
- buttonLink: e(c["data-product_button_link"], b.productButtonLinkControlValue),
54
- imageLink: e(c["data-product_image_link"], b.productImageLinkControlValue),
55
- buttonLabel: e(c["data-product_button_control_label"], "Buy"),
56
- buttonFullWidth: t(c["data-product_button_control_atw"], !0),
57
- imageVisible: t(c["data-product_image_control_enabled"], !0),
58
- nameVisible: t(c["data-product_name_control_enabled"], !0),
59
- quantityVisible: t(c["data-product_quantity_control_enabled"], !0),
60
- priceVisible: t(c["data-product_price_control_enabled"], !0),
61
- originalPriceVisible: t(c["data-product_original_price_control_enabled"], !0),
62
- buttonVisible: t(c["data-product_button_control_enabled"], !0)
53
+ priceOrientation: n["data-product_original_price_control_orientation"] || "horizontal",
54
+ quantityControlEnabled: t(n["data-product_quantity_control_enabled"], !0),
55
+ buttonLink: e(n["data-product_button_link"], b.productButtonLinkControlValue),
56
+ imageLink: e(n["data-product_image_link"], b.productImageLinkControlValue),
57
+ buttonLabel: e(n["data-product_button_control_label"], "Buy"),
58
+ buttonFullWidth: t(n["data-product_button_control_atw"], !0),
59
+ imageVisible: t(n["data-product_image_control_enabled"], !0),
60
+ nameVisible: t(n["data-product_name_control_enabled"], !0),
61
+ quantityVisible: t(n["data-product_quantity_control_enabled"], !0),
62
+ priceVisible: t(n["data-product_price_control_enabled"], !0),
63
+ originalPriceVisible: t(n["data-product_original_price_control_enabled"], !0),
64
+ buttonVisible: t(n["data-product_button_control_enabled"], !0)
63
65
  };
64
66
  }
65
- function H(c, t) {
67
+ function Y(n, t) {
66
68
  const e = {
67
69
  CART_ITEMS: `{{Abandoned Cart Item (${t}) Image}}`,
68
70
  BROWSED_ITEMS: `{{Browsed Item (${t}) Image}}`,
69
71
  PURCHASED_ITEMS: `{{Purchased Item (${t}) Image}}`
70
72
  };
71
- return e[c] || e.CART_ITEMS;
73
+ return e[n] || e.CART_ITEMS;
72
74
  }
73
- function $(c, t) {
75
+ function W(n, t) {
74
76
  const e = {
75
77
  CART_ITEMS: `{{Abandoned Cart Item (${t}) Url}}`,
76
78
  BROWSED_ITEMS: `{{Browsed Item (${t}) Url}}`,
77
79
  PURCHASED_ITEMS: `{{Purchased Item (${t}) Url}}`
78
80
  };
79
- return e[c] || e.CART_ITEMS;
81
+ return e[n] || e.CART_ITEMS;
80
82
  }
81
- class F {
83
+ class z {
82
84
  constructor() {
83
85
  M(this, "parser");
84
86
  this.parser = new DOMParser();
@@ -90,10 +92,10 @@ class F {
90
92
  const e = this.removeJinjaConditionals(t), a = this.parser.parseFromString(e, "text/html"), r = a.querySelectorAll(
91
93
  "td.esd-cart-items-block, td.esd-browsed-items-block, td.esd-purchased-items-block"
92
94
  );
93
- return x().$patch((n) => {
94
- n.migrations = { ...n.migrations, [R]: r.length };
95
- }), r.length === 0 ? (console.warn("ItemsBlockMigrator: No blocks found with items block selectors"), e) : (r.forEach((n) => {
96
- const o = this.extractConfiguration(n), i = L({
95
+ return O().$patch((c) => {
96
+ c.migrations = { ...c.migrations, [R]: r.length };
97
+ }), r.length === 0 ? (console.warn("ItemsBlockMigrator: No blocks found with items block selectors"), this.backfillV2ProductTdAttributes(e)) : (r.forEach((c) => {
98
+ const o = this.extractConfiguration(c), i = V({
97
99
  orientation: o.orientation,
98
100
  itemsType: o.itemsType,
99
101
  itemId: o.itemId,
@@ -107,18 +109,18 @@ class F {
107
109
  priceStyles: o.priceStyles,
108
110
  originalPriceStyles: o.originalPriceStyles,
109
111
  quantityStyles: o.quantityStyles,
110
- nodeConfig: D(o.configBlockAttributes)
112
+ nodeConfig: P(o.configBlockAttributes)
111
113
  }), l = this.parser.parseFromString(
112
114
  `<table><tbody><tr>${i}</tr></tbody></table>`,
113
115
  "text/html"
114
116
  ).querySelector("td");
115
- if (l && n.parentNode) {
116
- const s = D(o.configBlockAttributes);
117
+ if (l && c.parentNode) {
118
+ const s = P(o.configBlockAttributes);
117
119
  l.setAttribute("esd-ext-config", JSON.stringify(s)), l.setAttribute("data-type", s.type);
118
120
  const p = l.querySelector("esd-config-block");
119
- p && p.remove(), n.parentNode.replaceChild(l, n);
121
+ p && p.remove(), c.parentNode.replaceChild(l, c);
120
122
  }
121
- }), a.documentElement.outerHTML);
123
+ }), this.backfillV2ProductTdAttributes(a.documentElement.outerHTML));
122
124
  } catch (e) {
123
125
  return console.error("ItemsBlockMigrator failed:", e), t;
124
126
  }
@@ -131,24 +133,24 @@ class F {
131
133
  */
132
134
  extractConfiguration(t) {
133
135
  var C;
134
- const e = P(
135
- this.readSelfOrDescendantAttribute(t, "data-type") || V(t)
136
- ), a = this.readSelfOrDescendantAttribute(t, "data-number") || "1", r = parseInt(a) - 1, d = h[e], n = ((C = d == null ? void 0 : d[r]) == null ? void 0 : C.value) || d[0].value, o = this.extractConfigBlockAttributes(t, e, a);
136
+ const e = D(
137
+ this.readSelfOrDescendantAttribute(t, "data-type") || U(t)
138
+ ), a = this.readSelfOrDescendantAttribute(t, "data-number") || "1", r = parseInt(a) - 1, u = h[e], c = ((C = u == null ? void 0 : u[r]) == null ? void 0 : C.value) || u[0].value, o = this.extractConfigBlockAttributes(t, e, a);
137
139
  this.applyDomFallbacks(t, o);
138
- const i = t.querySelector('[product-attr="price"]'), u = o["data-product_price_control_currency_symbol"], l = o["data-product_price_currency_location"] || "0", s = o["data-product_price_control_formated"], p = s !== "false" && s !== "0", S = o["data-card_orientation_control_value"] === "horizontal" ? "horizontal" : "vertical", y = t.querySelector('a[product-attr="name"]'), f = (y == null ? void 0 : y.getAttribute("style")) || void 0, g = t.querySelector('a[product-attr="button"]') ?? t.querySelector('[product-attr="button"]'), I = (g == null ? void 0 : g.getAttribute("style")) || void 0, w = (i == null ? void 0 : i.getAttribute("style")) || void 0, m = t.querySelector("p.original-price") ?? t.querySelector('[product-attr="originalPrice"]'), A = m != null && m.getAttribute("style") ? m : (m == null ? void 0 : m.closest("p")) ?? m, k = (A == null ? void 0 : A.getAttribute("style")) || void 0, E = t.querySelector('[product-attr="quantity"]'), B = (E == null ? void 0 : E.getAttribute("style")) || void 0;
140
+ const i = t.querySelector('[product-attr="price"]'), d = o["data-product_price_control_currency_symbol"], l = o["data-product_price_currency_location"] || "0", s = o["data-product_price_control_formated"], p = s !== "false" && s !== "0", S = o["data-card_orientation_control_value"] === "horizontal" ? "horizontal" : "vertical", f = t.querySelector('a[product-attr="name"]'), y = (f == null ? void 0 : f.getAttribute("style")) || void 0, g = t.querySelector('a[product-attr="button"]') ?? t.querySelector('[product-attr="button"]'), I = (g == null ? void 0 : g.getAttribute("style")) || void 0, k = (i == null ? void 0 : i.getAttribute("style")) || void 0, m = t.querySelector("p.original-price") ?? t.querySelector('[product-attr="originalPrice"]'), A = m != null && m.getAttribute("style") ? m : (m == null ? void 0 : m.closest("p")) ?? m, q = (A == null ? void 0 : A.getAttribute("style")) || void 0, E = t.querySelector('[product-attr="quantity"]'), w = (E == null ? void 0 : E.getAttribute("style")) || void 0;
139
141
  return {
140
142
  orientation: S,
141
143
  itemsType: e,
142
- itemId: n,
143
- currencySymbol: u,
144
+ itemId: c,
145
+ currencySymbol: d,
144
146
  currencyLocation: l,
145
147
  formattedPrice: p,
146
148
  configBlockAttributes: o,
147
- nameStyles: f,
149
+ nameStyles: y,
148
150
  buttonStyles: I,
149
- priceStyles: w,
150
- originalPriceStyles: k,
151
- quantityStyles: B
151
+ priceStyles: k,
152
+ originalPriceStyles: q,
153
+ quantityStyles: w
152
154
  };
153
155
  }
154
156
  /**
@@ -159,8 +161,8 @@ class F {
159
161
  * card migrates with the boilerplate defaults: caption "Buy", USD, full-width button.
160
162
  */
161
163
  applyDomFallbacks(t, e) {
162
- var S, y;
163
- const a = t.querySelector("esd-config-block"), r = (...f) => !a || f.every((g) => !(a.getAttribute(g) ?? "").trim());
164
+ var S, f;
165
+ const a = t.querySelector("esd-config-block"), r = (...y) => !a || y.every((g) => !(a.getAttribute(g) ?? "").trim());
164
166
  Object.entries({
165
167
  image: '[product-attr="imageSrc"]',
166
168
  name: '[product-attr="name"]',
@@ -168,17 +170,17 @@ class F {
168
170
  original_price: '[product-attr="originalPrice"], p.original-price',
169
171
  quantity: '[product-attr="quantity"]',
170
172
  button: '[product-attr="button"]'
171
- }).forEach(([f, g]) => {
172
- const I = `data-product_${f}_control_enabled`;
173
+ }).forEach(([y, g]) => {
174
+ const I = `data-product_${y}_control_enabled`;
173
175
  r(I) && (e[I] = t.querySelector(g) ? "true" : "false");
174
176
  }), r("data-card_orientation_control_value") && (e["data-card_orientation_control_value"] = t.querySelector('[colspan="2"]') ? "vertical" : "horizontal");
175
- const n = t.querySelector('a[product-attr="button"]') ?? t.querySelector('[product-attr="button"]'), o = (S = n == null ? void 0 : n.textContent) == null ? void 0 : S.replace(/\s+/g, " ").trim();
177
+ const c = t.querySelector('a[product-attr="button"]') ?? t.querySelector('[product-attr="button"]'), o = (S = c == null ? void 0 : c.textContent) == null ? void 0 : S.replace(/\s+/g, " ").trim();
176
178
  o && r("data-product_button_control_label") && (e["data-product_button_control_label"] = o);
177
- const i = (n == null ? void 0 : n.getAttribute("style")) || "";
179
+ const i = (c == null ? void 0 : c.getAttribute("style")) || "";
178
180
  r("data-product_button_control_atw") && /display:\s*inline/.test(i) && !/(?:^|;)\s*width\s*:\s*100%/.test(i) && (e["data-product_button_control_atw"] = "false");
179
- const u = t.querySelector('[product-attr="imageSrc"]'), l = u ? this.readImageSize(u) : null, s = (l == null ? void 0 : l.height) ?? (l == null ? void 0 : l.width), p = (l == null ? void 0 : l.width) ?? (l == null ? void 0 : l.height);
181
+ const d = t.querySelector('[product-attr="imageSrc"]'), l = d ? this.readImageSize(d) : null, s = (l == null ? void 0 : l.height) ?? (l == null ? void 0 : l.width), p = (l == null ? void 0 : l.width) ?? (l == null ? void 0 : l.height);
180
182
  s && r("data-product_image_control_image-height") && (e["data-product_image_control_image-height"] = s), p && r("data-product_image_control_image-width") && (e["data-product_image_control_image-width"] = p), this.applyPriceDomFallbacks(t, e, r);
181
- const T = ((y = t.querySelector('[product-attr="name"]')) == null ? void 0 : y.getAttribute("style")) || "";
183
+ const T = ((f = t.querySelector('[product-attr="name"]')) == null ? void 0 : f.getAttribute("style")) || "";
182
184
  r("data-product_name_control_trim") && /white-space:\s*normal/.test(T) && (e["data-product_name_control_trim"] = "0");
183
185
  }
184
186
  /**
@@ -189,15 +191,15 @@ class F {
189
191
  * the default back over the real value.
190
192
  */
191
193
  applyPriceDomFallbacks(t, e, a) {
192
- var u;
194
+ var d;
193
195
  const r = t.querySelector('[product-attr="price"]') ?? t.querySelector('[product-attr="originalPrice"]');
194
196
  if (!r)
195
197
  return;
196
- const d = (u = r.getAttribute("data-currency_symbol")) == null ? void 0 : u.trim();
197
- d && a("data-product_price_control_currency_symbol") && (e["data-product_price_control_currency_symbol"] = d);
198
- const n = r.getAttribute("data-curency");
199
- if (n && a("data-product_price_currency_location", "data-product_price_control_curency")) {
200
- const l = n === "after" ? "1" : "0";
198
+ const u = (d = r.getAttribute("data-currency_symbol")) == null ? void 0 : d.trim();
199
+ u && a("data-product_price_control_currency_symbol") && (e["data-product_price_control_currency_symbol"] = u);
200
+ const c = r.getAttribute("data-curency");
201
+ if (c && a("data-product_price_currency_location", "data-product_price_control_curency")) {
202
+ const l = c === "after" ? "1" : "0";
201
203
  e["data-product_price_currency_location"] = l, e["data-product_price_control_curency"] = l;
202
204
  }
203
205
  const o = r.getAttribute("data-formated");
@@ -232,14 +234,14 @@ class F {
232
234
  * to nothing, so only a positive integer counts as an answer.
233
235
  */
234
236
  readImageDimension(t, e) {
235
- var u;
237
+ var d;
236
238
  const a = (l) => {
237
239
  const s = (l ?? "").trim().match(/^(\d+(?:\.\d+)?)(?:px)?$/i), p = s ? Math.floor(parseFloat(s[1])) : 0;
238
240
  return p > 0 ? String(p) : null;
239
- }, r = a((u = t.getAttribute(e)) == null ? void 0 : u.trim());
241
+ }, r = a((d = t.getAttribute(e)) == null ? void 0 : d.trim());
240
242
  if (r)
241
243
  return r;
242
- const d = t.getAttribute("style") || "", n = new RegExp(`(?:^|;)\\s*${e}:\\s*(\\d+(?:\\.\\d+)?)px`), o = new RegExp(`max-${e}:\\s*(\\d+(?:\\.\\d+)?)px`), i = d.match(n) || d.match(o);
244
+ const u = t.getAttribute("style") || "", c = new RegExp(`(?:^|;)\\s*${e}:\\s*(\\d+(?:\\.\\d+)?)px`), o = new RegExp(`max-${e}:\\s*(\\d+(?:\\.\\d+)?)px`), i = u.match(c) || u.match(o);
243
245
  return a(i == null ? void 0 : i[1]);
244
246
  }
245
247
  /**
@@ -250,26 +252,26 @@ class F {
250
252
  * @param itemNumber - The item number (1-based index)
251
253
  */
252
254
  extractConfigBlockAttributes(t, e, a) {
253
- const r = t.querySelector("esd-config-block"), d = {};
255
+ const r = t.querySelector("esd-config-block"), u = {};
254
256
  if (r) {
255
257
  if (Array.from(r.attributes).forEach((o) => {
256
- o.name.startsWith("data-") && (d[o.name] = o.value);
257
- }), d["data-cart_items_select_control_value"]) {
258
- const o = d["data-cart_items_select_control_value"];
258
+ o.name.startsWith("data-") && (u[o.name] = o.value);
259
+ }), u["data-cart_items_select_control_value"]) {
260
+ const o = u["data-cart_items_select_control_value"];
259
261
  if (/^\d+$/.test(o)) {
260
- const i = parseInt(o) - 1, u = h[e];
261
- u && u[i] && (d["data-cart_items_select_control_value"] = u[i].value);
262
+ const i = parseInt(o) - 1, d = h[e];
263
+ d && d[i] && (u["data-cart_items_select_control_value"] = d[i].value);
262
264
  }
263
265
  }
264
- if (d["data-product_price_control_curency"]) {
265
- const o = d["data-product_price_control_curency"];
266
+ if (u["data-product_price_control_curency"]) {
267
+ const o = u["data-product_price_control_curency"];
266
268
  let i = o;
267
- o === "before" ? i = "0" : o === "after" && (i = "1"), d["data-product_price_control_curency"] = i, d["data-product_price_currency_location"] = i;
269
+ o === "before" ? i = "0" : o === "after" && (i = "1"), u["data-product_price_control_curency"] = i, u["data-product_price_currency_location"] = i;
268
270
  }
269
- (!d["data-product_price_control_currency_symbol"] || d["data-product_price_control_currency_symbol"].trim() === "") && (d["data-product_price_control_currency_symbol"] = "USD");
271
+ (!u["data-product_price_control_currency_symbol"] || u["data-product_price_control_currency_symbol"].trim() === "") && (u["data-product_price_control_currency_symbol"] = "USD");
270
272
  }
271
- const n = { ...this.getDefaultConfigBlockAttributes(), ...d };
272
- return n["data-type"] = e, n["data-source"] = e, n["data-product_image_link"] = H(e, a), n["data-product_button_link"] = $(e, a), n;
273
+ const c = { ...this.getDefaultConfigBlockAttributes(), ...u };
274
+ return c["data-type"] = e, c["data-source"] = e, c["data-product_image_link"] = Y(e, a), c["data-product_button_link"] = W(e, a), c;
273
275
  }
274
276
  /**
275
277
  * Returns default esd-config-block attributes based on the old template structure
@@ -343,27 +345,29 @@ class F {
343
345
  backfillV2ProductTdAttributes(t) {
344
346
  if (!t.includes("ins-product-td") || !t.includes("esd-ext-config"))
345
347
  return t;
346
- const e = this.parser.parseFromString(t, "text/html");
348
+ const e = this.parser.parseFromString(H(t), "text/html");
347
349
  let a = !1;
348
350
  return e.querySelectorAll(".ins-product-td").forEach((r) => {
349
- r.hasAttribute("width") && (r.removeAttribute("width"), a = !0), r.classList.contains("esd-container-frame") && (r.classList.remove("esd-container-frame"), a = !0);
350
- const d = r.querySelector("table.ins-product-wrapper");
351
- d != null && d.hasAttribute("width") && d.getAttribute("width") !== "100%" && (d.setAttribute("width", "100%"), a = !0);
352
- const n = r.getAttribute("esd-ext-config");
353
- let o = null;
351
+ r.hasAttribute("width") && (r.removeAttribute("width"), a = !0), r.classList.contains("esd-container-frame") && (r.classList.remove("esd-container-frame"), a = !0), r.querySelectorAll("table.ins-product-wrapper").forEach((d) => {
352
+ d.hasAttribute("width") && d.getAttribute("width") !== "100%" && (d.setAttribute("width", "100%"), a = !0);
353
+ const l = d.getAttribute("style");
354
+ l && L(l) && (d.setAttribute("style", x(l)), d.setAttribute("width", "100%"), a = !0);
355
+ });
356
+ const u = r.getAttribute("esd-ext-config");
357
+ let c = null;
354
358
  try {
355
- o = n ? JSON.parse(n) : null;
359
+ c = u ? JSON.parse(u) : null;
356
360
  } catch {
357
361
  }
358
- if (!o || (!r.getAttribute("data-nodup") && typeof o.priceHideDiscount == "boolean" && (r.setAttribute("data-nodup", String(o.priceHideDiscount)), a = !0), r.getAttribute("data-type")))
362
+ if (!c || (!r.getAttribute("data-nodup") && typeof c.priceHideDiscount == "boolean" && (r.setAttribute("data-nodup", String(c.priceHideDiscount)), a = !0), r.getAttribute("data-type")))
359
363
  return;
360
- const i = o.type || o.source;
361
- if (!i)
364
+ const o = c.type || c.source;
365
+ if (!o)
362
366
  return;
363
- r.setAttribute("data-type", i), a = !0;
364
- const u = typeof o.itemsSelectValue == "string" ? o.itemsSelectValue.match(/\((\d+)\)/) : null;
365
- u && r.getAttribute("data-number") !== u[1] && r.setAttribute("data-number", u[1]);
366
- }), a ? e.documentElement.outerHTML : t;
367
+ r.setAttribute("data-type", o), a = !0;
368
+ const i = typeof c.itemsSelectValue == "string" ? c.itemsSelectValue.match(/\((\d+)\)/) : null;
369
+ i && r.getAttribute("data-number") !== i[1] && r.setAttribute("data-number", i[1]);
370
+ }), a ? $(e.documentElement.outerHTML) : t;
367
371
  }
368
372
  /**
369
373
  * Fast check for the presence of any items block (cart / browsed / purchased)
@@ -397,9 +401,9 @@ class F {
397
401
  `), r;
398
402
  }
399
403
  }
400
- function J(c) {
401
- return new F().migrate(c);
404
+ function X(n) {
405
+ return new z().migrate(n);
402
406
  }
403
407
  export {
404
- J as migrateItemsBlock
408
+ X as migrateItemsBlock
405
409
  };
@@ -1,32 +1,33 @@
1
1
  var k = Object.defineProperty;
2
- var D = (l, a, t) => a in l ? k(l, a, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[a] = t;
3
- var y = (l, a, t) => D(l, typeof a != "symbol" ? a + "" : a, t);
4
- import { BlockId as N } from "../../../enums/block.js";
2
+ var S = (d, l, e) => l in d ? k(d, l, { enumerable: !0, configurable: !0, writable: !0, value: e }) : d[l] = e;
3
+ var g = (d, l, e) => S(d, typeof l != "symbol" ? l + "" : l, e);
4
+ import { BlockId as D } from "../../../enums/block.js";
5
5
  import { useOnboardingStore as T } from "../../../stores/onboarding.js";
6
- import { getMigrationBannerHtml as S } from "../../../utils/migrationBannerHtml.js";
7
- import { Block as A, BlockCompositionType as M, ModificationDescription as u } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
8
- import { currencyAttrTargets as H, ITEMS_CURRENCY_ATTR as m } from "./constants/currency.js";
9
- import { ItemsBlockId as R } from "./enums/controlEnums.js";
10
- import { SETTINGS_ENUMS as C, DefaultConfigValues as g } from "./enums/settingsEnums.js";
6
+ import { getMigrationBannerHtml as N } from "../../../utils/migrationBannerHtml.js";
7
+ import { Block as H, BlockCompositionType as R, ModificationDescription as u } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
8
+ import { PRODUCT_WRAPPER_SELECTOR as M, isZeroWidthValue as m } from "./constants/cardWidth.js";
9
+ import { currencyAttrTargets as w, ITEMS_CURRENCY_ATTR as y } from "./constants/currency.js";
10
+ import { ItemsBlockId as E } from "./enums/controlEnums.js";
11
+ import { SETTINGS_ENUMS as b, DefaultConfigValues as p } from "./enums/settingsEnums.js";
11
12
  import { getDefaultTemplate as O } from "./template.js";
12
- import { getItemsBlockContainer as b, getItemsBlockConfig as h, deriveItemNumber as B, generateBlockInstanceId as E, getDefaultItemsBlockConfig as w } from "./utils/nodeConfigUtils.js";
13
- const _ = N.Items, P = "Reconcile Items currency DOM attributes";
14
- class K extends A {
13
+ import { getItemsBlockContainer as _, getItemsBlockConfig as C, deriveItemNumber as B, generateBlockInstanceId as P, getDefaultItemsBlockConfig as v } from "./utils/nodeConfigUtils.js";
14
+ const A = D.Items, V = "Reconcile Items currency DOM attributes";
15
+ class $ extends H {
15
16
  constructor() {
16
17
  super(...arguments);
17
18
  /** Block instances whose currency attrs were already self-healed this session (SD-147588 — undo-safe). */
18
- y(this, "_currencyHealed", /* @__PURE__ */ new Set());
19
+ g(this, "_currencyHealed", /* @__PURE__ */ new Set());
19
20
  /** blockInstanceIds already claimed by a live block this session (SD-147588 collision detection). */
20
- y(this, "_seenInstanceIds", /* @__PURE__ */ new Set());
21
+ g(this, "_seenInstanceIds", /* @__PURE__ */ new Set());
21
22
  }
22
23
  getId() {
23
- return _;
24
+ return A;
24
25
  }
25
26
  getIcon() {
26
27
  return "items-icon";
27
28
  }
28
29
  getBlockCompositionType() {
29
- return M.CONTAINER;
30
+ return R.CONTAINER;
30
31
  }
31
32
  getName() {
32
33
  return this.api.translate("Items");
@@ -35,20 +36,20 @@ class K extends A {
35
36
  return this.api.translate("Items lets you display personalized products based on user behavior.");
36
37
  }
37
38
  getSettingsPanelTitleHtml() {
38
- return S(
39
- _,
39
+ return N(
40
+ A,
40
41
  this.api.translate("Items"),
41
42
  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
43
  );
43
44
  }
44
45
  getTemplate() {
45
46
  return O({
46
- orientation: C.ORIENTATION.VERTICAL,
47
- itemsType: C.ITEMS_TYPE.CART_ITEMS,
47
+ orientation: b.ORIENTATION.VERTICAL,
48
+ itemsType: b.ITEMS_TYPE.CART_ITEMS,
48
49
  itemId: "{{Abandoned Cart Item (1) Url}}",
49
- currencySymbol: g.productPriceCurrencySymbolControlValue,
50
- currencyLocation: g.productPriceCurrencyLocationControlValue,
51
- formattedPrice: g.productPriceFormattedControlValue === "1"
50
+ currencySymbol: p.productPriceCurrencySymbolControlValue,
51
+ currencyLocation: p.productPriceCurrencyLocationControlValue,
52
+ formattedPrice: p.productPriceFormattedControlValue === "1"
52
53
  });
53
54
  }
54
55
  allowInnerBlocksDND() {
@@ -57,27 +58,27 @@ class K extends A {
57
58
  canBeSavedAsModule() {
58
59
  return !0;
59
60
  }
60
- onCreated(t) {
61
- const o = this.api.getDocumentModifier(), c = this.api.getDocumentRootCssNode();
62
- c.querySelector('[product-attr="imageSrc"] img') || o.modifyCss(c).appendRule('[product-attr="imageSrc"] img {object-fit: contain;}');
63
- const i = b(t);
64
- if (!i)
61
+ onCreated(e) {
62
+ const t = this.api.getDocumentModifier(), c = this.api.getDocumentRootCssNode();
63
+ c.querySelector('[product-attr="imageSrc"] img') || t.modifyCss(c).appendRule('[product-attr="imageSrc"] img {object-fit: contain;}');
64
+ const r = _(e);
65
+ if (!r)
65
66
  return;
66
- const r = i.getNodeConfig(), s = r && Object.keys(r).length > 0, e = h(t);
67
- if (e != null && e.initialized) {
67
+ const o = r.getNodeConfig(), s = o && Object.keys(o).length > 0, i = C(e);
68
+ if (i != null && i.initialized) {
68
69
  if (!s) {
69
- const d = this.api.getDocumentModifier();
70
- d.modifyHtml(i).setNodeConfig(e), this._stampProductTdDomAttributes(i, e, d), this._shouldReconcileCurrency(e) && this._reconcileCurrencyDomAttributes(i, e, d), d.apply(new u("Migrate legacy config to nodeConfig")), this._markCurrencyHealed(e.blockInstanceId);
70
+ const a = this.api.getDocumentModifier();
71
+ a.modifyHtml(r).setNodeConfig(i), this._stampProductTdDomAttributes(r, i, a), this._healCollapsedWidths(r, a), this._shouldReconcileCurrency(i) && this._reconcileCurrencyDomAttributes(r, i, a), a.apply(new u("Migrate legacy config to nodeConfig")), this._markCurrencyHealed(i.blockInstanceId);
71
72
  return;
72
73
  }
73
74
  } else {
74
- const d = w(), p = this.api.getDocumentModifier();
75
- p.modifyHtml(i).setNodeConfig(d), this._stampProductTdDomAttributes(i, d, p, !0), p.apply(new u("Initialize Items block with default configuration")), T().startOnboarding("itemsOnboarding");
75
+ const a = v(), I = this.api.getDocumentModifier();
76
+ I.modifyHtml(r).setNodeConfig(a), this._stampProductTdDomAttributes(r, a, I, !0), I.apply(new u("Initialize Items block with default configuration")), T().startOnboarding("itemsOnboarding");
76
77
  return;
77
78
  }
78
- const n = this._resolveInstanceId(e.blockInstanceId), f = this.api.getDocumentModifier();
79
- let I = !1;
80
- n !== e.blockInstanceId && (f.modifyHtml(i).setNodeConfig({ ...e, blockInstanceId: n }), I = !0), !this._currencyHealed.has(n) && this._reconcileCurrencyDomAttributes(i, e, f) && (I = !0), I && f.apply(new u("Assign Items block instance ID and reconcile currency")), this._markCurrencyHealed(n);
79
+ const n = this._resolveInstanceId(i.blockInstanceId), f = this.api.getDocumentModifier();
80
+ let h = !1;
81
+ n !== i.blockInstanceId && (f.modifyHtml(r).setNodeConfig({ ...i, blockInstanceId: n }), h = !0), !this._currencyHealed.has(n) && this._reconcileCurrencyDomAttributes(r, i, f) && (h = !0), this._healCollapsedWidths(r, f) && (h = !0), h && f.apply(new u("Assign Items block instance ID and reconcile currency")), this._markCurrencyHealed(n);
81
82
  }
82
83
  /**
83
84
  * Re-seeds nodeConfig from the persisted esd-ext-config when a saved module
@@ -85,24 +86,24 @@ class K extends A {
85
86
  * into nodeConfig, so without this a reused module would reset to defaults.
86
87
  * Guarded to the nodeConfig-empty case so it runs once and never loops.
87
88
  */
88
- onDocumentChanged(t) {
89
- const o = b(t);
90
- if (!o)
89
+ onDocumentChanged(e) {
90
+ const t = _(e);
91
+ if (!t)
91
92
  return;
92
- const c = o.getNodeConfig();
93
+ const c = t.getNodeConfig();
93
94
  if (c && Object.keys(c).length > 0) {
94
- const e = h(t);
95
- if (e != null && e.initialized && this._shouldReconcileCurrency(e)) {
95
+ const i = C(e);
96
+ if (i != null && i.initialized && this._shouldReconcileCurrency(i)) {
96
97
  const n = this.api.getDocumentModifier();
97
- this._reconcileCurrencyDomAttributes(o, e, n) && n.apply(new u(P)), this._markCurrencyHealed(e.blockInstanceId);
98
+ this._reconcileCurrencyDomAttributes(t, i, n) && n.apply(new u(V)), this._markCurrencyHealed(i.blockInstanceId);
98
99
  }
99
100
  return;
100
101
  }
101
- const r = h(t);
102
- if (!(r != null && r.initialized))
102
+ const o = C(e);
103
+ if (!(o != null && o.initialized))
103
104
  return;
104
105
  const s = this.api.getDocumentModifier();
105
- s.modifyHtml(o).setNodeConfig(r), this._stampProductTdDomAttributes(o, r, s), this._shouldReconcileCurrency(r) && this._reconcileCurrencyDomAttributes(o, r, s), s.apply(new u("Recover Items block config from saved module")), this._markCurrencyHealed(r.blockInstanceId);
106
+ s.modifyHtml(t).setNodeConfig(o), this._stampProductTdDomAttributes(t, o, s), this._healCollapsedWidths(t, s), this._shouldReconcileCurrency(o) && this._reconcileCurrencyDomAttributes(t, o, s), s.apply(new u("Recover Items block config from saved module")), this._markCurrencyHealed(o.blockInstanceId);
106
107
  }
107
108
  /**
108
109
  * Bakes the compiler-read DOM attributes (`data-type`, `data-number`, `data-nodup`) onto the
@@ -112,11 +113,21 @@ class K extends A {
112
113
  * restored before export. The name `<a>` carries no data-type/data-number of its own and
113
114
  * relies on this td-level fallback in pairProductVariables.
114
115
  */
115
- _stampProductTdDomAttributes(t, o, c, i = !1) {
116
- const r = B(o.itemsSelectValue, o.type), s = (e, n) => {
117
- i && t.getAttribute(e) || c.modifyHtml(t).setAttribute(e, n);
116
+ _stampProductTdDomAttributes(e, t, c, r = !1) {
117
+ const o = B(t.itemsSelectValue, t.type), s = (i, n) => {
118
+ r && e.getAttribute(i) || c.modifyHtml(e).setAttribute(i, n);
118
119
  };
119
- s("data-type", o.type), s("data-number", r), s("data-nodup", String(o.priceHideDiscount));
120
+ s("data-type", t.type), s("data-number", o), s("data-nodup", String(t.priceHideDiscount));
121
+ }
122
+ /**
123
+ * Repairs a saved module's collapsed card into the state the load migrator produces. Acts only
124
+ * on a zero width, so Stripo's non-zero drop-time width never triggers it and a healed block no-ops.
125
+ */
126
+ _healCollapsedWidths(e, t) {
127
+ const r = e.querySelectorAll(M).filter((o) => m(o.getAttribute("width")) || m(o.getStyle("width")));
128
+ return !m(e.getAttribute("width")) && !r.length ? !1 : (e.hasClass("esd-container-frame") && t.modifyHtml(e).removeClass("esd-container-frame"), e.getAttribute("width") !== null && t.modifyHtml(e).removeAttribute("width"), r.forEach((o) => {
129
+ m(o.getAttribute("width")) && t.modifyHtml(o).setAttribute("width", "100%"), m(o.getStyle("width")) && t.modifyHtml(o).setStyle("width", "100%");
130
+ }), !0);
120
131
  }
121
132
  /**
122
133
  * Whether a currency self-heal pass should run for this block (SD-147588). The only gate here is
@@ -126,12 +137,12 @@ class K extends A {
126
137
  * the symbol write alone is skipped for the 'USD' sentinel — so we must NOT gate the whole pass
127
138
  * on symbol customization here, or a default-symbol block with a toggled location never heals.
128
139
  */
129
- _shouldReconcileCurrency(t) {
130
- return !t.blockInstanceId || !this._currencyHealed.has(t.blockInstanceId);
140
+ _shouldReconcileCurrency(e) {
141
+ return !e.blockInstanceId || !this._currencyHealed.has(e.blockInstanceId);
131
142
  }
132
143
  /** Marks a block instance's currency as reconciled so it is not healed again (undo-safe). */
133
- _markCurrencyHealed(t) {
134
- t && this._currencyHealed.add(t);
144
+ _markCurrencyHealed(e) {
145
+ e && this._currencyHealed.add(e);
135
146
  }
136
147
  /**
137
148
  * Resolves the id for a just-created block to one that is unique per live instance.
@@ -140,13 +151,13 @@ class K extends A {
140
151
  * currency heal guard and settings-panel switch detection. Mint a fresh id on absence
141
152
  * or collision, otherwise keep the existing one. Registers the result as claimed.
142
153
  */
143
- _resolveInstanceId(t) {
144
- let o = t;
145
- if (!o || this._seenInstanceIds.has(o))
154
+ _resolveInstanceId(e) {
155
+ let t = e;
156
+ if (!t || this._seenInstanceIds.has(t))
146
157
  do
147
- o = E();
148
- while (this._seenInstanceIds.has(o));
149
- return this._seenInstanceIds.add(o), o;
158
+ t = P();
159
+ while (this._seenInstanceIds.has(t));
160
+ return this._seenInstanceIds.add(t), t;
150
161
  }
151
162
  /**
152
163
  * Stamps the export-read currency attrs onto every price `<p>` from config, so a template whose
@@ -159,15 +170,15 @@ class K extends A {
159
170
  * Returns true only when an attr actually changed, so the caller can skip an empty apply that
160
171
  * would otherwise re-trigger onDocumentChanged and loop.
161
172
  */
162
- _reconcileCurrencyDomAttributes(t, o, c) {
163
- const { position: i, symbol: r } = H(o), s = t.querySelectorAll(`.${R.PRICE} p`);
164
- let e = !1;
173
+ _reconcileCurrencyDomAttributes(e, t, c) {
174
+ const { position: r, symbol: o } = w(t), s = e.querySelectorAll(`.${E.PRICE} p`);
175
+ let i = !1;
165
176
  return s.forEach((n) => {
166
- i !== void 0 && n.getAttribute(m.POSITION) !== i && (c.modifyHtml(n).setAttribute(m.POSITION, i), e = !0), r !== void 0 && n.getAttribute(m.SYMBOL) !== r && (c.modifyHtml(n).setAttribute(m.SYMBOL, r), e = !0);
167
- }), e;
177
+ r !== void 0 && n.getAttribute(y.POSITION) !== r && (c.modifyHtml(n).setAttribute(y.POSITION, r), i = !0), o !== void 0 && n.getAttribute(y.SYMBOL) !== o && (c.modifyHtml(n).setAttribute(y.SYMBOL, o), i = !0);
178
+ }), i;
168
179
  }
169
180
  }
170
181
  export {
171
- _ as BLOCK_ID,
172
- K as ItemsBlock
182
+ A as BLOCK_ID,
183
+ $ as ItemsBlock
173
184
  };
@@ -0,0 +1,20 @@
1
+ const R = ".ins-product-td", T = ".ins-product-wrapper", s = "width: 100%", c = /(^|;)\s*width\s*:\s*0(?:px|%)?\s*(?:!important)?\s*(?=;|$)/i, n = new RegExp(c.source, "gi"), o = /(^|;)\s*width\s*:/i, _ = /^0(?:px|%)?$/i, a = (t) => _.test((t ?? "").trim()), E = (t) => c.test(t), h = (t) => {
2
+ if (E(t))
3
+ return t.replace(
4
+ n,
5
+ (i, e) => `${e}${e ? " " : ""}${s}`
6
+ );
7
+ if (o.test(t))
8
+ return t;
9
+ const r = t.trim();
10
+ return r ? r.endsWith(";") ? `${r} ${s};` : `${r}; ${s};` : `${s};`;
11
+ }, p = (t) => t.replace(n, (r, i) => i).replace(/;{2,}/g, ";").replace(/^\s*;\s*/, "").replace(/;\s*$/, "").trim();
12
+ export {
13
+ R as PRODUCT_TD_SELECTOR,
14
+ T as PRODUCT_WRAPPER_SELECTOR,
15
+ s as WIDTH_PIN_DECLARATION,
16
+ E as hasZeroWidthDeclaration,
17
+ a as isZeroWidthValue,
18
+ h as withWidthPin,
19
+ p as withoutZeroWidth
20
+ };
@@ -1,5 +1,5 @@
1
1
  const t = `{-{-TEMPLATE_FIRST_LINE-}-}
2
- <table class="es-left ins-product-wrapper" cellspacing="0" cellpadding="0" align="left" width="100%">
2
+ <table class="es-left ins-product-wrapper" cellspacing="0" cellpadding="0" align="left" width="100%" style="width: 100%;">
3
3
  <tbody>
4
4
  <tr>
5
5
  <td class="es-p20b es-p10r es-p10l es-m-p20b es-p10t" width="100%" align="center">
@@ -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
  };
@@ -10,3 +10,8 @@ export declare const MSO_ITEMS_HIDE_END = "MSO_ITEMS_HIDE_END";
10
10
  * and collapse them inline for web-engine Outlook.
11
11
  */
12
12
  export declare function wrapHiddenPriceTdsForOutlook(html: string): string;
13
+ /**
14
+ * Export safety net for a zero Items width: the wrapper gets the 100% pin, the cell's zero is
15
+ * dropped so it keeps its column width (a pin there overflows 33%/50% columns).
16
+ */
17
+ export declare function normalizeItemsBlockWidths(html: string): string;
@@ -46,6 +46,11 @@ export declare class ItemsBlock extends Block {
46
46
  * relies on this td-level fallback in pairProductVariables.
47
47
  */
48
48
  private _stampProductTdDomAttributes;
49
+ /**
50
+ * Repairs a saved module's collapsed card into the state the load migrator produces. Acts only
51
+ * on a zero width, so Stripo's non-zero drop-time width never triggers it and a healed block no-ops.
52
+ */
53
+ private _healCollapsedWidths;
49
54
  /**
50
55
  * Whether a currency self-heal pass should run for this block (SD-147588). The only gate here is
51
56
  * once-per-session: heal each instance at most once, so the auto-fix can't fight undo (undo
@@ -0,0 +1,12 @@
1
+ export declare const PRODUCT_TD_SELECTOR = ".ins-product-td";
2
+ export declare const PRODUCT_WRAPPER_SELECTOR = ".ins-product-wrapper";
3
+ /** The declaration `layouts/vertical.html` and `layouts/horizontal.html` ship inline. */
4
+ export declare const WIDTH_PIN_DECLARATION = "width: 100%";
5
+ /** True for a `width` attribute value that renders the card zero-wide (`0`, `0px`, `0%`). */
6
+ export declare const isZeroWidthValue: (value?: string | null) => boolean;
7
+ /** True when an inline style declares a zero `width` (ignores `max-width` / `min-width`). */
8
+ export declare const hasZeroWidthDeclaration: (style: string) => boolean;
9
+ /** Rewrites a zero width to the pin or appends it; a non-zero width is kept. Idempotent. */
10
+ export declare const withWidthPin: (style: string) => string;
11
+ /** Drops a zero `width` declaration; the product cell must inherit its column width, not be pinned. */
12
+ export declare const withoutZeroWidth: (style: string) => string;
@@ -1,5 +1,3 @@
1
- /** Separator between product ids in the `sanitizeProductIds` output */
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,3 @@
1
+ export declare const protectLiquid: (html: string) => string;
2
+ /** Reverses `protectLiquid`, including markers the serializer escaped inside attribute values. */
3
+ export declare const restoreLiquid: (html: string) => string;
@@ -0,0 +1,5 @@
1
+ const p = (l) => l.split(/(<!--[\s\S]*?-->)/).map((e, c) => c % 2 ? e : e.replaceAll("{%", "<!--lq{%").replaceAll("%}", "%}lq-->")).join(""), r = (l) => l.replaceAll("<!--lq{%", "{%").replaceAll("%}lq-->", "%}").replaceAll("&lt;!--lq{%", "{%").replaceAll("%}lq--&gt;", "%}");
2
+ export {
3
+ p as protectLiquid,
4
+ r as restoreLiquid
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.20.0-beta.11a0bde",
3
+ "version": "3.20.0-beta.30c96fc",
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",