@useinsider/guido 3.8.1-beta.f1e1757 → 3.8.1-beta.fa71fc2
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.
- package/dist/composables/useHtmlCompiler.js +10 -13
- package/dist/config/compiler/htmlCompilerRules.js +10 -38
- package/dist/config/compiler/recommendationCompilerRules.js +108 -83
- package/dist/config/migrator/itemsBlockMigrator.js +168 -122
- package/dist/extensions/Blocks/Items/controls/name/trimming.js +17 -18
- package/dist/extensions/Blocks/Items/controls/settingsControl.js +47 -47
- package/dist/extensions/Blocks/Items/layouts/horizontal.html.js +13 -9
- package/dist/extensions/Blocks/Items/layouts/vertical.html.js +26 -14
- package/dist/extensions/Blocks/Items/template.js +229 -223
- package/dist/src/extensions/Blocks/Items/template.d.ts +7 -0
- package/package.json +1 -1
|
@@ -26,27 +26,24 @@ const y = /* @__PURE__ */ new Set([
|
|
|
26
26
|
"format-comment-braces",
|
|
27
27
|
"add-universal-link-flags",
|
|
28
28
|
// Coupon placeholder replacement (only present when liquidSyntax is enabled).
|
|
29
|
-
"liquid-coupon-code"
|
|
30
|
-
// Editor-only attribute strip — AMP4EMAIL has no `contenteditable`, so leaving
|
|
31
|
-
// it in narrows/breaks rendering. Pure attribute removal, emits nothing.
|
|
32
|
-
"remove-contenteditable"
|
|
29
|
+
"liquid-coupon-code"
|
|
33
30
|
]), M = () => {
|
|
34
|
-
var
|
|
35
|
-
const { compiler:
|
|
36
|
-
...!!((m =
|
|
31
|
+
var t, m, r;
|
|
32
|
+
const { compiler: e, isFeatureEnabled: a, partner: n } = k(), p = ((t = e.value) == null ? void 0 : t.customRules) || [], l = [
|
|
33
|
+
...!!((m = e.value) != null && m.ignoreDefaultRules) ? [] : R,
|
|
37
34
|
...v,
|
|
38
35
|
...x,
|
|
39
36
|
...g,
|
|
40
37
|
...b,
|
|
41
38
|
...H,
|
|
42
|
-
...
|
|
43
|
-
...p.map((
|
|
44
|
-
...
|
|
45
|
-
priority:
|
|
39
|
+
...a("liquidSyntax") ? C : [],
|
|
40
|
+
...p.map((o, f) => ({
|
|
41
|
+
...o,
|
|
42
|
+
priority: o.priority + 1e3 + f
|
|
46
43
|
// Ensure additional rules run after default rules
|
|
47
44
|
}))
|
|
48
|
-
], u = s(l), c = l.filter((
|
|
49
|
-
return { compileHtml: (
|
|
45
|
+
], u = s(l), c = l.filter((o) => y.has(o.id)), d = s(c), i = (r = n.value) == null ? void 0 : r.fallbackFont;
|
|
46
|
+
return { compileHtml: (o) => u.compile(o, void 0, i), compileAmpHtml: (o) => d.compile(o, void 0, i) };
|
|
50
47
|
};
|
|
51
48
|
export {
|
|
52
49
|
M as useHtmlCompiler
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { stripFontTags as
|
|
2
|
-
const
|
|
1
|
+
import { stripFontTags as n } from "../../utils/stripFontTags.js";
|
|
2
|
+
const l = [
|
|
3
3
|
{
|
|
4
4
|
id: "fix-url-encoding-start",
|
|
5
5
|
description: "Replace {%22 with %7B%22 to fix URL encoding",
|
|
@@ -58,7 +58,7 @@ const d = [
|
|
|
58
58
|
id: "strip-font-tags",
|
|
59
59
|
description: 'Unwrap browser-translate-injected <font dir="auto"> tags, keeping inner content; other <font> elements are left intact.',
|
|
60
60
|
type: "custom",
|
|
61
|
-
processor: (e) =>
|
|
61
|
+
processor: (e) => n(e),
|
|
62
62
|
priority: 15
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -99,7 +99,7 @@ const d = [
|
|
|
99
99
|
description: "Adding MSO Conditions",
|
|
100
100
|
type: "custom",
|
|
101
101
|
processor: (e) => {
|
|
102
|
-
const
|
|
102
|
+
const i = [
|
|
103
103
|
`<!--[if gte mso 9]>
|
|
104
104
|
<style>sup {
|
|
105
105
|
font-size: 100% !important;
|
|
@@ -119,13 +119,13 @@ const d = [
|
|
|
119
119
|
<w:DontUseAdvancedTypographyReadingMail></w:DontUseAdvancedTypographyReadingMail>
|
|
120
120
|
</w:WordDocument>
|
|
121
121
|
</xml><![endif]-->`
|
|
122
|
-
],
|
|
122
|
+
], s = /<head>([\S\s]*)<\/head>/, o = new RegExp(s);
|
|
123
123
|
if (!e.match(o))
|
|
124
124
|
return e;
|
|
125
|
-
let
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
}),
|
|
125
|
+
let t = e;
|
|
126
|
+
return i.forEach((r) => {
|
|
127
|
+
t = t.replace("</head>", `${r}</head>`);
|
|
128
|
+
}), t;
|
|
129
129
|
},
|
|
130
130
|
priority: 30
|
|
131
131
|
},
|
|
@@ -146,36 +146,8 @@ const d = [
|
|
|
146
146
|
replacement: "email-static.useinsider.com",
|
|
147
147
|
replaceAll: !0,
|
|
148
148
|
priority: 41
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
id: "convert-rgb-to-hex",
|
|
152
|
-
// SD-142395: rgb()/6-digit hex are verbose; hex/3-digit shorthand is byte-identical
|
|
153
|
-
// to render. Shrinks the whole email to stay under Gmail's ~102KB clip threshold.
|
|
154
|
-
// Leaves rgba()/8-digit hex (alpha) untouched.
|
|
155
|
-
description: "Convert rgb() colors to hex and collapse 6-digit hex to shorthand",
|
|
156
|
-
type: "custom",
|
|
157
|
-
processor: (e) => {
|
|
158
|
-
const t = (i) => i.toString(16).padStart(2, "0");
|
|
159
|
-
return e.replace(/rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/gi, (i, o, n, s) => {
|
|
160
|
-
const [r, a, c] = [Number(o), Number(n), Number(s)];
|
|
161
|
-
return r > 255 || a > 255 || c > 255 ? i : `#${t(r)}${t(a)}${t(c)}`;
|
|
162
|
-
}).replace(/#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3\b/gi, "#$1$2$3");
|
|
163
|
-
},
|
|
164
|
-
priority: 44
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
id: "remove-contenteditable",
|
|
168
|
-
// SD-142395: contenteditable is a Stripo editor flag with zero effect in a
|
|
169
|
-
// delivered email. Stripping it globally shaves bytes off every text block,
|
|
170
|
-
// helping the whole email stay under Gmail's ~102KB clip threshold.
|
|
171
|
-
description: "Strip editor-only contenteditable attributes from compiled output",
|
|
172
|
-
type: "regex",
|
|
173
|
-
pattern: '\\s+contenteditable="[^"]*"',
|
|
174
|
-
replacement: "",
|
|
175
|
-
flags: "g",
|
|
176
|
-
priority: 45
|
|
177
149
|
}
|
|
178
150
|
];
|
|
179
151
|
export {
|
|
180
|
-
|
|
152
|
+
l as defaultHtmlCompilerRules
|
|
181
153
|
};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { useRecommendation as
|
|
2
|
-
import { DUMMY_IMAGE_MAPPINGS as
|
|
3
|
-
import { prepareRecommendationBlocks as
|
|
4
|
-
const
|
|
1
|
+
import { useRecommendation as h } from "../../composables/useRecommendation.js";
|
|
2
|
+
import { DUMMY_IMAGE_MAPPINGS as N, REGEX as T, VerticalOrientation as M, CSS as E, ATTRIBUTES as A, CONDITIONS as y, HTML as C } from "../../enums/recommendation.js";
|
|
3
|
+
import { prepareRecommendationBlocks as x } from "./utils/recommendationCompilerUtils.js";
|
|
4
|
+
const w = [
|
|
5
5
|
{
|
|
6
6
|
id: "replace-images-with-variable-names",
|
|
7
7
|
description: "Replacing dummy images with variable names in recommendation module",
|
|
8
8
|
type: "custom",
|
|
9
|
-
processor: (
|
|
10
|
-
let e =
|
|
11
|
-
return Object.entries(
|
|
12
|
-
Object.entries(
|
|
13
|
-
e = e.replaceAll(
|
|
9
|
+
processor: (c) => {
|
|
10
|
+
let e = c;
|
|
11
|
+
return Object.entries(N).forEach(([, l]) => {
|
|
12
|
+
Object.entries(l).forEach(([n, s]) => {
|
|
13
|
+
e = e.replaceAll(s, `{{${n}}}`);
|
|
14
14
|
});
|
|
15
15
|
}), e;
|
|
16
16
|
},
|
|
@@ -41,21 +41,21 @@ const U = [
|
|
|
41
41
|
id: "add-recommendation-unresponsive-css",
|
|
42
42
|
description: "Adding recommendation unresponsive css",
|
|
43
43
|
type: "custom",
|
|
44
|
-
processor: (
|
|
45
|
-
const { calculateCardWidth: e, getRecommendationCampaignData:
|
|
46
|
-
let
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
}),
|
|
54
|
-
const
|
|
55
|
-
|
|
44
|
+
processor: (c) => {
|
|
45
|
+
const { calculateCardWidth: e, getRecommendationCampaignData: l } = h();
|
|
46
|
+
let n = c;
|
|
47
|
+
const s = n.match(T.ID);
|
|
48
|
+
if (s) {
|
|
49
|
+
const a = [];
|
|
50
|
+
if (s.forEach((i) => {
|
|
51
|
+
const u = /recommendation-id="(.*?)"/i.exec(i), _ = u ? u[1].trim() : "", R = l(_);
|
|
52
|
+
R.textTrimming && R.orientation === M && a.push(e(R));
|
|
53
|
+
}), a.length) {
|
|
54
|
+
const i = `width:${Math.min(...a)}px!important;`;
|
|
55
|
+
n = n.replace(E.REGULAR_NAME_HEIGHT, `${E.TRIMMED_NAME_HEIGHT} ${i} ${E.ELLIPSIS}`).replace(E.REGULAR_NAME_CONTAINER_HEIGHT, E.TRIMMED_NAME_CONTAINER_CSS).replace(E.RESPONSIVE_NAME_SIZE, `${E.RESPONSIVE_NAME_HEIGHT} ${i} ${E.ELLIPSIS}`).replace(E.RESPONSIVE_NAME_CONTAINER_HEIGHT, E.TRIMMED_RESPONSIVE_NAME_CONTAINER_CSS);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
return
|
|
58
|
+
return n;
|
|
59
59
|
},
|
|
60
60
|
priority: 52
|
|
61
61
|
},
|
|
@@ -63,34 +63,34 @@ const U = [
|
|
|
63
63
|
id: "prepare-recommendations",
|
|
64
64
|
description: "Replacing product data with template variables in recommendation blocks",
|
|
65
65
|
type: "custom",
|
|
66
|
-
processor: (
|
|
66
|
+
processor: (c) => x(c),
|
|
67
67
|
priority: 48
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
id: "add-discount-conditions",
|
|
71
71
|
description: "Adding discount conditions to the recommendation block",
|
|
72
72
|
type: "custom",
|
|
73
|
-
processor: (
|
|
74
|
-
let e =
|
|
75
|
-
const
|
|
76
|
-
return
|
|
77
|
-
const
|
|
78
|
-
if (!
|
|
73
|
+
processor: (c) => {
|
|
74
|
+
let e = c;
|
|
75
|
+
const l = e.match(T.ATTRIBUTE_PARAGRAPH), { getRecommendationCampaignData: n } = h();
|
|
76
|
+
return l !== null && l.forEach((s) => {
|
|
77
|
+
const a = s.match(T.CUSTOM_FIELD);
|
|
78
|
+
if (!a)
|
|
79
79
|
return;
|
|
80
|
-
const [
|
|
81
|
-
if (!
|
|
80
|
+
const [i] = a, u = i.match(T.CUSTOM_FIELD_INDEXES_PART), _ = i.match(T.CUSTOM_FIELD_NAME_PART), R = s.match(T.ATTRIBUTE_PARAGRAPH_START_TAG);
|
|
81
|
+
if (!u || !_ || !R)
|
|
82
82
|
return;
|
|
83
|
-
const [
|
|
84
|
-
let
|
|
85
|
-
if (
|
|
86
|
-
const
|
|
87
|
-
|
|
83
|
+
const [b] = u, [I] = _, [d] = R, o = I.substring(1, I.length - 2), r = d.match(T.COMPOSITION) !== null;
|
|
84
|
+
let t = i;
|
|
85
|
+
if (r) {
|
|
86
|
+
const S = b.substring(2, b.length - 3), m = n(S);
|
|
87
|
+
o === A.OMNIBUS_PRICE && (m.priceBeforeTextValue && (t = `${m.priceBeforeTextValue}${t}`), m.priceAfterTextValue && (t = `${t}${m.priceAfterTextValue}`)), o === A.OMNIBUS_DISCOUNT && (m.discountBeforeTextValue && (t = `${m.discountBeforeTextValue}${t}`), m.discountAfterTextValue && (t = `${t}${m.discountAfterTextValue}`));
|
|
88
88
|
}
|
|
89
|
-
const
|
|
90
|
-
let
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
e = e.replace(
|
|
89
|
+
const p = b.substring(2);
|
|
90
|
+
let f = "";
|
|
91
|
+
o in y.IF && (f = y.IF[o].replaceAll(`{${A.DISCOUNT}}`, `${p}${A.DISCOUNT}`).replaceAll(`{${A.OMNIBUS_DISCOUNT}}`, `${p}${A.OMNIBUS_DISCOUNT}`).replaceAll(`{${A.OMNIBUS_PRICE}}`, `${p}${A.OMNIBUS_PRICE}`));
|
|
92
|
+
const g = `${d}${t}${C.PARAGRAPH_END_TAG}`, $ = `${f}${r ? g : s}${y.ELSE}${d}${C.PARAGRAPH_END_TAG}${y.END_IF}`;
|
|
93
|
+
e = e.replace(s, $);
|
|
94
94
|
}), e;
|
|
95
95
|
},
|
|
96
96
|
priority: 53
|
|
@@ -110,11 +110,11 @@ const U = [
|
|
|
110
110
|
type: "custom",
|
|
111
111
|
// Scoped to REC_START/REC_END markers so it cannot strip `product-attr`
|
|
112
112
|
// from Items block elements, which the items compiler rule depends on.
|
|
113
|
-
processor: (
|
|
113
|
+
processor: (c) => {
|
|
114
114
|
const e = /\s+(?:esd-extension-block-id|data-attribute-type|data-visibility|data-text-before|data-text-after|product-attr|composition)="[^"]*"/g;
|
|
115
|
-
return
|
|
115
|
+
return c.replace(
|
|
116
116
|
/<!--REC_START-->([\s\S]*?)<!--REC_END-->/g,
|
|
117
|
-
(
|
|
117
|
+
(l, n) => `<!--REC_START-->${n.replace(e, "")}<!--REC_END-->`
|
|
118
118
|
);
|
|
119
119
|
},
|
|
120
120
|
priority: 55
|
|
@@ -123,8 +123,8 @@ const U = [
|
|
|
123
123
|
id: "strip-unused-recommendation-classes",
|
|
124
124
|
description: "Remove CSS classes not referenced by any style rule from recommendation elements",
|
|
125
125
|
type: "custom",
|
|
126
|
-
processor: (
|
|
127
|
-
let e =
|
|
126
|
+
processor: (c) => {
|
|
127
|
+
let e = c.replace(
|
|
128
128
|
/ class="(?:product-card-segment|attribute-cell|recommendation-attribute-row|product-image|product-name|product-price|product-old-price|product-omnibus-price|product-omnibus-discount|product-button|recommendation-product-row|product-card-wrapper)"/g,
|
|
129
129
|
""
|
|
130
130
|
);
|
|
@@ -136,8 +136,8 @@ const U = [
|
|
|
136
136
|
id: "remove-empty-mobile-layout-artifacts",
|
|
137
137
|
description: "Remove empty mobile container rows and unused mobile layout CSS",
|
|
138
138
|
type: "custom",
|
|
139
|
-
processor: (
|
|
140
|
-
let e =
|
|
139
|
+
processor: (c) => {
|
|
140
|
+
let e = c;
|
|
141
141
|
return e = e.replace(
|
|
142
142
|
/<tr[^>]*class="ins-recommendation-mobile-row"[^>]*><\/tr>/g,
|
|
143
143
|
""
|
|
@@ -146,50 +146,75 @@ const U = [
|
|
|
146
146
|
""
|
|
147
147
|
), e = e.replace(
|
|
148
148
|
/@media[^{]*max-width\s*:\s*480px[^{]*\{((?:[^{}]*\{[^{}]*\})*[^{}]*)\}/g,
|
|
149
|
-
(
|
|
150
|
-
const
|
|
151
|
-
return
|
|
149
|
+
(l, n) => {
|
|
150
|
+
const s = n.match(/[^{}]+\{[^{}]*\}/g) || [], a = /ins-recommendation|product-image-cell|button-cell|product-info-cell/;
|
|
151
|
+
return s.every((u) => a.test(u)) ? "" : l;
|
|
152
152
|
}
|
|
153
153
|
)), e;
|
|
154
154
|
},
|
|
155
155
|
priority: 57
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
|
-
id: "
|
|
159
|
-
|
|
160
|
-
// `!important` on es-button anchor colors so the intended button text color
|
|
161
|
-
// wins. Kept INLINE (never moved into a <style> class) so it survives Gmail's
|
|
162
|
-
// clipping — "view entire message" strips <style> blocks but keeps inline styles.
|
|
163
|
-
// (SD-142395: split out of the removed deduplicate-inline-styles rule.)
|
|
164
|
-
description: "Force !important on es-button link color to defeat Gmail link-color override",
|
|
158
|
+
id: "deduplicate-inline-styles",
|
|
159
|
+
description: "Replace repeated inline styles with CSS class references within recommendation blocks",
|
|
165
160
|
type: "custom",
|
|
166
|
-
processor: (
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
161
|
+
processor: (c) => {
|
|
162
|
+
const e = c.replace(
|
|
163
|
+
/<a\b[^>]*\bes-button\b[^>]*>/g,
|
|
164
|
+
(o) => o.replace(
|
|
165
|
+
/([;"]color:)([^;"]+)/g,
|
|
166
|
+
(r, t, p) => p.includes("!important") ? r : `${t}${p} !important`
|
|
167
|
+
)
|
|
168
|
+
), l = /<!--REC_START-->([\s\S]*?)<!--REC_END-->/g, n = / style="([^"]*)"/g, s = /* @__PURE__ */ new Map();
|
|
169
|
+
let a = l.exec(e);
|
|
170
|
+
for (; a !== null; ) {
|
|
171
|
+
let o = n.exec(a[1]);
|
|
172
|
+
for (; o !== null; ) {
|
|
173
|
+
const [, r] = o;
|
|
174
|
+
s.set(r, (s.get(r) || 0) + 1), o = n.exec(a[1]);
|
|
175
|
+
}
|
|
176
|
+
n.lastIndex = 0, a = l.exec(e);
|
|
177
|
+
}
|
|
178
|
+
const i = /* @__PURE__ */ new Map(), u = [];
|
|
179
|
+
let _ = 0;
|
|
180
|
+
if (s.forEach((o, r) => {
|
|
181
|
+
if (!r.includes("v-text-anchor") && o >= 6) {
|
|
182
|
+
const t = `rc${_++}`, p = r.endsWith(";") ? r : `${r};`;
|
|
183
|
+
i.set(r, t), u.push(`.${t}{${p}}`);
|
|
184
|
+
}
|
|
185
|
+
}), i.size === 0) {
|
|
186
|
+
let o = e;
|
|
187
|
+
return o = o.replaceAll("<!--REC_START-->", ""), o = o.replaceAll("<!--REC_END-->", ""), o;
|
|
188
|
+
}
|
|
189
|
+
const R = (o) => o.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), b = (o, r) => `${o.slice(0, -1)} ${r}"`, I = /* @__PURE__ */ new Map();
|
|
190
|
+
i.forEach((o, r) => {
|
|
191
|
+
const t = R(r);
|
|
192
|
+
I.set(r, {
|
|
193
|
+
caseA: new RegExp(`(class="[^"]*")((?:[^>]*?)) style="${t}"`, "g"),
|
|
194
|
+
caseB: new RegExp(` style="${t}"((?:[^>]*?))(class="[^"]*")`, "g")
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
let d = e.replace("</style>", `${u.join("")}</style>`);
|
|
198
|
+
return d = d.replace(
|
|
199
|
+
/<!--REC_START-->([\s\S]*?)<!--REC_END-->/g,
|
|
200
|
+
(o, r) => {
|
|
201
|
+
let t = r;
|
|
202
|
+
return i.forEach((p, f) => {
|
|
203
|
+
const g = I.get(f);
|
|
204
|
+
t = t.replace(
|
|
205
|
+
g.caseA,
|
|
206
|
+
($, S, m) => b(S, p) + m
|
|
207
|
+
), t = t.replace(
|
|
208
|
+
g.caseB,
|
|
209
|
+
($, S, m) => S + b(m, p)
|
|
210
|
+
), t = t.replaceAll(` style="${f}"`, ` class="${p}"`);
|
|
211
|
+
}), t;
|
|
212
|
+
}
|
|
213
|
+
), d = d.replaceAll("<!--REC_START-->", ""), d = d.replaceAll("<!--REC_END-->", ""), d;
|
|
189
214
|
},
|
|
190
|
-
priority:
|
|
215
|
+
priority: 58
|
|
191
216
|
}
|
|
192
217
|
];
|
|
193
218
|
export {
|
|
194
|
-
|
|
219
|
+
w as recommendationCompilerRules
|
|
195
220
|
};
|