@useinsider/guido 3.4.1-beta.6fad109 → 3.4.1-beta.7f60a52

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.
@@ -12,7 +12,7 @@ var t = function() {
12
12
  n,
13
13
  !1,
14
14
  null,
15
- "b293a2b0"
15
+ "cdee3452"
16
16
  );
17
17
  const l = s.exports;
18
18
  export {
@@ -1,44 +1,42 @@
1
- import { defineComponent as Q, defineAsyncComponent as N, ref as I, computed as W, watch as X, onMounted as Y, onUnmounted as Z } from "vue";
2
- import { useCortexBlueprintBridge as ee } from "../composables/useCortexBlueprintBridge.js";
3
- import { provideGuidoActions as oe } from "../composables/useGuidoActions.js";
4
- import { useGuidoStateBridge as te } from "../composables/useGuidoStateBridge.js";
5
- import { usePartner as ne } from "../composables/usePartner.js";
6
- import { useStripo as re } from "../composables/useStripo.js";
7
- import { useTimerClone as se } from "../composables/useTimerClone.js";
1
+ import { defineComponent as J, defineAsyncComponent as R, ref as I, computed as W, watch as Q, onMounted as X, onUnmounted as Y } from "vue";
2
+ import { useCortexBlueprintBridge as Z } from "../composables/useCortexBlueprintBridge.js";
3
+ import { provideGuidoActions as ee } from "../composables/useGuidoActions.js";
4
+ import { useGuidoStateBridge as oe } from "../composables/useGuidoStateBridge.js";
5
+ import { usePartner as te } from "../composables/usePartner.js";
6
+ import { useStripo as ne } from "../composables/useStripo.js";
7
+ import { useTimerClone as re } from "../composables/useTimerClone.js";
8
8
  import { migrate as x } from "../config/migrator/index.js";
9
9
  import { ModuleFolderDefaults as G } from "../enums/defaults.js";
10
- import { RIBBON_SELECTOR as ce } from "../enums/onboarding.js";
11
- import { useRecommendationExtensionStore as ae } from "../extensions/Blocks/Recommendation/store/recommendation.js";
12
- import ie from "./organisms/AutoSaveController.vue.js";
13
- import me from "./organisms/base/Toaster.vue.js";
14
- import de from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
15
- import le from "./organisms/header/HeaderWrapper.vue.js";
16
- import ue from "./organisms/LoadingWrapper.vue.js";
17
- import pe from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
18
- import fe from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
19
- import { useStripoApi as ve } from "../services/stripoApi.js";
20
- import { useConfigStore as ye } from "../stores/config.js";
21
- import { useDynamicContentStore as Se } from "../stores/dynamic-content.js";
22
- import { useEditorStore as H } from "../stores/editor.js";
10
+ import { RIBBON_SELECTOR as se } from "../enums/onboarding.js";
11
+ import ce from "./organisms/AutoSaveController.vue.js";
12
+ import ae from "./organisms/base/Toaster.vue.js";
13
+ import ie from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
14
+ import me from "./organisms/header/HeaderWrapper.vue.js";
15
+ import de from "./organisms/LoadingWrapper.vue.js";
16
+ import le from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
17
+ import ue from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
18
+ import { useStripoApi as pe } from "../services/stripoApi.js";
19
+ import { useConfigStore as fe } from "../stores/config.js";
20
+ import { useDynamicContentStore as ve } from "../stores/dynamic-content.js";
21
+ import { useEditorStore as ye } from "../stores/editor.js";
23
22
  import { usePreviewStore as he } from "../stores/preview.js";
24
- import { useTemplateStore as be } from "../stores/template.js";
25
- import { useUnsubscribeStore as ge } from "../stores/unsubscribe.js";
26
- const Ke = /* @__PURE__ */ Q({
23
+ import { useUnsubscribeStore as Se } from "../stores/unsubscribe.js";
24
+ const He = /* @__PURE__ */ J({
27
25
  __name: "Guido",
28
26
  props: {
29
27
  config: null
30
28
  },
31
29
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
32
- setup($, { expose: z, emit: n }) {
33
- const g = $, q = N(
30
+ setup(H, { expose: z, emit: n }) {
31
+ const g = H, q = R(
34
32
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
35
- ), K = N(
33
+ ), K = R(
36
34
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
37
- ), E = I(), u = I(), p = Se(), w = ge(), i = ye();
35
+ ), w = I(), u = I(), p = ve(), E = Se(), i = fe();
38
36
  i.init(g.config);
39
- const f = H(), V = he(), m = W(() => f.hasChanges), { isTestPartner: j } = ne(), D = () => {
37
+ const f = ye(), V = he(), m = W(() => f.hasChanges), { isTestPartner: $ } = te(), D = () => {
40
38
  var e;
41
- return (e = E.value) == null ? void 0 : e.handleSave(!0);
39
+ return (e = w.value) == null ? void 0 : e.handleSave(!0);
42
40
  }, {
43
41
  templateId: v,
44
42
  userId: C,
@@ -47,8 +45,8 @@ const Ke = /* @__PURE__ */ Q({
47
45
  template: o,
48
46
  editor: s
49
47
  } = i, d = (o == null ? void 0 : o.html) || "", F = (o == null ? void 0 : o.css) || "", y = (o == null ? void 0 : o.preselectedDynamicContent) || [], L = (s == null ? void 0 : s.savedModulesFolderName) || G.SAVED_MODULES, U = (s == null ? void 0 : s.defaultModulesFolderName) || G.DEFAULT_MODULES;
50
- ee(), te();
51
- const S = {
48
+ f.templateId = v, Z(), oe();
49
+ const h = {
52
50
  emailId: v,
53
51
  userId: C,
54
52
  username: k,
@@ -60,11 +58,11 @@ const Ke = /* @__PURE__ */ Q({
60
58
  onReady: () => {
61
59
  console.debug("guido:ready"), n("ready");
62
60
  }
63
- }, { initPlugin: M } = re(S, _), { getDefaultTemplate: O } = ve(), { cloneTimersOnSave: P, hasTimerBlocks: R } = se(), J = W(() => {
61
+ }, { initPlugin: M } = ne(h, _), { getDefaultTemplate: O } = pe(), { cloneTimersOnSave: P, hasTimerBlocks: A } = re(), j = W(() => {
64
62
  var e;
65
63
  return !((e = i.ui) != null && e.showHeader);
66
64
  });
67
- oe({
65
+ ee({
68
66
  onBack: () => {
69
67
  console.debug("guido:back"), n("back");
70
68
  },
@@ -72,50 +70,50 @@ const Ke = /* @__PURE__ */ Q({
72
70
  console.debug("guido:save:start"), n("save:start");
73
71
  },
74
72
  onSaveComplete: (e) => {
75
- const t = { ...e, metadata: S };
73
+ const t = { ...e, metadata: h };
76
74
  console.debug("guido:save:complete", t), n("save:complete", t);
77
75
  },
78
76
  onTestEmailClick: () => {
79
77
  console.debug("guido:test-email:click"), n("test-email:click");
80
78
  }
81
79
  });
82
- const A = (e) => {
80
+ const B = (e) => {
83
81
  console.debug("dynamic-content:close", e), p.setSelectedDynamicContent(e), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: e }));
84
- }, B = () => {
82
+ }, N = () => {
85
83
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
86
84
  };
87
- X(() => m.value, () => {
85
+ Q(() => m.value, () => {
88
86
  n("on-change", m.value);
89
87
  });
90
- const h = (e) => {
88
+ const S = (e) => {
91
89
  const t = e, { attribute: l, position: a } = t.detail;
92
90
  console.debug("dynamic-content:open", t.detail), n("dynamic-content:open", l, a);
93
91
  };
94
92
  let c = null;
95
93
  const b = () => {
96
94
  var t;
97
- const e = document.querySelector(ce);
95
+ const e = document.querySelector(se);
98
96
  (t = u.value) == null || t.style.setProperty("--ribbon-offset", `${(e == null ? void 0 : e.offsetHeight) ?? 0}px`);
99
97
  };
100
- return Y(async () => {
98
+ return X(async () => {
101
99
  var t, l;
102
- console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), ae().$reset(), H().$reset(), f.templateId = v, be().$reset(), b();
100
+ console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), b();
103
101
  const e = (t = u.value) == null ? void 0 : t.parentElement;
104
102
  e && (c = new ResizeObserver(b), c.observe(e));
105
103
  try {
106
- w.selectedUnsubscribePages = (o == null ? void 0 : o.selectedUnsubscribePages) || [];
104
+ E.selectedUnsubscribePages = (o == null ? void 0 : o.selectedUnsubscribePages) || [];
107
105
  const a = ((l = o == null ? void 0 : o.migration) == null ? void 0 : l.recommendationConfigs) ?? {};
108
106
  let r = {
109
107
  html: d && await x(d, a),
110
108
  css: F
111
109
  };
112
- r.html || (r = await O(), r.html = await x(r.html, a)), R(r.html) && (r.html = await P(r.html)), await M(r), p.selectedDynamicContentList = y;
110
+ r.html || (r = await O(), r.html = await x(r.html, a)), A(r.html) && (r.html = await P(r.html)), await M(r), p.selectedDynamicContentList = y;
113
111
  } catch (a) {
114
112
  console.error("Failed to initialize Stripo editor:", a);
115
113
  }
116
- document.addEventListener("dynamic-content:open", h);
117
- }), Z(() => {
118
- c == null || c.disconnect(), document.removeEventListener("dynamic-content:open", h);
114
+ document.addEventListener("dynamic-content:open", S);
115
+ }), Y(() => {
116
+ c == null || c.disconnect(), document.removeEventListener("dynamic-content:open", S);
119
117
  try {
120
118
  window.UIEditor.removeEditor();
121
119
  } catch {
@@ -124,14 +122,14 @@ const Ke = /* @__PURE__ */ Q({
124
122
  i.reset();
125
123
  }), z({
126
124
  dynamicContent: {
127
- insert: A,
128
- close: B
125
+ insert: B,
126
+ close: N
129
127
  },
130
128
  hasChanges: m,
131
129
  saveSilent: D
132
- }), { __sfc: !0, PreviewContainer: q, OnboardingWrapper: K, headerWrapperRef: E, wrapperRef: u, dynamicContentStore: p, unsubscribeStore: w, props: g, configStore: i, editorStore: f, previewStore: V, hasChanges: m, isTestPartner: j, saveSilent: D, templateId: v, userId: C, partnerName: T, username: k, templateConfig: o, editorConfig: s, html: d, css: F, preselectedDynamicContentList: y, savedModulesFolderName: L, defaultModulesFolderName: U, emit: n, metadata: S, options: _, initPlugin: M, getDefaultTemplate: O, cloneTimersOnSave: P, hasTimerBlocks: R, noHeader: J, insertDynamicContent: A, closeDynamicContent: B, handleDynamicContentOpen: h, ribbonObserver: c, updateRibbonOffset: b, AutoSaveController: ie, Toaster: me, FilterSelectionDrawer: de, HeaderWrapper: le, LoadingWrapper: ue, SaveAsTemplateDrawer: pe, UnsubscribeWrapper: fe };
130
+ }), { __sfc: !0, PreviewContainer: q, OnboardingWrapper: K, headerWrapperRef: w, wrapperRef: u, dynamicContentStore: p, unsubscribeStore: E, props: g, configStore: i, editorStore: f, previewStore: V, hasChanges: m, isTestPartner: $, saveSilent: D, templateId: v, userId: C, partnerName: T, username: k, templateConfig: o, editorConfig: s, html: d, css: F, preselectedDynamicContentList: y, savedModulesFolderName: L, defaultModulesFolderName: U, emit: n, metadata: h, options: _, initPlugin: M, getDefaultTemplate: O, cloneTimersOnSave: P, hasTimerBlocks: A, noHeader: j, insertDynamicContent: B, closeDynamicContent: N, handleDynamicContentOpen: S, ribbonObserver: c, updateRibbonOffset: b, AutoSaveController: ce, Toaster: ae, FilterSelectionDrawer: ie, HeaderWrapper: me, LoadingWrapper: de, SaveAsTemplateDrawer: le, UnsubscribeWrapper: ue };
133
131
  }
134
132
  });
135
133
  export {
136
- Ke as default
134
+ He as default
137
135
  };
@@ -21,9 +21,9 @@ const v = () => {
21
21
  resetDataSavedFlag: !1,
22
22
  disableLineHeightsReplace: !0
23
23
  }, ...t }, s = {
24
- callback: (l, r, d, c, u) => {
24
+ callback: (l, p, d, c, u) => {
25
25
  l ? a(l) : e({
26
- html: r,
26
+ html: p,
27
27
  ampHtml: d,
28
28
  ampErrors: c,
29
29
  displayConditions: u
@@ -36,11 +36,11 @@ const v = () => {
36
36
  return {
37
37
  getCompiledEmail: m,
38
38
  getTemplateData: () => new Promise((t) => {
39
- const e = ({ html: a, css: i, width: o, height: p, utmParams: s, syncModulesIds: l }) => t({
39
+ const e = ({ html: a, css: i, width: o, height: r, utmParams: s, syncModulesIds: l }) => t({
40
40
  html: a,
41
41
  css: i,
42
42
  width: o,
43
- height: p,
43
+ height: r,
44
44
  utmParams: s,
45
45
  syncModulesIds: l
46
46
  });
@@ -91,7 +91,11 @@ const v = () => {
91
91
  },
92
92
  editorSave: () => new Promise((t) => {
93
93
  window.StripoEditorApi.actionsApi.save((e) => {
94
- e && n(e, "Failed to save template"), t();
94
+ if (e) {
95
+ n(e, "Failed to save template"), t(!1);
96
+ return;
97
+ }
98
+ t(!0);
95
99
  });
96
100
  })
97
101
  };
@@ -1,32 +1,31 @@
1
1
  import { useActionsApi as x } from "./useActionsApi.js";
2
2
  import { useConfig as y } from "./useConfig.js";
3
3
  import { useSaveStart as w, useSaveComplete as C } from "./useGuidoActions.js";
4
- import { useSyncModuleExtractor as H } from "./useSyncModuleExtractor.js";
5
- import { useStripoApi as b } from "../services/stripoApi.js";
6
- import { useTemplatePreparation as q } from "../utils/templatePreparation.js";
7
- import { useHtmlValidator as L } from "./useHtmlValidator.js";
8
- import { useCouponBlockValidator as P } from "./validators/useCouponBlockValidator.js";
9
- import { useLiquidValidator as E } from "./validators/useLiquidValidator.js";
10
- const j = () => {
11
- const o = w(), s = C(), { validateHtml: r } = L(), { validateLiquidSyntax: l } = E(), { validateCouponBlockTags: n } = P(), { callbacks: a, isFeatureEnabled: d } = y(), { extractSyncModuleData: u } = H(), { setSyncModuleUnsubscriptionPages: c } = b(), { editorSave: m } = x();
4
+ import { useSyncModuleExtractor as E } from "./useSyncModuleExtractor.js";
5
+ import { useStripoApi as H } from "../services/stripoApi.js";
6
+ import { useTemplatePreparation as b } from "../utils/templatePreparation.js";
7
+ import { useHtmlValidator as q } from "./useHtmlValidator.js";
8
+ import { useCouponBlockValidator as L } from "./validators/useCouponBlockValidator.js";
9
+ import { useLiquidValidator as P } from "./validators/useLiquidValidator.js";
10
+ const z = () => {
11
+ const o = w(), s = C(), { validateHtml: r } = q(), { validateLiquidSyntax: n } = P(), { validateCouponBlockTags: l } = L(), { callbacks: a, isFeatureEnabled: d } = y(), { extractSyncModuleData: u } = E(), { setSyncModuleUnsubscriptionPages: c } = H(), { editorSave: m } = x();
12
12
  return { save: async (p = !1, f = !1) => {
13
13
  var i;
14
14
  o();
15
- const { prepareTemplateDetails: v } = q(), t = await v();
16
- if (!n(t.compiledHtml))
15
+ const { prepareTemplateDetails: v } = b(), t = await v();
16
+ if (!l(t.compiledHtml))
17
17
  return;
18
18
  if (d("liquidSyntax")) {
19
- if (!await l(t.compiledHtml))
19
+ if (!await n(t.compiledHtml))
20
20
  return;
21
21
  } else if (!await r(t.compiledHtml, t.dynamicContentList, !0))
22
22
  return;
23
- if ((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(t))
23
+ if ((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(t) || !await m())
24
24
  return;
25
- await m();
26
25
  const { unsubscribePayload: S, stripoModules: V } = u(t.rawHtml);
27
26
  return await c(S), t.modules = V, p || s({ ...t, silent: f }), t;
28
27
  } };
29
28
  };
30
29
  export {
31
- j as useSave
30
+ z as useSave
32
31
  };
@@ -1,31 +1,39 @@
1
- var d = Object.defineProperty;
2
- var h = (n, i, e) => i in n ? d(n, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[i] = e;
3
- var u = (n, i, e) => h(n, typeof i != "symbol" ? i + "" : i, e);
1
+ var g = Object.defineProperty;
2
+ var k = (c, n, e) => n in c ? g(c, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[n] = e;
3
+ var l = (c, n, e) => k(c, typeof n != "symbol" ? n + "" : n, e);
4
+ import { useToaster as B } from "../../../composables/useToaster.js";
5
+ import { ToasterTypeOptions as S } from "../../../enums/toaster.js";
4
6
  import { PAGE_TYPES as E } from "../../../enums/unsubscribe.js";
5
- import { useUnsubscribeStore as c } from "../../../stores/unsubscribe.js";
6
- import { Block as _, BlockCompositionType as S, BlockType as L, ModificationDescription as b } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
- import { getDefaultTemplate as v } from "./template.js";
8
- import { UNSUBSCRIBE_EVENTS as a, DATA_ATTRIBUTES as o } from "./utils/constants.js";
7
+ import { useUnsubscribeStore as a } from "../../../stores/unsubscribe.js";
8
+ import { Block as L, BlockCompositionType as f, ContextActionType as h, ModificationDescription as b, BlockType as v } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
9
+ import { getDefaultTemplate as A } from "./template.js";
10
+ import { DATA_ATTRIBUTES as i, UNSUBSCRIBE_EVENTS as d } from "./utils/constants.js";
9
11
  import { parsePageList as p } from "./utils/utils.js";
10
- const g = "unsubscribe-block", T = 'a[data-unsubscribe-link="true"]', f = ".unsubscribe-block-v2", B = "{{ins-unsubscribe-link}}", C = {
12
+ const y = "unsubscribe-block", m = 'a[data-unsubscribe-link="true"]', _ = ".unsubscribe-block-v2", I = "{{ins-unsubscribe-link}}", T = "https://academy.insiderone.com/docs/adding-unsubscribe-pages-into-emails", C = "Removing the unsubscribe text leaves an empty block, but an active unsubscribe link is required. Undo your last action to restore the text, or delete the unsubscribe block entirely.", N = {
11
13
  [E.GLOBAL_UNSUBSCRIBE]: "{{ins-global-unsubscribe-link}}",
12
14
  [E.SUBSCRIPTION_PREFERENCE_CENTER]: "{{ins-preferences-unsubscribe-link}}"
13
15
  };
14
- class I extends _ {
16
+ class F extends L {
15
17
  constructor() {
16
18
  super();
17
- u(this, "selectEventListener", null);
18
- u(this, "cancelEventListener", null);
19
- u(this, "currentNode");
19
+ l(this, "selectEventListener", null);
20
+ l(this, "cancelEventListener", null);
21
+ l(this, "currentNode");
22
+ // Per-block "did this instance have a link last time we saw it?" tracking.
23
+ // Keyed by the stable `data-unsubscribe-block-id` we assign, because
24
+ // ImmutableHtmlNode instances are recreated on every document mutation and
25
+ // can't be used as Map keys directly. A singleton boolean here would be
26
+ // polluted across blocks since Stripo fires onDocumentChanged per-instance.
27
+ l(this, "linkStateByBlockId", /* @__PURE__ */ new Map());
20
28
  }
21
29
  getId() {
22
- return g;
30
+ return y;
23
31
  }
24
32
  getIcon() {
25
33
  return "unsubscribe-icon";
26
34
  }
27
35
  getBlockCompositionType() {
28
- return S.BLOCK;
36
+ return f.BLOCK;
29
37
  }
30
38
  getName() {
31
39
  return this.api.translate("Unsubscribe Block");
@@ -34,39 +42,115 @@ class I extends _ {
34
42
  return this.api.translate("Unsubscribe Block Description");
35
43
  }
36
44
  getTemplate() {
37
- return v();
45
+ return A();
46
+ }
47
+ getContextActionsIds() {
48
+ return [h.MOVE, h.REMOVE];
38
49
  }
39
50
  onSelect(e) {
40
- this.currentNode = e, !("getAttribute" in e && e.getAttribute("data-migration")) && (this._resetStoreState(), this._loadBlockState(e), this._setupSelectEventListener(), this._setupCancelEventListener(), this._checkExistingBlocks(), this._openDrawer());
51
+ this.currentNode = e;
52
+ const t = this._getOrAssignBlockId(e);
53
+ t && this.linkStateByBlockId.set(t, this._hasUnsubscribeLink(e)), !("getAttribute" in e && e.getAttribute("data-migration")) && (this._resetStoreState(), this._loadBlockState(e), this._setupSelectEventListener(), this._setupCancelEventListener(), this._checkExistingBlocks(), this._openDrawer());
54
+ }
55
+ onDocumentChanged(e) {
56
+ const t = this._getOrAssignBlockId(e);
57
+ if (!t)
58
+ return;
59
+ const r = this._hasUnsubscribeLink(e);
60
+ this.linkStateByBlockId.get(t) === !0 && !r && this._warnLinkRemoved(), this.linkStateByBlockId.set(t, r);
41
61
  }
42
62
  onDelete(e) {
43
63
  this._removeEventListeners(), this._removeBlockTemplatesFromStore(e), this._resetStoreState();
64
+ const t = this._readBlockId(e);
65
+ t && this.linkStateByBlockId.delete(t);
44
66
  }
45
67
  onDestroy() {
46
- this._removeEventListeners(), this.currentNode = void 0;
68
+ this._removeEventListeners(), this.currentNode = void 0, this.linkStateByBlockId.clear();
69
+ }
70
+ _hasUnsubscribeLink(e) {
71
+ return "querySelector" in e ? !!e.querySelector(m) : !1;
72
+ }
73
+ _readBlockId(e) {
74
+ return "getAttribute" in e ? e.getAttribute(i.BLOCK_ID) : null;
75
+ }
76
+ /**
77
+ * Returns the block's stable id, assigning one via the document modifier if
78
+ * the node has not been tagged yet. Idempotent: subsequent calls during
79
+ * the same document-change cycle (e.g. reentrant onDocumentChanged after
80
+ * `apply()`) short-circuit on the existing attribute.
81
+ */
82
+ _getOrAssignBlockId(e) {
83
+ const t = this._readBlockId(e);
84
+ if (t)
85
+ return t;
86
+ if (!("getAttribute" in e))
87
+ return null;
88
+ const r = this._generateNextBlockId();
89
+ try {
90
+ this.api.getDocumentModifier().modifyHtml(e).setAttribute(i.BLOCK_ID, r).apply(new b(`Assign unsubscribe block id ${r}`));
91
+ } catch (s) {
92
+ return console.warn("[UnsubscribeBlock] Failed to assign block id:", s), null;
93
+ }
94
+ return r;
95
+ }
96
+ /**
97
+ * Generates a unique id by scanning the document for the highest existing
98
+ * `data-unsubscribe-block-id` and returning max+1. Mirrors the strategy
99
+ * used by RecommendationBlock so reloaded templates don't collide.
100
+ */
101
+ _generateNextBlockId() {
102
+ let e = 0;
103
+ try {
104
+ const t = this.api.getDocumentRoot();
105
+ t && "querySelectorAll" in t && t.querySelectorAll(_).forEach((s) => {
106
+ if ("getAttribute" in s) {
107
+ const o = s.getAttribute(i.BLOCK_ID), u = o ? parseInt(o) : 0;
108
+ u > e && (e = u);
109
+ }
110
+ });
111
+ } catch {
112
+ }
113
+ return String(e + 1);
114
+ }
115
+ _warnLinkRemoved() {
116
+ try {
117
+ const { showToaster: e } = B();
118
+ e({
119
+ type: S.Warning,
120
+ message: this.api.translate(C),
121
+ actionButton: {
122
+ text: this.api.translate("Visit Academy"),
123
+ onClick: () => {
124
+ window.open(T, "_blank", "noopener,noreferrer");
125
+ }
126
+ }
127
+ });
128
+ } catch (e) {
129
+ console.error("[UnsubscribeBlock] Failed to show warning toaster:", e);
130
+ }
47
131
  }
48
132
  _setupSelectEventListener() {
49
133
  this._removeSelectEventListener(), this.selectEventListener = (e) => {
50
- const r = e, { collectionType: s, selectedPages: t } = r.detail;
51
- this._updateBlock(s, t.join(","));
52
- }, document.addEventListener(a.SELECT, this.selectEventListener);
134
+ const t = e, { collectionType: r, selectedPages: s } = t.detail;
135
+ this._updateBlock(r, s.join(","));
136
+ }, document.addEventListener(d.SELECT, this.selectEventListener);
53
137
  }
54
138
  _removeSelectEventListener() {
55
- this.selectEventListener && (document.removeEventListener(a.SELECT, this.selectEventListener), this.selectEventListener = null);
139
+ this.selectEventListener && (document.removeEventListener(d.SELECT, this.selectEventListener), this.selectEventListener = null);
56
140
  }
57
141
  _setupCancelEventListener() {
58
142
  this._removeCancelEventListener(), this.cancelEventListener = () => {
59
143
  this._handleCancel();
60
- }, document.addEventListener(a.CANCEL, this.cancelEventListener);
144
+ }, document.addEventListener(d.CANCEL, this.cancelEventListener);
61
145
  }
62
146
  _removeCancelEventListener() {
63
- this.cancelEventListener && (document.removeEventListener(a.CANCEL, this.cancelEventListener), this.cancelEventListener = null);
147
+ this.cancelEventListener && (document.removeEventListener(d.CANCEL, this.cancelEventListener), this.cancelEventListener = null);
64
148
  }
65
149
  _handleCancel() {
66
150
  try {
67
151
  if (!this.currentNode)
68
152
  return;
69
- this.api.getDocumentModifier().modifyHtml(this.currentNode).replaceWith(`<${L.EMPTY_CONTAINER}/>`).apply(new b("Removed unsubscribe block due to cancel"));
153
+ this.api.getDocumentModifier().modifyHtml(this.currentNode).replaceWith(`<${v.EMPTY_CONTAINER}/>`).apply(new b("Removed unsubscribe block due to cancel"));
70
154
  } catch (e) {
71
155
  console.warn("[UnsubscribeBlock] Failed to remove unsubscribe block:", e);
72
156
  }
@@ -74,35 +158,35 @@ class I extends _ {
74
158
  _removeEventListeners() {
75
159
  this._removeSelectEventListener(), this._removeCancelEventListener();
76
160
  }
77
- _updateBlock(e, r) {
161
+ _updateBlock(e, t) {
78
162
  if (!this.currentNode || !("querySelector" in this.currentNode))
79
163
  return;
80
- const s = this.currentNode.querySelector(T);
81
- if (!s)
164
+ const r = this.currentNode.querySelector(m);
165
+ if (!r)
82
166
  return;
83
- const t = this._getMergeTag(e);
84
- this.api.getDocumentModifier().modifyHtml(s).setAttribute("href", t).apply(new b(`Updated unsubscribe link to ${t}`)), this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(o.PAGE_TYPE, e.toString()).setAttribute(o.PAGE_LIST, r).apply(new b("Updated unsubscribe block metadata"));
167
+ const s = this._getMergeTag(e);
168
+ this.api.getDocumentModifier().modifyHtml(r).setAttribute("href", s).apply(new b(`Updated unsubscribe link to ${s}`)), this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute(i.PAGE_TYPE, e.toString()).setAttribute(i.PAGE_LIST, t).apply(new b("Updated unsubscribe block metadata"));
85
169
  }
86
170
  _getMergeTag(e) {
87
- return C[e] ?? B;
171
+ return N[e] ?? I;
88
172
  }
89
173
  _openDrawer() {
90
174
  if (!(this.currentNode && this.currentNode.getAttribute("data-unsubscribe-page-type")))
91
175
  try {
92
- const e = c();
176
+ const e = a();
93
177
  e.typeSelectionDrawerStatus = !0;
94
178
  } catch (e) {
95
179
  console.error("[UnsubscribeBlock] Failed to open drawer:", e);
96
180
  }
97
181
  }
98
182
  _checkExistingBlocks() {
99
- const e = c();
100
- e.isGlobalUnsubscribeDisabled = !1, e.isSubscriptionPreferencesCenterDisabled = !1, this.api.getDocumentRoot().querySelectorAll(f).forEach((s) => {
101
- if ("getAttribute" in s) {
102
- const t = s.getAttribute(o.PAGE_TYPE);
103
- if (t) {
104
- const l = Number(t);
105
- l === E.GLOBAL_UNSUBSCRIBE ? e.isGlobalUnsubscribeDisabled = !0 : l === E.SUBSCRIPTION_PREFERENCE_CENTER && (e.isSubscriptionPreferencesCenterDisabled = !0);
183
+ const e = a();
184
+ e.isGlobalUnsubscribeDisabled = !1, e.isSubscriptionPreferencesCenterDisabled = !1, this.api.getDocumentRoot().querySelectorAll(_).forEach((r) => {
185
+ if ("getAttribute" in r) {
186
+ const s = r.getAttribute(i.PAGE_TYPE);
187
+ if (s) {
188
+ const o = Number(s);
189
+ o === E.GLOBAL_UNSUBSCRIBE ? e.isGlobalUnsubscribeDisabled = !0 : o === E.SUBSCRIPTION_PREFERENCE_CENTER && (e.isSubscriptionPreferencesCenterDisabled = !0);
106
190
  }
107
191
  }
108
192
  });
@@ -110,26 +194,26 @@ class I extends _ {
110
194
  async _loadBlockState(e) {
111
195
  if (!("getAttribute" in e))
112
196
  return;
113
- const r = e.getAttribute(o.PAGE_TYPE), s = e.getAttribute(o.PAGE_LIST);
114
- if (!r || !s)
197
+ const t = e.getAttribute(i.PAGE_TYPE), r = e.getAttribute(i.PAGE_LIST);
198
+ if (!t || !r)
115
199
  return;
116
- const t = c(), l = Number(r), m = p(s);
117
- await t.fetchTemplates(), t.setCollectionWithoutAutoSelection(l), t.loadSelectedTemplates(m);
200
+ const s = a(), o = Number(t), u = p(r);
201
+ await s.fetchTemplates(), s.setCollectionWithoutAutoSelection(o), s.loadSelectedTemplates(u);
118
202
  }
119
203
  _resetStoreState() {
120
- c().$reset();
204
+ a().$reset();
121
205
  }
122
206
  _removeBlockTemplatesFromStore(e) {
123
207
  if (!("getAttribute" in e))
124
208
  return;
125
- const r = e.getAttribute(o.PAGE_LIST);
126
- if (!r)
209
+ const t = e.getAttribute(i.PAGE_LIST);
210
+ if (!t)
127
211
  return;
128
- const s = c(), t = p(r);
129
- s.removeUnsubscribePages(t);
212
+ const r = a(), s = p(t);
213
+ r.removeUnsubscribePages(s);
130
214
  }
131
215
  }
132
216
  export {
133
- g as UNSUBSCRIBE_BLOCK_ID,
134
- I as UnsubscribeBlock
217
+ y as UNSUBSCRIBE_BLOCK_ID,
218
+ F as UnsubscribeBlock
135
219
  };
@@ -1,22 +1,22 @@
1
- import { BlockType as e } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
- const s = "unsubscribe", n = "{{ins-unsubscribe-link}}", t = `
3
- <${e.BLOCK_TEXT}
1
+ import { BlockType as s } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ const e = "unsubscribe", n = "{{ins-unsubscribe-link}}", t = `
3
+ <${s.BLOCK_TEXT}
4
4
  class="unsubscribe-block-v2 esd-block-unsubscribe es-p0"
5
5
  align="center"
6
6
  data-unsubscribe-page-type=""
7
7
  data-unsubscribe-page-list=""
8
8
  >
9
- <p>You can <strong><a
9
+ <p>&nbsp;<strong><a
10
10
  href="${n}"
11
11
  class="unsubscribe-link"
12
12
  target="_blank"
13
13
  data-unsubscribe-link="true"
14
- >${s}</a></strong> from our emails, if you need to.</p>
15
- </${e.BLOCK_TEXT}>
14
+ >${e}</a></strong></p>
15
+ </${s.BLOCK_TEXT}>
16
16
  `;
17
- function r() {
17
+ function u() {
18
18
  return t;
19
19
  }
20
20
  export {
21
- r as getDefaultTemplate
21
+ u as getDefaultTemplate
22
22
  };
@@ -3,7 +3,8 @@ const s = {
3
3
  CANCEL: "unsubscribe:cancel"
4
4
  }, e = {
5
5
  PAGE_TYPE: "data-unsubscribe-page-type",
6
- PAGE_LIST: "data-unsubscribe-page-list"
6
+ PAGE_LIST: "data-unsubscribe-page-list",
7
+ BLOCK_ID: "data-unsubscribe-block-id"
7
8
  };
8
9
  export {
9
10
  e as DATA_ATTRIBUTES,
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- .gap-16[data-v-8053a037],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.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-4e2a4adb]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-b293a2b0]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-b293a2b0]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-b293a2b0]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-df672485]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-df672485]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-df672485]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-df672485]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-df672485]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-7419ae06] .vueperslides__bullets,[data-v-796d193b] .vueperslides__bullets{pointer-events:none!important}[data-v-796d193b] .vueperslides__parallax-wrapper{height:110px!important}[data-v-cadfc82d] .vueperslides__bullets{pointer-events:none!important}[data-v-cadfc82d] .vueperslides__parallax-wrapper{height:110px!important}
1
+ .gap-16[data-v-8053a037],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.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-4e2a4adb]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-cdee3452]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-cdee3452]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-cdee3452]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-df672485]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-df672485]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-df672485]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-df672485]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-df672485]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-7419ae06] .vueperslides__bullets,[data-v-796d193b] .vueperslides__bullets{pointer-events:none!important}[data-v-796d193b] .vueperslides__parallax-wrapper{height:110px!important}[data-v-cadfc82d] .vueperslides__bullets{pointer-events:none!important}[data-v-cadfc82d] .vueperslides__parallax-wrapper{height:110px!important}