@lupinum/nuxt-email 0.1.0

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 (159) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +172 -0
  4. package/THIRD_PARTY_NOTICES +75 -0
  5. package/dist/chunks/setup.mjs +149 -0
  6. package/dist/module.d.mts +15 -0
  7. package/dist/module.json +12 -0
  8. package/dist/module.mjs +300 -0
  9. package/dist/runtime/code-block/create-component.d.ts +16 -0
  10. package/dist/runtime/code-block/create-component.js +106 -0
  11. package/dist/runtime/components/EBody.d.ts +4 -0
  12. package/dist/runtime/components/EBody.js +75 -0
  13. package/dist/runtime/components/EButton.d.ts +11 -0
  14. package/dist/runtime/components/EButton.js +89 -0
  15. package/dist/runtime/components/EButton.padding.d.ts +12 -0
  16. package/dist/runtime/components/EButton.padding.js +118 -0
  17. package/dist/runtime/components/ECodeInline.d.ts +13 -0
  18. package/dist/runtime/components/ECodeInline.js +43 -0
  19. package/dist/runtime/components/EColumn.d.ts +4 -0
  20. package/dist/runtime/components/EColumn.js +12 -0
  21. package/dist/runtime/components/EContainer.d.ts +4 -0
  22. package/dist/runtime/components/EContainer.js +35 -0
  23. package/dist/runtime/components/EFont.d.ts +24 -0
  24. package/dist/runtime/components/EFont.js +124 -0
  25. package/dist/runtime/components/EHead.d.ts +4 -0
  26. package/dist/runtime/components/EHead.js +17 -0
  27. package/dist/runtime/components/EHeading.d.ts +7 -0
  28. package/dist/runtime/components/EHeading.js +23 -0
  29. package/dist/runtime/components/EHr.d.ts +4 -0
  30. package/dist/runtime/components/EHr.js +26 -0
  31. package/dist/runtime/components/EHtml.d.ts +4 -0
  32. package/dist/runtime/components/EHtml.js +17 -0
  33. package/dist/runtime/components/EImg.d.ts +7 -0
  34. package/dist/runtime/components/EImg.js +44 -0
  35. package/dist/runtime/components/ELink.d.ts +6 -0
  36. package/dist/runtime/components/ELink.js +35 -0
  37. package/dist/runtime/components/EMarkdown.d.ts +8 -0
  38. package/dist/runtime/components/EMarkdown.js +64 -0
  39. package/dist/runtime/components/EPreview.d.ts +8 -0
  40. package/dist/runtime/components/EPreview.js +85 -0
  41. package/dist/runtime/components/ERow.d.ts +4 -0
  42. package/dist/runtime/components/ERow.js +53 -0
  43. package/dist/runtime/components/ESection.d.ts +4 -0
  44. package/dist/runtime/components/ESection.js +35 -0
  45. package/dist/runtime/components/ETailwind.d.ts +24 -0
  46. package/dist/runtime/components/ETailwind.js +49 -0
  47. package/dist/runtime/components/EText.d.ts +4 -0
  48. package/dist/runtime/components/EText.js +20 -0
  49. package/dist/runtime/components/EText.margins.d.ts +18 -0
  50. package/dist/runtime/components/EText.margins.js +81 -0
  51. package/dist/runtime/components/attributes.d.ts +4 -0
  52. package/dist/runtime/components/attributes.js +11 -0
  53. package/dist/runtime/components/email-component-names.d.ts +2 -0
  54. package/dist/runtime/components/email-component-names.js +20 -0
  55. package/dist/runtime/components/email-component-registry.d.ts +8 -0
  56. package/dist/runtime/components/email-component-registry.js +2 -0
  57. package/dist/runtime/components/index.d.ts +23 -0
  58. package/dist/runtime/components/index.js +18 -0
  59. package/dist/runtime/components/markdown/parse-css-in-js-to-inline-css.d.ts +2 -0
  60. package/dist/runtime/components/markdown/parse-css-in-js-to-inline-css.js +60 -0
  61. package/dist/runtime/components/markdown/render-markdown.d.ts +2 -0
  62. package/dist/runtime/components/markdown/render-markdown.js +137 -0
  63. package/dist/runtime/components/markdown/styles.d.ts +30 -0
  64. package/dist/runtime/components/markdown/styles.js +91 -0
  65. package/dist/runtime/components/presentation-table.d.ts +7 -0
  66. package/dist/runtime/components/presentation-table.js +11 -0
  67. package/dist/runtime/components/style.d.ts +5 -0
  68. package/dist/runtime/components/style.js +32 -0
  69. package/dist/runtime/components/table-padding.d.ts +6 -0
  70. package/dist/runtime/components/table-padding.js +20 -0
  71. package/dist/runtime/define-email.d.ts +2 -0
  72. package/dist/runtime/define-email.js +5 -0
  73. package/dist/runtime/dev-preview/page-script.d.ts +1 -0
  74. package/dist/runtime/dev-preview/page-script.js +403 -0
  75. package/dist/runtime/dev-preview/page.css.d.ts +1 -0
  76. package/dist/runtime/dev-preview/page.css.js +602 -0
  77. package/dist/runtime/dev-preview/page.get.d.ts +4 -0
  78. package/dist/runtime/dev-preview/page.get.js +119 -0
  79. package/dist/runtime/dev-preview/render.get.d.ts +3 -0
  80. package/dist/runtime/dev-preview/render.get.js +123 -0
  81. package/dist/runtime/dev-preview/templates.get.d.ts +7 -0
  82. package/dist/runtime/dev-preview/templates.get.js +14 -0
  83. package/dist/runtime/errors.d.ts +4 -0
  84. package/dist/runtime/errors.js +7 -0
  85. package/dist/runtime/render/define-email.d.ts +56 -0
  86. package/dist/runtime/render/define-email.js +40 -0
  87. package/dist/runtime/render/document.d.ts +4 -0
  88. package/dist/runtime/render/document.js +75 -0
  89. package/dist/runtime/render/errors.d.ts +4 -0
  90. package/dist/runtime/render/errors.js +8 -0
  91. package/dist/runtime/render/plain-text.d.ts +1 -0
  92. package/dist/runtime/render/plain-text.js +15 -0
  93. package/dist/runtime/render/render-component.d.ts +4 -0
  94. package/dist/runtime/render/render-component.js +46 -0
  95. package/dist/runtime/render/render-email-component.d.ts +16 -0
  96. package/dist/runtime/render/render-email-component.js +46 -0
  97. package/dist/runtime/render/types.d.ts +9 -0
  98. package/dist/runtime/render/types.js +0 -0
  99. package/dist/runtime/tailwind/engine/compatibility/escape-class-name.d.ts +8 -0
  100. package/dist/runtime/tailwind/engine/compatibility/escape-class-name.js +10 -0
  101. package/dist/runtime/tailwind/engine/compatibility/sanitize-class-name.d.ts +7 -0
  102. package/dist/runtime/tailwind/engine/compatibility/sanitize-class-name.js +17 -0
  103. package/dist/runtime/tailwind/engine/compatibility/unescape-class.d.ts +1 -0
  104. package/dist/runtime/tailwind/engine/compatibility/unescape-class.js +3 -0
  105. package/dist/runtime/tailwind/engine/css/downlevel-for-email-clients.d.ts +63 -0
  106. package/dist/runtime/tailwind/engine/css/downlevel-for-email-clients.js +107 -0
  107. package/dist/runtime/tailwind/engine/css/extract-rules-per-class.d.ts +6 -0
  108. package/dist/runtime/tailwind/engine/css/extract-rules-per-class.js +54 -0
  109. package/dist/runtime/tailwind/engine/css/get-css-property.d.ts +17 -0
  110. package/dist/runtime/tailwind/engine/css/get-css-property.js +3 -0
  111. package/dist/runtime/tailwind/engine/css/get-custom-properties.d.ts +8 -0
  112. package/dist/runtime/tailwind/engine/css/get-custom-properties.js +37 -0
  113. package/dist/runtime/tailwind/engine/css/is-part-inlinable.d.ts +2 -0
  114. package/dist/runtime/tailwind/engine/css/is-part-inlinable.js +9 -0
  115. package/dist/runtime/tailwind/engine/css/is-rule-inlinable.d.ts +2 -0
  116. package/dist/runtime/tailwind/engine/css/is-rule-inlinable.js +9 -0
  117. package/dist/runtime/tailwind/engine/css/make-inline-styles-for.d.ts +21 -0
  118. package/dist/runtime/tailwind/engine/css/make-inline-styles-for.js +62 -0
  119. package/dist/runtime/tailwind/engine/css/resolve-all-css-variables.d.ts +8 -0
  120. package/dist/runtime/tailwind/engine/css/resolve-all-css-variables.js +138 -0
  121. package/dist/runtime/tailwind/engine/css/resolve-calc-expressions.d.ts +5 -0
  122. package/dist/runtime/tailwind/engine/css/resolve-calc-expressions.js +101 -0
  123. package/dist/runtime/tailwind/engine/css/sanitize-declarations.d.ts +15 -0
  124. package/dist/runtime/tailwind/engine/css/sanitize-declarations.js +358 -0
  125. package/dist/runtime/tailwind/engine/css/sanitize-non-inlinable-rules.d.ts +17 -0
  126. package/dist/runtime/tailwind/engine/css/sanitize-non-inlinable-rules.js +30 -0
  127. package/dist/runtime/tailwind/engine/css/split-mixed-rule.d.ts +12 -0
  128. package/dist/runtime/tailwind/engine/css/split-mixed-rule.js +37 -0
  129. package/dist/runtime/tailwind/engine/css/strip-empty-tailwind-vars.d.ts +19 -0
  130. package/dist/runtime/tailwind/engine/css/strip-empty-tailwind-vars.js +44 -0
  131. package/dist/runtime/tailwind/engine/css/unwrap-value.d.ts +2 -0
  132. package/dist/runtime/tailwind/engine/css/unwrap-value.js +6 -0
  133. package/dist/runtime/tailwind/engine/index.d.ts +63 -0
  134. package/dist/runtime/tailwind/engine/index.js +53 -0
  135. package/dist/runtime/tailwind/engine/pixel-based-preset.d.ts +9 -0
  136. package/dist/runtime/tailwind/engine/pixel-based-preset.js +58 -0
  137. package/dist/runtime/tailwind/engine/sanitize-stylesheet.d.ts +10 -0
  138. package/dist/runtime/tailwind/engine/sanitize-stylesheet.js +8 -0
  139. package/dist/runtime/tailwind/engine/setup-tailwind.d.ts +23 -0
  140. package/dist/runtime/tailwind/engine/setup-tailwind.js +98 -0
  141. package/dist/runtime/tailwind/engine/stylesheets.d.ts +4 -0
  142. package/dist/runtime/tailwind/engine/stylesheets.js +1756 -0
  143. package/dist/runtime/tailwind/engine/types.d.ts +25 -0
  144. package/dist/runtime/tailwind/engine/types.js +0 -0
  145. package/dist/runtime/tailwind/errors.d.ts +7 -0
  146. package/dist/runtime/tailwind/errors.js +9 -0
  147. package/dist/runtime/tailwind/inline-utils.d.ts +19 -0
  148. package/dist/runtime/tailwind/inline-utils.js +24 -0
  149. package/dist/runtime/tailwind/nested.d.ts +59 -0
  150. package/dist/runtime/tailwind/nested.js +47 -0
  151. package/dist/runtime/tailwind/post-render.d.ts +7 -0
  152. package/dist/runtime/tailwind/post-render.js +156 -0
  153. package/dist/runtime/template-registry/errors.d.ts +5 -0
  154. package/dist/runtime/template-registry/errors.js +11 -0
  155. package/dist/runtime/template-registry/registry.d.ts +13 -0
  156. package/dist/runtime/testing/index.d.ts +13 -0
  157. package/dist/runtime/testing/index.js +2 -0
  158. package/dist/types.d.mts +5 -0
  159. package/package.json +122 -0
