@useinsider/guido 3.22.0-beta.07e62e8 → 3.22.0-beta.0af1132

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 (75) hide show
  1. package/README.md +36 -4
  2. package/dist/@types/config/schemas.js +11 -10
  3. package/dist/components/Guido.vue.js +4 -4
  4. package/dist/components/Guido.vue2.js +124 -103
  5. package/dist/components/organisms/AutoSaveController.vue2.js +20 -10
  6. package/dist/components/organisms/header/AutoSaveStatus.vue.js +17 -0
  7. package/dist/components/organisms/header/AutoSaveStatus.vue2.js +25 -0
  8. package/dist/components/organisms/header/EditorActions.vue.js +13 -13
  9. package/dist/components/organisms/header/EditorActions.vue2.js +58 -73
  10. package/dist/components/organisms/header/EditorActionsMenu.vue.js +20 -0
  11. package/dist/components/organisms/header/EditorActionsMenu.vue2.js +99 -0
  12. package/dist/components/organisms/header/HeaderWrapper.vue.js +6 -6
  13. package/dist/components/organisms/header/HeaderWrapper.vue2.js +9 -17
  14. package/dist/components/organisms/header/LeftSlot.vue.js +1 -1
  15. package/dist/components/organisms/header/LeftSlot.vue2.js +28 -23
  16. package/dist/components/organisms/header/MiddleSlot.vue.js +4 -4
  17. package/dist/components/organisms/header/MiddleSlot.vue2.js +8 -7
  18. package/dist/components/organisms/header/RightSlot.vue.js +11 -10
  19. package/dist/components/organisms/header/RightSlot.vue2.js +13 -18
  20. package/dist/components/organisms/header/accessibility/AccessibilityToolbar.vue.js +18 -0
  21. package/dist/components/organisms/header/accessibility/AccessibilityToolbar.vue2.js +37 -0
  22. package/dist/components/organisms/header/accessibility/ColorVisionSelect.vue.js +22 -0
  23. package/dist/components/organisms/header/accessibility/ColorVisionSelect.vue2.js +48 -0
  24. package/dist/components/organisms/onboarding/EditorTabBarOnboarding.vue.js +19 -0
  25. package/dist/components/organisms/onboarding/EditorTabBarOnboarding.vue2.js +90 -0
  26. package/dist/components/organisms/onboarding/OnboardingWrapper.vue.js +12 -12
  27. package/dist/components/organisms/onboarding/OnboardingWrapper.vue2.js +60 -35
  28. package/dist/composables/useAccessibilityApi.js +51 -0
  29. package/dist/composables/useCustomInterfaceAppearance.js +42 -41
  30. package/dist/composables/useEditorOpenMetrics.js +167 -0
  31. package/dist/composables/useStripo.js +93 -82
  32. package/dist/config/i18n/en/labels.json.js +36 -4
  33. package/dist/config/i18n/en/tooltips.json.js +2 -1
  34. package/dist/guido.css +1 -1
  35. package/dist/library.js +12 -10
  36. package/dist/package.json.js +6 -4
  37. package/dist/public/prefetchRuntime.js +4 -0
  38. package/dist/sprite.svg +10 -0
  39. package/dist/src/@types/config/schemas.d.ts +2 -0
  40. package/dist/src/components/organisms/AutoSaveController.vue.d.ts +19 -1
  41. package/dist/src/components/organisms/header/EditorActionsMenu.vue.d.ts +2 -0
  42. package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +1 -19
  43. package/dist/src/components/organisms/header/RightSlot.vue.d.ts +1 -19
  44. package/dist/src/components/organisms/header/accessibility/AccessibilityToolbar.vue.d.ts +2 -0
  45. package/dist/src/components/organisms/header/accessibility/ColorVisionSelect.vue.d.ts +2 -0
  46. package/dist/src/components/organisms/onboarding/EditorTabBarOnboarding.vue.d.ts +2 -0
  47. package/dist/src/composables/useAccessibilityApi.d.ts +13 -0
  48. package/dist/src/composables/useActionsApi.d.ts +2 -2
  49. package/dist/src/composables/useConfig.d.ts +2 -0
  50. package/dist/src/composables/useEditorOpenMetrics.d.ts +27 -0
  51. package/dist/src/composables/useStripo.d.ts +2 -1
  52. package/dist/src/library.d.ts +1 -0
  53. package/dist/src/public/prefetchRuntime.d.ts +1 -0
  54. package/dist/src/stores/autosave.d.ts +73 -1
  55. package/dist/src/stores/config.d.ts +20 -0
  56. package/dist/src/stores/editor.d.ts +109 -0
  57. package/dist/src/stores/onboarding.d.ts +966 -35
  58. package/dist/src/stores/version-history.d.ts +1 -1
  59. package/dist/src/utils/runtimePrefetch.d.ts +4 -0
  60. package/dist/src/utils/stripoRuntime.d.ts +3 -0
  61. package/dist/src/utils/templatePreparation.d.ts +1 -1
  62. package/dist/src/utils/timeUtil.d.ts +5 -8
  63. package/dist/static/stripo-runtime-manifest.json.js +9 -0
  64. package/dist/static/styles/components/accessibility.css.js +234 -0
  65. package/dist/static/styles/variables.css.js +2 -0
  66. package/dist/stores/autosave.js +12 -7
  67. package/dist/stores/editor.js +8 -3
  68. package/dist/stores/onboarding.js +48 -22
  69. package/dist/utils/runtimePrefetch.js +26 -0
  70. package/dist/utils/stripoRuntime.js +13 -0
  71. package/dist/utils/timeUtil.js +6 -17
  72. package/package.json +6 -1
  73. package/dist/components/organisms/header/AutoSaveToggle.vue.js +0 -22
  74. package/dist/components/organisms/header/AutoSaveToggle.vue2.js +0 -19
  75. /package/dist/src/components/organisms/header/{AutoSaveToggle.vue.d.ts → AutoSaveStatus.vue.d.ts} +0 -0
