@useinsider/guido 2.0.0-beta.e73ba15 → 2.0.0-beta.fb0f99d

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.
Files changed (35) hide show
  1. package/dist/@types/config/schemas.js +53 -39
  2. package/dist/components/organisms/email-preview/amp/AmpToggle.vue.js +2 -2
  3. package/dist/components/organisms/header/RightSlot.vue2.js +10 -10
  4. package/dist/composables/useConfig.js +29 -27
  5. package/dist/composables/useSave.js +13 -11
  6. package/dist/extensions/Blocks/Recommendation/constants/layout.js +9 -4
  7. package/dist/extensions/Blocks/Recommendation/controls/cardBackground/index.js +21 -41
  8. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +37 -48
  9. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +78 -50
  10. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +72 -70
  11. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textAfter.js +1 -1
  12. package/dist/extensions/Blocks/Recommendation/controls/omnibusDiscount/textBefore.js +3 -3
  13. package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +60 -80
  14. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +16 -14
  15. package/dist/extensions/Blocks/Recommendation/utils/preserveTextStyles.js +27 -16
  16. package/dist/extensions/Blocks/Recommendation/utils/tagName.js +46 -0
  17. package/dist/extensions/Blocks/Unsubscribe/extension.js +9 -9
  18. package/dist/extensions/Blocks/common-control.js +6 -7
  19. package/dist/guido.css +1 -1
  20. package/dist/src/@types/config/index.d.ts +2 -2
  21. package/dist/src/@types/config/schemas.d.ts +26 -0
  22. package/dist/src/@types/config/types.d.ts +7 -1
  23. package/dist/src/composables/useConfig.d.ts +6 -0
  24. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
  25. package/dist/src/extensions/Blocks/Recommendation/constants/layout.d.ts +10 -0
  26. package/dist/src/extensions/Blocks/Recommendation/controls/cardBackground/index.d.ts +0 -10
  27. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +6 -17
  28. package/dist/src/extensions/Blocks/Recommendation/controls/spacing/index.d.ts +0 -5
  29. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +1 -0
  30. package/dist/src/extensions/Blocks/Recommendation/utils/tagName.d.ts +77 -0
  31. package/dist/src/extensions/Blocks/common-control.d.ts +1 -1
  32. package/dist/src/stores/config.d.ts +147 -1
  33. package/dist/static/styles/components/button.css.js +1 -1
  34. package/dist/stores/config.js +7 -0
  35. package/package.json +1 -1
