@useinsider/guido 3.27.0-beta.ee85b86 → 3.27.1-beta.842075e

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 (41) hide show
  1. package/README.md +5 -10
  2. package/dist/components/Guido.vue.js +7 -7
  3. package/dist/components/Guido.vue2.js +83 -86
  4. package/dist/composables/useHtmlCompiler.js +8 -9
  5. package/dist/composables/useModuleRepair.js +32 -63
  6. package/dist/composables/useRecommendation.js +8 -16
  7. package/dist/composables/useStripo.js +43 -44
  8. package/dist/config/compiler/htmlCompilerRules.js +6 -16
  9. package/dist/config/compiler/recommendationCompilerRules.js +29 -41
  10. package/dist/config/migrator/unsubscribeMigrator.js +112 -100
  11. package/dist/enums/recommendation.js +4 -5
  12. package/dist/extensions/Blocks/Recommendation/controls/image/index.js +58 -40
  13. package/dist/extensions/Blocks/Unsubscribe/block.js +104 -96
  14. package/dist/extensions/Blocks/Unsubscribe/utils/constants.js +4 -3
  15. package/dist/extensions/Blocks/Unsubscribe/utils/swapMergeTagInHref.js +5 -0
  16. package/dist/guido.css +1 -1
  17. package/dist/package.json.js +4 -4
  18. package/dist/src/@types/generic.d.ts +0 -7
  19. package/dist/src/composables/useModuleRepair.d.ts +0 -6
  20. package/dist/src/composables/useRecommendation.d.ts +0 -4
  21. package/dist/src/enums/recommendation.d.ts +0 -1
  22. package/dist/src/extensions/Blocks/Recommendation/controls/image/index.d.ts +2 -0
  23. package/dist/src/extensions/Blocks/Unsubscribe/utils/constants.d.ts +1 -0
  24. package/dist/src/extensions/Blocks/Unsubscribe/utils/swapMergeTagInHref.d.ts +1 -0
  25. package/dist/src/utils/dynamicContentConverter.d.ts +18 -20
  26. package/dist/src/utils/genericUtil.d.ts +8 -4
  27. package/dist/static/stripo-runtime-manifest.json.js +2 -2
  28. package/dist/utils/dynamicContentConverter.js +27 -41
  29. package/dist/utils/genericUtil.js +39 -39
  30. package/package.json +2 -2
  31. package/dist/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue.js +0 -24
  32. package/dist/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue2.js +0 -59
  33. package/dist/composables/useAmbiguousDynamicContent.js +0 -72
  34. package/dist/enums/dynamic-content.js +0 -4
  35. package/dist/src/components/organisms/dynamic-content/AmbiguousDynamicContentModal.vue.d.ts +0 -2
  36. package/dist/src/composables/useAmbiguousDynamicContent.d.ts +0 -7
  37. package/dist/src/enums/dynamic-content.d.ts +0 -3
  38. package/dist/src/stores/module-dynamic-content.d.ts +0 -30
  39. package/dist/src/utils/dynamicContentPendingMarker.d.ts +0 -2
  40. package/dist/stores/module-dynamic-content.js +0 -20
  41. package/dist/utils/dynamicContentPendingMarker.js +0 -6
