mirror of
https://github.com/resend/react-email.git
synced 2026-09-14 14:18:02 +08:00
feat(render): toPlainText function to convert existing HTML to plain text (#2412)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@react-email/render": minor
|
||||
---
|
||||
|
||||
add toPlainText utility and deprecate plainText option on `render`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@react-email/components": minor
|
||||
---
|
||||
|
||||
add toPlainText utility and deprecate plainText option on `render`
|
||||
@@ -9,6 +9,6 @@ export const renderAsync = (element: React.ReactElement, options?: Options) => {
|
||||
};
|
||||
|
||||
export * from '../shared/options';
|
||||
export * from '../shared/plain-text-selectors';
|
||||
export * from '../shared/utils/pretty';
|
||||
export * from '../shared/utils/to-plain-text';
|
||||
export * from './render';
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
import { createElement } from 'react';
|
||||
import usePromise from 'react-promise-suspense';
|
||||
import { Preview } from '../shared/utils/preview';
|
||||
import { Template } from '../shared/utils/template';
|
||||
import { Preview } from '../shared/utils/testing/preview';
|
||||
import { Template } from '../shared/utils/testing/template';
|
||||
import { render } from './render';
|
||||
|
||||
type Import = typeof import('react-dom/server') & {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { convert } from 'html-to-text';
|
||||
import { Suspense } from 'react';
|
||||
import type { ReactDOMServerReadableStream } from 'react-dom/server';
|
||||
import { pretty } from '../node';
|
||||
import { pretty, toPlainText } from '../node';
|
||||
import type { Options } from '../shared/options';
|
||||
import { plainTextSelectors } from '../shared/plain-text-selectors';
|
||||
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
|
||||
@@ -59,10 +57,7 @@ export const render = async (node: React.ReactNode, options?: Options) => {
|
||||
});
|
||||
|
||||
if (options?.plainText) {
|
||||
return convert(html, {
|
||||
selectors: plainTextSelectors,
|
||||
...options.htmlToTextOptions,
|
||||
});
|
||||
return toPlainText(html, options.htmlToTextOptions);
|
||||
}
|
||||
|
||||
const doctype =
|
||||
|
||||
@@ -9,6 +9,6 @@ export const renderAsync = (element: React.ReactElement, options?: Options) => {
|
||||
};
|
||||
|
||||
export * from '../shared/options';
|
||||
export * from '../shared/plain-text-selectors';
|
||||
export * from '../shared/utils/pretty';
|
||||
export * from '../shared/utils/to-plain-text';
|
||||
export * from './render';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Preview } from '../shared/utils/preview';
|
||||
import { Template } from '../shared/utils/template';
|
||||
import { Preview } from '../shared/utils/testing/preview';
|
||||
import { Template } from '../shared/utils/testing/template';
|
||||
import { render } from './render';
|
||||
|
||||
type Import = typeof import('react-dom/server') & {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
import { Suspense } from 'react';
|
||||
import usePromise from 'react-promise-suspense';
|
||||
import { Preview } from '../shared/utils/preview';
|
||||
import { Template } from '../shared/utils/template';
|
||||
import { Preview } from '../shared/utils/testing/preview';
|
||||
import { Template } from '../shared/utils/testing/template';
|
||||
import { render } from './render';
|
||||
|
||||
type Import = typeof import('react-dom/server') & {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { convert } from 'html-to-text';
|
||||
import { Suspense } from 'react';
|
||||
import type { Options } from '../shared/options';
|
||||
import { plainTextSelectors } from '../shared/plain-text-selectors';
|
||||
import { pretty } from '../shared/utils/pretty';
|
||||
import { toPlainText } from '../shared/utils/to-plain-text';
|
||||
import { readStream } from './read-stream';
|
||||
|
||||
export const render = async (node: React.ReactNode, options?: Options) => {
|
||||
@@ -35,10 +34,7 @@ export const render = async (node: React.ReactNode, options?: Options) => {
|
||||
}
|
||||
|
||||
if (options?.plainText) {
|
||||
return convert(html, {
|
||||
selectors: plainTextSelectors,
|
||||
...options.htmlToTextOptions,
|
||||
});
|
||||
return toPlainText(html, options.htmlToTextOptions);
|
||||
}
|
||||
|
||||
const doctype =
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { HtmlToTextOptions } from 'html-to-text';
|
||||
import type { pretty } from './utils/pretty';
|
||||
import type { toPlainText } from './utils/to-plain-text';
|
||||
|
||||
export type Options = {
|
||||
/**
|
||||
@@ -8,9 +9,15 @@ export type Options = {
|
||||
pretty?: boolean;
|
||||
} & (
|
||||
| {
|
||||
/**
|
||||
* @deprecated use {@link toPlainText} instead
|
||||
*/
|
||||
plainText?: false;
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* @deprecated use {@link toPlainText} instead
|
||||
*/
|
||||
plainText?: true;
|
||||
/**
|
||||
* These are options you can pass down directly to the library we use for
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import type { SelectorDefinition } from 'html-to-text';
|
||||
|
||||
export const plainTextSelectors: SelectorDefinition[] = [
|
||||
{ selector: 'img', format: 'skip' },
|
||||
{ selector: '[data-skip-in-text=true]', format: 'skip' },
|
||||
{
|
||||
selector: 'a',
|
||||
options: { linkBrackets: false },
|
||||
},
|
||||
];
|
||||
@@ -5,7 +5,7 @@ import { pretty } from './pretty';
|
||||
describe('pretty', () => {
|
||||
it("should prettify Preview component's complex characters correctly", async () => {
|
||||
const stripeHTML = await fs.readFile(
|
||||
path.resolve(__dirname, './stripe-email.html'),
|
||||
path.resolve(__dirname, './testing/stripe-email.html'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import {
|
||||
convert,
|
||||
type HtmlToTextOptions,
|
||||
type SelectorDefinition,
|
||||
} from 'html-to-text';
|
||||
|
||||
export const plainTextSelectors: SelectorDefinition[] = [
|
||||
{ selector: 'img', format: 'skip' },
|
||||
{ selector: '[data-skip-in-text=true]', format: 'skip' },
|
||||
{
|
||||
selector: 'a',
|
||||
options: { linkBrackets: false },
|
||||
},
|
||||
];
|
||||
|
||||
export function toPlainText(html: string, options?: HtmlToTextOptions) {
|
||||
return convert(html, {
|
||||
selectors: plainTextSelectors,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user