@travetto/email-inky 3.1.28 → 3.1.30
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/jsx-runtime.ts +1 -1
- package/package.json +7 -7
- package/src/render/common.ts +53 -0
- package/src/render/context.ts +7 -0
- package/src/render/html.ts +34 -85
- package/src/render/markdown.ts +7 -3
- package/src/render/renderer.ts +14 -20
- package/src/render/subject.ts +1 -1
- package/src/types.ts +2 -10
- package/src/wrapper.ts +18 -14
package/jsx-runtime.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/email-inky",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.30",
|
|
4
4
|
"description": "Email Inky templating module",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -27,17 +27,17 @@
|
|
|
27
27
|
"directory": "module/email-inky"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/base": "^3.1.
|
|
31
|
-
"@travetto/config": "^3.1.
|
|
32
|
-
"@travetto/di": "^3.1.
|
|
33
|
-
"@travetto/email": "^3.1.
|
|
30
|
+
"@travetto/base": "^3.1.4",
|
|
31
|
+
"@travetto/config": "^3.1.9",
|
|
32
|
+
"@travetto/di": "^3.1.5",
|
|
33
|
+
"@travetto/email": "^3.1.15",
|
|
34
34
|
"foundation-emails": "^2.4.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@travetto/email-compiler": "^3.1.
|
|
37
|
+
"@travetto/email-compiler": "^3.1.24"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@travetto/cli": "^3.1.
|
|
40
|
+
"@travetto/cli": "^3.1.10"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
43
|
"@travetto/cli": {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { JSXElement, isJSXElement } from '@travetto/email-inky/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
export const getKids = (el: JSXElement): JSXElement[] => {
|
|
4
|
+
const kids = el?.props?.children;
|
|
5
|
+
let result: unknown[] = [];
|
|
6
|
+
if (kids) {
|
|
7
|
+
result = !Array.isArray(kids) ? [kids] : kids;
|
|
8
|
+
}
|
|
9
|
+
return result.filter(isJSXElement);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const visit = (el: JSXElement, onVisit: (fn: JSXElement) => boolean | undefined | void, depth = 0): boolean | undefined => {
|
|
13
|
+
if (depth > 0) {
|
|
14
|
+
const res = onVisit(el);
|
|
15
|
+
if (res === true) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
for (const item of getKids(el)) {
|
|
20
|
+
const res = visit(item, onVisit, depth + 1);
|
|
21
|
+
if (res) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const classStr = (existing: string | undefined, ...toAdd: string[]): string => {
|
|
28
|
+
const out = [];
|
|
29
|
+
const seen = new Set<string>();
|
|
30
|
+
for (const item of existing?.split(/\s+/) ?? []) {
|
|
31
|
+
if (item && !seen.has(item)) {
|
|
32
|
+
out.push(item);
|
|
33
|
+
seen.add(item);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const item of toAdd) {
|
|
37
|
+
if (item && !seen.has(item)) {
|
|
38
|
+
out.push(item);
|
|
39
|
+
seen.add(item);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return out.join(' ');
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const combinePropsToStr = (allowedProps: Set<string>, props: Record<string, unknown>, ...addClasses: string[]): string => {
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
47
|
+
const out = { ...props, class: classStr(props.class as string, ...addClasses) };
|
|
48
|
+
return Object.entries(out)
|
|
49
|
+
.filter(([k, v]) => allowedProps.has(k) && v !== undefined && v !== null && v !== '')
|
|
50
|
+
.map(([k, v]) => `${k}="${v}"`).join(' ');
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const isOfType = (el: JSXElement, type: string): boolean => typeof el.type === 'function' && el.type.name === type;
|
package/src/render/context.ts
CHANGED
|
@@ -8,6 +8,13 @@ import { JSXElementByFn, c } from '../components';
|
|
|
8
8
|
export class RenderContext {
|
|
9
9
|
|
|
10
10
|
columnCount: number = 12;
|
|
11
|
+
file: string;
|
|
12
|
+
module: string;
|
|
13
|
+
|
|
14
|
+
constructor(srcFile: string, module: string) {
|
|
15
|
+
this.file = srcFile;
|
|
16
|
+
this.module = module;
|
|
17
|
+
}
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Create a new element from a given JSX factory
|
package/src/render/html.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { JSXElement
|
|
1
|
+
import { JSXElement } from '@travetto/email-inky/jsx-runtime';
|
|
2
2
|
import { EmailResource } from '@travetto/email';
|
|
3
3
|
|
|
4
4
|
import { RenderProvider, RenderState } from '../types';
|
|
5
5
|
import { RenderContext } from './context';
|
|
6
|
-
|
|
7
|
-
const isOfType = (el: JSXElement, type: string): boolean => typeof el.type === 'function' && el.type.name === type;
|
|
6
|
+
import { classStr, combinePropsToStr, getKids, isOfType, visit } from './common';
|
|
8
7
|
|
|
9
8
|
export const SUMMARY_STYLE = Object.entries({
|
|
10
9
|
display: 'none',
|
|
@@ -17,38 +16,13 @@ export const SUMMARY_STYLE = Object.entries({
|
|
|
17
16
|
overflow: 'hidden'
|
|
18
17
|
}).map(([k, v]) => `${k}: ${v}`).join('; ');
|
|
19
18
|
|
|
20
|
-
const classStr = (existing: string | undefined, ...toAdd: string[]): string => {
|
|
21
|
-
const out = [];
|
|
22
|
-
const seen = new Set<string>();
|
|
23
|
-
for (const item of existing?.split(/\s+/) ?? []) {
|
|
24
|
-
if (item && !seen.has(item)) {
|
|
25
|
-
out.push(item);
|
|
26
|
-
seen.add(item);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
for (const item of toAdd) {
|
|
30
|
-
if (item && !seen.has(item)) {
|
|
31
|
-
out.push(item);
|
|
32
|
-
seen.add(item);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return out.join(' ');
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
|
|
39
19
|
const allowedProps = new Set([
|
|
40
20
|
'class', 'id', 'dir', 'name', 'src',
|
|
41
21
|
'alt', 'href', 'title', 'height', 'target',
|
|
42
22
|
'width', 'style', 'align', 'valign'
|
|
43
23
|
]);
|
|
44
24
|
|
|
45
|
-
const propsToStr = (
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
47
|
-
const out = { ...props, class: classStr(props.class as string, ...addClasses) };
|
|
48
|
-
return Object.entries(out)
|
|
49
|
-
.filter(([k, v]) => allowedProps.has(k) && v !== undefined && v !== null && v !== '')
|
|
50
|
-
.map(([k, v]) => `${k}="${v}"`).join(' ');
|
|
51
|
-
};
|
|
25
|
+
const propsToStr = combinePropsToStr.bind(null, allowedProps);
|
|
52
26
|
|
|
53
27
|
const stdInline = async ({ recurse, el }: RenderState<JSXElement, RenderContext>): Promise<string> =>
|
|
54
28
|
`<${el.type} ${propsToStr(el.props)}>${await recurse()}</${el.type}>`;
|
|
@@ -56,34 +30,36 @@ const stdInline = async ({ recurse, el }: RenderState<JSXElement, RenderContext>
|
|
|
56
30
|
const std = async (state: RenderState<JSXElement, RenderContext>): Promise<string> => `${await stdInline(state)}\n`;
|
|
57
31
|
const stdFull = async (state: RenderState<JSXElement, RenderContext>): Promise<string> => `\n${await stdInline(state)}\n`;
|
|
58
32
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
33
|
+
export const Html: RenderProvider<RenderContext> = {
|
|
34
|
+
finalize: async (html, context, isRoot = false) => {
|
|
35
|
+
html = html
|
|
36
|
+
.replace(/(<[/](?:a)>)([A-Za-z0-9$])/g, (_, tag, v) => `${tag} ${v}`)
|
|
37
|
+
.replace(/(<[uo]l>)(<li>)/g, (_, a, b) => `${a} ${b}`);
|
|
38
|
+
|
|
39
|
+
if (isRoot) {
|
|
40
|
+
const wrapper = await new EmailResource([`${context.module}#resources`, '@travetto/email-inky#resources'])
|
|
41
|
+
.read('/email/inky.wrapper.html');
|
|
42
|
+
|
|
43
|
+
// Get Subject
|
|
44
|
+
const headerTop: string[] = [];
|
|
45
|
+
const bodyTop: string[] = [];
|
|
46
|
+
|
|
47
|
+
// Force summary to top, and title to head
|
|
48
|
+
const final = wrapper
|
|
49
|
+
.replace('<!-- BODY -->', html)
|
|
50
|
+
.replace(/<title>.*?<\/title>/, a => { headerTop.push(a); return ''; })
|
|
51
|
+
.replace(/<span[^>]+id="summary"[^>]*>(.*?)<\/span>/sm, a => { bodyTop.push(a); return ''; })
|
|
52
|
+
.replace(/<head( [^>]*)?>/, t => `${t}\n${headerTop.join('\n')}`)
|
|
53
|
+
.replace(/<body[^>]*>/, t => `${t}\n${bodyTop.join('\n')}`);
|
|
54
|
+
|
|
55
|
+
// Allow tag suffixes/prefixes via comments
|
|
56
|
+
html = final
|
|
57
|
+
.replace(/\s*<!--\s*[$]:([^ -]+)\s*-->\s*(<\/[^>]+>)/g, (_, suf, tag) => `${tag}${suf}`)
|
|
58
|
+
.replace(/(<[^\/][^>]+>)\s*<!--\s*[#]:([^ ]+)\s*-->\s*/g, (_, tag, pre) => `${pre}${tag}`);
|
|
79
59
|
}
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
60
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.replace(/(<[/](?:a)>)([A-Za-z0-9$])/g, (_, tag, v) => `${tag} ${v}`)
|
|
86
|
-
.replace(/(<[uo]l>)(<li>)/g, (_, a, b) => `${a} ${b}`),
|
|
61
|
+
return html;
|
|
62
|
+
},
|
|
87
63
|
|
|
88
64
|
For: async ({ recurse, props }) => `{{#${props.attr}}}${await recurse()}{{/${props.attr}}}`,
|
|
89
65
|
If: async ({ recurse, props }) => `{{#${props.attr}}}${await recurse()}{{/${props.attr}}}`,
|
|
@@ -109,16 +85,14 @@ export const Html: RenderProvider<RenderContext> = {
|
|
|
109
85
|
|
|
110
86
|
let expander = '';
|
|
111
87
|
|
|
112
|
-
const kids = getKids(el);
|
|
113
|
-
const colCount = kids.length || 1;
|
|
114
|
-
|
|
115
88
|
const parent = stack[stack.length - 1];
|
|
89
|
+
const sibs = getKids(parent).filter(x => isOfType(x, 'Column'));
|
|
90
|
+
const colCount = sibs.length || 1;
|
|
91
|
+
|
|
116
92
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
117
93
|
const pProps = parent.props as { columnVisited: boolean };
|
|
118
94
|
if (!pProps.columnVisited) {
|
|
119
95
|
pProps.columnVisited = true;
|
|
120
|
-
|
|
121
|
-
const sibs = getKids(parent).filter(x => isOfType(x, 'Column'));
|
|
122
96
|
if (sibs.length) {
|
|
123
97
|
sibs[0].props.class = classStr(sibs[0].props.class ?? '', 'first');
|
|
124
98
|
sibs[sibs.length - 1].props.class = classStr(sibs[sibs.length - 1].props.class ?? '', 'last');
|
|
@@ -362,29 +336,4 @@ export const Html: RenderProvider<RenderContext> = {
|
|
|
362
336
|
</tr>
|
|
363
337
|
</tbody>
|
|
364
338
|
</table>`
|
|
365
|
-
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
export const HtmlWrap = async (content: string): Promise<string> => {
|
|
369
|
-
const wrapper = await new EmailResource(['@', '@travetto/email-inky#resources'])
|
|
370
|
-
.read('/email/inky.wrapper.html');
|
|
371
|
-
|
|
372
|
-
// Get Subject
|
|
373
|
-
const headerTop: string[] = [];
|
|
374
|
-
const bodyTop: string[] = [];
|
|
375
|
-
|
|
376
|
-
// Force summary to top, and title to head
|
|
377
|
-
let final = wrapper
|
|
378
|
-
.replace('<!-- BODY -->', content)
|
|
379
|
-
.replace(/<title>.*?<\/title>/, a => { headerTop.push(a); return ''; })
|
|
380
|
-
.replace(/<span[^>]+id="summary"[^>]*>(.*?)<\/span>/sm, a => { bodyTop.push(a); return ''; })
|
|
381
|
-
.replace(/<head( [^>]*)?>/, t => `${t}\n${headerTop.join('\n')}`)
|
|
382
|
-
.replace(/<body[^>]*>/, t => `${t}\n${bodyTop.join('\n')}`);
|
|
383
|
-
|
|
384
|
-
// Allow tag suffixes/prefixes via comments
|
|
385
|
-
final = final
|
|
386
|
-
.replace(/\s*<!--\s*[$]:([^ -]+)\s*-->\s*(<\/[^>]+>)/g, (_, suf, tag) => `${tag}${suf}`)
|
|
387
|
-
.replace(/(<[^\/][^>]+>)\s*<!--\s*[#]:([^ ]+)\s*-->\s*/g, (_, tag, pre) => `${pre}${tag}`);
|
|
388
|
-
|
|
389
|
-
return final;
|
|
390
339
|
};
|
package/src/render/markdown.ts
CHANGED
|
@@ -6,9 +6,12 @@ const visit = ({ recurse }: RenderState<JSXElement, RenderContext>): Promise<str
|
|
|
6
6
|
const ignore = async ({ recurse: _ }: RenderState<JSXElement, RenderContext>): Promise<string> => '';
|
|
7
7
|
|
|
8
8
|
export const Markdown: RenderProvider<RenderContext> = {
|
|
9
|
-
finalize: (text
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
finalize: (text) => {
|
|
10
|
+
text = text
|
|
11
|
+
.replace(/(\[[^\]]+\]\([^)]+\))([A-Za-z0-9$]+)/g, (_, link, v) => v === 's' ? _ : `${link} ${v}`)
|
|
12
|
+
.replace(/(\S)\n(#)/g, (_, l, r) => `${l}\n\n${r}`);
|
|
13
|
+
return text;
|
|
14
|
+
},
|
|
12
15
|
|
|
13
16
|
For: async ({ recurse, props }) => `{{#${props.attr}}}${await recurse()}{{/${props.attr}}}`,
|
|
14
17
|
If: async ({ recurse, props }) => `{{#${props.attr}}}${await recurse()}{{/${props.attr}}}`,
|
|
@@ -39,6 +42,7 @@ export const Markdown: RenderProvider<RenderContext> = {
|
|
|
39
42
|
h2: async ({ recurse }) => `\n## ${await recurse()}\n\n`,
|
|
40
43
|
h3: async ({ recurse }) => `\n### ${await recurse()}\n\n`,
|
|
41
44
|
h4: async ({ recurse }) => `\n#### ${await recurse()}\n\n`,
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
42
46
|
a: async ({ recurse, props }) => `\n[${await recurse()}](${(props as { href: string }).href})\n`,
|
|
43
47
|
Button: async ({ recurse, props }) => `\n[${await recurse()}](${props.href})\n`,
|
|
44
48
|
|
package/src/render/renderer.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { isJSXElement, JSXElement, createFragment, JSXFragmentType, JSXChild } from '@travetto/email-inky/jsx-runtime';
|
|
2
|
+
import { EmailTemplateLocation } from '@travetto/email';
|
|
2
3
|
|
|
3
4
|
import { EMPTY_ELEMENT, getComponentName, JSXElementByFn, c } from '../components';
|
|
4
|
-
import {
|
|
5
|
+
import { RenderProvider, RenderState } from '../types';
|
|
5
6
|
import { RenderContext } from './context';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -19,7 +20,7 @@ export class InkyRenderer {
|
|
|
19
20
|
return '';
|
|
20
21
|
} else if (Array.isArray(node)) {
|
|
21
22
|
const out: string[] = [];
|
|
22
|
-
const nextStack = [...stack, { key: '', props: { children: node }, type:
|
|
23
|
+
const nextStack = [...stack, { key: '', props: { children: node }, type: JSXFragmentType }];
|
|
23
24
|
for (const el of node) {
|
|
24
25
|
out.push(await this.#render(ctx, renderer, el, nextStack));
|
|
25
26
|
}
|
|
@@ -27,7 +28,7 @@ export class InkyRenderer {
|
|
|
27
28
|
} else if (isJSXElement(node)) {
|
|
28
29
|
let final: JSXElement = node;
|
|
29
30
|
// Render simple element if needed
|
|
30
|
-
if (typeof node.type === 'function') {
|
|
31
|
+
if (typeof node.type === 'function' && node.type !== JSXFragmentType) {
|
|
31
32
|
// @ts-expect-error
|
|
32
33
|
const out = node.type(node.props);
|
|
33
34
|
final = out !== EMPTY_ELEMENT ? out : final;
|
|
@@ -79,22 +80,15 @@ export class InkyRenderer {
|
|
|
79
80
|
* Render a context given a specific renderer
|
|
80
81
|
* @param renderer
|
|
81
82
|
*/
|
|
82
|
-
static async render(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const text = await this.#render(ctx, provider, root.text, [par]);
|
|
93
|
-
|
|
94
|
-
let cleaned = `${text.replace(/\n{3,100}/msg, '\n\n').trim()}\n`;
|
|
95
|
-
if (root.wrap) {
|
|
96
|
-
cleaned = await root.wrap?.(cleaned);
|
|
97
|
-
}
|
|
98
|
-
return provider.finalize(cleaned, ctx);
|
|
83
|
+
static async render(
|
|
84
|
+
root: JSXElement,
|
|
85
|
+
provider: RenderProvider<RenderContext>,
|
|
86
|
+
sourceLoc: EmailTemplateLocation,
|
|
87
|
+
isRoot = true
|
|
88
|
+
): Promise<string> {
|
|
89
|
+
const ctx = new RenderContext(sourceLoc.file, sourceLoc.module);
|
|
90
|
+
const par: JSXElement = root.type === JSXFragmentType ? root : { props: { children: [root] }, type: JSXFragmentType, key: '' };
|
|
91
|
+
const text = await this.#render(ctx, provider, par, []);
|
|
92
|
+
return provider.finalize(text, ctx, isRoot);
|
|
99
93
|
}
|
|
100
94
|
}
|
package/src/render/subject.ts
CHANGED
|
@@ -6,7 +6,7 @@ const empty = async (): Promise<string> => '';
|
|
|
6
6
|
const visit = ({ recurse }: RenderState<JSXElement, RenderContext>): Promise<string> => recurse();
|
|
7
7
|
|
|
8
8
|
export const Subject: RenderProvider<RenderContext> = {
|
|
9
|
-
finalize: text => text,
|
|
9
|
+
finalize: (text, context, root) => text,
|
|
10
10
|
|
|
11
11
|
For: async ({ recurse, props }) => `{{#${props.attr}}}${await recurse()}{{/${props.attr}}}`,
|
|
12
12
|
If: async ({ recurse, props }) => `{{#${props.attr}}}${await recurse()}{{/${props.attr}}}`,
|
package/src/types.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JSXElement, ValidHtmlTags } from '../jsx-runtime';
|
|
2
2
|
import { JSXElementByFn, c } from './components';
|
|
3
3
|
|
|
4
4
|
export type Wrapper = Record<string, (cnt: string) => string>;
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Document file shape
|
|
8
|
-
*/
|
|
9
|
-
export interface DocumentShape {
|
|
10
|
-
text: JSXChild | JSXChild[] | undefined | null;
|
|
11
|
-
wrap?: (content: string) => string | Promise<string>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
export type RenderState<T extends JSXElement, C> = {
|
|
15
7
|
el: T;
|
|
16
8
|
props: T['props'];
|
|
@@ -25,7 +17,7 @@ export type RenderState<T extends JSXElement, C> = {
|
|
|
25
17
|
* Renderer
|
|
26
18
|
*/
|
|
27
19
|
export type RenderProvider<C> =
|
|
28
|
-
{ finalize: (text: string, ctx: C) => string } &
|
|
20
|
+
{ finalize: (text: string, ctx: C, isRoot?: boolean) => (string | Promise<string>) } &
|
|
29
21
|
{ [K in ValidHtmlTags]: (state: RenderState<JSXElement<K>, C>) => Promise<string>; } &
|
|
30
22
|
// @ts-expect-error
|
|
31
23
|
{ [K in keyof typeof c]: (state: RenderState<JSXElementByFn<K>, C>) => Promise<string>; };
|
package/src/wrapper.ts
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
import { createRequire } from 'module';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { JSXComponentFunction, JSXElement } from '@travetto/email-inky/jsx-runtime';
|
|
3
|
+
import { EmailCompileSource } from '@travetto/email';
|
|
4
|
+
import { JSXComponentFunction, JSXElement, JSXFragmentType } from '@travetto/email-inky/jsx-runtime';
|
|
5
5
|
import { RootIndex, path } from '@travetto/manifest';
|
|
6
6
|
|
|
7
7
|
import { InkyRenderer } from './render/renderer';
|
|
8
|
-
import { Html
|
|
8
|
+
import { Html } from './render/html';
|
|
9
9
|
import { Markdown } from './render/markdown';
|
|
10
10
|
import { Subject } from './render/subject';
|
|
11
11
|
|
|
12
|
-
export const wrap = (content: JSXElement):
|
|
12
|
+
export const wrap = (content: JSXElement): EmailCompileSource => {
|
|
13
13
|
const req = createRequire(`${RootIndex.manifest.workspacePath}/node_modules`);
|
|
14
|
+
const finalContent = { ...content, key: '', type: JSXFragmentType };
|
|
14
15
|
|
|
15
16
|
return {
|
|
16
|
-
file: '',
|
|
17
|
-
html: InkyRenderer.render.bind(InkyRenderer, { text: content.props.children, wrap: HtmlWrap }, Html),
|
|
18
|
-
text: InkyRenderer.render.bind(InkyRenderer, { text: content.props.children }, Markdown),
|
|
19
|
-
subject: InkyRenderer.render.bind(InkyRenderer, { text: content.props.children }, Subject),
|
|
20
17
|
styles: {
|
|
21
18
|
search: [path.dirname(req.resolve('foundation-emails/scss/_global.scss'))],
|
|
22
19
|
global: `
|
|
23
|
-
@import 'email/inky.variables';
|
|
24
|
-
@import '_global';
|
|
25
|
-
@import 'foundation-emails';
|
|
26
|
-
`
|
|
27
|
-
}
|
|
20
|
+
@import 'email/inky.variables';
|
|
21
|
+
@import '_global';
|
|
22
|
+
@import 'foundation-emails';
|
|
23
|
+
`
|
|
24
|
+
},
|
|
25
|
+
html: InkyRenderer.render.bind(InkyRenderer, finalContent, Html),
|
|
26
|
+
text: InkyRenderer.render.bind(InkyRenderer, finalContent, Markdown),
|
|
27
|
+
subject: InkyRenderer.render.bind(InkyRenderer, finalContent, Subject),
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
export const InkyTemplate: JSXComponentFunction<{}> = (): JSXElement => ({ type: '', key: '', props: {} });
|
|
31
|
+
export const InkyTemplate: JSXComponentFunction<{}> = (): JSXElement => ({ type: '', key: '', props: {} });
|
|
32
|
+
|
|
33
|
+
export const unwrap = (element: JSXElement): Promise<EmailCompileSource | undefined> =>
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
35
|
+
(element as unknown as { wrap: (el: JSXElement) => Promise<EmailCompileSource> }).wrap(element);
|