@@ -1,60 +1,49 @@
1
- var A = Object.defineProperty;
2
- var y = (n, i, t) => i in n ? A(n, i, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[i] = t;
3
- var p = (n, i, t) => y(n, typeof i != "symbol" ? i + "" : i, t);
4
- import { ModificationDescription as d } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
- import { CommonControl as b } from "../../../common-control.js";
6
- import { useRecommendationExtensionStore as P } from "../../store/recommendation.js";
7
- import { useDebounceFn as N } from "../../../../../node_modules/@vueuse/shared/index.js";
8
- const O = "recommendation-spacing-control", a = {
1
+ var P = Object.defineProperty;
2
+ var G = (o, n, t) => n in o ? P(o, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[n] = t;
3
+ var l = (o, n, t) => G(o, typeof n != "symbol" ? n + "" : n, t);
4
+ import { ModificationDescription as p } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
+ import { CommonControl as I } from "../../../common-control.js";
6
+ import { SPACING_STEP as N, MAX_SPACING as _, MIN_SPACING as f, DEFAULT_COLUMN_SPACING as c, DEFAULT_ROW_SPACING as b } from "../../constants/layout.js";
7
+ import { useRecommendationExtensionStore as L } from "../../store/recommendation.js";
8
+ import { safeGetStyle as d, safeGetParent as V } from "../../utils/tagName.js";
9
+ import { getCurrentLayout as m } from "../main/utils.js";
10
+ import { useDebounceFn as A } from "../../../../../node_modules/@vueuse/shared/index.js";
11
+ const w = "recommendation-spacing-control", a = {
9
12
  COLUMN_SPACING: "columnSpacing",
10
13
  COLUMN_SPACING_LABEL: "columnSpacingLabel",
11
14
  ROW_SPACING: "rowSpacing"
12
- }, _ = {
15
+ }, y = {
13
16
  COLUMN_SPACING: "data-column-spacing",
14
17
  ROW_SPACING: "data-row-spacing"
15
- }, s = {
16
- COLUMN_SPACING: 10,
17
- // 5px on each side = 10px total
18
- ROW_SPACING: 20
19
- }, u = {
20
- MIN_SPACING: 0,
21
- MAX_SPACING: 50,
22
- STEP: 5
23
18
  };
24
- function S(n, i) {
25
- return !n || !("getStyle" in n) ? null : n.getStyle(i);
19
+ function h(o, n) {
20
+ if (!o)
21
+ return n;
22
+ const t = parseFloat(o);
23
+ return Number.isNaN(t) ? n : t;
26
24
  }
27
- function I(n) {
28
- return !n || !("parent" in n) || typeof n.parent != "function" ? null : n.parent();
29
- }
30
- function C(n, i) {
31
- if (!n)
32
- return i;
33
- const t = parseFloat(n);
34
- return Number.isNaN(t) ? i : t;
35
- }
36
- class w extends b {
25
+ class q extends I {
37
26
  constructor() {
38
27
  super(...arguments);
39
- p(this, "store", P());
40
- p(this, "unsubscribeOrientation", null);
28
+ l(this, "store", L());
29
+ l(this, "unsubscribeOrientation", null);
41
30
  /**
42
31
  * Debounced version of _onColumnSpacingChange
43
32
  * Prevents excessive DOM updates when user rapidly adjusts the counter
44
33
  */
45
- p(this, "_debouncedOnColumnSpacingChange", N((t) => {
34
+ l(this, "_debouncedOnColumnSpacingChange", A((t) => {
46
35
  this._onColumnSpacingChange(t);
47
36
  }, 300));
48
37
  /**
49
38
  * Debounced version of _onRowSpacingChange
50
39
  * Prevents excessive DOM updates when user rapidly adjusts the counter
51
40
  */
52
- p(this, "_debouncedOnRowSpacingChange", N((t) => {
41
+ l(this, "_debouncedOnRowSpacingChange", A((t) => {
53
42
  this._onRowSpacingChange(t);
54
43
  }, 300));
55
44
  }
56
45
  getId() {
57
- return O;
46
+ return w;
58
47
  }
59
48
  getTemplate() {
60
49
  return `
@@ -63,16 +52,16 @@ class w extends b {
63
52
  this._GuLabel({ text: "Column Spacing (px)", name: a.COLUMN_SPACING_LABEL }),
64
53
  this._GuCounter({
65
54
  name: a.COLUMN_SPACING,
66
- minValue: u.MIN_SPACING,
67
- maxValue: u.MAX_SPACING,
68
- step: u.STEP
55
+ minValue: f,
56
+ maxValue: _,
57
+ step: N
69
58
  }),
70
59
  this._GuLabel({ text: "Row Spacing (px)" }),
71
60
  this._GuCounter({
72
61
  name: a.ROW_SPACING,
73
- minValue: u.MIN_SPACING,
74
- maxValue: u.MAX_SPACING,
75
- step: u.STEP
62
+ minValue: f,
63
+ maxValue: _,
64
+ step: N
76
65
  })
77
66
  ])}
78
67
  </div>
@@ -84,23 +73,14 @@ class w extends b {
84
73
  onTemplateNodeUpdated(t) {
85
74
  super.onTemplateNodeUpdated(t), this._setFormValues(), this._updateColumnSpacingVisibility();
86
75
  }
87
- /**
88
- * Gets the current layout orientation from the block's data attribute
89
- */
90
- _getCurrentLayout() {
91
- if (!this.currentNode || !("querySelector" in this.currentNode))
92
- return "vertical";
93
- const t = this.currentNode.querySelector(".ins-recommendation-v3-block-v2");
94
- return !t || !("getAttribute" in t) ? "vertical" : t.getAttribute("data-layout") === "horizontal" ? "horizontal" : "vertical";
95
- }
96
76
  /**
97
77
  * Updates column spacing visibility based on layout orientation
98
78
  * Column spacing is hidden for horizontal layout (products are stacked vertically)
99
79
  * Reads from store first for reliability, falls back to DOM
100
80
  */
101
81
  _updateColumnSpacingVisibility() {
102
- const r = (this.store.recommendationConfigs.orientation || this._getCurrentLayout()) === "vertical";
103
- this.api.setVisibility(a.COLUMN_SPACING, r), this.api.setVisibility(a.COLUMN_SPACING_LABEL, r);
82
+ const i = (this.store.recommendationConfigs.orientation || m(this.currentNode)) === "vertical";
83
+ this.api.setVisibility(a.COLUMN_SPACING, i), this.api.setVisibility(a.COLUMN_SPACING_LABEL, i);
104
84
  }
105
85
  /**
106
86
  * Reads spacing values from data attributes or returns defaults
@@ -120,28 +100,28 @@ class w extends b {
120
100
  */
121
101
  _getStoredColumnSpacing() {
122
102
  if (!this.currentNode)
123
- return s.COLUMN_SPACING;
124
- if (this._getCurrentLayout() === "vertical") {
125
- const o = this.currentNode.querySelector(".recommendation-attribute-row"), f = o == null ? void 0 : o.querySelector("td"), g = S(f, "padding");
126
- if (!g)
127
- return s.COLUMN_SPACING;
128
- const m = g.trim().split(/\s+/);
129
- return m.length < 2 ? s.COLUMN_SPACING : C(m[1], s.COLUMN_SPACING / 2) * 2;
103
+ return c;
104
+ if (m(this.currentNode) === "vertical") {
105
+ const r = this.currentNode.querySelector(".recommendation-attribute-row"), O = r == null ? void 0 : r.querySelector("td"), S = d(O, "padding");
106
+ if (!S)
107
+ return c;
108
+ const C = S.trim().split(/\s+/);
109
+ return C.length < 2 ? c : h(C[1], c / 2) * 2;
130
110
  }
131
- const e = this.currentNode.querySelector(".product-card-wrapper"), r = I(e), l = S(r, "padding");
132
- if (!l)
133
- return s.COLUMN_SPACING;
134
- const c = l.trim().split(/\s+/);
135
- return c.length < 2 ? s.COLUMN_SPACING : C(c[1], s.COLUMN_SPACING / 2) * 2;
111
+ const e = this.currentNode.querySelector(".product-card-wrapper"), i = V(e), u = d(i, "padding");
112
+ if (!u)
113
+ return c;
114
+ const s = u.trim().split(/\s+/);
115
+ return s.length < 2 ? c : h(s[1], c / 2) * 2;
136
116
  }
137
117
  /**
138
118
  * Gets stored row spacing from the first spacer element's height style
139
119
  */
140
120
  _getStoredRowSpacing() {
141
121
  if (!this.currentNode)
142
- return s.ROW_SPACING;
143
- const t = this.currentNode.querySelector(".spacer"), e = S(t, "height");
144
- return C(e, s.ROW_SPACING);
122
+ return b;
123
+ const t = this.currentNode.querySelector(".spacer"), e = d(t, "height");
124
+ return h(e, b);
145
125
  }
146
126
  /**
147
127
  * Handles column spacing changes.
@@ -152,16 +132,16 @@ class w extends b {
152
132
  if (!this.currentNode)
153
133
  return;
154
134
  this._storeColumnSpacing(t);
155
- const e = this._getCurrentLayout(), r = this.api.getDocumentModifier(), c = `0 ${t / 2}px`;
135
+ const e = m(this.currentNode), i = this.api.getDocumentModifier(), s = `0 ${t / 2}px`;
156
136
  e === "vertical" ? Array.from(
157
137
  this.currentNode.querySelectorAll(".attribute-cell")
158
- ).forEach((o) => {
159
- r.modifyHtml(o).setStyle("padding", c);
138
+ ).forEach((r) => {
139
+ i.modifyHtml(r).setStyle("padding", s);
160
140
  }) : Array.from(
161
141
  this.currentNode.querySelectorAll(".product-card-wrapper")
162
- ).forEach((o) => {
163
- "parent" in o && o.parent() && r.modifyHtml(o.parent()).setStyle("padding", c);
164
- }), r.apply(new d(`Update column spacing to ${t}px`));
142
+ ).forEach((r) => {
143
+ "parent" in r && r.parent() && i.modifyHtml(r.parent()).setStyle("padding", s);
144
+ }), i.apply(new p(`Update column spacing to ${t}px`));
165
145
  }
166
146
  /**
167
147
  * Handles row spacing changes
@@ -176,10 +156,10 @@ class w extends b {
176
156
  );
177
157
  if (!e.length)
178
158
  return;
179
- const r = this.api.getDocumentModifier(), l = `${t}px`;
180
- e.forEach((c) => {
181
- r.modifyHtml(c).setStyle("height", l);
182
- }), r.apply(new d(`Update row spacing to ${t}px`));
159
+ const i = this.api.getDocumentModifier(), u = `${t}px`;
160
+ e.forEach((s) => {
161
+ i.modifyHtml(s).setStyle("height", u);
162
+ }), i.apply(new p(`Update row spacing to ${t}px`));
183
163
  }
184
164
  /**
185
165
  * Stores column spacing value in block data attribute
@@ -188,7 +168,7 @@ class w extends b {
188
168
  if (!this.currentNode)
189
169
  return;
190
170
  const e = this.currentNode.querySelector(".ins-recommendation-v3-block-v2");
191
- e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(_.COLUMN_SPACING, t.toString()).apply(new d("Store column spacing"));
171
+ e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(y.COLUMN_SPACING, t.toString()).apply(new p("Store column spacing"));
192
172
  }
193
173
  /**
194
174
  * Stores row spacing value in block data attribute
@@ -197,7 +177,7 @@ class w extends b {
197
177
  if (!this.currentNode)
198
178
  return;
199
179
  const e = this.currentNode.querySelector(".ins-recommendation-v3-block-v2");
200
- e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(_.ROW_SPACING, t.toString()).apply(new d("Store row spacing"));
180
+ e && this.api.getDocumentModifier().modifyHtml(e).setAttribute(y.ROW_SPACING, t.toString()).apply(new p("Store row spacing"));
201
181
  }
202
182
  _listenToFormUpdates() {
203
183
  this.api.onValueChanged(a.COLUMN_SPACING, (t) => {
@@ -219,6 +199,6 @@ class w extends b {
219
199
  }
220
200
  }
221
201
  export {
222
- O as SPACING_CONTROL_ID,
223
- w as SpacingControl
202
+ w as SPACING_CONTROL_ID,
203
+ q as SpacingControl
224
204
  };
@@ -1,14 +1,14 @@
1
1
  import { RecommendationFeedSourceMaps as u, PriceAttributes as c } from "../../../../enums/extensions/recommendationBlock.js";
2
2
  import { useRecommendationApi as p } from "../../../../services/recommendationApi.js";
3
3
  import { useConfigStore as m } from "../../../../stores/config.js";
4
- import { defineStore as d } from "pinia";
5
- import { DEFAULT_CARDS_IN_ROW as f } from "../constants/layout.js";
4
+ import { defineStore as f } from "pinia";
5
+ import { DEFAULT_CARDS_IN_ROW as d } from "../constants/layout.js";
6
6
  import { generateCompleteFilterQuery as l } from "../utils/filterUtil.js";
7
- const n = p(), g = () => ({
7
+ const s = p(), g = () => ({
8
8
  recommendationCampaignUrls: {},
9
9
  recommendationProducts: [],
10
10
  recommendationConfigs: {
11
- cardsInRow: f,
11
+ cardsInRow: d,
12
12
  currencySettings: {
13
13
  name: "USD",
14
14
  value: "USD",
@@ -135,7 +135,7 @@ const n = p(), g = () => ({
135
135
  filterSelectionDrawerStatus: !1,
136
136
  filterList: {},
137
137
  filterGroup: 1
138
- }), S = d("guidoRecommendationExtension", {
138
+ }), S = f("guidoRecommendationExtension", {
139
139
  state: () => g(),
140
140
  getters: {
141
141
  hasFilters: (e) => !!e.recommendationConfigs.filters.length,
@@ -179,13 +179,13 @@ const n = p(), g = () => ({
179
179
  activePredictiveAlgorithms: e,
180
180
  languages: t,
181
181
  currencies: r
182
- } = await n.fetchRecommendationCreateData();
182
+ } = await s.fetchRecommendationCreateData();
183
183
  this.activePredictiveAlgorithms = e, this.languages = t;
184
184
  const [i] = r;
185
185
  this.recommendationConfigs.currencySettings.name = i.text, this.recommendationConfigs.currencySettings.value = i.value, this.currencyList = r, this.filterStatus = !!this.recommendationConfigs.filters.length;
186
186
  },
187
187
  async fetchRecommendationFilters() {
188
- const e = await n.fetchRecommendationFilters();
188
+ const e = await s.fetchRecommendationFilters();
189
189
  this.filterList = e;
190
190
  },
191
191
  addFilterGroup(e) {
@@ -225,13 +225,15 @@ const n = p(), g = () => ({
225
225
  }
226
226
  },
227
227
  addFilter(e) {
228
- const t = [...this.recommendationConfigs.filters], r = t.findLastIndex((i) => i.filterGroup === e.filterGroup);
229
- r !== -1 ? t.splice(r + 1, 0, {
228
+ const t = [...this.recommendationConfigs.filters], i = t.filter(
229
+ (a) => a.filterGroup === e.filterGroup
230
+ ).length + 1, o = t.findLastIndex((a) => a.filterGroup === e.filterGroup);
231
+ o !== -1 ? t.splice(o + 1, 0, {
230
232
  ...e,
231
- filterNumber: r + 2
233
+ filterNumber: i
232
234
  }) : t.push({
233
235
  ...e,
234
- filterNumber: 1
236
+ filterNumber: i
235
237
  }), this.$patch({
236
238
  recommendationConfigs: {
237
239
  filters: t
@@ -242,11 +244,11 @@ const n = p(), g = () => ({
242
244
  return l(this.recommendationConfigs.filters);
243
245
  },
244
246
  async fetchRecommendationProducts() {
245
- var s;
246
- const e = this.recommendationConfigs.filters.filter((a) => a.isValid), t = l(e), r = ((s = u.find((a) => a.key === this.recommendationConfigs.strategy)) == null ? void 0 : s.path) || "", i = m(), o = await n.fetchRecommendationProducts(
247
+ var a;
248
+ const e = this.recommendationConfigs.filters.filter((n) => n.isValid), t = l(e), r = ((a = u.find((n) => n.key === this.recommendationConfigs.strategy)) == null ? void 0 : a.path) || "", i = m(), o = await s.fetchRecommendationProducts(
247
249
  r,
248
250
  {
249
- // TODO: Here will be optimized and filled carefully
251
+ // Note: {itemId} and {campaignId} are template placeholders replaced at runtime
250
252
  locale: this.recommendationConfigs.language,
251
253
  currency: this.recommendationConfigs.currencySettings.value,
252
254
  partnerName: i.partnerName,
@@ -1,25 +1,36 @@
1
- function a(n) {
2
- return "getInnerHTML" in n && typeof n.getInnerHTML == "function" ? n.getInnerHTML() : "innerHTML" in n ? n.innerHTML : "";
1
+ function p(t) {
2
+ const r = {
3
+ "&": "&amp;",
4
+ "<": "&lt;",
5
+ ">": "&gt;",
6
+ '"': "&quot;",
7
+ "'": "&#39;"
8
+ };
9
+ return t.replace(/[&<>"']/g, (n) => r[n]);
3
10
  }
4
- function H(n, t) {
5
- if (!n)
6
- return t;
7
- const r = a(n);
8
- if (!r || r.trim() === "" || !/<(strong|em|u|s|b|i)\b/i.test(r))
9
- return t;
10
- const i = [], s = [];
11
- let o = r.trim();
11
+ function m(t) {
12
+ return "getInnerHTML" in t && typeof t.getInnerHTML == "function" ? t.getInnerHTML() : "innerHTML" in t ? t.innerHTML : "";
13
+ }
14
+ function T(t, r) {
15
+ const n = p(r);
16
+ if (!t)
17
+ return n;
18
+ const e = m(t);
19
+ if (!e || e.trim() === "" || !/<(strong|em|u|s|b|i)\b/i.test(e))
20
+ return n;
21
+ const i = [], o = [];
22
+ let c = e.trim();
12
23
  for (; ; ) {
13
- const u = o.match(/^<(strong|em|u|s|b|i)(\s[^>]*)?>(.*)$/is);
24
+ const u = c.match(/^<(strong|em|u|s|b|i)(\s[^>]*)?>(.*)$/is);
14
25
  if (!u)
15
26
  break;
16
- const [, e, f = "", g] = u, c = new RegExp(`</${e}>$`, "i");
17
- if (!c.test(g))
27
+ const [, s, f = "", g] = u, a = new RegExp(`</${s}>$`, "i");
28
+ if (!a.test(g))
18
29
  break;
19
- i.push(`<${e}${f}>`), s.unshift(`</${e}>`), o = g.replace(c, "").trim();
30
+ i.push(`<${s}${f}>`), o.unshift(`</${s}>`), c = g.replace(a, "").trim();
20
31
  }
21
- return i.length > 0 ? i.join("") + t + s.join("") : t;
32
+ return i.length > 0 ? i.join("") + n + o.join("") : n;
22
33
  }
23
34
  export {
24
- H as preserveTextStyles
35
+ T as preserveTextStyles
25
36
  };
@@ -0,0 +1,46 @@
1
+ function a(t) {
2
+ return typeof t == "object" && t !== null && "tagName" in t && typeof t.tagName == "string";
3
+ }
4
+ function r(t) {
5
+ return typeof t == "object" && t !== null && "getTagName" in t && typeof t.getTagName == "function";
6
+ }
7
+ function n(t) {
8
+ return typeof t == "object" && t !== null && "getStyle" in t && typeof t.getStyle == "function";
9
+ }
10
+ function u(t) {
11
+ return typeof t == "object" && t !== null && "parent" in t && typeof t.parent == "function";
12
+ }
13
+ function g(t) {
14
+ return typeof t == "object" && t !== null && "tagName" in t && t.tagName === "TD";
15
+ }
16
+ function p(t, e) {
17
+ return !t || !n(t) ? null : t.getStyle(e);
18
+ }
19
+ function N(t) {
20
+ return !t || !u(t) ? null : t.parent();
21
+ }
22
+ function l(t, e = "UNKNOWN") {
23
+ return t ? a(t) ? t.tagName.toUpperCase() : r(t) ? t.getTagName().toUpperCase() : e : e;
24
+ }
25
+ const f = /* @__PURE__ */ new Set(["TD", "BLOCK_IMAGE", "BLOCK_BUTTON"]);
26
+ function i(t) {
27
+ return f.has(t.toUpperCase());
28
+ }
29
+ function c(t) {
30
+ const e = l(t);
31
+ return i(e);
32
+ }
33
+ function s(t) {
34
+ return c(t) ? "table-cell" : "table-row";
35
+ }
36
+ export {
37
+ s as getTableDisplayValue,
38
+ l as getTagName,
39
+ n as hasGetStyle,
40
+ u as hasParent,
41
+ c as isTableCellNode,
42
+ i as isTableCellTag,
43
+ g as isTdNode,
44
+ N as safeGetParent,
45
+ p as safeGetStyle
46
+ };
@@ -1,21 +1,21 @@
1
1
  import { ExtensionBuilder as e } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
2
  import { UnsubscribeBlock as i } from "./block.js";
3
3
  import { UnsubscribeControl as t } from "./control.js";
4
- import { PreviewUIElement as o } from "./elements/preview.js";
5
- import { UnsubscribeIconsRegistry as r } from "./iconsRegistry.js";
6
- import { SettingsPanel as s } from "./settingsPanel.js";
4
+ import { PreviewUIElement as s } from "./elements/preview.js";
5
+ import { UnsubscribeIconsRegistry as o } from "./iconsRegistry.js";
6
+ import { SettingsPanel as r } from "./settingsPanel.js";
7
7
  import n from "./styles.css.js";
8
- import { UnsubscribeTagRegistry as l } from "./tagRegistry.js";
9
- const f = new e().addBlock(i).withSettingsPanelRegistry(s).addControl(t).addUiElement(o).addStyles(n).withLocalization({
8
+ import { UnsubscribeTagRegistry as c } from "./tagRegistry.js";
9
+ const g = new e().addBlock(i).withSettingsPanelRegistry(r).addControl(t).addUiElement(s).addStyles(n).withLocalization({
10
10
  en: {
11
- "Unsubscribe Block": "Unsubscribe Block",
12
- "Unsubscribe Block Description": "Add an unsubscribe link to your email",
11
+ "Unsubscribe Block": "Unsubscribe",
12
+ "Unsubscribe Block Description": "Unsubscribe lets you add an Unsubscribe Link to direct users to opt out of receiving your messages.",
13
13
  "Select Template": "Select Template",
14
14
  "Unsubscribe Template": "Unsubscribe Template",
15
15
  Showing: "Showing",
16
16
  of: "of"
17
17
  }
18
- }).withUiElementTagRegistry(l).withIconsRegistry(r).build();
18
+ }).withUiElementTagRegistry(c).withIconsRegistry(o).build();
19
19
  export {
20
- f as default
20
+ g as default
21
21
  };
@@ -1,12 +1,12 @@
1
1
  var c = Object.defineProperty;
2
2
  var I = (a, r, e) => r in a ? c(a, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[r] = e;
3
- var l = (a, r, e) => I(a, typeof r != "symbol" ? r + "" : r, e);
3
+ var u = (a, r, e) => I(a, typeof r != "symbol" ? r + "" : r, e);
4
4
  import { Control as O, UIElementType as t, UEAttr as $ } from "../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
5
  class _ extends O {
6
6
  constructor() {
7
7
  super(...arguments);
8
- l(this, "currentNode");
9
- l(this, "lastBlockInstanceId", null);
8
+ u(this, "currentNode");
9
+ u(this, "lastBlockInstanceId", null);
10
10
  }
11
11
  getContainer() {
12
12
  var e;
@@ -52,10 +52,9 @@ class _ extends O {
52
52
  const T = o !== this.lastBlockInstanceId;
53
53
  return T ? (this.currentNode && e(this.currentNode), n(), this.lastBlockInstanceId = o) : n(), T;
54
54
  }
55
- _GuLabel({ text: e, name: n = "", position: E = "top" }) {
55
+ _GuLabel({ text: e, name: n = "" }) {
56
56
  return `
57
57
  <${t.LABEL}
58
- style="${E === "top" ? "margin-bottom: 8px;" : ""}"
59
58
  ${$.LABEL.text}="${e}"
60
59
  ${$.LABEL.name}="${n || `${e} Label`}">
61
60
  </${t.LABEL}>
@@ -170,9 +169,9 @@ class _ extends O {
170
169
  _GuOrderable(e, n) {
171
170
  let E = "";
172
171
  n.forEach((T) => {
173
- const u = $.ORDERABLE_ITEM && "name" in $.ORDERABLE_ITEM ? $.ORDERABLE_ITEM.name : "name";
172
+ const l = $.ORDERABLE_ITEM && "name" in $.ORDERABLE_ITEM ? $.ORDERABLE_ITEM.name : "name";
174
173
  E += `
175
- <${t.ORDERABLE_ITEM} ${u}="${T.key}">
174
+ <${t.ORDERABLE_ITEM} ${l}="${T.key}">
176
175
  ${T.content}
177
176
  </${t.ORDERABLE_ITEM}>
178
177
  `;
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- .gap-16[data-v-6562e38c],.gap-16[data-v-1ccb6d4a]{gap:16px}[data-v-06e6f7a7] .in-button-v2__wrapper{line-height:0}[data-v-b5997368] .in-segments-wrapper .in-tooltip-wrapper__box{text-align:left}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history-wrapper[data-v-52a77eec]{gap:8px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-890b5336]{position:relative;width:100%;height:calc(100vh - 128px)}.guido-editor__container[data-v-890b5336]{width:100%;height:calc(100vh - 128px)}.guido-editor__no-header[data-v-890b5336]{height:calc(100vh - 75px)}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-a86fc486]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-a86fc486]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-a86fc486]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-a86fc486]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-a86fc486]{object-fit:cover;transform:scale(1)}[data-v-bb3bb07c] .guido__verion-history-view-option-selection-desktop svg,[data-v-bb3bb07c] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-bb3bb07c] .in-segments-wrapper__button_selected,[data-v-bb3bb07c] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-7a09985c]{gap:16px}[data-v-c2adc57d] .in-progress-wrapper__progress p span:last-child{display:none!important}.desktop-preview-container[data-v-2dd60b0c],[data-v-2dd60b0c] .desktop-preview-container .in-container{min-height:720px!important;height:100%}.cropped-text[data-v-4b876c1b]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}[data-v-d3c52b44] .vueperslides__bullets,[data-v-dd1a237a] .vueperslides__bullets{pointer-events:none!important}[data-v-dd1a237a] .vueperslides__parallax-wrapper{height:110px!important}[data-v-a408dcea] .vueperslides__bullets{pointer-events:none!important}[data-v-a408dcea] .vueperslides__parallax-wrapper{height:110px!important}
1
+ .gap-16[data-v-6562e38c],.gap-16[data-v-1ccb6d4a]{gap:16px}[data-v-06e6f7a7] .in-button-v2__wrapper{line-height:0}[data-v-5196584c] .in-segments-wrapper .in-tooltip-wrapper__box{text-align:left}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history-wrapper[data-v-52a77eec]{gap:8px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-890b5336]{position:relative;width:100%;height:calc(100vh - 128px)}.guido-editor__container[data-v-890b5336]{width:100%;height:calc(100vh - 128px)}.guido-editor__no-header[data-v-890b5336]{height:calc(100vh - 75px)}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-a86fc486]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-a86fc486]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-a86fc486]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-a86fc486]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-a86fc486]{object-fit:cover;transform:scale(1)}[data-v-bb3bb07c] .guido__verion-history-view-option-selection-desktop svg,[data-v-bb3bb07c] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-bb3bb07c] .in-segments-wrapper__button_selected,[data-v-bb3bb07c] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-7a09985c]{gap:16px}[data-v-c2adc57d] .in-progress-wrapper__progress p span:last-child{display:none!important}.desktop-preview-container[data-v-2dd60b0c],[data-v-2dd60b0c] .desktop-preview-container .in-container{min-height:720px!important;height:100%}.cropped-text[data-v-4b876c1b]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}[data-v-d3c52b44] .vueperslides__bullets,[data-v-dd1a237a] .vueperslides__bullets{pointer-events:none!important}[data-v-dd1a237a] .vueperslides__parallax-wrapper{height:110px!important}[data-v-a408dcea] .vueperslides__bullets{pointer-events:none!important}[data-v-a408dcea] .vueperslides__parallax-wrapper{height:110px!important}
@@ -7,8 +7,8 @@
7
7
  * - Default values for optional configuration
8
8
  * - Validation utilities
9
9
  */
10
- export { MessageType, ProductType, GuidoConfigSchema, IdentitySchema, PartnerSchema, TemplateSchema, EditorSchema, UISchema, FeaturesSchema, BlocksSchema, CompilerSchema, DynamicContentSchema, EmailHeaderSchema, DefaultBlockTypeSchema, CustomBlockTypeSchema, CompilerRuleSchema, CompilerRuleTypeSchema, ReplaceRuleSchema, RegexRuleSchema, RemoveRuleSchema, CustomRuleSchema, } from './schemas';
11
- export type { GuidoConfig, GuidoConfigInput, IdentityConfig, IdentityConfigInput, PartnerConfig, PartnerConfigInput, TemplateConfig, TemplateConfigInput, EditorConfig, EditorConfigInput, UIConfig, UIConfigInput, FeaturesConfig, FeaturesConfigInput, BlocksConfig, BlocksConfigInput, CompilerConfig, CompilerConfigInput, EmailHeader, DynamicContent, DefaultBlockType, CustomBlockType, BlockType, FeatureName, CompilerRule, ReplaceRule, RegexRule, RemoveRule, CustomRule, DeepPartial, ConfigOverrides, } from './types';
10
+ export { MessageType, ProductType, GuidoConfigSchema, IdentitySchema, PartnerSchema, TemplateSchema, EditorSchema, UISchema, FeaturesSchema, BlocksSchema, CompilerSchema, CallbacksSchema, DynamicContentSchema, EmailHeaderSchema, DefaultBlockTypeSchema, CustomBlockTypeSchema, CompilerRuleSchema, CompilerRuleTypeSchema, ReplaceRuleSchema, RegexRuleSchema, RemoveRuleSchema, CustomRuleSchema, } from './schemas';
11
+ export type { GuidoConfig, GuidoConfigInput, IdentityConfig, IdentityConfigInput, PartnerConfig, PartnerConfigInput, TemplateConfig, TemplateConfigInput, EditorConfig, EditorConfigInput, UIConfig, UIConfigInput, FeaturesConfig, FeaturesConfigInput, BlocksConfig, BlocksConfigInput, CompilerConfig, CompilerConfigInput, CallbacksConfig, CallbacksConfigInput, ExternalValidationHandler, EmailHeader, DynamicContent, DefaultBlockType, CustomBlockType, BlockType, FeatureName, CompilerRule, ReplaceRule, RegexRule, RemoveRule, CustomRule, DeepPartial, ConfigOverrides, } from './types';
12
12
  export { DEFAULT_EMAIL_HEADER, DEFAULT_TEMPLATE, DEFAULT_EDITOR, DEFAULT_UI, DEFAULT_FEATURES, DEFAULT_BLOCKS, DEFAULT_COMPILER, DEFAULT_PRODUCT_TYPE, DEFAULT_MESSAGE_TYPE, DEFAULT_USERNAME, EDITOR_TYPE, TEST_PARTNERS, isTestPartner, } from './defaults';
13
13
  export { validateConfig, parseConfig, parseConfigSafe, getValidationErrors, isValidConfig, validateIdentity, validatePartner, } from './validator';
14
14
  export type { ValidationResult, ValidationError, } from './validator';
@@ -5,7 +5,14 @@
5
5
  * All types are inferred from these schemas to ensure single source of truth.
6
6
  * @module @types/config/schemas
7
7
  */
8
+ import type { SavedTemplateDetails } from '../stripo';
8
9
  import * as v from 'valibot';
10
+ /**
11
+ * Handler function for external validation before save
12
+ * @param data - The template details to validate
13
+ * @returns Promise<boolean> - true if valid, false to cancel save
14
+ */
15
+ export type ExternalValidationHandler = (data: SavedTemplateDetails) => Promise<boolean>;
9
16
  /**
10
17
  * Message type constants for email templates
11
18
  */
@@ -346,6 +353,16 @@ export declare const CompilerSchema: v.ObjectSchema<{
346
353
  /** Skip default compiler rules */
347
354
  readonly ignoreDefaultRules: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
348
355
  }, undefined>;
356
+ /**
357
+ * Callbacks configuration - event handlers and hooks
358
+ */
359
+ export declare const CallbacksSchema: v.ObjectSchema<{
360
+ /**
361
+ * External validation handler called before save completes.
362
+ * Return false to cancel the save operation.
363
+ */
364
+ readonly externalValidation: v.OptionalSchema<v.CustomSchema<ExternalValidationHandler, v.ErrorMessage<v.CustomIssue> | undefined>, undefined>;
365
+ }, undefined>;
349
366
  /**
350
367
  * Complete Guido configuration schema
351
368
  *
@@ -358,6 +375,7 @@ export declare const CompilerSchema: v.ObjectSchema<{
358
375
  * - features: Feature toggles
359
376
  * - blocks: Block configuration
360
377
  * - compiler: HTML compilation
378
+ * - callbacks: Event handlers and hooks
361
379
  */
362
380
  export declare const GuidoConfigSchema: v.ObjectSchema<{
363
381
  /** Identity configuration (required) */
@@ -510,4 +528,12 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
510
528
  /** Skip default compiler rules */
511
529
  readonly ignoreDefaultRules: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
512
530
  }, undefined>, {}>;
531
+ /** Callbacks and event handlers */
532
+ readonly callbacks: v.OptionalSchema<v.ObjectSchema<{
533
+ /**
534
+ * External validation handler called before save completes.
535
+ * Return false to cancel the save operation.
536
+ */
537
+ readonly externalValidation: v.OptionalSchema<v.CustomSchema<ExternalValidationHandler, v.ErrorMessage<v.CustomIssue> | undefined>, undefined>;
538
+ }, undefined>, {}>;
513
539
  }, undefined>;