package/README.md CHANGED
@@ -119,8 +119,7 @@ const config: GuidoConfigInput = {
119
119
  // { [partnerName]: [{ text, value, children }] } (architect is multi-partner).
120
120
  // Guido flattens the active (first) partner's leaf attributes and uses them to
121
121
  // repair label-form tokens (`{{ Phone Number }}` -> `{{phone_number}}`) in
122
- // dropped saved modules; a label shared by several attributes opens a picker
123
- // modal (see "Saved-module token repair"); an unresolvable token raises a single warning toaster
122
+ // dropped saved modules; an unresolvable token raises a single warning toaster
124
123
  // (translation key `dynamic-content.unresolved-attributes-on-drop`, registered
125
124
  // host-side). Omit it and the repair is a silent no-op. Default: {}.
126
125
  dynamicContentList?: DynamicContentList,
@@ -692,22 +691,18 @@ const closeModal = () => {
692
691
 
693
692
  ### Saved-module token repair
694
693
 
695
- Legacy or hand-written **saved modules** may carry tokens by display label
694
+ Legacy **saved modules** may serialize their merge-tag chips by display label
696
695
  (`{{ Phone Number }}`) instead of the canonical token (`{{phone_number}}`), which the
697
696
  backend can't resolve. When such a module is dropped or copied into the editor, Guido
698
697
  repairs these automatically using the `template.dynamicContentList` catalog (see
699
698
  [Configuration](#configuration)):
700
699
 
701
- - **Off under `features.liquidSyntax`**: Liquid templates keep every token exactly as written — no rewrite, no modal, no toaster. The Items currency and legacy-unsubscribe repairs still run.
702
- - **Label match with one attribute** → canonical value: `{{ Phone Number }}` → `{{phone_number}}` (any author `| default:` / format tail is preserved). A label matches a leaf's `text` or its `tag_text` (e.g. `Wishlist Item (8) Name`), case-insensitively.
703
- - **Valid tokens are never rewritten**: an exact catalog value, an Items block variable, or an exact entry of `template.customFieldAttributes` (e.g. the host's long-form aliases `name`, `surname`), stays as written — so `{{name | downcase | capitalize}}` survives a drop.
704
- - **Catalog attributes the module ends up using are registered** for Save's allow-list, the same way the picker registers them, so a repaired or chosen token does not fail Save as an invalid custom field.
705
- - **Label match with several attributes** (e.g. a bare `Name` shared by a default attribute and a commerce field) is not guessed: the token is left in place and a modal asks the user to pick an attribute per label, showing each option as `category › label`. Applying the choice is one undo step; closing the modal keeps the tokens and shows the warning toaster below. A module whose choice was still open when the design was saved asks again when the design is reopened. Register these keys host-side: `email-editor.ambiguous-dynamic-content-title`, `email-editor.ambiguous-dynamic-content-message` and `email-editor.ambiguous-dynamic-content-apply` (Cancel reuses `action-builder.cancel`).
706
- - Liquid nested tokens (`coupon.code`), recommendation-block variables (`123_0_price`), allowed system tokens, and `data-*` product tags are left untouched.
700
+ - **Label match** → canonical value: `{{ Phone Number }}` → `{{phone_number}}` (any author `| default:` / format tail is preserved).
701
+ - Already-canonical values, Liquid nested tokens (`coupon.code`), recommendation-block variables (`123_0_price`), allowed system tokens, and `data-*` product tags are left untouched.
707
702
  - An **unresolvable** token is left in place and raises a single **warning toaster** (translation key `dynamic-content.unresolved-attributes-on-drop`; register the copy host-side).
708
703
 
709
704
  Pass `template.dynamicContentList` as a **partner-keyed** tree
710
- (`{ [partnerName]: DynamicContentNode[] }`, where a node is `{ text, tag_text?, value, children? }`).
705
+ (`{ [partnerName]: DynamicContentNode[] }`, where a node is `{ text, value, children? }`).
711
706
  Guido flattens the **active (first) partner's** leaf attributes. Products that manage
712
707
  multiple partners (e.g. architect) should key by partner and place the active partner
713
708
  first. Omit the prop and the repair is a safe no-op — nothing is rewritten and no
@@ -1,20 +1,20 @@
1
1
  import o from "./Guido.vue2.js";
2
2
  /* empty css */
3
3
  import i from "../_virtual/_plugin-vue2_normalizer.js";
4
- var n = function() {
4
+ var s = function() {
5
5
  var a = this, r = a._self._c, e = a._self._setupProxy;
6
- return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper), r(e.AutoSaveController, { ref: "autoSaveControllerRef" }), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : a._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.AuthErrorModal), r(e.FilterSelectionDrawer), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.AssignStrategyDrawer) : a._e(), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.RemoveStrategyModal) : a._e(), e.isRrsEnabled ? r(e.LegacyStrategyUpdatedModal) : a._e(), e.isLegacyUnsubscribeConversionEnabled ? r(e.LegacyUnsubscribeConvertedModal) : a._e(), e.moduleDynamicContentStore.queue.length > 0 ? r(e.AmbiguousDynamicContentModal) : a._e(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isExternalDisplayConditionsEnabled ? r(e.DisplayConditionsHost) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(l) {
6
+ return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper), r(e.AutoSaveController, { ref: "autoSaveControllerRef" }), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : a._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.AuthErrorModal), r(e.FilterSelectionDrawer), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.AssignStrategyDrawer) : a._e(), e.isRrsEnabled || e.hasAssignedStrategy ? r(e.RemoveStrategyModal) : a._e(), e.isRrsEnabled ? r(e.LegacyStrategyUpdatedModal) : a._e(), e.isLegacyUnsubscribeConversionEnabled ? r(e.LegacyUnsubscribeConvertedModal) : a._e(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isExternalDisplayConditionsEnabled ? r(e.DisplayConditionsHost) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(l) {
7
7
  return e.emit("onboarding:finished");
8
8
  } } }), r(e.UnsubscribeWrapper), r(e.LoadingWrapper)], 1);
9
- }, t = [], s = /* @__PURE__ */ i(
9
+ }, t = [], n = /* @__PURE__ */ i(
10
10
  o,
11
- n,
11
+ s,
12
12
  t,
13
13
  !1,
14
14
  null,
15
- "0c5f11a1"
15
+ "8fc59697"
16
16
  );
17
- const u = s.exports;
17
+ const v = n.exports;
18
18
  export {
19
- u as default
19
+ v as default
20
20
  };
