UNPKG

@maizzle/framework

Version:

Maizzle is a framework that helps you quickly build HTML emails with Tailwind CSS.

94 lines (93 loc) 3.35 kB
import { parse } from "../utils/ast/parser.js"; import { walk } from "../utils/ast/walker.js"; import { serialize } from "../utils/ast/serializer.js"; import "../utils/ast/index.js"; //#region src/transformers/attributeToStyle.ts /** * Default list of attributes that can be converted to inline styles. */ const DEFAULT_ATTRIBUTES = [ "width", "height", "bgcolor", "background", "align", "valign" ]; /** * Convert HTML attributes to inline CSS styles. * * Supported attributes: * - `width`: `width: ${value}${unit}` (px and %, defaults to px) * - `height`: `height: ${value}${unit}` (px and %, defaults to px) * - `bgcolor`: `background-color: ${value}` * - `background`: `background-image: url('${value}')` * - `align`: on `<table>`, `left`/`right` become `float`, `center` becomes * `margin-left/right: auto`; on other elements, becomes `text-align` * - `valign`: `vertical-align: ${value}` * * @param html HTML string to transform. * @param attributes `true` to process the default set, an array to restrict * to specific attribute names, `false` to disable. * @returns The transformed HTML string. * * @example * import { attributeToStyle } from '@maizzle/framework' * * const out = attributeToStyle('<table align="center"><tr><td bgcolor="#f00">x</td></tr></table>') * * // Restrict to specific attributes: * const limited = attributeToStyle(html, ['width', 'height']) */ function attributeToStyle(html, attributes = true) { return serialize(attributeToStyleDom(parse(html), attributes)); } /** * DOM-form of {@link attributeToStyle} used by the internal transformer * pipeline. Takes a parsed DOM, returns a parsed DOM — avoids redundant * serialize/parse round-trips when chained with other transformers. */ function attributeToStyleDom(dom, attributes = true) { if (!attributes) return dom; const attributesToProcess = attributes === true ? DEFAULT_ATTRIBUTES : Array.isArray(attributes) ? attributes : []; if (attributesToProcess.length === 0) return dom; walk(dom, (node) => { const el = node; if (!("attribs" in el) || !el.attribs) return; const styles = []; for (const attr of attributesToProcess) { const value = el.attribs[attr]; if (!value) continue; const styleValue = convertAttributeToStyle(el.name, attr, value); if (styleValue) styles.push(styleValue); } if (styles.length > 0) { const existingStyle = el.attribs.style || ""; const separator = existingStyle ? "; " : ""; el.attribs.style = existingStyle + separator + styles.join("; "); } }); return dom; } /** * Convert a single HTML attribute value to a CSS style declaration. */ function convertAttributeToStyle(tagName, attr, value) { switch (attr) { case "width": case "height": return `${attr}: ${/^\d+$/.test(value) ? `${value}px` : value}`; case "bgcolor": return `background-color: ${value}`; case "background": return `background-image: url('${value}')`; case "align": if (tagName === "table") { if (value === "left" || value === "right") return `float: ${value}`; if (value === "center") return "margin-left: auto; margin-right: auto"; } return `text-align: ${value}`; case "valign": return `vertical-align: ${value}`; default: return null; } } //#endregion export { attributeToStyle, attributeToStyleDom }; //# sourceMappingURL=attributeToStyle.js.map