@useinsider/guido 2.1.0-beta.6df87d7 → 2.1.0-beta.73f314b

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 (38) hide show
  1. package/README.md +36 -0
  2. package/dist/@types/config/schemas.js +70 -65
  3. package/dist/components/Guido.vue.js +1 -1
  4. package/dist/components/Guido.vue2.js +69 -58
  5. package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +11 -13
  6. package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +55 -24
  7. package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue.js +3 -3
  8. package/dist/components/organisms/extensions/recommendation/FilterSelectionDrawer.vue2.js +34 -21
  9. package/dist/components/organisms/extensions/recommendation/Filters.vue.js +11 -11
  10. package/dist/components/organisms/extensions/recommendation/Filters.vue2.js +44 -34
  11. package/dist/composables/useBlocksConfig.js +26 -16
  12. package/dist/composables/useHtmlValidator.js +107 -119
  13. package/dist/config/compiler/utils/recommendationCompilerUtils.js +27 -22
  14. package/dist/config/migrator/itemsBlockMigrator.js +101 -97
  15. package/dist/enums/defaults.js +8 -4
  16. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +117 -66
  17. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +95 -61
  18. package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +25 -30
  19. package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +20 -25
  20. package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +8 -8
  21. package/dist/extensions/Blocks/Recommendation/validation/filterSchema.js +29 -0
  22. package/dist/extensions/ModulesTabIcons/extension.js +17 -0
  23. package/dist/guido.css +1 -1
  24. package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +204 -136
  25. package/dist/services/stripoApi.js +20 -17
  26. package/dist/src/@types/config/schemas.d.ts +8 -0
  27. package/dist/src/components/organisms/extensions/recommendation/FilterItem.vue.d.ts +1 -0
  28. package/dist/src/components/organisms/extensions/recommendation/Filters.vue.d.ts +15 -1
  29. package/dist/src/composables/useConfig.d.ts +4 -0
  30. package/dist/src/enums/defaults.d.ts +4 -0
  31. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +17 -0
  32. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +18 -2
  33. package/dist/src/extensions/Blocks/Recommendation/validation/filterSchema.d.ts +15 -0
  34. package/dist/src/extensions/ModulesTabIcons/extension.d.ts +2 -0
  35. package/dist/src/stores/config.d.ts +36 -0
  36. package/dist/static/templates/empty/index.html.js +74 -0
  37. package/dist/static/templates/empty/style.css.js +779 -0
  38. package/package.json +1 -1
@@ -1,14 +1,15 @@
1
- import { RecommendationFeedSourceMaps as d, PriceAttributes as S } from "../../../../enums/extensions/recommendationBlock.js";
2
- import { useRecommendationApi as p } from "../../../../services/recommendationApi.js";
3
- import { useConfigStore as b } from "../../../../stores/config.js";
4
- import { defineStore as I } from "pinia";
5
- import { DEFAULT_CARDS_IN_ROW as R } from "../constants/layout.js";
6
- import { getDefaultProducts as k } from "../templates/utils.js";
1
+ import { RecommendationFeedSourceMaps as d, getOperatorOptions as S, PriceAttributes as p } from "../../../../enums/extensions/recommendationBlock.js";
2
+ import { useRecommendationApi as b } from "../../../../services/recommendationApi.js";
3
+ import { useConfigStore as I } from "../../../../stores/config.js";
4
+ import { defineStore as R } from "pinia";
5
+ import { DEFAULT_CARDS_IN_ROW as k } from "../constants/layout.js";
6
+ import { getDefaultProducts as C } from "../templates/utils.js";
7
7
  import { generateCompleteFilterQuery as f } from "../utils/filterUtil.js";
