@lit-pigeon/renderer-mjml 0.1.2 → 0.2.1

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.
package/dist/index.cjs CHANGED
@@ -1,42 +1,43 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("mjml"),T=require("@lit-pigeon/core");function u(e){return`${e.top}px ${e.right}px ${e.bottom}px ${e.left}px`}function h(e){const{content:t,padding:r,textAlign:o,lineHeight:n}=e.values;return`<mj-text ${[`padding="${u(r)}"`,`align="${o}"`,`line-height="${n}"`].join(" ")}>${t}</mj-text>`}function j(e){const{src:t,alt:r,width:o,href:n,padding:a,alignment:c,borderRadius:i}=e.values,s=[`src="${m(t)}"`,`alt="${m(r)}"`,`padding="${u(a)}"`,`align="${c}"`];return o!=="auto"&&s.push(`width="${o}px"`),n&&s.push(`href="${m(n)}"`),i!==void 0&&i>0&&s.push(`border-radius="${i}px"`),`<mj-image ${s.join(" ")} />`}function m(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function b(e){const{content:t,href:r,backgroundColor:o,textColor:n,borderRadius:a,padding:c,innerPadding:i,fontSize:s,fontWeight:l,alignment:g,fullWidth:d}=e.values,p=[`href="${H(r)}"`,`background-color="${o}"`,`color="${n}"`,`border-radius="${a}px"`,`padding="${u(c)}"`,`inner-padding="${u(i)}"`,`font-size="${s}px"`,`font-weight="${l}"`,`align="${g}"`];d&&p.push('width="100%"');const S=t.replace(/^\s*<p>([\s\S]*?)<\/p>\s*$/i,"$1");return`<mj-button ${p.join(" ")}>${S}</mj-button>`}function H(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function k(e){const{borderColor:t,borderWidth:r,borderStyle:o,padding:n,width:a}=e.values;return`<mj-divider ${[`border-color="${t}"`,`border-width="${r}px"`,`border-style="${o}"`,`padding="${u(n)}"`,`width="${a}"`].join(" ")} />`}function x(e){const{height:t}=e.values;return`<mj-spacer height="${t}px" />`}function W(e){switch(e.type){case"facebook":return"facebook";case"twitter":return"twitter";case"instagram":return"instagram";case"linkedin":return"linkedin";case"youtube":return"youtube";case"tiktok":return"web";case"custom":return"web";default:return"web"}}function q(e,t){const o=[`name="${W(e)}"`,`href="${$(e.href)}"`,`icon-size="${t}px"`];e.iconUrl&&o.push(`src="${$(e.iconUrl)}"`);const n=e.label??"";return`<mj-social-element ${o.join(" ")}>${N(n)}</mj-social-element>`}function v(e){const{icons:t,iconSize:r,spacing:o,alignment:n,padding:a}=e.values,c=[`icon-size="${r}px"`,`icon-padding="${o}px"`,`align="${n}"`,`padding="${u(a)}"`,'mode="horizontal"'],i=t.map(s=>q(s,r)).join(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("mjml"),R=require("@lit-pigeon/core");function u(e){return`${e.top}px ${e.right}px ${e.bottom}px ${e.left}px`}function j(e){const{content:t,padding:r,textAlign:a,lineHeight:n}=e.values;return`<mj-text ${[`padding="${u(r)}"`,`align="${a}"`,`line-height="${n}"`].join(" ")}>${t}</mj-text>`}function b(e){const{src:t,alt:r,width:a,href:n,padding:o,alignment:c,borderRadius:i}=e.values,s=[`src="${g(t)}"`,`alt="${g(r)}"`,`padding="${u(o)}"`,`align="${c}"`];return a!=="auto"&&s.push(`width="${a}px"`),n&&s.push(`href="${g(n)}"`),i!==void 0&&i>0&&s.push(`border-radius="${i}px"`),`<mj-image ${s.join(" ")} />`}function g(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function k(e){const{content:t,href:r,backgroundColor:a,textColor:n,borderRadius:o,padding:c,innerPadding:i,fontSize:s,fontWeight:l,alignment:p,fullWidth:m}=e.values,f=[`href="${H(r)}"`,`background-color="${a}"`,`color="${n}"`,`border-radius="${o}px"`,`padding="${u(c)}"`,`inner-padding="${u(i)}"`,`font-size="${s}px"`,`font-weight="${l}"`,`align="${p}"`];m&&f.push('width="100%"');const C=t.replace(/^\s*<p>([\s\S]*?)<\/p>\s*$/i,"$1");return`<mj-button ${f.join(" ")}>${C}</mj-button>`}function H(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function x(e){const{borderColor:t,borderWidth:r,borderStyle:a,padding:n,width:o}=e.values;return`<mj-divider ${[`border-color="${t}"`,`border-width="${r}px"`,`border-style="${a}"`,`padding="${u(n)}"`,`width="${o}"`].join(" ")} />`}function v(e){const{height:t}=e.values;return`<mj-spacer height="${t}px" />`}function W(e){switch(e.type){case"facebook":return"facebook";case"twitter":return"twitter";case"instagram":return"instagram";case"linkedin":return"linkedin";case"youtube":return"youtube";case"tiktok":return"web";case"custom":return"web";default:return"web"}}function N(e,t){const a=[`name="${W(e)}"`,`href="${$(e.href)}"`,`icon-size="${t}px"`];e.iconUrl&&a.push(`src="${$(e.iconUrl)}"`);const n=e.label??"";return`<mj-social-element ${a.join(" ")}>${q(n)}</mj-social-element>`}function w(e){const{icons:t,iconSize:r,spacing:a,alignment:n,padding:o}=e.values,c=[`icon-size="${r}px"`,`icon-padding="${a}px"`,`align="${n}"`,`padding="${u(o)}"`,'mode="horizontal"'],i=t.map(s=>N(s,r)).join(`
2
2
  `);return`<mj-social ${c.join(" ")}>
3
3
  ${i}
4
- </mj-social>`}function $(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function N(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const _=/<(\s*\/?\s*mj-raw\b[^>]*)>/gi;function z(e){return e.replace(_,"&lt;$1&gt;")}function w(e){const{content:t,padding:r}=e.values,o=u(r),n=z(t);return`<mj-raw><div style="padding: ${o};">${n}</div></mj-raw>`}function y(e){const{content:t,innerPadding:r}=e.values;return`<mj-text ${[`padding="${u(r)}"`].join(" ")}>${t}</mj-text>`}function B(e){const t=e.values,r=[`mode="${t.mode}"`,`height="${t.height}px"`,`vertical-align="${t.verticalAlign}"`,`padding="${u(t.padding)}"`];return t.backgroundUrl&&r.push(`background-width="${t.width}px"`),t.backgroundUrl&&(r.push(`background-url="${D(t.backgroundUrl)}"`),r.push(`background-position="${t.backgroundPosition}"`)),t.backgroundColor&&r.push(`background-color="${t.backgroundColor}"`),` <mj-hero ${r.join(" ")}>
4
+ </mj-social>`}function $(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function q(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const _=/<(\s*\/?\s*mj-raw\b[^>]*)>/gi;function z(e){return e.replace(_,"&lt;$1&gt;")}function y(e){const{content:t,padding:r}=e.values,a=u(r),n=z(t);return`<mj-raw><div style="padding: ${a};">${n}</div></mj-raw>`}function B(e){const{content:t,innerPadding:r}=e.values;return`<mj-text ${[`padding="${u(r)}"`].join(" ")}>${t}</mj-text>`}function M(e){const t=e.values,r=[`mode="${t.mode}"`,`height="${t.height}px"`,`vertical-align="${t.verticalAlign}"`,`padding="${u(t.padding)}"`];return t.backgroundUrl&&r.push(`background-width="${t.width}px"`),t.backgroundUrl&&(r.push(`background-url="${D(t.backgroundUrl)}"`),r.push(`background-position="${t.backgroundPosition}"`)),t.backgroundColor&&r.push(`background-color="${t.backgroundColor}"`),` <mj-hero ${r.join(" ")}>
5
5
  <mj-text padding="${u(t.innerPadding)}">${t.content}</mj-text>
6
- </mj-hero>`}function D(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function O(e){const t=[`href="${I(e.href)}"`];return e.color&&t.push(`color="${e.color}"`),e.fontWeight&&t.push(`font-weight="${e.fontWeight}"`),e.textDecoration&&t.push(`text-decoration="${e.textDecoration}"`),e.padding&&t.push(`padding="${e.padding}"`),`<mj-navbar-link ${t.join(" ")}>${E(e.text)}</mj-navbar-link>`}function M(e){const{links:t,hamburger:r,padding:o}=e.values,n=[`hamburger="${r}"`,`padding="${u(o)}"`],a=t.map(c=>O(c)).join(`
6
+ </mj-hero>`}function D(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function O(e){const t=[`href="${I(e.href)}"`];return e.color&&t.push(`color="${e.color}"`),e.fontWeight&&t.push(`font-weight="${e.fontWeight}"`),e.textDecoration&&t.push(`text-decoration="${e.textDecoration}"`),e.padding&&t.push(`padding="${e.padding}"`),`<mj-navbar-link ${t.join(" ")}>${E(e.text)}</mj-navbar-link>`}function A(e){const{links:t,hamburger:r,padding:a}=e.values,n=[`hamburger="${r}"`,`padding="${u(a)}"`],o=t.map(c=>O(c)).join(`
7
7
  `);return`<mj-navbar ${n.join(" ")}>
8
- ${a}
9
- </mj-navbar>`}function I(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function E(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function L(e){switch(e.type){case"text":return h(e);case"image":return j(e);case"button":return b(e);case"divider":return k(e);case"spacer":return x(e);case"social":return v(e);case"html":return w(e);case"hero":return y(e);case"navbar":return M(e);default:return P(e)}}function P(e){const t=e.type,r=T.getBlockDefinition(t);return r!=null&&r.renderMjml?r.renderMjml(e):`<!-- Unknown block type: ${t} -->`}function U(e,t){const{backgroundColor:r,padding:o,borderRadius:n,verticalAlign:a}=e.attributes,c=[`width="${t}"`,`padding="${u(o)}"`,`vertical-align="${a}"`];r&&c.push(`background-color="${r}"`),n!==void 0&&n>0&&c.push(`border-radius="${n}px"`);const i=e.blocks.map(s=>` ${L(s)}`).join(`
8
+ ${o}
9
+ </mj-navbar>`}function I(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function E(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function U(e){switch(e.type){case"text":return j(e);case"image":return b(e);case"button":return k(e);case"divider":return x(e);case"spacer":return v(e);case"social":return w(e);case"html":return y(e);case"hero":return B(e);case"navbar":return A(e);default:return L(e)}}function L(e){const t=e.type,r=R.getBlockDefinition(t);return r!=null&&r.renderMjml?r.renderMjml(e):`<!-- Unknown block type: ${t} -->`}function P(e,t){const{backgroundColor:r,padding:a,borderRadius:n,verticalAlign:o}=e.attributes,c=[`width="${t}"`,`padding="${u(a)}"`,`vertical-align="${o}"`];r&&c.push(`background-color="${r}"`),n!==void 0&&n>0&&c.push(`border-radius="${n}px"`);const i=e.blocks.map(s=>` ${U(s)}`).join(`
10
10
  `);return` <mj-column ${c.join(" ")}>
11
11
  ${i}
12
- </mj-column>`}function K(e){if(e.columns.length===1&&e.columns[0].blocks.length===1&&e.columns[0].blocks[0].type==="hero")return f(B(e.columns[0].blocks[0]),e.attributes.condition);const{backgroundColor:t,backgroundImage:r,padding:o,fullWidth:n}=e.attributes,a=[`padding="${u(o)}"`];n&&a.push('full-width="full-width"'),t&&a.push(`background-color="${t}"`),r&&(a.push(`background-url="${C(r)}"`),a.push('background-size="cover"'),a.push('background-repeat="no-repeat"'));const c=e.columnRatios.reduce((s,l)=>s+l,0),i=e.columns.map((s,l)=>{const d=((e.columnRatios[l]??1)/c*100).toFixed(2).replace(/\.?0+$/,"");return U(s,`${d}%`)}).join(`
13
- `);return f(` <mj-section ${a.join(" ")}>
12
+ </mj-column>`}function K(e){if(e.columns.length===1&&e.columns[0].blocks.length===1&&e.columns[0].blocks[0].type==="hero")return h(M(e.columns[0].blocks[0]),e.attributes.condition);const{backgroundColor:t,backgroundImage:r,padding:a,fullWidth:n}=e.attributes,o=[`padding="${u(a)}"`];n&&o.push('full-width="full-width"'),t&&o.push(`background-color="${t}"`),r&&(o.push(`background-url="${d(r)}"`),o.push('background-size="cover"'),o.push('background-repeat="no-repeat"'));const c=e.columnRatios.reduce((s,l)=>s+l,0),i=e.columns.map((s,l)=>{const m=((e.columnRatios[l]??1)/c*100).toFixed(2).replace(/\.?0+$/,"");return P(s,`${m}%`)}).join(`
13
+ `);return h(` <mj-section ${o.join(" ")}>
14
14
  ${i}
15
- </mj-section>`,e.attributes.condition)}function f(e,t){const r=t==null?void 0:t.trim();return r?` <mj-raw>{{#if ${r}}}</mj-raw>
15
+ </mj-section>`,e.attributes.condition)}function h(e,t){const r=t==null?void 0:t.trim();return r?` <mj-raw>{{#if ${r}}}</mj-raw>
16
16
  ${e}
17
- <mj-raw>{{/if}}</mj-raw>`:e}const G=` <mj-raw>
17
+ <mj-raw>{{/if}}</mj-raw>`:e}const F=` <mj-raw>
18
18
  <!--[if mso]>
19
19
  <style>
20
20
  body, table, td { font-family: Arial, Helvetica, sans-serif !important; }
21
21
  blockquote { margin: 0 0 16px !important; }
22
22
  </style>
23
23
  <![endif]-->
24
- </mj-raw>`,F=` <mj-raw>
24
+ </mj-raw>`,G=` <mj-raw>
25
25
  <meta name="color-scheme" content="light dark">
26
26
  <meta name="supported-color-schemes" content="light dark">
27
27
  </mj-raw>`,J=` <mj-style inline="inline">
28
28
  h1, h2, h3, blockquote { margin: 0 0 0.5em; }
29
- </mj-style>`;function Q(e,t){const{fontFamily:r}=e.body.attributes,o=e.metadata.previewText,n=[];return t.outlookWorkarounds&&(n.push(G),n.push(F),n.push(J)),n.push(` <mj-attributes>
30
- <mj-all font-family="${C(r)}" />
29
+ </mj-style>`;function Q(e){const t=new Set,r=[];for(const a of e){if(!a.url||t.has(a.url))continue;t.add(a.url);const n=a.family.split(",")[0].trim().replace(/^['"]|['"]$/g,""),o=d(a.url),c=d(n);r.push(` <mj-font name="${c}" href="${o}" />`),r.push(` <mj-raw><link rel="stylesheet" href="${o}"></mj-raw>`)}return r.join(`
30
+ `)}function V(e,t){const{fontFamily:r}=e.body.attributes,a=e.metadata.previewText,n=[];t.outlookWorkarounds&&(n.push(F),n.push(G),n.push(J));const o=Q(t.fonts);return o&&n.push(o),n.push(` <mj-attributes>
31
+ <mj-all font-family="${d(r)}" />
31
32
  <mj-text font-size="14px" line-height="1.5" />
32
33
  <mj-button font-size="14px" />
33
- </mj-attributes>`),o&&n.push(` <mj-preview>${V(o)}</mj-preview>`),` <mj-head>
34
+ </mj-attributes>`),a&&n.push(` <mj-preview>${X(a)}</mj-preview>`),` <mj-head>
34
35
  ${n.join(`
35
36
  `)}
36
- </mj-head>`}function A(e,t){const r={outlookWorkarounds:(t==null?void 0:t.outlookWorkarounds)??!0},{width:o,backgroundColor:n}=e.body.attributes,a=[`width="${o}px"`];n&&a.push(`background-color="${n}"`);const c=Q(e,r),i=e.body.rows.map(s=>K(s)).join(`
37
+ </mj-head>`}function S(e,t){const r={outlookWorkarounds:(t==null?void 0:t.outlookWorkarounds)??!0,fonts:(t==null?void 0:t.fonts)??[]},{width:a,backgroundColor:n}=e.body.attributes,o=[`width="${a}px"`];n&&o.push(`background-color="${n}"`);const c=V(e,r),i=e.body.rows.map(s=>K(s)).join(`
37
38
  `);return`<mjml>
38
39
  ${c}
39
- <mj-body ${a.join(" ")}>
40
+ <mj-body ${o.join(" ")}>
40
41
  ${i}
41
42
  </mj-body>
42
- </mjml>`}function C(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function V(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}class X{async render(t,r){const o=A(t,{outlookWorkarounds:r==null?void 0:r.outlookWorkarounds}),n={keepComments:!1};r!=null&&r.minify&&(n.minify=!0),r!=null&&r.beautify&&(n.beautify=!0);try{const a=R(o,n),c=(a.errors||[]).map(i=>({message:i.message,line:i.line,tagName:i.tagName}));return{html:a.html,errors:c}}catch(a){return{html:"",errors:[{message:`MJML compilation failed: ${a instanceof Error?a.message:String(a)}`}]}}}}exports.MjmlRenderer=X;exports.documentToMjml=A;exports.renderButtonBlock=b;exports.renderDividerBlock=k;exports.renderHeroBlock=y;exports.renderHeroSection=B;exports.renderHtmlBlock=w;exports.renderImageBlock=j;exports.renderNavBarBlock=M;exports.renderSocialBlock=v;exports.renderSpacerBlock=x;exports.renderTextBlock=h;exports.spacingToMjml=u;
43
+ </mjml>`}function d(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function X(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}class Y{async render(t,r){const a=S(t,{outlookWorkarounds:r==null?void 0:r.outlookWorkarounds,fonts:r==null?void 0:r.fonts}),n={keepComments:!1};r!=null&&r.minify&&(n.minify=!0),r!=null&&r.beautify&&(n.beautify=!0);try{const o=T(a,n),c=(o.errors||[]).map(i=>({message:i.message,line:i.line,tagName:i.tagName}));return{html:o.html,errors:c}}catch(o){return{html:"",errors:[{message:`MJML compilation failed: ${o instanceof Error?o.message:String(o)}`}]}}}}exports.MjmlRenderer=Y;exports.documentToMjml=S;exports.renderButtonBlock=k;exports.renderDividerBlock=x;exports.renderHeroBlock=B;exports.renderHeroSection=M;exports.renderHtmlBlock=y;exports.renderImageBlock=b;exports.renderNavBarBlock=A;exports.renderSocialBlock=w;exports.renderSpacerBlock=v;exports.renderTextBlock=j;exports.spacingToMjml=u;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ButtonBlock } from '@lit-pigeon/core';
2
2
  import { DividerBlock } from '@lit-pigeon/core';
3
+ import { FontDefinition } from '@lit-pigeon/core';
3
4
  import { HeroBlock } from '@lit-pigeon/core';
4
5
  import { HtmlBlock } from '@lit-pigeon/core';
5
6
  import { ImageBlock } from '@lit-pigeon/core';
@@ -41,6 +42,11 @@ declare interface DocumentToMjmlOptions {
41
42
  * `[if mso]` conditional block.
42
43
  */
43
44
  outlookWorkarounds?: boolean;
45
+ /**
46
+ * Web fonts to emit as `<mj-font>` in the head. Each font with a `url`
47
+ * produces one stylesheet link (deduped by url); URL-less fonts are skipped.
48
+ */
49
+ fonts?: FontDefinition[];
44
50
  }
45
51
 
46
52
  /**
package/dist/index.js CHANGED
@@ -11,45 +11,45 @@ function x(e) {
11
11
  `line-height="${n}"`
12
12
  ].join(" ")}>${t}</mj-text>`;
13
13
  }
14
- function v(e) {
15
- const { src: t, alt: r, width: a, href: n, padding: o, alignment: i, borderRadius: c } = e.values, s = [
16
- `src="${m(t)}"`,
17
- `alt="${m(r)}"`,
14
+ function w(e) {
15
+ const { src: t, alt: r, width: a, href: n, padding: o, alignment: c, borderRadius: i } = e.values, s = [
16
+ `src="${g(t)}"`,
17
+ `alt="${g(r)}"`,
18
18
  `padding="${u(o)}"`,
19
- `align="${i}"`
19
+ `align="${c}"`
20
20
  ];
21
- return a !== "auto" && s.push(`width="${a}px"`), n && s.push(`href="${m(n)}"`), c !== void 0 && c > 0 && s.push(`border-radius="${c}px"`), `<mj-image ${s.join(" ")} />`;
21
+ return a !== "auto" && s.push(`width="${a}px"`), n && s.push(`href="${g(n)}"`), i !== void 0 && i > 0 && s.push(`border-radius="${i}px"`), `<mj-image ${s.join(" ")} />`;
22
22
  }
23
- function m(e) {
23
+ function g(e) {
24
24
  return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
25
25
  }
26
- function w(e) {
26
+ function v(e) {
27
27
  const {
28
28
  content: t,
29
29
  href: r,
30
30
  backgroundColor: a,
31
31
  textColor: n,
32
32
  borderRadius: o,
33
- padding: i,
34
- innerPadding: c,
33
+ padding: c,
34
+ innerPadding: i,
35
35
  fontSize: s,
36
36
  fontWeight: l,
37
37
  alignment: p,
38
- fullWidth: d
39
- } = e.values, g = [
38
+ fullWidth: m
39
+ } = e.values, f = [
40
40
  `href="${y(r)}"`,
41
41
  `background-color="${a}"`,
42
42
  `color="${n}"`,
43
43
  `border-radius="${o}px"`,
44
- `padding="${u(i)}"`,
45
- `inner-padding="${u(c)}"`,
44
+ `padding="${u(c)}"`,
45
+ `inner-padding="${u(i)}"`,
46
46
  `font-size="${s}px"`,
47
47
  `font-weight="${l}"`,
48
48
  `align="${p}"`
49
49
  ];
50
- d && g.push('width="100%"');
50
+ m && f.push('width="100%"');
51
51
  const j = t.replace(/^\s*<p>([\s\S]*?)<\/p>\s*$/i, "$1");
52
- return `<mj-button ${g.join(" ")}>${j}</mj-button>`;
52
+ return `<mj-button ${f.join(" ")}>${j}</mj-button>`;
53
53
  }
54
54
  function y(e) {
55
55
  return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -99,16 +99,16 @@ function M(e, t) {
99
99
  return `<mj-social-element ${a.join(" ")}>${S(n)}</mj-social-element>`;
100
100
  }
101
101
  function R(e) {
102
- const { icons: t, iconSize: r, spacing: a, alignment: n, padding: o } = e.values, i = [
102
+ const { icons: t, iconSize: r, spacing: a, alignment: n, padding: o } = e.values, c = [
103
103
  `icon-size="${r}px"`,
104
104
  `icon-padding="${a}px"`,
105
105
  `align="${n}"`,
106
106
  `padding="${u(o)}"`,
107
107
  'mode="horizontal"'
108
- ], c = t.map((s) => M(s, r)).join(`
108
+ ], i = t.map((s) => M(s, r)).join(`
109
109
  `);
110
- return `<mj-social ${i.join(" ")}>
111
- ${c}
110
+ return `<mj-social ${c.join(" ")}>
111
+ ${i}
112
112
  </mj-social>`;
113
113
  }
114
114
  function $(e) {
@@ -117,32 +117,32 @@ function $(e) {
117
117
  function S(e) {
118
118
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
119
119
  }
120
- const W = /<(\s*\/?\s*mj-raw\b[^>]*)>/gi;
121
- function H(e) {
122
- return e.replace(W, "&lt;$1&gt;");
120
+ const T = /<(\s*\/?\s*mj-raw\b[^>]*)>/gi;
121
+ function W(e) {
122
+ return e.replace(T, "&lt;$1&gt;");
123
123
  }
124
- function T(e) {
125
- const { content: t, padding: r } = e.values, a = u(r), n = H(t);
124
+ function H(e) {
125
+ const { content: t, padding: r } = e.values, a = u(r), n = W(t);
126
126
  return `<mj-raw><div style="padding: ${a};">${n}</div></mj-raw>`;
127
127
  }
128
- function _(e) {
128
+ function N(e) {
129
129
  const { content: t, innerPadding: r } = e.values;
130
130
  return `<mj-text ${[
131
131
  `padding="${u(r)}"`
132
132
  ].join(" ")}>${t}</mj-text>`;
133
133
  }
134
- function z(e) {
134
+ function _(e) {
135
135
  const t = e.values, r = [
136
136
  `mode="${t.mode}"`,
137
137
  `height="${t.height}px"`,
138
138
  `vertical-align="${t.verticalAlign}"`,
139
139
  `padding="${u(t.padding)}"`
140
140
  ];
141
- return t.backgroundUrl && r.push(`background-width="${t.width}px"`), t.backgroundUrl && (r.push(`background-url="${N(t.backgroundUrl)}"`), r.push(`background-position="${t.backgroundPosition}"`)), t.backgroundColor && r.push(`background-color="${t.backgroundColor}"`), ` <mj-hero ${r.join(" ")}>
141
+ return t.backgroundUrl && r.push(`background-width="${t.width}px"`), t.backgroundUrl && (r.push(`background-url="${z(t.backgroundUrl)}"`), r.push(`background-position="${t.backgroundPosition}"`)), t.backgroundColor && r.push(`background-color="${t.backgroundColor}"`), ` <mj-hero ${r.join(" ")}>
142
142
  <mj-text padding="${u(t.innerPadding)}">${t.content}</mj-text>
143
143
  </mj-hero>`;
144
144
  }
145
- function N(e) {
145
+ function z(e) {
146
146
  return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
147
147
  }
148
148
  function q(e) {
@@ -155,7 +155,7 @@ function D(e) {
155
155
  const { links: t, hamburger: r, padding: a } = e.values, n = [
156
156
  `hamburger="${r}"`,
157
157
  `padding="${u(a)}"`
158
- ], o = t.map((i) => q(i)).join(`
158
+ ], o = t.map((c) => q(c)).join(`
159
159
  `);
160
160
  return `<mj-navbar ${n.join(" ")}>
161
161
  ${o}
@@ -172,9 +172,9 @@ function I(e) {
172
172
  case "text":
173
173
  return x(e);
174
174
  case "image":
175
- return v(e);
176
- case "button":
177
175
  return w(e);
176
+ case "button":
177
+ return v(e);
178
178
  case "divider":
179
179
  return A(e);
180
180
  case "spacer":
@@ -182,55 +182,55 @@ function I(e) {
182
182
  case "social":
183
183
  return R(e);
184
184
  case "html":
185
- return T(e);
185
+ return H(e);
186
186
  case "hero":
187
- return _(e);
187
+ return N(e);
188
188
  case "navbar":
189
189
  return D(e);
190
190
  default:
191
- return L(e);
191
+ return U(e);
192
192
  }
193
193
  }
194
- function L(e) {
194
+ function U(e) {
195
195
  const t = e.type, r = k(t);
196
196
  return r != null && r.renderMjml ? r.renderMjml(e) : `<!-- Unknown block type: ${t} -->`;
197
197
  }
198
- function U(e, t) {
199
- const { backgroundColor: r, padding: a, borderRadius: n, verticalAlign: o } = e.attributes, i = [
198
+ function L(e, t) {
199
+ const { backgroundColor: r, padding: a, borderRadius: n, verticalAlign: o } = e.attributes, c = [
200
200
  `width="${t}"`,
201
201
  `padding="${u(a)}"`,
202
202
  `vertical-align="${o}"`
203
203
  ];
204
- r && i.push(`background-color="${r}"`), n !== void 0 && n > 0 && i.push(`border-radius="${n}px"`);
205
- const c = e.blocks.map((s) => ` ${I(s)}`).join(`
204
+ r && c.push(`background-color="${r}"`), n !== void 0 && n > 0 && c.push(`border-radius="${n}px"`);
205
+ const i = e.blocks.map((s) => ` ${I(s)}`).join(`
206
206
  `);
207
- return ` <mj-column ${i.join(" ")}>
208
- ${c}
207
+ return ` <mj-column ${c.join(" ")}>
208
+ ${i}
209
209
  </mj-column>`;
210
210
  }
211
211
  function P(e) {
212
212
  if (e.columns.length === 1 && e.columns[0].blocks.length === 1 && e.columns[0].blocks[0].type === "hero")
213
- return f(
214
- z(e.columns[0].blocks[0]),
213
+ return h(
214
+ _(e.columns[0].blocks[0]),
215
215
  e.attributes.condition
216
216
  );
217
217
  const { backgroundColor: t, backgroundImage: r, padding: a, fullWidth: n } = e.attributes, o = [
218
218
  `padding="${u(a)}"`
219
219
  ];
220
- n && o.push('full-width="full-width"'), t && o.push(`background-color="${t}"`), r && (o.push(`background-url="${h(r)}"`), o.push('background-size="cover"'), o.push('background-repeat="no-repeat"'));
221
- const i = e.columnRatios.reduce((s, l) => s + l, 0), c = e.columns.map((s, l) => {
222
- const d = ((e.columnRatios[l] ?? 1) / i * 100).toFixed(2).replace(/\.?0+$/, "");
223
- return U(s, `${d}%`);
220
+ n && o.push('full-width="full-width"'), t && o.push(`background-color="${t}"`), r && (o.push(`background-url="${d(r)}"`), o.push('background-size="cover"'), o.push('background-repeat="no-repeat"'));
221
+ const c = e.columnRatios.reduce((s, l) => s + l, 0), i = e.columns.map((s, l) => {
222
+ const m = ((e.columnRatios[l] ?? 1) / c * 100).toFixed(2).replace(/\.?0+$/, "");
223
+ return L(s, `${m}%`);
224
224
  }).join(`
225
225
  `);
226
- return f(
226
+ return h(
227
227
  ` <mj-section ${o.join(" ")}>
228
- ${c}
228
+ ${i}
229
229
  </mj-section>`,
230
230
  e.attributes.condition
231
231
  );
232
232
  }
233
- function f(e, t) {
233
+ function h(e, t) {
234
234
  const r = t == null ? void 0 : t.trim();
235
235
  return r ? ` <mj-raw>{{#if ${r}}}</mj-raw>
236
236
  ${e}
@@ -243,46 +243,60 @@ const K = ` <mj-raw>
243
243
  blockquote { margin: 0 0 16px !important; }
244
244
  </style>
245
245
  <![endif]-->
246
- </mj-raw>`, G = ` <mj-raw>
246
+ </mj-raw>`, F = ` <mj-raw>
247
247
  <meta name="color-scheme" content="light dark">
248
248
  <meta name="supported-color-schemes" content="light dark">
249
- </mj-raw>`, F = ` <mj-style inline="inline">
249
+ </mj-raw>`, G = ` <mj-style inline="inline">
250
250
  h1, h2, h3, blockquote { margin: 0 0 0.5em; }
251
251
  </mj-style>`;
252
- function J(e, t) {
252
+ function J(e) {
253
+ const t = /* @__PURE__ */ new Set(), r = [];
254
+ for (const a of e) {
255
+ if (!a.url || t.has(a.url)) continue;
256
+ t.add(a.url);
257
+ const n = a.family.split(",")[0].trim().replace(/^['"]|['"]$/g, ""), o = d(a.url), c = d(n);
258
+ r.push(` <mj-font name="${c}" href="${o}" />`), r.push(` <mj-raw><link rel="stylesheet" href="${o}"></mj-raw>`);
259
+ }
260
+ return r.join(`
261
+ `);
262
+ }
263
+ function Q(e, t) {
253
264
  const { fontFamily: r } = e.body.attributes, a = e.metadata.previewText, n = [];
254
- return t.outlookWorkarounds && (n.push(K), n.push(G), n.push(F)), n.push(` <mj-attributes>
255
- <mj-all font-family="${h(r)}" />
265
+ t.outlookWorkarounds && (n.push(K), n.push(F), n.push(G));
266
+ const o = J(t.fonts);
267
+ return o && n.push(o), n.push(` <mj-attributes>
268
+ <mj-all font-family="${d(r)}" />
256
269
  <mj-text font-size="14px" line-height="1.5" />
257
270
  <mj-button font-size="14px" />
258
- </mj-attributes>`), a && n.push(` <mj-preview>${V(a)}</mj-preview>`), ` <mj-head>
271
+ </mj-attributes>`), a && n.push(` <mj-preview>${X(a)}</mj-preview>`), ` <mj-head>
259
272
  ${n.join(`
260
273
  `)}
261
274
  </mj-head>`;
262
275
  }
263
- function Q(e, t) {
276
+ function V(e, t) {
264
277
  const r = {
265
- outlookWorkarounds: (t == null ? void 0 : t.outlookWorkarounds) ?? !0
278
+ outlookWorkarounds: (t == null ? void 0 : t.outlookWorkarounds) ?? !0,
279
+ fonts: (t == null ? void 0 : t.fonts) ?? []
266
280
  }, { width: a, backgroundColor: n } = e.body.attributes, o = [
267
281
  `width="${a}px"`
268
282
  ];
269
283
  n && o.push(`background-color="${n}"`);
270
- const i = J(e, r), c = e.body.rows.map((s) => P(s)).join(`
284
+ const c = Q(e, r), i = e.body.rows.map((s) => P(s)).join(`
271
285
  `);
272
286
  return `<mjml>
273
- ${i}
274
- <mj-body ${o.join(" ")}>
275
287
  ${c}
288
+ <mj-body ${o.join(" ")}>
289
+ ${i}
276
290
  </mj-body>
277
291
  </mjml>`;
278
292
  }
279
- function h(e) {
293
+ function d(e) {
280
294
  return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
281
295
  }
282
- function V(e) {
296
+ function X(e) {
283
297
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
284
298
  }
285
- class Z {
299
+ class ee {
286
300
  /**
287
301
  * Renders a PigeonDocument to HTML using MJML as the compilation backend.
288
302
  *
@@ -291,22 +305,23 @@ class Z {
291
305
  * @returns A promise resolving to the rendered HTML and any errors
292
306
  */
293
307
  async render(t, r) {
294
- const a = Q(t, {
295
- outlookWorkarounds: r == null ? void 0 : r.outlookWorkarounds
308
+ const a = V(t, {
309
+ outlookWorkarounds: r == null ? void 0 : r.outlookWorkarounds,
310
+ fonts: r == null ? void 0 : r.fonts
296
311
  }), n = {
297
312
  // By default MJML inlines CSS; respect the option if provided
298
313
  keepComments: !1
299
314
  };
300
315
  r != null && r.minify && (n.minify = !0), r != null && r.beautify && (n.beautify = !0);
301
316
  try {
302
- const o = b(a, n), i = (o.errors || []).map((c) => ({
303
- message: c.message,
304
- line: c.line,
305
- tagName: c.tagName
317
+ const o = b(a, n), c = (o.errors || []).map((i) => ({
318
+ message: i.message,
319
+ line: i.line,
320
+ tagName: i.tagName
306
321
  }));
307
322
  return {
308
323
  html: o.html,
309
- errors: i
324
+ errors: c
310
325
  };
311
326
  } catch (o) {
312
327
  return {
@@ -317,14 +332,14 @@ class Z {
317
332
  }
318
333
  }
319
334
  export {
320
- Z as MjmlRenderer,
321
- Q as documentToMjml,
322
- w as renderButtonBlock,
335
+ ee as MjmlRenderer,
336
+ V as documentToMjml,
337
+ v as renderButtonBlock,
323
338
  A as renderDividerBlock,
324
- _ as renderHeroBlock,
325
- z as renderHeroSection,
326
- T as renderHtmlBlock,
327
- v as renderImageBlock,
339
+ N as renderHeroBlock,
340
+ _ as renderHeroSection,
341
+ H as renderHtmlBlock,
342
+ w as renderImageBlock,
328
343
  D as renderNavBarBlock,
329
344
  R as renderSocialBlock,
330
345
  B as renderSpacerBlock,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lit-pigeon/renderer-mjml",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "MJML-based HTML renderer for Pigeon email editor",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -18,7 +18,7 @@
18
18
  ],
19
19
  "dependencies": {
20
20
  "mjml": "^4.15.0",
21
- "@lit-pigeon/core": "^0.1.2"
21
+ "@lit-pigeon/core": "^0.3.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/mjml": "^4.7.0",