package/README.md CHANGED
@@ -166,6 +166,7 @@ const config: GuidoConfigInput = {
166
166
  allowlistEnabled?: boolean, // Default: false - Pre-save domain-allowlist check (opt-in). Guido self-serves the block toaster (role lookup, deep-link, copy from window.trans).
167
167
  allowSaveWithErrors?: boolean, // Default: true - Allow the validation drawer's "Save and Continue" soft-save. Set false to hard-block invalid saves (transactional + unsubscribe pages).
168
168
  reusableRecommendationStrategy?: boolean, // Default: false - Assign an RRS strategy to recommendation blocks instead of per-block algorithm/filters/shuffle/product-count settings.
169
+ accessibilityTesting?: boolean, // Default: false - Show the Accessibility Test entry in the header kebab menu (Stripo's checker: contrast, image alternatives, colour-vision simulation) and the tab-bar onboarding tour that points at it.
169
170
  },
170
171
 
171
172
  // Optional: Callbacks
@@ -582,9 +583,9 @@ import '@useinsider/guido/style';
582
583
 
583
584
  ### Subpath entries
584
585
 
585
- Two surfaces also ship as their own entry points. Importing one pulls in only its
586
- own dependencies, so a consumer that needs the store or the tracking-id helpers
587
- never loads the editor:
586
+ Three surfaces also ship as their own entry points. Importing one pulls in only its
587
+ own dependencies, so a consumer that needs the store, the tracking-id helpers or the
588
+ runtime prefetch never loads the editor:
588
589
 
589
590
  ```typescript
590
591
  // Live editor state, published by the editor into the host's shared Pinia instance.
@@ -595,11 +596,42 @@ import type { GuidoEmailEditorState } from '@useinsider/guido/editor-state';
595
596
  // Persistent link ids for the click heatmap.
596
597
  import { assignTrackingIds, TRACK_ID_ATTRIBUTE } from '@useinsider/guido/tracking-ids';
597
598
  import type { TrackingIdResult } from '@useinsider/guido/tracking-ids';
599
+
600
+ // Start downloading the Stripo editor runtime before the editor opens.
601
+ import { prefetchGuidoRuntime } from '@useinsider/guido/prefetch';
598
602
  ```
599
603
 
600
- Both are re-exported from the root barrel as well; the subpath is what keeps the
604
+ All three are re-exported from the root barrel as well; the subpath is what keeps the
601
605
  editor out of the consumer's module graph.
602
606
 
607
+ ### Runtime prefetch
608
+
609
+ ```typescript
610
+ import { prefetchGuidoRuntime } from '@useinsider/guido/prefetch';
611
+
612
+ prefetchGuidoRuntime(); // e.g. when the user lands on the page that opens the editor
613
+ ```
614
+
615
+ Call it as early as the host knows an editor is likely to open. It appends one
616
+ `<link rel="prefetch" data-guido-prefetch>` per file of the pinned Stripo runtime
617
+ (`src/static/stripo-runtime-manifest.json`) from
618
+ `https://email-static.useinsider.com/guido/<stripo version>/`, so the files are in the
619
+ HTTP cache when `<Guido>` mounts. It only downloads: no Stripo code runs and the
620
+ editor's startup order does not change.
621
+
622
+ - Returns `void` and never throws.
623
+ - Idempotent: later calls add nothing.
624
+ - Adds nothing when the runtime is already loading or loaded (`#UiEditorScript` exists
625
+ or `window.UIEditor` is defined), when the browser does not support `rel="prefetch"`
626
+ (Safari by default), when `navigator.connection.saveData` is on, or when
627
+ `navigator.connection.effectiveType` is `slow-2g` or `2g`.
628
+ - The `guido_editor_open` metric reports it as `runtime_prefetch`: `none` (not called
629
+ before Guido's setup), `pending` (some files still downloading) or `done`.
630
+
631
+ After bumping `guido.stripo.version`, regenerate the file list with
632
+ `npm run stripo:manifest`; a unit test fails while the manifest's version differs from
633
+ the pinned one.
634
+
603
635
  ---
604
636
 
605
637
  ## Constants
@@ -1,5 +1,5 @@
1
- import { ModuleFolderDefaults as f } from "../../enums/defaults.js";
2
- import { object as a, number as s, optional as e, string as t, picklist as m, pipe as i, minLength as b, custom as k, boolean as o, array as c, transform as y, unknown as r, record as g, fallback as R, literal as u, looseObject as C, variant as I, union as h, lazy as T } from "../../node_modules/valibot/dist/index.js";
1
+ import { ModuleFolderDefaults as S } from "../../enums/defaults.js";
2
+ import { object as a, number as s, optional as e, string as t, picklist as m, pipe as i, minLength as b, custom as k, boolean as o, array as c, transform as y, unknown as r, record as g, fallback as R, literal as u, looseObject as C, variant as T, union as h, lazy as I } from "../../node_modules/valibot/dist/index.js";
3
3
  const p = {
4
4
  /** Promotional/marketing emails */
5
5
  PROMOTIONAL: 1,
@@ -76,17 +76,17 @@ const p = {
76
76
  value: t()
77
77
  })
78
78
  )
