nuxt-email-renderer 0.0.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.
Files changed (108) hide show
  1. package/README.md +84 -0
  2. package/dist/chunks/build.mjs +705 -0
  3. package/dist/client/200.html +1 -0
  4. package/dist/client/404.html +1 -0
  5. package/dist/client/_nuxt/3R9sgenR.js +1 -0
  6. package/dist/client/_nuxt/5UMTGv3q.js +1 -0
  7. package/dist/client/_nuxt/BJ_ZNVwW.js +57 -0
  8. package/dist/client/_nuxt/BQq6TDT9.js +1 -0
  9. package/dist/client/_nuxt/BaEALuhw.js +1 -0
  10. package/dist/client/_nuxt/BpPBU6U6.js +1 -0
  11. package/dist/client/_nuxt/C-EM3RPC.js +1 -0
  12. package/dist/client/_nuxt/CAkrHwjs.js +1 -0
  13. package/dist/client/_nuxt/CLam8HLD.js +13 -0
  14. package/dist/client/_nuxt/CWC_D6I8.js +1 -0
  15. package/dist/client/_nuxt/CWrUPQXK.js +1 -0
  16. package/dist/client/_nuxt/ChBHSR31.js +1 -0
  17. package/dist/client/_nuxt/CjpBjtYD.js +1 -0
  18. package/dist/client/_nuxt/ClYUVDjM.js +1 -0
  19. package/dist/client/_nuxt/Coq9dpCu.js +1 -0
  20. package/dist/client/_nuxt/Ct-qVDJL.js +1 -0
  21. package/dist/client/_nuxt/DGBet86w.js +1 -0
  22. package/dist/client/_nuxt/D_dyXden.js +1 -0
  23. package/dist/client/_nuxt/DfWNeV2h.js +1 -0
  24. package/dist/client/_nuxt/GBsDgIkm.js +1 -0
  25. package/dist/client/_nuxt/ImWtXt63.js +10 -0
  26. package/dist/client/_nuxt/YAsWV_SB.js +1 -0
  27. package/dist/client/_nuxt/builds/latest.json +1 -0
  28. package/dist/client/_nuxt/builds/meta/b874db0a-5b15-4361-9e12-b85e9c2f73e6.json +1 -0
  29. package/dist/client/_nuxt/entry.uVMzXFrc.css +1 -0
  30. package/dist/client/_nuxt/error-404.BzYUYoct.css +1 -0
  31. package/dist/client/_nuxt/error-500.CZg0BYA4.css +1 -0
  32. package/dist/client/_nuxt/fDag-OJT.js +51 -0
  33. package/dist/client/index.html +1 -0
  34. package/dist/module.d.mts +15 -0
  35. package/dist/module.json +9 -0
  36. package/dist/module.mjs +192 -0
  37. package/dist/runtime/components/body/EBody.vue +43 -0
  38. package/dist/runtime/components/body/EBody.vue.d.ts +21 -0
  39. package/dist/runtime/components/body/__snapshots__/Ebody.test.ts.snap +3 -0
  40. package/dist/runtime/components/button/EButton.vue +75 -0
  41. package/dist/runtime/components/button/EButton.vue.d.ts +3 -0
  42. package/dist/runtime/components/button/__snapshots__/EButton.test.ts.snap +9 -0
  43. package/dist/runtime/components/button/utils/parse-padding.d.ts +24 -0
  44. package/dist/runtime/components/button/utils/parse-padding.js +83 -0
  45. package/dist/runtime/components/button/utils/px-to-pt.d.ts +1 -0
  46. package/dist/runtime/components/button/utils/px-to-pt.js +1 -0
  47. package/dist/runtime/components/code-block/ECodeBlock.vue +99 -0
  48. package/dist/runtime/components/code-block/ECodeBlock.vue.d.ts +78 -0
  49. package/dist/runtime/components/code-inline/ECodeInline.vue +42 -0
  50. package/dist/runtime/components/code-inline/ECodeInline.vue.d.ts +23 -0
  51. package/dist/runtime/components/column/EColumn.vue +18 -0
  52. package/dist/runtime/components/column/EColumn.vue.d.ts +4 -0
  53. package/dist/runtime/components/column/__snapshots__/EColumn.test.ts.snap +3 -0
  54. package/dist/runtime/components/container/EContainer.vue +25 -0
  55. package/dist/runtime/components/container/EContainer.vue.d.ts +3 -0
  56. package/dist/runtime/components/container/__snapshots__/EContainer.test.ts.snap +3 -0
  57. package/dist/runtime/components/font/EFont.vue +50 -0
  58. package/dist/runtime/components/font/EFont.vue.d.ts +65 -0
  59. package/dist/runtime/components/font/__snapshots__/EFont.test.ts.snap +33 -0
  60. package/dist/runtime/components/head/EHead.vue +16 -0
  61. package/dist/runtime/components/head/EHead.vue.d.ts +4 -0
  62. package/dist/runtime/components/head/__snapshots__/EHead.test.ts.snap +8 -0
  63. package/dist/runtime/components/heading/EHeading.utils.d.ts +14 -0
  64. package/dist/runtime/components/heading/EHeading.utils.js +23 -0
  65. package/dist/runtime/components/heading/EHeading.vue +74 -0
  66. package/dist/runtime/components/heading/EHeading.vue.d.ts +89 -0
  67. package/dist/runtime/components/heading/__snapshots__/EHeading.test.ts.snap +3 -0
  68. package/dist/runtime/components/hr/EHr.vue +14 -0
  69. package/dist/runtime/components/hr/EHr.vue.d.ts +4 -0
  70. package/dist/runtime/components/hr/__snapshots__/EHr.test.ts.snap +3 -0
  71. package/dist/runtime/components/html/EHtml.vue +29 -0
  72. package/dist/runtime/components/html/EHtml.vue.d.ts +26 -0
  73. package/dist/runtime/components/html/__snapshots__/EHtml.test.ts.snap +3 -0
  74. package/dist/runtime/components/img/EImg.vue +37 -0
  75. package/dist/runtime/components/img/EImg.vue.d.ts +39 -0
  76. package/dist/runtime/components/index.d.ts +38 -0
  77. package/dist/runtime/components/index.js +38 -0
  78. package/dist/runtime/components/link/ELink.vue +30 -0
  79. package/dist/runtime/components/link/ELink.vue.d.ts +24 -0
  80. package/dist/runtime/components/link/__snapshots__/ELink.test.ts.snap +3 -0
  81. package/dist/runtime/components/preview/EPreview.vue +41 -0
  82. package/dist/runtime/components/preview/EPreview.vue.d.ts +7 -0
  83. package/dist/runtime/components/preview/__snapshots__/EPreview.test.ts.snap +5 -0
  84. package/dist/runtime/components/row/ERow.vue +31 -0
  85. package/dist/runtime/components/row/ERow.vue.d.ts +4 -0
  86. package/dist/runtime/components/section/ESection.vue +23 -0
  87. package/dist/runtime/components/section/ESection.vue.d.ts +4 -0
  88. package/dist/runtime/components/style/EStyle.vue +18 -0
  89. package/dist/runtime/components/style/EStyle.vue.d.ts +4 -0
  90. package/dist/runtime/components/text/EText.vue +22 -0
  91. package/dist/runtime/components/text/EText.vue.d.ts +4 -0
  92. package/dist/runtime/server/api/emails/list.get.d.ts +2 -0
  93. package/dist/runtime/server/api/emails/list.get.js +19 -0
  94. package/dist/runtime/server/api/emails/render.get.d.ts +2 -0
  95. package/dist/runtime/server/api/emails/render.get.js +47 -0
  96. package/dist/runtime/server/tsconfig.json +3 -0
  97. package/dist/runtime/server/utils/cleanup.d.ts +1 -0
  98. package/dist/runtime/server/utils/cleanup.js +5 -0
  99. package/dist/runtime/server/utils/options.d.ts +15 -0
  100. package/dist/runtime/server/utils/options.js +0 -0
  101. package/dist/runtime/server/utils/plainTextSelectors.d.ts +2 -0
  102. package/dist/runtime/server/utils/plainTextSelectors.js +8 -0
  103. package/dist/runtime/server/utils/pretty.d.ts +1 -0
  104. package/dist/runtime/server/utils/pretty.js +11 -0
  105. package/dist/runtime/server/utils/render.d.ts +14 -0
  106. package/dist/runtime/server/utils/render.js +30 -0
  107. package/dist/types.d.mts +3 -0
  108. package/package.json +70 -0
