@useinsider/guido 3.23.0-beta.31d0f5f → 3.23.0-beta.9f6bfbf

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 (42) hide show
  1. package/README.md +1 -0
  2. package/dist/@types/config/schemas.js +17 -15
  3. package/dist/components/Guido.vue.js +1 -1
  4. package/dist/components/Guido.vue2.js +58 -56
  5. package/dist/composables/useModuleRepair.js +14 -12
  6. package/dist/config/migrator/index.js +16 -15
  7. package/dist/config/migrator/itemsPriceFormatMigrator.js +20 -0
  8. package/dist/extensions/Blocks/Items/block.js +115 -77
  9. package/dist/extensions/Blocks/Items/constants/currency.js +59 -14
  10. package/dist/extensions/Blocks/Items/controls/price/currencyLocation.js +33 -22
  11. package/dist/extensions/Blocks/Items/controls/price/currencySymbol.js +62 -51
  12. package/dist/extensions/Blocks/Items/controls/price/formattedPrice.js +18 -17
  13. package/dist/extensions/Blocks/Items/controls/price/singlePrice.js +42 -31
  14. package/dist/extensions/Blocks/Items/controls/priceFormat.js +145 -0
  15. package/dist/extensions/Blocks/Items/controls/settingsControl.js +141 -120
  16. package/dist/extensions/Blocks/Items/enums/controlEnums.js +1 -1
  17. package/dist/extensions/Blocks/Items/extension.js +9 -8
  18. package/dist/extensions/Blocks/Items/items.css.js +19 -0
  19. package/dist/extensions/Blocks/Items/settingsPanel.js +34 -25
  20. package/dist/extensions/Blocks/Items/template.js +250 -212
  21. package/dist/extensions/Blocks/Items/utils/priceFormatOps.js +185 -0
  22. package/dist/extensions/Blocks/Recommendation/utils/priceFormatter.js +1 -0
  23. package/dist/guido.css +1 -1
  24. package/dist/package.json.js +1 -1
  25. package/dist/src/@types/config/schemas.d.ts +4 -0
  26. package/dist/src/composables/useConfig.d.ts +2 -0
  27. package/dist/src/config/migrator/index.d.ts +4 -1
  28. package/dist/src/config/migrator/itemsPriceFormatMigrator.d.ts +1 -0
  29. package/dist/src/extensions/Blocks/Items/block.d.ts +6 -9
  30. package/dist/src/extensions/Blocks/Items/constants/currency.d.ts +32 -0
  31. package/dist/src/extensions/Blocks/Items/controls/priceFormat.d.ts +23 -0
  32. package/dist/src/extensions/Blocks/Items/controls/settingsControl.d.ts +1 -0
  33. package/dist/src/extensions/Blocks/Items/enums/controlEnums.d.ts +1 -0
  34. package/dist/src/extensions/Blocks/Items/template.d.ts +4 -1
  35. package/dist/src/extensions/Blocks/Items/utils/nodeConfigUtils.d.ts +3 -0
  36. package/dist/src/extensions/Blocks/Items/utils/priceFormatOps.d.ts +61 -0
  37. package/dist/src/extensions/Blocks/Recommendation/utils/priceFormatter.d.ts +12 -0
  38. package/dist/src/stores/config.d.ts +20 -0
  39. package/dist/src/utils/itemsCurrencyRepair.d.ts +5 -1
  40. package/dist/utils/itemsCurrencyRepair.js +29 -24
  41. package/dist/utils/pairProductVariables.js +119 -99
  42. package/package.json +1 -1
