@useinsider/guido 3.2.0-beta.c08c480 → 3.2.0-beta.c3bc14c

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 (31) hide show
  1. package/README.md +1 -25
  2. package/dist/@types/config/schemas.js +36 -38
  3. package/dist/components/Guido.vue.js +4 -4
  4. package/dist/components/Guido.vue2.js +34 -35
  5. package/dist/components/organisms/header/RightSlot.vue.js +8 -8
  6. package/dist/components/organisms/header/RightSlot.vue2.js +8 -9
  7. package/dist/composables/useSave.js +17 -14
  8. package/dist/composables/validators/useCouponBlockValidator.js +24 -0
  9. package/dist/guido.css +1 -1
  10. package/dist/src/@types/config/schemas.d.ts +0 -4
  11. package/dist/src/components/Guido.vue.d.ts +1 -1
  12. package/dist/src/components/organisms/header/EditorActions.vue.d.ts +1 -1
  13. package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +1 -1
  14. package/dist/src/components/organisms/header/RightSlot.vue.d.ts +1 -1
  15. package/dist/src/composables/useConfig.d.ts +0 -2
  16. package/dist/src/composables/useSave.d.ts +1 -1
  17. package/dist/src/composables/validators/useCouponBlockValidator.d.ts +3 -0
  18. package/dist/src/stores/config.d.ts +0 -18
  19. package/package.json +1 -1
  20. package/dist/components/organisms/AutoSaveController.vue.js +0 -17
  21. package/dist/components/organisms/AutoSaveController.vue2.js +0 -13
  22. package/dist/components/organisms/header/AutoSaveToggle.vue.js +0 -22
  23. package/dist/components/organisms/header/AutoSaveToggle.vue2.js +0 -19
  24. package/dist/composables/useAutoSave.js +0 -72
  25. package/dist/src/components/organisms/AutoSaveController.vue.d.ts +0 -2
  26. package/dist/src/components/organisms/header/AutoSaveToggle.vue.d.ts +0 -2
  27. package/dist/src/composables/useAutoSave.d.ts +0 -3
  28. package/dist/src/stores/autosave.d.ts +0 -6
  29. package/dist/src/utils/timeUtil.d.ts +0 -8
  30. package/dist/stores/autosave.js +0 -11
  31. package/dist/utils/timeUtil.js +0 -19
package/README.md CHANGED
@@ -143,8 +143,7 @@ const config: GuidoConfigInput = {
143
143
  displayConditions?: boolean, // Default: true
144
144
  unsubscribe?: boolean, // Default: true
145
145
  modulesDisabled?: boolean, // Default: false - Disable modules panel
146
- liquidSyntax?: boolean, // Default: false - Enable Liquid template syntax
147
- autosave?: boolean, // Default: false - Show the Auto Save toggle in the header. See wiki/AUTOSAVE.md.
146
+ liquidSyntax?: boolean, // Default: false - Enable Liquid template syntax
148
147
  },
149
148
 
150
149
  // Optional: Callbacks
@@ -203,7 +202,6 @@ interface SavedTemplateDetails {
203
202
  config: number[];
204
203
  };
205
204
  metadata: Metadata;
206
- silent: boolean; // true when triggered by autosave, false when user clicked Save
207
205
  }
208
206
 