79
- }), S = T(() => C({
79
+ }), f = I(() => C({
80
80
  text: e(t()),
81
81
  // eslint-disable-next-line camelcase -- backend field name
82
82
  tag_text: e(t()),
83
83
  value: e(t()),
84
- children: e(c(S)),
84
+ children: e(c(f)),
85
85
  // eslint-disable-next-line camelcase -- backend field name
86
- select_items: e(c(S))
86
+ select_items: e(c(f))
87
87
  })), N = g(
88
88
  t(),
89
- R(c(S), [])
89
+ R(c(f), [])
90
90
  ), P = C({
91
91
  /** Block ID (matches the dictionary key and the legacy HTML element id) */
92
92
  id: e(s()),
@@ -210,9 +210,9 @@ const p = {
210
210
  /** Email header settings */
211
211
  emailHeader: e(D, { senderName: "", subject: "" }),
212
212
  /** Folder name for user-saved modules (used by Stripo plugin panel for path construction) */
213
- savedModulesFolderName: e(t(), f.SAVED_MODULES),
213
+ savedModulesFolderName: e(t(), S.SAVED_MODULES),
214
214
  /** Folder name for default/prebuilt modules (used by Stripo plugin panel for path construction) */
215
- defaultModulesFolderName: e(t(), f.DEFAULT_MODULES)
215
+ defaultModulesFolderName: e(t(), S.DEFAULT_MODULES)
216
216
  }), F = a({
217
217
  /** Whether to show the header bar */
218
218
  showHeader: e(o(), !0),
@@ -237,6 +237,7 @@ const p = {
237
237
  liquidSyntax: e(o(), !1),
238
238
  /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
239
239
  autosave: e(o(), !1),
240
+ accessibilityTesting: e(o(), !1),
240
241
  /** Enable pre-save domain-allowlist validation (opt-in; Guido self-serves the block toaster) */
241
242
  allowlistEnabled: e(o(), !1),
242
243
  /** Enable persistent link tracking-id assignment for the click heatmap (opt-in) */
@@ -315,7 +316,7 @@ const p = {
315
316
  (n) => typeof n == "function",
316
317
  "processor must be a function"
317
318
  )
318
- }), V = I("type", [
319
+ }), V = T("type", [
319
320
  H,
320
321
  _,
321
322
  q,
@@ -367,7 +368,7 @@ export {
367
368
  G as CustomRuleSchema,
368
369
  w as DefaultBlockTypeSchema,
369
370
  N as DynamicContentListSchema,
370
- S as DynamicContentNodeSchema,
371
+ f as DynamicContentNodeSchema,
371
372
  M as DynamicContentSchema,
372
373
  O as EditorSchema,
373
374
  D as EmailHeaderSchema,
@@ -3,7 +3,7 @@ import o from "./Guido.vue2.js";
3
3
  import i from "../_virtual/_plugin-vue2_normalizer.js";
4
4
  var t = 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, { ref: "headerWrapperRef" }), r(e.AutoSaveController), 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(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(_) {
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(), r(e.SaveAsTemplateDrawer), e.isSaveValidationEnabled ? r(e.ValidationErrorDrawer) : a._e(), e.isTestPartner() ? a._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(_) {
7
7
  return e.emit("onboarding:finished");
8
8
  } } }), r(e.UnsubscribeWrapper), r(e.LoadingWrapper)], 1);
9
9
  }, s = [], n = /* @__PURE__ */ i(
@@ -12,9 +12,9 @@ var t = function() {
12
12
  s,
13
13
  !1,
14
14
  null,
15
- "c5146fc5"
15
+ "8422eef8"
16
16
  );
17
- const v = n.exports;
17
+ const c = n.exports;
18
18
  export {
19
- v as default
19
+ c as default
20
20
  };
@@ -1,63 +1,74 @@
1
- import { defineComponent as ie, defineAsyncComponent as m, ref as W, computed as p, watch as G, onMounted as ce, onUnmounted as de } from "vue";
2
- import { useCortexBlueprintBridge as me } from "../composables/useCortexBlueprintBridge.js";
3
- import { useEditorLock as le } from "../composables/useEditorLock.js";
4
- import { provideGuidoActions as ue } from "../composables/useGuidoActions.js";
5
- import { useGuidoStateBridge as pe } from "../composables/useGuidoStateBridge.js";
6
- import { usePartner as fe } from "../composables/usePartner.js";
7
- import { useSaveValidationRollout as ye } from "../composables/useSaveValidationRollout.js";
8
- import { useStripo as ge } from "../composables/useStripo.js";
9
- import { useTimerClone as Se } from "../composables/useTimerClone.js";
10
- import { migrate as V } from "../config/migrator/index.js";
1
+ import { defineComponent as le, defineAsyncComponent as l, ref as W, computed as f, watch as G, onMounted as ue, onUnmounted as pe } from "vue";
2
+ import { useCortexBlueprintBridge as fe } from "../composables/useCortexBlueprintBridge.js";
3
+ import { useEditorLock as ye } from "../composables/useEditorLock.js";
4
+ import { startEditorOpenMetrics as ge } from "../composables/useEditorOpenMetrics.js";
5
+ import { provideGuidoActions as ve } from "../composables/useGuidoActions.js";
6
+ import { useGuidoStateBridge as Se } from "../composables/useGuidoStateBridge.js";
7
+ import { usePartner as be } from "../composables/usePartner.js";
8
+ import { useSaveValidationRollout as he } from "../composables/useSaveValidationRollout.js";
9
+ import { useStripo as Ee } from "../composables/useStripo.js";
10
+ import { useTimerClone as we } from "../composables/useTimerClone.js";
11
+ import { useToaster as Te } from "../composables/useToaster.js";
12
+ import { useTranslations as ke } from "../composables/useTranslations.js";
13
+ import { migrate as Ce } from "../config/migrator/index.js";
11
14
  import { ModuleFolderDefaults as $ } from "../enums/defaults.js";
12
- import { RIBBON_SELECTOR as ve } from "../enums/onboarding.js";
13
- import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as be } from "../extensions/Blocks/Recommendation/store/recommendation.js";
14
- import { disposeUnsubscribeListeners as he } from "../extensions/Blocks/Unsubscribe/block.js";
15
- import Ee from "./organisms/AutoSaveController.vue.js";
16
- import we from "./organisms/base/AuthErrorModal.vue.js";
17
- import De from "./organisms/base/Toaster.vue.js";
18
- import Ce from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
19
- import ke from "./organisms/header/HeaderWrapper.vue.js";
20
- import Re from "./organisms/LoadingWrapper.vue.js";
21
- import Fe from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
22
- import Le from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
23
- import Me from "./organisms/validation/ValidationErrorDrawer.vue.js";
24
- import { useStripoApi as Te } from "../services/stripoApi.js";
25
- import { useConfigStore as Ie } from "../stores/config.js";
26
- import { useDynamicContentStore as Ue } from "../stores/dynamic-content.js";
27
- import { useEditorStore as E } from "../stores/editor.js";
28
- import { usePreviewStore as Ae } from "../stores/preview.js";
29
- import { useSaveValidationStore as Be } from "../stores/save-validation.js";
30
- import { useTemplateStore as Ne } from "../stores/template.js";
31
- import { useUnsubscribeStore as Pe } from "../stores/unsubscribe.js";
32
- import { readTrackFloor as H } from "../utils/linkTrackingIds.js";
33
- const yt = /* @__PURE__ */ ie({
15
+ import { RIBBON_SELECTOR as De } from "../enums/onboarding.js";
16
+ import { ToasterTypeOptions as Ie } from "../enums/toaster.js";
17
+ import { useRecommendationExtensionStore as z, disposeStrategyPageReturnListeners as Fe } from "../extensions/Blocks/Recommendation/store/recommendation.js";
18
+ import { disposeUnsubscribeListeners as Me } from "../extensions/Blocks/Unsubscribe/block.js";
19
+ import Re from "./organisms/AutoSaveController.vue.js";
20
+ import Le from "./organisms/base/AuthErrorModal.vue.js";
21
+ import Oe from "./organisms/base/Toaster.vue.js";
22
+ import Ue from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
23
+ import Ne from "./organisms/header/HeaderWrapper.vue.js";
24
+ import _e from "./organisms/LoadingWrapper.vue.js";
25
+ import Ae from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
26
+ import Be from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
27
+ import Pe from "./organisms/validation/ValidationErrorDrawer.vue.js";
28
+ import { useStripoApi as xe } from "../services/stripoApi.js";
29
+ import { useConfigStore as He } from "../stores/config.js";
30
+ import { useDynamicContentStore as Ve } from "../stores/dynamic-content.js";
31
+ import { useEditorStore as w } from "../stores/editor.js";
32
+ import { usePreviewStore as We } from "../stores/preview.js";
33
+ import { useSaveValidationStore as Ge } from "../stores/save-validation.js";
34
+ import { useTemplateStore as $e } from "../stores/template.js";
35
+ import { useUnsubscribeStore as ze } from "../stores/unsubscribe.js";
36
+ import { readTrackFloor as q } from "../utils/linkTrackingIds.js";
37
+ const Ft = /* @__PURE__ */ le({
34
38
  __name: "Guido",
35
39
  props: {
36
40
  config: null,
37
41
  ready: { type: Boolean, default: !0 }
38
42
  },
39
43
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
40
- setup(q, { expose: K, emit: r }) {
41
- const s = q, j = m(
44
+ setup(K, { expose: j, emit: s }) {
45
+ const a = K, n = ge(), J = l(
42
46
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
43
- ), J = m(
47
+ ), Q = l(
44
48
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
45
- ), Q = m(
49
+ ), X = l(
46
50
  () => import("./organisms/extensions/recommendation/AssignStrategyDrawer.vue.js")
47
- ), X = m(
51
+ ), Y = l(
48
52
  () => import("./organisms/extensions/recommendation/RemoveStrategyModal.vue.js")
49
- ), Y = m(
53
+ ), T = W(), Z = l(
50
54
  () => import("./organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js")
51
- ), w = W(), f = W(), y = Ue(), D = Pe(), o = Ie();
52
- s.ready && o.init(s.config);
53
- const c = E(), Z = Ae(), l = p(() => c.hasChanges), { isTestPartner: ee } = fe(), { isEnabled: te, loadRollout: C } = ye(), k = () => {
55
+ ), y = W(), g = Ve(), k = ze(), o = He();
56
+ a.ready && o.init(a.config);
57
+ const c = w(), ee = We(), u = f(() => c.hasChanges), { isTestPartner: te } = be(), { isEnabled: oe, loadRollout: C } = he(), { showToaster: D } = Te(), I = ke(), F = () => {
54
58
  var t;
55
- return (t = w.value) == null ? void 0 : t.handleSave(!0);
56
- }, R = (t) => {
59
+ if (c.isVersionHistoryOpen) {
60
+ console.debug("guido:save:silent:blocked", { isVersionHistoryOpen: !0 }), D({
61
+ type: Ie.Warning,
62
+ message: I("email-editor.save-blocked-outside-editor")
63
+ });
64
+ return;
65
+ }
66
+ return (t = T.value) == null ? void 0 : t.saveSilent();
67
+ }, M = (t) => {
57
68
  c.loadingStatus = t;
58
69
  };
59
- me(), pe();
60
- const g = () => {
70
+ fe(), Se();
71
+ const v = () => {
61
72
  var t, e;
62
73
  return {
63
74
  emailId: o.templateId,
@@ -67,113 +78,123 @@ const yt = /* @__PURE__ */ ie({
67
78
  savedModulesFolderName: ((t = o.editor) == null ? void 0 : t.savedModulesFolderName) || $.SAVED_MODULES,
68
79
  defaultModulesFolderName: ((e = o.editor) == null ? void 0 : e.defaultModulesFolderName) || $.DEFAULT_MODULES
69
80
  };
70
- }, { initPlugin: F, preloadRuntime: L } = ge(), { runExclusive: M, beginMount: T, isCurrentMount: S } = le();
71
- let u = 0;
72
- const { getDefaultTemplate: I } = Te(), { cloneTimersOnSave: U, hasTimerBlocks: A } = Se(), oe = p(() => {
81
+ }, { initPlugin: R, preloadRuntime: L } = Ee(n), { runExclusive: O, beginMount: U, isCurrentMount: S } = ye();
82
+ let p = 0;
83
+ const { getDefaultTemplate: N } = xe(), { cloneTimersOnSave: _, hasTimerBlocks: A } = we(), re = f(() => {
73
84
  var t;
74
85
  return !((t = o.ui) != null && t.showHeader);
75
- }), ne = p(() => o.isFeatureEnabled("reusableRecommendationStrategy")), re = p(
86
+ }), ne = f(() => o.isFeatureEnabled("reusableRecommendationStrategy")), se = f(
76
87
  () => !!z().recommendationConfigs.strategyId
77
88
  );
78
- ue({
89
+ ve({
79
90
  onBack: () => {
80
- console.debug("guido:back"), r("back");
91
+ console.debug("guido:back"), s("back");
81
92
  },
82
93
  onSaveStart: () => {
83
- console.debug("guido:save:start"), r("save:start");
94
+ console.debug("guido:save:start"), s("save:start");
84
95
  },
85
96
  onSaveComplete: (t) => {
86
- const e = { ...t, metadata: g() };
87
- console.debug("guido:save:complete", e), r("save:complete", e);
97
+ const e = { ...t, metadata: v() };
98
+ console.debug("guido:save:complete", e), s("save:complete", e);
88
99
  },
89
100
  onTestEmailClick: () => {
90
- console.debug("guido:test-email:click"), r("test-email:click");
101
+ console.debug("guido:test-email:click"), s("test-email:click");
91
102
  }
92
103
  });
93
104
  const B = (t) => {
94
- console.debug("dynamic-content:close", t), y.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
95
- }, N = () => {
105
+ console.debug("dynamic-content:close", t), g.setSelectedDynamicContent(t), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: t }));
106
+ }, P = () => {
96
107
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
97
108
  };
98
- G(() => l.value, () => {
99
- r("on-change", l.value);
109
+ G(() => u.value, () => {
110
+ s("on-change", u.value);
100
111
  });
101
- const v = (t) => {
102
- const e = t, { attribute: a, position: d } = e.detail;
103
- console.debug("dynamic-content:open", e.detail), r("dynamic-content:open", a, d);
112
+ const b = (t) => {
113
+ const e = t, { attribute: i, position: m } = e.detail;
114
+ console.debug("dynamic-content:open", e.detail), s("dynamic-content:open", i, m);
104
115
  };
105
- let i = null;
106
- const b = () => {
116
+ let d = null;
117
+ const h = () => {
107
118
  var e;
108
- const t = document.querySelector(ve);
109
- (e = f.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
110
- }, h = async () => {
119
+ const t = document.querySelector(De);
120
+ (e = y.value) == null || e.style.setProperty("--ribbon-offset", `${(t == null ? void 0 : t.offsetHeight) ?? 0}px`);
121
+ }, E = async () => {
111
122
  var t;
123
+ n.mark("host_ready");
112
124
  try {
113
- o.initialized || o.init(s.config), c.templateId = o.templateId;
114
- const e = o.template, a = (e == null ? void 0 : e.html) || "", d = (e == null ? void 0 : e.css) || "", P = (e == null ? void 0 : e.preselectedDynamicContent) || [];
115
- D.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
116
- const _ = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, O = o.isFeatureEnabled("linkTrackingIds"), x = {
125
+ o.initialized || o.init(a.config), c.templateId = o.templateId, n.setContext({
126
+ partnerName: o.partnerName,
127
+ productType: o.productType,
128
+ templateId: o.templateId,
129
+ variationId: o.variationId
130
+ });
131
+ const e = o.template, i = (e == null ? void 0 : e.html) || "", m = (e == null ? void 0 : e.css) || "", x = (e == null ? void 0 : e.preselectedDynamicContent) || [];
132
+ k.selectedUnsubscribePages = (e == null ? void 0 : e.selectedUnsubscribePages) || [];
133
+ const ie = ((t = e == null ? void 0 : e.migration) == null ? void 0 : t.recommendationConfigs) ?? {}, H = o.isFeatureEnabled("linkTrackingIds"), ae = {
117
134
  partnerName: o.partnerName,
118
135
  campaignUrls: e == null ? void 0 : e.recommendationCampaignUrls,
119
136
  rrsEnabled: o.isFeatureEnabled("reusableRecommendationStrategy")
137
+ }, V = (me) => n.timed(
138
+ "migration",
139
+ () => Ce(me, ie, ae)
140
+ );
141
+ let r = {
142
+ html: i && await V(i),
143
+ css: m
120
144
  };
121
- let n = {
122
- html: a && await V(a, _, x),
123
- css: d
124
- };
125
- n.html || (n = await I(), n.html = await V(n.html, _, x));
126
- const ae = O ? H(n.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
127
- A(n.html) && (n.html = await U(n.html)), O && (c.trackIdSessionFloor = Math.max(ae, H(n.html)));
128
- const se = {
129
- preselectedDynamicContentList: P,
145
+ r.html || (r = await n.timed("default_template", () => N()), r.html = await V(r.html));
146
+ const ce = H ? q(r.html, (e == null ? void 0 : e.trackIdCounter) || 0) : 0;
147
+ A(r.html) && (r.html = await n.timed("timer_clone", () => _(r.html))), H && (c.trackIdSessionFloor = Math.max(ce, q(r.html)));
148
+ const de = {
149
+ preselectedDynamicContentList: x,
130
150
  onReady: () => {
131
- console.debug("guido:ready"), r("ready");
151
+ console.debug("guido:ready"), s("ready");
132
152
  }
133
153
  };
134
- u = T(), await F(n, g(), se), y.selectedDynamicContentList = P;
154
+ p = U(), await R(r, v(), de), g.selectedDynamicContentList = x;
135
155
  } catch (e) {
136
- console.error("Failed to initialize Stripo editor:", e);
156
+ console.error("Failed to initialize Stripo editor:", e), n.markFailed();
137
157
  }
138
158
  };
139
- return ce(async () => {
159
+ return ue(async () => {
140
160
  var e;
141
- console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), E().$reset(), Ne().$reset(), Be().$reset(), C(), b();
142
- const t = (e = f.value) == null ? void 0 : e.parentElement;
143
- if (t && (i = new ResizeObserver(b), i.observe(t)), L(), s.ready)
144
- await h();
161
+ console.debug("Guido says happy coding 🎉"), console.debug("🚗 Ka-Chow"), z().$reset(), w().$reset(), $e().$reset(), Ge().$reset(), C(), h();
162
+ const t = (e = y.value) == null ? void 0 : e.parentElement;
163
+ if (t && (d = new ResizeObserver(h), d.observe(t)), L(), a.ready)
164
+ await E();
145
165
  else {
146
- const a = G(() => s.ready, (d) => {
147
- d && (a(), h());
166
+ const i = G(() => a.ready, (m) => {
167
+ m && (i(), E());
148
168
  });
149
169
  }
150
- document.addEventListener("dynamic-content:open", v);
151
- }), de(() => {
152
- if (he(), be(), i == null || i.disconnect(), document.removeEventListener("dynamic-content:open", v), S(u))
170
+ document.addEventListener("dynamic-content:open", b);
171
+ }), pe(() => {
172
+ if (Me(), Fe(), n.dispose(), d == null || d.disconnect(), document.removeEventListener("dynamic-content:open", b), S(p))
153
173
  try {
154
- E().isStripoInitialized = !1;
174
+ const t = w();
175
+ t.isStripoInitialized = !1, t.isAccessibilityTestingOpen = !1, t.imagesHidden = !1, t.colorVisionDeficiency = "";
155
176
  } catch (t) {
156
177
  console.debug("Failed to close the editor readiness gate on unmount", t);
157
178
  }
158
- M(async () => {
159
- if (S(u))
179
+ O(async () => {
180
+ if (S(p))
160
181
  try {
161
182
  window.UIEditor.removeEditor();
162
183
  } catch {
163
184
  console.debug("Failed to remove Stripo editor: No editor found");
164
185
  }
165
186
  }), o.reset();
166
- }), K({
187
+ }), j({
167
188
  dynamicContent: {
168
189
  insert: B,
169
- close: N
190
+ close: P
170
191
  },
171
- hasChanges: l,
172
- saveSilent: k,
173
- setLoading: R
174
- }), { __sfc: !0, PreviewContainer: j, OnboardingWrapper: J, AssignStrategyDrawer: Q, RemoveStrategyModal: X, LegacyStrategyUpdatedModal: Y, headerWrapperRef: w, wrapperRef: f, dynamicContentStore: y, unsubscribeStore: D, props: s, configStore: o, editorStore: c, previewStore: Z, hasChanges: l, isTestPartner: ee, isSaveValidationEnabled: te, loadRollout: C, saveSilent: k, setLoading: R, emit: r, buildMetadata: g, initPlugin: F, preloadRuntime: L, runExclusive: M, beginMount: T, isCurrentMount: S, mountGeneration: u, getDefaultTemplate: I, cloneTimersOnSave: U, hasTimerBlocks: A, noHeader: oe, isRrsEnabled: ne, hasAssignedStrategy: re, insertDynamicContent: B, closeDynamicContent: N, handleDynamicContentOpen: v, ribbonObserver: i, updateRibbonOffset: b, startEditor: h, AutoSaveController: Ee, AuthErrorModal: we, Toaster: De, FilterSelectionDrawer: Ce, HeaderWrapper: ke, LoadingWrapper: Re, SaveAsTemplateDrawer: Fe, UnsubscribeWrapper: Le, ValidationErrorDrawer: Me };
192
+ hasChanges: u,
193
+ saveSilent: F,
194
+ setLoading: M
195
+ }), { __sfc: !0, openMetrics: n, PreviewContainer: J, OnboardingWrapper: Q, AssignStrategyDrawer: X, RemoveStrategyModal: Y, autoSaveControllerRef: T, LegacyStrategyUpdatedModal: Z, wrapperRef: y, dynamicContentStore: g, unsubscribeStore: k, props: a, configStore: o, editorStore: c, previewStore: ee, hasChanges: u, isTestPartner: te, isSaveValidationEnabled: oe, loadRollout: C, showToaster: D, trans: I, saveSilent: F, setLoading: M, emit: s, buildMetadata: v, initPlugin: R, preloadRuntime: L, runExclusive: O, beginMount: U, isCurrentMount: S, mountGeneration: p, getDefaultTemplate: N, cloneTimersOnSave: _, hasTimerBlocks: A, noHeader: re, isRrsEnabled: ne, hasAssignedStrategy: se, insertDynamicContent: B, closeDynamicContent: P, handleDynamicContentOpen: b, ribbonObserver: d, updateRibbonOffset: h, startEditor: E, AutoSaveController: Re, AuthErrorModal: Le, Toaster: Oe, FilterSelectionDrawer: Ue, HeaderWrapper: Ne, LoadingWrapper: _e, SaveAsTemplateDrawer: Ae, UnsubscribeWrapper: Be, ValidationErrorDrawer: Pe };
175
196
  }
176
197
  });
177
198
  export {
178
- yt as default
199
+ Ft as default
179
200
  };
@@ -1,15 +1,25 @@
1
- import { defineComponent as n } from "vue";
2
- import { useAutoSave as u } from "../../composables/useAutoSave.js";
3
- import { useSave as i } from "../../composables/useSave.js";
4
- import { useSaveValidationRollout as l } from "../../composables/useSaveValidationRollout.js";
5
- import { useConfigStore as m } from "../../stores/config.js";
6
- const d = /* @__PURE__ */ n({
1
+ import { defineComponent as c } from "vue";
2
+ import { useAutoSave as m } from "../../composables/useAutoSave.js";
3
+ import { useSave as f } from "../../composables/useSave.js";
4
+ import { useSaveValidationRollout as v } from "../../composables/useSaveValidationRollout.js";
5
+ import { useToaster as p } from "../../composables/useToaster.js";
6
+ import { useConfigStore as S } from "../../stores/config.js";
7
+ const A = /* @__PURE__ */ c({
7
8
  __name: "AutoSaveController",
8
- setup(f) {
9
- const { save: e, saveRawOnly: t } = i(), { isEnabled: r } = l(), a = m(), o = () => r.value && a.allowSaveWithErrors, s = () => o() ? t() : e(!1, !0);
10
- return u(s, { clearsChanges: () => !o() }), { __sfc: !0, save: e, saveRawOnly: t, isEnabled: r, configStore: a, isRawAutosave: o, backgroundSave: s };
9
+ setup(d, { expose: u }) {
10
+ const { save: e, saveRawOnly: t } = f(), { isEnabled: r } = v(), { handleError: a } = p(), s = S(), o = () => r.value && s.allowSaveWithErrors, n = () => o() ? t() : e(!1, !0);
11
+ m(n, { clearsChanges: () => !o() });
12
+ const i = async () => {
13
+ try {
14
+ return await e(!0);
15
+ } catch (l) {
16
+ a(l, "Failed to save template");
17
+ return;
18
+ }
19
+ };
20
+ return u({ saveSilent: i }), { __sfc: !0, save: e, saveRawOnly: t, isEnabled: r, handleError: a, configStore: s, isRawAutosave: o, backgroundSave: n, saveSilent: i };
11
21
  }
12
22
  });
13
23
  export {
14
- d as default
24
+ A as default
15
25
  };
@@ -0,0 +1,17 @@
1
+ import t from "./AutoSaveStatus.vue2.js";
2
+ import r from "../../../_virtual/_plugin-vue2_normalizer.js";
3
+ var _ = function() {
4
+ var s = this, e = s._self._c, a = s._self._setupProxy;
5
+ return a.isFeatureEnabled("autosave") ? e("div", { staticClass: "d-f a-i-c auto-save-status" }, [a.autosaveStore.status === a.AUTOSAVE_STATUS.SAVING ? e("span", { staticClass: "d-f a-i-c f-s-1" }, [e(a.InLoading, { attrs: { "color-class": "i-c-53", size: "16" } }), e("span", { staticClass: "ml-1 t-c-53" }, [s._v(s._s(a.trans("newsletter.saving")))])], 1) : a.savedLabel ? e("span", { staticClass: "f-s-1 t-c-53" }, [s._v(s._s(a.savedLabel.before)), a.savedLabel.word ? e("span", { staticClass: "f-w-600" }, [s._v(s._s(a.savedLabel.word))]) : s._e(), s._v(s._s(a.savedLabel.after))]) : s._e()]) : s._e();
6
+ }, n = [], o = /* @__PURE__ */ r(
7
+ t,
8
+ _,
9
+ n,
10
+ !1,
11
+ null,
12
+ null
13
+ );
14
+ const v = o.exports;
15
+ export {
16
+ v as default
17
+ };
@@ -0,0 +1,25 @@
1
+ import { defineComponent as p, computed as S } from "vue";
2
+ import { useConfig as A } from "../../../composables/useConfig.js";
3
+ import { useTranslations as T } from "../../../composables/useTranslations.js";
4
+ import { useAutosaveStore as v, AUTOSAVE_STATUS as m } from "../../../stores/autosave.js";
5
+ import { autoSaveTimestamp as b } from "../../../utils/timeUtil.js";
6
+ import { InLoading as D } from "@useinsider/design-system-vue";
7
+ const j = /* @__PURE__ */ p({
8
+ __name: "AutoSaveStatus",
9
+ setup(O) {
10
+ const { isFeatureEnabled: u } = A(), a = v(), n = T(), t = "__BOLD_START__", o = "__BOLD_END__", s = (i) => i.split(t).join("").split(o).join(""), _ = S(() => {
11
+ if (a.status !== m.SAVED || !a.lastSavedAt)
12
+ return null;
13
+ const { isToday: i, time: c, date: f } = b(a.lastSavedAt), l = { boldStart: t, boldEnd: o }, e = i ? n("email-editor.autosaved-at-today", { ...l, time: c }) : n("email-editor.autosaved-at-date", { ...l, date: f }), r = e.indexOf(t), d = e.indexOf(o, r + t.length);
14
+ return r === -1 || d === -1 ? { before: s(e), word: "", after: "" } : {
15
+ before: s(e.slice(0, r)),
16
+ word: s(e.slice(r + t.length, d)),
17
+ after: s(e.slice(d + o.length))
18
+ };
19
+ });
20
+ return { __sfc: !0, isFeatureEnabled: u, autosaveStore: a, trans: n, BOLD_START: t, BOLD_END: o, stripMarkers: s, savedLabel: _, AUTOSAVE_STATUS: m, InLoading: D };
21
+ }
22
+ });
23
+ export {
24
+ j as default
25
+ };
@@ -1,23 +1,23 @@
1
- import l from "./EditorActions.vue2.js";
1
+ import a from "./EditorActions.vue2.js";
2
2
  /* empty css */
3
- import d from "../../../_virtual/_plugin-vue2_normalizer.js";
4
- var u = function() {
5
- var s, i, n, a;
6
- var o = this, e = o._self._c, t = o._self._setupProxy;
7
- return e("div", { staticClass: "d-f editor-actions" }, [t.isVersionHistoryButtonVisible ? e(t.InButtonV2, { attrs: { id: "guido__history-button", "left-icon": "line-architect-version-history", styling: "ghost", type: "secondary", "disabled-status": t.editorStore.isVersionHistoryButtonDisabled, "label-text-status": !1, "selected-status": t.editorStore.isVersionHistoryOpen, "tooltip-options": t.getTooltipOptions("guido__history-button"), "tooltip-text": t.versionHistoryTooltipText }, on: { click: t.handleVersionHistory } }) : o._e(), e(t.InButtonV2, { attrs: { id: "guido__export-button", "left-icon": "line-export", styling: "ghost", type: "secondary", "disabled-status": t.editorStore.isExportButtonDisabled, "label-text-status": !1, "loading-status": t.isExporting, "tooltip-options": t.getTooltipOptions("guido__export-button"), "tooltip-text": t.trans("newsletter.export") }, on: { click: t.handleExport } }), (i = (s = t.config) == null ? void 0 : s.features) != null && i.saveAsTemplate ? e(t.InButtonV2, { attrs: { id: "guido__save-as-button", "left-icon": "line-newsletter-save-as-template", styling: "ghost", type: "secondary", "disabled-status": t.editorStore.isSaveAsButtonDisabled, "label-text-status": !1, "tooltip-options": t.getTooltipOptions("guido__save-as-button"), "tooltip-text": t.trans("newsletter.save-templates") }, on: { click: t.handleSaveAs } }) : o._e(), (a = (n = t.config) == null ? void 0 : n.features) != null && a.testMessage ? e(t.InButtonV2, { attrs: { id: "guido__test-button", "left-icon": "line-architect-test-journey", styling: "ghost", type: "secondary", "disabled-status": t.editorStore.isTestButtonDisabled, "label-text-status": !1, "tooltip-options": t.getTooltipOptions("guido__test-button", { staticPosition: "bottom right" }), "tooltip-text": t.trans("newsletter.test-email") }, on: { click: t.handleTestEmail } }) : o._e(), t.editorStore.isPreviewModeOpen ? o._e() : e(t.InButtonV2, { staticClass: "ml-3", attrs: { id: "guido__save-button", "disabled-status": !t.isSaving && t.editorStore.isSaveButtonDisabled, "label-text": t.saveLabel, "loading-status": t.isSaving }, on: { click: function(r) {
3
+ import r from "../../../_virtual/_plugin-vue2_normalizer.js";
4
+ var d = function() {
5
+ var o, s;
6
+ var i = this, e = i._self._c, t = i._self._setupProxy;
7
+ return e("div", { staticClass: "d-f a-i-c editor-actions" }, [!t.editorStore.isPreviewModeOpen && t.hasContentOnTheLeft ? e("div", { staticClass: "editor-actions__divider" }) : i._e(), (s = (o = t.config) == null ? void 0 : o.features) != null && s.testMessage ? e(t.InButtonV2, { attrs: { id: "guido__test-button", "left-icon": "line-architect-test-journey", styling: "ghost", type: "secondary", "disabled-status": t.editorStore.isTestButtonDisabled, "label-text-status": !1, "tooltip-options": t.getTooltipOptions("guido__test-button", { staticPosition: "bottom right" }), "tooltip-text": t.trans("newsletter.test-email") }, on: { click: t.handleTestEmail } }) : i._e(), e(t.EditorActionsMenu), t.editorStore.isPreviewModeOpen ? i._e() : e("div", { staticClass: "editor-actions__divider" }), t.editorStore.isPreviewModeOpen ? i._e() : e(t.InButtonV2, { staticClass: "ml-3", attrs: { id: "guido__save-button", "disabled-status": !t.isSaving && t.editorStore.isSaveButtonDisabled, "label-text": t.saveLabel, "loading-status": t.isSaving }, on: { click: function(n) {
8
8
  return t.handleSave(!1);
9
- } } }), e(t.MigrationConfirmModal, { ref: "migrationModalRef", on: { confirm: function(r) {
9
+ } } }), e(t.MigrationConfirmModal, { ref: "migrationModalRef", on: { confirm: function(n) {
10
10
  return t.executeSave(!1);
11
11
  } } })], 1);
12
- }, p = [], c = /* @__PURE__ */ d(
12
+ }, l = [], c = /* @__PURE__ */ r(
13
+ a,
14
+ d,
13
15
  l,
14
- u,
15
- p,
16
16
  !1,
17
17
  null,
18
- "baf7a5dd"
18
+ "9a028d08"
19
19
  );
20
- const v = c.exports;
20
+ const p = c.exports;
21
21
  export {
22
- v as default
22
+ p as default
23
23
  };