@pagenflow/email 1.4.4 → 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.
Files changed (39) hide show
  1. package/dist/components/Button.d.ts +4 -0
  2. package/dist/components/Column.d.ts +1 -1
  3. package/dist/components/Container.d.ts +1 -1
  4. package/dist/components/Image.d.ts +8 -0
  5. package/dist/components/Row.d.ts +1 -1
  6. package/dist/components/Section.d.ts +1 -1
  7. package/dist/components/Text.d.ts +2 -1
  8. package/dist/components/utils/MiniDomParser.d.ts +23 -0
  9. package/dist/components/utils/injectLinkStyles.d.ts +1 -0
  10. package/dist/index.cjs.js +177 -132
  11. package/dist/index.cjs.js.map +1 -1
  12. package/dist/index.esm.js +177 -132
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/types/IInnerLink.d.ts +17 -0
  15. package/package.json +1 -1
  16. package/dist/components/Body.js +0 -57
  17. package/dist/components/BodyDev.js +0 -57
  18. package/dist/components/Button.js +0 -327
  19. package/dist/components/Column.js +0 -127
  20. package/dist/components/Container.js +0 -179
  21. package/dist/components/Divider.js +0 -41
  22. package/dist/components/Font.js +0 -44
  23. package/dist/components/Head.js +0 -134
  24. package/dist/components/HeadDev.js +0 -311
  25. package/dist/components/Heading.js +0 -46
  26. package/dist/components/Html.js +0 -20
  27. package/dist/components/Icon.js +0 -276
  28. package/dist/components/Image.js +0 -119
  29. package/dist/components/MsoConditional.js +0 -19
  30. package/dist/components/Row.js +0 -157
  31. package/dist/components/Section.js +0 -65
  32. package/dist/components/Spacer.js +0 -40
  33. package/dist/components/Text.js +0 -42
  34. package/dist/index.js +0 -17
  35. package/dist/types/IInnerLink.js +0 -1
  36. package/dist/types/ResolvedFont.js +0 -1
  37. package/dist/types/index.js +0 -1
  38. package/dist/utils/isEqual.js +0 -1439
  39. package/dist/utils/memoUtils.js +0 -55