@@ -5,7 +5,7 @@
5
5
  * This ensures type definitions are always in sync with validation.
6
6
  * @module @types/config/types
7
7
  */
8
- import type { GuidoConfigSchema, IdentitySchema, PartnerSchema, TemplateSchema, EditorSchema, UISchema, FeaturesSchema, BlocksSchema, CompilerSchema, DynamicContentSchema, EmailHeaderSchema, CompilerRuleSchema, ReplaceRuleSchema, RegexRuleSchema, RemoveRuleSchema, CustomRuleSchema, DefaultBlockTypeSchema, CustomBlockTypeSchema } from './schemas';
8
+ import type { GuidoConfigSchema, IdentitySchema, PartnerSchema, TemplateSchema, EditorSchema, UISchema, FeaturesSchema, BlocksSchema, CompilerSchema, CallbacksSchema, DynamicContentSchema, EmailHeaderSchema, CompilerRuleSchema, ReplaceRuleSchema, RegexRuleSchema, RemoveRuleSchema, CustomRuleSchema, DefaultBlockTypeSchema, CustomBlockTypeSchema, ExternalValidationHandler } from './schemas';
9
9
  import type * as v from 'valibot';
10
10
  /**
11
11
  * Complete validated Guido configuration.
@@ -41,6 +41,10 @@ export type FeaturesConfig = v.InferOutput<typeof FeaturesSchema>;
41
41
  export type BlocksConfig = v.InferOutput<typeof BlocksSchema>;
42
42
  /** Compiler configuration (custom rules, ignore defaults) */
