@useinsider/guido 3.18.1-beta.d56e3d5 → 3.18.1-beta.dea994d

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.
@@ -1,39 +1,37 @@
1
- import { useEditorStore as d } from "../stores/editor.js";
2
- import { usePreviewStore as p } from "../stores/preview.js";
3
- import { fixMobileNonResponsiveLayout as c } from "../utils/fixMobileNonResponsiveLayout.js";
4
- import { useActionsApi as u } from "./useActionsApi.js";
5
- import { useCodeEditorApi as v } from "./useCodeEditorApi.js";
6
- import { useHtmlCompiler as w } from "./useHtmlCompiler.js";
1
+ import { useEditorStore as p } from "../stores/editor.js";
2
+ import { usePreviewStore as c } from "../stores/preview.js";
3
+ import { appendMobileHiddenColumnCss as u } from "../utils/appendMobileHiddenColumnCss.js";
4
+ import { useActionsApi as v } from "./useActionsApi.js";
5
+ import { useCodeEditorApi as w } from "./useCodeEditorApi.js";
6
+ import { useHtmlCompiler as P } from "./useHtmlCompiler.js";
7
7
  import { useRecommendationPreview as f } from "./useRecommendationPreview.js";
8
- const y = () => {
9
- const o = d(), e = p(), { closeCodeEditor: a } = v(), { getPreviewData: m, getCompiledEmail: s } = u(), { compileHtml: l } = w(), { substituteRecommendationPreview: i } = f(), r = () => {
10
- o.isPreviewModeOpen = !1, e.$reset();
8
+ const A = () => {
9
+ const t = p(), e = c(), { closeCodeEditor: a } = w(), { getPreviewData: m, getCompiledEmail: s } = v(), { compileHtml: l } = P(), { substituteRecommendationPreview: r } = f(), i = () => {
10
+ t.isPreviewModeOpen = !1, e.$reset();
11
11
  };
12
12
  return {
13
- closePreviewMode: r,
13
+ closePreviewMode: i,
14
14
  openPreviewMode: () => {
15
- o.isCodeEditorOpen && a(), o.isPreviewModeOpen = !0;
15
+ t.isCodeEditorOpen && a(), t.isPreviewModeOpen = !0;
16
16
  },
17
17
  loadPreviewData: async () => {
18
- if (!(o.loadingStatus || e.isLoaded)) {
19
- o.loadingStatus = !0;
18
+ if (!(t.loadingStatus || e.isLoaded)) {
19
+ t.loadingStatus = !0;
20
20
  try {
21
- const [t, n] = await Promise.all([
21
+ const [o, d] = await Promise.all([
22
22
  m(),
23
23
  s({ minimize: !0, resetDataSavedFlag: !1 })
24
- ]);
25
- e.templateHtml = c(
26
- i(t.html || "")
27
- ), e.ampHtml = i(t.ampHtml || ""), e.ampErrors = t.ampErrors || [], e.setEmailFormat(t.ampHtml ? "AMP" : "html"), e.emailSizeKB = l(n.html).estimatedSizeKB, e.isLoaded = !0;
28
- } catch (t) {
29
- console.error("Failed to load preview data:", t), r();
24
+ ]), n = r(o.html || "");
25
+ e.templateHtml = u(n), e.ampHtml = r(o.ampHtml || ""), e.ampErrors = o.ampErrors || [], e.setEmailFormat(o.ampHtml ? "AMP" : "html"), e.emailSizeKB = l(d.html).estimatedSizeKB, e.isLoaded = !0;
26
+ } catch (o) {
27
+ console.error("Failed to load preview data:", o), i();
30
28
  } finally {
31
- o.loadingStatus = !1;
29
+ t.loadingStatus = !1;
32
30
  }
33
31
  }
34
32
  }
35
33
  };
36
34
  };
37
35
  export {
38
- y as usePreviewMode
36
+ A as usePreviewMode
39
37
  };
@@ -1,6 +1,6 @@
1
- import { fixMobileNonResponsiveLayout as c } from "../../utils/fixMobileNonResponsiveLayout.js";
1
+ import { appendMobileHiddenColumnCss as c } from "../../utils/appendMobileHiddenColumnCss.js";
2
2
  import { stripFontTags as l } from "../../utils/stripFontTags.js";
3
- const f = [
3
+ const g = [
4
4
  {
5
5
  id: "fix-url-encoding-start",
6
6
  description: "Replace {%22 with %7B%22 to fix URL encoding",
@@ -55,13 +55,6 @@ const f = [
55
55
  replaceAll: !0,
56
56
  priority: 14
57
57
  },
58
- {
59
- id: "fix-mobile-non-responsive-layout",
60
- description: "SD-151345: drop mobile-hidden columns and their gaps from non-responsive structures, let long words break.",
61
- type: "custom",
62
- processor: (e) => c(e),
63
- priority: 15
64
- },
65
58
  {
66
59
  id: "strip-font-tags",
67
60
  description: 'Unwrap browser-translate-injected <font dir="auto"> tags, keeping inner content; other <font> elements are left intact.',
@@ -137,6 +130,13 @@ const f = [
137
130
  },
138
131
  priority: 30
139
132
  },
133
+ {
134
+ id: "append-mobile-hidden-column-css",
135
+ description: "Inject media-query CSS that hides mobile-hidden columns and their gap cells",
136
+ type: "custom",
137
+ processor: (e) => c(e),
138
+ priority: 31
139
+ },
140
140
  {
141
141
  id: "replace-old-image-domain",
142
142
  description: "Replacing old image domains",
@@ -208,5 +208,5 @@ const f = [
208
208
  }
209
209
  ];
210
210
  export {
211
- f as defaultHtmlCompilerRules
211
+ g as defaultHtmlCompilerRules
212
212
  };
@@ -0,0 +1,2 @@
1
+ /** Exported for the preview drawer, which takes its HTML from the backend and never runs the compiler. */
2
+ export declare function appendMobileHiddenColumnCss(html: string): string;
@@ -1,4 +1,4 @@
1
- const e = `.esd-x,
1
+ const n = `.esd-x,
2
2
  .esd-merge-tag {
3
3
  color: #0a2ecc !important;
4
4
  box-shadow: none !important;
@@ -107,21 +107,20 @@ const e = `.esd-x,
107
107
  display: none !important;
108
108
  }
109
109
 
110
- /* SD-151345: mirror the compiled-email fix in the editor's mobile preview.
111
- The editor simulates mobile with .ue-mobile-mode, not a viewport media query. */
112
- .ue-mobile-mode .esd-block-text:not(.ins-coupon-code),
113
- .ue-mobile-mode .esd-block-text:not(.ins-coupon-code) p {
114
- word-break: break-word !important;
115
- overflow-wrap: anywhere !important;
110
+ /* SD-151345: a non-responsive structure still renders the 20px "Containers Gap on Mobile" cell of
111
+ every container it hides on mobile, so the visible containers sit off-centre and rows drift apart. */
112
+ .ue-mobile-mode td.esdev-mso-td:has(td.esd-container-frame.esd-mobile-hidden) {
113
+ display: none !important;
114
+ }
115
+
116
+ .ue-mobile-mode table.esdev-mso-table:has(td.esd-container-frame.esd-mobile-hidden) {
117
+ table-layout: fixed !important;
116
118
  }
117
119
 
118
- /* SD-151345: a non-responsive column whose containers are all mobile-hidden still
119
- takes its share of the row in the editor's mobile mode. Drop it like the compiled
120
- email does (ins-m-hidden-col) so the visible columns split the row. */
121
- .ue-mobile-mode td.esdev-mso-td:not(:has(td.esd-container-frame:not(.esd-mobile-hidden))) {
120
+ .ue-mobile-mode table.esdev-mso-table:has(td.esd-container-frame.esd-mobile-hidden) td.es-m-w0 {
122
121
  display: none !important;
123
122
  }
124
123
  `;
125
124
  export {
126
- e as default
125
+ n as default
127
126
  };
@@ -0,0 +1,11 @@
1
+ const s = "td.esdev-mso-td:has(> table > tbody > tr.es-mobile-hidden)", d = "table.esdev-mso-table:has(> tbody > tr > td.esdev-mso-td > table > tbody > tr.es-mobile-hidden)", t = `<style type="text/css">@media only screen and (max-width:600px){
2
+ ${s}{display:none !important}
3
+ ${d}{table-layout:fixed !important}
4
+ ${d} > tbody > tr > td.es-m-w0{display:none !important}
5
+ }</style>`;
6
+ function n(e) {
7
+ return !e || e.includes(t) ? e : /<\/head\s*>/i.test(e) ? e.replace(/<\/head\s*>/i, `${t}$&`) : `${t}${e}`;
8
+ }
9
+ export {
10
+ n as appendMobileHiddenColumnCss
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.18.1-beta.d56e3d5",
3
+ "version": "3.18.1-beta.dea994d",
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,23 +0,0 @@
1
- /**
2
- * SD-151345 — non-responsive structures break on mobile in two ways.
3
- *
4
- * 1. A structure with "Responsive Structure" off compiles to a real
5
- * `table.esdev-mso-table` whose row alternates column cells (`td.esdev-mso-td`)
6
- * with fixed 20px gap cells (`td.es-m-w0`). When a column's content is mobile
7
- * hidden (`tr.es-mobile-hidden`) the column collapses to 0px but its gap cells
8
- * stay, so the visible columns end up shifted left in one row and right in
9
- * the next. We tag those cells so a media query can drop them and let the
10
- * remaining columns split the row evenly.
11
- * 2. A word that cannot wrap widens its cell past its share and the row spills
12
- * past the mobile viewport. Letting words break restores the intended widths.
13
- * Scoped to `.esdev-mso-table` — only non-responsive structures share a row on
14
- * mobile, and `overflow-wrap:anywhere` feeds min-content sizing, so a wrapper-wide
15
- * rule would reflow every other email. The coupon exception carries the same
16
- * prefix plus its own class so it outranks the blanket rule (both !important,
17
- * so specificity decides) and a promo code stays one token.
18
- *
19
- * Stripo strips `esd-*` classes on export, so the selectors only rely on classes
20
- * that survive compilation. Pure string ops, no DOM — a DOMParser round trip would
21
- * rewrite conditional comments and entities in the sent HTML.
22
- */
23
- export declare function fixMobileNonResponsiveLayout(html: string): string;
@@ -1,54 +0,0 @@
1
- const h = "ins-mobile-layout", b = "ins-m-hidden-col", f = "ins-m-collapsed", x = `<style type="text/css">/* ${h} */
2
- @media only screen and (max-width:600px){
3
- .${b}{display:none !important}
4
- table.${f}{table-layout:fixed !important}
5
- .esdev-mso-table h1,.esdev-mso-table h2,.esdev-mso-table h3,.esdev-mso-table h4,.esdev-mso-table h5,
6
- .esdev-mso-table h6,.esdev-mso-table p,
7
- .esdev-mso-table td{word-break:break-word !important;overflow-wrap:anywhere !important}
8
- .esdev-mso-table .ins-coupon-code,
9
- .esdev-mso-table .ins-coupon-code *{word-break:normal !important;overflow-wrap:normal !important}
10
- }</style>`, w = /<\/head\s*>/i, u = /<(\/?)(table|tr|td)\b[^>]*>/gi, m = /\sclass=(["'])(.*?)\1/i, r = (t, s) => {
11
- const e = m.exec(t);
12
- return !!e && e[2].split(/\s+/).includes(s);
13
- }, v = (t, s) => r(t, s) ? t : m.test(t) ? t.replace(
14
- m,
15
- (e, n, l) => ` class=${n}${l} ${s}${n}`
16
- ) : t.replace(/\s*\/?>$/, (e) => ` class="${s}"${e}`), E = (t) => {
17
- const s = [], e = [];
18
- let n;
19
- for (u.lastIndex = 0; (n = u.exec(t)) !== null; ) {
20
- const [l, p, i] = n, o = i.toLowerCase();
21
- if (p) {
22
- const d = e.map((c) => c.tag).lastIndexOf(o);
23
- d !== -1 && e.splice(d);
24
- } else {
25
- const d = { tag: o, index: n.index, text: l }, c = e[e.length - 1], a = e[e.length - 2];
26
- o === "table" && r(l, "esdev-mso-table") ? (d.mso = !0, s.push({ index: n.index, text: l, cells: [] })) : o === "td" && (c == null ? void 0 : c.tag) === "tr" && (a != null && a.mso) ? (d.cell = { index: n.index, text: l, isGap: r(l, "es-m-w0"), rowsHidden: [] }, s[s.length - 1].cells.push(d.cell)) : o === "tr" && (c == null ? void 0 : c.tag) === "table" && (a != null && a.cell) && a.cell.rowsHidden.push(r(l, "es-mobile-hidden")), e.push(d);
27
- }
28
- }
29
- return s;
30
- }, L = (t) => {
31
- const s = t.map((i) => !i.isGap && i.rowsHidden.length > 0 && i.rowsHidden.every(Boolean));
32
- if (!s.includes(!0))
33
- return [];
34
- const e = s.map((i, o) => !i && !(t[o].isGap && s[o - 1])), n = (i) => e[i] && !t[i].isGap, l = e.findIndex((i, o) => n(o)), p = e.length - 1 - [...e].reverse().findIndex((i, o) => n(e.length - 1 - o));
35
- return t.filter((i, o) => !e[o] || i.isGap && (o < l || o > p));
36
- }, _ = (t) => {
37
- const s = [];
38
- return E(t).forEach((e) => {
39
- const n = L(e.cells);
40
- n.length && (s.push({ index: e.index, text: e.text, className: f }), n.forEach((l) => s.push({ index: l.index, text: l.text, className: b })));
41
- }), s.sort((e, n) => n.index - e.index).reduce((e, n) => {
42
- const l = e.slice(n.index + n.text.length);
43
- return e.slice(0, n.index) + v(n.text, n.className) + l;
44
- }, t);
45
- };
46
- function C(t) {
47
- if (!t || t.includes(h))
48
- return t;
49
- const s = _(t), e = w.exec(s);
50
- return e ? s.slice(0, e.index) + x + s.slice(e.index) : x + s;
51
- }
52
- export {
53
- C as fixMobileNonResponsiveLayout
54
- };