@@ -1,82 +1,79 @@
1
- import { defineComponent as Se, defineAsyncComponent as a, ref as W, computed as l, watch as $, onMounted as he, onUnmounted as Ee } from "vue";
2
- import { useCortexBlueprintBridge as Ce } from "../composables/useCortexBlueprintBridge.js";
3
- import { useEditorLock as De } from "../composables/useEditorLock.js";
4
- import { startEditorOpenMetrics as we } from "../composables/useEditorOpenMetrics.js";
5
- import { provideGuidoActions as Te } from "../composables/useGuidoActions.js";
6
- import { useGuidoStateBridge as ke } from "../composables/useGuidoStateBridge.js";
7
- import { usePartner as Fe } from "../composables/usePartner.js";
8
- import { useSaveValidationRollout as Me } from "../composables/useSaveValidationRollout.js";
9
- import { useStripo as Ie } from "../composables/useStripo.js";
10
- import { useTimerClone as Le } from "../composables/useTimerClone.js";
11
- import { useToaster as Re } from "../composables/useToaster.js";
12
- import { useTranslations as Oe } from "../composables/useTranslations.js";
13
- import { migrate as Ue } from "../config/migrator/index.js";
14
- import { ModuleFolderDefaults as G } from "../enums/defaults.js";
15
- import { RIBBON_SELECTOR as Ae } from "../enums/onboarding.js";
16
- import { ToasterTypeOptions as Ne } from "../enums/toaster.js";
17
- import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as _e } from "../extensions/Blocks/Recommendation/store/recommendation.js";
18
- import { disposeUnsubscribeListeners as Pe } from "../extensions/Blocks/Unsubscribe/block.js";
19
- import { disposeDisplayConditionRequest as xe } from "../extensions/DisplayConditions/bridge.js";
20
- import Be from "./organisms/AutoSaveController.vue.js";
21
- import He from "./organisms/base/AuthErrorModal.vue.js";
22
- import Ve from "./organisms/base/Toaster.vue.js";
23
- import We from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
24
- import $e from "./organisms/header/HeaderWrapper.vue.js";
25
- import Ge from "./organisms/LoadingWrapper.vue.js";
26
- import ze from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
27
- import qe from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
28
- import Ke from "./organisms/validation/ValidationErrorDrawer.vue.js";
29
- import { useStripoApi as je } from "../services/stripoApi.js";
30
- import { useConfigStore as Je } from "../stores/config.js";
31
- import { useDynamicContentStore as Qe } from "../stores/dynamic-content.js";
1
+ import { defineComponent as ye, defineAsyncComponent as a, ref as W, computed as l, watch as G, onMounted as be, onUnmounted as ve } from "vue";
2
+ import { useCortexBlueprintBridge as Se } from "../composables/useCortexBlueprintBridge.js";
3
+ import { useEditorLock as he } from "../composables/useEditorLock.js";
4
+ import { startEditorOpenMetrics as Ee } from "../composables/useEditorOpenMetrics.js";
5
+ import { provideGuidoActions as Ce } from "../composables/useGuidoActions.js";
6
+ import { useGuidoStateBridge as De } from "../composables/useGuidoStateBridge.js";
7
+ import { usePartner as we } from "../composables/usePartner.js";
8
+ import { useSaveValidationRollout as Te } from "../composables/useSaveValidationRollout.js";
9
+ import { useStripo as ke } from "../composables/useStripo.js";
10
+ import { useTimerClone as Fe } from "../composables/useTimerClone.js";
11
+ import { useToaster as Ie } from "../composables/useToaster.js";
12
+ import { useTranslations as Le } from "../composables/useTranslations.js";
13
+ import { migrate as Me } from "../config/migrator/index.js";
14
+ import { ModuleFolderDefaults as $ } from "../enums/defaults.js";
15
+ import { RIBBON_SELECTOR as Re } from "../enums/onboarding.js";
16
+ import { ToasterTypeOptions as Oe } from "../enums/toaster.js";
17
+ import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as Ue } from "../extensions/Blocks/Recommendation/store/recommendation.js";
18
+ import { disposeUnsubscribeListeners as Ne } from "../extensions/Blocks/Unsubscribe/block.js";
19
+ import { disposeDisplayConditionRequest as _e } from "../extensions/DisplayConditions/bridge.js";
20
+ import Ae from "./organisms/AutoSaveController.vue.js";
21
+ import Pe from "./organisms/base/AuthErrorModal.vue.js";
22
+ import xe from "./organisms/base/Toaster.vue.js";
23
+ import Be from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
24
+ import He from "./organisms/header/HeaderWrapper.vue.js";
25
+ import Ve from "./organisms/LoadingWrapper.vue.js";
26
+ import We from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
27
+ import Ge from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
28
+ import $e from "./organisms/validation/ValidationErrorDrawer.vue.js";
29
+ import { useStripoApi as ze } from "../services/stripoApi.js";
30
+ import { useConfigStore as qe } from "../stores/config.js";
31
+ import { useDynamicContentStore as Ke } from "../stores/dynamic-content.js";
32
32
  import { useEditorStore as C } from "../stores/editor.js";
