@useinsider/guido 3.18.2 → 3.19.0-beta.5355c3f

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 (33) hide show
  1. package/README.md +20 -0
  2. package/dist/components/Guido.vue.js +3 -3
  3. package/dist/components/Guido.vue2.js +67 -61
  4. package/dist/components/organisms/save-as-template/SaveAsTemplateDrawer.vue2.js +34 -34
  5. package/dist/composables/useActionsApi.js +24 -20
  6. package/dist/composables/useCortexBlueprintBridge.js +115 -54
  7. package/dist/composables/useEmailTemplateApplier.js +93 -50
  8. package/dist/composables/useGuidoStateBridge.js +29 -24
  9. package/dist/composables/useHttp.js +24 -22
  10. package/dist/composables/useStripo.js +7 -7
  11. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +4 -4
  12. package/dist/extensions/Blocks/Recommendation/recommendation.css.js +6 -3
  13. package/dist/guido.css +1 -1
  14. package/dist/library.js +15 -13
  15. package/dist/package.json.js +1 -1
  16. package/dist/public/editorState.js +4 -0
  17. package/dist/services/templateLibraryApi.js +17 -14
  18. package/dist/src/composables/useCortexBlueprintBridge.d.ts +4 -3
  19. package/dist/src/composables/useEmailTemplateApplier.d.ts +22 -2
  20. package/dist/src/composables/useGuidoStateBridge.d.ts +11 -7
  21. package/dist/src/library.d.ts +2 -0
  22. package/dist/src/public/editorState.d.ts +14 -0
  23. package/dist/src/public/trackingIds.d.ts +6 -2
  24. package/dist/src/stores/editor.d.ts +25 -0
  25. package/dist/src/stores/guido-email-editor.d.ts +49 -27
  26. package/dist/src/utils/genericUtil.d.ts +6 -0
  27. package/dist/src/utils/liquidDynamicContent.d.ts +20 -0
  28. package/dist/stores/editor.js +4 -0
  29. package/dist/stores/guido-email-editor.js +3 -5
  30. package/dist/utils/genericUtil.js +63 -54
  31. package/dist/utils/liquidDynamicContent.js +15 -0
  32. package/dist/utils/templatePreparation.js +37 -36
  33. package/package.json +10 -6
