@useinsider/guido 3.2.0-beta.da93bda → 3.2.0-beta.dc55d68

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 (61) hide show
  1. package/dist/@types/config/schemas.js +150 -94
  2. package/dist/components/Guido.vue.js +1 -1
  3. package/dist/components/Guido.vue2.js +88 -87
  4. package/dist/composables/useRecommendation.js +16 -12
  5. package/dist/config/compiler/unsubscribeCompilerRules.js +40 -37
  6. package/dist/config/migrator/index.js +9 -9
  7. package/dist/config/migrator/recommendation/compositionMapper.js +98 -0
  8. package/dist/config/migrator/recommendation/extractors.js +27 -0
  9. package/dist/config/migrator/recommendation/htmlBuilder.js +496 -0
  10. package/dist/config/migrator/recommendation/parseLegacyConfig.js +33 -0
  11. package/dist/config/migrator/recommendation/settingsMapper.js +78 -0
  12. package/dist/config/migrator/recommendation/themeMapper.js +93 -0
  13. package/dist/config/migrator/recommendationMigrator.js +74 -290
  14. package/dist/enums/extensions/recommendationBlock.js +2 -1
  15. package/dist/enums/unsubscribe.js +34 -27
  16. package/dist/extensions/Blocks/Recommendation/block.js +35 -32
  17. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +5 -5
  18. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +228 -181
  19. package/dist/extensions/Blocks/Recommendation/services/configService.js +65 -29
  20. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +21 -19
  21. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +8 -8
  22. package/dist/extensions/Blocks/Recommendation/templates/utils.js +1 -1
  23. package/dist/extensions/Blocks/Recommendation/utils/preserveTextStyles.js +13 -22
  24. package/dist/guido.css +1 -1
  25. package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +258 -235
  26. package/dist/node_modules/valibot/dist/index.js +450 -235
  27. package/dist/package.json.js +1 -1
  28. package/dist/src/@types/config/defaults.d.ts +5 -1
  29. package/dist/src/@types/config/index.d.ts +3 -3
  30. package/dist/src/@types/config/schemas.d.ts +213 -0
  31. package/dist/src/@types/config/types.d.ts +9 -1
  32. package/dist/src/components/wrappers/WpModal.vue.d.ts +1 -1
  33. package/dist/src/composables/useConfig.d.ts +56 -0
  34. package/dist/src/composables/useRecommendation.test.d.ts +1 -0
  35. package/dist/src/config/migrator/index.d.ts +2 -1
  36. package/dist/src/config/migrator/recommendation/compositionMapper.d.ts +2 -0
  37. package/dist/src/config/migrator/recommendation/compositionMapper.test.d.ts +1 -0
  38. package/dist/src/config/migrator/recommendation/extractors.d.ts +7 -0
  39. package/dist/src/config/migrator/recommendation/extractors.test.d.ts +1 -0
  40. package/dist/src/config/migrator/recommendation/htmlBuilder.d.ts +11 -0
  41. package/dist/src/config/migrator/recommendation/parseLegacyConfig.d.ts +15 -0
  42. package/dist/src/config/migrator/recommendation/parseLegacyConfig.test.d.ts +1 -0
  43. package/dist/src/config/migrator/recommendation/settingsMapper.d.ts +7 -0
  44. package/dist/src/config/migrator/recommendation/settingsMapper.test.d.ts +1 -0
  45. package/dist/src/config/migrator/recommendation/themeMapper.d.ts +5 -0
  46. package/dist/src/config/migrator/recommendation/themeMapper.test.d.ts +1 -0
  47. package/dist/src/config/migrator/recommendation/types.d.ts +205 -0
  48. package/dist/src/config/migrator/recommendationMigrator.d.ts +13 -1
  49. package/dist/src/config/migrator/recommendationMigrator.test.d.ts +1 -0
  50. package/dist/src/enums/unsubscribe.d.ts +5 -0
  51. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.test.d.ts +1 -0
  52. package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +10 -0
  53. package/dist/src/extensions/Blocks/Recommendation/services/configService.test.d.ts +1 -0
  54. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +1 -1
  55. package/dist/src/extensions/Blocks/Recommendation/utils/preserveTextStyles.d.ts +0 -3
  56. package/dist/src/stores/config.d.ts +504 -0
  57. package/dist/src/utils/htmlEscape.d.ts +5 -0
  58. package/dist/src/utils/htmlEscape.test.d.ts +1 -0
  59. package/dist/utils/htmlEscape.js +13 -0
  60. package/package.json +7 -3
  61. package/dist/extensions/Blocks/Recommendation/templates/grid/migration.js +0 -251
