fix(email-renderer): preserve section ancestry in parsed HTML
This commit is contained in:
1 parent
d8b9c2dcb5
commit
2cd8f8ea14
4 files changed
+24
-6
No files matched your search
@@ -270,7 +270,7 @@
|
|||||||
},
|
},
|
||||||
"packages/block-editor": {
|
"packages/block-editor": {
|
||||||
"name": "@wrnexus/block-editor",
|
"name": "@wrnexus/block-editor",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/blocks": "workspace:*",
|
"@wrnexus/blocks": "workspace:*",
|
||||||
"@wrnexus/dnd": "workspace:*",
|
"@wrnexus/dnd": "workspace:*",
|
||||||
@@ -284,7 +284,7 @@
|
|||||||
},
|
},
|
||||||
"packages/blocks": {
|
"packages/blocks": {
|
||||||
"name": "@wrnexus/blocks",
|
"name": "@wrnexus/blocks",
|
||||||
"version": "0.1.0",
|
"version": "0.1.2",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.4.0",
|
"@types/bun": "^1.4.0",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
@@ -428,7 +428,7 @@
|
|||||||
},
|
},
|
||||||
"packages/email-renderer": {
|
"packages/email-renderer": {
|
||||||
"name": "@wrnexus/email-renderer",
|
"name": "@wrnexus/email-renderer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.8",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/blocks": "workspace:*",
|
"@wrnexus/blocks": "workspace:*",
|
||||||
"amphtml-validator": "1.0.38",
|
"amphtml-validator": "1.0.38",
|
||||||
@@ -437,6 +437,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.4.0",
|
"@types/bun": "^1.4.0",
|
||||||
|
"parse5": "7.3.0",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/email-renderer",
|
"name": "@wrnexus/email-renderer",
|
||||||
"version": "0.1.7",
|
"version": "0.1.8",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "WRNexus block email renderers with HTML, text, AMP Email, and MJML interoperability.",
|
"description": "WRNexus block email renderers with HTML, text, AMP Email, and MJML interoperability.",
|
||||||
"exports": {
|
"exports": {
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
"mjml-parser-xml": "5.4.0"
|
"mjml-parser-xml": "5.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"parse5": "7.3.0",
|
||||||
"@types/bun": "^1.4.0",
|
"@types/bun": "^1.4.0",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,12 +129,12 @@ export const sectionBlock = defineBlock({
|
|||||||
renderers: {
|
renderers: {
|
||||||
emailHtml: ({ node, slots }) =>
|
emailHtml: ({ node, slots }) =>
|
||||||
emailCell(
|
emailCell(
|
||||||
`<table role="presentation" width="100%"><tr><td style="background:${html(attrs(node).background)};padding:${html(attrs(node).padding)};">${slots.content}</td></tr></table>`,
|
`<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="background:${html(attrs(node).background)};padding:${html(attrs(node).padding)};"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">${slots.content}</table></td></tr></table>`,
|
||||||
node,
|
node,
|
||||||
),
|
),
|
||||||
ampEmail: ({ node, slots }) =>
|
ampEmail: ({ node, slots }) =>
|
||||||
emailCell(
|
emailCell(
|
||||||
`<table role="presentation" width="100%"><tr><td class="section">${slots.content}</td></tr></table>`,
|
`<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td class="section"><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">${slots.content}</table></td></tr></table>`,
|
||||||
node,
|
node,
|
||||||
),
|
),
|
||||||
mjml: ({ node, slots }) =>
|
mjml: ({ node, slots }) =>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
|
import { parse, type DefaultTreeAdapterMap } from "parse5";
|
||||||
import {
|
import {
|
||||||
emailCoreBlocks,
|
emailCoreBlocks,
|
||||||
renderEmail,
|
renderEmail,
|
||||||
@@ -55,6 +56,21 @@ const document: BlockDocument = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("email renderer", () => {
|
describe("email renderer", () => {
|
||||||
|
test("browser HTML parsing preserves every block inside its section", async () => {
|
||||||
|
const rendered = await renderEmail(document);
|
||||||
|
expect(rendered.ok).toBe(true);
|
||||||
|
if (!rendered.ok) return;
|
||||||
|
const tree = parse(rendered.value.parts.html.content);
|
||||||
|
const ancestry = new Map<string, string[]>();
|
||||||
|
const walk = (node: DefaultTreeAdapterMap["node"], parents: string[]) => {
|
||||||
|
const id = "attrs" in node ? node.attrs.find(attr => attr.name === "data-block-id")?.value : undefined;
|
||||||
|
if (id) ancestry.set(id, parents);
|
||||||
|
if ("childNodes" in node) for (const child of node.childNodes) walk(child, id ? [...parents, id] : parents);
|
||||||
|
};
|
||||||
|
walk(tree, []);
|
||||||
|
expect(ancestry.get("heading")).toEqual(["root", "section"]);
|
||||||
|
expect(ancestry.get("button")).toEqual(["root", "section"]);
|
||||||
|
});
|
||||||
test("renders deterministic HTML, text, AMP, and MJML", async () => {
|
test("renders deterministic HTML, text, AMP, and MJML", async () => {
|
||||||
const first = await renderEmail(document, { amp: true, mjml: true });
|
const first = await renderEmail(document, { amp: true, mjml: true });
|
||||||
const second = await renderEmail(document, { amp: true, mjml: true });
|
const second = await renderEmail(document, { amp: true, mjml: true });
|
||||||
|
|||||||
Reference in new issue
Block a user