From 91e3baa95aa9a2a81e651b355e6ea017c76c6f2c Mon Sep 17 00:00:00 2001 From: "Grok (via xAI)" Date: Thu, 15 Oct 2026 04:29:12 +0000 Subject: [PATCH] feat: template-level shell defaults and structured attributes - htmlAttributes / bodyAttributes accept a raw string or a structured map. - openTag / serializeAttributes handle both shapes (raw interpolation). - EmailTemplate.shell holds default DocumentShellOptions; per-render props override them. - composeEmail merges the two and forwards the result to document(). A Postmark-style or styled-body template can declare its shape once. --- README.md | 2 +- llms-full.txt | 4 ++-- src/index.ts | 2 ++ src/templates/body/body.ts | 10 +++++---- src/templates/document/document.ts | 28 ++++++++++++++--------- src/templates/email/email.ts | 2 +- src/templates/email/shell.ts | 36 ++++++++++++++++++++---------- src/templates/email/types.ts | 4 ++++ src/utils/openTag.ts | 30 ++++++++++++++++++++++--- test/email.test.ts | 18 +++++++++++++++ test/index.test.ts | 11 +++++++++ 11 files changed, 113 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index caf61f1..711fce0 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ The email preset calls these. They stay public so a part, or a caller, can use t | `footer({ companyName?, unsubscribeUrl? })` | `