@@ -1,8 +1,14 @@
1
- import { ModificationDescription as f } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
- import { CURRENT_CONFIG_VERSION as u, DEFAULT_NODE_CONFIG as e } from "../constants/defaultConfig.js";
3
- import { setCurrencyAttributes as g } from "../controls/main/utils.js";
4
- import { hasMinimalConfig as a } from "../types/nodeConfig.js";
5
- class C {
1
+ import { ModificationDescription as h } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ import { CURRENT_CONFIG_VERSION as l, DEFAULT_NODE_CONFIG as r } from "../constants/defaultConfig.js";
3
+ import { setCurrencyAttributes as D } from "../controls/main/utils.js";
4
+ import { hasMinimalConfig as A } from "../types/nodeConfig.js";
5
+ function S(e) {
6
+ return e === "." || e === "," || e === " ";
7
+ }
8
+ function N(e) {
9
+ return e === "." || e === "," || e === " " || e === "";
10
+ }
11
+ class V {
6
12
  // ========================================================================
7
13
  // Read Operations
8
14
  // ========================================================================
@@ -42,7 +48,7 @@ class C {
42
48
  return !1;
43
49
  try {
44
50
  const t = i.getNodeConfig();
45
- return a(t);
51
+ return A(t);
46
52
  } catch {
47
53
  return !1;
48
54
  }
@@ -77,8 +83,8 @@ class C {
77
83
  * @returns The new complete configuration
78
84
  */
79
85
  static updateConfig(i, t, o, n) {
80
- const s = this.getConfig(t), r = this.deepMerge(s, o);
81
- return this.saveConfig(i, t, r, n), r;
86
+ const c = this.getConfig(t), u = this.deepMerge(c, o);
87
+ return this.saveConfig(i, t, u, n), u;
82
88
  }
83
89
  /**
84
90
  * Initialize configuration for a new block
@@ -95,7 +101,7 @@ class C {
95
101
  */
96
102
  static initializeConfig(i, t, o) {
97
103
  const n = o ? this.mergeWithDefaults(o) : this.cloneDefaults();
98
- return this.saveConfig(i, t, n, "Initialize recommendation block"), g({
104
+ return this.saveConfig(i, t, n, "Initialize recommendation block"), D({
99
105
  currentNode: t,
100
106
  documentModifier: i.getDocumentModifier(),
101
107
  currency: n.currency
@@ -112,9 +118,9 @@ class C {
112
118
  */
113
119
  static saveConfig(i, t, o, n) {
114
120
  try {
115
- i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new f(n));
116
- } catch (s) {
117
- console.warn("[RecommendationConfigService] Failed to save config:", s);
121
+ i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new h(n));
122
+ } catch (c) {
123
+ console.warn("[RecommendationConfigService] Failed to save config:", c);
118
124
  }
119
125
  }
120
126
  // ========================================================================
@@ -125,23 +131,53 @@ class C {
125
131
  *
126
132
  * Reads existing data-attributes and creates a proper node config.
127
133
  * Used when loading templates created before node config was implemented.
134
+ *
135
+ * Sources, in priority order (later overrides earlier):
136
+ * 1. `esd-ext-config` JSON blob — emitted by the recommendation migrator and
137
+ * by hand-authored new templates. Carries the full RecommendationNodeConfig
138
+ * (strategy, language, currency, filters, productIds, etc.) which the
139
+ * discrete data-* attrs below cannot capture.
140
+ * 2. Discrete `data-*` attributes — runtime source of truth for
141
+ * layout/composition/spacing; controls keep these in sync as the user
142
+ * edits, so we let them override the JSON blob if they disagree.
143
+ * 3. `currency-*` attributes — durable currency source on the block element.
128
144
  * @param api - Stripo extension API with document modifier
129
145
  * @param node - The block node to migrate
130
146
  * @returns The migrated configuration
131
147
  */
132
148
  static migrateFromDataAttributes(i, t) {
133
149
  const o = {
134
- configVersion: u
150
+ configVersion: l
135
151
  };
136
152
  if ("getAttribute" in t && typeof t.getAttribute == "function") {
137
- const n = t.getAttribute("data-layout");
138
- n === "list" || n === "horizontal" ? o.layout = "list" : (n === "grid" || n === "vertical") && (o.layout = "grid");
139
- const s = t.getAttribute("data-card-composition");
140
- s && (o.composition = s.split(",").filter(Boolean));
141
- const r = t.getAttribute("data-column-spacing");
142
- r && (o.columnSpacing = parseInt(r) || e.columnSpacing);
143
- const c = t.getAttribute("data-row-spacing");
144
- c && (o.rowSpacing = parseInt(c) || e.rowSpacing);
153
+ const n = t.getAttribute("esd-ext-config");
154
+ if (n)
155
+ try {
156
+ const s = JSON.parse(n);
157
+ s && typeof s == "object" && (Object.assign(o, s), o.configVersion = l);
158
+ } catch {
159
+ }
160
+ const c = t.getAttribute("data-layout");
161
+ c === "list" || c === "horizontal" ? o.layout = "list" : (c === "grid" || c === "vertical") && (o.layout = "grid");
162
+ const u = t.getAttribute("data-card-composition");
163
+ u && (o.composition = u.split(",").filter(Boolean));
164
+ const p = t.getAttribute("data-column-spacing");
165
+ p && (o.columnSpacing = parseInt(p) || r.columnSpacing);
166
+ const b = t.getAttribute("data-row-spacing");
167
+ if (b && (o.rowSpacing = parseInt(b) || r.rowSpacing), !o.currency) {
168
+ const s = t.getAttribute("currency"), y = t.getAttribute("currency-symbol"), d = t.getAttribute("currency-alignment"), f = t.getAttribute("currency-thousand-separator"), g = t.getAttribute("currency-decimal-separator"), m = t.getAttribute("currency-decimal-count");
169
+ if (s || y || d || f || g || m) {
170
+ const a = r.currency, C = m ? parseInt(m) : NaN;
171
+ o.currency = {
172
+ code: s ?? a.code,
173
+ symbol: y ?? a.symbol,
174
+ alignment: d === "0" ? "before" : "after",
175
+ decimalCount: Number.isFinite(C) ? C : a.decimalCount,
176
+ decimalSeparator: S(g) ? g : a.decimalSeparator,
177
+ thousandSeparator: N(f) ? f : a.thousandSeparator
178
+ };
179
+ }
180
+ }
145
181
  }
146
182
  return this.initializeConfig(i, t, o);
147
183
  }
@@ -151,7 +187,7 @@ class C {
151
187
  * @returns True if migration is needed
152
188
  */
153
189
  static needsMigration(i) {
154
- return i ? this.hasConfig(i) ? this.getConfigVersion(i) < u : !0 : !1;
190
+ return i ? this.hasConfig(i) ? this.getConfigVersion(i) < l : !0 : !1;
155
191
  }
156
192
  // ========================================================================
157
193
  // Internal Helpers
@@ -161,12 +197,12 @@ class C {
161
197
  */
162
198
  static cloneDefaults() {
163
199
  return {
164
- ...e,
165
- currency: { ...e.currency },
166
- omnibusPrice: { ...e.omnibusPrice },
167
- omnibusDiscount: { ...e.omnibusDiscount },
168
- composition: [...e.composition],
169
- visibility: { ...e.visibility },
200
+ ...r,
201
+ currency: { ...r.currency },
202
+ omnibusPrice: { ...r.omnibusPrice },
203
+ omnibusDiscount: { ...r.omnibusDiscount },
204
+ composition: [...r.composition],
205
+ visibility: { ...r.visibility },
170
206
  filters: [],
171
207
  productIds: [],
172
208
  recommendationId: 0
@@ -236,5 +272,5 @@ class C {
236
272
  }
237
273
  }
238
274
  export {
239
- C as RecommendationConfigService
275
+ V as RecommendationConfigService
240
276
  };
@@ -1,4 +1,4 @@
1
- import { RecommendationFeedSourceMaps as g, getOperatorOptions as R, PriceAttributes as k } from "../../../../enums/extensions/recommendationBlock.js";
1
+ import { RecommendationFeedSourceMaps as g, getOperatorOptions as k, PriceAttributes as R } from "../../../../enums/extensions/recommendationBlock.js";
2
2
  import { useRecommendationApi as C } from "../../../../services/recommendationApi.js";
3
3
  import { useConfigStore as y } from "../../../../stores/config.js";
4
4
  import { defineStore as G } from "pinia";
@@ -6,7 +6,7 @@ import { DEFAULT_CARDS_IN_ROW as F } from "../constants/layout.js";
6
6
  import { EXCLUDED_ALGORITHM_IDS as w } from "../constants/defaultConfig.js";
7
7
  import { getDefaultProducts as S } from "../templates/utils.js";
8
8
  import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
9
- import { isFilterValid as D } from "../validation/filterSchema.js";
9
+ import { isFilterValid as P } from "../validation/filterSchema.js";
10
10
  const h = C();
11
11
  let m = null, u = null, d = null;
12
12
  function I() {
@@ -37,7 +37,7 @@ function I() {
37
37
  customAttributes: []
38
38
  };
39
39
  }
40
- function P() {
40
+ function D() {
41
41
  return {
42
42
  recommendationConfigs: I(),
43
43
  recommendationProducts: [],
@@ -132,7 +132,7 @@ const v = () => ({
132
132
  getFilterList() {
133
133
  return Object.values(this.filterList).map((t) => {
134
134
  let r;
135
- return t.type === "productAttribute" ? r = `product_attributes.${t.attributeName}` : k.includes(t.attributeName) ? r = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : r = t.attributeName, {
135
+ return t.type === "productAttribute" ? r = `product_attributes.${t.attributeName}` : R.includes(t.attributeName) ? r = `${t.attributeName}.${this.recommendationConfigs.currencySettings.value}` : r = t.attributeName, {
136
136
  text: t.displayName,
137
137
  value: r,
138
138
  type: t.attributeType
@@ -154,7 +154,7 @@ const v = () => ({
154
154
  setCurrentBlock(t) {
155
155
  this.blockStates[t] || (this.blockStates = {
156
156
  ...this.blockStates,
157
- [t]: P()
157
+ [t]: D()
158
158
  }), this.currentRecommendationId = t;
159
159
  },
160
160
  /**
@@ -203,7 +203,7 @@ const v = () => ({
203
203
  * Creates a filter with the first available attribute and operator pre-selected.
204
204
  */
205
205
  createDefaultFilter(t, r) {
206
- const [e] = this.getFilterList, [n] = R(e == null ? void 0 : e.type);
206
+ const [e] = this.getFilterList, [n] = k(e == null ? void 0 : e.type);
207
207
  return {
208
208
  type: "standardFilter",
209
209
  attribute: (e == null ? void 0 : e.value) ?? "",
@@ -306,10 +306,10 @@ const v = () => ({
306
306
  deleteFilterGroup(t) {
307
307
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
308
308
  return;
309
- const r = this.blockStates[this.currentRecommendationId], e = r.recommendationConfigs.filters.filter((i) => i.filterGroup !== t), n = [...new Set(e.map((i) => i.filterGroup))].sort((i, o) => i - o), c = new Map(n.map((i, o) => [i, o + 1]));
309
+ const r = this.blockStates[this.currentRecommendationId], e = r.recommendationConfigs.filters.filter((i) => i.filterGroup !== t), n = [...new Set(e.map((i) => i.filterGroup))].sort((i, o) => i - o), l = new Map(n.map((i, o) => [i, o + 1]));
310
310
  r.recommendationConfigs.filters = e.map((i) => ({
311
311
  ...i,
312
- filterGroup: c.get(i.filterGroup) ?? i.filterGroup
312
+ filterGroup: l.get(i.filterGroup) ?? i.filterGroup
313
313
  }));
314
314
  },
315
315
  updateFilter(t) {
@@ -320,7 +320,7 @@ const v = () => ({
320
320
  const n = [...r.recommendationConfigs.filters];
321
321
  n[e] = {
322
322
  ...t,
323
- isValid: D(t)
323
+ isValid: P(t)
324
324
  }, r.recommendationConfigs.filters = n;
325
325
  }
326
326
  },
@@ -334,7 +334,7 @@ const v = () => ({
334
334
  let i = 1;
335
335
  n = n.map((o) => o.filterGroup === t.filterGroup ? { ...o, filterNumber: i++ } : o);
336
336
  } else {
337
- const i = [...new Set(n.map((s) => s.filterGroup))].sort((s, l) => s - l), o = new Map(i.map((s, l) => [s, l + 1]));
337
+ const i = [...new Set(n.map((s) => s.filterGroup))].sort((s, c) => s - c), o = new Map(i.map((s, c) => [s, c + 1]));
338
338
  n = n.map((s) => ({
339
339
  ...s,
340
340
  filterGroup: o.get(s.filterGroup) ?? s.filterGroup
@@ -346,15 +346,15 @@ const v = () => ({
346
346
  addFilter(t) {
347
347
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
348
348
  return;
349
- const r = this.blockStates[this.currentRecommendationId], e = [...r.recommendationConfigs.filters], c = e.filter(
349
+ const r = this.blockStates[this.currentRecommendationId], e = [...r.recommendationConfigs.filters], l = e.filter(
350
350
  (o) => o.filterGroup === t.filterGroup
351
351
  ).length + 1, i = e.findLastIndex((o) => o.filterGroup === t.filterGroup);
352
352
  i !== -1 ? e.splice(i + 1, 0, {
353
353
  ...t,
354
- filterNumber: c
354
+ filterNumber: l
355
355
  }) : e.push({
356
356
  ...t,
357
- filterNumber: c
357
+ filterNumber: l
358
358
  }), r.recommendationConfigs.filters = e;
359
359
  },
360
360
  generateFilterQuery() {
@@ -379,7 +379,7 @@ const v = () => ({
379
379
  },
380
380
  async _doFetchProducts() {
381
381
  var p;
382
- const t = this.currentRecommendationId, r = this.blockStates[t], { recommendationConfigs: e } = r, n = e.filters.filter((a) => a.isValid), c = b(n), i = ((p = g.find((a) => a.key === e.strategy)) == null ? void 0 : p.path) || "", o = y(), s = {
382
+ const t = this.currentRecommendationId, r = this.blockStates[t], { recommendationConfigs: e } = r, n = e.filters.filter((a) => a.isValid), l = b(n), i = ((p = g.find((a) => a.key === e.strategy)) == null ? void 0 : p.path) || "", o = y(), s = parseInt(e.size) || 6, c = {
383
383
  locale: e.language,
384
384
  currency: e.currencySettings.value,
385
385
  partnerName: o.partnerName,
@@ -387,17 +387,19 @@ const v = () => ({
387
387
  details: !0,
388
388
  campaignId: o.variationId
389
389
  };
390
- e.strategy === "manualMerchandising" ? s.productId = e.productIds.join(",") : e.strategy === "similarViewed" && (s.productId = "{itemId}"), e.strategy === "userBased" && (s.userId = "{user_id}"), c && (s.filter = c), e.shuffleProducts && (s.shuffle = !0);
391
- const l = parseInt(e.size) || 6;
390
+ e.strategy === "manualMerchandising" ? c.productId = e.productIds.slice(0, s).join(",") : e.strategy === "similarViewed" && (c.productId = "{itemId}"), e.strategy === "userBased" && (c.userId = "{user_id}"), l && (c.filter = l), e.shuffleProducts && (c.shuffle = !0);
392
391
  let f;
393
392
  try {
394
- f = await h.fetchRecommendationProducts(i, s);
393
+ f = await h.fetchRecommendationProducts(i, c);
395
394
  } catch {
396
395
  f = [];
397
396
  }
398
397
  if (this.blockStates[t]) {
399
- const a = f.length > 0 ? f : S(l);
400
- this.blockStates[t].recommendationProducts = a.length < l ? [...a, ...S(l - a.length)] : a;
398
+ const a = f.length > 0 ? f : S(s);
399
+ a.length < s ? this.blockStates[t].recommendationProducts = [
400
+ ...a,
401
+ ...S(s - a.length)
402
+ ] : a.length > s ? this.blockStates[t].recommendationProducts = a.slice(0, s) : this.blockStates[t].recommendationProducts = a;
401
403
  }
402
404
  }
403
405
  }
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_PRODUCTS_PER_ROW as L } from "../../constants/layout.js";
2
- import { DEFAULT_CARD_COMPOSITION as E, spacer as I, getDefaultProducts as _, createBlockTemplate as S, DEFAULTS as b, buildElementRenderer as A, DEFAULT_CARD_VISIBILITY as f } from "../utils.js";
3
- import { gridElementRenderer as w, ATTRIBUTE_CELL_CLASS as D, DEFAULT_CELL_PADDING as C } from "./elementRenderer.js";
2
+ import { getDefaultProducts as E, createBlockTemplate as I, DEFAULTS as _, DEFAULT_CARD_COMPOSITION as S, spacer as b, buildElementRenderer as A, DEFAULT_CARD_VISIBILITY as f } from "../utils.js";
3
+ import { ATTRIBUTE_CELL_CLASS as w, DEFAULT_CELL_PADDING as D, gridElementRenderer as C } from "./elementRenderer.js";
4
4
  const O = `
5
5
  <tr class="recommendation-product-row">
6
6
  <td>
@@ -27,8 +27,8 @@ const O = `
27
27
  {-{-CELLS-}-}
28
28
  </tr>
29
29
  `;
30
- function P(t, e, o, r = E, n = {}) {
31
- const c = (100 / e).toFixed(2), i = e - t.length, l = `<td class="${D}" style="padding: ${C};" width="${c}%"></td>`, d = i > 0 ? l.repeat(i) : "", a = A(o, r, n);
30
+ function P(t, e, o, r = S, n = {}) {
31
+ const c = (100 / e).toFixed(2), i = e - t.length, l = `<td class="${w}" style="padding: ${D};" width="${c}%"></td>`, d = i > 0 ? l.repeat(i) : "", a = A(o, r, n);
32
32
  return r.filter((s) => a[s]).map((s) => {
33
33
  const T = f[s] ?? !0, u = T ? "" : 'style="display: none;"', R = t.map((m) => a[s](m).replace("<td", `<td width="${c}%"`)).join("");
34
34
  return g.replace("{-{-ATTR_TYPE-}-}", s).replace("{-{-VISIBILITY-}-}", T ? "1" : "0").replace("{-{-DISPLAY_STYLE-}-}", u).replace("{-{-CELLS-}-}", R + d);
@@ -46,15 +46,15 @@ function U(t, e, o, r, n = {}) {
46
46
  r,
47
47
  n
48
48
  ), p = O.replace("{-{-ATTRIBUTE_ROWS-}-}", a);
49
- return d > 0 ? I + p : p;
49
+ return d > 0 ? b + p : p;
50
50
  }).join("");
51
51
  }
52
52
  function h(t, e, o, r = {}) {
53
- return U(t, e, w, o, r);
53
+ return U(t, e, C, o, r);
54
54
  }
55
55
  function F(t) {
56
- const e = t ? `ins-recommendation-v3-block-${t}` : void 0, o = S("grid", e), r = _(), n = h(r, L);
57
- return o.replace("{-{-TITLE-}-}", b.TITLE).replace("{-{-PRODUCT_ROWS-}-}", n).replace("{-{-MOBILE_PRODUCT_ROWS-}-}", "");
56
+ const e = t ? `ins-recommendation-v3-block-${t}` : void 0, o = I("grid", e), r = E(), n = h(r, L);
57
+ return o.replace("{-{-TITLE-}-}", _.TITLE).replace("{-{-PRODUCT_ROWS-}-}", n).replace("{-{-MOBILE_PRODUCT_ROWS-}-}", "");
58
58
  }
59
59
  export {
60
60
  F as getDefaultTemplate,
@@ -1,4 +1,4 @@
1
- import { ATTR_PRODUCT_IMAGE as m, ATTR_PRODUCT_NAME as b, ATTR_PRODUCT_OLD_PRICE as T, ATTR_PRODUCT_PRICE as _, ATTR_PRODUCT_OMNIBUS_PRICE as g, ATTR_PRODUCT_OMNIBUS_DISCOUNT as C, ATTR_PRODUCT_BUTTON as f, ATTR_CUSTOM_PREFIX as u } from "../constants/selectors.js";
1
+ import { ATTR_CUSTOM_PREFIX as u, ATTR_PRODUCT_IMAGE as m, ATTR_PRODUCT_NAME as b, ATTR_PRODUCT_OLD_PRICE as T, ATTR_PRODUCT_PRICE as _, ATTR_PRODUCT_OMNIBUS_PRICE as g, ATTR_PRODUCT_OMNIBUS_DISCOUNT as C, ATTR_PRODUCT_BUTTON as f } from "../constants/selectors.js";
2
2
  function U(t) {
3
3
  return t.replace(/_/g, " ").replace(/\b\w/g, (e) => e.toUpperCase());
4
4
  }
@@ -1,36 +1,27 @@
1
- function m(t) {
2
- const e = {
3
- "&": "&amp;",
4
- "<": "&lt;",
5
- ">": "&gt;",
6
- '"': "&quot;",
7
- "'": "&#39;"
8
- };
9
- return t.replace(/[&<>"']/g, (n) => e[n]);
10
- }
11
- function p(t) {
1
+ import { escapeHtml as m } from "../../../../utils/htmlEscape.js";
2
+ function T(t) {
12
3
  return "getInnerHTML" in t && typeof t.getInnerHTML == "function" ? t.getInnerHTML().trim() : "innerHTML" in t ? t.innerHTML : "";
13
4
  }
14
- function T(t, e) {
15
- const n = m(e);
5
+ function H(t, f) {
6
+ const n = m(f);
16
7
  if (!t)
17
8
  return n;
18
- const r = p(t);
9
+ const r = T(t);
19
10
  if (!r || r.trim() === "" || !/<(strong|em|u|s|b|i)\b/i.test(r))
20
11
  return n;
21
- const i = [], o = [];
22
- let c = r.trim();
12
+ const e = [], s = [];
13
+ let o = r.trim();
23
14
  for (; ; ) {
24
- const u = c.match(/^<(strong|em|u|s|b|i)(\s[^>]*)?>(.*)$/is);
15
+ const u = o.match(/^<(strong|em|u|s|b|i)(\s[^>]*)?>(.*)$/is);
25
16
  if (!u)
26
17
  break;
27
- const [, s, f = "", g] = u, a = new RegExp(`</${s}>$`, "i");
28
- if (!a.test(g))
18
+ const [, i, a = "", c] = u, g = new RegExp(`</${i}>$`, "i");
19
+ if (!g.test(c))
29
20
  break;
30
- i.push(`<${s}${f}>`), o.unshift(`</${s}>`), c = g.replace(a, "").trim();
21
+ e.push(`<${i}${a}>`), s.unshift(`</${i}>`), o = c.replace(g, "").trim();
31
22
  }
32
- return i.length > 0 ? i.join("") + n + o.join("") : n;
23
+ return e.length > 0 ? e.join("") + n + s.join("") : n;
33
24
  }
34
25
  export {
35
- T as preserveTextStyles
26
+ H as preserveTextStyles
36
27
  };
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- .gap-16[data-v-3b53a736],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.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}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.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}.editor-actions[data-v-4e2a4adb]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-25780af6]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-25780af6]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-25780af6]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-df672485]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-df672485]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-df672485]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-df672485]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-df672485]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-7419ae06] .vueperslides__bullets,[data-v-796d193b] .vueperslides__bullets{pointer-events:none!important}[data-v-796d193b] .vueperslides__parallax-wrapper{height:110px!important}[data-v-cadfc82d] .vueperslides__bullets{pointer-events:none!important}[data-v-cadfc82d] .vueperslides__parallax-wrapper{height:110px!important}
1
+ .gap-16[data-v-3b53a736],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.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}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.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}.editor-actions[data-v-4e2a4adb]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-428c209a]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-428c209a]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-428c209a]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-df672485]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-df672485]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-df672485]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-df672485]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-df672485]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-7419ae06] .vueperslides__bullets,[data-v-796d193b] .vueperslides__bullets{pointer-events:none!important}[data-v-796d193b] .vueperslides__parallax-wrapper{height:110px!important}[data-v-cadfc82d] .vueperslides__bullets{pointer-events:none!important}[data-v-cadfc82d] .vueperslides__parallax-wrapper{height:110px!important}