@pagenflow/email 1.4.5 → 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/utils/MiniDomParser.d.ts +23 -0
- package/dist/components/utils/injectLinkStyles.d.ts +1 -0
- package/dist/index.cjs.js +175 -132
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +175 -132
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/Body.js +0 -57
- package/dist/components/BodyDev.js +0 -57
- package/dist/components/Button.js +0 -327
- package/dist/components/Column.js +0 -127
- package/dist/components/Container.js +0 -179
- package/dist/components/Divider.js +0 -41
- package/dist/components/Font.js +0 -44
- package/dist/components/Head.js +0 -134
- package/dist/components/HeadDev.js +0 -311
- package/dist/components/Heading.js +0 -46
- package/dist/components/Html.js +0 -20
- package/dist/components/Icon.js +0 -276
- package/dist/components/Image.js +0 -119
- package/dist/components/MsoConditional.js +0 -19
- package/dist/components/Row.js +0 -157
- package/dist/components/Section.js +0 -65
- package/dist/components/Spacer.js +0 -40
- package/dist/components/Text.js +0 -42
- package/dist/index.js +0 -17
- package/dist/types/IInnerLink.js +0 -1
- package/dist/types/ResolvedFont.js +0 -1
- package/dist/types/index.js +0 -1
- package/dist/utils/isEqual.js +0 -1439
- package/dist/utils/memoUtils.js +0 -55
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface StyleMap {
|
|
2
|
+
[property: string]: string;
|
|
3
|
+
}
|
|
4
|
+
export interface DomNode {
|
|
5
|
+
tagName: string;
|
|
6
|
+
attributes: Record<string, string>;
|
|
7
|
+
style: StyleMap;
|
|
8
|
+
children: DomNode[];
|
|
9
|
+
parent: DomNode | null;
|
|
10
|
+
rawHtml: string;
|
|
11
|
+
}
|
|
12
|
+
export default class MiniDomParser {
|
|
13
|
+
private html;
|
|
14
|
+
root: DomNode;
|
|
15
|
+
constructor(html: string);
|
|
16
|
+
private makeNode;
|
|
17
|
+
parseStyle(styleStr: string): StyleMap;
|
|
18
|
+
private parseAttributes;
|
|
19
|
+
private parse;
|
|
20
|
+
private collectByTag;
|
|
21
|
+
querySelectorAllByTag(tag: string): DomNode[];
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function injectLinkStyles(html: string, fallback?: Record<string, string>): string;
|
package/dist/index.cjs.js
CHANGED
|
@@ -6,16 +6,16 @@ var React = require('react');
|
|
|
6
6
|
function Body({ children, config = {} }) {
|
|
7
7
|
var _a, _b, _c, _d;
|
|
8
8
|
// Extract config values with fallbacks
|
|
9
|
-
const globalColor = config.color || "
|
|
10
|
-
const globalFontSize = config.fontSize || "
|
|
11
|
-
const globalBackgroundColor = config.backgroundColor || "
|
|
12
|
-
const globalLineHeight = config.lineHeight || "
|
|
13
|
-
const globalFontFamily = config.fontFamily || "
|
|
9
|
+
const globalColor = config.color || "";
|
|
10
|
+
const globalFontSize = config.fontSize || "";
|
|
11
|
+
const globalBackgroundColor = config.backgroundColor || "";
|
|
12
|
+
const globalLineHeight = config.lineHeight || "";
|
|
13
|
+
const globalFontFamily = config.fontFamily || "";
|
|
14
14
|
// Background image properties
|
|
15
15
|
const bgImage = ((_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.src) || "";
|
|
16
|
-
const bgRepeat = ((_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.repeat) || "
|
|
17
|
-
const bgSize = ((_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.size) || "
|
|
18
|
-
const bgPosition = ((_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.position) || "
|
|
16
|
+
const bgRepeat = ((_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.repeat) || "";
|
|
17
|
+
const bgSize = ((_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.size) || "";
|
|
18
|
+
const bgPosition = ((_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.position) || "";
|
|
19
19
|
// 1. Style for the <body> tag inline
|
|
20
20
|
const bodyStyle = {
|
|
21
21
|
backgroundColor: globalBackgroundColor,
|
|
@@ -1614,135 +1614,40 @@ function Button({ config, devMode }) {
|
|
|
1614
1614
|
};
|
|
1615
1615
|
// Border styles
|
|
1616
1616
|
const borderStyleString = getBorderStyleString$2(border);
|
|
1617
|
-
// --- Determine Button Approach Based on Width ---
|
|
1618
|
-
// Check if width is percentage-based or not defined
|
|
1619
|
-
const isPercentageWidth = !width || width.includes("%");
|
|
1620
|
-
const useSimpleOutlookApproach = isPercentageWidth;
|
|
1621
1617
|
const align = justifyContent ? justifyMap$3[justifyContent] : undefined;
|
|
1622
|
-
// --- VML Calculation and Code for Outlook Compatibility (Fixed Width Only) ---
|
|
1623
|
-
let vmlButton = "";
|
|
1624
|
-
if (!useSimpleOutlookApproach) {
|
|
1625
|
-
// VML needs fixed pixel height. We estimate it based on padding and potential wrapping.
|
|
1626
|
-
const numericPadding = padding
|
|
1627
|
-
? parseInt(padding.split(" ")[0] || "12", 10)
|
|
1628
|
-
: 12;
|
|
1629
|
-
const numericFontSize = fontSize ? parseInt(fontSize, 10) : 0;
|
|
1630
|
-
const numericLineHeight = lineHeight
|
|
1631
|
-
? lineHeight.includes("px")
|
|
1632
|
-
? parseInt(lineHeight, 10)
|
|
1633
|
-
: numericFontSize * parseFloat(lineHeight)
|
|
1634
|
-
: numericFontSize;
|
|
1635
|
-
// Trust user's explicit pixel width - no calculation needed
|
|
1636
|
-
const vmlWidth = parseInt(width, 10);
|
|
1637
|
-
// Calculate VML height - trust user's padding and let text wrap naturally
|
|
1638
|
-
// VML v:textbox will handle text wrapping automatically
|
|
1639
|
-
const textContent = typeof children === "string" ? children : "";
|
|
1640
|
-
// Estimate number of lines based on text length and button width
|
|
1641
|
-
const horizontalPadding = (padding === null || padding === void 0 ? void 0 : padding.split(" ")[1])
|
|
1642
|
-
? parseInt(padding.split(" ")[1], 10) * 2
|
|
1643
|
-
: numericPadding * 2;
|
|
1644
|
-
const availableTextWidth = vmlWidth - horizontalPadding;
|
|
1645
|
-
const charWidthMultiplier = fontWeight && parseInt(fontWeight) >= 500 ? 0.7 : 0.6;
|
|
1646
|
-
const avgCharWidth = numericFontSize * charWidthMultiplier;
|
|
1647
|
-
const charsPerLine = Math.max(Math.floor(availableTextWidth / avgCharWidth), 1);
|
|
1648
|
-
const numberOfLines = Math.max(Math.ceil(textContent.length / charsPerLine), 1);
|
|
1649
|
-
// Calculate height: vertical padding + (lines * line height) + extra buffer for VML
|
|
1650
|
-
const textHeight = numberOfLines * numericLineHeight;
|
|
1651
|
-
// Add extra 4px buffer to prevent bottom cropping in VML
|
|
1652
|
-
const vmlHeight = Math.max(numericPadding * 2 + textHeight + 4, 40);
|
|
1653
|
-
// VML colors must use the full hex format (e.g., #000000)
|
|
1654
|
-
const vmlFillColor = backgroundColor
|
|
1655
|
-
? backgroundColor.startsWith("#")
|
|
1656
|
-
? backgroundColor
|
|
1657
|
-
: `#${backgroundColor}`
|
|
1658
|
-
: undefined;
|
|
1659
|
-
// VML stroke color for border
|
|
1660
|
-
const vmlStrokeColor = (border === null || border === void 0 ? void 0 : border.color) || vmlFillColor;
|
|
1661
|
-
const vmlStrokeWeight = (border === null || border === void 0 ? void 0 : border.width) ? parseInt(border.width, 10) : 0;
|
|
1662
|
-
const hasVmlStroke = vmlStrokeWeight > 0;
|
|
1663
|
-
// Build VML font styles - consistent with other rendering paths
|
|
1664
|
-
const vmlFontWeight = fontWeight;
|
|
1665
|
-
const vmlFontStyle = fontStyle === "italic" ? "font-style:italic;" : "";
|
|
1666
|
-
const vmlLetterSpacing = letterSpacing
|
|
1667
|
-
? `letter-spacing:${letterSpacing};`
|
|
1668
|
-
: "";
|
|
1669
|
-
const vmlTextTransform = textTransform
|
|
1670
|
-
? `text-transform:${textTransform};`
|
|
1671
|
-
: "";
|
|
1672
|
-
const vmlTextDecoration = textDecoration && textDecoration !== "none"
|
|
1673
|
-
? `text-decoration:${textDecoration};`
|
|
1674
|
-
: "";
|
|
1675
|
-
const vmlWhiteSpace = whiteSpace ? `white-space:${whiteSpace};` : "";
|
|
1676
|
-
const vmlDirection = direction ? `direction:${direction};` : "";
|
|
1677
|
-
const vmlOpacity = opacity !== undefined ? `opacity:${opacity};` : "";
|
|
1678
|
-
// VML code uses MSO conditional comments to render only in Outlook
|
|
1679
|
-
// Use table with explicit MSO height for vertical centering
|
|
1680
|
-
const horizontalPaddingValue = (padding === null || padding === void 0 ? void 0 : padding.split(" ")[1])
|
|
1681
|
-
? parseInt(padding.split(" ")[1], 10)
|
|
1682
|
-
: numericPadding;
|
|
1683
|
-
// For VML, we need to use a table inside to properly apply padding and centering
|
|
1684
|
-
let vmlAlignAttr = "";
|
|
1685
|
-
let vmlAlignStyle = "";
|
|
1686
|
-
if (textAlign === "center") {
|
|
1687
|
-
vmlAlignAttr = 'align="center"';
|
|
1688
|
-
}
|
|
1689
|
-
else if (textAlign) {
|
|
1690
|
-
vmlAlignStyle = `text-align:${textAlign};`;
|
|
1691
|
-
}
|
|
1692
|
-
// Border radius is intentionally omitted (arcsize="0%") for Outlook Classic.
|
|
1693
|
-
// Outlook Classic does not reliably support rounded corners and the result
|
|
1694
|
-
// is inconsistent, so we render sharp corners there instead.
|
|
1695
|
-
vmlButton = `
|
|
1696
|
-
<!--[if mso]>
|
|
1697
|
-
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" ${href ? `href="${href}"` : ""} style="height:${vmlHeight}px;width:${vmlWidth}px;" arcsize="0%" ${vmlStrokeColor ? `strokecolor="${vmlStrokeColor}"` : ""} ${hasVmlStroke ? `strokeweight="${vmlStrokeWeight}px"` : 'stroke="f"'} ${vmlFillColor ? `fillcolor="${vmlFillColor}"` : ""}>
|
|
1698
|
-
<w:anchorlock/>
|
|
1699
|
-
<v:textbox inset="${horizontalPaddingValue}px,${numericPadding}px,${horizontalPaddingValue}px,${numericPadding}px">
|
|
1700
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
|
|
1701
|
-
<tr>
|
|
1702
|
-
<td ${vmlAlignAttr} valign="middle" style="${vmlAlignStyle}${color ? `color:${color};` : ""}${safeFontFamily ? `font-family:${safeFontFamily};` : ""}${fontSize ? `font-size:${fontSize};` : ""}${vmlFontWeight ? `font-weight:${vmlFontWeight};` : ""}${vmlFontStyle}${vmlLetterSpacing}${vmlTextTransform}${vmlTextDecoration}${vmlWhiteSpace}${vmlDirection}${vmlOpacity}${lineHeight ? `line-height:${lineHeight};` : ""}mso-line-height-rule:exactly;">
|
|
1703
|
-
${typeof children === "string" ? children : ""}
|
|
1704
|
-
</td>
|
|
1705
|
-
</tr>
|
|
1706
|
-
</table>
|
|
1707
|
-
</v:textbox>
|
|
1708
|
-
</v:roundrect>
|
|
1709
|
-
<![endif]-->
|
|
1710
|
-
`;
|
|
1711
|
-
}
|
|
1712
1618
|
// --- Simple Outlook Approach for Percentage Widths ---
|
|
1713
1619
|
let simpleOutlookButton = "";
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
simpleOutlookButton = `
|
|
1620
|
+
// Build consistent inline styles for text properties
|
|
1621
|
+
const textDecorationStyle = textDecoration && textDecoration !== "none"
|
|
1622
|
+
? `text-decoration: ${textDecoration};`
|
|
1623
|
+
: "";
|
|
1624
|
+
const fontStyleProp = fontStyle ? `font-style: ${fontStyle};` : "";
|
|
1625
|
+
const letterSpacingProp = letterSpacing
|
|
1626
|
+
? `letter-spacing: ${letterSpacing};`
|
|
1627
|
+
: "";
|
|
1628
|
+
const textTransformProp = textTransform
|
|
1629
|
+
? `text-transform: ${textTransform};`
|
|
1630
|
+
: "";
|
|
1631
|
+
const whiteSpaceProp = whiteSpace ? `white-space: ${whiteSpace};` : "";
|
|
1632
|
+
const directionProp = direction ? `direction: ${direction};` : "";
|
|
1633
|
+
const opacityProp = opacity !== undefined ? `opacity: ${opacity};` : "";
|
|
1634
|
+
const wordBreakProp = wordBreak ? `word-break: ${wordBreak};` : "";
|
|
1635
|
+
// Border radius is intentionally omitted from the Outlook Classic table cell.
|
|
1636
|
+
// Outlook Classic ignores border-radius on table cells anyway, and including it
|
|
1637
|
+
// can cause unexpected rendering artifacts, so we explicitly leave it out.
|
|
1638
|
+
simpleOutlookButton = `
|
|
1734
1639
|
<!--[if mso]>
|
|
1735
1640
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse: collapse;">
|
|
1736
1641
|
<tr>
|
|
1737
1642
|
<td ${align ? `align="${align}"` : ""} style="padding: 0;">
|
|
1738
1643
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="${width || "auto"}" style="border-collapse: collapse;">
|
|
1739
1644
|
<tr>
|
|
1740
|
-
<td ${backgroundColor ? `bgcolor="${backgroundColor}"` : ""} ${textAlign ? `align="${textAlign}"` : ""} style="${padding ? `padding: ${padding};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${borderStyleString}">
|
|
1645
|
+
<td ${backgroundColor ? `bgcolor="${backgroundColor}"` : ""} ${textAlign ? `align="${textAlign}"` : ""} style="${padding ? `padding: ${padding};` : ""} ${href ? "cursor: pointer;" : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${borderStyleString}">
|
|
1741
1646
|
${href
|
|
1742
|
-
|
|
1647
|
+
? `<a href="${href}" target="${target}" rel="noopener noreferrer" style="${color ? `color: ${color};` : ""} ${textDecorationStyle} display: block; ${safeFontFamily ? `font-family: ${safeFontFamily};` : ""} ${fontSize ? `font-size: ${fontSize};` : ""} ${fontWeight ? `font-weight: ${fontWeight};` : ""} ${fontStyleProp} ${lineHeight ? `line-height: ${lineHeight};` : ""} ${letterSpacingProp} ${textTransformProp} ${textAlign ? `text-align: ${textAlign};` : ""} ${whiteSpaceProp} ${directionProp} ${opacityProp} ${wordBreakProp} mso-line-height-rule: exactly;">
|
|
1743
1648
|
${typeof children === "string" ? children : ""}
|
|
1744
1649
|
</a>`
|
|
1745
|
-
|
|
1650
|
+
: `<span style="${color ? `color: ${color};` : ""} ${textDecorationStyle} display: block; ${safeFontFamily ? `font-family: ${safeFontFamily};` : ""} ${fontSize ? `font-size: ${fontSize};` : ""} ${fontWeight ? `font-weight: ${fontWeight};` : ""} ${fontStyleProp} ${lineHeight ? `line-height: ${lineHeight};` : ""} ${letterSpacingProp} ${textTransformProp} ${textAlign ? `text-align: ${textAlign};` : ""} ${whiteSpaceProp} ${directionProp} ${opacityProp} ${wordBreakProp} mso-line-height-rule: exactly;">
|
|
1746
1651
|
${typeof children === "string" ? children : ""}
|
|
1747
1652
|
</span>`}
|
|
1748
1653
|
</td>
|
|
@@ -1753,7 +1658,6 @@ function Button({ config, devMode }) {
|
|
|
1753
1658
|
</table>
|
|
1754
1659
|
<![endif]-->
|
|
1755
1660
|
`;
|
|
1756
|
-
}
|
|
1757
1661
|
// Build shared inline style fragments for the non-MSO path.
|
|
1758
1662
|
// fontFamily uses the sanitized value so embedded quotes never break the
|
|
1759
1663
|
// style attribute string (which is always wrapped in double quotes).
|
|
@@ -1800,7 +1704,7 @@ function Button({ config, devMode }) {
|
|
|
1800
1704
|
padding: 0,
|
|
1801
1705
|
}, onClick: devMode ? (e) => e.preventDefault() : undefined, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { dangerouslySetInnerHTML: {
|
|
1802
1706
|
__html: `
|
|
1803
|
-
${
|
|
1707
|
+
${simpleOutlookButton}
|
|
1804
1708
|
<!--[if !mso]><!-->
|
|
1805
1709
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; width: 100%;">
|
|
1806
1710
|
<tbody>
|
|
@@ -1815,7 +1719,7 @@ function Button({ config, devMode }) {
|
|
|
1815
1719
|
${typeof children === "string" ? children : ""}
|
|
1816
1720
|
</span>`
|
|
1817
1721
|
: href
|
|
1818
|
-
? `<a href="${href}" target="${target}" rel="noopener noreferrer" style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; ${wordBreak ? `word-break: ${wordBreak};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${padding ? `padding: ${padding};` : ""}">
|
|
1722
|
+
? `<a href="${href}" target="${target}" rel="noopener noreferrer" style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; cursor: pointer; ${wordBreak ? `word-break: ${wordBreak};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${padding ? `padding: ${padding};` : ""}">
|
|
1819
1723
|
<span>
|
|
1820
1724
|
${typeof children === "string" ? children : ""}
|
|
1821
1725
|
</span>
|
|
@@ -2363,6 +2267,139 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
|
|
|
2363
2267
|
return (jsxRuntime.jsxs("head", { children: [jsxRuntime.jsx("meta", { httpEquiv: "Content-Type", content: "text/html; charset=utf-8" }), jsxRuntime.jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), jsxRuntime.jsx("meta", { httpEquiv: "X-UA-Compatible", content: "IE=edge" }), jsxRuntime.jsx("title", { children: title }), fonts.flatMap((resolved) => resolved.fontProps.map((props, i) => (jsxRuntime.jsx(Font, { ...props }, `${resolved.family}-${props.fontWeight}-${props.fontStyle}-${i}`)))), children, jsxRuntime.jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: msoResetStyles } }), jsxRuntime.jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: globalStyles } })] }));
|
|
2364
2268
|
}
|
|
2365
2269
|
|
|
2270
|
+
class MiniDomParser {
|
|
2271
|
+
constructor(html) {
|
|
2272
|
+
this.html = html;
|
|
2273
|
+
this.root = this.makeNode("root", {}, null);
|
|
2274
|
+
this.parse();
|
|
2275
|
+
}
|
|
2276
|
+
makeNode(tagName, attributes, parent) {
|
|
2277
|
+
var _a;
|
|
2278
|
+
return {
|
|
2279
|
+
tagName,
|
|
2280
|
+
attributes,
|
|
2281
|
+
style: this.parseStyle((_a = attributes["style"]) !== null && _a !== void 0 ? _a : ""),
|
|
2282
|
+
children: [],
|
|
2283
|
+
parent,
|
|
2284
|
+
rawHtml: "",
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
parseStyle(styleStr) {
|
|
2288
|
+
const map = {};
|
|
2289
|
+
for (const declaration of styleStr.split(";")) {
|
|
2290
|
+
const [prop, ...rest] = declaration.split(":");
|
|
2291
|
+
if (!prop || !rest.length)
|
|
2292
|
+
continue;
|
|
2293
|
+
const key = prop.trim().toLowerCase();
|
|
2294
|
+
const val = rest.join(":").trim();
|
|
2295
|
+
if (key && val)
|
|
2296
|
+
map[key] = val;
|
|
2297
|
+
}
|
|
2298
|
+
return map;
|
|
2299
|
+
}
|
|
2300
|
+
parseAttributes(attrStr) {
|
|
2301
|
+
var _a, _b, _c;
|
|
2302
|
+
const attrs = {};
|
|
2303
|
+
const pattern = /(\w[\w-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
|
|
2304
|
+
let m;
|
|
2305
|
+
while ((m = pattern.exec(attrStr)) !== null) {
|
|
2306
|
+
const key = m[1].toLowerCase();
|
|
2307
|
+
const val = (_c = (_b = (_a = m[2]) !== null && _a !== void 0 ? _a : m[3]) !== null && _b !== void 0 ? _b : m[4]) !== null && _c !== void 0 ? _c : "";
|
|
2308
|
+
attrs[key] = val;
|
|
2309
|
+
}
|
|
2310
|
+
return attrs;
|
|
2311
|
+
}
|
|
2312
|
+
parse() {
|
|
2313
|
+
const tokenPattern = /(<\/[\w]+\s*>|<[\w][^>]*>|[^<]+)/gi;
|
|
2314
|
+
const stack = [this.root];
|
|
2315
|
+
let m;
|
|
2316
|
+
while ((m = tokenPattern.exec(this.html)) !== null) {
|
|
2317
|
+
const token = m[0];
|
|
2318
|
+
if (token.startsWith("</")) {
|
|
2319
|
+
if (stack.length > 1)
|
|
2320
|
+
stack.pop();
|
|
2321
|
+
continue;
|
|
2322
|
+
}
|
|
2323
|
+
if (token.startsWith("<")) {
|
|
2324
|
+
const tagMatch = token.match(/^<([\w]+)([\s\S]*)>$/i);
|
|
2325
|
+
if (!tagMatch)
|
|
2326
|
+
continue;
|
|
2327
|
+
const tagName = tagMatch[1].toLowerCase();
|
|
2328
|
+
const attrStr = tagMatch[2].trim();
|
|
2329
|
+
const attrs = this.parseAttributes(attrStr);
|
|
2330
|
+
const current = stack[stack.length - 1];
|
|
2331
|
+
const node = this.makeNode(tagName, attrs, current);
|
|
2332
|
+
node.rawHtml = token;
|
|
2333
|
+
current.children.push(node);
|
|
2334
|
+
const selfClosing = /\/$/.test(attrStr) ||
|
|
2335
|
+
["br", "hr", "img", "input", "meta", "link"].includes(tagName);
|
|
2336
|
+
if (!selfClosing)
|
|
2337
|
+
stack.push(node);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
collectByTag(node, tag, results) {
|
|
2342
|
+
if (node.tagName === tag)
|
|
2343
|
+
results.push(node);
|
|
2344
|
+
for (const child of node.children) {
|
|
2345
|
+
this.collectByTag(child, tag, results);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
querySelectorAllByTag(tag) {
|
|
2349
|
+
const results = [];
|
|
2350
|
+
this.collectByTag(this.root, tag.toLowerCase(), results);
|
|
2351
|
+
return results;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
function resolveInheritedStyle(node, prop) {
|
|
2356
|
+
let el = node.parent;
|
|
2357
|
+
while (el && el.tagName !== "root") {
|
|
2358
|
+
const val = el.style[prop];
|
|
2359
|
+
if (val && val !== "inherit")
|
|
2360
|
+
return val;
|
|
2361
|
+
el = el.parent;
|
|
2362
|
+
}
|
|
2363
|
+
return undefined;
|
|
2364
|
+
}
|
|
2365
|
+
const BROWSER_LINK_DEFAULTS = ["color", "text-decoration"];
|
|
2366
|
+
function resolveAnchorStyles(anchor, fallback) {
|
|
2367
|
+
const resolved = { ...anchor.style };
|
|
2368
|
+
for (const prop of BROWSER_LINK_DEFAULTS) {
|
|
2369
|
+
if (resolved[prop] && resolved[prop] !== "inherit")
|
|
2370
|
+
continue;
|
|
2371
|
+
const inherited = resolveInheritedStyle(anchor, prop);
|
|
2372
|
+
if (inherited) {
|
|
2373
|
+
resolved[prop] = inherited;
|
|
2374
|
+
}
|
|
2375
|
+
else if (fallback === null || fallback === void 0 ? void 0 : fallback[prop]) {
|
|
2376
|
+
resolved[prop] = fallback[prop];
|
|
2377
|
+
}
|
|
2378
|
+
// if neither — leave it out entirely, don't force inherit
|
|
2379
|
+
}
|
|
2380
|
+
return Object.entries(resolved)
|
|
2381
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
2382
|
+
.join(";");
|
|
2383
|
+
}
|
|
2384
|
+
function injectLinkStyles(html, fallback) {
|
|
2385
|
+
if (!html || (!html.includes("<a ") && !html.includes("<a>")))
|
|
2386
|
+
return html;
|
|
2387
|
+
const parser = new MiniDomParser(html);
|
|
2388
|
+
const anchors = parser.querySelectorAllByTag("a");
|
|
2389
|
+
let result = html;
|
|
2390
|
+
for (const anchor of anchors) {
|
|
2391
|
+
const resolvedStyle = resolveAnchorStyles(anchor, fallback !== null && fallback !== void 0 ? fallback : {});
|
|
2392
|
+
const cleanAttrs = anchor.rawHtml
|
|
2393
|
+
.replace(/^<a\s*/i, "")
|
|
2394
|
+
.replace(/>$/, "")
|
|
2395
|
+
.replace(/style\s*=\s*(?:"[^"]*"|'[^']*')/gi, "")
|
|
2396
|
+
.trim();
|
|
2397
|
+
const newTag = `<a ${cleanAttrs} style="${resolvedStyle}">`.replace(/\s+/g, " ");
|
|
2398
|
+
result = result.replace(anchor.rawHtml, newTag);
|
|
2399
|
+
}
|
|
2400
|
+
return result;
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2366
2403
|
function Heading({ config, devMode, children }) {
|
|
2367
2404
|
const { text, level = "h1", padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, wordBreak, whiteSpace, } = config;
|
|
2368
2405
|
// Determine the content to render
|
|
@@ -2379,7 +2416,7 @@ function Heading({ config, devMode, children }) {
|
|
|
2379
2416
|
const headingStyle = {
|
|
2380
2417
|
color: color,
|
|
2381
2418
|
textAlign: textAlign,
|
|
2382
|
-
fontFamily: fontFamily
|
|
2419
|
+
fontFamily: fontFamily,
|
|
2383
2420
|
fontSize: fontSize,
|
|
2384
2421
|
fontWeight: fontWeight,
|
|
2385
2422
|
fontStyle: fontStyle,
|
|
@@ -2396,6 +2433,9 @@ function Heading({ config, devMode, children }) {
|
|
|
2396
2433
|
// Outlook specific fixes (using string indexing)
|
|
2397
2434
|
["msoLineHeightRule"]: "exactly",
|
|
2398
2435
|
};
|
|
2436
|
+
const processedHtml = isString
|
|
2437
|
+
? injectLinkStyles(content, headingStyle)
|
|
2438
|
+
: "";
|
|
2399
2439
|
// Dynamically create the Heading element
|
|
2400
2440
|
const HeadingTag = level;
|
|
2401
2441
|
return (
|
|
@@ -2403,7 +2443,7 @@ function Heading({ config, devMode, children }) {
|
|
|
2403
2443
|
jsxRuntime.jsx("table", { "aria-label": "Heading Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2404
2444
|
width: "100%",
|
|
2405
2445
|
borderCollapse: "collapse",
|
|
2406
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: isString ? (jsxRuntime.jsx(HeadingTag, { style: headingStyle, dangerouslySetInnerHTML: { __html:
|
|
2446
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: isString ? (jsxRuntime.jsx(HeadingTag, { style: headingStyle, dangerouslySetInnerHTML: { __html: processedHtml } })) : (jsxRuntime.jsx(HeadingTag, { style: headingStyle, children: content })) }) }) }) }));
|
|
2407
2447
|
}
|
|
2408
2448
|
var Heading_default = React.memo(Heading, arePropsEqual);
|
|
2409
2449
|
|
|
@@ -2878,7 +2918,7 @@ function Text({ config, devMode, children }) {
|
|
|
2878
2918
|
const contentStyle = {
|
|
2879
2919
|
color: color,
|
|
2880
2920
|
textAlign: textAlign,
|
|
2881
|
-
fontFamily: fontFamily
|
|
2921
|
+
fontFamily: fontFamily,
|
|
2882
2922
|
fontSize: fontSize,
|
|
2883
2923
|
fontWeight: fontWeight,
|
|
2884
2924
|
fontStyle: fontStyle,
|
|
@@ -2898,10 +2938,13 @@ function Text({ config, devMode, children }) {
|
|
|
2898
2938
|
// Determine content to render
|
|
2899
2939
|
const content = text !== null && text !== void 0 ? text : children;
|
|
2900
2940
|
const isString = typeof content === "string";
|
|
2941
|
+
const processedHtml = isString
|
|
2942
|
+
? injectLinkStyles(content, contentStyle)
|
|
2943
|
+
: "";
|
|
2901
2944
|
return (jsxRuntime.jsx("table", { "aria-label": "Text Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2902
2945
|
width: "100%",
|
|
2903
2946
|
borderCollapse: "collapse",
|
|
2904
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: isString ? (jsxRuntime.jsx("div", { style: contentStyle, dangerouslySetInnerHTML: { __html:
|
|
2947
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: isString ? (jsxRuntime.jsx("div", { style: contentStyle, dangerouslySetInnerHTML: { __html: processedHtml } })) : (jsxRuntime.jsx("div", { style: contentStyle, children: content })) }) }) }) }));
|
|
2905
2948
|
}
|
|
2906
2949
|
var Text_default = React.memo(Text, arePropsEqual);
|
|
2907
2950
|
|