@@ -0,0 +1,39 @@
1
+ import type { PropType } from 'vue';
2
+ export declare const EImg: import("@vue/runtime-core").DefineComponent<import("@vue/runtime-core").ExtractPropTypes<{
3
+ src: {
4
+ type: StringConstructor;
5
+ required: true;
6
+ };
7
+ width: {
8
+ type: PropType<string | number>;
9
+ required: false;
10
+ };
11
+ height: {
12
+ type: PropType<string | number>;
13
+ required: false;
14
+ };
15
+ alt: {
16
+ type: StringConstructor;
17
+ required: false;
18
+ };
19
+ }>, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
20
+ [key: string]: any;
21
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<import("@vue/runtime-core").ExtractPropTypes<{
22
+ src: {
23
+ type: StringConstructor;
24
+ required: true;
25
+ };
26
+ width: {
27
+ type: PropType<string | number>;
28
+ required: false;
29
+ };
30
+ height: {
31
+ type: PropType<string | number>;
32
+ required: false;
33
+ };
34
+ alt: {
35
+ type: StringConstructor;
36
+ required: false;
37
+ };
38
+ }>> & Readonly<{}>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
39
+ export default EImg;
@@ -0,0 +1,38 @@
1
+ export { default as EHtml } from './html/EHtml.vue.js';
2
+ export { default as EText } from './text/EText.vue.js';
3
+ export { default as EBody } from './body/EBody.vue.js';
4
+ export { default as EButton } from './button/EButton.vue.js';
5
+ export { default as EColumn } from './column/EColumn.vue.js';
6
+ export { default as ECodeBlock } from './code-block/ECodeBlock.vue.js';
7
+ export { default as EContainer } from './container/EContainer.vue.js';
8
+ export { default as EFont } from './font/EFont.vue.js';
9
+ export { default as EHead } from './head/EHead.vue.js';
10
+ export { default as EHeading } from './heading/EHeading.vue.js';
11
+ export { default as EHr } from './hr/EHr.vue.js';
12
+ export { default as EImg } from './img/EImg.vue.js';
13
+ export { default as ELink } from './link/ELink.vue.js';
14
+ export { default as EPreview } from './preview/EPreview.vue.js';
15
+ export { default as ERow } from './row/ERow.vue.js';
16
+ export { default as ESection } from './section/ESection.vue.js';
17
+ export { default as EStyle } from './style/EStyle.vue.js';
18
+ export { default as ECodeInline } from './code-inline/ECodeInline.vue.js';
19
+ export declare const emailComponents: {
20
+ EBody: () => Promise<any>;
21
+ EButton: () => Promise<any>;
22
+ ECodeBlock: () => Promise<any>;
23
+ ECodeInline: () => Promise<any>;
24
+ EColumn: () => Promise<any>;
25
+ EContainer: () => Promise<any>;
26
+ EFont: () => Promise<any>;
27
+ EHead: () => Promise<any>;
28
+ EHeading: () => Promise<any>;
29
+ EHr: () => Promise<any>;
30
+ EHtml: () => Promise<any>;
31
+ EImg: () => Promise<any>;
32
+ ELink: () => Promise<any>;
33
+ EPreview: () => Promise<any>;
34
+ ERow: () => Promise<any>;
35
+ ESection: () => Promise<any>;
36
+ EStyle: () => Promise<any>;
37
+ EText: () => Promise<any>;
38
+ };
@@ -0,0 +1,38 @@
1
+ export { default as EHtml } from "./html/EHtml.vue";
2
+ export { default as EText } from "./text/EText.vue";
3
+ export { default as EBody } from "./body/EBody.vue";
4
+ export { default as EButton } from "./button/EButton.vue";
5
+ export { default as EColumn } from "./column/EColumn.vue";
6
+ export { default as ECodeBlock } from "./code-block/ECodeBlock.vue";
7
+ export { default as EContainer } from "./container/EContainer.vue";
8
+ export { default as EFont } from "./font/EFont.vue";
9
+ export { default as EHead } from "./head/EHead.vue";
10
+ export { default as EHeading } from "./heading/EHeading.vue";
11
+ export { default as EHr } from "./hr/EHr.vue";
12
+ export { default as EImg } from "./img/EImg.vue";
13
+ export { default as ELink } from "./link/ELink.vue";
14
+ export { default as EPreview } from "./preview/EPreview.vue";
15
+ export { default as ERow } from "./row/ERow.vue";
16
+ export { default as ESection } from "./section/ESection.vue";
17
+ export { default as EStyle } from "./style/EStyle.vue";
18
+ export { default as ECodeInline } from "./code-inline/ECodeInline.vue";
19
+ export const emailComponents = {
20
+ EBody: () => import("./body/EBody.vue"),
21
+ EButton: () => import("./button/EButton.vue"),
22
+ ECodeBlock: () => import("./code-block/ECodeBlock.vue"),
23
+ ECodeInline: () => import("./code-inline/ECodeInline.vue"),
24
+ EColumn: () => import("./column/EColumn.vue"),
25
+ EContainer: () => import("./container/EContainer.vue"),
26
+ EFont: () => import("./font/EFont.vue"),
27
+ EHead: () => import("./head/EHead.vue"),
28
+ EHeading: () => import("./heading/EHeading.vue"),
29
+ EHr: () => import("./hr/EHr.vue"),
30
+ EHtml: () => import("./html/EHtml.vue"),
31
+ EImg: () => import("./img/EImg.vue"),
32
+ ELink: () => import("./link/ELink.vue"),
33
+ EPreview: () => import("./preview/EPreview.vue"),
34
+ ERow: () => import("./row/ERow.vue"),
35
+ ESection: () => import("./section/ESection.vue"),
36
+ EStyle: () => import("./style/EStyle.vue"),
37
+ EText: () => import("./text/EText.vue")
38
+ };
@@ -0,0 +1,30 @@
1
+ <script>
2
+ import { defineComponent, h } from "vue";
3
+ export const ELink = defineComponent({
4
+ name: "ELink",
5
+ props: {
6
+ href: {
7
+ type: String,
8
+ required: true
9
+ },
10
+ target: {
11
+ type: String,
12
+ default: "_blank"
13
+ }
14
+ },
15
+ setup(props, { slots }) {
16
+ return () => {
17
+ return h(
18
+ "a",
19
+ {
20
+ style: "color: #067df7; text-decoration: none",
21
+ href: props.href,
22
+ target: props.target
23
+ },
24
+ slots.default?.()
25
+ );
26
+ };
27
+ }
28
+ });
29
+ export default ELink;
30
+ </script>
@@ -0,0 +1,24 @@
1
+ export declare const ELink: import("@vue/runtime-core").DefineComponent<import("@vue/runtime-core").ExtractPropTypes<{
2
+ href: {
3
+ type: StringConstructor;
4
+ required: true;
5
+ };
6
+ target: {
7
+ type: StringConstructor;
8
+ default: string;
9
+ };
10
+ }>, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
11
+ [key: string]: any;
12
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<import("@vue/runtime-core").ExtractPropTypes<{
13
+ href: {
14
+ type: StringConstructor;
15
+ required: true;
16
+ };
17
+ target: {
18
+ type: StringConstructor;
19
+ default: string;
20
+ };
21
+ }>> & Readonly<{}>, {
22
+ target: string;
23
+ }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
24
+ export default ELink;
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`<ELink> component > renders correctly 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><a style="color: #067df7; text-decoration: none" href="https://example.com" target="_blank">Example</a>"`;
@@ -0,0 +1,41 @@
1
+ <script>
2
+ import { computed, defineComponent, h } from "vue";
3
+ const PREVIEW_MAX_LENGTH = 150;
4
+ export const renderWhiteSpace = (text) => {
5
+ if (text.length >= PREVIEW_MAX_LENGTH) {
6
+ return null;
7
+ }
8
+ const whiteSpaceCodes = "\xA0\u200C\u200B\u200D\u200E\u200F\uFEFF";
9
+ return h("div", [whiteSpaceCodes.repeat(PREVIEW_MAX_LENGTH - text.length)]);
10
+ };
11
+ export const EPreview = defineComponent({
12
+ name: "EPreview",
13
+ setup(_, { slots }) {
14
+ const text = computed(() => {
15
+ if (slots.default !== void 0) {
16
+ const children = slots.default()[0]?.children;
17
+ const newText = Array.isArray(children) ? children.join("") : children;
18
+ return newText?.substring(0, PREVIEW_MAX_LENGTH);
19
+ }
20
+ return "";
21
+ });
22
+ return () => {
23
+ return h(
24
+ "div",
25
+ {
26
+ style: {
27
+ display: "none",
28
+ overflow: "hidden",
29
+ lineHeight: "1px",
30
+ opacity: 0,
31
+ maxHeight: 0,
32
+ maxWidth: 0
33
+ }
34
+ },
35
+ [text.value, renderWhiteSpace(text.value)]
36
+ );
37
+ };
38
+ }
39
+ });
40
+ export default EPreview;
41
+ </script>
@@ -0,0 +1,7 @@
1
+ export declare const renderWhiteSpace: (text: string) => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
2
+ [key: string]: any;
3
+ }> | null;
4
+ export declare const EPreview: import("@vue/runtime-core").DefineComponent<{}, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
5
+ [key: string]: any;
6
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
7
+ export default EPreview;
@@ -0,0 +1,5 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`<EPreview> component > renders correctly with array text 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0;">Email preview<div> ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏ ‌​‍‎‏</div></div>"`;
4
+
5
+ exports[`<EPreview> component > renders correctly with really long text 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0;">really longreally longreally longreally longreally longreally longreally longreally longreally longreally longreally longreally longreally longreally </div>"`;
@@ -0,0 +1,31 @@
1
+ <script>
2
+ import { defineComponent, h } from "vue";
3
+ export const ERow = defineComponent({
4
+ name: "ERow",
5
+ setup(_, { slots }) {
6
+ return () => {
7
+ return h(
8
+ "table",
9
+ {
10
+ align: "center",
11
+ width: "100%",
12
+ border: "0",
13
+ cellPadding: "0",
14
+ cellSpacing: "0",
15
+ role: "presentation"
16
+ },
17
+ [h("tbody", {
18
+ style: {
19
+ width: "100%"
20
+ }
21
+ }, [h("tr", {
22
+ style: {
23
+ width: "100%"
24
+ }
25
+ }, slots.default?.())])]
26
+ );
27
+ };
28
+ }
29
+ });
30
+ export default ERow;
31
+ </script>
@@ -0,0 +1,4 @@
1
+ export declare const ERow: import("@vue/runtime-core").DefineComponent<{}, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
2
+ [key: string]: any;
3
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
4
+ export default ERow;
@@ -0,0 +1,23 @@
1
+ <script>
2
+ import { defineComponent, h } from "vue";
3
+ export const ESection = defineComponent({
4
+ name: "ESection",
5
+ setup(_, { slots }) {
6
+ return () => {
7
+ return h(
8
+ "table",
9
+ {
10
+ align: "center",
11
+ width: "100%",
12
+ border: "0",
13
+ cellPadding: "0",
14
+ cellSpacing: "0",
15
+ role: "presentation"
16
+ },
17
+ [h("tbody", [h("tr", [h("td", slots.default?.())])])]
18
+ );
19
+ };
20
+ }
21
+ });
22
+ export default ESection;
23
+ </script>
@@ -0,0 +1,4 @@
1
+ export declare const ESection: import("@vue/runtime-core").DefineComponent<{}, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
2
+ [key: string]: any;
3
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
4
+ export default ESection;
@@ -0,0 +1,18 @@
1
+ <script>
2
+ import { defineComponent, h } from "vue";
3
+ export const EStyle = defineComponent({
4
+ name: "EStyle",
5
+ setup(_, { slots }) {
6
+ return () => {
7
+ return h(
8
+ "style",
9
+ {
10
+ "data-id": "__nuxt-email-style"
11
+ },
12
+ slots.default?.()
13
+ );
14
+ };
15
+ }
16
+ });
17
+ export default EStyle;
18
+ </script>
@@ -0,0 +1,4 @@
1
+ export declare const EStyle: import("@vue/runtime-core").DefineComponent<{}, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
2
+ [key: string]: any;
3
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
4
+ export default EStyle;
@@ -0,0 +1,22 @@
1
+ <script>
2
+ import { defineComponent, h } from "vue";
3
+ export const EText = defineComponent({
4
+ name: "EText",
5
+ setup(_, { slots }) {
6
+ return () => {
7
+ return h(
8
+ "p",
9
+ {
10
+ style: {
11
+ fontSize: "14px",
12
+ lineHeight: "24px",
13
+ margin: "16px 0"
14
+ }
15
+ },
16
+ slots.default?.()
17
+ );
18
+ };
19
+ }
20
+ });
21
+ export default EText;
22
+ </script>
@@ -0,0 +1,4 @@
1
+ export declare const EText: import("@vue/runtime-core").DefineComponent<{}, () => import("@vue/runtime-core").VNode<import("@vue/runtime-core").RendererNode, import("@vue/runtime-core").RendererElement, {
2
+ [key: string]: any;
3
+ }>, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, true, {}, any>;
4
+ export default EText;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { useStorage } from "#imports";
3
+ export default defineEventHandler(async () => {
4
+ try {
5
+ const storage = useStorage("assets:emails");
6
+ const files = await storage.getKeys();
7
+ const emailTemplates = files.filter((file) => file.endsWith(".vue")).map((file) => ({
8
+ name: file.replace(".vue", ""),
9
+ filename: file,
10
+ displayName: file.replace(".vue", "").replace(/([A-Z])/g, " $1").trim()
11
+ })).sort((a, b) => a.displayName.localeCompare(b.displayName));
12
+ return emailTemplates;
13
+ } catch (error) {
14
+ return {
15
+ error: true,
16
+ message: error.message || "Failed to fetch email templates"
17
+ };
18
+ }
19
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
2
+ export default _default;
@@ -0,0 +1,47 @@
1
+ import { useStorage } from "#imports";
2
+ import { defineEventHandler, getQuery, createError } from "h3";
3
+ import { render } from "../../utils/render.js";
4
+ export default defineEventHandler(async (event) => {
5
+ const query = getQuery(event);
6
+ const emailName = query.name;
7
+ if (!emailName) {
8
+ throw createError({
9
+ statusCode: 400,
10
+ statusMessage: "Email name is required. Use ?name=EmailName"
11
+ });
12
+ }
13
+ try {
14
+ const filename = emailName.endsWith(".vue") ? emailName : `${emailName}.vue`;
15
+ const storage = useStorage("assets:emails");
16
+ const source = await storage.getItem(filename);
17
+ if (!source) {
18
+ throw createError({
19
+ statusCode: 404,
20
+ statusMessage: `Email template "${emailName}" not found`
21
+ });
22
+ }
23
+ const templateMatch = source.match(/<template[^>]*>([\s\S]*?)<\/template>/i);
24
+ if (!templateMatch) {
25
+ throw createError({
26
+ statusCode: 500,
27
+ statusMessage: `Email template "${emailName}" has no template block`
28
+ });
29
+ }
30
+ const templateContent = templateMatch[1].trim();
31
+ const component = {
32
+ template: templateContent,
33
+ setup() {
34
+ return {};
35
+ }
36
+ };
37
+ return await render(component);
38
+ } catch (error) {
39
+ if (error.statusCode) {
40
+ throw error;
41
+ }
42
+ throw createError({
43
+ statusCode: 500,
44
+ statusMessage: `Failed to render email: ${error.message || "Unknown error"}`
45
+ });
46
+ }
47
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json",
3
+ }
@@ -0,0 +1 @@
1
+ export declare function cleanup(str: string): string;
@@ -0,0 +1,5 @@
1
+ export function cleanup(str) {
2
+ if (!str)
3
+ return str;
4
+ return str.replace(/ data-v-inspector="[^"]*"/g, "").replace(/<!--\[-->/g, "").replace(/<!--\]-->/g, "").replace(/<!--[\s\S]*?-->/g, "").replace(/<style>(?![\s\S]*@font-face)[\s\S]*?<\/style>/g, "").replace(/<script>[\s\S]*?<\/script>/g, "").replace(/<script[^>]*>[\s\S]*?<\/script>/g, "").replace(/<template>/g, "").replace(/<template[^>]*>/g, "").replace(/<\/template>/g, "").replace(/<\/tailwind-clean-component>/g, "");
5
+ }
@@ -0,0 +1,15 @@
1
+ import type { HtmlToTextOptions } from 'html-to-text';
2
+ export type Options = {
3
+ pretty?: boolean;
4
+ } & ({
5
+ plainText?: false;
6
+ } | {
7
+ plainText?: true;
8
+ /**
9
+ * These are options you can pass down directly to the library we use for
10
+ * converting the rendered email's HTML into plain text.
11
+ *
12
+ * @see https://github.com/html-to-text/node-html-to-text
13
+ */
14
+ htmlToTextOptions?: HtmlToTextOptions;
15
+ });
File without changes
@@ -0,0 +1,2 @@
1
+ import type { SelectorDefinition } from 'html-to-text';
2
+ export declare const plainTextSelectors: SelectorDefinition[];
@@ -0,0 +1,8 @@
1
+ export const plainTextSelectors = [
2
+ { selector: "img", format: "skip" },
3
+ { selector: "#__vue-email-preview", format: "skip" },
4
+ {
5
+ selector: "a",
6
+ options: { linkBrackets: false }
7
+ }
8
+ ];
@@ -0,0 +1 @@
1
+ export declare const pretty: (str: string, options?: {}) => string;
@@ -0,0 +1,11 @@
1
+ import jsBeautify from "js-beautify";
2
+ const defaults = {
3
+ unformatted: ["code", "pre", "em", "strong", "span"],
4
+ indent_inner_html: true,
5
+ indent_char: " ",
6
+ indent_size: 2,
7
+ sep: "\n"
8
+ };
9
+ export const pretty = (str, options = {}) => {
10
+ return jsBeautify.html(str, { ...defaults, ...options });
11
+ };
@@ -0,0 +1,14 @@
1
+ import type { AllowedComponentProps, Component, VNodeProps } from 'vue';
2
+ import type { Options } from './options.js';
3
+ export type ExtractComponentProps<TComponent> = TComponent extends new () => {
4
+ $props: infer P;
5
+ } ? Omit<P, keyof VNodeProps | keyof AllowedComponentProps> : never;
6
+ export interface VNode {
7
+ type: string;
8
+ props: {
9
+ style?: Record<string, string | number>;
10
+ children?: string | VNode | VNode[];
11
+ [prop: string]: unknown;
12
+ };
13
+ }
14
+ export declare function render<T extends Component>(component: T, props?: ExtractComponentProps<T>, options?: Options): Promise<string>;
@@ -0,0 +1,30 @@
1
+ import { renderToString } from "vue/server-renderer";
2
+ import { createSSRApp } from "vue";
3
+ import { convert } from "html-to-text";
4
+ import { pretty } from "./pretty.js";
5
+ import { plainTextSelectors } from "./plainTextSelectors.js";
6
+ import { cleanup } from "./cleanup.js";
7
+ import { emailComponents } from "../../components/index.js";
8
+ async function registerEmailComponents(app) {
9
+ for (const [name, componentImporter] of Object.entries(emailComponents)) {
10
+ const component = await componentImporter();
11
+ app.component(name, component.default);
12
+ }
13
+ }
14
+ export async function render(component, props, options) {
15
+ const doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
16
+ const App = createSSRApp(component, props || {});
17
+ await registerEmailComponents(App);
18
+ const markup = await renderToString(App);
19
+ if (options?.plainText) {
20
+ return convert(markup, {
21
+ selectors: plainTextSelectors,
22
+ ...options?.plainText === true ? options.htmlToTextOptions : {}
23
+ });
24
+ }
25
+ const doc = `${doctype}${cleanup(markup)}`;
26
+ if (options && options.pretty) {
27
+ return pretty(doc);
28
+ }
29
+ return doc;
30
+ }
@@ -0,0 +1,3 @@
1
+ export { default } from './module.mjs'
2
+
3
+ export { type ModuleOptions } from './module.mjs'
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "nuxt-email-renderer",
3
+ "version": "0.0.1",
4
+ "description": "Nuxt email module for rendering HTML emails with Vue components",
5
+ "repository": "mokkapps/nuxt-email",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types.d.mts",
11
+ "import": "./dist/module.mjs"
12
+ }
13
+ },
14
+ "main": "./dist/module.mjs",
15
+ "typesVersions": {
16
+ "*": {
17
+ ".": [
18
+ "./dist/types.d.mts"
19
+ ]
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "prepack": "nuxt-module-build && npm run client:build",
27
+ "client:build": "nuxi generate client",
28
+ "client:dev": "nuxi dev client --port 3300",
29
+ "dev": "npm run play:dev",
30
+ "dev:prepare": "nuxt-module-build --stub && nuxi prepare client",
31
+ "prepare": "nuxi prepare client",
32
+ "play:dev": "nuxi dev playground",
33
+ "play:prod": "npm run prepack && nuxi dev playground",
34
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
35
+ "lint": "eslint .",
36
+ "lint:fix": "eslint . --fix",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest watch"
39
+ },
40
+ "dependencies": {
41
+ "@nuxt/devtools-kit": "^2.6.5",
42
+ "@nuxt/kit": "^4.1.2",
43
+ "@vitejs/plugin-vue": "^6.0.1",
44
+ "@vue/compiler-dom": "^3.5.21",
45
+ "@vue/compiler-sfc": "^3.5.21",
46
+ "html-to-text": "^9.0.5",
47
+ "js-beautify": "^1.15.4",
48
+ "shiki": "^3.13.0",
49
+ "zod": "^4.1.11"
50
+ },
51
+ "devDependencies": {
52
+ "@nuxt/devtools": "^2.6.5",
53
+ "@nuxt/devtools-ui-kit": "^2.6.5",
54
+ "@nuxt/eslint-config": "^1.9.0",
55
+ "@nuxt/module-builder": "^1.0.2",
56
+ "@nuxt/schema": "^4.1.2",
57
+ "@nuxt/test-utils": "^3.19.2",
58
+ "@types/html-to-text": "^9.0.4",
59
+ "@types/js-beautify": "^1.14.3",
60
+ "@types/node": "latest",
61
+ "changelogen": "^0.6.2",
62
+ "eslint": "^9.36.0",
63
+ "jsdom": "^27.0.0",
64
+ "nuxt": "4.1.2",
65
+ "typescript": "~5.9.2",
66
+ "vitest": "^3.2.4",
67
+ "vue-tsc": "^3.0.8"
68
+ },
69
+ "packageManager": "pnpm@10.16.1"
70
+ }