fix(email-renderer): constrain images to available content width
Quality / quality (ubuntu-latest) (push) Failing after 0s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
Clintchiz committed 2026-09-05 14:00:47 +05:30
1 parent 42b91f765d
commit bb28b8759a
3 files changed
+5 -4

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/email-renderer", "name": "@wrnexus/email-renderer",
"version": "0.1.19", "version": "0.1.20",
"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": {
+3 -3
View File
@@ -49,7 +49,7 @@ const marketingImage = (node: BlockNode, target: "html" | "amp" | "mjml") => {
const src = html(p.image), alt = html(p.title); const src = html(p.image), alt = html(p.title);
if (target === "amp") return `<amp-img class="marketing-image" src="${src}" alt="${alt}" width="${width}" height="${height}" layout="responsive"></amp-img>`; if (target === "amp") return `<amp-img class="marketing-image" src="${src}" alt="${alt}" width="${width}" height="${height}" layout="responsive"></amp-img>`;
if (target === "mjml") return `<mj-image src="${src}" alt="${alt}" width="${width}px" />`; if (target === "mjml") return `<mj-image src="${src}" alt="${alt}" width="${width}px" />`;
return `<img src="${src}" alt="${alt}" width="${width}" style="display:block;height:auto;max-width:100%;" />`; return `<img src="${src}" alt="${alt}" width="${width}" style="display:block;height:auto;width:100%;max-width:${width}px;" />`;
}; };
const styleBase = (node: BlockNode, key: string) => { const styleBase = (node: BlockNode, key: string) => {
const value = (node.styles as Record<string, unknown>)[key]; const value = (node.styles as Record<string, unknown>)[key];
@@ -319,7 +319,7 @@ export const imageBlock = leaf(
{ {
emailHtml: ({ node }) => emailHtml: ({ node }) =>
emailCell( emailCell(
`<img src="${html(attrs(node).src)}" alt="${html(attrs(node).decorative ? "" : attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" style="border:0;display:block;height:auto;max-width:100%;" />`, `<img src="${html(attrs(node).src)}" alt="${html(attrs(node).decorative ? "" : attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" style="border:0;display:block;height:auto;width:100%;max-width:${html(attrs(node).width)}px;" />`,
node, node,
), ),
ampEmail: ({ node }) => ampEmail: ({ node }) =>
@@ -401,7 +401,7 @@ export const videoBlock = leaf(
height: string({ default: "338" }), height: string({ default: "338" }),
}) as never, }) as never,
{ {
emailHtml: ({ node }) => emailCell(`<a href="${html(attrs(node).href)}" aria-label="${html(attrs(node).title)}"><img src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" style="border:0;display:block;height:auto;max-width:100%;" /></a>`, node), emailHtml: ({ node }) => emailCell(`<a href="${html(attrs(node).href)}" aria-label="${html(attrs(node).title)}"><img src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" style="border:0;display:block;height:auto;width:100%;max-width:${html(attrs(node).width)}px;" /></a>`, node),
ampEmail: ({ node }) => emailCell(`<a href="${html(attrs(node).href)}" aria-label="${html(attrs(node).title)}"><amp-img src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" layout="responsive"></amp-img></a>`, node), ampEmail: ({ node }) => emailCell(`<a href="${html(attrs(node).href)}" aria-label="${html(attrs(node).title)}"><amp-img src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" layout="responsive"></amp-img></a>`, node),
mjml: ({ node }) => `<mj-image href="${html(attrs(node).href)}" src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}px" />`, mjml: ({ node }) => `<mj-image href="${html(attrs(node).href)}" src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}px" />`,
}, },
@@ -54,6 +54,7 @@ test("product and RSS images survive HTML, AMP and strict MJML exports", async (
const result = await renderEmail(document(type, props), { amp: true, mjml: true }); const result = await renderEmail(document(type, props), { amp: true, mjml: true });
expect(result.ok).toBe(true); expect(result.ok).toBe(true);
if (!result.ok) continue; if (!result.ok) continue;
expect(result.value.parts.html.content).toContain('width:100%;max-width:320px;');
for (const output of [ for (const output of [
result.value.parts.html.content, result.value.parts.html.content,
result.value.parts.amp?.content, result.value.parts.amp?.content,