@@ -1,69 +1,78 @@
1
- const o = (t) => {
2
- const a = t.value.match(/\{\{([^}]+)\}\}/)[1].split("|").map((l) => l.trim()), [s] = a, r = {
1
+ import { formatToLiquidFilter as b, quoteArgument as y, liquidFilterToFormat as h } from "./liquidDynamicContent.js";
2
+ const g = (t) => {
3
+ if (!t.includes("="))
4
+ return null;
5
+ const [r, e] = t.split("=");
6
+ return { key: r.trim(), value: e.trim() };
7
+ }, c = "default:", f = (t) => {
8
+ if (!t.startsWith(c))
9
+ return t;
10
+ const r = t.slice(c.length).trim(), e = (l) => r.length >= 2 && r.startsWith(l) && r.endsWith(l);
11
+ return e('"') || e("'") ? r.slice(1, -1) : r;
12
+ }, k = (t) => {
13
+ const e = t.value.match(/\{\{([^}]+)\}\}/)[1].split("|").map((a) => a.trim()), [l] = e, s = {
3
14
  text: t.label,
4
- value: s || ""
15
+ value: l || ""
5
16
  };
6
- if (a.length >= 2) {
7
- const [, l, e] = a;
8
- if (l.startsWith("default:")) {
9
- let n = l.slice(8).trim();
10
- n.startsWith('"') && n.endsWith('"') && (n = n.slice(1, -1)), r.fallback = n;
11
- } else {
12
- const n = l.includes("=") ? { key: l.split("=")[0].trim(), value: l.split("=")[1].trim() } : null;
13
- n ? r.format = n : e || (r.fallback = l), e && (r.fallback = e);
17
+ if (e.length >= 2) {
18
+ const [, a, n] = e;
19
+ if (a.startsWith(c))
20
+ s.fallback = f(a);
21
+ else {
22
+ const o = h(a) ?? g(a);
23
+ o ? s.format = o : n || (s.fallback = a), n && (s.fallback = f(n));
14
24
  }
15
25
  }
16
- return r;
17
- }, f = (t, c = !1) => t.map((a) => {
18
- if (a.format)
19
- return {
20
- label: `${a.text} | ${a.format.key}=${a.format.value}`,
21
- value: `{{${a.value}|${a.format.key}=${a.format.value}}}`
22
- };
23
- if (c) {
24
- if (!a.fallback)
25
- return {
26
- label: a.text,
27
- value: `{{ ${a.value} }}`
28
- };
29
- const r = !Number.isNaN(Number(a.fallback)) && a.fallback.trim() !== "" ? a.fallback : `"${a.fallback}"`;
30
- return {
31
- label: `${a.text} | ${a.fallback}`,
32
- value: `{{ ${a.value} | default: ${r} }}`
33
- };
34
- }
26
+ return s;
27
+ }, p = (t) => {
28
+ const e = !Number.isNaN(Number(t)) && t.trim() !== "" ? t : y(t);
29
+ return e === null ? null : `${c} ${e}`;
30
+ }, v = (t) => {
31
+ const r = t.format ? b(t.format) : null, e = t.fallback ? p(t.fallback) : null, l = [t.value, r, e].filter(Boolean);
35
32
  return {
36
- label: a.fallback ? `${a.text} | ${a.fallback}` : a.text,
37
- value: a.fallback ? `{{${a.value}|${a.fallback}}}` : `{{${a.value}}}`
33
+ label: [t.text, r, e && t.fallback].filter(Boolean).join(" | "),
34
+ value: `{{ ${l.join(" | ")} }}`
38
35
  };
39
- }), b = (t) => {
40
- const c = [], a = /* @__PURE__ */ new Set(), s = (l) => {
41
- Array.isArray(l) && l.forEach((e) => {
42
- const n = [...e.children ?? [], ...e.select_items ?? []];
43
- if (n.length > 0) {
44
- s(n);
36
+ }, i = (t, r = !1) => t.map((e) => r ? v(e) : e.format ? {
37
+ label: `${e.text} | ${e.format.key}=${e.format.value}`,
38
+ value: `{{${e.value}|${e.format.key}=${e.format.value}}}`
39
+ } : {
40
+ label: e.fallback ? `${e.text} | ${e.fallback}` : e.text,
41
+ value: e.fallback ? `{{${e.value}|${e.fallback}}}` : `{{${e.value}}}`
42
+ }), $ = (t) => {
43
+ const r = [], e = /* @__PURE__ */ new Set(), l = (a) => {
44
+ Array.isArray(a) && a.forEach((n) => {
45
+ const o = [...n.children ?? [], ...n.select_items ?? []];
46
+ if (o.length > 0) {
47
+ l(o);
45
48
  return;
46
49
  }
47
- const u = e.text || e.tag_text;
48
- u && e.value && !a.has(e.value) && (a.add(e.value), c.push({ text: u, value: e.value }));
50
+ const u = n.text || n.tag_text;
51
+ u && n.value && !e.has(n.value) && (e.add(n.value), r.push({ text: u, value: n.value }));
49
52
  });
50
- }, [r] = Object.values(t ?? {});
51
- return s(r), c;
52
- }, i = (t, c, a = !1) => {
53
- const s = new Set(t.map((l) => l.value)), r = c.filter((l) => s.has(l.value) ? !1 : (s.add(l.value), !0));
53
+ }, [s] = Object.values(t ?? {});
54
+ return l(s), r;
55
+ }, d = (t, r, e = !1) => {
56
+ const l = new Set(t.map((a) => a.value)), s = r.filter((a) => l.has(a.value) ? !1 : (l.add(a.value), !0));
54
57
  return [
55
- ...f(t, a),
56
- ...f(r, a)
58
+ ...i(t, e),
59
+ ...i(s, e)
57
60
  ];
58
- }, v = () => {
61
+ }, F = () => {
59
62
  var t;
60
63
  return ((t = document.head.querySelector('meta[name="csrf-token"]')) == null ? void 0 : t.getAttribute("content")) ?? "";
61
- }, k = (t) => typeof t == "string" ? t : typeof t == "number" ? String(t) : "";
64
+ }, T = (t) => typeof t == "string" ? t : typeof t == "number" ? String(t) : "", x = (t) => {
65
+ if (t === null || typeof t != "object" || Array.isArray(t))
66
+ return !1;
67
+ const r = Object.getPrototypeOf(t);
68
+ return r === Object.prototype || r === null;
69
+ };
62
70
  export {
63
- k as asText,
64
- i as buildMergeTagEntries,
65
- f as dynamicContentToMergeTags,
66
- b as flattenDynamicContentList,
67
- v as getCsrfToken,
68
- o as mergeTagToDynamicContent
71
+ T as asText,
72
+ d as buildMergeTagEntries,
73
+ i as dynamicContentToMergeTags,
74
+ $ as flattenDynamicContentList,
75
+ F as getCsrfToken,
76
+ x as isPlainObject,
77
+ k as mergeTagToDynamicContent
69
78
  };
@@ -0,0 +1,15 @@
1
+ const E = "time-format", r = "date", u = new RegExp(`^${r}\\s*:\\s*(?:"([^"]*)"|'([^']*)')$`), s = /%[-_0^#]?\d*[a-zA-Z%]/, c = new RegExp(s, "g"), l = /\b(?:Y{2,4}|M{2,4}|D{1,4}|d{3,4}|H{2}|h{2}|m{2}|s{2}|S{1,3}|A|a)\b/, T = (t) => t.includes('"') ? t.includes("'") ? null : `'${t}'` : `"${t}"`, i = (t) => s.test(t) && !l.test(t.replace(c, "")), R = (t) => {
2
+ if (t.key !== E || !i(t.value ?? ""))
3
+ return null;
4
+ const n = T(t.value);
5
+ return n === null ? null : `${r}: ${n}`;
6
+ }, _ = (t) => {
7
+ const [, n, o] = t.match(u) ?? [], e = n ?? o;
8
+ return e ? { key: E, value: e } : null;
9
+ };
10
+ export {
11
+ E as TIME_FORMAT_KEY,
12
+ R as formatToLiquidFilter,
13
+ _ as liquidFilterToFormat,
14
+ T as quoteArgument
15
+ };
@@ -1,30 +1,31 @@
1
1
  import { useActionsApi as k } from "../composables/useActionsApi.js";
2
2
  import { useConfig as U } from "../composables/useConfig.js";
3
3
  import { useHtmlCompiler as x } from "../composables/useHtmlCompiler.js";
4
- import { DEFAULT_CURRENCY as m, DEFAULT_NODE_CONFIG as a } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
5
- import { useRecommendationExtensionStore as T } from "../extensions/Blocks/Recommendation/store/recommendation.js";
4
+ import { DEFAULT_CURRENCY as m, DEFAULT_NODE_CONFIG as n } from "../extensions/Blocks/Recommendation/constants/defaultConfig.js";
5
+ import { useRecommendationExtensionStore as A } from "../extensions/Blocks/Recommendation/store/recommendation.js";
6
6
  import { mapLegacyStrategy as L } from "../extensions/Blocks/Recommendation/utils/legacyStrategyMap.js";
7
- import { DATA_ATTRIBUTES as C } from "../extensions/Blocks/Unsubscribe/utils/constants.js";
7
+ import { DATA_ATTRIBUTES as T } from "../extensions/Blocks/Unsubscribe/utils/constants.js";
8
8
  import { parsePageList as R } from "../extensions/Blocks/Unsubscribe/utils/utils.js";
9
9
  import { useDynamicContentStore as N } from "../stores/dynamic-content.js";
10
10
  import { useEditorStore as z } from "../stores/editor.js";
11
- import { useUnsubscribeStore as _ } from "../stores/unsubscribe.js";
11
+ import { useUnsubscribeStore as O } from "../stores/unsubscribe.js";
12
+ import { isPlainObject as _ } from "./genericUtil.js";
12
13
  import { assignTrackingIds as v } from "./linkTrackingIds.js";
13
- function O(l) {
14
- const c = new DOMParser().parseFromString(l, "text/html").querySelectorAll(`[${C.PAGE_LIST}]`), t = [];
15
- return c.forEach((i) => {
16
- const o = i.getAttribute(C.PAGE_LIST);
14
+ function M(l) {
15
+ const i = new DOMParser().parseFromString(l, "text/html").querySelectorAll(`[${T.PAGE_LIST}]`), t = [];
16
+ return i.forEach((c) => {
17
+ const o = c.getAttribute(T.PAGE_LIST);
17
18
  o && t.push(...R(o));
18
19
  }), [...new Set(t)];
19
20
  }
20
- async function M(l) {
21
- const n = new DOMParser().parseFromString(l, "text/html").querySelectorAll(".recommendation-block-v2");
22
- if (n.length === 0)
21
+ async function q(l) {
22
+ const a = new DOMParser().parseFromString(l, "text/html").querySelectorAll(".recommendation-block-v2");
23
+ if (a.length === 0)
23
24
  return;
24
- const c = T();
25
- n.forEach((t) => {
25
+ const i = A();
26
+ a.forEach((t) => {
26
27
  var r, d, g, f, s, y;
27
- const i = t.getAttribute("recommendation-id"), o = i ? Number(i) : NaN;
28
+ const c = t.getAttribute("recommendation-id"), o = c ? Number(c) : NaN;
28
29
  if (!Number.isFinite(o))
29
30
  return;
30
31
  const p = t.getAttribute("esd-ext-config");
@@ -36,21 +37,21 @@ async function M(l) {
36
37
  } catch {
37
38
  return;
38
39
  }
39
- if (!e || typeof e != "object" || Array.isArray(e))
40
+ if (!_(e))
40
41
  return;
41
42
  const b = {
42
43
  // Normalize legacy strategy keys (e.g. `mostViewed` → `mostPopular`) so
43
44
  // already-saved blocks that never re-run the migrator don't emit a
44
45
  // strategy-less campaign URL. `||` also catches '' / undefined (SD-144882).
45
- strategy: L(e.strategy) || a.strategy,
46
- strategyId: e.strategyId ?? a.strategyId,
47
- language: e.language ?? a.language,
48
- size: e.size ?? a.size,
46
+ strategy: L(e.strategy) || n.strategy,
47
+ strategyId: e.strategyId ?? n.strategyId,
48
+ language: e.language ?? n.language,
49
+ size: e.size ?? n.size,
49
50
  // Spread the default arrays so each block gets a fresh reference
50
51
  // instead of sharing the singleton in DEFAULT_NODE_CONFIG.
51
- productIds: e.productIds ?? [...a.productIds],
52
- filters: e.filters ?? [...a.filters],
53
- shuffleProducts: e.shuffleProducts ?? a.shuffleProducts,
52
+ productIds: e.productIds ?? [...n.productIds],
53
+ filters: e.filters ?? [...n.filters],
54
+ shuffleProducts: e.shuffleProducts ?? n.shuffleProducts,
54
55
  currencyCode: ((r = e.currency) == null ? void 0 : r.code) ?? m.code,
55
56
  currencySymbol: ((d = e.currency) == null ? void 0 : d.symbol) ?? m.symbol,
56
57
  currencyAlignment: ((g = e.currency) == null ? void 0 : g.alignment) ?? m.alignment,
@@ -58,10 +59,10 @@ async function M(l) {
58
59
  currencyDecimalSeparator: ((s = e.currency) == null ? void 0 : s.decimalSeparator) ?? m.decimalSeparator,
59
60
  currencyThousandSeparator: ((y = e.currency) == null ? void 0 : y.thousandSeparator) ?? m.thousandSeparator
60
61
  };
61
- c.seedBlockUrlConfig(o, b);
62
+ i.seedBlockUrlConfig(o, b);
62
63
  });
63
64
  try {
64
- await c.fetchRecommendationCreateData();
65
+ await i.fetchRecommendationCreateData();
65
66
  } catch (t) {
66
67
  console.warn(
67
68
  "Recommendation reference data pre-load failed; validator will skip the availability check.",
@@ -69,24 +70,24 @@ async function M(l) {
69
70
  );
70
71
  }
71
72
  }
72
- const Z = () => {
73
- const l = N(), u = z(), n = _(), { getCompiledEmail: c, getTemplateData: t, updateHtmlAndCss: i } = k(), { compileHtml: o, compileAmpHtml: p } = x(), { isFeatureEnabled: e } = U();
73
+ const te = () => {
74
+ const l = N(), u = z(), a = O(), { getCompiledEmail: i, getTemplateData: t, updateHtmlAndCss: c } = k(), { compileHtml: o, compileAmpHtml: p } = x(), { isFeatureEnabled: e } = U();
74
75
  return {
75
76
  prepareTemplateDetails: async () => {
76
77
  let { html: r, css: d, syncModulesIds: g = [] } = await t();
77
78
  if (e("linkTrackingIds"))
78
79
  try {
79
80
  const { html: h, changed: F, nextSeq: H } = v(r, u.trackIdSessionFloor);
80
- u.trackIdSessionFloor = H, F && (r = h, await i(h, d));
81
+ u.trackIdSessionFloor = H, F && (r = h, await c(h, d));
81
82
  } catch (h) {
82
83
  console.error("Tracking-id step failed, saving anyway:", h);
83
84
  }
84
- const { html: f, ampHtml: s = "", ampErrors: y = [] } = await c({
85
+ const { html: f, ampHtml: s = "", ampErrors: y = [] } = await i({
85
86
  minimize: !0,
86
87
  resetDataSavedFlag: !1
87
88
  });
88
- n.selectedUnsubscribePages.length && await n.fetchTemplates(), await M(r);
89
- const { compiledHtml: I, stats: S, appliedRules: w } = o(f), D = s && p(s).compiledHtml, E = l.getSelectedDynamicContentList, P = T(), A = O(r);
89
+ a.selectedUnsubscribePages.length && await a.fetchTemplates(), await q(r);
90
+ const { compiledHtml: I, stats: S, appliedRules: w } = o(f), D = s && p(s).compiledHtml, P = l.getSelectedDynamicContentList, E = A(), C = M(r);
90
91
  return console.debug("HTML Compilation Stats:", {
91
92
  originalSize: S.originalSize,
92
93
  compiledSize: S.compiledSize,
@@ -94,7 +95,7 @@ const Z = () => {
94
95
  appliedRules: w,
95
96
  executionTime: `${S.executionTime.toFixed(2)}ms`
96
97
  }), {
97
- dynamicContentList: E,
98
+ dynamicContentList: P,
98
99
  compiledHtml: I,
99
100
  rawHtml: r,
100
101
  css: d,
@@ -102,18 +103,18 @@ const Z = () => {
102
103
  ampErrors: y,
103
104
  modules: g.map(Number),
104
105
  recommendation: {
105
- campaignUrls: P.recommendationCampaignUrls,
106
+ campaignUrls: E.recommendationCampaignUrls,
106
107
  configs: {}
107
108
  },
108
109
  unsubscribe: {
109
- status: A.length > 0,
110
- config: A
110
+ status: C.length > 0,
111
+ config: C
111
112
  }
112
113
  };
113
114
  }
114
115
  };
115
116
  };
116
117
  export {
117
- O as getHtmlReferencedUnsubscribePages,
118
- Z as useTemplatePreparation
118
+ M as getHtmlReferencedUnsubscribePages,
119
+ te as useTemplatePreparation
119
120
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.18.2",
3
+ "version": "3.19.0-beta.5355c3f",
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",
@@ -18,6 +18,10 @@
18
18
  "types": "./dist/src/public/trackingIds.d.ts",
19
19
  "import": "./dist/public/trackingIds.js"
20
20
  },
21
+ "./editor-state": {
22
+ "types": "./dist/src/public/editorState.d.ts",
23
+ "import": "./dist/public/editorState.js"
24
+ },
21
25
  "./style": "./dist/guido.css"
22
26
  },
23
27
  "scripts": {
@@ -77,7 +81,7 @@
77
81
  "@typescript-eslint/parser": "7.18.0",
78
82
  "@useinsider/eslint-config": "1.5.3",
79
83
  "@vitejs/plugin-vue2": "2.3.1",
80
- "@vitest/coverage-v8": "2.1.9",
84
+ "@vitest/coverage-v8": "4.1.11",
81
85
  "eslint": "8.57.1",
82
86
  "eslint-config-airbnb-base": "15.0.0",
83
87
  "eslint-config-airbnb-typescript": "18.0.0",
@@ -90,17 +94,17 @@
90
94
  "happy-dom": "15.11.7",
91
95
  "husky": "9.1.7",
92
96
  "msw": "2.10.3",
93
- "nyc": "17.1.0",
97
+ "nyc": "18.0.0",
94
98
  "sass": "1.69.7",
95
99
  "typescript": "5.5.4",
96
100
  "typescript-eslint": "8.26.0",
97
101
  "vite-plugin-dts": "4.5.4",
98
102
  "vite-plugin-istanbul": "7.0.0",
99
- "vitest": "2.1.9",
103
+ "vitest": "4.1.11",
100
104
  "vue-tsc": "2.2.10"
101
105
  },
102
106
  "overrides": {
103
- "axios": "1.8.2",
107
+ "axios": "1.20.0",
104
108
  "flatted": "3.4.2",
105
109
  "micromatch": "4.0.8",
106
110
  "path-to-regexp": "6.3.0"
@@ -118,7 +122,7 @@
118
122
  },
119
123
  "guido": {
120
124
  "stripo": {
121
- "version": "2.76.0"
125
+ "version": "2.77.0"
122
126
  }
123
127
  }
124
128
  }