Skip to content

Commit b462971

Browse files
committed
feat(render): pass options to rendered component
1 parent b2407a1 commit b462971

File tree

6 files changed

+73
-2
lines changed

6 files changed

+73
-2
lines changed

packages/render/src/browser/render-web.spec.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import { createElement } from 'react';
66
import usePromise from 'react-promise-suspense';
7+
import type { Options } from '../shared/options';
78
import { Preview } from '../shared/utils/preview';
89
import { Template } from '../shared/utils/template';
910
import { render } from './render';
@@ -146,4 +147,22 @@ describe('render on the browser environment', () => {
146147
const element = createElement(undefined);
147148
await expect(render(element)).rejects.toThrowErrorMatchingSnapshot();
148149
});
150+
151+
152+
it('passes render options to the rendered component', async () => {
153+
type TemplateWithOptionsProps = {
154+
reactEmailRenderOptions?: Options;
155+
};
156+
const TemplateWithOptions = ({
157+
reactEmailRenderOptions,
158+
}: TemplateWithOptionsProps) => {
159+
return JSON.stringify(reactEmailRenderOptions);
160+
};
161+
162+
const actualOutput = await render(<TemplateWithOptions />, {
163+
plainText: true,
164+
});
165+
166+
expect(actualOutput).toMatchInlineSnapshot('"{"plainText":true}"');
167+
});
149168
});

packages/render/src/browser/render.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { ReactDOMServerReadableStream } from 'react-dom/server';
44
import { pretty } from '../node';
55
import type { Options } from '../shared/options';
66
import { plainTextSelectors } from '../shared/plain-text-selectors';
7+
import { withAdditionalProps } from '../shared/with-additional-props';
78

89
const decoder = new TextDecoder('utf-8');
910

@@ -39,7 +40,8 @@ const readStream = async (stream: ReactDOMServerReadableStream) => {
3940
};
4041

4142
export const render = async (node: React.ReactNode, options?: Options) => {
42-
const suspendedElement = <Suspense>{node}</Suspense>;
43+
const nodeWithAdditionalProps = withAdditionalProps(node, options);
44+
const suspendedElement = <Suspense>{nodeWithAdditionalProps}</Suspense>;
4345
const reactDOMServer = await import('react-dom/server.browser').then(
4446
// This is beacuse react-dom/server is CJS
4547
(m) => m.default,

packages/render/src/node/render-edge.spec.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Options } from '../shared/options';
12
import { Preview } from '../shared/utils/preview';
23
import { Template } from '../shared/utils/template';
34
import { render } from './render';
@@ -107,4 +108,22 @@ describe('render on the edge', () => {
107108
`"THIS SHOULD BE RENDERED IN PLAIN TEXT"`,
108109
);
109110
});
111+
112+
113+
it('passes render options to the rendered component', async () => {
114+
type TemplateWithOptionsProps = {
115+
reactEmailRenderOptions?: Options;
116+
};
117+
const TemplateWithOptions = ({
118+
reactEmailRenderOptions,
119+
}: TemplateWithOptionsProps) => {
120+
return JSON.stringify(reactEmailRenderOptions);
121+
};
122+
123+
const actualOutput = await render(<TemplateWithOptions />, {
124+
plainText: true,
125+
});
126+
127+
expect(actualOutput).toMatchInlineSnapshot('"{"plainText":true}"');
128+
});
110129
});

packages/render/src/node/render-node.spec.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import { Suspense } from 'react';
66
import usePromise from 'react-promise-suspense';
7+
import type { Options } from '../shared/options';
78
import { Preview } from '../shared/utils/preview';
89
import { Template } from '../shared/utils/template';
910
import { render } from './render';
@@ -133,4 +134,21 @@ describe('render on node environments', () => {
133134
`"THIS SHOULD BE RENDERED IN PLAIN TEXT"`,
134135
);
135136
});
137+
138+
it('passes render options to the rendered component', async () => {
139+
type TemplateWithOptionsProps = {
140+
reactEmailRenderOptions?: Options;
141+
};
142+
const TemplateWithOptions = ({
143+
reactEmailRenderOptions,
144+
}: TemplateWithOptionsProps) => {
145+
return JSON.stringify(reactEmailRenderOptions);
146+
};
147+
148+
const actualOutput = await render(<TemplateWithOptions />, {
149+
plainText: true,
150+
});
151+
152+
expect(actualOutput).toMatchInlineSnapshot('"{"plainText":true}"');
153+
});
136154
});

packages/render/src/node/render.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { Suspense } from 'react';
33
import type { Options } from '../shared/options';
44
import { plainTextSelectors } from '../shared/plain-text-selectors';
55
import { pretty } from '../shared/utils/pretty';
6+
import { withAdditionalProps } from '../shared/with-additional-props';
67
import { readStream } from './read-stream';
78

89
export const render = async (node: React.ReactNode, options?: Options) => {
9-
const suspendedElement = <Suspense>{node}</Suspense>;
10+
const nodeWithAdditionalProps = withAdditionalProps(node, options);
11+
const suspendedElement = <Suspense>{nodeWithAdditionalProps}</Suspense>;
1012
const reactDOMServer = await import('react-dom/server').then(
1113
// This is beacuse react-dom/server is CJS
1214
(m) => m.default,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { cloneElement, isValidElement } from 'react';
2+
import type { Options } from './options';
3+
4+
export const withAdditionalProps = (
5+
node: React.ReactNode,
6+
options?: Options,
7+
): React.ReactNode => {
8+
if (!isValidElement(node)) return node;
9+
const additionalProps = { reactEmailRenderOptions: options };
10+
return cloneElement(node, additionalProps);
11+
};

0 commit comments

Comments
 (0)