33
- import { useModuleDynamicContentStore as q } from "../stores/module-dynamic-content.js";
34
- import { useOnboardingStore as Xe } from "../stores/onboarding.js";
35
- import { usePreviewStore as Ye } from "../stores/preview.js";
36
- import { useSaveValidationStore as Ze } from "../stores/save-validation.js";
37
- import { useTemplateStore as et } from "../stores/template.js";
38
- import { useUnsubscribeStore as tt } from "../stores/unsubscribe.js";
39
- import { readTrackFloor as K } from "../utils/linkTrackingIds.js";
40
- const Vt = /* @__PURE__ */ Se({
33
+ import { useOnboardingStore as je } from "../stores/onboarding.js";
34
+ import { usePreviewStore as Je } from "../stores/preview.js";
35
+ import { useSaveValidationStore as Qe } from "../stores/save-validation.js";
36
+ import { useTemplateStore as Xe } from "../stores/template.js";
37
+ import { useUnsubscribeStore as Ye } from "../stores/unsubscribe.js";
38
+ import { readTrackFloor as q } from "../utils/linkTrackingIds.js";
39
+ const Pt = /* @__PURE__ */ ye({
41
40
  __name: "Guido",
42
41
  props: {
43
42
  config: null,
44
43
  ready: { type: Boolean, default: !0 }
45
44
  },
46
45
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
47
- setup(j, { expose: J, emit: i }) {
48
- const c = j, r = we(), Q = a(
46
+ setup(K, { expose: j, emit: i }) {
47
+ const c = K, r = Ee(), J = a(
49
48
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
50
- ), X = a(
49
+ ), Q = a(
51
50
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
52
- ), Y = a(
51
+ ), X = a(
53
52
  () => import("./organisms/extensions/recommendation/AssignStrategyDrawer.vue.js")
54
- ), Z = a(
53
+ ), Y = a(
55
54
  () => import("./organisms/extensions/recommendation/RemoveStrategyModal.vue.js")
56
- ), ee = a(
55
+ ), Z = a(
57
56
  () => import("./organisms/display-conditions/DisplayConditionsHost.vue.js")
58
- ), D = W(), te = a(
57
+ ), D = W(), ee = a(
59
58
  () => import("./organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js")
60
- ), oe = a(
59
+ ), te = a(
61
60
  () => import("./organisms/unsubscribe/LegacyUnsubscribeConvertedModal.vue.js")
62
- ), ne = a(
63
- () => import("./organisms/dynamic-content/AmbiguousDynamicContentModal.vue.js")
64
- ), y = W(), g = Qe(), w = tt(), re = q(), o = Je();
61
+ ), g = W(), y = Ke(), w = Ye(), o = qe();
65
62
  c.ready && o.init(c.config);
66
- const d = C(), ie = Ye(), p = l(() => d.hasChanges), { isTestPartner: se } = Fe(), { isEnabled: ae, loadRollout: T } = Me(), { showToaster: k } = Re(), F = Oe(), M = () => {
63
+ const d = C(), oe = Je(), p = l(() => d.hasChanges), { isTestPartner: ne } = we(), { isEnabled: re, loadRollout: T } = Te(), { showToaster: k } = Ie(), F = Le(), I = () => {
67
64
  var t;
68
65
  if (d.isVersionHistoryOpen) {
69
66
  console.debug("guido:save:silent:blocked", { isVersionHistoryOpen: !0 }), k({
70
- type: Ne.Warning,
67
+ type: Oe.Warning,
71
68
  message: F("email-editor.save-blocked-outside-editor")
72
69
  });
73
70
  return;
74
71
  }
75
72
  return (t = D.value) == null ? void 0 : t.saveSilent();
76
- }, I = (t) => {
73
+ }, L = (t) => {
77
74
  d.loadingStatus = t;
78
75
  };
79
- Ce(), ke();
76
+ Se(), De();
80
77
  const b = () => {
81
78
  var t, e;
82
79
  return {
@@ -84,20 +81,20 @@ const Vt = /* @__PURE__ */ Se({
84
81
  userId: o.userId,
85
82
  username: o.username,
86
83
  partnerName: o.partnerName,
87
- savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || G.SAVED_MODULES,
88
- defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || G.DEFAULT_MODULES
84
+ savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || $.SAVED_MODULES,
85
+ defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || $.DEFAULT_MODULES
89
86
  };
90
- }, { initPlugin: L, preloadRuntime: R } = Ie(r), { runExclusive: O, beginMount: U, isCurrentMount: v } = De();
87
+ }, { initPlugin: M, preloadRuntime: R } = ke(r), { runExclusive: O, beginMount: U, isCurrentMount: v } = he();
91
88
  let f = 0;
92
- const { getDefaultTemplate: A } = je(), { cloneTimersOnSave: N, hasTimerBlocks: _ } = Le(), ce = l(() => {
89
+ const { getDefaultTemplate: N } = ze(), { cloneTimersOnSave: _, hasTimerBlocks: A } = Fe(), ie = l(() => {
93
90
  var t;
94
91
  return !((t = o.ui) != null && t.showHeader);
95
- }), de = l(() => o.isFeatureEnabled("reusableRecommendationStrategy")), me = l(() => o.externalDisplayConditions), le = l(
92
+ }), se = l(() => o.isFeatureEnabled("reusableRecommendationStrategy")), ae = l(() => o.externalDisplayConditions), ce = l(
96
93
  () => o.isFeatureEnabled("legacyUnsubscribeConversion")
97
- ), ue = l(
94
+ ), de = l(
98
95
  () => !!z().recommendationConfigs.strategyId
99
96
  );
100
- Te({
97
+ Ce({
101
98
  onBack: () => {
102
99
  console.debug("guido:back"), i("back");
103
100
  },
@@ -113,11 +110,11 @@ const Vt = /* @__PURE__ */ Se({
113
110
  }
114
111
  });
115
112
  const P = (t) => {
116
- console.debug("dynamic-content:close", t), g.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
113
+ console.debug("dynamic-content:close", t), y.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
117
114
  }, x = () => {
118
115
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
119
116
  };
120
- $(() => p.value, () => {
117
+ G(() => p.value, () => {
121
118
  i("on-change", p.value);
122
119
  });
123
120
  const S = (t) => {
@@ -127,8 +124,8 @@ const Vt = /* @__PURE__ */ Se({
127
124
  let m = null;
128
125
  const h = () => {
129
126
  var e;
130
- const t = document.querySelector(Ae);
131
- (e = y.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
127
+ const t = document.querySelector(Re);
128
+ (e = g.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
132
129
  }, E = async () => {
133
130
  var t;
134
131
  r.mark("host_ready");
@@ -141,49 +138,49 @@ const Vt = /* @__PURE__ */ Se({
141
138
  });
142
139
  const e = o.template, s = (e == null ? void 0 : e.html) || "", u = (e == null ? void 0 : e.css) || "", B = (e == null ? void 0 : e.preselectedDynamicContent) || [];
143
140
  w.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
144
- const pe = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, H = o.isFeatureEnabled("linkTrackingIds"), fe = {
141
+ const me = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, H = o.isFeatureEnabled("linkTrackingIds"), le = {
145
142
  partnerName: o.partnerName,
146
143
  campaignUrls: e == null ? void 0 : e.recommendationCampaignUrls,
147
144
  rrsEnabled: o.isFeatureEnabled("reusableRecommendationStrategy")
148
- }, ye = {
145
+ }, ue = {
149
146
  itemsPriceFormatting: o.isFeatureEnabled("itemsPriceFormatting")
150
- }, V = (ve) => r.timed(
147
+ }, V = (ge) => r.timed(
151
148
  "migration",
152
- () => Ue(ve, pe, fe, ye)
149
+ () => Me(ge, me, le, ue)
153
150
  );
154
151
  let n = {
155
152
  html: s && await V(s),
156
153
  css: u
157
154
  };
158
- n.html || (n = await r.timed("default_template", () => A()), n.html = await V(n.html));
159
- const ge = H ? K(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
160
- _(n.html) && (n.html = await r.timed("timer_clone", () => N(n.html))), H && (d.trackIdSessionFloor = Math.max(ge, K(n.html)));
161
- const be = {
155
+ n.html || (n = await r.timed("default_template", () => N()), n.html = await V(n.html));
156
+ const pe = H ? q(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
157
+ A(n.html) && (n.html = await r.timed("timer_clone", () => _(n.html))), H && (d.trackIdSessionFloor = Math.max(pe, q(n.html)));
158
+ const fe = {
162
159
  preselectedDynamicContentList: B,
163
160
  onReady: () => {
164
161
  console.debug("guido:ready"), i("ready");
165
162
  }
166
163
  };
167
- f = U(), await L(n, b(), be, n.html !== s), g.selectedDynamicContentList = B;
164
+ f = U(), await M(n, b(), fe, n.html !== s), y.selectedDynamicContentList = B;
168
165
  } catch (e) {
169
166
  console.error("Failed to initialize Stripo editor:", e), r.markFailed();
170
167
  }
171
168
  };
172
- return he(async () => {
169
+ return be(async () => {
173
170
  var e;
174
- console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), C().$reset(), et().$reset(), Ze().$reset(), q().$reset(), Xe().resetOnboarding("recommendationLegacyStrategyOnboarding"), T(), h();
175
- const t = (e = y.value) == null ? void 0 : e.parentElement;
171
+ console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), C().$reset(), Xe().$reset(), Qe().$reset(), je().resetOnboarding("recommendationLegacyStrategyOnboarding"), T(), h();
172
+ const t = (e = g.value) == null ? void 0 : e.parentElement;
176
173
  if (t && (m = new ResizeObserver(h), m.observe(t)), R(), c.ready)
177
174
  await E();
178
175
  else {
179
- const s = $(() => c.ready, (u) => {
176
+ const s = G(() => c.ready, (u) => {
180
177
  u && (s(), E());
181
178
  });
182
179
  }
183
180
  document.addEventListener("dynamic-content:open", S);
184
- }), Ee(() => {
185
- if (Pe(), _e(), r.dispose(), m == null || m.disconnect(), document.removeEventListener("dynamic-content:open", S), v(f)) {
186
- xe();
181
+ }), ve(() => {
182
+ if (Ne(), Ue(), r.dispose(), m == null || m.disconnect(), document.removeEventListener("dynamic-content:open", S), v(f)) {
183
+ _e();
187
184
  try {
188
185
  const t = C();
189
186
  t.isStripoInitialized = !1, t.isAccessibilityTestingOpen = !1, t.imagesHidden = !1, t.colorVisionDeficiency = "";
@@ -199,17 +196,17 @@ const Vt = /* @__PURE__ */ Se({
199
196
  console.debug("Failed to remove Stripo editor: No editor found");
200
197
  }
201
198
  }), o.reset();
202
- }), J({
199
+ }), j({
203
200
  dynamicContent: {
204
201
  insert: P,
205
202
  close: x
206
203
  },
207
204
  hasChanges: p,
208
- saveSilent: M,
209
- setLoading: I
210
- }), { __sfc: !0, openMetrics: r, PreviewContainer: Q, OnboardingWrapper: X, AssignStrategyDrawer: Y, RemoveStrategyModal: Z, DisplayConditionsHost: ee, autoSaveControllerRef: D, LegacyStrategyUpdatedModal: te, LegacyUnsubscribeConvertedModal: oe, AmbiguousDynamicContentModal: ne, wrapperRef: y, dynamicContentStore: g, unsubscribeStore: w, moduleDynamicContentStore: re, props: c, configStore: o, editorStore: d, previewStore: ie, hasChanges: p, isTestPartner: se, isSaveValidationEnabled: ae, loadRollout: T, showToaster: k, trans: F, saveSilent: M, setLoading: I, emit: i, buildMetadata: b, initPlugin: L, preloadRuntime: R, runExclusive: O, beginMount: U, isCurrentMount: v, mountGeneration: f, getDefaultTemplate: A, cloneTimersOnSave: N, hasTimerBlocks: _, noHeader: ce, isRrsEnabled: de, isExternalDisplayConditionsEnabled: me, isLegacyUnsubscribeConversionEnabled: le, hasAssignedStrategy: ue, insertDynamicContent: P, closeDynamicContent: x, handleDynamicContentOpen: S, ribbonObserver: m, updateRibbonOffset: h, startEditor: E, AutoSaveController: Be, AuthErrorModal: He, Toaster: Ve, FilterSelectionDrawer: We, HeaderWrapper: $e, LoadingWrapper: Ge, SaveAsTemplateDrawer: ze, UnsubscribeWrapper: qe, ValidationErrorDrawer: Ke };
205
+ saveSilent: I,
206
+ setLoading: L
207
+ }), { __sfc: !0, openMetrics: r, PreviewContainer: J, OnboardingWrapper: Q, AssignStrategyDrawer: X, RemoveStrategyModal: Y, DisplayConditionsHost: Z, autoSaveControllerRef: D, LegacyStrategyUpdatedModal: ee, LegacyUnsubscribeConvertedModal: te, wrapperRef: g, dynamicContentStore: y, unsubscribeStore: w, props: c, configStore: o, editorStore: d, previewStore: oe, hasChanges: p, isTestPartner: ne, isSaveValidationEnabled: re, loadRollout: T, showToaster: k, trans: F, saveSilent: I, setLoading: L, emit: i, buildMetadata: b, initPlugin: M, preloadRuntime: R, runExclusive: O, beginMount: U, isCurrentMount: v, mountGeneration: f, getDefaultTemplate: N, cloneTimersOnSave: _, hasTimerBlocks: A, noHeader: ie, isRrsEnabled: se, isExternalDisplayConditionsEnabled: ae, isLegacyUnsubscribeConversionEnabled: ce, hasAssignedStrategy: de, insertDynamicContent: P, closeDynamicContent: x, handleDynamicContentOpen: S, ribbonObserver: m, updateRibbonOffset: h, startEditor: E, AutoSaveController: Ae, AuthErrorModal: Pe, Toaster: xe, FilterSelectionDrawer: Be, HeaderWrapper: He, LoadingWrapper: Ve, SaveAsTemplateDrawer: We, UnsubscribeWrapper: Ge, ValidationErrorDrawer: $e };
211
208
  }
212
209
  });
213
210
  export {
214
- Vt as default
211
+ Pt as default
215
212
  };
@@ -1,8 +1,8 @@
1
1
  import { defaultHtmlCompilerRules as d } from "../config/compiler/htmlCompilerRules.js";
2
2
  import { itemsCompilerRules as f } from "../config/compiler/itemsCompilerRules.js";
3
3
  import { liquidCompilerRules as g } from "../config/compiler/liquidCompilerRules.js";
4
- import { outlookCompilerRules as v } from "../config/compiler/outlookCompilerRules.js";
5
- import { recommendationCompilerRules as R } from "../config/compiler/recommendationCompilerRules.js";
4
+ import { outlookCompilerRules as R } from "../config/compiler/outlookCompilerRules.js";
5
+ import { recommendationCompilerRules as v } from "../config/compiler/recommendationCompilerRules.js";
6
6
  import { socialCompilerRules as H } from "../config/compiler/socialCompilerRules.js";
7
7
  import { unsubscribeCompilerRules as b } from "../config/compiler/unsubscribeCompilerRules.js";
8
8
  import { createHtmlCompiler as n } from "../utils/htmlCompiler.js";
@@ -32,20 +32,19 @@ const x = /* @__PURE__ */ new Set([
32
32
  "liquid-coupon-code",
33
33
  // Editor-only attribute strip — AMP4EMAIL has no `contenteditable`, so leaving
34
34
  // it in narrows/breaks rendering. Pure attribute removal, emits nothing.
35
- "remove-contenteditable",
36
- "remove-dc-pending-marker"
35
+ "remove-contenteditable"
37
36
  ]), I = () => {
38
- const { compiler: i, isFeatureEnabled: a, partner: u } = C(), c = p(() => {
37
+ const { compiler: i, isFeatureEnabled: u, partner: a } = C(), c = p(() => {
39
38
  var m, l;
40
39
  const e = ((m = i.value) == null ? void 0 : m.customRules) || [];
41
40
  return [
42
41
  ...!!((l = i.value) != null && l.ignoreDefaultRules) ? [] : d,
43
- ...R,
42
+ ...v,
44
43
  ...b,
45
44
  ...f,
46
- ...v,
45
+ ...R,
47
46
  ...H,
48
- ...a("liquidSyntax") ? g : [],
47
+ ...u("liquidSyntax") ? g : [],
49
48
  ...e.map((t, o) => ({
50
49
  ...t,
51
50
  priority: t.priority + 1e3 + o
@@ -54,7 +53,7 @@ const x = /* @__PURE__ */ new Set([
54
53
  ];
55
54
  }), r = p(() => {
56
55
  var t;
57
- const e = c.value, s = n(e), m = n(e.filter((o) => x.has(o.id))), l = (t = u.value) == null ? void 0 : t.fallbackFont;
56
+ const e = c.value, s = n(e), m = n(e.filter((o) => x.has(o.id))), l = (t = a.value) == null ? void 0 : t.fallbackFont;
58
57
  return {
59
58
  compileHtml: (o) => s.compile(o, void 0, l),
60
59
  compileAmpHtml: (o) => m.compile(o, void 0, l)
@@ -1,75 +1,44 @@
1
- import { useConfig as h } from "./useConfig.js";
2
- import { useToaster as v } from "./useToaster.js";
3
- import { useTranslations as M } from "./useTranslations.js";
4
- import { ModuleDynamicContentAttribute as T } from "../enums/dynamic-content.js";
5
- import { ToasterTypeOptions as A } from "../enums/toaster.js";
6
- import { itemsBlockDynamicVariables as O } from "../extensions/Blocks/Items/enums/productEnums.js";
7
- import { useDynamicContentStore as E } from "../stores/dynamic-content.js";
8
- import { useEditorStore as L } from "../stores/editor.js";
9
- import { useModuleDynamicContentStore as U } from "../stores/module-dynamic-content.js";
10
- import { buildDynamicContentLookup as _, convertModuleDynamicContent as F } from "../utils/dynamicContentConverter.js";
11
- import { stripPendingMarker as P } from "../utils/dynamicContentPendingMarker.js";
12
- import { flattenDynamicContentCandidates as S } from "../utils/genericUtil.js";
13
- import { repairItemsCurrencyAttributes as N } from "../utils/itemsCurrencyRepair.js";
14
- import { convertLegacyUnsubscribeInModuleHtml as R } from "../utils/legacyUnsubscribeConversion.js";
15
- import { extractUsedDynamicContent as k } from "../utils/registerUsedDynamicContent.js";
16
- const q = "dynamic-content.unresolved-attributes-on-drop", H = /^(\s*<[a-zA-Z][a-zA-Z0-9-]*)/;
17
- let y = 0;
18
- const $ = (s) => {
19
- y += 1;
20
- const o = `${Date.now().toString(36)}-${y}`;
21
- return { html: s.replace(H, `$1 ${T.Pending}="${o}"`), id: o };
22
- }, I = (s, o) => {
23
- try {
24
- const i = k(s, o.map(({ text: a, value: m }) => ({ text: a, value: m })));
25
- i.length > 0 && E().registerDynamicContent(i);
26
- } catch (i) {
27
- console.error("Failed to register module dynamic content:", i);
28
- }
29
- }, re = () => {
30
- const { template: s, isFeatureEnabled: o } = h(), { showToaster: i } = v(), a = M(), m = (r) => {
31
- var u, e;
32
- const t = o("liquidSyntax") ? [] : S((u = s.value) == null ? void 0 : u.dynamicContentList), c = _(t);
33
- return c.size === 0 ? { html: r, unresolved: [], ambiguous: [], candidates: t } : {
34
- ...F(
35
- r,
36
- c,
37
- [...((e = s.value) == null ? void 0 : e.customFieldAttributes) ?? [], ...O]
38
- ),
39
- candidates: t
40
- };
41
- };
42
- return { handleModuleAdd: (r, t) => {
43
- var c, u;
1
+ import { useConfig as f } from "./useConfig.js";
2
+ import { useToaster as d } from "./useToaster.js";
3
+ import { useTranslations as C } from "./useTranslations.js";
4
+ import { ToasterTypeOptions as T } from "../enums/toaster.js";
5
+ import { useEditorStore as h } from "../stores/editor.js";
6
+ import { buildDynamicContentLookup as v, convertModuleDynamicContent as D } from "../utils/dynamicContentConverter.js";
7
+ import { flattenDynamicContentList as L } from "../utils/genericUtil.js";
8
+ import { repairItemsCurrencyAttributes as M } from "../utils/itemsCurrencyRepair.js";
9
+ import { convertLegacyUnsubscribeInModuleHtml as O } from "../utils/legacyUnsubscribeConversion.js";
10
+ const E = "dynamic-content.unresolved-attributes-on-drop", S = () => {
11
+ const { template: p, isFeatureEnabled: n } = f(), { showToaster: y } = d(), b = C();
12
+ return { handleModuleAdd: (t, r) => {
13
+ var c, i, l;
44
14
  try {
45
- if ((r == null ? void 0 : r.action) !== "ADD" && (r == null ? void 0 : r.action) !== "COPY")
15
+ if ((t == null ? void 0 : t.action) !== "ADD" && (t == null ? void 0 : t.action) !== "COPY")
46
16
  return;
47
- const e = (c = t == null ? void 0 : t.getTargetNode) == null ? void 0 : c.call(t), l = (u = e == null ? void 0 : e.getOuterHTML) == null ? void 0 : u.call(e);
48
- if (!e || typeof l != "string")
17
+ const e = (c = r == null ? void 0 : r.getTargetNode) == null ? void 0 : c.call(r), s = (i = e == null ? void 0 : e.getOuterHTML) == null ? void 0 : i.call(e);
18
+ if (!e || typeof s != "string")
49
19
  return;
50
- let n = P(N(l, {
51
- convertToPriceFormat: o("itemsPriceFormatting")
52
- })), p = !1;
53
- o("legacyUnsubscribeConversion") && ({ html: n, converted: p } = R(n));
54
- const { html: f, unresolved: b, ambiguous: g, candidates: C } = m(n);
55
- let d = null;
56
- if (n = f, g.length > 0 && ({ html: n, id: d } = $(n)), n !== l && t.modifyHtml(e).replaceWith(n), I(n, C), p)
20
+ let o = M(s, {
21
+ convertToPriceFormat: n("itemsPriceFormatting")
22
+ }), u = !1;
23
+ n("legacyUnsubscribeConversion") && ({ html: o, converted: u } = O(o));
24
+ const m = v(L((l = p.value) == null ? void 0 : l.dynamicContentList));
25
+ let a = [];
26
+ if (m.size > 0 && ({ html: o, unresolved: a } = D(o, m, n("liquidSyntax"))), o !== s && r.modifyHtml(e).replaceWith(o), u)
57
27
  try {
58
- L().isLegacyUnsubscribeModalRequested = !0;
59
- } catch (D) {
60
- console.error("Failed to request the legacy unsubscribe modal:", D);
28
+ h().isLegacyUnsubscribeModalRequested = !0;
29
+ } catch (g) {
30
+ console.error("Failed to request the legacy unsubscribe modal:", g);
61
31
  }
62
- d && U().enqueue({ id: d, items: g }), b.length > 0 && i({
63
- type: A.Warning,
64
- message: a(q)
32
+ a.length > 0 && y({
33
+ type: T.Warning,
34
+ message: b(E)
65
35
  });
66
36
  } catch (e) {
67
37
  console.error("Failed to repair module on add:", e);
68
38
  }
69
- }, convertDynamicContent: m };
39
+ } };
70
40
  };
71
41
  export {
72
- q as UNRESOLVED_DYNAMIC_CONTENT_ON_DROP_KEY,
73
- I as registerUsedAttributes,
74
- re as useModuleRepair
42
+ E as UNRESOLVED_DYNAMIC_CONTENT_ON_DROP_KEY,
43
+ S as useModuleRepair
75
44
  };
@@ -3,9 +3,9 @@ import { MinDeviceViewport as C, DefaultPadding as R } from "../enums/recommenda
3
3
  import { useRecommendationExtensionStore as g } from "../extensions/Blocks/Recommendation/store/recommendation.js";
4
4
  import { generateCompleteFilterQuery as b } from "../extensions/Blocks/Recommendation/utils/filterUtil.js";
5
5
  import { getPartnerRecommendationParams as h } from "../extensions/Blocks/Recommendation/utils/partnerCustomizations.js";
6
- import { sanitizeProductIds as x } from "../extensions/Blocks/Recommendation/utils/productIds.js";
7
- import { useConfigStore as P } from "../stores/config.js";
8
- const B = () => ({
6
+ import { sanitizeProductIds as P } from "../extensions/Blocks/Recommendation/utils/productIds.js";
7
+ import { useConfigStore as S } from "../stores/config.js";
8
+ const M = () => ({
9
9
  calculateCardWidth: ({
10
10
  mobileLeftPadding: s,
11
11
  mobileRightPadding: c,
@@ -24,11 +24,7 @@ const B = () => ({
24
24
  mobileLeftPadding: 0,
25
25
  mobileRightPadding: 0,
26
26
  cardsInRow: 2,
27
- unresponsive: !1,
28
- priceBeforeTextValue: "",
29
- priceAfterTextValue: "",
30
- discountBeforeTextValue: "",
31
- discountAfterTextValue: ""
27
+ unresponsive: !1
32
28
  };
33
29
  const { recommendationConfigs: i } = a, e = i.orientation === "grid" ? "vertical" : "horizontal";
34
30
  return {
@@ -37,16 +33,12 @@ const B = () => ({
37
33
  mobileLeftPadding: 0,
38
34
  mobileRightPadding: 0,
39
35
  cardsInRow: i.cardsInRow,
40
- unresponsive: i.unresponsive,
41
- priceBeforeTextValue: "",
42
- priceAfterTextValue: "",
43
- discountBeforeTextValue: "",
44
- discountAfterTextValue: ""
36
+ unresponsive: i.unresponsive
45
37
  };
46
38
  },
47
39
  buildCampaignUrl: (s, c) => {
48
40
  var l;
49
- const o = g(), a = P(), i = Number(s);
41
+ const o = g(), a = S(), i = Number(s);
50
42
  let e;
51
43
  if (c)
52
44
  e = c;
@@ -78,7 +70,7 @@ const B = () => ({
78
70
  return delete r[s], o.recommendationCampaignUrls = r, "";
79
71
  }
80
72
  const t = new URLSearchParams();
81
- t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", a.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", a.variationId), e.strategy === "manualMerchandising" ? t.set("productId", x(e.productIds)) : e.strategy === "similarViewed" && t.set("productId", "{itemId}"), e.strategy === "userBased" && t.set("userId", "{user_id}");
73
+ t.set("locale", e.language), t.set("currency", e.currencyCode), t.set("partnerName", a.partnerName), t.set("size", e.size), t.set("details", "true"), t.set("campaignId", a.variationId), e.strategy === "manualMerchandising" ? t.set("productId", P(e.productIds)) : e.strategy === "similarViewed" && t.set("productId", "{itemId}"), e.strategy === "userBased" && t.set("userId", "{user_id}");
82
74
  const f = e.filters.filter((r) => r.isValid), m = b(f);
83
75
  m && t.set("filter", m), e.shuffleProducts && t.set("shuffle", "true"), Object.entries(h(a.partnerName, e.strategy)).forEach(([r, n]) => t.set(r, n));
84
76
  const p = decodeURIComponent(t.toString()), u = `${I.RECOMMENDATION_API_URL}/v2/${d}?${p}`;
@@ -86,5 +78,5 @@ const B = () => ({
86
78
  }
87
79
  });
88
80
  export {
89
- B as useRecommendation
81
+ M as useRecommendation
90
82
  };