From 1143da808f3037fcb7b6dc434206201115942968 Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Sat, 5 Sep 2026 12:18:35 +0530 Subject: [PATCH] fix(email-renderer): inherit global brand fonts in content blocks --- packages/email-renderer/package.json | 2 +- packages/email-renderer/src/blocks.ts | 16 ++++++++-------- packages/email-renderer/test/email.test.ts | 11 +++++++++++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/email-renderer/package.json b/packages/email-renderer/package.json index cf90c958..6cba1de2 100644 --- a/packages/email-renderer/package.json +++ b/packages/email-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/email-renderer", - "version": "0.1.8", + "version": "0.1.9", "type": "module", "description": "WRNexus block email renderers with HTML, text, AMP Email, and MJML interoperability.", "exports": { diff --git a/packages/email-renderer/src/blocks.ts b/packages/email-renderer/src/blocks.ts index 448c7db2..5767e213 100644 --- a/packages/email-renderer/src/blocks.ts +++ b/packages/email-renderer/src/blocks.ts @@ -251,7 +251,7 @@ export const headingBlock = leaf( { emailHtml: ({ node }) => emailCell( - `${html(attrs(node).text)}`, + `${html(attrs(node).text)}`, node, ), ampEmail: ({ node }) => @@ -270,7 +270,7 @@ export const textBlock = leaf( { emailHtml: ({ node }) => emailCell( - `

${html(attrs(node).text)}

`, + `

${html(attrs(node).text)}

`, node, ), ampEmail: ({ node }) => emailCell(`

${html(attrs(node).text)}

`, node), @@ -318,7 +318,7 @@ export const buttonBlock = leaf( { emailHtml: ({ node }) => emailCell( - `
${html(attrs(node).label)}
`, + `
${html(attrs(node).label)}
`, node, ), ampEmail: ({ node }) => @@ -394,7 +394,7 @@ export const socialBlock = leaf( x: safeUrl({ schemes: ["https"], optional: true }), }) as never, { - emailHtml: ({ node }) => emailCell(`

${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`${name}`).join("")}

`, node), + emailHtml: ({ node }) => emailCell(`

${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`${name}`).join("")}

`, node), ampEmail: ({ node }) => emailCell(`

${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`${name}`).join(" ")}

`, node), mjml: ({ node }) => `${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`${name}`).join(" ")}`, }, @@ -411,7 +411,7 @@ export const countdownBlock = leaf( fallback: string({ max: 300, default: "This offer has ended." }), }) as never, { - emailHtml: ({ node }) => emailCell(`

${html(attrs(node).label)}:

`, node), + emailHtml: ({ node }) => emailCell(`

${html(attrs(node).label)}:

`, node), ampEmail: ({ node }) => emailCell(`

${html(attrs(node).label)}:

`, node), mjml: ({ node }) => `${html(attrs(node).label)}: ${html(attrs(node).deadline)}`, }, @@ -424,7 +424,7 @@ export const surveyBlock = leaf( "icon-[lucide--list-checks]", object({ question: string({ min: 1, max: 500 }), buttonLabel: string({ min: 1, max: 200, default: "Answer survey" }), href: safeUrl({ schemes: ["https"] }) }) as never, { - emailHtml: ({ node }) => emailCell(`

${html(attrs(node).question)}

${html(attrs(node).buttonLabel)}

`, node), + emailHtml: ({ node }) => emailCell(`

${html(attrs(node).question)}

${html(attrs(node).buttonLabel)}

`, node), ampEmail: ({ node }) => emailCell(`

${html(attrs(node).question)}

${html(attrs(node).buttonLabel)}

`, node), mjml: ({ node }) => `${html(attrs(node).question)}${html(attrs(node).buttonLabel)}`, }, @@ -437,7 +437,7 @@ export const feedItemBlock = leaf( "icon-[lucide--rss]", object({ feedUrl: safeUrl({ schemes: ["https"], optional: true }), title: string({ min: 1, max: 500 }), summary: string({ max: 2_000, default: "" }), href: safeUrl({ schemes: ["https"] }), image: safeUrl({ schemes: ["https"], optional: true }) }) as never, { - emailHtml: ({ node }) => emailCell(`${attrs(node).image ? `` : ""}

${html(attrs(node).title)}

${html(attrs(node).summary)}

`, node), + emailHtml: ({ node }) => emailCell(`${attrs(node).image ? `` : ""}

${html(attrs(node).title)}

${html(attrs(node).summary)}

`, node), ampEmail: ({ node }) => emailCell(`

${html(attrs(node).title)}

${html(attrs(node).summary)}

`, node), mjml: ({ node }) => `${html(attrs(node).title)}${html(attrs(node).summary)}`, }, @@ -450,7 +450,7 @@ export const productBlock = leaf( "icon-[lucide--shopping-bag]", object({ provider: choice(["shopify", "woocommerce", "manual"] as const, { default: "manual" }), storeUrl: safeUrl({ schemes: ["https"], optional: true }), productId: string({ max: 300, default: "" }), title: string({ min: 1, max: 500 }), price: string({ max: 100 }), image: safeUrl({ schemes: ["https"] }), href: safeUrl({ schemes: ["https"] }), buttonLabel: string({ max: 200, default: "Shop now" }) }) as never, { - emailHtml: ({ node }) => emailCell(`${html(attrs(node).title)}

${html(attrs(node).title)}

${html(attrs(node).price)}

${html(attrs(node).buttonLabel)}

`, node), + emailHtml: ({ node }) => emailCell(`${html(attrs(node).title)}

${html(attrs(node).title)}

${html(attrs(node).price)}

${html(attrs(node).buttonLabel)}

`, node), ampEmail: ({ node }) => emailCell(`

${html(attrs(node).title)}

${html(attrs(node).price)}

${html(attrs(node).buttonLabel)}

`, node), mjml: ({ node }) => `${html(attrs(node).title)}${html(attrs(node).price)}${html(attrs(node).buttonLabel)}`, }, diff --git a/packages/email-renderer/test/email.test.ts b/packages/email-renderer/test/email.test.ts index e0ac094e..f4955725 100644 --- a/packages/email-renderer/test/email.test.ts +++ b/packages/email-renderer/test/email.test.ts @@ -56,6 +56,17 @@ const document: BlockDocument = { }; describe("email renderer", () => { + test("content inherits the selected brand font instead of overriding it", async () => { + const branded = structuredClone(document); + branded.root.props.fontFamily = "Georgia, serif"; + const result = await renderEmail(branded); + expect(result.ok).toBe(true); + if (!result.ok) return; + expect(result.value.parts.html.content).toContain("font-family:Georgia, serif"); + expect(result.value.parts.html.content).not.toContain("font-family:Arial"); + expect(result.value.parts.html.content).toContain('

{ const rendered = await renderEmail(document); expect(rendered.ok).toBe(true);