@@ -0,0 +1,185 @@
1
+ import { formatNumber as w } from "../../Recommendation/utils/priceFormatter.js";
2
+ import { escapeHtml as q } from "../../../../utils/htmlEscape.js";
3
+ import { extractWrapperTags as B } from "../../../../utils/preserveTextStyles.js";
4
+ import { ITEMS_PRICE_FORMAT_ATTR as c, priceFormatFromConfig as _, normalizeDecimalCount as V, LEGACY_PRICE_PARAGRAPH_ATTRS as O, ITEMS_CURRENCY_ATTR as b } from "../constants/currency.js";
5
+ import { productPairs as W } from "../enums/productEnums.js";
6
+ import { DefaultConfigValues as I } from "../enums/settingsEnums.js";
7
+ import { escapeReplacement as z } from "./nodeConfigUtils.js";
8
+ const J = 'p[product-attr="price"], p[product-attr="originalPrice"]', K = [
9
+ ...Object.values(c),
10
+ "data-type"
11
+ ], L = "CART_ITEMS";
12
+ function X() {
13
+ return { rootSet: {}, paragraphRemove: [], configPatch: null, texts: null, changed: !1 };
14
+ }
15
+ function h(t) {
16
+ return t != null;
17
+ }
18
+ function Pt(t) {
19
+ return t === "price" || t === "originalPrice" ? t : null;
20
+ }
21
+ function N(t) {
22
+ const n = W.PAIRS_FOR_EXTENSION, r = t != null && t.type && t.type in n.price ? t.type : L, o = (t == null ? void 0 : t.priceSinglePrice) === !0, e = n.price[r], i = n.originalPrice[r];
23
+ return {
24
+ price: o ? e.DEFAULT_SINGLE_PRICE : e.DEFAULT_PRICE,
25
+ originalPrice: o ? i.DEFAULT_SINGLE_PRICE : i.DEFAULT_PRICE
26
+ };
27
+ }
28
+ function P({ amount: t, format: n, symbol: r, alignment: o }) {
29
+ const e = w(Number(t), n), i = q((r ?? "").trim());
30
+ return i ? o === "1" ? `${e} ${i}` : `${i} ${e}` : e;
31
+ }
32
+ function Tt(t) {
33
+ const n = N(t), r = {
34
+ format: _(t),
35
+ symbol: (t == null ? void 0 : t.priceCurrencySymbol) ?? I.productPriceCurrencySymbolControlValue,
36
+ alignment: (t == null ? void 0 : t.priceCurrencyLocation) ?? "0"
37
+ };
38
+ return {
39
+ price: P({ amount: n.price, ...r }),
40
+ originalPrice: P({ amount: n.originalPrice, ...r })
41
+ };
42
+ }
43
+ const x = /&nbsp;|\u00a0|\s+/g, Q = "(?:&nbsp;| |\\s)+", Z = /&(amp|lt|gt|quot|#x27|#39);/g, tt = { amp: "&", lt: "<", gt: ">", quot: '"', "#x27": "'", "#39": "'" }, rt = {
44
+ "&": "(?:&amp;|&)",
45
+ "<": "(?:&lt;|<)",
46
+ ">": "(?:&gt;|>)",
47
+ '"': '(?:&quot;|")',
48
+ "'": "(?:&#x27;|&#39;|')"
49
+ }, et = (t) => t.replace(Z, (n, r) => tt[r]), nt = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
50
+ function ot(t) {
51
+ return Array.from(t, (n) => rt[n] ?? nt(n)).join("");
52
+ }
53
+ function D(t, n) {
54
+ const r = (o) => o.replace(x, " ").trim();
55
+ return r(t ?? "") === r(et(n ?? ""));
56
+ }
57
+ function it(t, n, r) {
58
+ const o = t.trim(), e = n.trim().split(x).filter(Boolean), i = e.length ? new RegExp(e.map(ot).join(Q)) : null;
59
+ if (i != null && i.test(o))
60
+ return o.replace(i, z(r));
61
+ const { openTags: s, closeTags: u } = B(o);
62
+ return `${s}${r}${u}`;
63
+ }
64
+ function ct(t, n) {
65
+ if (!t)
66
+ return null;
67
+ const r = Object.fromEntries(
68
+ Object.entries(n).filter(([o, e]) => t[o] !== e)
69
+ );
70
+ return Object.keys(r).length > 0 ? r : null;
71
+ }
72
+ function Ct(t, { convertLegacy: n }) {
73
+ const { rootAttrs: r, paragraphs: o, config: e } = t, i = h(r[c.DECIMAL_COUNT]);
74
+ if (!i && !n)
75
+ return X();
76
+ const s = o.find((a) => a.kind === "price") ?? o[0], u = (a) => (s == null ? void 0 : s.attrs[a]) ?? null, l = i ? r[c.SINGLE_PRICE] : u("data-single_price"), m = typeof (e == null ? void 0 : e.priceSinglePrice) == "boolean" ? e.priceSinglePrice : l === "true", A = e == null ? void 0 : e.priceCurrencyLocation, j = u(b.POSITION) === "after" ? "1" : "0", H = i ? r[c.ALIGNMENT] : j, E = (typeof A == "string" && A.trim() !== "" ? A : H) === "1" ? "1" : "0", U = i ? r[c.SYMBOL] : u(b.SYMBOL), S = typeof (e == null ? void 0 : e.priceCurrencySymbol) == "string" ? e.priceCurrencySymbol : U ?? I.productPriceCurrencySymbolControlValue, p = _({
77
+ priceThousandSeparator: (e == null ? void 0 : e.priceThousandSeparator) ?? (i ? r[c.THOUSAND_SEPARATOR] ?? void 0 : void 0),
78
+ priceDecimalSeparator: (e == null ? void 0 : e.priceDecimalSeparator) ?? (i ? r[c.DECIMAL_SEPARATOR] ?? void 0 : void 0),
79
+ priceDecimalCount: (e == null ? void 0 : e.priceDecimalCount) ?? (i ? V(r[c.DECIMAL_COUNT]) : void 0)
80
+ }), G = {
81
+ [c.SYMBOL]: S.trim(),
82
+ [c.ALIGNMENT]: E,
83
+ [c.THOUSAND_SEPARATOR]: p.thousandSeparator,
84
+ [c.DECIMAL_SEPARATOR]: p.decimalSeparator,
85
+ [c.DECIMAL_COUNT]: String(p.decimalCount),
86
+ [c.SINGLE_PRICE]: m ? "true" : "false"
87
+ }, T = Object.fromEntries(
88
+ Object.entries(G).filter(([a, d]) => r[a] !== d)
89
+ ), C = O.filter(
90
+ (a) => o.some((d) => h(d.attrs[a]))
91
+ ), $ = {
92
+ priceThousandSeparator: p.thousandSeparator,
93
+ priceDecimalSeparator: p.decimalSeparator,
94
+ priceDecimalCount: p.decimalCount,
95
+ priceSinglePrice: m,
96
+ priceCurrencyLocation: E,
97
+ priceCurrencySymbol: S
98
+ }, f = ct(e, $), k = (e == null ? void 0 : e.type) ?? r["data-type"] ?? L, R = N({ type: k, priceSinglePrice: m }), y = (a) => P({ amount: a, format: p, symbol: S, alignment: E }), g = { price: y(R.price), originalPrice: y(R.originalPrice) }, Y = o.some((a) => !D(a.text, g[a.kind]));
99
+ return {
100
+ rootSet: T,
101
+ paragraphRemove: C,
102
+ configPatch: f,
103
+ texts: g,
104
+ changed: Object.keys(T).length > 0 || C.length > 0 || f !== null || Y
105
+ };
106
+ }
107
+ function at(t) {
108
+ const n = {};
109
+ return K.forEach((r) => {
110
+ n[r] = t.rootAttr(r) ?? null;
111
+ }), {
112
+ rootAttrs: n,
113
+ config: t.config,
114
+ paragraphs: t.paragraphs.map((r) => {
115
+ const o = {};
116
+ return O.forEach((e) => {
117
+ o[e] = r.attr(e) ?? null;
118
+ }), { kind: r.kind, attrs: o, text: r.text.trim() };
119
+ })
120
+ };
121
+ }
122
+ function M(t) {
123
+ const n = t.getAttribute("esd-ext-config");
124
+ if (!n)
125
+ return null;
126
+ try {
127
+ const r = JSON.parse(n);
128
+ return r && typeof r == "object" ? r : null;
129
+ } catch {
130
+ return null;
131
+ }
132
+ }
133
+ function F(t) {
134
+ return Array.from(t.querySelectorAll(J)).map((n) => ({
135
+ kind: n.getAttribute("product-attr"),
136
+ element: n
137
+ }));
138
+ }
139
+ function v(t) {
140
+ return t.textContent;
141
+ }
142
+ function ft(t) {
143
+ return at({
144
+ rootAttr: (n) => t.getAttribute(n),
145
+ config: M(t),
146
+ paragraphs: F(t).map(({ kind: n, element: r }) => ({
147
+ kind: n,
148
+ attr: (o) => r.getAttribute(o),
149
+ text: v(r)
150
+ }))
151
+ });
152
+ }
153
+ function Rt(t, n) {
154
+ if (!n.changed)
155
+ return !1;
156
+ let r = !1;
157
+ if (Object.entries(n.rootSet).forEach(([o, e]) => {
158
+ t.getAttribute(o) !== e && (t.setAttribute(o, e), r = !0);
159
+ }), F(t).forEach(({ kind: o, element: e }) => {
160
+ var u;
161
+ n.paragraphRemove.forEach((l) => {
162
+ e.hasAttribute(l) && (e.removeAttribute(l), r = !0);
163
+ });
164
+ const i = (u = n.texts) == null ? void 0 : u[o], s = v(e).trim();
165
+ i !== void 0 && !D(s, i) && (e.innerHTML = it(e.innerHTML, s, i), r = !0);
166
+ }), n.configPatch) {
167
+ const o = M(t);
168
+ o && (t.setAttribute("esd-ext-config", JSON.stringify({ ...o, ...n.configPatch })), r = !0);
169
+ }
170
+ return r;
171
+ }
172
+ export {
173
+ J as PRICE_PARAGRAPH_SELECTOR,
174
+ Rt as applyPriceFormatOpsToElement,
175
+ at as buildPriceFormatSnapshot,
176
+ P as formatItemsDummyPrice,
177
+ Pt as paragraphKindOf,
178
+ Ct as planPriceFormatOps,
179
+ Tt as priceTextsFromConfig,
180
+ M as readPersistedConfigAttribute,
181
+ it as replacePriceText,
182
+ N as resolvePriceDummyAmounts,
183
+ D as samePriceText,
184
+ ft as snapshotPriceFormatFromElement
185
+ };
@@ -25,5 +25,6 @@ function f(c) {
25
25
  return r === "before" ? `${e} ${a}` : `${a} ${e}`;
26
26
  }