8
- const m = p();
8
+ import { isFilterValid as y } from "../validation/filterSchema.js";
9
+ const m = b();
9
10
  function h() {
10
11
  return {
11
- cardsInRow: R,
12
+ cardsInRow: k,
12
13
  currencySettings: {
13
14
  name: "USD",
14
15
  value: "USD",
@@ -32,17 +33,18 @@ function h() {
32
33
  size: "6"
33
34
  };
34
35
  }
35
- function C() {
36
+ function G() {
36
37
  return {
37
38
  recommendationConfigs: h(),
38
39
  recommendationProducts: [],
39
40
  filterStatus: !1,
40
41
  filterSelectionDrawerStatus: !1,
41
42
  filterGroup: 1,
42
- isInitialized: !1
43
+ isInitialized: !1,
44
+ filterSnapshot: null
43
45
  };
44
46
  }
45
- const y = () => ({
47
+ const F = () => ({
46
48
  recommendationCampaignUrls: {},
47
49
  activePredictiveAlgorithms: [],
48
50
  languages: {},
@@ -51,8 +53,8 @@ const y = () => ({
51
53
  blockStates: {},
52
54
  currentRecommendationId: null,
53
55
  configVersion: 0
54
- }), A = I("guidoRecommendationExtension", {
55
- state: () => y(),
56
+ }), V = R("guidoRecommendationExtension", {
57
+ state: () => F(),
56
58
  getters: {
57
59
  // ====================================================================
58
60
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -94,9 +96,17 @@ const y = () => ({
94
96
  hasFilters() {
95
97
  return !!this.recommendationConfigs.filters.length;
96
98
  },
99
+ hasValidFilters() {
100
+ const { filters: t } = this.recommendationConfigs;
101
+ return t.length ? t.every((r) => r.isValid) : !1;
102
+ },
97
103
  getFilterGroupCount() {
98
104
  const { filters: t } = this.recommendationConfigs;
99
- return t.length && t[t.length - 1].filterGroup || 0;
105
+ return t.length ? new Set(t.map((r) => r.filterGroup)).size : 0;
106
+ },
107
+ getUniqueFilterGroups() {
108
+ const { filters: t } = this.recommendationConfigs;
109
+ return [...new Set(t.map((r) => r.filterGroup))].sort((r, e) => r - e);
100
110
  },
101
111
  getActivePredictiveAlgorithms: (t) => {
102
112
  const r = [];
@@ -117,7 +127,7 @@ const y = () => ({
117
127
  })),
118
128
  getFilterList() {
119
129
  return Object.values(this.filterList).map((t) => {
120
- const r = t.type === "defaultAttribute", e = S.includes(t.attributeName);
130
+ const r = t.type === "defaultAttribute", e = p.includes(t.attributeName);
121
131
  let n = r ? t.attributeName : `product_attributes.${t.attributeName}`;
122
132
  return n = e ? `${n}.${this.recommendationConfigs.currencySettings.value}` : n, {
123
133
  text: t.displayName,
@@ -141,7 +151,7 @@ const y = () => ({
141
151
  setCurrentBlock(t) {
142
152
  this.blockStates[t] || (this.blockStates = {
143
153
  ...this.blockStates,
144
- [t]: C()
154
+ [t]: G()
145
155
  }), this.currentRecommendationId = t;
146
156
  },
147
157
  /**
@@ -181,33 +191,56 @@ const y = () => ({
181
191
  const { triggerRefetch: n = !0 } = r;
182
192
  n && this.configVersion++;
183
193
  },
194
+ /**
195
+ * Creates a filter with the first available attribute and operator pre-selected.
196
+ */
197
+ createDefaultFilter(t, r) {
198
+ const [e] = this.getFilterList, [n] = S(e == null ? void 0 : e.type);
199
+ return {
200
+ type: "standardFilter",
201
+ attribute: (e == null ? void 0 : e.value) ?? "",
202
+ operator: (n == null ? void 0 : n.value) ?? "",
203
+ innerGroupOperator: "*",
204
+ outerGroupOperator: "*",
205
+ filterNumber: r,
206
+ filterGroup: t,
207
+ isValid: !1,
208
+ value: ""
209
+ };
210
+ },
184
211
  /**
185
212
  * Opens the filter selection drawer for the current block.
186
- * If no filters exist, initializes with a default empty filter
213
+ * Saves a snapshot of current filters for cancel/revert.
214
+ * If no filters exist, initializes with a default filter
187
215
  * so the user has a starting point for input.
188
216
  */
189
217
  openFilterDrawer() {
190
218
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
191
219
  return;
192
220
  const t = this.blockStates[this.currentRecommendationId];
193
- t.recommendationConfigs.filters.length || (t.recommendationConfigs.filters = [{
194
- type: "standardFilter",
195
- attribute: "",
196
- operatorReplace: "",
197
- operator: "",
198
- innerGroupOperator: "*",
199
- outerGroupOperator: "*",
200
- filterNumber: 1,
201
- filterGroup: 1,
202
- isValid: !1,
203
- value: ""
204
- }]), t.filterSelectionDrawerStatus = !0;
221
+ t.filterSnapshot = JSON.parse(
222
+ JSON.stringify(t.recommendationConfigs.filters)
223
+ ), t.recommendationConfigs.filters.length || (t.recommendationConfigs.filters = [this.createDefaultFilter(1, 1)]), t.filterSelectionDrawerStatus = !0;
205
224
  },
206
225
  /**
207
- * Closes the filter selection drawer for the current block
226
+ * Closes the filter selection drawer for the current block.
227
+ * Called after successful apply — discards the snapshot.
208
228
  */
209
229
  closeFilterDrawer() {
210
- this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].filterSelectionDrawerStatus = !1);
230
+ if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
231
+ return;
232
+ const t = this.blockStates[this.currentRecommendationId];
233
+ t.filterSnapshot = null, t.filterSelectionDrawerStatus = !1;
234
+ },
235
+ /**
236
+ * Cancels the filter selection drawer and reverts filters
237
+ * to the snapshot taken when the drawer was opened.
238
+ */
239
+ cancelFilterDrawer() {
240
+ if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
241
+ return;
242
+ const t = this.blockStates[this.currentRecommendationId];
243
+ t.filterSnapshot !== null && (t.recommendationConfigs.filters = t.filterSnapshot, t.filterSnapshot = null), t.filterSelectionDrawerStatus = !1;
211
244
  },
212
245
  // ====================================================================
213
246
  // Shared Data Fetching (fetched once, used by all blocks)
@@ -220,11 +253,9 @@ const y = () => ({
220
253
  languages: r,
221
254
  currencies: e
222
255
  } = await m.fetchRecommendationCreateData();
223
- this.activePredictiveAlgorithms = t, this.languages = r;
224
- const [n] = e, o = n.value.includes(".") ? n.value.split(".")[1] : n.value;
225
- if (this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
226
- const i = this.blockStates[this.currentRecommendationId];
227
- i.recommendationConfigs.currencySettings.name = n.text, i.recommendationConfigs.currencySettings.value = o, i.filterStatus = !!i.recommendationConfigs.filters.length;
256
+ if (this.activePredictiveAlgorithms = t, this.languages = r, this.currentRecommendationId !== null && this.blockStates[this.currentRecommendationId]) {
257
+ const n = this.blockStates[this.currentRecommendationId];
258
+ n.filterStatus = !!n.recommendationConfigs.filters.length;
228
259
  }
229
260
  this.currencyList = e;
230
261
  },
@@ -236,18 +267,18 @@ const y = () => ({
236
267
  // Per-Block Filter Actions
237
268
  // ====================================================================
238
269
  addFilterGroup(t) {
239
- this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || this.blockStates[this.currentRecommendationId].recommendationConfigs.filters.push({
240
- type: "standardFilter",
241
- attribute: "",
242
- operatorReplace: "",
243
- operator: "",
244
- innerGroupOperator: "",
245
- outerGroupOperator: "",
246
- value: "",
247
- filterNumber: 1,
248
- isValid: !0,
249
- filterGroup: t
250
- });
270
+ this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || this.blockStates[this.currentRecommendationId].recommendationConfigs.filters.push(
271
+ this.createDefaultFilter(t, 1)
272
+ );
273
+ },
274
+ deleteFilterGroup(t) {
275
+ if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
276
+ return;
277
+ 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), s = new Map(n.map((i, o) => [i, o + 1]));
278
+ r.recommendationConfigs.filters = e.map((i) => ({
279
+ ...i,
280
+ filterGroup: s.get(i.filterGroup) ?? i.filterGroup
281
+ }));
251
282
  },
252
283
  updateFilter(t) {
253
284
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
@@ -255,7 +286,10 @@ const y = () => ({
255
286
  const r = this.blockStates[this.currentRecommendationId], e = r.recommendationConfigs.filters.findIndex((n) => n.filterNumber === t.filterNumber && n.filterGroup === t.filterGroup);
256
287
  if (e !== -1) {
257
288
  const n = [...r.recommendationConfigs.filters];
258
- n[e] = t, t.value.length && t.operator && t.attribute && t.innerGroupOperator && t.outerGroupOperator ? n[e].isValid = !0 : n[e].isValid = !1, r.recommendationConfigs.filters = n;
289
+ n[e] = {
290
+ ...t,
291
+ isValid: y(t)
292
+ }, r.recommendationConfigs.filters = n;
259
293
  }
260
294
  },
261
295
  deleteFilter(t) {
@@ -270,15 +304,15 @@ const y = () => ({
270
304
  addFilter(t) {
271
305
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
272
306
  return;
273
- const r = this.blockStates[this.currentRecommendationId], e = [...r.recommendationConfigs.filters], o = e.filter(
274
- (c) => c.filterGroup === t.filterGroup
275
- ).length + 1, i = e.findLastIndex((c) => c.filterGroup === t.filterGroup);
307
+ const r = this.blockStates[this.currentRecommendationId], e = [...r.recommendationConfigs.filters], s = e.filter(
308
+ (o) => o.filterGroup === t.filterGroup
309
+ ).length + 1, i = e.findLastIndex((o) => o.filterGroup === t.filterGroup);
276
310
  i !== -1 ? e.splice(i + 1, 0, {
277
311
  ...t,
278
- filterNumber: o
312
+ filterNumber: s
279
313
  }) : e.push({
280
314
  ...t,
281
- filterNumber: o
315
+ filterNumber: s
282
316
  }), r.recommendationConfigs.filters = e;
283
317
  },
284
318
  generateFilterQuery() {
@@ -291,26 +325,26 @@ const y = () => ({
291
325
  var u;
292
326
  if (this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId])
293
327
  return;
294
- const t = this.currentRecommendationId, r = this.blockStates[t], { recommendationConfigs: e } = r, n = e.filters.filter((l) => l.isValid), o = f(n), i = ((u = d.find((l) => l.key === e.strategy)) == null ? void 0 : u.path) || "", c = b(), s = {
328
+ const t = this.currentRecommendationId, r = this.blockStates[t], { recommendationConfigs: e } = r, n = e.filters.filter((l) => l.isValid), s = f(n), i = ((u = d.find((l) => l.key === e.strategy)) == null ? void 0 : u.path) || "", o = I(), c = {
295
329
  locale: e.language,
296
330
  currency: e.currencySettings.value,
297
- partnerName: c.partnerName,
331
+ partnerName: o.partnerName,
298
332
  size: e.size,
299
333
  details: !0,
300
- campaignId: c.variationId
334
+ campaignId: o.variationId
301
335
  };
302
- e.strategy === "manualMerchandising" ? s.productId = e.productIds.join(",") : e.strategy === "similarViewed" && (s.productId = "{itemId}"), o && (s.filter = o), e.shuffleProducts && (s.shuffle = !0);
336
+ e.strategy === "manualMerchandising" ? c.productId = e.productIds.join(",") : e.strategy === "similarViewed" && (c.productId = "{itemId}"), s && (c.filter = s), e.shuffleProducts && (c.shuffle = !0);
303
337
  const g = parseInt(e.size) || 6;
304
338
  let a;
305
339
  try {
306
- a = await m.fetchRecommendationProducts(i, s);
340
+ a = await m.fetchRecommendationProducts(i, c);
307
341
  } catch {
308
342
  a = [];
309
343
  }
310
- this.blockStates[t] && (this.blockStates[t].recommendationProducts = a.length > 0 ? a : k(g));
344
+ this.blockStates[t] && (this.blockStates[t].recommendationProducts = a.length > 0 ? a : C(g));
311
345
  }
312
346
  }
313
347
  });
314
348
  export {
315
- A as useRecommendationExtensionStore
349
+ V as useRecommendationExtensionStore
316
350
  };
@@ -3,7 +3,7 @@ import { ATTR_PRODUCT_BUTTON as b, ATTR_PRODUCT_OMNIBUS_DISCOUNT as u, ATTR_PROD
3
3
  import { useRecommendationExtensionStore as T } from "../../store/recommendation.js";
4
4
  import { formatPrice as _ } from "../../utils/priceFormatter.js";
5
5
  import { sanitizeImageUrl as $ } from "../utils.js";
6
- const o = "0 5px", a = "attribute-cell";
6
+ const a = "0 5px", o = "attribute-cell";
7
7
  function p() {
8
8
  const t = T(), { currencySettings: e } = t.recommendationConfigs;
9
9
  return {
@@ -15,16 +15,16 @@ function p() {
15
15
  thousandSeparator: e.thousandSeparator
16
16
  };
17
17
  }
18
- function r(t, e = "price") {
19
- const n = p(), l = t[e], i = (l == null ? void 0 : l[n.code]) ?? Object.values(l ?? {})[0] ?? 0;
18
+ function c(t, e = "price") {
19
+ const n = p(), l = t[e], r = (l == null ? void 0 : l[n.code]) ?? Object.values(l ?? {})[0] ?? 0;
20
20
  return _({
21
- price: i,
21
+ price: r,
22
22
  currency: n
23
23
  });
24
24
  }
25
25
  const P = {
26
26
  [x]: (t) => `
27
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="top">
27
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="top">
28
28
  <table
29
29
  class="product-card-segment"
30
30
  width="100%"
@@ -38,18 +38,13 @@ const P = {
38
38
  class="esd-block-image product-image"
39
39
  align="center"
40
40
  esd-extension-block-id="${s.IMAGE}">
41
- <div style="position: relative; width: 100%; padding-bottom: 100%; overflow: hidden;">
42
- <a
43
- target="_blank"
44
- href="${t.url}"
45
- style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
46
- <img
47
- src="${$(t.image_url)}"
48
- alt="${t.name}"
49
- style="max-width: 100%; max-height: 100%; object-fit: contain; display: block;"
50
- class="adapt-img">
51
- </a>
52
- </div>
41
+ <a target="_blank" href="${t.url}">
42
+ <img
43
+ src="${$(t.image_url)}"
44
+ alt="${t.name}"
45
+ style="display: block; max-width: 100%; height: auto;"
46
+ class="adapt-img">
47
+ </a>
53
48
  </td>
54
49
  </tr>
55
50
  </tbody>
@@ -57,7 +52,7 @@ const P = {
57
52
  </td>
58
53
  `,
59
54
  [f]: (t) => `
60
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="middle">
55
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="middle">
61
56
  <table
62
57
  class="product-card-segment"
63
58
  width="100%"
@@ -82,7 +77,7 @@ const P = {
82
77
  </td>
83
78
  `,
84
79
  [y]: (t) => `
85
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="top">
80
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="top">
86
81
  <table
87
82
  class="product-card-segment"
88
83
  width="100%"
@@ -97,7 +92,7 @@ const P = {
97
92
  align="center"
98
93
  esd-extension-block-id="${s.PRICE}">
99
94
  <p contenteditable="false" style="font-size: 16px; color: #333333;">
100
- <strong>${r(t, "price")}</strong>
95
+ <strong>${c(t, "price")}</strong>
101
96
  </p>
102
97
  </td>
103
98
  </tr>
@@ -106,7 +101,7 @@ const P = {
106
101
  </td>
107
102
  `,
108
103
  [h]: (t) => `
109
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="top">
104
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="top">
110
105
  <table
111
106
  class="product-card-segment"
112
107
  width="100%"
@@ -121,7 +116,7 @@ const P = {
121
116
  align="center"
122
117
  esd-extension-block-id="${s.OLD_PRICE}">
123
118
  <p contenteditable="false" style="font-size: 14px; color: #999999;">
124
- <strong>${r(t, "original_price")}</strong>
119
+ <strong>${c(t, "original_price")}</strong>
125
120
  </p>
126
121
  </td>
127
122
  </tr>
@@ -130,7 +125,7 @@ const P = {
130
125
  </td>
131
126
  `,
132
127
  [m]: (t) => `
133
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="top">
128
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="top">
134
129
  <table
135
130
  class="product-card-segment"
136
131
  width="100%"
@@ -148,7 +143,7 @@ const P = {
148
143
  esd-extension-block-id="${s.OMNIBUS_PRICE}">
149
144
  <p style="font-size: 12px; color: #666666;">
150
145
  <span class="omnibus-text-before">Lowest 30-day price: </span>
151
- <span class="omnibus-price-value">${r(t, "original_price")}</span>
146
+ <span class="omnibus-price-value">${c(t, "original_price")}</span>
152
147
  <span class="omnibus-text-after"></span>
153
148
  </p>
154
149
  </td>
@@ -158,10 +153,10 @@ const P = {
158
153
  </td>
159
154
  `,
160
155
  [u]: (t) => {
161
- var d, c;
162
- const e = p(), n = ((d = t.original_price) == null ? void 0 : d[e.code]) ?? Object.values(t.original_price ?? {})[0] ?? 0, l = ((c = t.price) == null ? void 0 : c[e.code]) ?? Object.values(t.price ?? {})[0] ?? 0, i = n > 0 ? Math.round((n - l) / n * 100) : 0, g = i > 0 ? `-${i}%` : "0%";
156
+ var d, i;
157
+ const e = p(), n = ((d = t.original_price) == null ? void 0 : d[e.code]) ?? Object.values(t.original_price ?? {})[0] ?? 0, l = ((i = t.price) == null ? void 0 : i[e.code]) ?? Object.values(t.price ?? {})[0] ?? 0, r = n > 0 ? Math.round((n - l) / n * 100) : 0, g = r > 0 ? `-${r}%` : "0%";
163
158
  return `
164
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="top">
159
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="top">
165
160
  <table
166
161
  class="product-card-segment"
167
162
  width="100%"
@@ -190,7 +185,7 @@ const P = {
190
185
  `;
191
186
  },
192
187
  [b]: () => `
193
- <td class="${a}" style="padding: ${o}; height: 100%;" valign="top">
188
+ <td class="${o}" style="padding: ${a}; height: 100%;" valign="top">
194
189
  <table
195
190
  class="product-card-segment"
196
191
  width="100%"
@@ -227,7 +222,7 @@ const P = {
227
222
  `
228
223
  };
229
224
  export {
230
- a as ATTRIBUTE_CELL_CLASS,
231
- o as DEFAULT_CELL_PADDING,
225
+ o as ATTRIBUTE_CELL_CLASS,
226
+ a as DEFAULT_CELL_PADDING,
232
227
  P as gridElementRenderer
233
228
  };
@@ -1,5 +1,5 @@
1
1
  import { RecommendationBlockId as o } from "../../constants/blockIds.js";
2
- import { ATTR_PRODUCT_BUTTON as l, ATTR_PRODUCT_IMAGE as d, ATTR_PRODUCT_OMNIBUS_DISCOUNT as m, ATTR_PRODUCT_OMNIBUS_PRICE as u, ATTR_PRODUCT_OLD_PRICE as g, ATTR_PRODUCT_PRICE as f, ATTR_PRODUCT_NAME as x } from "../../constants/selectors.js";
2
+ import { ATTR_PRODUCT_BUTTON as l, ATTR_PRODUCT_IMAGE as d, ATTR_PRODUCT_OMNIBUS_DISCOUNT as u, ATTR_PRODUCT_OMNIBUS_PRICE as m, ATTR_PRODUCT_OLD_PRICE as g, ATTR_PRODUCT_PRICE as f, ATTR_PRODUCT_NAME as x } from "../../constants/selectors.js";
3
3
  import { useRecommendationExtensionStore as T } from "../../store/recommendation.js";
4
4
  import { formatPrice as _ } from "../../utils/priceFormatter.js";
5
5
  import { sanitizeImageUrl as y } from "../utils.js";
@@ -14,14 +14,14 @@ function p() {
14
14
  thousandSeparator: e.thousandSeparator
15
15
  };
16
16
  }
17
- function a(t, e = "price") {
18
- const n = p(), r = t[e], i = (r == null ? void 0 : r[n.code]) ?? Object.values(r ?? {})[0] ?? 0;
17
+ function s(t, e = "price") {
18
+ const n = p(), r = t[e], a = (r == null ? void 0 : r[n.code]) ?? Object.values(r ?? {})[0] ?? 0;
19
19
  return _({
20
- price: i,
20
+ price: a,
21
21
  currency: n
22
22
  });
23
23
  }
24
- const P = {
24
+ const $ = {
25
25
  /**
26
26
  * Image cell - left column (120px fixed width)
27
27
  * Has recommendation-attribute-row class and data attributes for Card Composition control
@@ -35,18 +35,13 @@ const P = {
35
35
  data-visibility="1"
36
36
  align="center"
37
37
  valign="middle">
38
- <div style="position: relative; width: 100%; padding-bottom: 100%; overflow: hidden;">
39
- <a
40
- target="_blank"
41
- href="${t.url}"
42
- style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
43
- <img
44
- src="${y(t.image_url)}"
45
- alt="${t.name}"
46
- style="max-width: 100%; max-height: 100%; object-fit: contain; display: block;"
47
- class="adapt-img product-image">
48
- </a>
49
- </div>
38
+ <a target="_blank" href="${t.url}">
39
+ <img
40
+ src="${y(t.image_url)}"
41
+ alt="${t.name}"
42
+ style="display: block; max-width: 100%; height: auto;"
43
+ class="adapt-img product-image">
44
+ </a>
50
45
  </td>
51
46
  `,
52
47
  /**
@@ -74,7 +69,7 @@ const P = {
74
69
  esd-extension-block-id="${o.PRICE}"
75
70
  align="left">
76
71
  <p contenteditable="false" style="font-size: 16px; color: #333333; font-weight: bold; margin: 0;">
77
- <strong>${a(t, "price")}</strong>
72
+ <strong>${s(t, "price")}</strong>
78
73
  </p>
79
74
  </td>
80
75
  </tr>
@@ -91,7 +86,7 @@ const P = {
91
86
  <p
92
87
  contenteditable="false"
93
88
  style="font-size: 14px; color: #999999; text-decoration: line-through; margin: 0;">
94
- <strong>${a(t, "original_price")}</strong>
89
+ <strong>${s(t, "original_price")}</strong>
95
90
  </p>
96
91
  </td>
97
92
  </tr>
@@ -99,7 +94,7 @@ const P = {
99
94
  /**
100
95
  * Omnibus price element - row for info cell table
101
96
  */
102
- [u]: (t) => `
97
+ [m]: (t) => `
103
98
  <tr>
104
99
  <td
105
100
  class="esd-block-text product-omnibus-price"
@@ -109,7 +104,7 @@ const P = {
109
104
  align="left">
110
105
  <p style="font-size: 12px; color: #666666; margin: 0;">
111
106
  <span class="omnibus-text-before">Lowest 30-day price: </span>
112
- <span class="omnibus-price-value">${a(t, "original_price")}</span>
107
+ <span class="omnibus-price-value">${s(t, "original_price")}</span>
113
108
  <span class="omnibus-text-after"></span>
114
109
  </p>
115
110
  </td>
@@ -118,9 +113,9 @@ const P = {
118
113
  /**
119
114
  * Omnibus discount element - row for info cell table
120
115
  */
121
- [m]: (t) => {
122
- var s, c;
123
- const e = p(), n = ((s = t.original_price) == null ? void 0 : s[e.code]) ?? Object.values(t.original_price ?? {})[0] ?? 0, r = ((c = t.price) == null ? void 0 : c[e.code]) ?? Object.values(t.price ?? {})[0] ?? 0, i = n > 0 ? Math.round((n - r) / n * 100) : 0, b = i > 0 ? `-${i}%` : "0%";
116
+ [u]: (t) => {
117
+ var i, c;
118
+ const e = p(), n = ((i = t.original_price) == null ? void 0 : i[e.code]) ?? Object.values(t.original_price ?? {})[0] ?? 0, r = ((c = t.price) == null ? void 0 : c[e.code]) ?? Object.values(t.price ?? {})[0] ?? 0, a = n > 0 ? Math.round((n - r) / n * 100) : 0, b = a > 0 ? `-${a}%` : "0%";
124
119
  return `
125
120
  <tr>
126
121
  <td
@@ -170,5 +165,5 @@ const P = {
170
165
  `
171
166
  };
172
167
  export {
173
- P as listElementRenderer
168
+ $ as listElementRenderer
174
169
  };
@@ -1,22 +1,22 @@
1
1
  function l(t) {
2
2
  if (t.length === 0)
3
3
  return "";
4
- const o = t.sort((r, e) => r.filterNumber - e.filterNumber), n = o.map((r) => `[${r.attribute}][${r.operatorReplace}][${r.value}]`), [i, ...p] = n;
5
- let u = i;
6
- for (let r = 0; r < p.length; r++) {
7
- const e = o[r + 1].innerGroupOperator;
8
- u += `${e}${p[r]}`;
4
+ const o = t.sort((r, e) => r.filterNumber - e.filterNumber), n = o.map((r) => `[${r.attribute}][${r.operator}][${r.value}]`), [p, ...i] = n;
5
+ let u = p;
6
+ for (let r = 0; r < i.length; r++) {
7
+ const e = o[r].innerGroupOperator;
8
+ u += `${e}${i[r]}`;
9
9
  }
10
10
  return `(${u})`;
11
11
  }
12
12
  function f(t) {
13
13
  if (!t || t.length === 0)
14
14
  return "";
15
- const o = t.reduce((r, e) => (r[e.filterGroup] || (r[e.filterGroup] = []), r[e.filterGroup].push(e), r), {}), n = Object.keys(o).map(Number).sort((r, e) => r - e), i = n.map((r) => {
15
+ const o = t.reduce((r, e) => (r[e.filterGroup] || (r[e.filterGroup] = []), r[e.filterGroup].push(e), r), {}), n = Object.keys(o).map(Number).sort((r, e) => r - e), p = n.map((r) => {
16
16
  const e = o[r];
17
17
  return l(e);
18
- }), [p, ...u] = i;
19
- let s = p;
18
+ }), [i, ...u] = p;
19
+ let s = i;
20
20
  for (let r = 0; r < u.length; r++) {
21
21
  const e = n[r + 1], c = o[e][0].outerGroupOperator;
22
22
  s += `${c}${u[r]}`;
@@ -0,0 +1,29 @@
1
+ import { safeParse as o, object as p, boolean as l, number as i, pipe as c, minLength as f, string as m } from "../../../../node_modules/valibot/dist/index.js";
2
+ const e = c(m(), f(1)), s = p({
3
+ type: e,
4
+ attribute: e,
5
+ operator: e,
6
+ innerGroupOperator: e,
7
+ outerGroupOperator: e,
8
+ value: e,
9
+ filterGroup: i(),
10
+ filterNumber: i(),
11
+ isValid: l()
12
+ });
13
+ function g(t) {
14
+ return o(s, t).success;
15
+ }
16
+ function S(t) {
17
+ const r = o(s, t);
18
+ return r.success ? /* @__PURE__ */ new Set() : new Set(
19
+ r.issues.flatMap((u) => {
20
+ var n;
21
+ return ((n = u.path) == null ? void 0 : n.map((a) => String(a.key))) ?? [];
22
+ })
23
+ );
24
+ }
25
+ export {
26
+ s as FilterSchema,
27
+ S as getInvalidFilterFields,
28
+ g as isFilterValid
29
+ };
@@ -0,0 +1,17 @@
1
+ import { ModuleFolderDefaults as n } from "../../enums/defaults.js";
2
+ import { ExtensionBuilder as t, BlocksPanel as r } from "../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
3
+ class u extends r {
4
+ getModulesTabIconName(o) {
5
+ const { key: e } = o, { SAVED_MODULES: l, DEFAULT_MODULES: s } = n;
6
+ if (e.includes(l))
7
+ return "user-profile";
8
+ if (e.includes(s))
9
+ return "modules";
10
+ if (e === "amp_modules")
11
+ return "mail-template";
12
+ }
13
+ }
14
+ const c = new t().withBlocksPanel(u).build();
15
+ export {
16
+ c as default
17
+ };
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- .gap-16[data-v-6562e38c],.gap-16[data-v-1ccb6d4a]{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-913a3417] .in-progress-wrapper__progress p span:last-child{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-17dd4d8b]{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-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-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-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-b88d274d],.gap-16[data-v-c5dee797]{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-913a3417] .in-progress-wrapper__progress p span:last-child{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-17dd4d8b]{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-16abb398]{position:relative;width:100%;height:calc(100vh - 128px)}.guido-editor__container[data-v-16abb398]{width:100%;height:calc(100vh - 128px)}.guido-editor__no-header[data-v-16abb398]{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-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-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}