43
43
  export type CompilerConfig = v.InferOutput<typeof CompilerSchema>;
44
+ /** Callbacks configuration (event handlers and hooks) */
45
+ export type CallbacksConfig = v.InferOutput<typeof CallbacksSchema>;
46
+ /** Re-export ExternalValidationHandler for convenience */
47
+ export type { ExternalValidationHandler };
44
48
  /** Email header configuration (senderName, subject) */
45
49
  export type EmailHeader = v.InferOutput<typeof EmailHeaderSchema>;
46
50
  /** Dynamic content item */
@@ -85,6 +89,8 @@ export type FeaturesConfigInput = v.InferInput<typeof FeaturesSchema>;
85
89
  export type BlocksConfigInput = v.InferInput<typeof BlocksSchema>;
86
90
  /** Input type for compiler configuration */
87
91
  export type CompilerConfigInput = v.InferInput<typeof CompilerSchema>;
92
+ /** Input type for callbacks configuration */
93
+ export type CallbacksConfigInput = v.InferInput<typeof CallbacksSchema>;
88
94
  /** Default Stripo block types */
89
95
  export type DefaultBlockType = v.InferOutput<typeof DefaultBlockTypeSchema>;
90
96
  /** Custom Guido block types */
@@ -91,6 +91,9 @@ export declare const useConfig: () => {
91
91
  })[];