@@ -0,0 +1,118 @@
1
+ import { normalizeEmailStyle } from "./style.js";
2
+ export function convertToPixels(value) {
3
+ if (typeof value === "number") {
4
+ if (!Number.isFinite(value) || value < 0) {
5
+ throw new TypeError(`EButton padding must be a finite non-negative value; received ${String(value)}`);
6
+ }
7
+ return value;
8
+ }
9
+ if (typeof value !== "string") {
10
+ throw new TypeError(`EButton padding must be a number or CSS length string; received ${String(value)}`);
11
+ }
12
+ const normalizedValue = value.trim();
13
+ if (normalizedValue === "0") {
14
+ return 0;
15
+ }
16
+ const matches = /^(\d+(?:\.\d+)?|\.\d+)(px|em|rem|%)$/.exec(normalizedValue);
17
+ if (!matches) {
18
+ throw new TypeError(
19
+ `EButton padding supports only non-negative px, em, rem, and % values; received ${value}`
20
+ );
21
+ }
22
+ const amount = Number.parseFloat(matches[1]);
23
+ if (!Number.isFinite(amount)) {
24
+ throw new TypeError(`EButton padding must resolve to finite pixels; received ${value}`);
25
+ }
26
+ switch (matches[2]) {
27
+ case "em":
28
+ case "rem":
29
+ return amount * 16;
30
+ case "%":
31
+ return amount / 100 * 600;
32
+ default:
33
+ return amount;
34
+ }
35
+ }
36
+ function expandPadding(value) {
37
+ if (typeof value === "number") {
38
+ return {
39
+ paddingTop: value,
40
+ paddingBottom: value,
41
+ paddingLeft: value,
42
+ paddingRight: value
43
+ };
44
+ }
45
+ if (typeof value === "string") {
46
+ const values = value.trim().split(/\s+/);
47
+ if (values.length === 1) {
48
+ return {
49
+ paddingTop: values[0],
50
+ paddingBottom: values[0],
51
+ paddingLeft: values[0],
52
+ paddingRight: values[0]
53
+ };
54
+ }
55
+ if (values.length === 2) {
56
+ return {
57
+ paddingTop: values[0],
58
+ paddingRight: values[1],
59
+ paddingBottom: values[0],
60
+ paddingLeft: values[1]
61
+ };
62
+ }
63
+ if (values.length === 3) {
64
+ return {
65
+ paddingTop: values[0],
66
+ paddingRight: values[1],
67
+ paddingBottom: values[2],
68
+ paddingLeft: values[1]
69
+ };
70
+ }
71
+ if (values.length === 4) {
72
+ return {
73
+ paddingTop: values[0],
74
+ paddingRight: values[1],
75
+ paddingBottom: values[2],
76
+ paddingLeft: values[3]
77
+ };
78
+ }
79
+ }
80
+ throw new TypeError(`EButton padding shorthand must contain one to four values; received ${String(value)}`);
81
+ }
82
+ function convertOptionalPadding(value) {
83
+ return value === void 0 ? void 0 : convertToPixels(value);
84
+ }
85
+ export function parseButtonPadding(style) {
86
+ let paddingTop;
87
+ let paddingRight;
88
+ let paddingBottom;
89
+ let paddingLeft;
90
+ for (const [property, value] of Object.entries(normalizeEmailStyle(style) ?? {})) {
91
+ if (property === "padding") {
92
+ ({ paddingTop, paddingRight, paddingBottom, paddingLeft } = expandPadding(value));
93
+ } else if (property === "paddingTop") {
94
+ paddingTop = value;
95
+ } else if (property === "paddingRight") {
96
+ paddingRight = value;
97
+ } else if (property === "paddingBottom") {
98
+ paddingBottom = value;
99
+ } else if (property === "paddingLeft") {
100
+ paddingLeft = value;
101
+ }
102
+ }
103
+ return {
104
+ paddingTop: convertOptionalPadding(paddingTop),
105
+ paddingRight: convertOptionalPadding(paddingRight),
106
+ paddingBottom: convertOptionalPadding(paddingBottom),
107
+ paddingLeft: convertOptionalPadding(paddingLeft)
108
+ };
109
+ }
110
+ export function pixelsToPoints(pixels) {
111
+ return typeof pixels === "number" && !Number.isNaN(Number(pixels)) ? pixels * 3 / 4 : void 0;
112
+ }
113
+ export function pixelStyle(value) {
114
+ if (value === void 0 || value === 0) {
115
+ return value;
116
+ }
117
+ return `${value}px`;
118
+ }
@@ -0,0 +1,13 @@
1
+ import type { DefineComponent, HTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type ECodeInlineProps = SafeEmailAttributes<HTMLAttributes>;
4
+ /**
5
+ * Byte-identical to React Email's Orange.fr fix-up `<style>` (see
6
+ * code-inline.tsx). Exported so conformance can assert the exact bytes.
7
+ *
8
+ * On the Orange.fr email client the head/html elements are removed, turning
9
+ * the meta tag into a sibling; the `meta ~` selectors then swap which copy of
10
+ * the children is visible.
11
+ */
12
+ export declare const ORANGE_FR_STYLE = "\n meta ~ .cino {\n display: none !important;\n opacity: 0 !important;\n }\n\n meta ~ .cio {\n display: block !important;\n }\n ";
13
+ export declare const ECodeInline: DefineComponent<ECodeInlineProps>;
@@ -0,0 +1,43 @@
1
+ import { defineComponent, h } from "vue";
2
+ import { assertSafeEmailAttributes } from "./attributes.js";
3
+ import { mergeEmailStyles } from "./style.js";
4
+ export const ORANGE_FR_STYLE = `
5
+ meta ~ .cino {
6
+ display: none !important;
7
+ opacity: 0 !important;
8
+ }
9
+
10
+ meta ~ .cio {
11
+ display: block !important;
12
+ }
13
+ `;
14
+ export const ECodeInline = defineComponent({
15
+ name: "ECodeInline",
16
+ inheritAttrs: false,
17
+ setup(_props, { attrs, slots }) {
18
+ return () => {
19
+ assertSafeEmailAttributes("ECodeInline", attrs);
20
+ const { class: className, style, ...attributes } = attrs;
21
+ const userClass = typeof className === "string" && className ? className : "";
22
+ const codeProps = {
23
+ ...attributes,
24
+ class: `${userClass} cino`
25
+ };
26
+ if (style !== void 0) {
27
+ codeProps.style = style;
28
+ }
29
+ return [
30
+ h("style", ORANGE_FR_STYLE),
31
+ // Does not render on Orange.fr
32
+ h("code", codeProps, slots.default?.()),
33
+ // Renders only on Orange.fr
34
+ h("span", {
35
+ ...attributes,
36
+ "class": `${userClass} cio`,
37
+ "style": mergeEmailStyles({ display: "none" }, style),
38
+ "data-skip-in-text": "true"
39
+ }, slots.default?.())
40
+ ];
41
+ };
42
+ }
43
+ });
@@ -0,0 +1,4 @@
1
+ import type { DefineComponent, TdHTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type EColumnProps = SafeEmailAttributes<TdHTMLAttributes>;
4
+ export declare const EColumn: DefineComponent<EColumnProps>;
@@ -0,0 +1,12 @@
1
+ import { defineComponent, h } from "vue";
2
+ import { assertSafeEmailAttributes } from "./attributes.js";
3
+ export const EColumn = defineComponent({
4
+ name: "EColumn",
5
+ inheritAttrs: false,
6
+ setup(_props, { attrs, slots }) {
7
+ return () => {
8
+ assertSafeEmailAttributes("EColumn", attrs);
9
+ return h("td", attrs, slots.default?.());
10
+ };
11
+ }
12
+ });
@@ -0,0 +1,4 @@
1
+ import type { DefineComponent, TableHTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type EContainerProps = Omit<SafeEmailAttributes<TableHTMLAttributes>, 'border' | 'cellpadding' | 'cellspacing' | 'role'>;
4
+ export declare const EContainer: DefineComponent<EContainerProps>;
@@ -0,0 +1,35 @@
1
+ import { defineComponent, h, inject } from "vue";
2
+ import { resolveNestedTailwindStyle, TAILWIND_NESTED_KEY } from "../tailwind/nested.js";
3
+ import { assertSafeEmailAttributes } from "./attributes.js";
4
+ import { assertFixedPresentationTable } from "./presentation-table.js";
5
+ import { splitTablePadding } from "./table-padding.js";
6
+ export const EContainer = defineComponent({
7
+ name: "EContainer",
8
+ inheritAttrs: false,
9
+ setup(_props, { attrs, slots }) {
10
+ const holder = inject(TAILWIND_NESTED_KEY, null);
11
+ return () => {
12
+ assertSafeEmailAttributes("EContainer", attrs);
13
+ assertFixedPresentationTable("EContainer", attrs);
14
+ const { style, ...attributes } = attrs;
15
+ const effectiveStyle = resolveNestedTailwindStyle(holder, attributes, style).style;
16
+ const { tableStyle, cellStyle } = splitTablePadding(effectiveStyle);
17
+ return h("table", {
18
+ align: "center",
19
+ width: "100%",
20
+ ...attributes,
21
+ border: 0,
22
+ cellpadding: "0",
23
+ cellspacing: "0",
24
+ role: "presentation",
25
+ style: { maxWidth: "37.5em", ...tableStyle }
26
+ }, [
27
+ h("tbody", [
28
+ h("tr", { style: { width: "100%" } }, [
29
+ h("td", Object.keys(cellStyle).length > 0 ? { style: cellStyle } : {}, slots.default?.())
30
+ ])
31
+ ])
32
+ ]);
33
+ };
34
+ }
35
+ });
@@ -0,0 +1,24 @@
1
+ import type { DefineComponent } from 'vue';
2
+ export type FontFallback = 'Arial' | 'Helvetica' | 'Verdana' | 'Georgia' | 'Times New Roman' | 'serif' | 'sans-serif' | 'monospace' | 'cursive' | 'fantasy';
3
+ export type FontFormat = 'woff' | 'woff2' | 'truetype' | 'opentype' | 'embedded-opentype' | 'svg';
4
+ export interface FontWebFont {
5
+ url: string;
6
+ format: FontFormat;
7
+ }
8
+ export type FontStyle = 'normal' | 'italic' | 'oblique';
9
+ export type FontWeight = number | 'normal' | 'bold' | 'bolder' | 'lighter';
10
+ export type FontFallbackList = readonly [FontFallback, ...FontFallback[]];
11
+ export interface EFontProps {
12
+ /** The font you want to use. Do not insert multiple fonts here, use fallbackFontFamily for that. */
13
+ fontFamily: string;
14
+ /** A non-empty array is possible; the order of the array is the priority order. */
15
+ fallbackFontFamily: FontFallback | FontFallbackList;
16
+ /** Web font source; not all clients support web fonts. */
17
+ webFont?: FontWebFont;
18
+ /** Default: 'normal' */
19
+ fontStyle?: FontStyle;
20
+ /** Default: 400 */
21
+ fontWeight?: FontWeight;
22
+ }
23
+ /** The component MUST be placed inside the <head> tag. */
24
+ export declare const EFont: DefineComponent<EFontProps>;
@@ -0,0 +1,124 @@
1
+ import { defineComponent, h } from "vue";
2
+ const FONT_FALLBACKS = /* @__PURE__ */ new Set([
3
+ "Arial",
4
+ "Helvetica",
5
+ "Verdana",
6
+ "Georgia",
7
+ "Times New Roman",
8
+ "serif",
9
+ "sans-serif",
10
+ "monospace",
11
+ "cursive",
12
+ "fantasy"
13
+ ]);
14
+ const FONT_FORMATS = /* @__PURE__ */ new Set([
15
+ "woff",
16
+ "woff2",
17
+ "truetype",
18
+ "opentype",
19
+ "embedded-opentype",
20
+ "svg"
21
+ ]);
22
+ const FONT_STYLES = /* @__PURE__ */ new Set(["normal", "italic", "oblique"]);
23
+ const FONT_WEIGHTS = /* @__PURE__ */ new Set(["normal", "bold", "bolder", "lighter"]);
24
+ const SAFE_UNQUOTED_URL = /^[\w\-.~:/?#[\]@!$&*+,;=%]+$/;
25
+ function cssString(value) {
26
+ return value.replace(/[\\'\n\r\f\0<>]/g, (character) => {
27
+ switch (character) {
28
+ case "\\":
29
+ return "\\\\";
30
+ case "'":
31
+ return "\\'";
32
+ case "\n":
33
+ case "\r":
34
+ case "\f":
35
+ return "\\A ";
36
+ case "\0":
37
+ return "\\FFFD ";
38
+ case "<":
39
+ return "\\3C ";
40
+ case ">":
41
+ return "\\3E ";
42
+ default:
43
+ return character;
44
+ }
45
+ });
46
+ }
47
+ function cssUrl(value) {
48
+ return SAFE_UNQUOTED_URL.test(value) ? value : `'${cssString(value)}'`;
49
+ }
50
+ function assertValidFontProps(props) {
51
+ if (props.fontFamily.trim().length === 0) {
52
+ throw new TypeError("EFont fontFamily must be a non-empty string");
53
+ }
54
+ const fallbacks = Array.isArray(props.fallbackFontFamily) ? props.fallbackFontFamily : [props.fallbackFontFamily];
55
+ if (fallbacks.length === 0) {
56
+ throw new TypeError("EFont fallbackFontFamily must contain at least one fallback");
57
+ }
58
+ const invalidFallback = fallbacks.find((fallback) => !FONT_FALLBACKS.has(fallback));
59
+ if (invalidFallback !== void 0) {
60
+ throw new TypeError(`EFont fallbackFontFamily contains unsupported fallback ${JSON.stringify(invalidFallback)}`);
61
+ }
62
+ if (!FONT_STYLES.has(props.fontStyle ?? "normal")) {
63
+ throw new TypeError(`EFont fontStyle must be normal, italic, or oblique; received ${JSON.stringify(props.fontStyle)}`);
64
+ }
65
+ const weight = props.fontWeight ?? 400;
66
+ if (typeof weight === "number" ? !Number.isFinite(weight) || weight < 1 || weight > 1e3 : !FONT_WEIGHTS.has(weight)) {
67
+ throw new TypeError(`EFont fontWeight must be between 1 and 1000 or a supported keyword; received ${JSON.stringify(weight)}`);
68
+ }
69
+ if (props.webFont !== void 0) {
70
+ if (props.webFont.url.trim().length === 0) {
71
+ throw new TypeError("EFont webFont.url must be a non-empty string");
72
+ }
73
+ if (!FONT_FORMATS.has(props.webFont.format)) {
74
+ throw new TypeError(`EFont webFont.format is unsupported: ${JSON.stringify(props.webFont.format)}`);
75
+ }
76
+ }
77
+ }
78
+ export const EFont = defineComponent({
79
+ name: "EFont",
80
+ inheritAttrs: false,
81
+ props: {
82
+ fontFamily: {
83
+ type: String,
84
+ required: true
85
+ },
86
+ fallbackFontFamily: {
87
+ type: [String, Array],
88
+ required: true
89
+ },
90
+ webFont: {
91
+ type: Object,
92
+ default: void 0
93
+ },
94
+ fontStyle: {
95
+ type: String,
96
+ default: "normal"
97
+ },
98
+ fontWeight: {
99
+ type: [String, Number],
100
+ default: 400
101
+ }
102
+ },
103
+ setup(props) {
104
+ return () => {
105
+ assertValidFontProps(props);
106
+ const fallbacks = Array.isArray(props.fallbackFontFamily) ? props.fallbackFontFamily : [props.fallbackFontFamily];
107
+ const src = props.webFont ? `src: url(${cssUrl(props.webFont.url)}) format('${props.webFont.format}');` : "";
108
+ const style = `
109
+ @font-face {
110
+ font-family: '${cssString(props.fontFamily)}';
111
+ font-style: ${props.fontStyle};
112
+ font-weight: ${props.fontWeight};
113
+ mso-font-alt: '${fallbacks[0]}';
114
+ ${src}
115
+ }
116
+
117
+ * {
118
+ font-family: '${cssString(props.fontFamily)}', ${fallbacks.join(", ")};
119
+ }
120
+ `;
121
+ return h("style", { innerHTML: style });
122
+ };
123
+ }
124
+ });
@@ -0,0 +1,4 @@
1
+ import type { DefineComponent, HTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type EHeadProps = SafeEmailAttributes<HTMLAttributes>;
4
+ export declare const EHead: DefineComponent<EHeadProps>;
@@ -0,0 +1,17 @@
1
+ import { defineComponent, h } from "vue";
2
+ import { assertSafeEmailAttributes } from "./attributes.js";
3
+ export const EHead = defineComponent({
4
+ name: "EHead",
5
+ inheritAttrs: false,
6
+ setup(_props, { attrs, slots }) {
7
+ return () => {
8
+ assertSafeEmailAttributes("EHead", attrs);
9
+ const children = slots.default?.() ?? [];
10
+ return h("head", attrs, [
11
+ h("meta", { "content": "text/html; charset=UTF-8", "http-equiv": "Content-Type" }),
12
+ h("meta", { name: "x-apple-disable-message-reformatting" }),
13
+ ...children
14
+ ]);
15
+ };
16
+ }
17
+ });
@@ -0,0 +1,7 @@
1
+ import type { DefineComponent, HTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
4
+ export type EHeadingProps = SafeEmailAttributes<HTMLAttributes> & {
5
+ as?: HeadingTag;
6
+ };
7
+ export declare const EHeading: DefineComponent<EHeadingProps>;
@@ -0,0 +1,23 @@
1
+ import { defineComponent, h } from "vue";
2
+ import { assertSafeEmailAttributes } from "./attributes.js";
3
+ const HEADING_TAGS = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
4
+ export const EHeading = defineComponent({
5
+ name: "EHeading",
6
+ inheritAttrs: false,
7
+ props: {
8
+ as: {
9
+ type: String,
10
+ default: "h1"
11
+ }
12
+ },
13
+ setup(props, { attrs, slots }) {
14
+ return () => {
15
+ assertSafeEmailAttributes("EHeading", attrs);
16
+ const tag = props.as ?? "h1";
17
+ if (!HEADING_TAGS.has(tag)) {
18
+ throw new TypeError(`EHeading as must be one of ${[...HEADING_TAGS].join(", ")}; received ${String(tag)}`);
19
+ }
20
+ return h(tag, attrs, slots.default?.());
21
+ };
22
+ }
23
+ });
@@ -0,0 +1,4 @@
1
+ import type { DefineComponent, HTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type EHrProps = SafeEmailAttributes<HTMLAttributes>;
4
+ export declare const EHr: DefineComponent<EHrProps>;
@@ -0,0 +1,26 @@
1
+ import { defineComponent, h, inject } from "vue";
2
+ import { resolveNestedTailwindStyle, TAILWIND_NESTED_KEY } from "../tailwind/nested.js";
3
+ import { assertSafeEmailAttributes } from "./attributes.js";
4
+ import { mergeEmailStyles } from "./style.js";
5
+ const DEFAULT_HR_STYLE = {
6
+ width: "100%",
7
+ border: "none",
8
+ borderColor: "transparent",
9
+ borderTop: "1px solid #eaeaea"
10
+ };
11
+ export const EHr = defineComponent({
12
+ name: "EHr",
13
+ inheritAttrs: false,
14
+ setup(_props, { attrs }) {
15
+ const holder = inject(TAILWIND_NESTED_KEY, null);
16
+ return () => {
17
+ assertSafeEmailAttributes("EHr", attrs);
18
+ const { style, ...attributes } = attrs;
19
+ const effectiveStyle = resolveNestedTailwindStyle(holder, attributes, style).style;
20
+ return h("hr", {
21
+ ...attributes,
22
+ style: mergeEmailStyles(DEFAULT_HR_STYLE, effectiveStyle)
23
+ });
24
+ };
25
+ }
26
+ });
@@ -0,0 +1,4 @@
1
+ import type { DefineComponent, HTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type EHtmlProps = SafeEmailAttributes<HTMLAttributes>;
4
+ export declare const EHtml: DefineComponent<EHtmlProps>;
@@ -0,0 +1,17 @@
1
+ import { defineComponent, h } from "vue";
2
+ import { assertSafeEmailAttributes } from "./attributes.js";
3
+ export const EHtml = defineComponent({
4
+ name: "EHtml",
5
+ inheritAttrs: false,
6
+ setup(_props, { attrs, slots }) {
7
+ return () => {
8
+ assertSafeEmailAttributes("EHtml", attrs);
9
+ const { dir = "ltr", lang = "en", ...attributes } = attrs;
10
+ return h("html", {
11
+ ...attributes,
12
+ dir,
13
+ lang
14
+ }, slots.default?.());
15
+ };
16
+ }
17
+ });
@@ -0,0 +1,7 @@
1
+ import type { DefineComponent, ImgHTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type EImgProps = Omit<SafeEmailAttributes<ImgHTMLAttributes>, 'alt' | 'src'> & {
4
+ alt: string;
5
+ src: string;
6
+ };
7
+ export declare const EImg: DefineComponent<EImgProps>;
@@ -0,0 +1,44 @@
1
+ import { defineComponent, h, inject } from "vue";
2
+ import { resolveNestedTailwindStyle, TAILWIND_NESTED_KEY } from "../tailwind/nested.js";
3
+ import { assertSafeEmailAttributes } from "./attributes.js";
4
+ import { mergeEmailStyles } from "./style.js";
5
+ const DEFAULT_IMAGE_STYLE = {
6
+ display: "block",
7
+ outline: "none",
8
+ border: "none",
9
+ textDecoration: "none"
10
+ };
11
+ export const EImg = defineComponent({
12
+ name: "EImg",
13
+ inheritAttrs: false,
14
+ props: {
15
+ alt: {
16
+ type: String,
17
+ required: true
18
+ },
19
+ src: {
20
+ type: String,
21
+ required: true
22
+ }
23
+ },
24
+ setup(props, { attrs }) {
25
+ const holder = inject(TAILWIND_NESTED_KEY, null);
26
+ return () => {
27
+ assertSafeEmailAttributes("EImg", attrs);
28
+ if (typeof props.alt !== "string") {
29
+ throw new TypeError("EImg alt must be a string; use an empty string for decorative images");
30
+ }
31
+ if (typeof props.src !== "string" || props.src.length === 0) {
32
+ throw new TypeError("EImg src must be a non-empty string");
33
+ }
34
+ const { style, ...attributes } = attrs;
35
+ const effectiveStyle = resolveNestedTailwindStyle(holder, attributes, style).style;
36
+ return h("img", {
37
+ ...attributes,
38
+ alt: props.alt,
39
+ src: props.src,
40
+ style: mergeEmailStyles(DEFAULT_IMAGE_STYLE, effectiveStyle)
41
+ });
42
+ };
43
+ }
44
+ });
@@ -0,0 +1,6 @@
1
+ import type { AnchorHTMLAttributes, DefineComponent } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ export type ELinkProps = Omit<SafeEmailAttributes<AnchorHTMLAttributes>, 'href'> & {
4
+ href: string;
5
+ };
6
+ export declare const ELink: DefineComponent<ELinkProps>;
@@ -0,0 +1,35 @@
1
+ import { defineComponent, h, inject } from "vue";
2
+ import { resolveNestedTailwindStyle, TAILWIND_NESTED_KEY } from "../tailwind/nested.js";
3
+ import { assertSafeEmailAttributes } from "./attributes.js";
4
+ import { mergeEmailStyles } from "./style.js";
5
+ const DEFAULT_LINK_STYLE = {
6
+ color: "#067df7",
7
+ textDecorationLine: "none"
8
+ };
9
+ export const ELink = defineComponent({
10
+ name: "ELink",
11
+ inheritAttrs: false,
12
+ props: {
13
+ href: {
14
+ type: String,
15
+ required: true
16
+ }
17
+ },
18
+ setup(props, { attrs, slots }) {
19
+ const holder = inject(TAILWIND_NESTED_KEY, null);
20
+ return () => {
21
+ assertSafeEmailAttributes("ELink", attrs);
22
+ if (typeof props.href !== "string" || props.href.length === 0) {
23
+ throw new TypeError("ELink href must be a non-empty string");
24
+ }
25
+ const { style, ...attributes } = attrs;
26
+ const effectiveStyle = resolveNestedTailwindStyle(holder, attributes, style).style;
27
+ return h("a", {
28
+ ...attributes,
29
+ href: props.href,
30
+ style: mergeEmailStyles(DEFAULT_LINK_STYLE, effectiveStyle),
31
+ target: attrs.target ?? "_blank"
32
+ }, slots.default?.());
33
+ };
34
+ }
35
+ });
@@ -0,0 +1,8 @@
1
+ import type { DefineComponent, HTMLAttributes } from 'vue';
2
+ import type { SafeEmailAttributes } from './attributes.js';
3
+ import type { StylesType } from './markdown/styles.js';
4
+ export type EMarkdownProps = SafeEmailAttributes<HTMLAttributes> & {
5
+ source?: string;
6
+ markdownCustomStyles?: StylesType;
7
+ };
8
+ export declare const EMarkdown: DefineComponent<EMarkdownProps>;
@@ -0,0 +1,64 @@
1
+ import { Comment, defineComponent, Fragment, h, isVNode, Text } from "vue";
2
+ import { assertSafeEmailAttributes } from "./attributes.js";
3
+ import { renderMarkdown } from "./markdown/render-markdown.js";
4
+ function appendSlotText(child, text) {
5
+ if (child === null || child === void 0 || typeof child === "boolean") {
6
+ return;
7
+ }
8
+ if (typeof child === "string" || typeof child === "number") {
9
+ text.value += String(child);
10
+ return;
11
+ }
12
+ if (Array.isArray(child)) {
13
+ for (const nestedChild of child) {
14
+ appendSlotText(nestedChild, text);
15
+ }
16
+ return;
17
+ }
18
+ if (!isVNode(child)) {
19
+ throw new TypeError("EMarkdown default slot must contain text only");
20
+ }
21
+ if (child.type === Comment) {
22
+ return;
23
+ }
24
+ if (child.type === Text) {
25
+ appendSlotText(child.children, text);
26
+ return;
27
+ }
28
+ if (child.type === Fragment && Array.isArray(child.children)) {
29
+ appendSlotText(child.children, text);
30
+ return;
31
+ }
32
+ throw new TypeError("EMarkdown default slot must contain text only");
33
+ }
34
+ function slotSource(children) {
35
+ const text = { value: "" };
36
+ appendSlotText(children, text);
37
+ return text.value;
38
+ }
39
+ export const EMarkdown = defineComponent({
40
+ name: "EMarkdown",
41
+ inheritAttrs: false,
42
+ props: {
43
+ source: {
44
+ type: String,
45
+ required: false,
46
+ default: void 0
47
+ },
48
+ markdownCustomStyles: {
49
+ type: Object,
50
+ required: false,
51
+ default: void 0
52
+ }
53
+ },
54
+ setup(props, { attrs, slots }) {
55
+ return () => {
56
+ assertSafeEmailAttributes("EMarkdown", attrs);
57
+ const source = typeof props.source === "string" ? props.source : slotSource(slots.default?.() ?? []);
58
+ return h("div", {
59
+ ...attrs,
60
+ innerHTML: renderMarkdown(source, props.markdownCustomStyles)
61
+ });
62
+ };
63
+ }
64
+ });