@maizzle/framework
Version:
Maizzle is a framework that helps you quickly build HTML emails with Tailwind CSS.
94 lines (93 loc) • 3.35 kB
JavaScript
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