92
92
  ignoreDefaultRules: boolean;
93
93
  };
94
+ callbacks: {
95
+ externalValidation?: import("@@/Types/config").ExternalValidationHandler | undefined;
96
+ };
94
97
  } | null>;
95
98
  initialized: import("vue").Ref<boolean>;
96
99
  identity: import("vue").ComputedRef<{
@@ -177,6 +180,9 @@ export declare const useConfig: () => {
177
180
  })[];
178
181
  ignoreDefaultRules: boolean;
179
182
  } | null>;
183
+ callbacks: import("vue").ComputedRef<{
184
+ externalValidation?: import("@@/Types/config").ExternalValidationHandler | undefined;
185
+ } | null>;
180
186
  templateId: import("vue").ComputedRef<string>;
181
187
  userId: import("vue").ComputedRef<string>;
182
188
  variationId: import("vue").ComputedRef<string>;
@@ -9,4 +9,4 @@
9
9
  export { RecommendationBlockId } from './blockIds';
10
10
  export { RecommendationControlId } from './controlIds';
11
11
  export { CONTAINER_SELECTOR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, } from './selectors';
12
- export { DEFAULT_PRODUCTS_PER_ROW, DEFAULT_CARDS_IN_ROW, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_PRODUCTS_PER_ROW, } from './layout';
12
+ export { DEFAULT_PRODUCTS_PER_ROW, DEFAULT_CARDS_IN_ROW, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_PRODUCTS_PER_ROW, DEFAULT_COLUMN_SPACING, DEFAULT_ROW_SPACING, MIN_SPACING, MAX_SPACING, SPACING_STEP, } from './layout';