@useinsider/guido 3.14.1-beta.9ad6513 → 3.15.0-beta.166619d
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/useEmailTemplateApplier.js +46 -32
- package/dist/composables/useHtmlValidator.js +111 -106
- package/dist/extensions/Blocks/Recommendation/controls/cardBackground/index.js +5 -9
- package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +98 -113
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +21 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +5 -0
- package/dist/src/stores/dynamic-content.d.ts +8 -0
- package/dist/src/utils/registerUsedDynamicContent.d.ts +8 -0
- package/dist/stores/dynamic-content.js +12 -2
- package/dist/utils/registerUsedDynamicContent.js +23 -0
- package/package.json +1 -1
|
@@ -1,43 +1,57 @@
|
|
|
1
|
-
import { useActionsApi as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { useActionsApi as d } from "./useActionsApi.js";
|
|
2
|
+
import { useConfig as D } from "./useConfig.js";
|
|
3
|
+
import { useToaster as h } from "./useToaster.js";
|
|
4
|
+
import { useTranslations as E } from "./useTranslations.js";
|
|
5
|
+
import { ToasterTypeOptions as f } from "../enums/toaster.js";
|
|
6
|
+
import { useDynamicContentStore as A } from "../stores/dynamic-content.js";
|
|
7
|
+
import { flattenDynamicContentList as S } from "../utils/genericUtil.js";
|
|
8
|
+
import { extractUsedDynamicContent as O } from "../utils/registerUsedDynamicContent.js";
|
|
9
|
+
import { ref as U } from "vue";
|
|
10
|
+
const w = 250, o = U({}), s = {}, u = /* @__PURE__ */ new Map(), z = () => {
|
|
11
|
+
const { updateHtmlAndCss: c } = d(), { showToaster: m } = h(), y = E(), { template: T } = D(), v = A(), g = (e, t) => {
|
|
12
|
+
const a = y(e);
|
|
13
|
+
return a === e ? t : a;
|
|
14
|
+
}, C = (e) => {
|
|
15
|
+
o.value[e] === void 0 && (o.value = { ...o.value, [e]: "pending" });
|
|
16
|
+
}, l = (e, t, a) => {
|
|
17
|
+
var n;
|
|
18
|
+
o.value = { ...o.value, [e]: "applying" };
|
|
11
19
|
try {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
c(t, a), o.value = { ...o.value, [e]: "applied" };
|
|
21
|
+
try {
|
|
22
|
+
const r = S((n = T.value) == null ? void 0 : n.dynamicContentList), p = O(t, r);
|
|
23
|
+
p.length > 0 && v.registerDynamicContent(p);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
u.get(e) !== t && (u.set(e, t), m({
|
|
27
|
+
type: f.Success,
|
|
28
|
+
message: g("newsletter.ai-template-applied", "Template applied to the editor")
|
|
29
|
+
}));
|
|
30
|
+
} catch (r) {
|
|
31
|
+
o.value = { ...o.value, [e]: "failed" }, m({
|
|
32
|
+
type: f.Error,
|
|
33
|
+
message: r instanceof Error ? r.message : "Failed to apply template"
|
|
20
34
|
});
|
|
21
35
|
}
|
|
22
|
-
},
|
|
23
|
-
const t =
|
|
24
|
-
t && (clearTimeout(t), delete
|
|
36
|
+
}, i = (e) => {
|
|
37
|
+
const t = s[e];
|
|
38
|
+
t && (clearTimeout(t), delete s[e]);
|
|
25
39
|
};
|
|
26
|
-
return { applyStatus:
|
|
27
|
-
t.html && (
|
|
40
|
+
return { applyStatus: o, markPending: C, applyTemplate: (e, t) => {
|
|
41
|
+
t.html && (i(e), l(e, t.html, t.css ?? ""));
|
|
28
42
|
}, applyTemplateDebounced: (e, t) => {
|
|
29
43
|
if (!t.html)
|
|
30
44
|
return;
|
|
31
|
-
|
|
32
|
-
const { html:
|
|
33
|
-
|
|
34
|
-
delete
|
|
35
|
-
},
|
|
45
|
+
i(e);
|
|
46
|
+
const { html: a } = t, n = t.css ?? "";
|
|
47
|
+
s[e] = setTimeout(() => {
|
|
48
|
+
delete s[e], l(e, a, n);
|
|
49
|
+
}, w);
|
|
36
50
|
} };
|
|
37
|
-
},
|
|
38
|
-
Object.values(
|
|
51
|
+
}, G = () => {
|
|
52
|
+
Object.values(s).forEach(clearTimeout), Object.keys(s).forEach((c) => delete s[c]), o.value = {};
|
|
39
53
|
};
|
|
40
54
|
export {
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
G as resetEmailTemplateApplier,
|
|
56
|
+
z as useEmailTemplateApplier
|
|
43
57
|
};
|
|
@@ -1,64 +1,69 @@
|
|
|
1
|
-
import { useConfig as
|
|
2
|
-
import { getIgnoredRecommendationBlockIds as
|
|
3
|
-
import { TemplateTypes as
|
|
4
|
-
import { DISPLAY_CONDITIONS_REGEX as
|
|
1
|
+
import { useConfig as V } from "./useConfig.js";
|
|
2
|
+
import { getIgnoredRecommendationBlockIds as M } from "../config/compiler/utils/recommendationIgnoreUtils.js";
|
|
3
|
+
import { TemplateTypes as W } from "../enums/defaults.js";
|
|
4
|
+
import { DISPLAY_CONDITIONS_REGEX as G, DISPLAY_CONDITIONS_EXCEPTIONS_REGEX as H, CampaignCouldNotBeSavedKey as P, CanNotMakeAnyChangesForRunningKey as X, DATA_ATTRIBUTE_REGEX as $, DYNAMIC_CONTENT_TAG_REGEX as Y, ALLOWED_DYNAMIC_SYSTEM_TOKENS as U, VALID_DYNAMIC_VARIABLE_REGEX as j } from "../enums/html-validator.js";
|
|
5
5
|
import { ToasterTypeOptions as c } from "../enums/toaster.js";
|
|
6
|
-
import { itemsBlockDynamicVariables as
|
|
7
|
-
import { RECOMMENDATION_VARIABLE_BUILTIN_ATTRIBUTES as
|
|
8
|
-
import { useRecommendationExtensionStore as
|
|
9
|
-
import { resolveProductAttrValue as
|
|
10
|
-
import { RecommendationRequiredFieldsKey as
|
|
11
|
-
import { useRecommendationStore as
|
|
12
|
-
import { base64EncodeWithSpecialChars as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
import { itemsBlockDynamicVariables as q } from "../extensions/Blocks/Items/enums/productEnums.js";
|
|
7
|
+
import { RECOMMENDATION_VARIABLE_BUILTIN_ATTRIBUTES as K } from "../extensions/Blocks/Recommendation/constants/selectors.js";
|
|
8
|
+
import { useRecommendationExtensionStore as z } from "../extensions/Blocks/Recommendation/store/recommendation.js";
|
|
9
|
+
import { resolveProductAttrValue as Z } from "../extensions/Blocks/Recommendation/templates/utils.js";
|
|
10
|
+
import { RecommendationRequiredFieldsKey as J } from "../extensions/Blocks/Recommendation/validation/requiredFields.js";
|
|
11
|
+
import { useRecommendationStore as Q } from "../stores/recommendation.js";
|
|
12
|
+
import { base64EncodeWithSpecialChars as ee } from "../utils/base64.js";
|
|
13
|
+
import { computed as te } from "vue";
|
|
14
|
+
import { useHttp as ne } from "./useHttp.js";
|
|
15
|
+
import { useToaster as se } from "./useToaster.js";
|
|
16
|
+
import { useTranslations as re } from "./useTranslations.js";
|
|
17
|
+
const oe = /recommendation-id="(\d+)"/g;
|
|
18
|
+
function ie(n) {
|
|
19
|
+
return [...n.matchAll(oe)].map((m) => m[1]);
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
-
return m.some((f) =>
|
|
21
|
+
function ae(n, m) {
|
|
22
|
+
return m.some((f) => n.startsWith(`${f}_`));
|
|
22
23
|
}
|
|
23
|
-
const
|
|
24
|
-
function
|
|
25
|
-
const m =
|
|
24
|
+
const ce = /^(\d+)_\d+_(.+)$/;
|
|
25
|
+
function le(n) {
|
|
26
|
+
const m = n.match(ce);
|
|
26
27
|
return m ? { recoId: m[1], attribute: m[2] } : null;
|
|
27
28
|
}
|
|
28
|
-
function
|
|
29
|
-
const m = new Set(
|
|
30
|
-
return Object.values(
|
|
31
|
-
m.add(
|
|
29
|
+
function me(n) {
|
|
30
|
+
const m = new Set(K);
|
|
31
|
+
return Object.values(n).forEach((f) => {
|
|
32
|
+
m.add(Z(f.attributeName, n).toLowerCase());
|
|
32
33
|
}), m;
|
|
33
34
|
}
|
|
34
|
-
function
|
|
35
|
-
const u =
|
|
35
|
+
function ue(n, m, f, o, d) {
|
|
36
|
+
const u = n.match(/{{([a-zA-Z0-9_.\s]*)}}/gm);
|
|
36
37
|
if (!u)
|
|
37
38
|
return [];
|
|
38
|
-
const
|
|
39
|
+
const g = new Set(m.map((h) => h.toLowerCase())), E = [];
|
|
39
40
|
return u.forEach((h) => {
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
41
|
+
const p = h.slice(2, -2).trim().toLowerCase();
|
|
42
|
+
if (p !== "" && g.has(p))
|
|
42
43
|
return;
|
|
43
|
-
const y =
|
|
44
|
+
const y = le(p);
|
|
44
45
|
if (y && o.has(y.recoId)) {
|
|
45
46
|
if (!d || d.has(y.attribute))
|
|
46
47
|
return;
|
|
47
|
-
E.push(
|
|
48
|
+
E.push(p);
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
ae(p, f) || p.includes(".") || E.push(p);
|
|
51
52
|
}), E;
|
|
52
53
|
}
|
|
53
|
-
function
|
|
54
|
-
return (
|
|
55
|
-
const d = o.slice(2, -2), u = d.indexOf("|"),
|
|
56
|
-
return
|
|
54
|
+
function de(n) {
|
|
55
|
+
return (n.replace($, "$1").match(Y) ?? []).filter((o) => {
|
|
56
|
+
const d = o.slice(2, -2), u = d.indexOf("|"), g = (u === -1 ? d : d.slice(0, u)).trim();
|
|
57
|
+
return U.includes(g) ? !1 : j.test(g) ? u !== -1 && d.slice(u + 1).trim() === "" : !0;
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
const xe = () => {
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
const { showToaster: n } = se(), { post: m } = ne(), { config: f } = V(), o = re(), d = Q(), u = z(), g = te(
|
|
62
|
+
() => {
|
|
63
|
+
var e, t;
|
|
64
|
+
return ((t = (e = f.value) == null ? void 0 : e.partner) == null ? void 0 : t.messageType) === W.transactional;
|
|
65
|
+
}
|
|
66
|
+
), E = async (e) => {
|
|
62
67
|
if (e.size === 0)
|
|
63
68
|
return /* @__PURE__ */ new Set();
|
|
64
69
|
try {
|
|
@@ -66,61 +71,61 @@ const xe = () => {
|
|
|
66
71
|
} catch {
|
|
67
72
|
return null;
|
|
68
73
|
}
|
|
69
|
-
return
|
|
74
|
+
return me(u.filterList);
|
|
70
75
|
}, h = async (e) => {
|
|
71
|
-
const
|
|
76
|
+
const s = await m(
|
|
72
77
|
"/newsletter/template-library/check-template-html-body",
|
|
73
|
-
{ html:
|
|
74
|
-
), { status: r, message: a } =
|
|
75
|
-
return r ||
|
|
78
|
+
{ html: ee(e) }
|
|
79
|
+
), { status: r, message: a } = s.data;
|
|
80
|
+
return r || n({
|
|
76
81
|
type: c.Error,
|
|
77
82
|
message: r === void 0 ? a : o("newsletter.invalid-url-link-for-toaster")
|
|
78
|
-
}), o(
|
|
83
|
+
}), o(P), a === o(X) && n({
|
|
79
84
|
type: c.Error,
|
|
80
85
|
message: o("newsletter.already-in-progress")
|
|
81
86
|
}), r;
|
|
82
|
-
},
|
|
83
|
-
const
|
|
87
|
+
}, p = (e) => !["if", "endif", "else", "elif", "now"].includes(e.toLowerCase()), y = (e) => ["if", "endif"].includes(e.toLowerCase()), S = (e, t) => {
|
|
88
|
+
const s = e.match(/({%(.*?)%})/g);
|
|
84
89
|
let r = !0;
|
|
85
|
-
return
|
|
90
|
+
return s !== null && !g.value && s.forEach((a) => {
|
|
86
91
|
const i = a.slice(2, -2).trim().match(/(".*?"|[^"\s]+)(?=\s*|\s*$)/g);
|
|
87
92
|
if (i && i.length > 0) {
|
|
88
93
|
const [l] = i;
|
|
89
|
-
|
|
94
|
+
p(l) && !t.includes(l) && (n({
|
|
90
95
|
type: c.Warning,
|
|
91
96
|
message: o("custom-fields.invalid-custom-fields")
|
|
92
97
|
}), r = !1);
|
|
93
98
|
}
|
|
94
99
|
}), r;
|
|
95
|
-
},
|
|
96
|
-
const r =
|
|
97
|
-
return
|
|
98
|
-
},
|
|
100
|
+
}, A = async (e, t, s) => {
|
|
101
|
+
const r = s ? await h(e) : !0;
|
|
102
|
+
return S(e, t) && r;
|
|
103
|
+
}, T = (e) => e.length > 0 ? !0 : (n({
|
|
99
104
|
type: c.Warning,
|
|
100
105
|
message: o("newsletter.html-content-is-empty")
|
|
101
|
-
}), !1),
|
|
102
|
-
const
|
|
103
|
-
return
|
|
106
|
+
}), !1), w = (e) => {
|
|
107
|
+
const t = (e.match(/{/gm) || []).length, s = (e.match(/}/gm) || []).length;
|
|
108
|
+
return t > s && n({
|
|
104
109
|
type: c.Warning,
|
|
105
110
|
message: o("custom-fields.missing-closing-braces")
|
|
106
|
-
}),
|
|
111
|
+
}), t < s && n({
|
|
107
112
|
type: c.Warning,
|
|
108
113
|
message: o("custom-fields.missing-opening-braces")
|
|
109
|
-
}),
|
|
110
|
-
},
|
|
111
|
-
const
|
|
112
|
-
return
|
|
114
|
+
}), t === s;
|
|
115
|
+
}, R = (e) => {
|
|
116
|
+
const t = de(e).length === 0;
|
|
117
|
+
return t || n({
|
|
113
118
|
type: c.Warning,
|
|
114
119
|
message: o("custom-fields.invalid-custom-fields")
|
|
115
|
-
}),
|
|
116
|
-
},
|
|
117
|
-
if (
|
|
120
|
+
}), t;
|
|
121
|
+
}, _ = (e, t, s, r) => {
|
|
122
|
+
if (g.value)
|
|
118
123
|
return !0;
|
|
119
|
-
const a =
|
|
124
|
+
const a = ue(
|
|
120
125
|
e,
|
|
126
|
+
t,
|
|
127
|
+
ie(e),
|
|
121
128
|
s,
|
|
122
|
-
ae(e),
|
|
123
|
-
n,
|
|
124
129
|
r
|
|
125
130
|
);
|
|
126
131
|
if (a.length > 0) {
|
|
@@ -129,91 +134,91 @@ const xe = () => {
|
|
|
129
134
|
${a.map((l) => `<li>${l}</li>`).join("")}
|
|
130
135
|
</ul>
|
|
131
136
|
`;
|
|
132
|
-
return
|
|
137
|
+
return n({
|
|
133
138
|
type: c.Error,
|
|
134
139
|
message: o("custom-fields.invalid-custom-fields") + i
|
|
135
140
|
}), !1;
|
|
136
141
|
}
|
|
137
142
|
return !0;
|
|
138
|
-
},
|
|
139
|
-
const
|
|
143
|
+
}, N = (e) => {
|
|
144
|
+
const t = e.match(/{%(.*?)%}/g), s = [];
|
|
140
145
|
let r = !0;
|
|
141
|
-
if (
|
|
142
|
-
const i = a.match(
|
|
143
|
-
(!i || a !==
|
|
146
|
+
if (t && t.forEach((a) => {
|
|
147
|
+
const i = a.match(G), l = a.match(H), C = (i == null ? void 0 : i.join("")) || "";
|
|
148
|
+
(!i || a !== C) && !l && (n({
|
|
144
149
|
type: c.Error,
|
|
145
150
|
message: o("newsletter.display-conditions-invalid-syntax")
|
|
146
|
-
}), r = !1), i && i.forEach((
|
|
147
|
-
|
|
151
|
+
}), r = !1), i && i.forEach((v) => {
|
|
152
|
+
v.trim() === "=" && (n({
|
|
148
153
|
type: c.Error,
|
|
149
154
|
message: o("custom-conditions.wrong-equality-operators")
|
|
150
155
|
}), r = !1);
|
|
151
|
-
const I =
|
|
152
|
-
I && I.forEach((
|
|
153
|
-
y(
|
|
156
|
+
const I = v.match(/^[a-zA-Z]*$/g);
|
|
157
|
+
I && I.forEach((b) => {
|
|
158
|
+
y(b) && s.push(b);
|
|
154
159
|
});
|
|
155
160
|
});
|
|
156
|
-
}),
|
|
157
|
-
const a =
|
|
158
|
-
a.length !== i.length && (
|
|
161
|
+
}), s.length) {
|
|
162
|
+
const a = s.filter((l) => l === "if"), i = s.filter((l) => l === "endif");
|
|
163
|
+
a.length !== i.length && (n({
|
|
159
164
|
type: c.Error,
|
|
160
165
|
message: o("custom-conditions.missing-if-endif-tag")
|
|
161
166
|
}), r = !1);
|
|
162
167
|
}
|
|
163
168
|
return r;
|
|
164
|
-
},
|
|
165
|
-
const
|
|
166
|
-
return r ||
|
|
169
|
+
}, x = (e) => {
|
|
170
|
+
const t = (e.match(/{% /gm) || []).length, s = (e.match(/ %}/gm) || []).length, r = t === s;
|
|
171
|
+
return r || n({
|
|
167
172
|
type: c.Warning,
|
|
168
173
|
message: o("custom-conditions.no-space-after-braces")
|
|
169
174
|
}), r;
|
|
170
|
-
},
|
|
175
|
+
}, O = (e) => (e.match(/({%(.*?)%})/g) || []).filter((s) => s.includes("if")).map((s) => (s.match(/{{.*}}/gm) || []).length).reduce((s, r) => s + r, 0) > 0 ? (n({
|
|
171
176
|
type: c.Warning,
|
|
172
177
|
message: o("custom-conditions.no-braces-inside-if-tag")
|
|
173
|
-
}), !1) : !0,
|
|
178
|
+
}), !1) : !0, k = () => u.hasInvalidBlock() ? (n({
|
|
174
179
|
type: c.Error,
|
|
175
|
-
message: o(
|
|
176
|
-
}), !1) : !0,
|
|
180
|
+
message: o(J)
|
|
181
|
+
}), !1) : !0, B = () => d.recommendationConfigs && Object.values(d.recommendationConfigs).find((t) => t.filters.find((s) => s.value === "")) !== void 0 ? (n({
|
|
177
182
|
type: c.Error,
|
|
178
183
|
message: o("newsletter.fill-all-necessary-fields")
|
|
179
|
-
}), !1) : !0,
|
|
180
|
-
const
|
|
181
|
-
return e.match(
|
|
184
|
+
}), !1) : !0, D = (e) => {
|
|
185
|
+
const t = /src="[^"]*\.(svg|pst)"/gm;
|
|
186
|
+
return e.match(t) === null ? !0 : (n({
|
|
182
187
|
type: c.Error,
|
|
183
188
|
message: o("newsletter.invalid-image-type")
|
|
184
189
|
}), !1);
|
|
185
|
-
},
|
|
190
|
+
}, F = (e) => {
|
|
186
191
|
const r = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".checkbox-block-v2");
|
|
187
192
|
return Array.from(r).find((i) => {
|
|
188
193
|
var l;
|
|
189
194
|
return !((l = i.id) != null && l.trim());
|
|
190
|
-
}) ? (
|
|
195
|
+
}) ? (n({
|
|
191
196
|
type: c.Error,
|
|
192
197
|
message: o("unsubscribe-templates.select-checkbox-groups")
|
|
193
198
|
}), !1) : !0;
|
|
194
|
-
},
|
|
199
|
+
}, L = (e) => {
|
|
195
200
|
const r = new DOMParser().parseFromString(e, "text/html").querySelectorAll(".radio-button-v2");
|
|
196
201
|
return Array.from(r).find((i) => {
|
|
197
202
|
var l;
|
|
198
203
|
return !((l = i.id) != null && l.trim());
|
|
199
|
-
}) ? (
|
|
204
|
+
}) ? (n({
|
|
200
205
|
type: c.Error,
|
|
201
206
|
message: o("unsubscribe-templates.select-radio-button-groups")
|
|
202
207
|
}), !1) : !0;
|
|
203
208
|
};
|
|
204
|
-
return { validateHtml: async (e,
|
|
205
|
-
var
|
|
209
|
+
return { validateHtml: async (e, t, s = !1) => {
|
|
210
|
+
var C, v;
|
|
206
211
|
const r = [
|
|
207
|
-
...
|
|
208
|
-
...
|
|
209
|
-
...((
|
|
210
|
-
], a =
|
|
211
|
-
return await
|
|
212
|
+
...t.map((I) => I.value),
|
|
213
|
+
...q,
|
|
214
|
+
...((v = (C = f.value) == null ? void 0 : C.template) == null ? void 0 : v.customFieldAttributes) ?? []
|
|
215
|
+
], a = M(e), i = await E(a);
|
|
216
|
+
return await A(e, r, s) && T(e) && w(e) && R(e) && _(e, r, a, i) && N(e) && x(e) && O(e) && k() && B() && D(e) && F(e) && L(e);
|
|
212
217
|
} };
|
|
213
218
|
};
|
|
214
219
|
export {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
220
|
+
me as buildPartnerAttributeNameSet,
|
|
221
|
+
ue as findInvalidCustomFields,
|
|
222
|
+
le as parseRecommendationVariable,
|
|
218
223
|
xe as useHtmlValidator
|
|
219
224
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ModificationDescription as d } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
2
|
import { CommonControl as s } from "../../../common-control.js";
|
|
3
3
|
import { getCurrentLayout as l } from "../main/utils.js";
|
|
4
|
-
const
|
|
4
|
+
const u = "recommendation-card-background-color-control", e = {
|
|
5
5
|
CARD_BACKGROUND_COLOR: "cardBackgroundColor"
|
|
6
6
|
}, a = {
|
|
7
7
|
GRID: ".product-card-segment",
|
|
@@ -9,17 +9,13 @@ const i = "recommendation-card-background-color-control", e = {
|
|
|
9
9
|
};
|
|
10
10
|
class _ extends s {
|
|
11
11
|
getId() {
|
|
12
|
-
return
|
|
12
|
+
return u;
|
|
13
13
|
}
|
|
14
14
|
getTemplate() {
|
|
15
|
-
return
|
|
16
|
-
<div class="card-bg-control-container">
|
|
17
|
-
${this._GuTwoColumns([
|
|
15
|
+
return this._GuTwoColumns([
|
|
18
16
|
this._GuLabel({ text: this.api.translate("Card Background Color") }),
|
|
19
17
|
this._GuColorPicker(e.CARD_BACKGROUND_COLOR)
|
|
20
|
-
])
|
|
21
|
-
</div>
|
|
22
|
-
`;
|
|
18
|
+
]);
|
|
23
19
|
}
|
|
24
20
|
onRender() {
|
|
25
21
|
this._setFormValues(), this._listenToFormUpdates();
|
|
@@ -75,6 +71,6 @@ class _ extends s {
|
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
73
|
export {
|
|
78
|
-
|
|
74
|
+
u as CARD_BACKGROUND_COLOR_CONTROL_ID,
|
|
79
75
|
_ as CardBackgroundColorControl
|
|
80
76
|
};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { ModificationDescription as
|
|
5
|
-
import { CommonControl as
|
|
6
|
-
import { DESKTOP_CONTAINER_SELECTOR as
|
|
7
|
-
import { SPACING_STEP as
|
|
1
|
+
var y = Object.defineProperty;
|
|
2
|
+
var M = (u, s, t) => s in u ? y(u, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : u[s] = t;
|
|
3
|
+
var g = (u, s, t) => M(u, typeof s != "symbol" ? s + "" : s, t);
|
|
4
|
+
import { ModificationDescription as S } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
5
|
+
import { CommonControl as E } from "../../../common-control.js";
|
|
6
|
+
import { DESKTOP_CONTAINER_SELECTOR as m, MOBILE_CONTAINER_SELECTOR as L } from "../../constants/selectors.js";
|
|
7
|
+
import { SPACING_STEP as P, MAX_SPACING as G, MIN_SPACING as R, DEFAULT_COLUMN_SPACING as C, DEFAULT_ROW_SPACING as I } from "../../constants/layout.js";
|
|
8
8
|
import { RecommendationConfigService as p } from "../../services/configService.js";
|
|
9
9
|
import { useRecommendationExtensionStore as w } from "../../store/recommendation.js";
|
|
10
|
-
import { safeGetStyle as
|
|
11
|
-
import { getCurrentLayout as
|
|
12
|
-
import { useDebounceFn as
|
|
13
|
-
const
|
|
10
|
+
import { safeGetStyle as f, safeGetParent as B } from "../../utils/tagName.js";
|
|
11
|
+
import { getCurrentLayout as _, getBlockElement as U } from "../main/utils.js";
|
|
12
|
+
import { useDebounceFn as N } from "../../../../../node_modules/@vueuse/shared/index.js";
|
|
13
|
+
const V = "recommendation-spacing-control", o = {
|
|
14
14
|
COLUMN_SPACING: "columnSpacing",
|
|
15
15
|
COLUMN_SPACING_LABEL: "columnSpacingLabel",
|
|
16
16
|
ROW_SPACING: "rowSpacing",
|
|
@@ -19,97 +19,67 @@ const U = "recommendation-spacing-control", n = {
|
|
|
19
19
|
MOBILE_COLUMN_SPACING_LABEL: "mobileColumnSpacingLabel",
|
|
20
20
|
MOBILE_ROW_SPACING: "mobileRowSpacing",
|
|
21
21
|
MOBILE_ROW_SPACING_LABEL: "mobileRowSpacingLabel"
|
|
22
|
-
},
|
|
22
|
+
}, b = {
|
|
23
23
|
COLUMN_SPACING: "data-column-spacing",
|
|
24
24
|
ROW_SPACING: "data-row-spacing",
|
|
25
25
|
MOBILE_COLUMN_SPACING: "data-mobile-column-spacing",
|
|
26
26
|
MOBILE_ROW_SPACING: "data-mobile-row-spacing"
|
|
27
27
|
};
|
|
28
|
-
function
|
|
28
|
+
function O(u, s) {
|
|
29
29
|
if (!u)
|
|
30
30
|
return s;
|
|
31
31
|
const t = parseFloat(u);
|
|
32
32
|
return Number.isNaN(t) ? s : t;
|
|
33
33
|
}
|
|
34
|
-
class j extends
|
|
34
|
+
class j extends E {
|
|
35
35
|
constructor() {
|
|
36
36
|
super(...arguments);
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
g(this, "store", w());
|
|
38
|
+
g(this, "unsubscribeOrientation", null);
|
|
39
39
|
/**
|
|
40
40
|
* Debounced version of _onColumnSpacingChange
|
|
41
41
|
* Prevents excessive DOM updates when user rapidly adjusts the counter
|
|
42
42
|
*/
|
|
43
|
-
|
|
43
|
+
g(this, "_debouncedOnColumnSpacingChange", N((t) => {
|
|
44
44
|
this._onColumnSpacingChange(t);
|
|
45
45
|
}, 300));
|
|
46
46
|
/**
|
|
47
47
|
* Debounced version of _onRowSpacingChange
|
|
48
48
|
*/
|
|
49
|
-
|
|
49
|
+
g(this, "_debouncedOnRowSpacingChange", N((t) => {
|
|
50
50
|
this._onRowSpacingChange(t);
|
|
51
51
|
}, 300));
|
|
52
52
|
/**
|
|
53
53
|
* Debounced version of _onMobileColumnSpacingChange
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
g(this, "_debouncedOnMobileColumnSpacingChange", N((t) => {
|
|
56
56
|
this._onMobileColumnSpacingChange(t);
|
|
57
57
|
}, 300));
|
|
58
58
|
/**
|
|
59
59
|
* Debounced version of _onMobileRowSpacingChange
|
|
60
60
|
*/
|
|
61
|
-
|
|
61
|
+
g(this, "_debouncedOnMobileRowSpacingChange", N((t) => {
|
|
62
62
|
this._onMobileRowSpacingChange(t);
|
|
63
63
|
}, 300));
|
|
64
64
|
}
|
|
65
65
|
getId() {
|
|
66
|
-
return
|
|
66
|
+
return V;
|
|
67
67
|
}
|
|
68
68
|
getTemplate() {
|
|
69
69
|
return `
|
|
70
70
|
<div class="spacing-control-container">
|
|
71
|
-
${this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
text: this.api.translate("Row Spacing (px)"),
|
|
84
|
-
name: n.ROW_SPACING_LABEL
|
|
85
|
-
}),
|
|
86
|
-
this._GuCounter({
|
|
87
|
-
name: n.ROW_SPACING,
|
|
88
|
-
minValue: b,
|
|
89
|
-
maxValue: N,
|
|
90
|
-
step: _
|
|
91
|
-
}),
|
|
92
|
-
this._GuLabel({
|
|
93
|
-
text: this.api.translate("Column Spacing on Mobile (px)"),
|
|
94
|
-
name: n.MOBILE_COLUMN_SPACING_LABEL
|
|
95
|
-
}),
|
|
96
|
-
this._GuCounter({
|
|
97
|
-
name: n.MOBILE_COLUMN_SPACING,
|
|
98
|
-
minValue: b,
|
|
99
|
-
maxValue: N,
|
|
100
|
-
step: _
|
|
101
|
-
}),
|
|
102
|
-
this._GuLabel({
|
|
103
|
-
text: this.api.translate("Row Spacing on Mobile (px)"),
|
|
104
|
-
name: n.MOBILE_ROW_SPACING_LABEL
|
|
105
|
-
}),
|
|
106
|
-
this._GuCounter({
|
|
107
|
-
name: n.MOBILE_ROW_SPACING,
|
|
108
|
-
minValue: b,
|
|
109
|
-
maxValue: N,
|
|
110
|
-
step: _
|
|
111
|
-
})
|
|
112
|
-
])}
|
|
71
|
+
${this._spacingRow("Column Spacing (px)", o.COLUMN_SPACING_LABEL, o.COLUMN_SPACING)}
|
|
72
|
+
${this._spacingRow("Row Spacing (px)", o.ROW_SPACING_LABEL, o.ROW_SPACING)}
|
|
73
|
+
${this._spacingRow(
|
|
74
|
+
"Column Spacing on Mobile (px)",
|
|
75
|
+
o.MOBILE_COLUMN_SPACING_LABEL,
|
|
76
|
+
o.MOBILE_COLUMN_SPACING
|
|
77
|
+
)}
|
|
78
|
+
${this._spacingRow(
|
|
79
|
+
"Row Spacing on Mobile (px)",
|
|
80
|
+
o.MOBILE_ROW_SPACING_LABEL,
|
|
81
|
+
o.MOBILE_ROW_SPACING
|
|
82
|
+
)}
|
|
113
83
|
</div>
|
|
114
84
|
`;
|
|
115
85
|
}
|
|
@@ -122,6 +92,21 @@ class j extends R {
|
|
|
122
92
|
onDestroy() {
|
|
123
93
|
this.unsubscribeOrientation && (this.unsubscribeOrientation(), this.unsubscribeOrientation = null);
|
|
124
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* One label + counter per two-column row, so every spacing field gets the same
|
|
97
|
+
* 16px-padded row the color controls already render instead of sharing one grid.
|
|
98
|
+
*/
|
|
99
|
+
_spacingRow(t, e, n) {
|
|
100
|
+
return this._GuTwoColumns([
|
|
101
|
+
this._GuLabel({ text: this.api.translate(t), name: e }),
|
|
102
|
+
this._GuCounter({
|
|
103
|
+
name: n,
|
|
104
|
+
minValue: R,
|
|
105
|
+
maxValue: G,
|
|
106
|
+
step: P
|
|
107
|
+
})
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
125
110
|
/**
|
|
126
111
|
* Updates spacing control visibility based on layout orientation and mobileLayoutEnabled.
|
|
127
112
|
* - List layout: hide column spacing (products are full-width), hide ALL mobile
|
|
@@ -132,14 +117,14 @@ class j extends R {
|
|
|
132
117
|
_updateSpacingVisibility() {
|
|
133
118
|
if (!this.api)
|
|
134
119
|
return;
|
|
135
|
-
const t = p.getConfig(this.currentNode), e = this.store.recommendationConfigs.orientation, i = (t.layout || e ||
|
|
136
|
-
this.api.setVisibility(
|
|
137
|
-
|
|
120
|
+
const t = p.getConfig(this.currentNode), e = this.store.recommendationConfigs.orientation, i = (t.layout || e || _(this.currentNode)) === "grid", { mobileLayoutEnabled: a } = t, r = t.cardsInRow > 1, c = t.mobileCardsInRow > 1;
|
|
121
|
+
this.api.setVisibility(o.COLUMN_SPACING, i && r), this.api.setVisibility(o.COLUMN_SPACING_LABEL, i && r), this.api.setVisibility(o.ROW_SPACING, !0), this.api.setVisibility(o.ROW_SPACING_LABEL, !0), this.api.setVisibility(
|
|
122
|
+
o.MOBILE_COLUMN_SPACING,
|
|
138
123
|
i && a && c
|
|
139
124
|
), this.api.setVisibility(
|
|
140
|
-
|
|
125
|
+
o.MOBILE_COLUMN_SPACING_LABEL,
|
|
141
126
|
i && a && c
|
|
142
|
-
), this.api.setVisibility(
|
|
127
|
+
), this.api.setVisibility(o.MOBILE_ROW_SPACING, i && a), this.api.setVisibility(o.MOBILE_ROW_SPACING_LABEL, i && a);
|
|
143
128
|
}
|
|
144
129
|
/**
|
|
145
130
|
* Reads spacing values from node config first, falls back to DOM styles.
|
|
@@ -148,12 +133,12 @@ class j extends R {
|
|
|
148
133
|
_setFormValues() {
|
|
149
134
|
if (!this.api)
|
|
150
135
|
return;
|
|
151
|
-
const t = p.hasConfig(this.currentNode), e = p.getConfig(this.currentNode),
|
|
136
|
+
const t = p.hasConfig(this.currentNode), e = p.getConfig(this.currentNode), n = t ? e.columnSpacing : this._getStoredColumnSpacing(), i = t ? e.rowSpacing : this._getStoredRowSpacing();
|
|
152
137
|
this.api.updateValues({
|
|
153
|
-
[
|
|
154
|
-
[
|
|
155
|
-
[
|
|
156
|
-
[
|
|
138
|
+
[o.COLUMN_SPACING]: n,
|
|
139
|
+
[o.ROW_SPACING]: i,
|
|
140
|
+
[o.MOBILE_COLUMN_SPACING]: e.mobileColumnSpacing,
|
|
141
|
+
[o.MOBILE_ROW_SPACING]: e.mobileRowSpacing
|
|
157
142
|
});
|
|
158
143
|
}
|
|
159
144
|
/**
|
|
@@ -165,20 +150,20 @@ class j extends R {
|
|
|
165
150
|
*/
|
|
166
151
|
_getStoredColumnSpacing() {
|
|
167
152
|
if (!this.currentNode)
|
|
168
|
-
return
|
|
169
|
-
const t = this.currentNode.querySelector(
|
|
170
|
-
if (
|
|
171
|
-
const h = t.querySelector(".recommendation-attribute-row"), l = (h == null ? void 0 : h.querySelector("td")) ?? null, d =
|
|
153
|
+
return C;
|
|
154
|
+
const t = this.currentNode.querySelector(m) ?? this.currentNode;
|
|
155
|
+
if (_(this.currentNode) === "grid") {
|
|
156
|
+
const h = t.querySelector(".recommendation-attribute-row"), l = (h == null ? void 0 : h.querySelector("td")) ?? null, d = f(l, "padding");
|
|
172
157
|
if (!d)
|
|
173
|
-
return
|
|
174
|
-
const
|
|
175
|
-
return
|
|
158
|
+
return C;
|
|
159
|
+
const A = d.trim().split(/\s+/);
|
|
160
|
+
return A.length < 2 ? C : O(A[1], C / 2) * 2;
|
|
176
161
|
}
|
|
177
|
-
const
|
|
162
|
+
const n = t.querySelector(".product-card-wrapper") ?? null, i = B(n), a = f(i, "padding");
|
|
178
163
|
if (!a)
|
|
179
|
-
return
|
|
164
|
+
return C;
|
|
180
165
|
const r = a.trim().split(/\s+/);
|
|
181
|
-
return r.length < 2 ?
|
|
166
|
+
return r.length < 2 ? C : O(r[1], C / 2) * 2;
|
|
182
167
|
}
|
|
183
168
|
/**
|
|
184
169
|
* Gets stored row spacing from the first spacer element's height style
|
|
@@ -186,9 +171,9 @@ class j extends R {
|
|
|
186
171
|
*/
|
|
187
172
|
_getStoredRowSpacing() {
|
|
188
173
|
if (!this.currentNode)
|
|
189
|
-
return
|
|
190
|
-
const e = (this.currentNode.querySelector(
|
|
191
|
-
return
|
|
174
|
+
return I;
|
|
175
|
+
const e = (this.currentNode.querySelector(m) ?? this.currentNode).querySelector(".spacer") ?? null, n = f(e, "height");
|
|
176
|
+
return O(n, I);
|
|
192
177
|
}
|
|
193
178
|
// ========================================================================
|
|
194
179
|
// Desktop Spacing Handlers
|
|
@@ -205,9 +190,9 @@ class j extends R {
|
|
|
205
190
|
this.currentNode,
|
|
206
191
|
{ columnSpacing: t },
|
|
207
192
|
`Changed column spacing to ${t}px`
|
|
208
|
-
), this._storeDataAttribute(
|
|
209
|
-
const
|
|
210
|
-
c && (
|
|
193
|
+
), this._storeDataAttribute(b.COLUMN_SPACING, t);
|
|
194
|
+
const n = p.getConfig(this.currentNode).layout || _(this.currentNode), i = this.api.getDocumentModifier(), r = `0 ${t / 2}px`, c = this.currentNode.querySelector(m);
|
|
195
|
+
c && (n === "grid" ? Array.from(
|
|
211
196
|
c.querySelectorAll(".attribute-cell")
|
|
212
197
|
).forEach((l) => {
|
|
213
198
|
i.modifyHtml(l).setStyle("padding", r);
|
|
@@ -216,7 +201,7 @@ class j extends R {
|
|
|
216
201
|
).forEach((l) => {
|
|
217
202
|
const d = "parent" in l ? l.parent() : void 0;
|
|
218
203
|
d && i.modifyHtml(d).setStyle("padding", r);
|
|
219
|
-
}), i.apply(new
|
|
204
|
+
}), i.apply(new S(`Update column spacing to ${t}px`)));
|
|
220
205
|
}
|
|
221
206
|
/**
|
|
222
207
|
* Handles row spacing changes for desktop.
|
|
@@ -230,19 +215,19 @@ class j extends R {
|
|
|
230
215
|
this.currentNode,
|
|
231
216
|
{ rowSpacing: t },
|
|
232
217
|
`Changed row spacing to ${t}px`
|
|
233
|
-
), this._storeDataAttribute(
|
|
234
|
-
const e = this.currentNode.querySelector(
|
|
218
|
+
), this._storeDataAttribute(b.ROW_SPACING, t);
|
|
219
|
+
const e = this.currentNode.querySelector(m);
|
|
235
220
|
if (!e)
|
|
236
221
|
return;
|
|
237
|
-
const
|
|
222
|
+
const n = Array.from(
|
|
238
223
|
e.querySelectorAll(".spacer")
|
|
239
224
|
);
|
|
240
|
-
if (!
|
|
225
|
+
if (!n.length)
|
|
241
226
|
return;
|
|
242
227
|
const i = this.api.getDocumentModifier(), a = `${t}px`;
|
|
243
|
-
|
|
228
|
+
n.forEach((r) => {
|
|
244
229
|
i.modifyHtml(r).setStyle("height", a);
|
|
245
|
-
}), i.apply(new
|
|
230
|
+
}), i.apply(new S(`Update row spacing to ${t}px`));
|
|
246
231
|
}
|
|
247
232
|
// ========================================================================
|
|
248
233
|
// Mobile Spacing Handlers
|
|
@@ -259,9 +244,9 @@ class j extends R {
|
|
|
259
244
|
this.currentNode,
|
|
260
245
|
{ mobileColumnSpacing: t },
|
|
261
246
|
`Changed mobile column spacing to ${t}px`
|
|
262
|
-
), this._storeDataAttribute(
|
|
263
|
-
const
|
|
264
|
-
c && (
|
|
247
|
+
), this._storeDataAttribute(b.MOBILE_COLUMN_SPACING, t);
|
|
248
|
+
const n = p.getConfig(this.currentNode).layout || _(this.currentNode), i = this.api.getDocumentModifier(), r = `0 ${t / 2}px`, c = this.currentNode.querySelector(L);
|
|
249
|
+
c && (n === "grid" ? Array.from(
|
|
265
250
|
c.querySelectorAll(".attribute-cell")
|
|
266
251
|
).forEach((l) => {
|
|
267
252
|
i.modifyHtml(l).setStyle("padding", r);
|
|
@@ -270,7 +255,7 @@ class j extends R {
|
|
|
270
255
|
).forEach((l) => {
|
|
271
256
|
const d = "parent" in l ? l.parent() : void 0;
|
|
272
257
|
d && i.modifyHtml(d).setStyle("padding", r);
|
|
273
|
-
}), i.apply(new
|
|
258
|
+
}), i.apply(new S(`Update mobile column spacing to ${t}px`)));
|
|
274
259
|
}
|
|
275
260
|
/**
|
|
276
261
|
* Handles row spacing changes for mobile.
|
|
@@ -284,19 +269,19 @@ class j extends R {
|
|
|
284
269
|
this.currentNode,
|
|
285
270
|
{ mobileRowSpacing: t },
|
|
286
271
|
`Changed mobile row spacing to ${t}px`
|
|
287
|
-
), this._storeDataAttribute(
|
|
288
|
-
const e = this.currentNode.querySelector(
|
|
272
|
+
), this._storeDataAttribute(b.MOBILE_ROW_SPACING, t);
|
|
273
|
+
const e = this.currentNode.querySelector(L);
|
|
289
274
|
if (!e)
|
|
290
275
|
return;
|
|
291
|
-
const
|
|
276
|
+
const n = Array.from(
|
|
292
277
|
e.querySelectorAll(".spacer")
|
|
293
278
|
);
|
|
294
|
-
if (!
|
|
279
|
+
if (!n.length)
|
|
295
280
|
return;
|
|
296
281
|
const i = this.api.getDocumentModifier(), a = `${t}px`;
|
|
297
|
-
|
|
282
|
+
n.forEach((r) => {
|
|
298
283
|
i.modifyHtml(r).setStyle("height", a);
|
|
299
|
-
}), i.apply(new
|
|
284
|
+
}), i.apply(new S(`Update mobile row spacing to ${t}px`));
|
|
300
285
|
}
|
|
301
286
|
// ========================================================================
|
|
302
287
|
// Data Attribute Storage
|
|
@@ -305,23 +290,23 @@ class j extends R {
|
|
|
305
290
|
* Stores a spacing value as a data attribute on the block root element
|
|
306
291
|
*/
|
|
307
292
|
_storeDataAttribute(t, e) {
|
|
308
|
-
const
|
|
309
|
-
|
|
293
|
+
const n = U(this.currentNode);
|
|
294
|
+
n && this.api.getDocumentModifier().modifyHtml(n).setAttribute(t, e.toString()).apply(new S(`Store ${t}`));
|
|
310
295
|
}
|
|
311
296
|
// ========================================================================
|
|
312
297
|
// Event Listeners
|
|
313
298
|
// ========================================================================
|
|
314
299
|
_listenToFormUpdates() {
|
|
315
|
-
this.api.onValueChanged(
|
|
300
|
+
this.api.onValueChanged(o.COLUMN_SPACING, (t) => {
|
|
316
301
|
const e = parseInt(t);
|
|
317
302
|
Number.isNaN(e) || this._debouncedOnColumnSpacingChange(e);
|
|
318
|
-
}), this.api.onValueChanged(
|
|
303
|
+
}), this.api.onValueChanged(o.ROW_SPACING, (t) => {
|
|
319
304
|
const e = parseInt(t);
|
|
320
305
|
Number.isNaN(e) || this._debouncedOnRowSpacingChange(e);
|
|
321
|
-
}), this.api.onValueChanged(
|
|
306
|
+
}), this.api.onValueChanged(o.MOBILE_COLUMN_SPACING, (t) => {
|
|
322
307
|
const e = parseInt(t);
|
|
323
308
|
Number.isNaN(e) || this._debouncedOnMobileColumnSpacingChange(e);
|
|
324
|
-
}), this.api.onValueChanged(
|
|
309
|
+
}), this.api.onValueChanged(o.MOBILE_ROW_SPACING, (t) => {
|
|
325
310
|
const e = parseInt(t);
|
|
326
311
|
Number.isNaN(e) || this._debouncedOnMobileRowSpacingChange(e);
|
|
327
312
|
});
|
|
@@ -337,6 +322,6 @@ class j extends R {
|
|
|
337
322
|
}
|
|
338
323
|
}
|
|
339
324
|
export {
|
|
340
|
-
|
|
325
|
+
V as SPACING_CONTROL_ID,
|
|
341
326
|
j as SpacingControl
|
|
342
327
|
};
|
|
@@ -25,6 +25,27 @@ const n = `/* Utils */
|
|
|
25
25
|
border-top: none;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/* The editor's row-separator rule only reaches \`.container\`s that are direct
|
|
29
|
+
children of \`.container-wrapper\`; the spacing rows sit one level deeper, so the
|
|
30
|
+
first one loses its line. Restore it with the editor's own border token. */
|
|
31
|
+
.spacing-control-container > .container {
|
|
32
|
+
border-top: var(--ue-border-width-1, 1px) solid var(--ue-panels-border-color, rgba(0, 0, 0, 0.07));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* A spacing field that doesn't apply (mobile rows, column spacing in list layout) is
|
|
36
|
+
removed from its row and leaves the wrapper behind — collapse it so it can't
|
|
37
|
+
render as an empty separator-topped strip. */
|
|
38
|
+
.spacing-control-container > .container:not(:has(ue-counter)) {
|
|
39
|
+
display: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* The block background row stacks the editor's "inherits background color" banner
|
|
43
|
+
above its field, separated by the editor's default 10px gap — match the tab's 16px.
|
|
44
|
+
Scoped via the spacing control so other blocks keep the default. */
|
|
45
|
+
.ue-scrollable-content:has(.spacing-control-container) .e2e-block-bg-color {
|
|
46
|
+
row-gap: 16px;
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
/* Right-align the mobile layout toggle within the two-column grid */
|
|
29
50
|
.product-layout-control-container ue-switcher {
|
|
30
51
|
justify-self: end;
|
|
@@ -30,6 +30,11 @@ export declare class SpacingControl extends CommonControl {
|
|
|
30
30
|
onRender(): void;
|
|
31
31
|
onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
|
|
32
32
|
onDestroy(): void;
|
|
33
|
+
/**
|
|
34
|
+
* One label + counter per two-column row, so every spacing field gets the same
|
|
35
|
+
* 16px-padded row the color controls already render instead of sharing one grid.
|
|
36
|
+
*/
|
|
37
|
+
_spacingRow(label: string, labelName: string, counterName: string): string;
|
|
33
38
|
/**
|
|
34
39
|
* Updates spacing control visibility based on layout orientation and mobileLayoutEnabled.
|
|
35
40
|
* - List layout: hide column spacing (products are full-width), hide ALL mobile
|
|
@@ -36,4 +36,12 @@ export declare const useDynamicContentStore: import("pinia").StoreDefinition<"gu
|
|
|
36
36
|
}[];
|
|
37
37
|
}, {
|
|
38
38
|
setSelectedDynamicContent(dynamicContent: DynamicContent): void;
|
|
39
|
+
/**
|
|
40
|
+
* Append-only bulk registration for dynamic content used by an
|
|
41
|
+
* AI-applied template. Unlike `setSelectedDynamicContent` it doesn't
|
|
42
|
+
* touch `selectedDynamicContent`; the getter removes duplicates, so
|
|
43
|
+
* re-registering the same entries is harmless. Items are shallow-copied so Pinia
|
|
44
|
+
* reactivity can't write a later mutation back into the host's catalog.
|
|
45
|
+
*/
|
|
46
|
+
registerDynamicContent(items: DynamicContent[]): void;
|
|
39
47
|
}>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DynamicContent } from '@@/Types/generic';
|
|
2
|
+
export declare const extractUsedDynamicContent: (html: string, flattenedCatalog: DynamicContent[] | undefined | null) => DynamicContent[];
|
|
3
|
+
/**
|
|
4
|
+
* Dev-diagnostic sibling of `extractUsedDynamicContent`: the used token names
|
|
5
|
+
* with NO catalog match (so intentionally not registered). Surfaced via a
|
|
6
|
+
* dev-gated `console.debug` to spot a neo↔guido vocabulary mismatch. Never throws.
|
|
7
|
+
*/
|
|
8
|
+
export declare const getUnmatchedDynamicContentTokens: (html: string, flattenedCatalog: DynamicContent[] | undefined | null) => string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { removeDuplicatesFromArray as n } from "../utils/arrayUtil.js";
|
|
2
2
|
import { defineStore as a } from "pinia";
|
|
3
|
-
const
|
|
3
|
+
const c = a("guidoDynamicContent", {
|
|
4
4
|
state: () => ({
|
|
5
5
|
selectedDynamicContent: { text: "", value: "" },
|
|
6
6
|
selectedDynamicContentList: []
|
|
@@ -8,6 +8,16 @@ const s = a("guidoDynamicContent", {
|
|
|
8
8
|
actions: {
|
|
9
9
|
setSelectedDynamicContent(t) {
|
|
10
10
|
this.selectedDynamicContent = t, this.selectedDynamicContentList.push(t);
|
|
11
|
+
},
|
|
12
|
+
/**
|
|
13
|
+
* Append-only bulk registration for dynamic content used by an
|
|
14
|
+
* AI-applied template. Unlike `setSelectedDynamicContent` it doesn't
|
|
15
|
+
* touch `selectedDynamicContent`; the getter removes duplicates, so
|
|
16
|
+
* re-registering the same entries is harmless. Items are shallow-copied so Pinia
|
|
17
|
+
* reactivity can't write a later mutation back into the host's catalog.
|
|
18
|
+
*/
|
|
19
|
+
registerDynamicContent(t) {
|
|
20
|
+
this.selectedDynamicContentList.push(...t.map((e) => ({ ...e })));
|
|
11
21
|
}
|
|
12
22
|
},
|
|
13
23
|
getters: {
|
|
@@ -20,5 +30,5 @@ const s = a("guidoDynamicContent", {
|
|
|
20
30
|
}
|
|
21
31
|
});
|
|
22
32
|
export {
|
|
23
|
-
|
|
33
|
+
c as useDynamicContentStore
|
|
24
34
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DATA_ATTRIBUTE_REGEX as T } from "../enums/html-validator.js";
|
|
2
|
+
const d = /{{([a-zA-Z0-9_.\s]*)}}/gm, h = (n, e) => {
|
|
3
|
+
if (!e || e.length === 0)
|
|
4
|
+
return { matched: [], unmatchedTokens: [] };
|
|
5
|
+
const s = n.replace(T, "$1").match(d);
|
|
6
|
+
if (!s)
|
|
7
|
+
return { matched: [], unmatchedTokens: [] };
|
|
8
|
+
const u = new Map(
|
|
9
|
+
e.map((c) => [c.value.trim().toLowerCase(), c])
|
|
10
|
+
), a = /* @__PURE__ */ new Set(), o = [], m = [];
|
|
11
|
+
return s.forEach((c) => {
|
|
12
|
+
const t = c.slice(2, -2).trim().toLowerCase();
|
|
13
|
+
if (t === "" || a.has(t))
|
|
14
|
+
return;
|
|
15
|
+
a.add(t);
|
|
16
|
+
const r = u.get(t);
|
|
17
|
+
r ? o.push(r) : m.push(t);
|
|
18
|
+
}), { matched: o, unmatchedTokens: m };
|
|
19
|
+
}, E = (n, e) => h(n, e).matched, k = (n, e) => h(n, e).unmatchedTokens;
|
|
20
|
+
export {
|
|
21
|
+
E as extractUsedDynamicContent,
|
|
22
|
+
k as getUnmatchedDynamicContentTokens
|
|
23
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.0-beta.166619d",
|
|
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",
|