27
27
  export {
28
+ d as formatNumber,
28
29
  f as formatPrice
29
30
  };
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.auth-error-modal[data-v-b4d7ae51]{position:relative;z-index:145}.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-b8f24f34] .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-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-baf7a5dd]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.validation-error-list[data-v-e48cebe9]{gap:16px}.validation-error-row[data-v-e48cebe9]{gap:8px;padding:24px;border:1px solid #E1E1E1;border-radius:8px}.validation-error-row__icon[data-v-e48cebe9]{flex-shrink:0;font-size:24px;line-height:0}.validation-error-row__text[data-v-e48cebe9]{font-size:13px;line-height:16px;color:#292929;word-break:break-word}.guido-editor__wrapper[data-v-f2154cb6]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-f2154cb6]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-f2154cb6]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-eaf8e461]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-eaf8e461]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-eaf8e461]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-eaf8e461]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-eaf8e461]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .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-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{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-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-19d8cb42] .vueperslides__bullets,[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}.legacy-strategy-updated-modal[data-v-da2225a1]{position:relative;z-index:145}
1
+ @charset "UTF-8";.auth-error-modal[data-v-b4d7ae51]{position:relative;z-index:145}.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-b8f24f34] .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-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-baf7a5dd]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.validation-error-list[data-v-e48cebe9]{gap:16px}.validation-error-row[data-v-e48cebe9]{gap:8px;padding:24px;border:1px solid #E1E1E1;border-radius:8px}.validation-error-row__icon[data-v-e48cebe9]{flex-shrink:0;font-size:24px;line-height:0}.validation-error-row__text[data-v-e48cebe9]{font-size:13px;line-height:16px;color:#292929;word-break:break-word}.guido-editor__wrapper[data-v-49dc1b30]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-49dc1b30]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-49dc1b30]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-eaf8e461]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-eaf8e461]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-eaf8e461]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-eaf8e461]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-eaf8e461]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .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-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{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-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-19d8cb42] .vueperslides__bullets,[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}.legacy-strategy-updated-modal[data-v-da2225a1]{position:relative;z-index:145}
@@ -1,4 +1,4 @@
1
- const o = "3.23.0-beta.31d0f5f", s = { stripo: { version: "2.81.1" } }, t = {
1
+ const o = "3.23.0-beta.9f6bfbf", s = { stripo: { version: "2.81.1" } }, t = {
2
2
  version: o,
3
3
  guido: s
4
4
  };
@@ -414,6 +414,8 @@ export declare const FeaturesSchema: v.ObjectSchema<{
414
414
  /** Allow persisting a template that still has validation errors (drawer "Save and Continue" soft-save). Host sets false for transactional + unsubscribe. */
415
415
  readonly allowSaveWithErrors: v.OptionalSchema<v.BooleanSchema<undefined>, true>;
416
416
  readonly reusableRecommendationStrategy: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
417
+ /** Items block: Recommendation-style price formatting (root currency-* attrs, raw price tags). Released dark. */
418
+ readonly itemsPriceFormatting: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
417
419
  }, undefined>;
418
420
  /**
419
421
  * Default block types available in Stripo
@@ -832,6 +834,8 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
832
834
  /** Allow persisting a template that still has validation errors (drawer "Save and Continue" soft-save). Host sets false for transactional + unsubscribe. */
833
835
  readonly allowSaveWithErrors: v.OptionalSchema<v.BooleanSchema<undefined>, true>;
834
836
  readonly reusableRecommendationStrategy: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
837
+ /** Items block: Recommendation-style price formatting (root currency-* attrs, raw price tags). Released dark. */
838
+ readonly itemsPriceFormatting: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
835
839
  }, undefined>, {}>;
836
840
  /** Block configuration */
837
841
  readonly blocks: v.OptionalSchema<v.ObjectSchema<{
@@ -104,6 +104,7 @@ export declare const useConfig: () => {
104
104
  linkTrackingIds: boolean;
105
105
  allowSaveWithErrors: boolean;
106
106
  reusableRecommendationStrategy: boolean;
107
+ itemsPriceFormatting: boolean;
107
108
  };
108
109
  blocks: {
109
110
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -243,6 +244,7 @@ export declare const useConfig: () => {
243
244
  linkTrackingIds: boolean;
244
245
  allowSaveWithErrors: boolean;
245
246
  reusableRecommendationStrategy: boolean;
247
+ itemsPriceFormatting: boolean;
246
248
  } | null>;
247
249
  blocks: import("vue").ComputedRef<{
248
250
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1,3 +1,6 @@
1
1
  import type { LegacyRecommendationConfig } from '@@/Types/config';
2
2
  import { type PartnerScopeMigrationOptions } from './recommendationPartnerMigrator';
3
- export declare const migrate: (html: string, recommendationConfigs?: Record<string, LegacyRecommendationConfig>, partnerScope?: PartnerScopeMigrationOptions) => Promise<string>;
3
+ export interface MigrationFeatureFlags {
4
+ itemsPriceFormatting?: boolean;
5
+ }
6
+ export declare const migrate: (html: string, recommendationConfigs?: Record<string, LegacyRecommendationConfig>, partnerScope?: PartnerScopeMigrationOptions, features?: MigrationFeatureFlags) => Promise<string>;
@@ -0,0 +1 @@
1
+ export declare function migrateItemsPriceFormat(html: string): string;
@@ -71,15 +71,12 @@ export declare class ItemsBlock extends Block {
71
71
  */
72
72
  private _resolveInstanceId;
73
73
  /**
74
- * Stamps the export-read currency attrs onto every price `<p>` from config, so a template whose
75
- * attrs drifted (e.g. a location toggle before the sync fix) self-heals to match the editor.
76
- * Config is the source of truth — never derive from visible text.
77
- *
78
- * Authority split lives in `currencyAttrTargets` (SD-147588) — position only when a location
79
- * is recorded, symbol only when customized — so this heal and the module-drop repair can't drift.
80
- *
81
- * Returns true only when an attr actually changed, so the caller can skip an empty apply that
82
- * would otherwise re-trigger onDocumentChanged and loop.
74
+ * Single self-heal slot: the flag only decides whether a legacy root is converted; a root
75
+ * already in the new format is reconciled from config regardless. Returns whether anything was queued.
83
76
  */
84
77
  private _reconcileCurrencyDomAttributes;
78
+ /** Legacy `<p>` contract via `currencyAttrTargets`: position when recorded, symbol only when custom. */
79
+ private _reconcileLegacyCurrencyAttributes;
80
+ private _priceParagraphs;
81
+ private _isPriceFormattingEnabled;
85
82
  }
@@ -41,3 +41,35 @@ export declare function currencyAttrTargets(config: {
41
41
  priceCurrencyLocation?: string;
42
42
  priceCurrencySymbol?: string;
43
43
  }): CurrencyAttrTargets;
44
+ export declare const ITEMS_PRICE_FORMAT_ATTR: {
45
+ readonly SYMBOL: "currency-symbol";
46
+ readonly ALIGNMENT: "currency-alignment";
47
+ readonly THOUSAND_SEPARATOR: "currency-thousand-separator";
48
+ readonly DECIMAL_SEPARATOR: "currency-decimal-separator";
49
+ readonly DECIMAL_COUNT: "currency-decimal-count";
50
+ readonly SINGLE_PRICE: "data-single_price";
51
+ };
52
+ /** Price `<p>` attrs of the legacy model; a new-format block carries none of them. */
53
+ export declare const LEGACY_PRICE_PARAGRAPH_ATTRS: readonly ["data-formated", "data-single_price", "data-curency", "data-currency_symbol"];
54
+ export declare const PRICE_FORMAT_CONFIG_KEYS: readonly ["priceThousandSeparator", "priceDecimalSeparator", "priceDecimalCount"];
55
+ export interface ItemsPriceFormat {
56
+ thousandSeparator: string;
57
+ decimalSeparator: string;
58
+ decimalCount: number;
59
+ }
60
+ /** en-US, the shape the legacy pre-formatted price tags produced. */
61
+ export declare const DEFAULT_ITEMS_PRICE_FORMAT: ItemsPriceFormat;
62
+ export interface PriceFormatConfigSlice {
63
+ priceThousandSeparator?: string;
64
+ priceDecimalSeparator?: string;
65
+ priceDecimalCount?: number;
66
+ }
67
+ export declare function normalizeDecimalCount(value: unknown): number;
68
+ /** Config → format, defaulting each missing key independently. */
69
+ export declare function priceFormatFromConfig(config: PriceFormatConfigSlice | null | undefined): ItemsPriceFormat;
70
+ export declare function isNewPriceFormatConfig(config: PriceFormatConfigSlice | null | undefined): boolean;
71
+ export interface AttributeReader {
72
+ getAttribute(name: string): string | null | undefined;
73
+ }
74
+ /** The export/control switch: a root carrying `currency-decimal-count` is in the new format. */
75
+ export declare function isNewPriceFormatRoot(root: AttributeReader | null | undefined): boolean;
@@ -0,0 +1,23 @@
1
+ import { ControlApi, ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
2
+ import { CommonControl } from '../../common-control';
3
+ import { ItemsBlockControlId } from '../enums/controlEnums';
4
+ import { type ItemsBlockConfig } from '../utils/nodeConfigUtils';
5
+ export declare const CONTROL_BLOCK_ID = ItemsBlockControlId.PRICE_FORMAT;
6
+ export declare function isNewPriceFormatBlock(currentNode: ImmutableHtmlNode | undefined): boolean;
7
+ /** One apply: the config patch, the root attrs the export reads, and both price texts re-rendered. */
8
+ export declare function applyPriceFormatChange(currentNode: ImmutableHtmlNode | undefined, api: ControlApi, patch: Partial<ItemsBlockConfig>, description: string): void;
9
+ export declare class ItemsBlockPriceFormatControl extends CommonControl {
10
+ private lastWritten;
11
+ getId(): string;
12
+ getTemplate(): string;
13
+ onRender(): void;
14
+ onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
15
+ onDestroy(): void;
16
+ _onThousandSeparatorChange(value: string): void;
17
+ _onDecimalSeparatorChange(value: string): void;
18
+ _onDecimalCountChange(value: string): void;
19
+ private _currentFormat;
20
+ private _write;
21
+ private _formValues;
22
+ private _getSelectRow;
23
+ }
@@ -35,6 +35,7 @@ export declare class ItemsBlockControl extends CommonControl {
35
35
  _reFillTemplate(itemsType?: ProductType): void;
36
36
  _recalculateTrimming(): void;
37
37
  private _getParagraphFromBlock;
38
+ private _replacePriceText;
38
39
  private _escapeRegex;
39
40
  private _removeCurrencySymbol;
40
41
  private _replacePriceNumber;
@@ -46,6 +46,7 @@ export declare enum ItemsBlockControlId {
46
46
  PRICE_CURRENCY_SYMBOL = "items-block-price-currency-symbol-control",
47
47
  PRICE_CURRENCY_LOCATION = "items-block-price-currency-location-control",
48
48
  PRICE_ORIENTATION = "items-block-price-orientation-control",
49
+ PRICE_FORMAT = "items-block-price-format-control",
49
50
  NAME_ALIGN = "items-block-name-align-control",
50
51
  NAME_COLOR = "items-block-name-color-control",
51
52
  NAME_SIZE = "items-block-name-size-control",
@@ -1,3 +1,4 @@
1
+ import { type ItemsPriceFormat } from './constants/currency';
1
2
  import { type ItemsBlockConfig } from './utils/nodeConfigUtils';
2
3
  declare const migrationTemplate = "ADD YOUR MIGRATION HERE";
3
4
  type ProductType = 'CART_ITEMS' | 'BROWSED_ITEMS' | 'PURCHASED_ITEMS';
@@ -36,6 +37,8 @@ type TemplateParameters = {
36
37
  quantityStyles?: string;
37
38
  /** Price orientation within the card ('vertical' = stacked, 'horizontal' = side-by-side) */
38
39
  priceOrientation?: PriceOrientationType;
40
+ /** New price model (itemsPriceFormatting): root attrs + raw dummy amounts; absent = legacy output. */
41
+ priceFormat?: ItemsPriceFormat;
39
42
  };
40
43
  /**
41
44
  * Applies price orientation styles to the generated HTML template.
@@ -67,5 +70,5 @@ export declare const applyPriceOrientationStyles: (html: string, layoutOrientati
67
70
  * @param params.formattedPrice - Whether to use formatted price display
68
71
  * @returns HTML template string for the Items Block
69
72
  */
70
- export declare function getDefaultTemplate({ orientation, itemsType, itemId, currencySymbol, currencyLocation, migrate, formattedPrice, configBlockAttributes, nodeConfig, nameStyles, buttonStyles, priceStyles, originalPriceStyles, quantityStyles, priceOrientation, }: TemplateParameters): string;
73
+ export declare function getDefaultTemplate({ orientation, itemsType, itemId, currencySymbol, currencyLocation, migrate, formattedPrice, configBlockAttributes, nodeConfig, nameStyles, buttonStyles, priceStyles, originalPriceStyles, quantityStyles, priceOrientation, priceFormat, }: TemplateParameters): string;
71
74
  export default migrationTemplate;
@@ -18,6 +18,9 @@ export interface ItemsBlockConfig {
18
18
  priceCurrencySymbol: string;
19
19
  priceCurrencyLocation: string;
20
20
  priceOrientation: 'vertical' | 'horizontal';
21
+ priceThousandSeparator?: string;
22
+ priceDecimalSeparator?: string;
23
+ priceDecimalCount?: number;
21
24
  quantityControlEnabled: boolean;
22
25
  buttonLink: string;
23
26
  imageLink: string;
@@ -0,0 +1,61 @@
1
+ import { type ItemsPriceFormat } from '../constants/currency';
2
+ import { type ItemsBlockConfig } from './nodeConfigUtils';
3
+ export type PriceParagraphKind = 'price' | 'originalPrice';
4
+ export declare const PRICE_PARAGRAPH_SELECTOR = "p[product-attr=\"price\"], p[product-attr=\"originalPrice\"]";
5
+ type AttrMap = Record<string, string | null | undefined>;
6
+ export interface PriceParagraphSnapshot {
7
+ kind: PriceParagraphKind;
8
+ attrs: AttrMap;
9
+ text: string;
10
+ }
11
+ export interface PriceFormatSnapshot {
12
+ rootAttrs: AttrMap;
13
+ paragraphs: PriceParagraphSnapshot[];
14
+ config: Partial<ItemsBlockConfig> | null;
15
+ }
16
+ export interface PriceTexts {
17
+ price: string;
18
+ originalPrice: string;
19
+ }
20
+ export interface PriceFormatOps {
21
+ rootSet: Record<string, string>;
22
+ paragraphRemove: string[];
23
+ configPatch: Partial<ItemsBlockConfig> | null;
24
+ texts: PriceTexts | null;
25
+ changed: boolean;
26
+ }
27
+ export interface PlanPriceFormatOptions {
28
+ convertLegacy: boolean;
29
+ }
30
+ export interface FormatDummyPriceInput {
31
+ amount: string | number;
32
+ format: ItemsPriceFormat;
33
+ symbol: string | null | undefined;
34
+ alignment: string | null | undefined;
35
+ }
36
+ export declare function paragraphKindOf(productAttr: string | null | undefined): PriceParagraphKind | null;
37
+ export declare function resolvePriceDummyAmounts(config: Pick<Partial<ItemsBlockConfig>, 'type' | 'priceSinglePrice'> | null | undefined): PriceTexts;
38
+ export declare function formatItemsDummyPrice({ amount, format, symbol, alignment }: FormatDummyPriceInput): string;
39
+ export declare function priceTextsFromConfig(config: Partial<ItemsBlockConfig> | null | undefined): PriceTexts;
40
+ /** `text` is decoded DOM text, `html` the rendered markup text (entities allowed). */
41
+ export declare function samePriceText(text: string | null | undefined, html: string | null | undefined): boolean;
42
+ /** Swaps the whole price text inside the paragraph markup, keeping the style wrappers around it. */
43
+ export declare function replacePriceText(innerHtml: string, currentText: string, newText: string): string;
44
+ export declare function planPriceFormatOps(snapshot: PriceFormatSnapshot, { convertLegacy }: PlanPriceFormatOptions): PriceFormatOps;
45
+ export interface PriceParagraphSource {
46
+ kind: PriceParagraphKind;
47
+ attr(name: string): string | null | undefined;
48
+ text: string;
49
+ }
50
+ export interface PriceFormatSnapshotSource {
51
+ rootAttr(name: string): string | null | undefined;
52
+ paragraphs: PriceParagraphSource[];
53
+ config: Partial<ItemsBlockConfig> | null;
54
+ }
55
+ /** Shared snapshot builder so DOM (migrator, repair) and Stripo-node callers read the same attrs. */
56
+ export declare function buildPriceFormatSnapshot(source: PriceFormatSnapshotSource): PriceFormatSnapshot;
57
+ export declare function readPersistedConfigAttribute(root: Element): Partial<ItemsBlockConfig> | null;
58
+ export declare function snapshotPriceFormatFromElement(root: Element): PriceFormatSnapshot;
59
+ /** DOM applier for parsed HTML (migrator, module repair). Returns whether anything was written. */
60
+ export declare function applyPriceFormatOpsToElement(root: Element, ops: PriceFormatOps): boolean;
61
+ export {};
@@ -14,6 +14,18 @@ export interface FormatPriceOptions {
14
14
  /** Currency configuration */
15
15
  currency: CurrencyConfig;
16
16
  }
17
+ export interface FormatNumberOptions {
18
+ thousandSeparator: string;
19
+ decimalSeparator: string;
20
+ decimalCount: number;
21
+ }
22
+ /**
23
+ * Formats a number with custom thousand and decimal separators
24
+ * @param value - The numeric value to format
25
+ * @param options - Formatting options
26
+ * @returns Formatted number string
27
+ */
28
+ export declare function formatNumber(value: number, options: FormatNumberOptions): string;
17
29
  /**
18
30
  * Formats a numeric price according to currency settings
19
31
  * @example