Centralize palette block creation in the email framework
This commit is contained in:
1 parent
89954181ec
commit
16d804e16f
3 files changed
+36
-2
No files matched your search
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/email-renderer",
|
"name": "@wrnexus/email-renderer",
|
||||||
"version": "0.1.40",
|
"version": "0.1.41",
|
||||||
"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": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./blocks": "./src/blocks.ts"
|
"./blocks": "./src/blocks.ts",
|
||||||
|
"./create": "./src/create.ts"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import type { BlockNode } from "@wrnexus/blocks";
|
||||||
|
import { emailCoreBlocks } from "./blocks.ts";
|
||||||
|
|
||||||
|
/** Canonical initial content for palette blocks; time and instance IDs are injectable. */
|
||||||
|
export function createEmailBlock(type: string, context: { id(): string; now?: number }): BlockNode {
|
||||||
|
const now = context.now ?? Date.now();
|
||||||
|
const defaults: Record<string, Record<string, unknown>> = {"content.heading":{text:'New heading',level:'2'},"content.text":{text:'New paragraph'},"content.button":{label:'Call to action',href:'https://example.com'},"content.image":{src:'https://placehold.co/600x300',alt:'',width:'600',height:'300',decorative:false},"content.divider":{},"content.spacer":{height:'24'},"content.video":{title:'Watch video',href:'https://example.com',thumbnail:'https://placehold.co/600x338',alt:'Video thumbnail',width:'600',height:'338'},"content.social":{label:'Follow us',facebook:'',instagram:'',linkedin:'',x:''},"content.countdown":{label:'Offer ends',deadline:new Date(now+86400000).toISOString(),fallback:'This offer has ended.'},"content.survey":{question:'What do you think?',buttonLabel:'Answer survey',href:'https://example.com'},"content.feed-item":{width:'600',height:'400',feedUrl:'',title:'Latest article',summary:'Article summary',href:'https://example.com',image:''},"commerce.product":{width:'600',height:'400',provider:'manual',storeUrl:'',productId:'',title:'Featured product',price:'$0.00',image:'https://placehold.co/600x400',href:'https://example.com',buttonLabel:'Shop now'}};
|
||||||
|
const definition = emailCoreBlocks.find(block => block.manifest.type === type);
|
||||||
|
if (!definition || !Object.prototype.hasOwnProperty.call(defaults, type))
|
||||||
|
throw new Error("This block is not available for palette insertion.");
|
||||||
|
const props = definition.manifest.props.parse(defaults[type], "props");
|
||||||
|
if (!props.ok) throw new Error(props.errors.map(error => error.message).join("\n"));
|
||||||
|
const node = definition.create(context);
|
||||||
|
return { ...node, type: definition.manifest.type, version: definition.manifest.version, props: props.value };
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import { createEmailBlock } from "../src/create.ts";
|
||||||
|
import { emailCoreBlocks } from "../src/blocks.ts";
|
||||||
|
|
||||||
|
test("palette factory produces schema-valid independent blocks with injected IDs and time", () => {
|
||||||
|
let sequence = 0;
|
||||||
|
for (const definition of emailCoreBlocks.filter(block => /^(content|commerce)\./.test(block.manifest.type))) {
|
||||||
|
const context = { id: () => `node-${++sequence}`, now: Date.parse("2026-09-05T00:00:00Z") };
|
||||||
|
const first = createEmailBlock(definition.manifest.type, context), second = createEmailBlock(definition.manifest.type, context);
|
||||||
|
expect(definition.manifest.props.parse(first.props).ok).toBe(true);
|
||||||
|
expect(first.id).not.toBe(second.id);
|
||||||
|
expect(first.props).toEqual(second.props);
|
||||||
|
expect(first.props).not.toBe(second.props);
|
||||||
|
expect(first.version).toBe(definition.manifest.version);
|
||||||
|
if (first.type === "content.countdown") expect(first.props.deadline).toBe("2026-09-06T00:00:00.000Z");
|
||||||
|
}
|
||||||
|
expect(() => createEmailBlock("untrusted.block", { id: () => "id" })).toThrow();
|
||||||
|
});
|
||||||
Reference in new issue
Block a user