@templatical/renderer
Advanced tools
+16
-1
@@ -83,3 +83,3 @@ import { CustomFont, Block, ColumnLayout, SpacingValue, CustomBlock, TemplateContent } from '@templatical/types'; | ||
| * Get the MJML css-class attribute string for visibility hiding. | ||
| * Returns a string like ` css-class="tpl-hide-desktop tpl-hide-tablet"` or empty string. | ||
| * Returns a string like ` css-class="tpl-hide-desktop"` or empty string. | ||
| */ | ||
@@ -137,2 +137,17 @@ declare function getCssClassAttr(block: Block): string; | ||
| /** | ||
| * Resolves the definition-level CSS for a custom block type. Called once | ||
| * per unique `customType` present in the content tree (not per instance). | ||
| * The non-empty results are deduped by content and emitted as additional | ||
| * `<mj-style>` blocks inside `<mj-head>` alongside the built-in visibility | ||
| * media queries. | ||
| * | ||
| * Editor consumers: pass a function that reads | ||
| * `blockRegistry.getDefinition(customType)?.stylesheet`. | ||
| * | ||
| * Headless consumers: provide your own resolver, typically from the same | ||
| * definitions map used by `renderCustomBlock`. Return `undefined` or `null` | ||
| * for definitions without a stylesheet — those are skipped. | ||
| */ | ||
| getCustomBlockStylesheet?: (customType: string) => string | undefined | null; | ||
| /** | ||
| * Base URL (no trailing slash) for the social icon PNG assets. Resolved to | ||
@@ -139,0 +154,0 @@ * `${baseUrl}/${style}/${platform}.png` per icon. Defaults to the |
+53
-13
@@ -8,3 +8,3 @@ // src/index.ts | ||
| description: "Render Templatical email templates to MJML", | ||
| version: "0.9.1", | ||
| version: "0.10.0", | ||
| bugs: "https://github.com/templatical/sdk/issues", | ||
@@ -240,3 +240,3 @@ dependencies: { | ||
| } | ||
| return !visibility.desktop && !visibility.tablet && !visibility.mobile; | ||
| return !visibility.desktop && !visibility.mobile; | ||
| } | ||
@@ -259,5 +259,2 @@ function getCssClassAttr(block) { | ||
| } | ||
| if (!visibility.tablet) { | ||
| classes.push("tpl-hide-tablet"); | ||
| } | ||
| if (!visibility.mobile) { | ||
@@ -439,3 +436,5 @@ classes.push("tpl-hide-mobile"); | ||
| const visibilityAttr = getCssClassAttr(block); | ||
| return `<mj-text${visibilityAttr}> | ||
| const padding = toPaddingString(block.styles.padding); | ||
| const bgColor = bgAttr(block.styles.backgroundColor, "container"); | ||
| return `<mj-text padding="${padding}"${bgColor}${visibilityAttr}> | ||
| ${content} | ||
@@ -653,4 +652,5 @@ </mj-text>`; | ||
| const visibilityAttr = getCssClassAttr(block); | ||
| const bgColor = bgAttr(block.styles?.backgroundColor, "container"); | ||
| return `<mj-text${bgColor}${visibilityAttr}> | ||
| const padding = toPaddingString(block.styles.padding); | ||
| const bgColor = bgAttr(block.styles.backgroundColor, "container"); | ||
| return `<mj-text padding="${padding}"${bgColor}${visibilityAttr}> | ||
| ${content} | ||
@@ -843,2 +843,6 @@ </mj-text>`; | ||
| ); | ||
| const customBlockStylesheets = collectCustomBlockStylesheets( | ||
| content, | ||
| options?.getCustomBlockStylesheet | ||
| ); | ||
| const renderContext = new RenderContext( | ||
@@ -875,9 +879,6 @@ content.settings.width, | ||
| } | ||
| @media only screen and (min-width: 481px) and (max-width: 768px) { | ||
| .tpl-hide-tablet { display: none !important; mso-hide: all !important; } | ||
| } | ||
| @media only screen and (min-width: 769px) { | ||
| @media only screen and (min-width: 481px) { | ||
| .tpl-hide-desktop { display: none !important; mso-hide: all !important; } | ||
| } | ||
| </mj-style> | ||
| </mj-style>${renderCustomBlockStylesheets(customBlockStylesheets)} | ||
| </mj-head> | ||
@@ -981,2 +982,41 @@ <mj-body width="${renderContext.containerWidth}px" background-color="${backgroundColor}"> | ||
| } | ||
| function collectCustomBlockStylesheets(content, resolver) { | ||
| if (!resolver) { | ||
| return []; | ||
| } | ||
| const customBlocks = []; | ||
| collectCustomBlocks(content.blocks, customBlocks); | ||
| if (customBlocks.length === 0) { | ||
| return []; | ||
| } | ||
| const seenTypes = /* @__PURE__ */ new Set(); | ||
| const seenContent = /* @__PURE__ */ new Set(); | ||
| const stylesheets = []; | ||
| for (const block of customBlocks) { | ||
| if (seenTypes.has(block.customType)) { | ||
| continue; | ||
| } | ||
| seenTypes.add(block.customType); | ||
| const css = resolver(block.customType); | ||
| if (!css) { | ||
| continue; | ||
| } | ||
| const trimmed = css.trim(); | ||
| if (trimmed === "" || seenContent.has(trimmed)) { | ||
| continue; | ||
| } | ||
| seenContent.add(trimmed); | ||
| stylesheets.push(trimmed); | ||
| } | ||
| return stylesheets; | ||
| } | ||
| function renderCustomBlockStylesheets(stylesheets) { | ||
| if (stylesheets.length === 0) { | ||
| return ""; | ||
| } | ||
| return stylesheets.map((css) => ` | ||
| <mj-style> | ||
| ${css} | ||
| </mj-style>`).join(""); | ||
| } | ||
| export { | ||
@@ -983,0 +1023,0 @@ DEFAULT_SOCIAL_ICONS_BASE_URL, |
+2
-2
| { | ||
| "name": "@templatical/renderer", | ||
| "description": "Render Templatical email templates to MJML", | ||
| "version": "0.9.1", | ||
| "version": "0.10.0", | ||
| "bugs": "https://github.com/templatical/sdk/issues", | ||
| "dependencies": { | ||
| "@templatical/types": "0.9.1" | ||
| "@templatical/types": "0.10.0" | ||
| }, | ||
@@ -9,0 +9,0 @@ "devDependencies": { |
Sorry, the diff of this file is too big to display
470293
1.22%1167
4.95%+ Added
- Removed
Updated