@useinsider/guido 3.21.1 → 3.21.2
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/config/compiler/utils/recommendationCompilerUtils.js +55 -53
- package/dist/extensions/Blocks/Recommendation/block.js +52 -37
- package/dist/extensions/Blocks/Recommendation/controls/image/index.js +76 -16
- package/dist/extensions/Blocks/Recommendation/utils/captureStyleTemplates.js +16 -15
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +2 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/image/index.d.ts +31 -17
- package/package.json +1 -1
|
@@ -7,13 +7,13 @@ function L(t, r, e, o, c = "") {
|
|
|
7
7
|
const i = `{{${c}${t}_${r}_${e}}}`, n = `{{${c}${t}_${r}_currency}}`;
|
|
8
8
|
return o === "before" ? `${n} ${i}` : `${i} ${n}`;
|
|
9
9
|
}
|
|
10
|
-
function
|
|
10
|
+
function A(t) {
|
|
11
11
|
let r = t;
|
|
12
12
|
for (; r.children.length === 1; )
|
|
13
13
|
[r] = r.children;
|
|
14
14
|
return r;
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function y(t, r, e, o, c, i) {
|
|
17
17
|
switch (r) {
|
|
18
18
|
case "productImage": {
|
|
19
19
|
const n = t.querySelector("img");
|
|
@@ -24,7 +24,7 @@ function A(t, r, e, o, c, i) {
|
|
|
24
24
|
}
|
|
25
25
|
case "productName": {
|
|
26
26
|
const n = t.querySelector("p");
|
|
27
|
-
n && (
|
|
27
|
+
n && (A(n).textContent = `{{${i}${e}_${o}_name}}`);
|
|
28
28
|
break;
|
|
29
29
|
}
|
|
30
30
|
// Inline mode ("Move to next line" OFF) merges BOTH prices into one row
|
|
@@ -32,16 +32,16 @@ function A(t, r, e, o, c, i) {
|
|
|
32
32
|
// substitute by cell content, not by the row's anchor (SD-145161).
|
|
33
33
|
case "productPrice":
|
|
34
34
|
case "productOldPrice": {
|
|
35
|
-
const n = (
|
|
36
|
-
|
|
35
|
+
const n = (a, l) => {
|
|
36
|
+
a && (A(a).textContent = L(
|
|
37
37
|
e,
|
|
38
38
|
o,
|
|
39
|
-
|
|
39
|
+
l,
|
|
40
40
|
c,
|
|
41
41
|
i
|
|
42
42
|
));
|
|
43
|
-
}, s = t.querySelector(".product-price p"),
|
|
44
|
-
n(s ?? (r === "productPrice" ? u : null), "price"), n(
|
|
43
|
+
}, s = t.querySelector(".product-price p"), d = t.querySelector(".product-old-price p"), u = !s && !d ? t.querySelector("p") : null;
|
|
44
|
+
n(s ?? (r === "productPrice" ? u : null), "price"), n(d ?? (r === "productOldPrice" ? u : null), "original_price");
|
|
45
45
|
break;
|
|
46
46
|
}
|
|
47
47
|
case "productButton": {
|
|
@@ -70,8 +70,8 @@ function A(t, r, e, o, c, i) {
|
|
|
70
70
|
default: {
|
|
71
71
|
const n = t.getAttribute("product-attr") ? t : t.querySelector("[product-attr]");
|
|
72
72
|
if (n) {
|
|
73
|
-
const s = n.getAttribute("product-attr"),
|
|
74
|
-
|
|
73
|
+
const s = n.getAttribute("product-attr"), d = n.querySelector("p");
|
|
74
|
+
d && (A(d).textContent = `{{${i}${e}_${o}_${s}}}`);
|
|
75
75
|
}
|
|
76
76
|
break;
|
|
77
77
|
}
|
|
@@ -88,54 +88,54 @@ function b(t, r, e, o) {
|
|
|
88
88
|
function R(t, r, e) {
|
|
89
89
|
return b(t, r, 0, e);
|
|
90
90
|
}
|
|
91
|
-
function
|
|
91
|
+
function w(t, r, e, o) {
|
|
92
92
|
if (!t.innerHTML.includes("{{"))
|
|
93
93
|
return;
|
|
94
94
|
const { open: c, close: i } = b(t.ownerDocument, r, e, o);
|
|
95
95
|
t.insertBefore(c, t.firstChild), t.appendChild(i);
|
|
96
96
|
}
|
|
97
|
-
function
|
|
97
|
+
function D(t, r, e, o) {
|
|
98
98
|
var n, s;
|
|
99
99
|
if (!t.innerHTML.includes("{{"))
|
|
100
100
|
return;
|
|
101
101
|
const { open: c, close: i } = b(t.ownerDocument, r, e, o);
|
|
102
102
|
(n = t.parentNode) == null || n.insertBefore(c, t), (s = t.parentNode) == null || s.insertBefore(i, t.nextSibling);
|
|
103
103
|
}
|
|
104
|
-
function
|
|
104
|
+
function v(t, r, e, o) {
|
|
105
105
|
t.querySelectorAll(".recommendation-product-row").forEach((i, n) => {
|
|
106
|
-
i.querySelectorAll("[data-attribute-type]").forEach((
|
|
107
|
-
const u =
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}) :
|
|
111
|
-
}),
|
|
106
|
+
i.querySelectorAll("[data-attribute-type]").forEach((d) => {
|
|
107
|
+
const u = d.getAttribute("data-attribute-type") || "", a = d.querySelectorAll(".attribute-cell");
|
|
108
|
+
a.length > 0 ? a.forEach((l) => {
|
|
109
|
+
y(l, u, r, n, e, o);
|
|
110
|
+
}) : y(d, u, r, n, e, o);
|
|
111
|
+
}), D(i, r, n, o);
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
|
-
function
|
|
114
|
+
function H(t, r, e, o) {
|
|
115
115
|
const c = t.querySelectorAll(".recommendation-product-row");
|
|
116
116
|
if (!c.length)
|
|
117
117
|
return;
|
|
118
118
|
const [i] = c, n = i.querySelector("[data-attribute-type]"), s = n ? n.querySelectorAll(".attribute-cell").length : 1;
|
|
119
|
-
c.forEach((
|
|
120
|
-
|
|
121
|
-
const p =
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
119
|
+
c.forEach((d, u) => {
|
|
120
|
+
d.querySelectorAll("[data-attribute-type]").forEach((l) => {
|
|
121
|
+
const p = l.getAttribute("data-attribute-type") || "";
|
|
122
|
+
l.querySelectorAll(".attribute-cell").forEach((f, h) => {
|
|
123
|
+
const S = u * s + h;
|
|
124
|
+
y(f, p, r, S, e, o), w(f, r, S, o);
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
-
function
|
|
129
|
+
function W(t, r, e, o) {
|
|
130
130
|
t.querySelectorAll(".ins-recommendation-product-container").forEach((i) => {
|
|
131
|
-
|
|
131
|
+
H(i, r, e, o);
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
function F(t, r, e) {
|
|
135
135
|
const o = t.getAttribute("data-layout") || "grid", c = t.getAttribute("currency-alignment") || "after";
|
|
136
|
-
o === "list" ?
|
|
136
|
+
o === "list" ? v(t, r, c, e) : W(t, r, c, e);
|
|
137
137
|
}
|
|
138
|
-
function
|
|
138
|
+
function _(t, r, e) {
|
|
139
139
|
const o = new RegExp(`${r}\\s*:\\s*(\\d+)\\s*px`, "i"), c = t.match(o);
|
|
140
140
|
return c ? parseInt(c[1]) : e;
|
|
141
141
|
}
|
|
@@ -150,7 +150,7 @@ function C(t) {
|
|
|
150
150
|
const e = (t.getAttribute("style") || "").match(/(?:^|[;\s])width\s*:\s*(\d+(?:\.\d+)?(?:px|%))/i);
|
|
151
151
|
return e && $(e[1]) ? e[1] : null;
|
|
152
152
|
}
|
|
153
|
-
function
|
|
153
|
+
function x(t, r) {
|
|
154
154
|
let e = t.parentElement;
|
|
155
155
|
for (; e && e !== r; ) {
|
|
156
156
|
if (e.tagName === "TD" && C(e))
|
|
@@ -159,35 +159,37 @@ function G(t, r) {
|
|
|
159
159
|
}
|
|
160
160
|
return null;
|
|
161
161
|
}
|
|
162
|
-
function
|
|
163
|
-
const r = t.getAttribute("style") || "", e =
|
|
162
|
+
function G(t) {
|
|
163
|
+
const r = t.getAttribute("style") || "", e = _(r, "width", 600), o = _(r, "padding", 0) * 2, c = Math.max(0, e - o);
|
|
164
164
|
c !== 0 && t.querySelectorAll("img.adapt-img").forEach((i) => {
|
|
165
165
|
if (i.hasAttribute("width"))
|
|
166
166
|
return;
|
|
167
|
-
const n =
|
|
167
|
+
const n = x(i, t);
|
|
168
168
|
if (!n)
|
|
169
169
|
return;
|
|
170
|
-
const s = C(n),
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
const s = C(n), d = _(n.getAttribute("style") || "", "padding", 0) * 2, u = s.endsWith("%") ? Math.floor(c * parseFloat(s) / 100) : parseInt(s), a = Math.max(1, u - d), l = i.getAttribute("style") || "", p = /(?:^|[;\s])max-height\s*:\s*(\d+(?:\.\d+)?)px/i.exec(l);
|
|
171
|
+
if (p) {
|
|
172
|
+
i.setAttribute("width", String(Math.max(1, Math.min(a, Math.floor(parseFloat(p[1])))))), i.removeAttribute("height");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (i.setAttribute("width", String(a)), !/\bwidth\s*:\s*\d/i.test(l)) {
|
|
176
|
+
const m = l && !l.trim().endsWith(";") ? "; " : "";
|
|
177
|
+
i.setAttribute("style", `${l}${m}width: ${a}px`);
|
|
176
178
|
}
|
|
177
179
|
});
|
|
178
180
|
}
|
|
179
|
-
const E = "MSO_MOBILE_HIDE_START",
|
|
180
|
-
function
|
|
181
|
+
const E = "MSO_MOBILE_HIDE_START", V = "MSO_MOBILE_HIDE_END";
|
|
182
|
+
function U(t, r) {
|
|
181
183
|
t.querySelectorAll(q).forEach((e) => {
|
|
182
184
|
var i, n;
|
|
183
185
|
const o = e.querySelector(M);
|
|
184
186
|
if (!o || o.children.length === 0)
|
|
185
187
|
return;
|
|
186
188
|
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(
|
|
189
|
+
(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(V), e.nextSibling));
|
|
188
190
|
});
|
|
189
191
|
}
|
|
190
|
-
function
|
|
192
|
+
function X(t, r) {
|
|
191
193
|
const e = t.match(/<!DOCTYPE[^>]*>/i);
|
|
192
194
|
return (e ? `${e[0]}
|
|
193
195
|
` : "") + r.documentElement.outerHTML;
|
|
@@ -200,17 +202,17 @@ function Q(t) {
|
|
|
200
202
|
i.recommendationCampaignUrls = {};
|
|
201
203
|
const { isFeatureEnabled: n } = g(), s = n("liquidSyntax") ? "reco_" : "";
|
|
202
204
|
return o.forEach((u) => {
|
|
203
|
-
var
|
|
204
|
-
const
|
|
205
|
-
if (
|
|
206
|
-
if ((
|
|
207
|
-
F(u,
|
|
208
|
-
const { open:
|
|
209
|
-
(
|
|
205
|
+
var l, p, m, f;
|
|
206
|
+
const a = u.getAttribute("recommendation-id");
|
|
207
|
+
if (a) {
|
|
208
|
+
if ((l = u.parentNode) == null || l.insertBefore(e.createComment("REC_START"), u), (p = u.parentNode) == null || p.insertBefore(e.createComment("REC_END"), u.nextSibling), u.querySelectorAll('[data-visibility="0"]').forEach((h) => h.remove()), c(a), U(u, e), !T(u)) {
|
|
209
|
+
F(u, a, s);
|
|
210
|
+
const { open: h, close: S } = R(e, a, s);
|
|
211
|
+
(m = u.parentNode) == null || m.insertBefore(h, u), (f = u.parentNode) == null || f.insertBefore(S, u.nextSibling);
|
|
210
212
|
}
|
|
211
|
-
|
|
213
|
+
G(u);
|
|
212
214
|
}
|
|
213
|
-
}),
|
|
215
|
+
}), X(r, e).replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}").replaceAll("<!--{%", "{%").replaceAll("%}-->", "%}");
|
|
214
216
|
}
|
|
215
217
|
export {
|
|
216
218
|
L as formatPriceVariable,
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var u = (m, c, e) =>
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var A = (m, c, e) => c in m ? b(m, c, { enumerable: !0, configurable: !0, writable: !0, value: e }) : m[c] = e;
|
|
3
|
+
var u = (m, c, e) => A(m, typeof c != "symbol" ? c + "" : c, e);
|
|
4
4
|
import { useConfig as g } from "../../../composables/useConfig.js";
|
|
5
|
-
import { BlockId as
|
|
5
|
+
import { BlockId as D } from "../../../enums/block.js";
|
|
6
6
|
import { getMigrationBannerHtml as E } from "../../../utils/migrationBannerHtml.js";
|
|
7
7
|
import { Block as S, BlockCompositionType as v, ModificationDescription as _ } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
8
|
-
import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as
|
|
8
|
+
import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as M } from "./constants/defaultConfig.js";
|
|
9
9
|
import { RECOMMENDATION_ID_ATTR as f } from "./constants/selectors.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { ensureMobileFitRule as w, syncHeightBound as O } from "./controls/image/index.js";
|
|
11
|
+
import { regenerateMobileProductRows as H } from "./controls/main/utils.js";
|
|
12
|
+
import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as T } from "./controls/mobileLayout/cssRules.js";
|
|
12
13
|
import { RecommendationConfigService as a } from "./services/configService.js";
|
|
13
14
|
import { useRecommendationExtensionStore as p } from "./store/recommendation.js";
|
|
14
|
-
import { getDefaultTemplate as
|
|
15
|
-
import { useRecommendationBlockWarning as
|
|
16
|
-
import { registerNodeConfigWriter as
|
|
17
|
-
import { refreshArrivedStrategyBlocks as q, resolveSourceConfig as
|
|
18
|
-
const
|
|
15
|
+
import { getDefaultTemplate as x } from "./templates/grid/template.js";
|
|
16
|
+
import { useRecommendationBlockWarning as F } from "./useRecommendationBlockWarning.js";
|
|
17
|
+
import { registerNodeConfigWriter as y, readBlockNodeConfigs as $ } from "./utils/nodeConfigWriter.js";
|
|
18
|
+
import { refreshArrivedStrategyBlocks as q, resolveSourceConfig as L, refreshDuplicatedStrategyBlocks as P } from "./utils/strategyCommit.js";
|
|
19
|
+
const k = D.Recommendation, h = "recommendation-block-v2", C = "hide-price";
|
|
19
20
|
let B = !1;
|
|
20
|
-
class
|
|
21
|
+
class se extends S {
|
|
21
22
|
constructor() {
|
|
22
23
|
super();
|
|
23
24
|
/**
|
|
@@ -34,7 +35,7 @@ class te extends S {
|
|
|
34
35
|
u(this, "_refreshClaims", /* @__PURE__ */ new Map());
|
|
35
36
|
}
|
|
36
37
|
getId() {
|
|
37
|
-
return
|
|
38
|
+
return k;
|
|
38
39
|
}
|
|
39
40
|
getIcon() {
|
|
40
41
|
return "recommendation-icon";
|
|
@@ -52,7 +53,7 @@ class te extends S {
|
|
|
52
53
|
}
|
|
53
54
|
getSettingsPanelTitleHtml() {
|
|
54
55
|
return E(
|
|
55
|
-
|
|
56
|
+
k,
|
|
56
57
|
this.api.translate("Recommendation Block"),
|
|
57
58
|
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.")
|
|
58
59
|
);
|
|
@@ -75,7 +76,7 @@ class te extends S {
|
|
|
75
76
|
*/
|
|
76
77
|
getTemplate() {
|
|
77
78
|
const e = this._generateNextId();
|
|
78
|
-
return this._pendingBlockId = e,
|
|
79
|
+
return this._pendingBlockId = e, x(e);
|
|
79
80
|
}
|
|
80
81
|
/**
|
|
81
82
|
* Called when a new block is dropped into the template
|
|
@@ -87,7 +88,7 @@ class te extends S {
|
|
|
87
88
|
onCreated(e) {
|
|
88
89
|
const t = this._getRecommendationId(e);
|
|
89
90
|
if (t !== null && t > 0) {
|
|
90
|
-
if (this._pendingBlockId = null, this._detectDuplicate(t)) {
|
|
91
|
+
if (this._pendingBlockId = null, this._ensureMobileFitRule(e), this._detectDuplicate(t)) {
|
|
91
92
|
this._handleDuplicate(e, t), this._scheduleArrivalReset(e);
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
@@ -109,7 +110,7 @@ class te extends S {
|
|
|
109
110
|
e,
|
|
110
111
|
{
|
|
111
112
|
recommendationId: i,
|
|
112
|
-
configVersion: r ? N :
|
|
113
|
+
configVersion: r ? N : M,
|
|
113
114
|
...s ? { partnerName: g().partnerName.value } : {},
|
|
114
115
|
// An RRS block picks a strategy, not an algorithm, and its algorithm control is
|
|
115
116
|
// hidden. Keeping the `mostPopular` default would bake a most-popular feed URL
|
|
@@ -119,8 +120,8 @@ class te extends S {
|
|
|
119
120
|
), l = p();
|
|
120
121
|
if (l.setCurrentBlock(i), this._stampHidePrice(e, n.priceHideIfSameAsDiscounted), o) {
|
|
121
122
|
I(this.api);
|
|
122
|
-
const
|
|
123
|
-
|
|
123
|
+
const d = this._getBlockElement(e);
|
|
124
|
+
d && (R(this.api, d, !0), H({
|
|
124
125
|
currentNode: e,
|
|
125
126
|
documentModifier: this.api.getDocumentModifier()
|
|
126
127
|
}));
|
|
@@ -131,7 +132,7 @@ class te extends S {
|
|
|
131
132
|
onDocumentInit() {
|
|
132
133
|
try {
|
|
133
134
|
const e = this.api.getDocumentRoot();
|
|
134
|
-
e && "querySelectorAll" in e && e.querySelectorAll(`.${
|
|
135
|
+
e && "querySelectorAll" in e && e.querySelectorAll(`.${h}`).forEach((t) => this._queueArrivalRefresh(t));
|
|
135
136
|
} catch (e) {
|
|
136
137
|
console.error("[recommendation] refreshing an opened strategy failed", e);
|
|
137
138
|
}
|
|
@@ -154,13 +155,13 @@ class te extends S {
|
|
|
154
155
|
"Assign recommendation ID to legacy block"
|
|
155
156
|
);
|
|
156
157
|
}
|
|
157
|
-
this._healLingeringDuplicate(e), a.needsMigration(e) && this._migrateFromLegacy(e), this._healHidePriceAttr(e);
|
|
158
|
+
this._healLingeringDuplicate(e), a.needsMigration(e) && this._migrateFromLegacy(e), this._healHidePriceAttr(e), this._ensureMobileFitRule(e), this._syncHeightBound(e);
|
|
158
159
|
try {
|
|
159
160
|
B || (I(this.api), B = !0);
|
|
160
161
|
const t = a.getConfig(e), i = this._getBlockElement(e);
|
|
161
162
|
if (i) {
|
|
162
163
|
const r = !t.mobileLayoutEnabled;
|
|
163
|
-
|
|
164
|
+
T(i) !== r && R(this.api, i, r);
|
|
164
165
|
}
|
|
165
166
|
} catch {
|
|
166
167
|
}
|
|
@@ -176,6 +177,20 @@ class te extends S {
|
|
|
176
177
|
const t = this._getRecommendationId(e);
|
|
177
178
|
t && p().removeBlockState(t);
|
|
178
179
|
}
|
|
180
|
+
_ensureMobileFitRule(e) {
|
|
181
|
+
try {
|
|
182
|
+
w(this.api, e);
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
_syncHeightBound(e) {
|
|
187
|
+
const t = this._getBlockElement(e);
|
|
188
|
+
if (t)
|
|
189
|
+
try {
|
|
190
|
+
O(this.api, t);
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
}
|
|
179
194
|
/**
|
|
180
195
|
* Warns (dark advisory toaster) when the design holds more than one live
|
|
181
196
|
* recommendation block. Triggered from the user-add paths only (fresh drop
|
|
@@ -190,7 +205,7 @@ class te extends S {
|
|
|
190
205
|
*/
|
|
191
206
|
_warnIfMultipleBlocks() {
|
|
192
207
|
try {
|
|
193
|
-
|
|
208
|
+
F().warnIfMultipleBlocks(this.api.getDocumentRootHtmlNode());
|
|
194
209
|
} catch {
|
|
195
210
|
}
|
|
196
211
|
}
|
|
@@ -203,7 +218,7 @@ class te extends S {
|
|
|
203
218
|
const t = /* @__PURE__ */ new Set();
|
|
204
219
|
try {
|
|
205
220
|
const i = this.api.getDocumentRoot();
|
|
206
|
-
i && "querySelectorAll" in i && i.querySelectorAll(`.${
|
|
221
|
+
i && "querySelectorAll" in i && i.querySelectorAll(`.${h}`).forEach((s) => {
|
|
207
222
|
if ("getAttribute" in s) {
|
|
208
223
|
const n = s.getAttribute(f), o = n ? parseInt(n) : 0;
|
|
209
224
|
t.add(o), o > e && (e = o);
|
|
@@ -244,7 +259,7 @@ class te extends S {
|
|
|
244
259
|
}, 0));
|
|
245
260
|
}
|
|
246
261
|
_refreshArrivedBlocks(e) {
|
|
247
|
-
|
|
262
|
+
y(this.api);
|
|
248
263
|
const t = /* @__PURE__ */ new Set(), i = e.flatMap(({ node: r, id: s }) => {
|
|
249
264
|
const n = s ?? this._getRecommendationId(r), o = this._getBlockElement(r);
|
|
250
265
|
if (!n || !o || t.has(n))
|
|
@@ -252,8 +267,8 @@ class te extends S {
|
|
|
252
267
|
const l = a.getConfig(o);
|
|
253
268
|
if (!this._canClaimRefresh(n, l.strategyId))
|
|
254
269
|
return [];
|
|
255
|
-
const
|
|
256
|
-
return t.add(n), this._refreshClaims.set(n,
|
|
270
|
+
const d = { strategyId: l.strategyId };
|
|
271
|
+
return t.add(n), this._refreshClaims.set(n, d), [{ id: n, config: l, claim: d }];
|
|
257
272
|
});
|
|
258
273
|
i.length && q(i.map(({ id: r, config: s }) => ({ id: r, config: s }))).catch((r) => console.error("[recommendation] refreshing an arrived strategy failed", r)).finally(() => i.forEach(({ id: r, claim: s }) => this._releaseRefreshClaim(r, s)));
|
|
259
274
|
}
|
|
@@ -292,7 +307,7 @@ class te extends S {
|
|
|
292
307
|
if (!i || !("querySelectorAll" in i))
|
|
293
308
|
return;
|
|
294
309
|
const r = i.querySelectorAll(
|
|
295
|
-
`.${
|
|
310
|
+
`.${h}[${f}="${t}"]`
|
|
296
311
|
);
|
|
297
312
|
if (r.length <= 1)
|
|
298
313
|
return;
|
|
@@ -317,7 +332,7 @@ class te extends S {
|
|
|
317
332
|
const t = this.api.getDocumentRoot();
|
|
318
333
|
if (t && "querySelectorAll" in t)
|
|
319
334
|
return t.querySelectorAll(
|
|
320
|
-
`.${
|
|
335
|
+
`.${h}[${f}="${e}"]`
|
|
321
336
|
).length > 1;
|
|
322
337
|
} catch {
|
|
323
338
|
}
|
|
@@ -327,12 +342,12 @@ class te extends S {
|
|
|
327
342
|
_handleDuplicate(e, t) {
|
|
328
343
|
const i = this._reassignDuplicateId(e, t), r = p();
|
|
329
344
|
if (r.cloneBlockState(t, i), r.setCurrentBlock(i), g().isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
330
|
-
this._resetSourceIds.add(t),
|
|
345
|
+
this._resetSourceIds.add(t), y(this.api);
|
|
331
346
|
const s = a.getConfig(e), n = [
|
|
332
|
-
{ id: t, claim: { strategyId:
|
|
347
|
+
{ id: t, claim: { strategyId: L(t, s).strategyId } },
|
|
333
348
|
{ id: i, claim: { strategyId: s.strategyId } }
|
|
334
349
|
].filter(({ id: o }) => !this._refreshClaims.has(o));
|
|
335
|
-
n.forEach(({ id: o, claim: l }) => this._refreshClaims.set(o, l)),
|
|
350
|
+
n.forEach(({ id: o, claim: l }) => this._refreshClaims.set(o, l)), P(t, i, s).catch((o) => console.error("[recommendation] refreshing a duplicated strategy failed", o)).finally(() => n.forEach(({ id: o, claim: l }) => this._releaseRefreshClaim(o, l)));
|
|
336
351
|
}
|
|
337
352
|
this._warnIfMultipleBlocks();
|
|
338
353
|
}
|
|
@@ -422,10 +437,10 @@ class te extends S {
|
|
|
422
437
|
_getBlockElement(e) {
|
|
423
438
|
if ("getAttribute" in e) {
|
|
424
439
|
const t = e.getAttribute("class");
|
|
425
|
-
if (t && t.includes(
|
|
440
|
+
if (t && t.includes(h))
|
|
426
441
|
return e;
|
|
427
442
|
}
|
|
428
|
-
return "querySelector" in e ? e.querySelector(`.${
|
|
443
|
+
return "querySelector" in e ? e.querySelector(`.${h}`) ?? null : null;
|
|
429
444
|
}
|
|
430
445
|
/**
|
|
431
446
|
* Migrate configuration from legacy format
|
|
@@ -435,6 +450,6 @@ class te extends S {
|
|
|
435
450
|
}
|
|
436
451
|
}
|
|
437
452
|
export {
|
|
438
|
-
|
|
439
|
-
|
|
453
|
+
k as BLOCK_ID,
|
|
454
|
+
se as RecommendationBlock
|
|
440
455
|
};
|
|
@@ -1,19 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
t
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { EditorStatePropertyType as E, PreviewDeviceMode as I, ModificationDescription as h } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { createImageMarginsControl as M, createImageSizeControl as C } from "../../../controlFactories.js";
|
|
3
|
+
import { RecommendationBlockId as c } from "../../constants/blockIds.js";
|
|
4
|
+
import { RecommendationControlId as g } from "../../constants/controlIds.js";
|
|
5
|
+
import { BLOCK_ROOT_SELECTOR as l } from "../../constants/selectors.js";
|
|
6
|
+
import { hasGetStyle as a, hasGetAttribute as O } from "../../utils/tagName.js";
|
|
7
|
+
const R = { width: "", height: "auto", "max-height": "" }, f = `${l} img.adapt-img`, x = `*${l.slice(1)}`, p = `@media only screen and (max-width: 600px) { ${f} { max-height: none !important; } }`;
|
|
8
|
+
function _(t) {
|
|
9
|
+
return { width: "auto", height: "auto", "max-height": `${t}px` };
|
|
10
|
+
}
|
|
11
|
+
function A(t) {
|
|
12
|
+
return t.querySelectorAll(x).some((e) => "getSelector" in e && e.getSelector() === f);
|
|
13
|
+
}
|
|
14
|
+
function T(t, e) {
|
|
15
|
+
return a(t) && Object.entries(e).some(([o, n]) => (t.getStyle(o) ?? "") !== n);
|
|
16
|
+
}
|
|
17
|
+
function S(t) {
|
|
18
|
+
const e = t.getDocumentRootCssNode();
|
|
19
|
+
return e && !A(e) ? e : null;
|
|
20
|
+
}
|
|
21
|
+
function H(t, e) {
|
|
22
|
+
const n = e.querySelectorAll("img").some((r) => a(r) && !!r.getStyle("max-height")) ? S(t) : null;
|
|
23
|
+
if (!n)
|
|
24
|
+
return;
|
|
25
|
+
const i = t.getDocumentModifier();
|
|
26
|
+
i.modifyCss(n).appendRule(p), i.apply(new h("Add the reco image mobile fit rule"));
|
|
27
|
+
}
|
|
28
|
+
const B = `[esd-extension-block-id="${c.IMAGE}"]`, L = /^\d+px$/;
|
|
29
|
+
function y(t) {
|
|
30
|
+
return O(t) && Number(t.getAttribute("height")) || 0;
|
|
31
|
+
}
|
|
32
|
+
function b(t) {
|
|
33
|
+
const e = y(t), o = a(t) ? t.getStyle("max-height") ?? "" : "";
|
|
34
|
+
return L.test(o) && e > 0 && o !== `${e}px`;
|
|
35
|
+
}
|
|
36
|
+
function U(t, e) {
|
|
37
|
+
const o = e.querySelectorAll(B).map((i) => i.querySelector("img")).filter(b);
|
|
38
|
+
if (!o.length)
|
|
39
|
+
return;
|
|
40
|
+
const n = t.getDocumentModifier();
|
|
41
|
+
o.forEach((i) => n.modifyHtml(i).setStyle("max-height", `${y(i)}px`)), n.apply(new h("Sync the reco image height bound").asHidden());
|
|
42
|
+
}
|
|
43
|
+
class D extends C(
|
|
44
|
+
g.IMAGE_SIZE,
|
|
45
|
+
c.IMAGE,
|
|
46
|
+
l
|
|
47
|
+
) {
|
|
48
|
+
getAdditionalModifications(e) {
|
|
49
|
+
if (this.api.getEditorState()[E.previewDeviceMode] === I.MOBILE)
|
|
50
|
+
return;
|
|
51
|
+
const o = this.getFitStyles(), n = this.getTargetNodes(e).map((s) => s.querySelector("img")).filter((s) => T(s, o)), i = o["max-height"] ? S(this.api) : null;
|
|
52
|
+
if (!n.length && !i)
|
|
53
|
+
return;
|
|
54
|
+
const r = this.api.getDocumentModifier();
|
|
55
|
+
return i && r.modifyCss(i).appendRule(p), n.forEach((s) => {
|
|
56
|
+
const m = r.modifyHtml(s);
|
|
57
|
+
Object.entries(o).forEach(([u, d]) => {
|
|
58
|
+
d ? m.setStyle(u, d) : m.removeStyle(u);
|
|
59
|
+
});
|
|
60
|
+
}), r;
|
|
61
|
+
}
|
|
62
|
+
getFitStyles() {
|
|
63
|
+
const { size: e } = this.api.getValues();
|
|
64
|
+
return (e == null ? void 0 : e.type) === "height" && e.value ? _(e.value) : R;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const F = M(
|
|
68
|
+
g.IMAGE_MARGINS,
|
|
69
|
+
c.IMAGE,
|
|
70
|
+
l
|
|
71
|
+
), P = {
|
|
72
|
+
size: D,
|
|
73
|
+
margins: F
|
|
16
74
|
};
|
|
17
75
|
export {
|
|
18
|
-
|
|
76
|
+
P as ImageControls,
|
|
77
|
+
H as ensureMobileFitRule,
|
|
78
|
+
U as syncHeightBound
|
|
19
79
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { extractWrapperTags as A } from "../../../../utils/preserveTextStyles.js";
|
|
2
2
|
import { RecommendationBlockId as c } from "../constants/blockIds.js";
|
|
3
|
-
import { DESKTOP_CONTAINER_SELECTOR as
|
|
3
|
+
import { DESKTOP_CONTAINER_SELECTOR as g, ATTR_PRODUCT_NAME as k, ATTR_PRODUCT_PRICE as y, ATTR_PRODUCT_OLD_PRICE as p, ATTR_PRODUCT_OMNIBUS_PRICE as R, ATTR_PRODUCT_OMNIBUS_DISCOUNT as _, ATTR_PRODUCT_BUTTON as x, ATTR_PRODUCT_IMAGE as q, ATTR_PRODUCT_ATTR as v } from "../constants/selectors.js";
|
|
4
4
|
import { CSS_CLASS_TEXT_TRIM as B } from "../controls/shared/textTrimCssRules.js";
|
|
5
5
|
import { toCustomCompositionKey as U } from "../templates/utils.js";
|
|
6
6
|
import { resolveRowVisibilityKeys as N, isMergedInlinePriceRow as C } from "./compositionKeys.js";
|
|
7
|
-
import { hasQuerySelectorAll as I, hasGetAttribute as l, hasGetStyle as
|
|
7
|
+
import { hasQuerySelectorAll as I, hasGetAttribute as l, hasGetStyle as h, hasGetComputedStyle as M } from "./tagName.js";
|
|
8
8
|
const s = [
|
|
9
9
|
"font-size",
|
|
10
10
|
"font-family",
|
|
@@ -37,9 +37,10 @@ const s = [
|
|
|
37
37
|
"width",
|
|
38
38
|
"height",
|
|
39
39
|
"max-width",
|
|
40
|
+
"max-height",
|
|
40
41
|
"border-radius",
|
|
41
42
|
"margin"
|
|
42
|
-
],
|
|
43
|
+
], b = /* @__PURE__ */ new Set(["transparent", "rgba(0, 0, 0, 0)"]), L = [
|
|
43
44
|
{ attrKey: k, blockId: c.NAME, kind: "text" },
|
|
44
45
|
{ attrKey: y, blockId: c.PRICE, kind: "text" },
|
|
45
46
|
{ attrKey: p, blockId: c.OLD_PRICE, kind: "text" },
|
|
@@ -48,14 +49,14 @@ const s = [
|
|
|
48
49
|
{ attrKey: x, blockId: c.BUTTON, kind: "button" },
|
|
49
50
|
{ attrKey: q, blockId: c.IMAGE, kind: "image" }
|
|
50
51
|
];
|
|
51
|
-
function
|
|
52
|
+
function O(t) {
|
|
52
53
|
return t && "getInnerHTML" in t && typeof t.getInnerHTML == "function" ? t.getInnerHTML().trim() : "";
|
|
53
54
|
}
|
|
54
55
|
function K(t) {
|
|
55
56
|
return t && "getInnerText" in t && typeof t.getInnerText == "function" ? t.getInnerText().trim() : "";
|
|
56
57
|
}
|
|
57
58
|
function a(t, e, r) {
|
|
58
|
-
!e || !
|
|
59
|
+
!e || !h(e) || r.forEach((n) => {
|
|
59
60
|
const o = e.getStyle(n);
|
|
60
61
|
o && o !== "inherit" && o !== "initial" && (t[n] = o);
|
|
61
62
|
});
|
|
@@ -64,10 +65,10 @@ function E(t) {
|
|
|
64
65
|
return Object.entries(t).map(([e, r]) => `${e}: ${r};`).join(" ");
|
|
65
66
|
}
|
|
66
67
|
function P(t) {
|
|
67
|
-
if (!t || !
|
|
68
|
+
if (!t || !h(t))
|
|
68
69
|
return;
|
|
69
70
|
const e = t.getStyle("background-color") || t.getStyle("background");
|
|
70
|
-
return e && !
|
|
71
|
+
return e && !b.has(e) ? e : void 0;
|
|
71
72
|
}
|
|
72
73
|
function S(t, e) {
|
|
73
74
|
const r = {};
|
|
@@ -76,11 +77,11 @@ function S(t, e) {
|
|
|
76
77
|
function $(t) {
|
|
77
78
|
const e = t.querySelector("p"), r = {};
|
|
78
79
|
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 = E(r), { openTags: o, closeTags: i } = A(
|
|
80
|
+
const n = E(r), { openTags: o, closeTags: i } = A(O(e));
|
|
80
81
|
return !n && !o ? null : { pStyle: n || void 0, openTags: o, closeTags: i };
|
|
81
82
|
}
|
|
82
83
|
function H(t) {
|
|
83
|
-
const e = t.querySelector(".es-button-border"), r = t.querySelector("a.es-button") ?? t.querySelector("a"), n = S(e, D), o = S(r, w), i = e && "getAttribute" in e ? e.getAttribute("class") ?? "" : "", u = /\bes-fw\b/.test(i), { openTags: T, closeTags: d } = A(
|
|
84
|
+
const e = t.querySelector(".es-button-border"), r = t.querySelector("a.es-button") ?? t.querySelector("a"), n = S(e, D), o = S(r, w), i = e && "getAttribute" in e ? e.getAttribute("class") ?? "" : "", u = /\bes-fw\b/.test(i), { openTags: T, closeTags: d } = A(O(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,
|
|
@@ -100,7 +101,7 @@ function j(t, e) {
|
|
|
100
101
|
function f(t, e) {
|
|
101
102
|
if (!t || !("querySelector" in t))
|
|
102
103
|
return;
|
|
103
|
-
const r = t.querySelector(
|
|
104
|
+
const r = t.querySelector(g) ?? t;
|
|
104
105
|
if (L.forEach(({ attrKey: i, blockId: u, kind: T }) => {
|
|
105
106
|
const d = r.querySelector(`[esd-extension-block-id="${u}"]`);
|
|
106
107
|
d && e(d, i, T);
|
|
@@ -126,20 +127,20 @@ function V(t) {
|
|
|
126
127
|
function X(t) {
|
|
127
128
|
if (!t || !("querySelector" in t))
|
|
128
129
|
return;
|
|
129
|
-
const e = t.querySelector(
|
|
130
|
+
const e = t.querySelector(g) ?? t, r = e.querySelector(".product-card-segment") ?? e.querySelector(".product-card-wrapper");
|
|
130
131
|
return P(r);
|
|
131
132
|
}
|
|
132
133
|
function z(t) {
|
|
133
134
|
if (!t)
|
|
134
135
|
return;
|
|
135
136
|
const e = l(t) ? t.getAttribute("bgcolor") : null;
|
|
136
|
-
if (e && !
|
|
137
|
+
if (e && !b.has(e))
|
|
137
138
|
return e;
|
|
138
139
|
const r = P(t);
|
|
139
140
|
if (r)
|
|
140
141
|
return r;
|
|
141
142
|
const n = M(t) ? t.getComputedStyle("background-color") : void 0;
|
|
142
|
-
return n && !
|
|
143
|
+
return n && !b.has(n) ? n : void 0;
|
|
143
144
|
}
|
|
144
145
|
function Q(t) {
|
|
145
146
|
const e = {};
|
|
@@ -170,7 +171,7 @@ function J(t) {
|
|
|
170
171
|
function Z(t) {
|
|
171
172
|
if (!t || !("querySelector" in t))
|
|
172
173
|
return !1;
|
|
173
|
-
const e = t.querySelector(
|
|
174
|
+
const e = t.querySelector(g) ?? t;
|
|
174
175
|
return C(e.querySelector(`[data-attribute-type="${y}"]`)) || C(e.querySelector(`[data-attribute-type="${p}"]`));
|
|
175
176
|
}
|
|
176
177
|
function tt(t) {
|
|
@@ -195,7 +196,7 @@ function rt(t) {
|
|
|
195
196
|
const e = {};
|
|
196
197
|
if (!t || !("querySelector" in t))
|
|
197
198
|
return e;
|
|
198
|
-
const r = t.querySelector(
|
|
199
|
+
const r = t.querySelector(g) ?? t;
|
|
199
200
|
return I(r) && r.querySelectorAll(".recommendation-attribute-row").forEach((n) => {
|
|
200
201
|
if (!l(n))
|
|
201
202
|
return;
|
|
@@ -64,6 +64,8 @@ export declare class RecommendationBlock extends Block {
|
|
|
64
64
|
* @param node - The block node being deleted
|
|
65
65
|
*/
|
|
66
66
|
onDelete(node: ImmutableHtmlNode): void;
|
|
67
|
+
private _ensureMobileFitRule;
|
|
68
|
+
private _syncHeightBound;
|
|
67
69
|
/**
|
|
68
70
|
* Warns (dark advisory toaster) when the design holds more than one live
|
|
69
71
|
* recommendation block. Triggered from the user-add paths only (fresh drop
|
|
@@ -3,35 +3,49 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Controls for styling the product image element in recommendation cards.
|
|
5
5
|
*/
|
|
6
|
+
import type { CssNodeModifier, HtmlNodeModifier, ImmutableCssNode, ImmutableHtmlNode, TemplateModifier } from '@stripoinc/ui-editor-extensions';
|
|
7
|
+
import { ModificationDescription } from '@stripoinc/ui-editor-extensions';
|
|
8
|
+
interface FitRuleApi {
|
|
9
|
+
getDocumentRootCssNode: () => ImmutableCssNode | null;
|
|
10
|
+
getDocumentModifier: () => TemplateModifier<HtmlNodeModifier, CssNodeModifier>;
|
|
11
|
+
}
|
|
12
|
+
export declare function ensureMobileFitRule(api: FitRuleApi, block: ImmutableHtmlNode): void;
|
|
13
|
+
export declare function syncHeightBound(api: Pick<FitRuleApi, 'getDocumentModifier'>, block: ImmutableHtmlNode): void;
|
|
14
|
+
declare const SizeControl_base: {
|
|
15
|
+
new (): {
|
|
16
|
+
getId(): string;
|
|
17
|
+
getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
|
|
18
|
+
getParentControlId(): string;
|
|
19
|
+
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
20
|
+
getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
|
|
21
|
+
getModificationDescription(): ModificationDescription | undefined;
|
|
22
|
+
getAdditionalModifications(_root: ImmutableHtmlNode): TemplateModifier<HtmlNodeModifier, CssNodeModifier> | undefined;
|
|
23
|
+
isVisible(_node: ImmutableHtmlNode): boolean;
|
|
24
|
+
getElementLockCategory(): import("@stripoinc/ui-editor-extensions").ElementLockCategory | undefined;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
declare class SizeControl extends SizeControl_base {
|
|
28
|
+
getAdditionalModifications(root: ImmutableHtmlNode): TemplateModifier<HtmlNodeModifier, CssNodeModifier> | undefined;
|
|
29
|
+
private getFitStyles;
|
|
30
|
+
}
|
|
6
31
|
/**
|
|
7
32
|
* Grouped Image Controls
|
|
8
33
|
* Use this object for cleaner imports in extension.ts
|
|
9
34
|
*/
|
|
10
35
|
export declare const ImageControls: {
|
|
11
|
-
readonly size:
|
|
12
|
-
new (): {
|
|
13
|
-
getId(): string;
|
|
14
|
-
getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
|
|
15
|
-
getParentControlId(): string;
|
|
16
|
-
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
17
|
-
getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
|
|
18
|
-
getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
|
|
19
|
-
getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
|
|
20
|
-
isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
|
|
21
|
-
getElementLockCategory(): import("@stripoinc/ui-editor-extensions").ElementLockCategory | undefined;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
36
|
+
readonly size: typeof SizeControl;
|
|
24
37
|
readonly margins: {
|
|
25
38
|
new (): {
|
|
26
39
|
getId(): string;
|
|
27
|
-
getTargetNodes(root:
|
|
40
|
+
getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
|
|
28
41
|
getParentControlId(): string;
|
|
29
42
|
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
30
43
|
getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
|
|
31
|
-
getModificationDescription():
|
|
32
|
-
getAdditionalModifications(_root:
|
|
33
|
-
isVisible(_node:
|
|
44
|
+
getModificationDescription(): ModificationDescription | undefined;
|
|
45
|
+
getAdditionalModifications(_root: ImmutableHtmlNode): TemplateModifier<HtmlNodeModifier, CssNodeModifier> | undefined;
|
|
46
|
+
isVisible(_node: ImmutableHtmlNode): boolean;
|
|
34
47
|
getElementLockCategory(): import("@stripoinc/ui-editor-extensions").ElementLockCategory | undefined;
|
|
35
48
|
};
|
|
36
49
|
};
|
|
37
50
|
};
|
|
51
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.21.
|
|
3
|
+
"version": "3.21.2",
|
|
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",
|