@@ -4,6 +4,10 @@ import IInnerLink from "../types/IInnerLink";
4
4
  export interface ButtonConfig {
5
5
  /** Link configuration for the button destination. Required. */
6
6
  innerLink?: IInnerLink;
7
+ /**
8
+ * @deprecated Use innerLink property instead
9
+ */
10
+ href?: string;
7
11
  /** Button text. */
8
12
  children: ReactNode;
9
13
  /** Background color. Required for VML compatibility. */
@@ -19,7 +19,7 @@ export type ColumnConfig = {
19
19
  gap?: string;
20
20
  };
21
21
  export type ColumnProps = {
22
- children: ReactNode;
22
+ children?: ReactNode;
23
23
  config: ColumnConfig;
24
24
  devNode?: ReactNode;
25
25
  };
@@ -37,7 +37,7 @@ export interface ContainerConfig {
37
37
  }
38
38
  export type ContainerProps = {
39
39
  config: ContainerConfig;
40
- children: ReactNode;
40
+ children?: ReactNode;
41
41
  devMode?: boolean;
42
42
  devNode?: ReactNode;
43
43
  };
@@ -31,6 +31,14 @@ export interface ImageConfig {
31
31
  borderRadius?: string;
32
32
  border?: BorderConfig;
33
33
  innerLink?: IInnerLink;
34
+ /**
35
+ * @deprecated Use innerLink property instead
36
+ */
37
+ href?: string;
38
+ /**
39
+ * @deprecated Use innerLink property instead
40
+ */
41
+ target?: string;
34
42
  objectFit?: CSSProperties["objectFit"];
35
43
  objectPosition?: string;
36
44
  mobile?: ImageMobileConfig;
@@ -36,7 +36,7 @@ export interface RowConfig {
36
36
  };
37
37
  }
38
38
  export type RowProps = {
39
- children: ReactNode;
39
+ children?: ReactNode;
40
40
  config: RowConfig;
41
41
  devNode?: ReactNode;
42
42
  devMode?: boolean;
@@ -15,7 +15,7 @@ export type SectionConfig = {
15
15
  };
16
16
  export interface SectionProps {
17
17
  config: SectionConfig;
18
- children: ReactNode;
18
+ children?: ReactNode;
19
19
  devNode?: ReactNode;
20
20
  }
21
21
  declare const _default: React.NamedExoticComponent<SectionProps>;
@@ -17,7 +17,7 @@ export interface TextConfig {
17
17
  /** Font style (e.g., 'italic'). */
18
18
  fontStyle?: string;
19
19
  /** Line height (e.g., '1.5' or '24px'). */
20
- lineHeight?: string;
20
+ lineHeight?: string | number;
21
21
  /** Letter spacing (e.g., '0.5px', '1px'). */
22
22
  letterSpacing?: string;
23
23
  /** Text transform (e.g., 'uppercase', 'lowercase', 'capitalize'). */
@@ -37,6 +37,7 @@ export interface TextConfig {
37
37
  /** Word break behavior (e.g., 'break-all', 'break-word', 'keep-all', 'normal'). */
38
38
  wordBreak?: string;
39
39
  maxWidth?: string;
40
+ listStyle?: string;
40
41
  }
41
42
  export type TextProps = {
42
43
  config: TextConfig;
@@ -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 || "#000000";
10
- const globalFontSize = config.fontSize || "16px";
11
- const globalBackgroundColor = config.backgroundColor || "#ffffff";
12
- const globalLineHeight = config.lineHeight || "1.4";
13
- const globalFontFamily = config.fontFamily || "Arial, Helvetica, sans-serif";
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) || "no-repeat";
17
- const bgSize = ((_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.size) || "cover";
18
- const bgPosition = ((_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.position) || "center";
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,133 +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 ? parseInt(padding.split(" ")[0] || "12", 10) : 12;
1627
- const numericFontSize = fontSize ? parseInt(fontSize, 10) : 0;
1628
- const numericLineHeight = lineHeight
1629
- ? lineHeight.includes("px")
1630
- ? parseInt(lineHeight, 10)
1631
- : numericFontSize * parseFloat(lineHeight)
1632
- : numericFontSize;
1633
- // Trust user's explicit pixel width - no calculation needed
1634
- const vmlWidth = parseInt(width, 10);
1635
- // Calculate VML height - trust user's padding and let text wrap naturally
1636
- // VML v:textbox will handle text wrapping automatically
1637
- const textContent = typeof children === "string" ? children : "";
1638
- // Estimate number of lines based on text length and button width
1639
- const horizontalPadding = (padding === null || padding === void 0 ? void 0 : padding.split(" ")[1])
1640
- ? parseInt(padding.split(" ")[1], 10) * 2
1641
- : numericPadding * 2;
1642
- const availableTextWidth = vmlWidth - horizontalPadding;
1643
- const charWidthMultiplier = fontWeight && parseInt(fontWeight) >= 500 ? 0.7 : 0.6;
1644
- const avgCharWidth = numericFontSize * charWidthMultiplier;
1645
- const charsPerLine = Math.max(Math.floor(availableTextWidth / avgCharWidth), 1);
1646
- const numberOfLines = Math.max(Math.ceil(textContent.length / charsPerLine), 1);
1647
- // Calculate height: vertical padding + (lines * line height) + extra buffer for VML
1648
- const textHeight = numberOfLines * numericLineHeight;
1649
- // Add extra 4px buffer to prevent bottom cropping in VML
1650
- const vmlHeight = Math.max(numericPadding * 2 + textHeight + 4, 40);
1651
- // VML colors must use the full hex format (e.g., #000000)
1652
- const vmlFillColor = backgroundColor
1653
- ? backgroundColor.startsWith("#")
1654
- ? backgroundColor
1655
- : `#${backgroundColor}`
1656
- : undefined;
1657
- // VML stroke color for border
1658
- const vmlStrokeColor = (border === null || border === void 0 ? void 0 : border.color) || vmlFillColor;
1659
- const vmlStrokeWeight = (border === null || border === void 0 ? void 0 : border.width) ? parseInt(border.width, 10) : 0;
1660
- const hasVmlStroke = vmlStrokeWeight > 0;
1661
- // Build VML font styles - consistent with other rendering paths
1662
- const vmlFontWeight = fontWeight;
1663
- const vmlFontStyle = fontStyle === "italic" ? "font-style:italic;" : "";
1664
- const vmlLetterSpacing = letterSpacing
1665
- ? `letter-spacing:${letterSpacing};`
1666
- : "";
1667
- const vmlTextTransform = textTransform
1668
- ? `text-transform:${textTransform};`
1669
- : "";
1670
- const vmlTextDecoration = textDecoration && textDecoration !== "none"
1671
- ? `text-decoration:${textDecoration};`
1672
- : "";
1673
- const vmlWhiteSpace = whiteSpace ? `white-space:${whiteSpace};` : "";
1674
- const vmlDirection = direction ? `direction:${direction};` : "";
1675
- const vmlOpacity = opacity !== undefined ? `opacity:${opacity};` : "";
1676
- // VML code uses MSO conditional comments to render only in Outlook
1677
- // Use table with explicit MSO height for vertical centering
1678
- const horizontalPaddingValue = (padding === null || padding === void 0 ? void 0 : padding.split(" ")[1])
1679
- ? parseInt(padding.split(" ")[1], 10)
1680
- : numericPadding;
1681
- // For VML, we need to use a table inside to properly apply padding and centering
1682
- let vmlAlignAttr = "";
1683
- let vmlAlignStyle = "";
1684
- if (textAlign === "center") {
1685
- vmlAlignAttr = 'align="center"';
1686
- }
1687
- else if (textAlign) {
1688
- vmlAlignStyle = `text-align:${textAlign};`;
1689
- }
1690
- // Border radius is intentionally omitted (arcsize="0%") for Outlook Classic.
1691
- // Outlook Classic does not reliably support rounded corners and the result
1692
- // is inconsistent, so we render sharp corners there instead.
1693
- vmlButton = `
1694
- <!--[if mso]>
1695
- <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}"` : ""}>
1696
- <w:anchorlock/>
1697
- <v:textbox inset="${horizontalPaddingValue}px,${numericPadding}px,${horizontalPaddingValue}px,${numericPadding}px">
1698
- <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
1699
- <tr>
1700
- <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;">
1701
- ${typeof children === "string" ? children : ""}
1702
- </td>
1703
- </tr>
1704
- </table>
1705
- </v:textbox>
1706
- </v:roundrect>
1707
- <![endif]-->
1708
- `;
1709
- }
1710
1618
  // --- Simple Outlook Approach for Percentage Widths ---
1711
1619
  let simpleOutlookButton = "";
1712
- if (useSimpleOutlookApproach) {
1713
- // Build consistent inline styles for text properties
1714
- const textDecorationStyle = textDecoration && textDecoration !== "none"
1715
- ? `text-decoration: ${textDecoration};`
1716
- : "";
1717
- const fontStyleProp = fontStyle ? `font-style: ${fontStyle};` : "";
1718
- const letterSpacingProp = letterSpacing
1719
- ? `letter-spacing: ${letterSpacing};`
1720
- : "";
1721
- const textTransformProp = textTransform
1722
- ? `text-transform: ${textTransform};`
1723
- : "";
1724
- const whiteSpaceProp = whiteSpace ? `white-space: ${whiteSpace};` : "";
1725
- const directionProp = direction ? `direction: ${direction};` : "";
1726
- const opacityProp = opacity !== undefined ? `opacity: ${opacity};` : "";
1727
- const wordBreakProp = wordBreak ? `word-break: ${wordBreak};` : "";
1728
- // Border radius is intentionally omitted from the Outlook Classic table cell.
1729
- // Outlook Classic ignores border-radius on table cells anyway, and including it
1730
- // can cause unexpected rendering artifacts, so we explicitly leave it out.
1731
- 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 = `
1732
1639
  <!--[if mso]>
1733
1640
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse: collapse;">
1734
1641
  <tr>
1735
1642
  <td ${align ? `align="${align}"` : ""} style="padding: 0;">
1736
1643
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="${width || "auto"}" style="border-collapse: collapse;">
1737
1644
  <tr>
1738
- <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}">
1739
1646
  ${href
1740
- ? `<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;">
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;">
1741
1648
  ${typeof children === "string" ? children : ""}
1742
1649
  </a>`
1743
- : `<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;">
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;">
1744
1651
  ${typeof children === "string" ? children : ""}
1745
1652
  </span>`}
1746
1653
  </td>
@@ -1751,7 +1658,6 @@ function Button({ config, devMode }) {
1751
1658
  </table>
1752
1659
  <![endif]-->
1753
1660
  `;
1754
- }
1755
1661
  // Build shared inline style fragments for the non-MSO path.
1756
1662
  // fontFamily uses the sanitized value so embedded quotes never break the
1757
1663
  // style attribute string (which is always wrapped in double quotes).
@@ -1798,7 +1704,7 @@ function Button({ config, devMode }) {
1798
1704
  padding: 0,
1799
1705
  }, onClick: devMode ? (e) => e.preventDefault() : undefined, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { dangerouslySetInnerHTML: {
1800
1706
  __html: `
1801
- ${useSimpleOutlookApproach ? simpleOutlookButton : vmlButton}
1707
+ ${simpleOutlookButton}
1802
1708
  <!--[if !mso]><!-->
1803
1709
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; width: 100%;">
1804
1710
  <tbody>
@@ -1813,7 +1719,7 @@ function Button({ config, devMode }) {
1813
1719
  ${typeof children === "string" ? children : ""}
1814
1720
  </span>`
1815
1721
  : href
1816
- ? `<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};` : ""}">
1817
1723
  <span>
1818
1724
  ${typeof children === "string" ? children : ""}
1819
1725
  </span>
@@ -2361,6 +2267,139 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
2361
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 } })] }));
2362
2268
  }
2363
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
+
2364
2403
  function Heading({ config, devMode, children }) {
2365
2404
  const { text, level = "h1", padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, wordBreak, whiteSpace, } = config;
2366
2405
  // Determine the content to render
@@ -2377,7 +2416,7 @@ function Heading({ config, devMode, children }) {
2377
2416
  const headingStyle = {
2378
2417
  color: color,
2379
2418
  textAlign: textAlign,
2380
- fontFamily: fontFamily || "Arial, Helvetica, sans-serif",
2419
+ fontFamily: fontFamily,
2381
2420
  fontSize: fontSize,
2382
2421
  fontWeight: fontWeight,
2383
2422
  fontStyle: fontStyle,
@@ -2394,6 +2433,9 @@ function Heading({ config, devMode, children }) {
2394
2433
  // Outlook specific fixes (using string indexing)
2395
2434
  ["msoLineHeightRule"]: "exactly",
2396
2435
  };
2436
+ const processedHtml = isString
2437
+ ? injectLinkStyles(content, headingStyle)
2438
+ : "";
2397
2439
  // Dynamically create the Heading element
2398
2440
  const HeadingTag = level;
2399
2441
  return (
@@ -2401,7 +2443,7 @@ function Heading({ config, devMode, children }) {
2401
2443
  jsxRuntime.jsx("table", { "aria-label": "Heading Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2402
2444
  width: "100%",
2403
2445
  borderCollapse: "collapse",
2404
- }, 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: content } })) : (jsxRuntime.jsx(HeadingTag, { style: headingStyle, children: content })) }) }) }) }));
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 })) }) }) }) }));
2405
2447
  }
2406
2448
  var Heading_default = React.memo(Heading, arePropsEqual);
2407
2449
 
@@ -2864,7 +2906,7 @@ function Spacer({ config, devNode }) {
2864
2906
  var Spacer_default = React.memo(Spacer, arePropsEqual);
2865
2907
 
2866
2908
  function Text({ config, devMode, children }) {
2867
- const { text, padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, opacity, whiteSpace, wordBreak = "break-all", maxWidth } = config;
2909
+ const { text, padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, opacity, whiteSpace, wordBreak = "break-all", maxWidth, } = config;
2868
2910
  // 1. TD Style: Where padding and background are reliably applied.
2869
2911
  const tdStyle = {
2870
2912
  padding: padding,
@@ -2876,7 +2918,7 @@ function Text({ config, devMode, children }) {
2876
2918
  const contentStyle = {
2877
2919
  color: color,
2878
2920
  textAlign: textAlign,
2879
- fontFamily: fontFamily || "Arial, Helvetica, sans-serif",
2921
+ fontFamily: fontFamily,
2880
2922
  fontSize: fontSize,
2881
2923
  fontWeight: fontWeight,
2882
2924
  fontStyle: fontStyle,
@@ -2891,15 +2933,18 @@ function Text({ config, devMode, children }) {
2891
2933
  wordBreak: wordBreak,
2892
2934
  margin: "0",
2893
2935
  padding: "0",
2894
- maxWidth
2936
+ maxWidth,
2895
2937
  };
2896
2938
  // Determine content to render
2897
2939
  const content = text !== null && text !== void 0 ? text : children;
2898
2940
  const isString = typeof content === "string";
2941
+ const processedHtml = isString
2942
+ ? injectLinkStyles(content, contentStyle)
2943
+ : "";
2899
2944
  return (jsxRuntime.jsx("table", { "aria-label": "Text Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2900
2945
  width: "100%",
2901
2946
  borderCollapse: "collapse",
2902
- }, 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: content } })) : (jsxRuntime.jsx("div", { style: contentStyle, children: content })) }) }) }) }));
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 })) }) }) }) }));
2903
2948
  }
2904
2949
  var Text_default = React.memo(Text, arePropsEqual);
2905
2950