209
207
  interface Metadata {
@@ -329,28 +327,6 @@ const config: GuidoConfigInput = {
329
327
 
330
328
  ---
331
329
 
332
- ## Autosave
333
-
334
- Guido ships an opt-in **autosave** that saves on a 3-minute interval and when the user leaves the tab. Enable it with the `features.autosave` feature flag — this **shows an "Auto Save" toggle in the editor header**; the end user switches autosave on per session.
335
-
336
- ```typescript
337
- const config: GuidoConfigInput = {
338
- identity: { templateId: 'tpl-123', userId: 'user-456' },
339
- partner: { name: 'partner' },
340
- features: {
341
- autosave: true, // Default: false — shows the Auto Save toggle in the header
342
- },
343
- };
344
- ```
345
-
346
- - Default is `false` — integrations see no change unless they opt in.
347
- - Autosave reuses the same save pipeline as the Save button, so your existing `@save:complete` handler receives autosave output identically to a manual save. No new events or callbacks.
348
- - Toggle state is **session-only** (Pinia) — resets to OFF on reload.
349
-
350
- For a deep dive on triggers, guards, and limitations, see **[wiki/AUTOSAVE.md](wiki/AUTOSAVE.md)**.
351
-
352
- ---
353
-
354
330
  ## HTML Compiler Rules
355
331
 
356
332
  Add custom rules to transform HTML during export:
@@ -1,5 +1,5 @@
1
1
  import { ModuleFolderDefaults as b } from "../../enums/defaults.js";
2
- import { object as a, number as p, optional as e, string as t, pipe as u, picklist as n, minLength as d, custom as S, boolean as o, array as c, literal as l, variant as k } from "../../node_modules/valibot/dist/index.js";
2
+ import { object as o, number as p, optional as e, string as t, pipe as u, picklist as n, minLength as d, custom as S, boolean as a, array as c, literal as l, variant as k } from "../../node_modules/valibot/dist/index.js";
3
3
  const m = {
4
4
  /** Promotional/marketing emails */
5
5
  PROMOTIONAL: 1,
@@ -12,7 +12,7 @@ const m = {
12
12
  ARCHITECT: 49,
13
13
  /** Unsubscribe page builder */
14
14
  UNSUBSCRIBE_PAGES: 97
15
- }, h = a({
15
+ }, h = o({
16
16
  /** Unique identifier for the template being edited */
17
17
  templateId: u(
18
18
  t(),
@@ -25,12 +25,12 @@ const m = {
25
25
  ),
26
26
  /** Optional variation ID for A/B testing */
27
27
  variationId: e(t())
28
- }), f = a({
28
+ }), y = o({
29
29
  /** Fallback font name (e.g., "Georgia") */
30
30
  name: t(),
31
31
  /** Fallback font family (e.g., "serif" or "sans-serif") */
32
32
  family: t()
33
- }), y = a({
33
+ }), f = o({
34
34
  /** Partner/organization name (required) */
35
35
  name: u(
36
36
  t(),
@@ -53,8 +53,8 @@ const m = {
53
53
  /** Display name for the current user */
54
54
  username: e(t(), "Guido User"),
55
55
  /** Fallback font settings from partner settings — used to match backend size calculation */
56
- fallbackFont: e(f)
57
- }), A = a({
56
+ fallbackFont: e(y)
57
+ }), A = o({
58
58
  /** Display text for the dynamic content */
59
59
  text: t(),
60
60
  /** Template variable value (e.g., {{username}}) */
@@ -63,12 +63,12 @@ const m = {
63
63
  fallback: e(t()),
64
64
  /** Optional formatting options */
65
65
  format: e(
66
- a({
66
+ o({
67
67
  key: t(),
68
68
  value: t()
69
69
  })
70
70
  )
71
- }), R = a({
71
+ }), R = o({
72
72
  /** Initial HTML content */
73
73
  html: e(t(), ""),
74
74
  /** Initial CSS content */
@@ -83,13 +83,13 @@ const m = {
83
83
  /** Selected unsubscribe page IDs */
84
84
  selectedUnsubscribePages: e(c(p()), []),
85
85
  /** Force recreate template in Stripo storage (use true when updating externally modified templates) */
86
- forceRecreate: e(o(), !1)
87
- }), C = a({
86
+ forceRecreate: e(a(), !1)
87
+ }), C = o({
88
88
  /** Sender display name */
89
89
  senderName: e(t(), ""),
90
90
  /** Email subject line */
91
91
  subject: e(t(), "")
92
- }), T = a({
92
+ }), T = o({
93
93
  /** Locale for the editor UI */
94
94
  locale: e(t(), "en"),
95
95
  /** Path to translations object */
@@ -102,30 +102,28 @@ const m = {
102
102
  savedModulesFolderName: e(t(), b.SAVED_MODULES),
103
103
  /** Folder name for default/prebuilt modules (used by Stripo plugin panel for path construction) */
104
104
  defaultModulesFolderName: e(t(), b.DEFAULT_MODULES)
105
- }), I = a({
105
+ }), I = o({
106
106
  /** Whether to show the header bar */
107
- showHeader: e(o(), !0),
107
+ showHeader: e(a(), !0),
108
108
  /** Custom label for back button (if shown) */
109
109
  backButtonLabel: e(t())
110
- }), E = a({
110
+ }), E = o({
111
111
  /** Enable dynamic content insertion */
112
- dynamicContent: e(o(), !0),
112
+ dynamicContent: e(a(), !0),
113
113
  /** Enable save as template functionality */
114
- saveAsTemplate: e(o(), !0),
114
+ saveAsTemplate: e(a(), !0),
115
115
  /** Enable version history */
116
- versionHistory: e(o(), !0),
116
+ versionHistory: e(a(), !0),
117
117
  /** Enable test message sending */
118
- testMessage: e(o(), !0),
118
+ testMessage: e(a(), !0),
119
119
  /** Enable display conditions */
120
- displayConditions: e(o(), !0),
120
+ displayConditions: e(a(), !0),
121
121
  /** Enable unsubscribe block */
122
- unsubscribe: e(o(), !0),
122
+ unsubscribe: e(a(), !0),
123
123
  /** Disable modules panel in the editor */
124
- modulesDisabled: e(o(), !1),
124
+ modulesDisabled: e(a(), !1),
125
125
  /** Enable Liquid template syntax */
126
- liquidSyntax: e(o(), !1),
127
- /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
128
- autosave: e(o(), !1)
126
+ liquidSyntax: e(a(), !1)
129
127
  }), g = n([
130
128
  "amp-accordion",
131
129
  "amp-carousel",
@@ -148,7 +146,7 @@ const m = {
148
146
  "unsubscribe-block",
149
147
  "coupon-block",
150
148
  "items-block"
151
- ]), L = a({
149
+ ]), L = o({
152
150
  /** Default blocks to exclude from the editor */
153
151
  excludeDefaults: e(
154
152
  c(g),
@@ -159,14 +157,14 @@ const m = {
159
157
  c(O),
160
158
  []
161
159
  )
162
- }), r = a({
160
+ }), r = o({
163
161
  /** Unique identifier for the rule */
164
162
  id: t(),
165
163
  /** Human-readable description */
166
164
  description: e(t()),
167
165
  /** Priority for rule ordering (lower = earlier) */
168
166
  priority: p()
169
- }), M = a({
167
+ }), M = o({
170
168
  ...r.entries,
171
169
  type: l("replace"),
172
170
  /** String to search for */
@@ -174,8 +172,8 @@ const m = {
174
172
  /** Replacement string */
175
173
  replacement: t(),
176
174
  /** Replace all occurrences (default: false) */
177
- replaceAll: e(o())
178
- }), N = a({
175
+ replaceAll: e(a())
176
+ }), N = o({
179
177
  ...r.entries,
180
178
  type: l("regex"),
181
179
  /** Regex pattern string */
@@ -184,12 +182,12 @@ const m = {
184
182
  replacement: t(),
185
183
  /** Regex flags (e.g., 'gi') */
186
184
  flags: e(t())
187
- }), D = a({
185
+ }), D = o({
188
186
  ...r.entries,
189
187
  type: l("remove"),
190
188
  /** Strings or patterns to remove */
191
189
  targets: c(t())
192
- }), v = a({
190
+ }), v = o({
193
191
  ...r.entries,
194
192
  type: l("custom"),
195
193
  /** Custom processor function */
@@ -202,12 +200,12 @@ const m = {
202
200
  N,
203
201
  D,
204
202
  v
205
- ]), U = a({
203
+ ]), U = o({
206
204
  /** Custom compiler rules to apply */
207
205
  customRules: e(c(x), []),
208
206
  /** Skip default compiler rules */
209
- ignoreDefaultRules: e(o(), !1)
210
- }), B = a({
207
+ ignoreDefaultRules: e(a(), !1)
208
+ }), B = o({
211
209
  /**
212
210
  * External validation handler called before save completes.
213
211
  * Return false to cancel the save operation.
@@ -218,12 +216,12 @@ const m = {
218
216
  "externalValidation must be a function"
219
217
  )
220
218
  )
221
- }), H = a({
219
+ }), H = o({
222
220
  // Required sections
223
221
  /** Identity configuration (required) */
224
222
  identity: h,
225
223
  /** Partner configuration (required) */
226
- partner: y,
224
+ partner: f,
227
225
  // Optional sections (with defaults)
228
226
  /** Template content and presets */
229
227
  template: e(R, {}),
@@ -251,12 +249,12 @@ export {
251
249
  A as DynamicContentSchema,
252
250
  T as EditorSchema,
253
251
  C as EmailHeaderSchema,
254
- f as FallbackFontSchema,
252
+ y as FallbackFontSchema,
255
253
  E as FeaturesSchema,
256
254
  H as GuidoConfigSchema,
257
255
  h as IdentitySchema,
258
256
  m as MessageType,
259
- y as PartnerSchema,
257
+ f as PartnerSchema,
260
258
  s as ProductType,
261
259
  N as RegexRuleSchema,
262
260
  D as RemoveRuleSchema,
@@ -3,7 +3,7 @@ import i from "./Guido.vue2.js";
3
3
  import a from "../_virtual/_plugin-vue2_normalizer.js";
4
4
  var t = function() {
5
5
  var o = this, r = o._self._c, e = o._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) : o._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.FilterSelectionDrawer), r(e.SaveAsTemplateDrawer), e.isTestPartner() ? o._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(p) {
6
+ return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper, { ref: "headerWrapperRef" }), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : o._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.FilterSelectionDrawer), r(e.SaveAsTemplateDrawer), e.isTestPartner() ? o._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(p) {
7
7
  return e.emit("onboarding:finished");
8
8
  } } }), r(e.UnsubscribeWrapper), r(e.LoadingWrapper)], 1);
9
9
  }, n = [], s = /* @__PURE__ */ a(
@@ -12,9 +12,9 @@ var t = function() {
12
12
  n,
13
13
  !1,
14
14
  null,
15
- "fffc13d6"
15
+ "25780af6"
16
16
  );
17
- const l = s.exports;
17
+ const u = s.exports;
18
18
  export {
19
- l as default
19
+ u as default
20
20
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent as j, defineAsyncComponent as N, ref as R, computed as I, watch as J, onMounted as Q, onUnmounted as X } from "vue";
1
+ import { defineComponent as j, defineAsyncComponent as R, ref as A, computed as I, watch as J, onMounted as Q, onUnmounted as X } from "vue";
2
2
  import { provideGuidoActions as Y } from "../composables/useGuidoActions.js";
3
3
  import { usePartner as Z } from "../composables/usePartner.js";
4
4
  import { useStripo as ee } from "../composables/useStripo.js";
@@ -6,43 +6,42 @@ import { useTimerClone as te } from "../composables/useTimerClone.js";
6
6
  import { migrate as W } from "../config/migrator/index.js";
7
7
  import { ModuleFolderDefaults as B } from "../enums/defaults.js";
8
8
  import { RIBBON_SELECTOR as oe } from "../enums/onboarding.js";
9
- import ne from "./organisms/AutoSaveController.vue.js";
10
- import re from "./organisms/base/Toaster.vue.js";
9
+ import ne from "./organisms/base/Toaster.vue.js";
11
10
  import se from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
12
- import ce from "./organisms/header/HeaderWrapper.vue.js";
13
- import ae from "./organisms/LoadingWrapper.vue.js";
14
- import ie from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
15
- import me from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
16
- import { useStripoApi as de } from "../services/stripoApi.js";
17
- import { useConfigStore as le } from "../stores/config.js";
18
- import { useDynamicContentStore as ue } from "../stores/dynamic-content.js";
19
- import { useEditorStore as pe } from "../stores/editor.js";
20
- import { usePreviewStore as fe } from "../stores/preview.js";
21
- import { useUnsubscribeStore as ve } from "../stores/unsubscribe.js";
22
- const Ie = /* @__PURE__ */ j({
11
+ import re from "./organisms/header/HeaderWrapper.vue.js";
12
+ import ce from "./organisms/LoadingWrapper.vue.js";
13
+ import ae from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
14
+ import ie from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
15
+ import { useStripoApi as me } from "../services/stripoApi.js";
16
+ import { useConfigStore as de } from "../stores/config.js";
17
+ import { useDynamicContentStore as le } from "../stores/dynamic-content.js";
18
+ import { useEditorStore as ue } from "../stores/editor.js";
19
+ import { usePreviewStore as pe } from "../stores/preview.js";
20
+ import { useUnsubscribeStore as fe } from "../stores/unsubscribe.js";
21
+ const Re = /* @__PURE__ */ j({
23
22
  __name: "Guido",
24
23
  props: {
25
24
  config: null
26
25
  },
27
26
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
28
- setup(H, { expose: x, emit: r }) {
29
- const S = H, G = N(
27
+ setup(H, { expose: x, emit: s }) {
28
+ const b = H, G = R(
30
29
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
31
- ), z = N(
30
+ ), z = R(
32
31
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
33
- ), b = R(), d = R(), l = ue(), g = ve(), a = le();
34
- a.init(S.config);
35
- const u = pe(), q = fe(), i = I(() => u.hasChanges), { isTestPartner: K } = Z(), w = () => {
32
+ ), S = A(), d = A(), l = le(), g = fe(), a = de();
33
+ a.init(b.config);
34
+ const u = ue(), q = pe(), i = I(() => u.hasChanges), { isTestPartner: K } = Z(), w = () => {
36
35
  var e;
37
- return (e = b.value) == null ? void 0 : e.handleSave(!0);
36
+ return (e = S.value) == null ? void 0 : e.handleSave(!0);
38
37
  }, {
39
38
  templateId: p,
40
39
  userId: E,
41
40
  partnerName: D,
42
41
  username: C,
43
42
  template: t,
44
- editor: s
45
- } = a, m = (t == null ? void 0 : t.html) || "", T = (t == null ? void 0 : t.css) || "", f = (t == null ? void 0 : t.preselectedDynamicContent) || [], k = (s == null ? void 0 : s.savedModulesFolderName) || B.SAVED_MODULES, F = (s == null ? void 0 : s.defaultModulesFolderName) || B.DEFAULT_MODULES;
43
+ editor: r
44
+ } = a, m = (t == null ? void 0 : t.html) || "", T = (t == null ? void 0 : t.css) || "", f = (t == null ? void 0 : t.preselectedDynamicContent) || [], k = (r == null ? void 0 : r.savedModulesFolderName) || B.SAVED_MODULES, F = (r == null ? void 0 : r.defaultModulesFolderName) || B.DEFAULT_MODULES;
46
45
  u.templateId = p;
47
46
  const v = {
48
47
  emailId: p,
@@ -54,38 +53,38 @@ const Ie = /* @__PURE__ */ j({
54
53
  }, L = {
55
54
  preselectedDynamicContentList: f,
56
55
  onReady: () => {
57
- console.debug("guido:ready"), r("ready");
56
+ console.debug("guido:ready"), s("ready");
58
57
  }
59
- }, { initPlugin: U } = ee(v, L), { getDefaultTemplate: _ } = de(), { cloneTimersOnSave: M, hasTimerBlocks: O } = te(), V = I(() => {
58
+ }, { initPlugin: U } = ee(v, L), { getDefaultTemplate: _ } = me(), { cloneTimersOnSave: M, hasTimerBlocks: O } = te(), V = I(() => {
60
59
  var e;
61
60
  return !((e = a.ui) != null && e.showHeader);
62
61
  });
63
62
  Y({
64
63
  onBack: () => {
65
- console.debug("guido:back"), r("back");
64
+ console.debug("guido:back"), s("back");
66
65
  },
67
66
  onSaveStart: () => {
68
- console.debug("guido:save:start"), r("save:start");
67
+ console.debug("guido:save:start"), s("save:start");
69
68
  },
70
69
  onSaveComplete: (e) => {
71
70
  const n = { ...e, metadata: v };
72
- console.debug("guido:save:complete", n), r("save:complete", n);
71
+ console.debug("guido:save:complete", n), s("save:complete", n);
73
72
  },
74
73
  onTestEmailClick: () => {
75
- console.debug("guido:test-email:click"), r("test-email:click");
74
+ console.debug("guido:test-email:click"), s("test-email:click");
76
75
  }
77
76
  });
78
77
  const P = (e) => {
79
78
  console.debug("dynamic-content:close", e), l.setSelectedDynamicContent(e), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: e }));
80
- }, A = () => {
79
+ }, N = () => {
81
80
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
82
81
  };
83
82
  J(() => i.value, () => {
84
- r("on-change", i.value);
83
+ s("on-change", i.value);
85
84
  });
86
85
  const y = (e) => {
87
86
  const n = e, { attribute: o, position: $ } = n.detail;
88
- console.debug("dynamic-content:open", n.detail), r("dynamic-content:open", o, $);
87
+ console.debug("dynamic-content:open", n.detail), s("dynamic-content:open", o, $);
89
88
  };
90
89
  let c = null;
91
90
  const h = () => {
@@ -120,13 +119,13 @@ const Ie = /* @__PURE__ */ j({
120
119
  }), x({
121
120
  dynamicContent: {
122
121
  insert: P,
123
- close: A
122
+ close: N
124
123
  },
125
124
  hasChanges: i,
126
125
  saveSilent: w
127
- }), { __sfc: !0, PreviewContainer: G, OnboardingWrapper: z, headerWrapperRef: b, wrapperRef: d, dynamicContentStore: l, unsubscribeStore: g, props: S, configStore: a, editorStore: u, previewStore: q, hasChanges: i, isTestPartner: K, saveSilent: w, templateId: p, userId: E, partnerName: D, username: C, templateConfig: t, editorConfig: s, html: m, css: T, preselectedDynamicContentList: f, savedModulesFolderName: k, defaultModulesFolderName: F, emit: r, metadata: v, options: L, initPlugin: U, getDefaultTemplate: _, cloneTimersOnSave: M, hasTimerBlocks: O, noHeader: V, insertDynamicContent: P, closeDynamicContent: A, handleDynamicContentOpen: y, ribbonObserver: c, updateRibbonOffset: h, AutoSaveController: ne, Toaster: re, FilterSelectionDrawer: se, HeaderWrapper: ce, LoadingWrapper: ae, SaveAsTemplateDrawer: ie, UnsubscribeWrapper: me };
126
+ }), { __sfc: !0, PreviewContainer: G, OnboardingWrapper: z, headerWrapperRef: S, wrapperRef: d, dynamicContentStore: l, unsubscribeStore: g, props: b, configStore: a, editorStore: u, previewStore: q, hasChanges: i, isTestPartner: K, saveSilent: w, templateId: p, userId: E, partnerName: D, username: C, templateConfig: t, editorConfig: r, html: m, css: T, preselectedDynamicContentList: f, savedModulesFolderName: k, defaultModulesFolderName: F, emit: s, metadata: v, options: L, initPlugin: U, getDefaultTemplate: _, cloneTimersOnSave: M, hasTimerBlocks: O, noHeader: V, insertDynamicContent: P, closeDynamicContent: N, handleDynamicContentOpen: y, ribbonObserver: c, updateRibbonOffset: h, Toaster: ne, FilterSelectionDrawer: se, HeaderWrapper: re, LoadingWrapper: ce, SaveAsTemplateDrawer: ae, UnsubscribeWrapper: ie };
128
127
  }
129
128
  });
130
129
  export {
131
- Ie as default
130
+ Re as default
132
131
  };
@@ -1,11 +1,11 @@
1
- import s from "./RightSlot.vue2.js";
2
- import o from "../../../_virtual/_plugin-vue2_normalizer.js";
3
- var r = function() {
4
- var i = this, e = i._self._c, t = i._self._setupProxy;
5
- return e("div", { staticClass: "d-f a-i-c" }, [t.editorStore.isVersionHistoryOpen ? i._e() : e(t.AutoSaveToggle), t.isLiquidEnabled && !t.editorStore.isVersionHistoryOpen ? e(t.InChips, { staticClass: "mr-1", attrs: { id: "guido__liquid-tag-chip", styles: "stroke", type: "default", value: "liquid-tags", "close-button": !1, "disabled-status": t.editorStore.loadingStatus, interactive: !1, text: t.trans("email-editor.liquid-tags-enabled") } }) : i._e(), t.editorStore.isVersionHistoryOpen ? e(t.RestoreButton) : e(t.EditorActions, { ref: "editorActionsRef" })], 1);
6
- }, a = [], n = /* @__PURE__ */ o(
7
- s,
8
- r,
1
+ import i from "./RightSlot.vue2.js";
2
+ import r from "../../../_virtual/_plugin-vue2_normalizer.js";
3
+ var o = function() {
4
+ var s = this, e = s._self._c, t = s._self._setupProxy;
5
+ return e("div", { staticClass: "d-f a-i-c" }, [t.isLiquidEnabled && !t.editorStore.isVersionHistoryOpen ? e(t.InChips, { staticClass: "mr-3", attrs: { id: "guido__liquid-tag-chip", styles: "stroke", type: "default", value: "liquid-tags", "close-button": !1, "disabled-status": t.editorStore.loadingStatus, interactive: !1, text: t.trans("email-editor.liquid-tags-enabled") } }) : s._e(), t.editorStore.isVersionHistoryOpen ? e(t.RestoreButton) : e(t.EditorActions, { ref: "editorActionsRef" })], 1);
6
+ }, a = [], n = /* @__PURE__ */ r(
7
+ i,
8
+ o,
9
9
  a,
10
10
  !1,
11
11
  null,
@@ -1,23 +1,22 @@
1
1
  import { defineComponent as a, ref as f, computed as p } from "vue";
2
2
  import { useConfig as u } from "../../../composables/useConfig.js";
3
3
  import { useTranslations as d } from "../../../composables/useTranslations.js";
4
- import { useEditorStore as l } from "../../../stores/editor.js";
5
- import { InChips as c } from "@useinsider/design-system-vue";
6
- import _ from "./AutoSaveToggle.vue.js";
7
- import S from "./EditorActions.vue.js";
8
- import g from "./version-history/RestoreButton.vue.js";
9
- const T = /* @__PURE__ */ a({
4
+ import { useEditorStore as c } from "../../../stores/editor.js";
5
+ import { InChips as l } from "@useinsider/design-system-vue";
6
+ import _ from "./EditorActions.vue.js";
7
+ import S from "./version-history/RestoreButton.vue.js";
8
+ const x = /* @__PURE__ */ a({
10
9
  __name: "RightSlot",
11
10
  setup(h, { expose: r }) {
12
- const { isFeatureEnabled: o } = u(), i = d(), n = l(), t = f(null), s = p(() => o("liquidSyntax"));
11
+ const { isFeatureEnabled: o } = u(), n = d(), i = c(), t = f(null), s = p(() => o("liquidSyntax"));
13
12
  return r({
14
13
  handleSave: (m) => {
15
14
  var e;
16
15
  return (e = t.value) == null ? void 0 : e.handleSave(m);
17
16
  }
18
- }), { __sfc: !0, isFeatureEnabled: o, trans: i, editorStore: n, editorActionsRef: t, isLiquidEnabled: s, InChips: c, AutoSaveToggle: _, EditorActions: S, RestoreButton: g };
17
+ }), { __sfc: !0, isFeatureEnabled: o, trans: n, editorStore: i, editorActionsRef: t, isLiquidEnabled: s, InChips: l, EditorActions: _, RestoreButton: S };
19
18
  }
20
19
  });
21
20
  export {
22
- T as default
21
+ x as default
23
22
  };
@@ -1,29 +1,32 @@
1
1
  import { useActionsApi as V } from "./useActionsApi.js";
2
2
  import { useConfig as x } from "./useConfig.js";
3
3
  import { useSaveStart as y, useSaveComplete as w } from "./useGuidoActions.js";
4
- import { useSyncModuleExtractor as b } from "./useSyncModuleExtractor.js";
5
- import { useStripoApi as q } from "../services/stripoApi.js";
6
- import { useTemplatePreparation as H } from "../utils/templatePreparation.js";
7
- import { useHtmlValidator as L } from "./useHtmlValidator.js";
4
+ import { useSyncModuleExtractor as C } 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";
8
9
  import { useLiquidValidator as P } from "./validators/useLiquidValidator.js";
9
- const U = () => {
10
- const o = y(), s = w(), { validateHtml: r } = L(), { validateLiquidSyntax: n } = P(), { callbacks: a, isFeatureEnabled: l } = x(), { extractSyncModuleData: d } = b(), { setSyncModuleUnsubscriptionPages: u } = q(), { editorSave: c } = V();
11
- return { save: async (m = !1, p = !1) => {
10
+ const h = () => {
11
+ const o = y(), s = w(), { validateHtml: r } = q(), { validateLiquidSyntax: l } = P(), { validateCouponBlockTags: n } = L(), { callbacks: a, isFeatureEnabled: d } = x(), { extractSyncModuleData: u } = C(), { setSyncModuleUnsubscriptionPages: c } = H(), { editorSave: m } = V();
12
+ return { save: async (p = !1) => {
12
13
  var i;
13
14
  o();
14
- const { prepareTemplateDetails: f } = H(), t = await f();
15
- if (l("liquidSyntax")) {
16
- if (!await n(t.compiledHtml))
15
+ const { prepareTemplateDetails: f } = b(), t = await f();
16
+ if (!n(t.compiledHtml))
17
+ return;
18
+ if (d("liquidSyntax")) {
19
+ if (!await l(t.compiledHtml))
17
20
  return;
18
21
  } else if (!await r(t.compiledHtml, t.dynamicContentList, !0))
19
22
  return;
20
23
  if ((i = a.value) != null && i.externalValidation && !await a.value.externalValidation(t))
21
24
  return;
22
- await c();
23
- const { unsubscribePayload: v, stripoModules: S } = d(t.rawHtml);
24
- return await u(v), t.modules = S, m || s({ ...t, silent: p }), t;
25
+ await m();
26
+ const { unsubscribePayload: v, stripoModules: S } = u(t.rawHtml);
27
+ return await c(v), t.modules = S, p || s(t), t;
25
28
  } };
26
29
  };
27
30
  export {
28
- U as useSave
31
+ h as useSave
29
32
  };
@@ -0,0 +1,24 @@
1
+ import { ToasterTypeOptions as c } from "../../enums/toaster.js";
2
+ import { COUPON_PLACEHOLDER_DEFAULT as l, COUPON_PLACEHOLDER_LIQUID as i } from "../../extensions/Blocks/CouponBlock/template.js";
3
+ import { useToaster as m } from "../useToaster.js";
4
+ import { useTranslations as p } from "../useTranslations.js";
5
+ const u = /* @__PURE__ */ new Set([
6
+ l,
7
+ i
8
+ ]), L = () => {
9
+ const { showToaster: t } = m(), r = p();
10
+ return { validateCouponBlockTags: (e) => {
11
+ const n = new DOMParser().parseFromString(e, "text/html");
12
+ return Array.from(n.querySelectorAll(".coupon-block")).find((s) => {
13
+ var o;
14
+ const a = ((o = s.textContent) == null ? void 0 : o.trim()) ?? "";
15
+ return !u.has(a);
16
+ }) ? (t({
17
+ type: c.Alert,
18
+ message: r("newsletter.coupon-tag-modified")
19
+ }), !1) : !0;
20
+ } };
21
+ };
22
+ export {
23
+ L as useCouponBlockValidator
24
+ };
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- .gap-16[data-v-3b53a736],.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-4cbf0abd]{position:relative}.auto-save-toggle__info-box[data-v-4cbf0abd]{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-fffc13d6]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-fffc13d6]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-fffc13d6]{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-29b9af29] .vueperslides__bullets,[data-v-dd1a237a] .vueperslides__bullets{pointer-events:none!important}[data-v-dd1a237a] .vueperslides__parallax-wrapper{height:110px!important}[data-v-d073b1dc] .vueperslides__bullets{pointer-events:none!important}[data-v-d073b1dc] .vueperslides__parallax-wrapper{height:110px!important}
1
+ .gap-16[data-v-3b53a736],.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}.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-25780af6]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-25780af6]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-25780af6]{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-29b9af29] .vueperslides__bullets,[data-v-dd1a237a] .vueperslides__bullets{pointer-events:none!important}[data-v-dd1a237a] .vueperslides__parallax-wrapper{height:110px!important}[data-v-d073b1dc] .vueperslides__bullets{pointer-events:none!important}[data-v-d073b1dc] .vueperslides__parallax-wrapper{height:110px!important}
@@ -178,8 +178,6 @@ export declare const FeaturesSchema: v.ObjectSchema<{
178
178
  readonly modulesDisabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
179
179
  /** Enable Liquid template syntax */
180
180
  readonly liquidSyntax: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
181
- /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
182
- readonly autosave: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
183
181
  }, undefined>;
184
182
  /**
185
183
  * Default block types available in Stripo
@@ -503,8 +501,6 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
503
501
  readonly modulesDisabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
504
502
  /** Enable Liquid template syntax */
505
503
  readonly liquidSyntax: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
506
- /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
507
- readonly autosave: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
508
504
  }, undefined>, {}>;
509
505
  /** Block configuration */
510
506
  readonly blocks: v.OptionalSchema<v.ObjectSchema<{
@@ -11,7 +11,7 @@ declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<__
11
11
  close: () => void;
12
12
  };
13
13
  hasChanges: import("vue").ComputedRef<boolean>;
14
- saveSilent: () => Promise<Omit<SavedTemplateDetails, "metadata" | "silent"> | undefined> | undefined;
14
+ saveSilent: () => Promise<Omit<SavedTemplateDetails, "metadata"> | undefined> | undefined;
15
15
  }, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {
16
16
  "dynamic-content:open": (detail: {
17
17
  text: string;
@@ -1,4 +1,4 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
- handleSave: (isSilent: boolean) => Promise<Omit<import("../../../@types/stripo.js").SavedTemplateDetails, "metadata" | "silent"> | undefined> | undefined;
2
+ handleSave: (isSilent: boolean) => Promise<Omit<import("../../../@types/stripo.js").SavedTemplateDetails, "metadata"> | undefined> | undefined;
3
3
  }, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
4
4
  export default _default;
@@ -1,4 +1,4 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
- handleSave: (isSilent: boolean) => Promise<Omit<import("../../../@types/stripo.js").SavedTemplateDetails, "metadata" | "silent"> | undefined> | undefined;
2
+ handleSave: (isSilent: boolean) => Promise<Omit<import("../../../@types/stripo.js").SavedTemplateDetails, "metadata"> | undefined> | undefined;
3
3
  }, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
4
4
  export default _default;
@@ -1,4 +1,4 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
- handleSave: (isSilent: boolean) => Promise<Omit<import("../../../@types/stripo.js").SavedTemplateDetails, "metadata" | "silent"> | undefined> | undefined;
2
+ handleSave: (isSilent: boolean) => Promise<Omit<import("../../../@types/stripo.js").SavedTemplateDetails, "metadata"> | undefined> | undefined;
3
3
  }, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
4
4
  export default _default;
@@ -62,7 +62,6 @@ export declare const useConfig: () => {
62
62
  unsubscribe: boolean;
63
63
  modulesDisabled: boolean;
64
64
  liquidSyntax: boolean;
65
- autosave: boolean;
66
65
  };
67
66
  blocks: {
68
67
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -160,7 +159,6 @@ export declare const useConfig: () => {
160
159
  unsubscribe: boolean;
161
160
  modulesDisabled: boolean;
162
161
  liquidSyntax: boolean;
163
- autosave: boolean;
164
162
  } | null>;
165
163
  blocks: import("vue").ComputedRef<{
166
164
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1,4 +1,4 @@
1
1
  import type { SavedTemplateDetails } from '@@/Types/stripo';
2
2
  export declare const useSave: () => {
3
- save: (isAsync?: boolean, silent?: boolean) => Promise<Omit<SavedTemplateDetails, "metadata" | "silent"> | undefined>;
3
+ save: (isSilent?: boolean) => Promise<Omit<SavedTemplateDetails, "metadata"> | undefined>;
4
4
  };
@@ -0,0 +1,3 @@
1
+ export declare const useCouponBlockValidator: () => {
2
+ validateCouponBlockTags: (html: string) => boolean;
3
+ };
@@ -67,7 +67,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
67
67
  unsubscribe: boolean;
68
68
  modulesDisabled: boolean;
69
69
  liquidSyntax: boolean;
70
- autosave: boolean;
71
70
  };
72
71
  blocks: {
73
72
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -171,7 +170,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
171
170
  unsubscribe: boolean;
172
171
  modulesDisabled: boolean;
173
172
  liquidSyntax: boolean;
174
- autosave: boolean;
175
173
  };
176
174
  blocks: {
177
175
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -275,7 +273,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
275
273
  unsubscribe: boolean;
276
274
  modulesDisabled: boolean;
277
275
  liquidSyntax: boolean;
278
- autosave: boolean;
279
276
  };
280
277
  blocks: {
281
278
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -379,7 +376,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
379
376
  unsubscribe: boolean;
380
377
  modulesDisabled: boolean;
381
378
  liquidSyntax: boolean;
382
- autosave: boolean;
383
379
  };
384
380
  blocks: {
385
381
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -483,7 +479,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
483
479
  unsubscribe: boolean;
484
480
  modulesDisabled: boolean;
485
481
  liquidSyntax: boolean;
486
- autosave: boolean;
487
482
  };
488
483
  blocks: {
489
484
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -587,7 +582,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
587
582
  unsubscribe: boolean;
588
583
  modulesDisabled: boolean;
589
584
  liquidSyntax: boolean;
590
- autosave: boolean;
591
585
  };
592
586
  blocks: {
593
587
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -691,7 +685,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
691
685
  unsubscribe: boolean;
692
686
  modulesDisabled: boolean;
693
687
  liquidSyntax: boolean;
694
- autosave: boolean;
695
688
  };
696
689
  blocks: {
697
690
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -795,7 +788,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
795
788
  unsubscribe: boolean;
796
789
  modulesDisabled: boolean;
797
790
  liquidSyntax: boolean;
798
- autosave: boolean;
799
791
  };
800
792
  blocks: {
801
793
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -899,7 +891,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
899
891
  unsubscribe: boolean;
900
892
  modulesDisabled: boolean;
901
893
  liquidSyntax: boolean;
902
- autosave: boolean;
903
894
  };
904
895
  blocks: {
905
896
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1003,7 +994,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1003
994
  unsubscribe: boolean;
1004
995
  modulesDisabled: boolean;
1005
996
  liquidSyntax: boolean;
1006
- autosave: boolean;
1007
997
  };
1008
998
  blocks: {
1009
999
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1107,7 +1097,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1107
1097
  unsubscribe: boolean;
1108
1098
  modulesDisabled: boolean;
1109
1099
  liquidSyntax: boolean;
1110
- autosave: boolean;
1111
1100
  };
1112
1101
  blocks: {
1113
1102
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1211,7 +1200,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1211
1200
  unsubscribe: boolean;
1212
1201
  modulesDisabled: boolean;
1213
1202
  liquidSyntax: boolean;
1214
- autosave: boolean;
1215
1203
  };
1216
1204
  blocks: {
1217
1205
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1315,7 +1303,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1315
1303
  unsubscribe: boolean;
1316
1304
  modulesDisabled: boolean;
1317
1305
  liquidSyntax: boolean;
1318
- autosave: boolean;
1319
1306
  };
1320
1307
  blocks: {
1321
1308
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1419,7 +1406,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1419
1406
  unsubscribe: boolean;
1420
1407
  modulesDisabled: boolean;
1421
1408
  liquidSyntax: boolean;
1422
- autosave: boolean;
1423
1409
  };
1424
1410
  blocks: {
1425
1411
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1523,7 +1509,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1523
1509
  unsubscribe: boolean;
1524
1510
  modulesDisabled: boolean;
1525
1511
  liquidSyntax: boolean;
1526
- autosave: boolean;
1527
1512
  };
1528
1513
  blocks: {
1529
1514
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1627,7 +1612,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1627
1612
  unsubscribe: boolean;
1628
1613
  modulesDisabled: boolean;
1629
1614
  liquidSyntax: boolean;
1630
- autosave: boolean;
1631
1615
  };
1632
1616
  blocks: {
1633
1617
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1731,7 +1715,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1731
1715
  unsubscribe: boolean;
1732
1716
  modulesDisabled: boolean;
1733
1717
  liquidSyntax: boolean;
1734
- autosave: boolean;
1735
1718
  };
1736
1719
  blocks: {
1737
1720
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -1835,7 +1818,6 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
1835
1818
  unsubscribe: boolean;
1836
1819
  modulesDisabled: boolean;
1837
1820
  liquidSyntax: boolean;
1838
- autosave: boolean;
1839
1821
  };
1840
1822
  blocks: {
1841
1823
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.2.0-beta.c08c480",
3
+ "version": "3.2.0-beta.c3bc14c",
4
4
  "description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
5
5
  "main": "./dist/guido.umd.cjs",
6
6
  "module": "./dist/library.js",
@@ -1,17 +0,0 @@
1
- import n from "./AutoSaveController.vue2.js";
2
- import t from "../../_virtual/_plugin-vue2_normalizer.js";
3
- var o = function() {
4
- var r = this, e = r._self._c;
5
- return r._self._setupProxy, e("div", { staticClass: "d-n" });
6
- }, s = [], _ = /* @__PURE__ */ t(
7
- n,
8
- o,
9
- s,
10
- !1,
11
- null,
12
- null
13
- );
14
- const f = _.exports;
15
- export {
16
- f as default
17
- };
@@ -1,13 +0,0 @@
1
- import { defineComponent as t } from "vue";
2
- import { useAutoSave as r } from "../../composables/useAutoSave.js";
3
- import { useSave as s } from "../../composables/useSave.js";
4
- const f = /* @__PURE__ */ t({
5
- __name: "AutoSaveController",
6
- setup(a) {
7
- const { save: e } = s(), o = () => e(!1, !0);
8
- return r(o), { __sfc: !0, save: e, backgroundSave: o };
9
- }
10
- });
11
- export {
12
- f as default
13
- };
@@ -1,22 +0,0 @@
1
- import o from "./AutoSaveToggle.vue2.js";
2
- /* empty css */
3
- import i from "../../../_virtual/_plugin-vue2_normalizer.js";
4
- var n = function() {
5
- var e = this, a = e._self._c, t = e._self._setupProxy;
6
- return t.isFeatureEnabled("autosave") ? a("div", { staticClass: "d-f a-i-c mr-3 auto-save-toggle", on: { mouseenter: function(s) {
7
- t.isHovered = !0;
8
- }, mouseleave: function(s) {
9
- t.isHovered = !1;
10
- } } }, [a(t.InToggle, { attrs: { id: "guido__autosave-toggle", name: "guido-autosave-toggle", checked: t.autosaveStore.isOn, disable: t.editorStore.loadingStatus }, on: { click: t.toggle } }), a("span", { staticClass: "ml-2 auto-save-toggle__label t-c-55" }, [e._v(" " + e._s(t.trans("email-editor.auto-save")) + " ")]), t.autosaveStore.status === "saving" ? a("span", { staticClass: "ml-2 d-f a-i-c f-s-1" }, [a(t.InLoading, { attrs: { "color-class": "i-c-53", size: "16" } }), a("span", { staticClass: "ml-1 t-c-53" }, [e._v(" " + e._s(t.trans("newsletter.saving")) + " ")])], 1) : t.lastSavedLabel ? a("span", { staticClass: "ml-2 f-s-1 t-c-53" }, [e._v(" " + e._s(t.lastSavedLabel) + " ")]) : e._e(), t.isHovered ? a(t.InInfoBox, { staticClass: "auto-save-toggle__info-box", attrs: { id: "guido__autosave-info-box", size: "small", variant: "information", "description-text": t.trans("email-editor.auto-save-description"), "title-text": t.trans("email-editor.auto-save-title") } }) : e._e()], 1) : e._e();
11
- }, l = [], r = /* @__PURE__ */ i(
12
- o,
13
- n,
14
- l,
15
- !1,
16
- null,
17
- "4cbf0abd"
18
- );
19
- const d = r.exports;
20
- export {
21
- d as default
22
- };
@@ -1,19 +0,0 @@
1
- import { defineComponent as m, ref as i, computed as f } from "vue";
2
- import { useConfig as u } from "../../../composables/useConfig.js";
3
- import { useTranslations as l } from "../../../composables/useTranslations.js";
4
- import { useAutosaveStore as p } from "../../../stores/autosave.js";
5
- import { useEditorStore as c } from "../../../stores/editor.js";
6
- import { formatLocalTime as d } from "../../../utils/timeUtil.js";
7
- import { InToggle as g, InLoading as v, InInfoBox as S } from "@useinsider/design-system-vue";
8
- const B = /* @__PURE__ */ m({
9
- __name: "AutoSaveToggle",
10
- setup(_) {
11
- const { isFeatureEnabled: t } = u(), e = c(), o = p(), r = l(), s = i(!1), n = f(() => o.status !== "saved" || !o.lastSavedAt ? "" : d(o.lastSavedAt));
12
- return { __sfc: !0, isFeatureEnabled: t, editorStore: e, autosaveStore: o, trans: r, isHovered: s, lastSavedLabel: n, toggle: (a) => {
13
- o.isOn = a;
14
- }, InInfoBox: S, InLoading: v, InToggle: g };
15
- }
16
- });
17
- export {
18
- B as default
19
- };
@@ -1,72 +0,0 @@
1
- import { useConfig as m } from "./useConfig.js";
2
- import { useAutosaveStore as p } from "../stores/autosave.js";
3
- import { useEditorStore as S } from "../stores/editor.js";
4
- import { computed as f, watch as E, onUnmounted as y } from "vue";
5
- const A = 18e4, c = 6e4, k = (l) => {
6
- const { isFeatureEnabled: b } = m(), s = S(), t = p();
7
- let a = null, u = 0;
8
- const n = f(
9
- () => b("autosave") && t.isOn
10
- ), g = () => s.hasChanges && !s.isSaveButtonDisabled && !s.isCodeEditorOpen, h = () => ({
11
- hasChanges: s.hasChanges,
12
- isSaveButtonDisabled: s.isSaveButtonDisabled,
13
- isCodeEditorOpen: s.isCodeEditorOpen
14
- }), r = async (e) => {
15
- if (!n.value) {
16
- console.debug("guido:autosave:skipped", { trigger: e, reason: "not-active" });
17
- return;
18
- }
19
- if (!g()) {
20
- console.debug("guido:autosave:skipped", { trigger: e, reason: "gates-blocked", gates: h() });
21
- return;
22
- }
23
- if (t.status === "saving") {
24
- console.debug("guido:autosave:skipped", { trigger: e, reason: "already-saving" });
25
- return;
26
- }
27
- console.debug("guido:autosave:save-start", { trigger: e }), t.status = "saving";
28
- try {
29
- if (await l() === void 0) {
30
- console.debug("guido:autosave:blocked", { trigger: e, reason: "save-returned-undefined" }), t.status = "error";
31
- return;
32
- }
33
- s.hasChanges = !1, t.status = "saved", t.lastSavedAt = /* @__PURE__ */ new Date(), console.debug("guido:autosave:save-complete", { trigger: e, at: t.lastSavedAt });
34
- } catch (o) {
35
- console.debug("guido:autosave:error", { trigger: e, error: o }), t.status = "error";
36
- }
37
- }, i = () => {
38
- const { visibilityState: e } = document;
39
- if (console.debug("guido:autosave:visibility-change", {
40
- visibilityState: e,
41
- isActive: n.value
42
- }), e !== "hidden")
43
- return;
44
- const o = Date.now() - u;
45
- if (o < c) {
46
- console.debug("guido:autosave:visibility-debounced", {
47
- sinceLastMs: o,
48
- debounceMs: c
49
- });
50
- return;
51
- }
52
- u = Date.now(), r("visibility");
53
- }, d = () => {
54
- a && (clearInterval(a), a = null);
55
- }, v = () => {
56
- document.removeEventListener("visibilitychange", i), window.removeEventListener("pagehide", i);
57
- };
58
- E(
59
- n,
60
- (e) => {
61
- console.debug("guido:autosave:active-changed", { active: e }), e ? (d(), a = setInterval(() => {
62
- console.debug("guido:autosave:interval-tick"), r("interval");
63
- }, A), document.addEventListener("visibilitychange", i), window.addEventListener("pagehide", i)) : (d(), v(), t.status = "idle");
64
- },
65
- { immediate: !0 }
66
- ), y(() => {
67
- d(), v(), t.$reset();
68
- });
69
- };
70
- export {
71
- k as useAutoSave
72
- };
@@ -1,2 +0,0 @@
1
- declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
2
- export default _default;
@@ -1,2 +0,0 @@
1
- declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
2
- export default _default;
@@ -1,3 +0,0 @@
1
- type SaveSilent = () => Promise<unknown>;
2
- export declare const useAutoSave: (saveSilent: SaveSilent) => void;
3
- export {};
@@ -1,6 +0,0 @@
1
- export type AutosaveStatus = 'idle' | 'saving' | 'saved' | 'error';
2
- export declare const useAutosaveStore: import("pinia").StoreDefinition<"guidoAutosave", {
3
- isOn: boolean;
4
- lastSavedAt: Date | null;
5
- status: AutosaveStatus;
6
- }, {}, {}>;
@@ -1,8 +0,0 @@
1
- /**
2
- * Formats a Date as local time in 24-hour format.
3
- * Pass `useTimezone = true` to append the UTC offset and city name — useful when the
4
- * timestamp must clearly communicate the client's timezone.
5
- * @example formatLocalTime(date) -> 12:20:02
6
- * @example formatLocalTime(date, true) -> 12:20:02 (UTC+3 Istanbul)
7
- */
8
- export declare const formatLocalTime: (date: Date, useTimezone?: boolean) => string;
@@ -1,11 +0,0 @@
1
- import { defineStore as t } from "pinia";
2
- const s = t("guidoAutosave", {
3
- state: () => ({
4
- isOn: !1,
5
- lastSavedAt: null,
6
- status: "idle"
7
- })
8
- });
9
- export {
10
- s as useAutosaveStore
11
- };
@@ -1,19 +0,0 @@
1
- const r = (t) => {
2
- const e = -t.getTimezoneOffset(), o = e >= 0 ? "+" : "-", n = Math.abs(e), s = Math.floor(n / 60), i = n % 60;
3
- return i === 0 ? `UTC${o}${s}` : `UTC${o}${s}:${String(i).padStart(2, "0")}`;
4
- }, a = () => {
5
- var e;
6
- const { timeZone: t } = new Intl.DateTimeFormat().resolvedOptions();
7
- return ((e = t.split("/").pop()) == null ? void 0 : e.replace(/_/g, " ")) ?? t;
8
- }, c = (t, e = !1) => {
9
- const o = t.toLocaleTimeString([], {
10
- hour: "2-digit",
11
- hour12: !1,
12
- minute: "2-digit",
13
- second: "2-digit"
14
- });
15
- return e ? `${o} (${r(t)} ${a()})` : o;
16
- };
17
- export {
18
- c as formatLocalTime
19
- };