@pagenflow/email 1.3.6 → 1.4.0

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/index.esm.js CHANGED
@@ -1529,80 +1529,267 @@ const justifyMap$3 = {
1529
1529
  center: "center",
1530
1530
  end: "right",
1531
1531
  };
1532
+ function getBorderStyle$6(border) {
1533
+ if (!border)
1534
+ return {};
1535
+ const style = {};
1536
+ // If a full border is specified, apply it
1537
+ if (border.width && border.style && border.color) {
1538
+ style.border = `${border.width} ${border.style} ${border.color}`;
1539
+ }
1540
+ else {
1541
+ // If only individual borders are specified, explicitly set others to 'none'
1542
+ // to prevent Outlook Classic from showing black borders
1543
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
1544
+ if (hasIndividualBorders) {
1545
+ // Default all borders to none
1546
+ style.borderTop = "none";
1547
+ style.borderRight = "none";
1548
+ style.borderBottom = "none";
1549
+ style.borderLeft = "none";
1550
+ }
1551
+ }
1552
+ // Override with specific borders if provided
1553
+ if (border.top) {
1554
+ style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
1555
+ }
1556
+ if (border.right) {
1557
+ style.borderRight = `${border.right.width} ${border.right.style} ${border.right.color}`;
1558
+ }
1559
+ if (border.bottom) {
1560
+ style.borderBottom = `${border.bottom.width} ${border.bottom.style} ${border.bottom.color}`;
1561
+ }
1562
+ if (border.left) {
1563
+ style.borderLeft = `${border.left.width} ${border.left.style} ${border.left.color}`;
1564
+ }
1565
+ return style;
1566
+ }
1567
+ function getBorderStyleString$2(border) {
1568
+ if (!border)
1569
+ return "";
1570
+ const styles = [];
1571
+ // If a full border is specified, apply it
1572
+ if (border.width && border.style && border.color) {
1573
+ styles.push(`border: ${border.width} ${border.style} ${border.color};`);
1574
+ }
1575
+ else {
1576
+ // If only individual borders are specified
1577
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
1578
+ if (hasIndividualBorders) {
1579
+ // Default all borders to none
1580
+ styles.push("border-top: none;");
1581
+ styles.push("border-right: none;");
1582
+ styles.push("border-bottom: none;");
1583
+ styles.push("border-left: none;");
1584
+ }
1585
+ }
1586
+ // Override with specific borders if provided
1587
+ if (border.top) {
1588
+ styles.push(`border-top: ${border.top.width} ${border.top.style} ${border.top.color};`);
1589
+ }
1590
+ if (border.right) {
1591
+ styles.push(`border-right: ${border.right.width} ${border.right.style} ${border.right.color};`);
1592
+ }
1593
+ if (border.bottom) {
1594
+ styles.push(`border-bottom: ${border.bottom.width} ${border.bottom.style} ${border.bottom.color};`);
1595
+ }
1596
+ if (border.left) {
1597
+ styles.push(`border-left: ${border.left.width} ${border.left.style} ${border.left.color};`);
1598
+ }
1599
+ return styles.join(" ");
1600
+ }
1532
1601
  function Button({ config, devMode }) {
1533
1602
  const { href, children, backgroundColor = "#007bff", // Default blue
1534
- color = "#ffffff", padding = "12px 24px", borderRadius = "3px", width, justifyContent = "center", textAlign = "center", fontSize = "16px", fontWeight = "500", fontStyle, lineHeight = "1.2", letterSpacing, textTransform, textDecoration = "none", fontFamily = "Arial, sans-serif", whiteSpace = "normal", } = config;
1535
- // 1. Link (A) Tag Styles (Fallback for Webmail/Mobile)
1536
- const linkStyle = {
1537
- display: "block",
1538
- wordBreak: "break-word"};
1603
+ color = "#ffffff", padding = "12px 24px", borderRadius = "3px", border, width, maxWidth, justifyContent = "center", textAlign = "center", fontSize = "16px", fontWeight = "500", fontStyle, fontFamily = "Arial, sans-serif", lineHeight = "1.2", letterSpacing, textTransform, textDecoration = "none", direction, verticalAlign, opacity, whiteSpace = "normal", wordBreak = "break-word", } = config;
1604
+ // Sanitize fontFamily early so safeFontFamily is available for all paths below.
1605
+ const safeFontFamily = fontFamily
1606
+ ? fontFamily.replace(/['"]/g, "")
1607
+ : fontFamily;
1539
1608
  // 2. Outer TD Style for Background and Border Radius (no border)
1540
- const backgroundTdStyle = Object.assign({ backgroundColor: backgroundColor, borderRadius: borderRadius, width: width || "auto" }, (borderRadius && { overflow: "hidden" }));
1541
- // --- VML Calculation and Code for Outlook Compatibility ---
1542
- // VML needs fixed pixel height. We estimate it based on padding.
1543
- const numericPadding = parseInt(padding.split(" ")[0] || "12", 10);
1544
- const vmlHeight = numericPadding * 2 + 20; // Estimate height based on padding + font size
1545
- const vmlWidth = width ? parseInt(width, 10) : 200; // Default VML width (fixed)
1546
- // VML colors must use the full hex format (e.g., #000000)
1547
- const vmlFillColor = backgroundColor.startsWith("#")
1548
- ? backgroundColor
1549
- : `#${backgroundColor}`;
1609
+ const backgroundTdStyle = Object.assign(Object.assign({ backgroundColor: backgroundColor, borderRadius: borderRadius, width: width || "auto" }, (maxWidth && { maxWidth: maxWidth })), (borderRadius && { overflow: "hidden" }));
1610
+ // 3. Border styles
1611
+ getBorderStyle$6(border);
1612
+ const borderStyleString = getBorderStyleString$2(border);
1613
+ // --- Determine Button Approach Based on Width ---
1614
+ // Check if width is percentage-based or not defined
1615
+ const isPercentageWidth = !width || width.includes("%");
1616
+ const useSimpleOutlookApproach = isPercentageWidth;
1550
1617
  const align = justifyMap$3[justifyContent];
1551
- // Build VML font styles
1552
- const vmlFontWeight = fontWeight || "bold";
1553
- const vmlFontStyle = fontStyle === "italic" ? "font-style:italic;" : "";
1554
- const vmlLetterSpacing = letterSpacing
1555
- ? `letter-spacing:${letterSpacing};`
1556
- : "";
1557
- const vmlTextTransform = textTransform
1558
- ? `text-transform:${textTransform};`
1559
- : "";
1560
- const vmlTextDecoration = textDecoration && textDecoration !== "none"
1561
- ? `text-decoration:${textDecoration};`
1562
- : "";
1563
- const vmlWhiteSpace = whiteSpace && whiteSpace !== "normal" ? `white-space:${whiteSpace};` : "";
1564
- // VML code uses MSO conditional comments to render only in Outlook
1565
- const vmlButton = `
1618
+ // --- VML Calculation and Code for Outlook Compatibility (Fixed Width Only) ---
1619
+ let vmlButton = "";
1620
+ if (!useSimpleOutlookApproach) {
1621
+ // VML needs fixed pixel height. We estimate it based on padding and potential wrapping.
1622
+ const numericPadding = parseInt(padding.split(" ")[0] || "12", 10);
1623
+ const numericFontSize = parseInt(fontSize, 10);
1624
+ const numericLineHeight = lineHeight.includes("px")
1625
+ ? parseInt(lineHeight, 10)
1626
+ : numericFontSize * parseFloat(lineHeight);
1627
+ // Trust user's explicit pixel width - no calculation needed
1628
+ const vmlWidth = parseInt(width, 10);
1629
+ // Calculate VML height - trust user's padding and let text wrap naturally
1630
+ // VML v:textbox will handle text wrapping automatically
1631
+ const textContent = typeof children === "string" ? children : "";
1632
+ // Estimate number of lines based on text length and button width
1633
+ const horizontalPadding = padding.split(" ")[1]
1634
+ ? parseInt(padding.split(" ")[1], 10) * 2
1635
+ : numericPadding * 2;
1636
+ const availableTextWidth = vmlWidth - horizontalPadding;
1637
+ const charWidthMultiplier = fontWeight && parseInt(fontWeight) >= 500 ? 0.7 : 0.6;
1638
+ const avgCharWidth = numericFontSize * charWidthMultiplier;
1639
+ const charsPerLine = Math.max(Math.floor(availableTextWidth / avgCharWidth), 1);
1640
+ const numberOfLines = Math.max(Math.ceil(textContent.length / charsPerLine), 1);
1641
+ // Calculate height: vertical padding + (lines * line height) + extra buffer for VML
1642
+ const textHeight = numberOfLines * numericLineHeight;
1643
+ // Add extra 4px buffer to prevent bottom cropping in VML
1644
+ const vmlHeight = Math.max(numericPadding * 2 + textHeight + 4, 40);
1645
+ // VML colors must use the full hex format (e.g., #000000)
1646
+ const vmlFillColor = backgroundColor.startsWith("#")
1647
+ ? backgroundColor
1648
+ : `#${backgroundColor}`;
1649
+ // VML stroke color for border
1650
+ const vmlStrokeColor = (border === null || border === void 0 ? void 0 : border.color) || vmlFillColor;
1651
+ const vmlStrokeWeight = (border === null || border === void 0 ? void 0 : border.width) ? parseInt(border.width, 10) : 0;
1652
+ const hasVmlStroke = vmlStrokeWeight > 0;
1653
+ // Build VML font styles - consistent with other rendering paths
1654
+ const vmlFontWeight = fontWeight || "500";
1655
+ const vmlFontStyle = fontStyle === "italic" ? "font-style:italic;" : "";
1656
+ const vmlLetterSpacing = letterSpacing
1657
+ ? `letter-spacing:${letterSpacing};`
1658
+ : "";
1659
+ const vmlTextTransform = textTransform
1660
+ ? `text-transform:${textTransform};`
1661
+ : "";
1662
+ const vmlTextDecoration = textDecoration && textDecoration !== "none"
1663
+ ? `text-decoration:${textDecoration};`
1664
+ : "";
1665
+ const vmlWhiteSpace = whiteSpace !== "normal" ? `white-space:${whiteSpace};` : "";
1666
+ const vmlDirection = direction ? `direction:${direction};` : "";
1667
+ const vmlOpacity = opacity !== undefined ? `opacity:${opacity};` : "";
1668
+ // VML code uses MSO conditional comments to render only in Outlook
1669
+ // Use table with explicit MSO height for vertical centering
1670
+ const horizontalPaddingValue = padding.split(" ")[1]
1671
+ ? parseInt(padding.split(" ")[1], 10)
1672
+ : numericPadding;
1673
+ // For VML, we need to use a table inside to properly apply padding and centering
1674
+ let vmlAlignAttr = "";
1675
+ let vmlAlignStyle = "";
1676
+ if (textAlign === "center") {
1677
+ vmlAlignAttr = 'align="center"';
1678
+ }
1679
+ else {
1680
+ vmlAlignStyle = `text-align:${textAlign};`;
1681
+ }
1682
+ vmlButton = `
1566
1683
  <!--[if mso]>
1567
- <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${href}" style="height:${vmlHeight}px;v-text-anchor:middle;width:${vmlWidth}px;" arcsize="${(parseInt(borderRadius) / vmlHeight) * 100}%" strokecolor="${vmlFillColor}" fillcolor="${vmlFillColor}">
1684
+ <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${href}" style="height:${vmlHeight}px;width:${vmlWidth}px;" arcsize="${Math.min((parseInt(borderRadius) / vmlHeight) * 100, 50)}%" strokecolor="${vmlStrokeColor}" ${hasVmlStroke ? `strokeweight="${vmlStrokeWeight}px"` : 'stroke="f"'} fillcolor="${vmlFillColor}">
1568
1685
  <w:anchorlock/>
1569
- <center style="color:${color};font-family:${fontFamily};font-size:${fontSize};font-weight:${vmlFontWeight};${vmlFontStyle}${vmlLetterSpacing}${vmlTextTransform}${vmlTextDecoration}${vmlWhiteSpace}">
1570
- ${typeof children === "string" ? children : ""}
1571
- </center>
1686
+ <v:textbox inset="${horizontalPaddingValue}px,${numericPadding}px,${horizontalPaddingValue}px,${numericPadding}px">
1687
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
1688
+ <tr>
1689
+ <td ${vmlAlignAttr} valign="middle" style="${vmlAlignStyle}color:${color};font-family:${safeFontFamily};font-size:${fontSize};font-weight:${vmlFontWeight};${vmlFontStyle}${vmlLetterSpacing}${vmlTextTransform}${vmlTextDecoration}${vmlWhiteSpace}${vmlDirection}${vmlOpacity}line-height:${lineHeight};mso-line-height-rule:exactly;">
1690
+ ${typeof children === "string" ? children : ""}
1691
+ </td>
1692
+ </tr>
1693
+ </table>
1694
+ </v:textbox>
1572
1695
  </v:roundrect>
1573
1696
  <![endif]-->
1574
1697
  `;
1698
+ }
1699
+ // --- Simple Outlook Approach for Percentage Widths ---
1700
+ let simpleOutlookButton = "";
1701
+ if (useSimpleOutlookApproach) {
1702
+ // Build consistent inline styles for text properties
1703
+ const textDecorationStyle = textDecoration && textDecoration !== "none"
1704
+ ? `text-decoration: ${textDecoration};`
1705
+ : "";
1706
+ const fontStyleProp = fontStyle ? `font-style: ${fontStyle};` : "";
1707
+ const letterSpacingProp = letterSpacing
1708
+ ? `letter-spacing: ${letterSpacing};`
1709
+ : "";
1710
+ const textTransformProp = textTransform
1711
+ ? `text-transform: ${textTransform};`
1712
+ : "";
1713
+ const whiteSpaceProp = whiteSpace !== "normal" ? `white-space: ${whiteSpace};` : "";
1714
+ const directionProp = direction ? `direction: ${direction};` : "";
1715
+ const opacityProp = opacity !== undefined ? `opacity: ${opacity};` : "";
1716
+ const wordBreakProp = wordBreak !== "break-word" ? `word-break: ${wordBreak};` : "";
1717
+ simpleOutlookButton = `
1718
+ <!--[if mso]>
1719
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse: collapse;">
1720
+ <tr>
1721
+ <td align="${align}" style="padding: 0;">
1722
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="${width || "auto"}" style="border-collapse: collapse;">
1723
+ <tr>
1724
+ <td bgcolor="${backgroundColor}" align="${textAlign}" style="padding: ${padding}; text-align: ${textAlign}; border-radius: ${borderRadius}; ${borderStyleString}">
1725
+ <a href="${href}" target="_blank" rel="noopener noreferrer" style="color: ${color}; ${textDecorationStyle} display: block; font-family: ${safeFontFamily}; font-size: ${fontSize}; font-weight: ${fontWeight}; ${fontStyleProp} line-height: ${lineHeight}; ${letterSpacingProp} ${textTransformProp} text-align: ${textAlign}; ${whiteSpaceProp} ${directionProp} ${opacityProp} ${wordBreakProp} mso-line-height-rule: exactly;">
1726
+ ${typeof children === "string" ? children : ""}
1727
+ </a>
1728
+ </td>
1729
+ </tr>
1730
+ </table>
1731
+ </td>
1732
+ </tr>
1733
+ </table>
1734
+ <![endif]-->
1735
+ `;
1736
+ }
1737
+ // Build shared inline style fragments for the non-MSO path.
1738
+ // fontFamily uses the sanitized value so embedded quotes never break the
1739
+ // style attribute string (which is always wrapped in double quotes).
1740
+ const sharedTextStyles = [
1741
+ `color: ${color};`,
1742
+ safeFontFamily ? `font-family: ${safeFontFamily};` : "",
1743
+ fontSize ? `font-size: ${fontSize};` : "",
1744
+ fontWeight ? `font-weight: ${fontWeight};` : "",
1745
+ fontStyle ? `font-style: ${fontStyle};` : "",
1746
+ lineHeight ? `line-height: ${lineHeight};` : "",
1747
+ letterSpacing ? `letter-spacing: ${letterSpacing};` : "",
1748
+ textTransform ? `text-transform: ${textTransform};` : "",
1749
+ textDecoration && textDecoration !== "none"
1750
+ ? `text-decoration: ${textDecoration};`
1751
+ : "",
1752
+ direction ? `direction: ${direction};` : "",
1753
+ opacity !== undefined ? `opacity: ${opacity};` : "",
1754
+ whiteSpace !== "normal" ? `white-space: ${whiteSpace};` : "",
1755
+ ]
1756
+ .filter(Boolean)
1757
+ .join(" ");
1575
1758
  return (
1576
- // Outer table for alignment (center the button horizontally)
1577
- jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, align: align, style: {
1578
- // --- Start dev
1579
- position: "relative",
1580
- // --- End dev
1581
- width: width || "auto",
1759
+ // Wrapper table for alignment - maintains proper positioning for hover indicators
1760
+ jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
1761
+ width: "100%",
1582
1762
  borderCollapse: "collapse",
1583
- // base
1584
1763
  boxSizing: "border-box",
1585
1764
  border: 0,
1586
1765
  margin: 0,
1587
1766
  padding: 0,
1588
- }, onClick: devMode ? (e) => e.preventDefault() : undefined, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { dangerouslySetInnerHTML: {
1589
- __html: `
1590
- ${devMode ? "" : vmlButton}
1767
+ }, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { align: align, style: {
1768
+ padding: 0,
1769
+ }, children: jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: Object.assign(Object.assign({
1770
+ // --- Start dev
1771
+ position: "relative",
1772
+ // --- End dev
1773
+ width: width || "auto" }, (maxWidth && { maxWidth: maxWidth })), { borderCollapse: "collapse",
1774
+ // base
1775
+ boxSizing: "border-box", border: 0, margin: 0, padding: 0 }), onClick: devMode ? (e) => e.preventDefault() : undefined, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { dangerouslySetInnerHTML: {
1776
+ __html: `
1777
+ ${devMode ? "" : useSimpleOutlookApproach ? simpleOutlookButton : vmlButton}
1591
1778
  <!--[if !mso]><!-->
1592
1779
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; width: 100%;">
1593
1780
  <tbody>
1594
1781
  <tr>
1595
- <td style="background-color: ${backgroundTdStyle.backgroundColor}; border-radius: ${backgroundTdStyle.borderRadius}; width: ${backgroundTdStyle.width}; ${borderRadius ? "overflow: hidden;" : ""}">
1596
- <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: separate; border-spacing: 0; border-radius: ${borderRadius}; width: 100%;">
1782
+ <td style="background-color: ${backgroundTdStyle.backgroundColor}; border-radius: ${backgroundTdStyle.borderRadius}; width: ${backgroundTdStyle.width}; ${maxWidth ? `max-width: ${maxWidth};` : ""} ${borderRadius ? "overflow: hidden;" : ""}">
1783
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: separate; border-spacing: 0; border-radius: ${borderRadius}; width: 100%; ${borderStyleString}">
1597
1784
  <tbody>
1598
1785
  <tr>
1599
- <td style="padding: ${padding};">
1786
+ <td style="padding: 0;">
1600
1787
  ${devMode
1601
- ? `<span style="color: ${color}; font-family: ${fontFamily}; font-size: ${fontSize}; font-weight: ${fontWeight}; font-style: ${fontStyle || "normal"}; line-height: ${lineHeight}; letter-spacing: ${letterSpacing || "normal"}; text-transform: ${textTransform || "none"}; text-decoration: ${textDecoration}; white-space: ${whiteSpace}; display: ${linkStyle.display}; text-align: ${textAlign}; word-break: ${linkStyle.wordBreak};">
1788
+ ? `<span style="${sharedTextStyles} display: block; text-align: ${textAlign}; word-break: ${wordBreak}; padding: ${padding};">
1602
1789
  ${typeof children === "string" ? children : ""}
1603
1790
  </span>`
1604
- : `<a href="${href}" target="_blank" rel="noopener noreferrer" style="color: ${color}; text-decoration: ${textDecoration}; display: ${linkStyle.display}; word-break: ${linkStyle.wordBreak}; font-family: ${fontFamily}; font-size: ${fontSize}; font-weight: ${fontWeight}; font-style: ${fontStyle || "normal"}; line-height: ${lineHeight}; letter-spacing: ${letterSpacing || "normal"}; text-transform: ${textTransform || "none"}; text-align: ${textAlign}; white-space: ${whiteSpace};">
1605
- <span style="color: ${color}; font-family: ${fontFamily}; font-size: ${fontSize}; font-weight: ${fontWeight}; font-style: ${fontStyle || "normal"}; line-height: ${lineHeight}; letter-spacing: ${letterSpacing || "normal"}; text-transform: ${textTransform || "none"}; text-decoration: ${textDecoration}; white-space: ${whiteSpace};">
1791
+ : `<a href="${href}" target="_blank" rel="noopener noreferrer" style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; word-break: ${wordBreak}; text-align: ${textAlign}; padding: ${padding};">
1792
+ <span style="${sharedTextStyles}">
1606
1793
  ${typeof children === "string" ? children : ""}
1607
1794
  </span>
1608
1795
  </a>`}
@@ -1616,7 +1803,7 @@ function Button({ config, devMode }) {
1616
1803
  </table>
1617
1804
  <!--<![endif]-->
1618
1805
  `,
1619
- } }) }) }) }));
1806
+ } }) }) }) }) }) }) }) }));
1620
1807
  }
1621
1808
  var Button_default = memo(Button, arePropsEqual);
1622
1809
 
@@ -1633,15 +1820,27 @@ const alignMap$2 = {
1633
1820
  end: "right",
1634
1821
  };
1635
1822
  // Helper to convert border config to CSS border shorthand
1636
- function getBorderStyle$3(border) {
1823
+ function getBorderStyle$5(border) {
1637
1824
  if (!border)
1638
1825
  return {};
1639
1826
  const style = {};
1640
- // Check for unified border
1827
+ // If a full border is specified, apply it
1641
1828
  if (border.width && border.style && border.color) {
1642
1829
  style.border = `${border.width} ${border.style} ${border.color}`;
1643
1830
  }
1644
- // Individual sides override unified border
1831
+ else {
1832
+ // If only individual borders are specified, explicitly set others to 'none'
1833
+ // to prevent Outlook Classic from showing black borders
1834
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
1835
+ if (hasIndividualBorders) {
1836
+ // Default all borders to none
1837
+ style.borderTop = "none";
1838
+ style.borderRight = "none";
1839
+ style.borderBottom = "none";
1840
+ style.borderLeft = "none";
1841
+ }
1842
+ }
1843
+ // Override with specific borders if provided
1645
1844
  if (border.top) {
1646
1845
  style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
1647
1846
  }
@@ -1661,24 +1860,32 @@ function Column({ children, config, devNode }) {
1661
1860
  // Process children array for gap support
1662
1861
  const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
1663
1862
  const numChildren = childrenArray.length;
1664
- // 1. Outer table style: Takes up the full width/height of its parent TD
1863
+ // 1. Outer table style: Takes up the full width/height of its parent TD.
1864
+ // height here drives the *total* outer height of the column.
1665
1865
  const outerTableStyle = {
1666
1866
  width: "100%",
1667
1867
  height: config.height,
1668
1868
  borderCollapse: "collapse",
1669
1869
  };
1670
- // 2. Outer TD style: Background and Border Radius (no border here)
1870
+ // 2. Outer TD style: Background and Border Radius (no border here).
1871
+ // height is set so the TD occupies the full declared height.
1671
1872
  const outerTdStyle = Object.assign({ width: config.width, height: config.height, backgroundColor: config.backgroundColor, borderRadius: config.borderRadius,
1672
1873
  // Background Image styles
1673
1874
  backgroundImage: config.backgroundImage
1674
1875
  ? `url(${config.backgroundImage.src})`
1675
1876
  : undefined, backgroundRepeat: (_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.repeat, backgroundSize: (_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.size, backgroundPosition: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.position }, (config.borderRadius && { overflow: "hidden" }));
1676
- // 2b. Inner table style: Border and Border Radius
1677
- const innerTableStyle = Object.assign({ width: "100%", height: config.height, borderCollapse: "separate", borderSpacing: 0, borderRadius: config.borderRadius }, getBorderStyle$3(config.border));
1678
- // 3. Inner TD style: Padding and Vertical Alignment
1877
+ // 2b. Inner table style: Border and Border Radius.
1878
+ // height: 100% so it stretches to fill the outer TD's declared height.
1879
+ const innerTableStyle = Object.assign({ width: "100%", height: "100%", borderCollapse: "separate", borderSpacing: 0, borderRadius: config.borderRadius }, getBorderStyle$5(config.border));
1880
+ // 3. Inner TD style: Padding and Vertical Alignment only.
1881
+ // *** No height here. ***
1882
+ // The outer TD/table owns the height; padding is purely inner spacing,
1883
+ // so the total rendered height = declared height (padding is inside).
1679
1884
  const innerTdStyle = {
1680
1885
  padding: config.padding,
1681
- height: config.height,
1886
+ // height intentionally omitted — setting it here would make browsers
1887
+ // treat it as content-box height and add padding on top, causing the
1888
+ // total to exceed the declared height in preview mode.
1682
1889
  verticalAlign: config.alignItems ? alignMap$2[config.alignItems] : "top",
1683
1890
  };
1684
1891
  // 4. Gap spacer style (used between children)
@@ -1689,7 +1896,7 @@ function Column({ children, config, devNode }) {
1689
1896
  width: "100%",
1690
1897
  };
1691
1898
  // Main content rendering
1692
- const renderContent = () => (jsx("table", { "aria-label": "Column Padding", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: innerTableStyle, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", Object.assign({ style: innerTdStyle, valign: config.justifyContent ? vAlignMap[config.justifyContent] : "top", align: config.alignItems ? alignMap$2[config.alignItems] : "left" }, (config.height && { height: config.height }), { children: config.gap && numChildren > 1 ? (jsx("table", { "aria-label": "Column Gap Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
1899
+ const renderContent = () => (jsx("table", { "aria-label": "Column Padding", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: innerTableStyle, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: innerTdStyle, valign: config.justifyContent ? vAlignMap[config.justifyContent] : "top", align: config.alignItems ? alignMap$2[config.alignItems] : "left", children: config.gap && numChildren > 1 ? (jsx("table", { "aria-label": "Column Gap Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
1693
1900
  width: "100%",
1694
1901
  borderCollapse: "collapse",
1695
1902
  }, children: jsx("tbody", { children: childrenArray.map((child, index) => (jsxs(Fragment, { children: [jsx("tr", { children: jsx("td", { style: {
@@ -1700,7 +1907,7 @@ function Column({ children, config, devNode }) {
1700
1907
  ? vAlignMap[config.justifyContent]
1701
1908
  : "top", align: config.alignItems
1702
1909
  ? alignMap$2[config.alignItems]
1703
- : "left", children: child }) }), index < numChildren - 1 && (jsx("tr", { children: jsx("td", { style: gapSpacerStyle, children: "\u00A0" }) }))] }, `col-child-${index}`))) }) })) : (children) })) }) }) }));
1910
+ : "left", children: child }) }), index < numChildren - 1 && (jsx("tr", { children: jsx("td", { style: gapSpacerStyle, children: "\u00A0" }) }))] }, `col-child-${index}`))) }) })) : (children) }) }) }) }));
1704
1911
  return (jsxs("table", Object.assign({ "aria-label": "Column Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: Object.assign({ position: "relative" }, outerTableStyle) }, (config.height && { height: config.height }), { children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", Object.assign({ style: outerTdStyle }, (config.width && { width: config.width }), (config.height && { height: config.height }), { children: renderContent() })) }) }), devNode && (jsx("tfoot", { children: jsx("tr", { children: jsx("td", { children: devNode }) }) }))] })));
1705
1912
  }
1706
1913
  var Column_default = memo(Column, arePropsEqual);
@@ -1715,13 +1922,27 @@ const justifyMap$2 = {
1715
1922
  center: "center",
1716
1923
  end: "right",
1717
1924
  };
1718
- function getBorderStyle$2(border) {
1925
+ function getBorderStyle$4(border) {
1719
1926
  if (!border)
1720
1927
  return {};
1721
1928
  const style = {};
1929
+ // If a full border is specified, apply it
1722
1930
  if (border.width && border.style && border.color) {
1723
1931
  style.border = `${border.width} ${border.style} ${border.color}`;
1724
1932
  }
1933
+ else {
1934
+ // If only individual borders are specified, explicitly set others to 'none'
1935
+ // to prevent Outlook Classic from showing black borders
1936
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
1937
+ if (hasIndividualBorders) {
1938
+ // Default all borders to none
1939
+ style.borderTop = "none";
1940
+ style.borderRight = "none";
1941
+ style.borderBottom = "none";
1942
+ style.borderLeft = "none";
1943
+ }
1944
+ }
1945
+ // Override with specific borders if provided
1725
1946
  if (border.top) {
1726
1947
  style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
1727
1948
  }
@@ -1796,7 +2017,7 @@ function Container({ children, config, devMode, devNode }) {
1796
2017
  ? `url(${config.backgroundImage.src})`
1797
2018
  : undefined, backgroundRepeat: (_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.repeat, backgroundSize: (_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.size, backgroundPosition: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.position }, (config.borderRadius && { overflow: "hidden" }));
1798
2019
  // 2. Border Table Style - Border and border radius
1799
- const borderTableStyle = Object.assign({ width: "100%", borderCollapse: "separate", borderSpacing: 0, borderRadius: config.borderRadius }, getBorderStyle$2(config.border));
2020
+ const borderTableStyle = Object.assign({ width: "100%", borderCollapse: "separate", borderSpacing: 0, borderRadius: config.borderRadius }, getBorderStyle$4(config.border));
1800
2021
  // 3. Padding TD Style
1801
2022
  const innerTdStyle = {
1802
2023
  padding: config.padding,
@@ -1832,7 +2053,7 @@ function Container({ children, config, devMode, devNode }) {
1832
2053
  fontSize: "0",
1833
2054
  lineHeight: "0",
1834
2055
  height: config.gap,
1835
- }, children: "\u00A0" }))] }, `child-${index}`), jsx("td", { className: "desktop-gap-column", width: config.gap, style: gapTdStyle, children: "\u00A0" }, `gap-${index}`)] }, `ctn:${index}`));
2056
+ }, children: "\u00A0" }))] }, `child-${index}`), jsx("td", { className: isStacking ? "desktop-gap-column" : undefined, width: config.gap, style: gapTdStyle, children: "\u00A0" }, `gap-${index}`)] }, `ctn:${index}`));
1836
2057
  }
1837
2058
  return (jsx("td", { className: isStacking ? "stack-td" : undefined, width: getChildWidths[index], style: childTdStyle, children: child }, `child-${index}`));
1838
2059
  });
@@ -1850,7 +2071,7 @@ function Container({ children, config, devMode, devNode }) {
1850
2071
  var Container_default = memo(Container, arePropsEqual);
1851
2072
 
1852
2073
  function Divider({ config, devNode }) {
1853
- const { height = "1px", color = "#cccccc", width = "100%", margin = "20px 0", align = "center", } = config;
2074
+ const { height = "1px", color = "#cccccc", width = "100%", margin = "20px 0", align = "center", hideOnMobile, } = config;
1854
2075
  // 1. Outer TD Style: Applies the vertical spacing (margin)
1855
2076
  const outerTdStyle = {
1856
2077
  padding: margin,
@@ -1879,7 +2100,7 @@ function Divider({ config, devNode }) {
1879
2100
  // --- End dev
1880
2101
  width: "100%",
1881
2102
  borderCollapse: "collapse",
1882
- }, children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: outerTdStyle, align: align, children: jsx("table", Object.assign({ "aria-label": "Divider Line", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, align: align, style: dividerTableStyle }, { height: dividerHeightAttribute }, { children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: {
2103
+ }, className: hideOnMobile ? "hide-on-mobile" : undefined, children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: outerTdStyle, align: align, children: jsx("table", Object.assign({ "aria-label": "Divider Line", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, align: align, style: dividerTableStyle }, { height: dividerHeightAttribute }, { children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: {
1883
2104
  height: height,
1884
2105
  fontSize: "0",
1885
2106
  lineHeight: "0",
@@ -1888,24 +2109,58 @@ function Divider({ config, devNode }) {
1888
2109
  }
1889
2110
  var Divider_default = memo(Divider, arePropsEqual);
1890
2111
 
1891
- function Head({ children, backgroundColor = "#ffffff", title = "Email Preview", }) {
1892
- // Outlook (MSO) Styles and Reset
2112
+ // ── Helpers ───────────────────────────────────────────────────────────────────
2113
+ function normaliseFallbacks(fallbackFontFamily) {
2114
+ if (!fallbackFontFamily)
2115
+ return [];
2116
+ return Array.isArray(fallbackFontFamily)
2117
+ ? fallbackFontFamily
2118
+ : [fallbackFontFamily];
2119
+ }
2120
+ /**
2121
+ * Build the CSS font-stack string from the primary family + fallbacks.
2122
+ * Wraps names that contain spaces in single quotes.
2123
+ */
2124
+ function buildFontStack(primary, fallbacks) {
2125
+ const quote = (name) => (name.includes(" ") ? `'${name}'` : name);
2126
+ return [primary, ...fallbacks].map(quote).join(", ");
2127
+ }
2128
+ // ── Component ─────────────────────────────────────────────────────────────────
2129
+ function Font({ fontFamily, fallbackFontFamily, webFont, fontWeight = 400, fontStyle = "normal", }) {
2130
+ var _a;
2131
+ const fallbacks = normaliseFallbacks(fallbackFontFamily);
2132
+ const fontFaceCss = webFont
2133
+ ? `
2134
+ @font-face {
2135
+ font-family: '${fontFamily}';
2136
+ font-style: ${fontStyle};
2137
+ font-weight: ${fontWeight};
2138
+ font-display: swap;
2139
+ src: url('${webFont.url}') format('${webFont.format}');
2140
+ mso-font-alt: '${(_a = fallbacks[0]) !== null && _a !== void 0 ? _a : "sans-serif"}';
2141
+ }`.trim()
2142
+ : null;
2143
+ const msoComment = fallbacks.length > 0
2144
+ ? `<!--[if mso]>\n<style type="text/css">\n .${cssClassName(fontFamily)} {\n font-family: ${buildFontStack(fallbacks[0], fallbacks.slice(1))}, sans-serif !important;\n }\n</style>\n<![endif]-->`
2145
+ : null;
2146
+ return (jsxs(Fragment$1, { children: [fontFaceCss && (jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: fontFaceCss } })), msoComment && (jsx("style", { type: "text/css", dangerouslySetInnerHTML: {
2147
+ __html: `</style>${msoComment}<style type="text/css">`,
2148
+ } }))] }));
2149
+ }
2150
+ // ── Utility: generate a stable CSS class name from a font family name ─────────
2151
+ // Used in the MSO conditional comment to scope the fallback rule.
2152
+ function cssClassName(fontFamily) {
2153
+ return `font-${fontFamily.toLowerCase().replace(/\s+/g, "-")}`;
2154
+ }
2155
+
2156
+ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview", rowGaps = [], fonts = [], }) {
1893
2157
  const msoResetStyles = `
1894
- /* Forces Outlook to render 100% width and prevents line-height issues */
1895
2158
  .ExternalClass { width: 100%; line-height: 100%; }
1896
2159
  .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { line-height: 100%; }
1897
-
1898
- /* Reset tables for MSO and border issues */
1899
2160
  table { mso-table-lspace: 0pt; mso-table-rspace: 0pt; border-collapse: collapse; border-spacing: 0; }
1900
2161
  td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
1901
-
1902
- /* Reset images */
1903
2162
  img { border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; }
1904
-
1905
- /* Fix for Gmail image wrapping and blue links */
1906
2163
  #MessageViewBody img { min-width: 100%; }
1907
-
1908
- /* --- APPLE BLUE LINK FIX --- */
1909
2164
  a[x-apple-data-detectors] {
1910
2165
  color: inherit !important;
1911
2166
  text-decoration: none !important;
@@ -1914,14 +2169,8 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
1914
2169
  font-weight: inherit !important;
1915
2170
  line-height: inherit !important;
1916
2171
  }
1917
-
1918
- /* 🔒 NEW: Set global background color via CSS for clients that respect it */
1919
2172
  body { background-color: ${backgroundColor} !important; }
1920
-
1921
- /* Disable browser default margin */
1922
- p {
1923
- margin: 0;
1924
- }
2173
+ p { margin: 0; }
1925
2174
  `;
1926
2175
  const globalStyles = `
1927
2176
  @media screen and (max-width: 768px) {
@@ -1930,7 +2179,22 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
1930
2179
  max-width: 100% !important;
1931
2180
  }
1932
2181
  }
1933
-
2182
+ @media screen and (max-width: 768px) {
2183
+ .hide-on-mobile {
2184
+ display: none !important;
2185
+ max-height: 0 !important;
2186
+ overflow: hidden !important;
2187
+ mso-hide: all;
2188
+ }
2189
+ }
2190
+ @media screen and (min-width: 769px) {
2191
+ .hide-on-desktop {
2192
+ display: none !important;
2193
+ max-height: 0 !important;
2194
+ overflow: hidden !important;
2195
+ mso-hide: all;
2196
+ }
2197
+ }
1934
2198
  @media screen and (max-width: 768px) {
1935
2199
  .stack-td {
1936
2200
  width: 100% !important;
@@ -1940,12 +2204,7 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
1940
2204
  padding-left: 0 !important;
1941
2205
  padding-right: 0 !important;
1942
2206
  }
1943
-
1944
- .desktop-gap-column {
1945
- width: 0 !important;
1946
- display: none !important;
1947
- }
1948
-
2207
+ .desktop-gap-column { width: 0 !important; display: none !important; }
1949
2208
  .mobile-gap-spacer {
1950
2209
  display: block !important;
1951
2210
  width: 100% !important;
@@ -1954,143 +2213,38 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
1954
2213
  mso-line-height-rule: exactly;
1955
2214
  }
1956
2215
  }
1957
-
1958
2216
  @media only screen and (max-width: 768px) {
1959
- /* 1. Handling Mobile Alignment (Justify) - Works for both wrapped and non-wrapped */
1960
- /* We target the inner table alignment */
1961
- .responsive-row[data-mobile-justify="center"] .content-table {
1962
- margin: 0 auto !important;
1963
- float: none !important;
1964
- }
1965
- .responsive-row[data-mobile-justify="start"] .content-table {
1966
- margin: 0 !important;
1967
- float: left !important;
1968
- }
1969
- .responsive-row[data-mobile-justify="end"] .content-table {
1970
- margin: 0 0 0 auto !important;
1971
- float: right !important;
1972
- }
1973
-
1974
- /* Mobile justify for wrapped children - we need to target the outer wrapper td */
1975
- .responsive-row[data-mobile-wrap="true"][data-mobile-justify="center"] td[align] {
1976
- text-align: center !important;
1977
- }
1978
- .responsive-row[data-mobile-wrap="true"][data-mobile-justify="start"] td[align] {
1979
- text-align: left !important;
1980
- }
1981
- .responsive-row[data-mobile-wrap="true"][data-mobile-justify="end"] td[align] {
1982
- text-align: right !important;
1983
- }
1984
-
1985
- /* Also apply to child content tables for better support */
1986
- .responsive-row[data-mobile-wrap="true"][data-mobile-justify="center"] .child-cell table {
1987
- margin-left: auto !important;
1988
- margin-right: auto !important;
1989
- }
1990
- .responsive-row[data-mobile-wrap="true"][data-mobile-justify="start"] .child-cell table {
1991
- margin-left: 0 !important;
1992
- margin-right: auto !important;
1993
- }
1994
- .responsive-row[data-mobile-wrap="true"][data-mobile-justify="end"] .child-cell table {
1995
- margin-left: auto !important;
1996
- margin-right: 0 !important;
1997
- }
1998
-
1999
- /* 2. Handling Mobile Vertical Alignment (Align Items) */
2000
- /* For non-wrapped rows - controls vertical alignment when cells are side-by-side */
2001
- .responsive-row[data-mobile-align="center"]:not([data-mobile-wrap="true"]) .child-cell {
2002
- vertical-align: middle !important;
2003
- }
2004
- .responsive-row[data-mobile-align="start"]:not([data-mobile-wrap="true"]) .child-cell {
2005
- vertical-align: top !important;
2006
- }
2007
- .responsive-row[data-mobile-align="end"]:not([data-mobile-wrap="true"]) .child-cell {
2008
- vertical-align: bottom !important;
2009
- }
2010
-
2011
- /* For wrapped rows - alignItems controls vertical alignment of content within each child cell */
2012
- .responsive-row[data-mobile-wrap="true"][data-mobile-align="center"] .child-cell {
2013
- vertical-align: middle !important;
2014
- }
2015
- .responsive-row[data-mobile-wrap="true"][data-mobile-align="start"] .child-cell {
2016
- vertical-align: top !important;
2017
- }
2018
- .responsive-row[data-mobile-wrap="true"][data-mobile-align="end"] .child-cell {
2019
- vertical-align: bottom !important;
2020
- }
2021
-
2022
- /* 3. Handling Mobile Wrap - Pure CSS Solution */
2023
- /* Target only the direct row-content-table, not nested ones */
2024
-
2025
- /* Force table to act like block container */
2026
- .responsive-row[data-mobile-wrap="true"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table {
2027
- width: 100% !important;
2028
- max-width: 100% !important;
2029
- }
2030
-
2031
- /* Force table row to stack cells */
2032
- .responsive-row[data-mobile-wrap="true"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr {
2033
- display: block !important;
2034
- }
2035
-
2036
- /* Force each child cell to be full width block */
2037
- .responsive-row[data-mobile-wrap="true"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell {
2217
+ .row-content-table[data-mobile-justify="center"] { margin: 0 auto !important; float: none !important; }
2218
+ .row-content-table[data-mobile-justify="start"] { margin: 0 !important; float: left !important; }
2219
+ .row-content-table[data-mobile-justify="end"] { margin: 0 0 0 auto !important; float: right !important; }
2220
+ .row-content-table[data-mobile-align="center"] .child-cell { vertical-align: middle !important; }
2221
+ .row-content-table[data-mobile-align="start"] .child-cell { vertical-align: top !important; }
2222
+ .row-content-table[data-mobile-align="end"] .child-cell { vertical-align: bottom !important; }
2223
+ .row-content-table[data-mobile-wrap="true"] { width: 100% !important; max-width: 100% !important; }
2224
+ .row-content-table[data-mobile-wrap="true"] > tbody > .content-tr { display: block !important; }
2225
+ .row-content-table[data-mobile-wrap="true"] > tbody > .content-tr > .child-cell {
2038
2226
  display: block !important;
2039
2227
  width: 100% !important;
2040
2228
  box-sizing: border-box !important;
2041
2229
  }
2042
-
2043
- /* Hide horizontal gap cells and create vertical spacing with padding */
2044
- .responsive-row[data-mobile-wrap="true"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .row-gap-td {
2230
+ .row-content-table[data-mobile-wrap="true"] > tbody > .content-tr > .row-gap-td {
2045
2231
  display: none !important;
2046
2232
  width: 0 !important;
2047
2233
  height: 0 !important;
2048
2234
  }
2049
-
2050
- /* Add vertical spacing between stacked cells using margin */
2051
- .responsive-row[data-mobile-wrap="true"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2235
+ .row-content-table[data-mobile-wrap="true"] > tbody > .content-tr > .child-cell:not(:last-child) {
2052
2236
  margin-bottom: 20px !important;
2053
2237
  }
2054
-
2055
- /* Dynamic gap support - common values */
2056
- .responsive-row[data-mobile-wrap="true"][data-gap="10px"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2057
- margin-bottom: 10px !important;
2058
- }
2059
- .responsive-row[data-mobile-wrap="true"][data-gap="15px"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2060
- margin-bottom: 15px !important;
2061
- }
2062
- .responsive-row[data-mobile-wrap="true"][data-gap="20px"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2063
- margin-bottom: 20px !important;
2064
- }
2065
- .responsive-row[data-mobile-wrap="true"][data-gap="24px"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2066
- margin-bottom: 24px !important;
2067
- }
2068
- .responsive-row[data-mobile-wrap="true"][data-gap="30px"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2069
- margin-bottom: 30px !important;
2070
- }
2071
- .responsive-row[data-mobile-wrap="true"][data-gap="40px"] > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > .row-content-table > tbody > .content-tr > .child-cell:not(:last-child) {
2072
- margin-bottom: 40px !important;
2073
- }
2238
+ ${["10px", "15px", "20px", "24px", "30px", "40px", ...rowGaps]
2239
+ .filter((gap, index, self) => self.indexOf(gap) === index)
2240
+ .map((gap) => `
2241
+ .row-content-table[data-mobile-wrap="true"][data-gap="${gap}"] > tbody > .content-tr > .child-cell:not(:last-child) {
2242
+ margin-bottom: ${gap} !important;
2243
+ }`)
2244
+ .join("\n")}
2074
2245
  }
2075
-
2076
- /* ================================================= */
2077
- /* 🔒 UNIVERSAL LINK RESET */
2078
- a {
2079
- color: inherit;
2080
- text-decoration: none;
2081
- }
2082
- /* ================================================= */
2083
-
2084
- /* ================================================= */
2085
- /* 🔒 LIST STYLE ENFORCEMENT */
2086
-
2087
- /* Reset all lists and list items */
2088
- ol, ul {
2089
- margin: 0px;
2090
- padding: 0px;
2091
- list-style: none;
2092
- }
2093
-
2246
+ a { color: inherit; text-decoration: none; }
2247
+ ol, ul { margin: 0px; padding: 0px; list-style: none; }
2094
2248
  li {
2095
2249
  list-style-type: none !important;
2096
2250
  list-style: none !important;
@@ -2099,8 +2253,6 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
2099
2253
  margin: 0px;
2100
2254
  display: block !important;
2101
2255
  }
2102
-
2103
- /* 🔒 FORCE HIDE ::marker pseudo-element for non-list items */
2104
2256
  li::marker {
2105
2257
  content: "" !important;
2106
2258
  font-size: 0px !important;
@@ -2108,24 +2260,18 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
2108
2260
  color: transparent !important;
2109
2261
  width: 0px !important;
2110
2262
  }
2111
-
2112
- /* Apply bullet styles only to items with data-list="bullet" */
2113
2263
  li[data-list="bullet"] {
2114
2264
  list-style-type: disc !important;
2115
2265
  list-style-position: inside !important;
2116
2266
  padding-left: 1.5em;
2117
2267
  display: list-item !important;
2118
2268
  }
2119
-
2120
- /* Apply ordered styles only to items with data-list="ordered" */
2121
2269
  li[data-list="ordered"] {
2122
2270
  list-style-type: decimal !important;
2123
2271
  list-style-position: inside !important;
2124
2272
  padding-left: 1.5em;
2125
2273
  display: list-item !important;
2126
2274
  }
2127
-
2128
- /* Ensure marker only takes its natural size with no extra spacing */
2129
2275
  li[data-list="bullet"]::marker,
2130
2276
  li[data-list="ordered"]::marker {
2131
2277
  content: normal !important;
@@ -2135,22 +2281,13 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
2135
2281
  padding: 0 !important;
2136
2282
  margin: 0 !important;
2137
2283
  }
2138
- /* ================================================= */
2139
-
2140
- /* ================================================= */
2141
- /* 🔒 HEADING STYLE RESET */
2142
- h1, h2, h3, h4, h5, h6 {
2143
- margin: 0;
2144
- padding: 0;
2145
- font-weight: inherit; /* Disables browser defaults */
2146
- }
2147
- /* ================================================= */
2284
+ h1, h2, h3, h4, h5, h6 { margin: 0; padding: 0; font-weight: inherit; }
2148
2285
  `;
2149
- return (jsxs("head", { children: [jsx("meta", { httpEquiv: "Content-Type", content: "text/html; charset=utf-8" }), jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), jsx("meta", { httpEquiv: "X-UA-Compatible", content: "IE=edge" }), jsx("title", { children: title }), jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: msoResetStyles } }), jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: globalStyles } }), children] }));
2286
+ return (jsxs("head", { children: [jsx("meta", { httpEquiv: "Content-Type", content: "text/html; charset=utf-8" }), jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), jsx("meta", { httpEquiv: "X-UA-Compatible", content: "IE=edge" }), jsx("title", { children: title }), fonts.flatMap((resolved) => resolved.fontProps.map((props, i) => (jsx(Font, Object.assign({}, props), `${resolved.family}-${props.fontWeight}-${props.fontStyle}-${i}`)))), children, jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: msoResetStyles } }), jsx("style", { type: "text/css", dangerouslySetInnerHTML: { __html: globalStyles } })] }));
2150
2287
  }
2151
2288
 
2152
2289
  function Heading({ config, devMode, children }) {
2153
- const { text, level = "h1", padding, color, textAlign, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, } = config;
2290
+ const { text, level = "h1", padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, wordBreak, whiteSpace, } = config;
2154
2291
  // Determine the content to render
2155
2292
  const content = text !== null && text !== void 0 ? text : children;
2156
2293
  const isString = typeof content === "string";
@@ -2165,6 +2302,7 @@ function Heading({ config, devMode, children }) {
2165
2302
  const headingStyle = {
2166
2303
  color: color,
2167
2304
  textAlign: textAlign,
2305
+ fontFamily: fontFamily || "Arial, Helvetica, sans-serif",
2168
2306
  fontSize: fontSize,
2169
2307
  fontWeight: fontWeight,
2170
2308
  fontStyle: fontStyle,
@@ -2173,11 +2311,11 @@ function Heading({ config, devMode, children }) {
2173
2311
  textTransform: textTransform,
2174
2312
  textDecoration: textDecoration,
2175
2313
  direction: direction,
2314
+ wordBreak: wordBreak,
2315
+ whiteSpace: whiteSpace,
2176
2316
  // Critical: Remove default top/bottom margin from HTML heading tags
2177
2317
  margin: "0",
2178
2318
  padding: "0",
2179
- // Ensures compatibility with MSO/general font rendering
2180
- fontFamily: "Arial, Helvetica, sans-serif",
2181
2319
  // Outlook specific fixes (using string indexing)
2182
2320
  ["msoLineHeightRule"]: "exactly",
2183
2321
  };
@@ -2212,61 +2350,196 @@ function Html({ children, backgroundColor = "#ffffff", }) {
2212
2350
  );
2213
2351
  }
2214
2352
 
2215
- function Image({ config, devNode, devMode }) {
2216
- const { src, alt, width, height, maxHeight, maxWidth, backgroundColor, padding, borderRadius, href, target, } = config;
2217
- // 1. Image Style: Critical for compatibility, especially display: block
2218
- const imgStyle = {
2219
- // Basic image properties
2220
- display: "block", // Prevents extra vertical space/gaps below the image
2221
- objectFit: "cover", // For controlling how the image fits (modern CSS, may be ignored)
2222
- // Dimensions (using CSS fallback)
2223
- width: width || "100%",
2224
- height: height || "auto",
2225
- maxWidth: maxWidth || "100%",
2226
- maxHeight: maxHeight,
2227
- // Styling
2228
- border: "0", // Ensures no default browser/client border
2229
- borderRadius: borderRadius,
2353
+ /**
2354
+ * Content rendered by Outlook Classic only.
2355
+ * Outputs: <!--[if mso]> ... <![endif]-->
2356
+ */
2357
+ function MsoOnly({ html }) {
2358
+ return (jsx("td", { dangerouslySetInnerHTML: {
2359
+ __html: `<!--[if mso]>${html}<![endif]-->`,
2360
+ } }));
2361
+ }
2362
+ /**
2363
+ * Content hidden from Outlook Classic, visible in all other clients.
2364
+ * Outputs: <!--[if !mso]><!--> ... <!--<![endif]-->
2365
+ */
2366
+ function NonMso({ html }) {
2367
+ return (jsx("td", { dangerouslySetInnerHTML: {
2368
+ __html: `<!--[if !mso]><!-->${html}<!--<![endif]-->`,
2369
+ } }));
2370
+ }
2371
+
2372
+ // ---------------------------------------------------------------------------
2373
+ // Helpers
2374
+ // ---------------------------------------------------------------------------
2375
+ function getBorderStyle$3(border) {
2376
+ if (!border)
2377
+ return {};
2378
+ const style = {};
2379
+ if (border.width && border.style && border.color) {
2380
+ style.border = `${border.width} ${border.style} ${border.color}`;
2381
+ }
2382
+ else {
2383
+ const hasIndividual = border.top || border.right || border.bottom || border.left;
2384
+ if (hasIndividual) {
2385
+ style.borderTop = "none";
2386
+ style.borderRight = "none";
2387
+ style.borderBottom = "none";
2388
+ style.borderLeft = "none";
2389
+ }
2390
+ }
2391
+ if (border.top)
2392
+ style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
2393
+ if (border.right)
2394
+ style.borderRight = `${border.right.width} ${border.right.style} ${border.right.color}`;
2395
+ if (border.bottom)
2396
+ style.borderBottom = `${border.bottom.width} ${border.bottom.style} ${border.bottom.color}`;
2397
+ if (border.left)
2398
+ style.borderLeft = `${border.left.width} ${border.left.style} ${border.left.color}`;
2399
+ return style;
2400
+ }
2401
+ function getBorderStyleString$1(border) {
2402
+ if (!border)
2403
+ return "";
2404
+ const styles = [];
2405
+ if (border.width && border.style && border.color) {
2406
+ styles.push(`border:${border.width} ${border.style} ${border.color};`);
2407
+ }
2408
+ else {
2409
+ const hasIndividual = border.top || border.right || border.bottom || border.left;
2410
+ if (hasIndividual) {
2411
+ styles.push("border-top:none;", "border-right:none;", "border-bottom:none;", "border-left:none;");
2412
+ }
2413
+ }
2414
+ if (border.top)
2415
+ styles.push(`border-top:${border.top.width} ${border.top.style} ${border.top.color};`);
2416
+ if (border.right)
2417
+ styles.push(`border-right:${border.right.width} ${border.right.style} ${border.right.color};`);
2418
+ if (border.bottom)
2419
+ styles.push(`border-bottom:${border.bottom.width} ${border.bottom.style} ${border.bottom.color};`);
2420
+ if (border.left)
2421
+ styles.push(`border-left:${border.left.width} ${border.left.style} ${border.left.color};`);
2422
+ return styles.join(" ");
2423
+ }
2424
+ // ---------------------------------------------------------------------------
2425
+ // Merged styles helper — applies mobile overrides on top of desktop values
2426
+ // ---------------------------------------------------------------------------
2427
+ function mergeConfig(config, overrides) {
2428
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2429
+ return {
2430
+ width: (_a = overrides === null || overrides === void 0 ? void 0 : overrides.width) !== null && _a !== void 0 ? _a : config.width,
2431
+ height: (_b = overrides === null || overrides === void 0 ? void 0 : overrides.height) !== null && _b !== void 0 ? _b : config.height,
2432
+ maxWidth: (_c = overrides === null || overrides === void 0 ? void 0 : overrides.maxWidth) !== null && _c !== void 0 ? _c : config.maxWidth,
2433
+ maxHeight: (_d = overrides === null || overrides === void 0 ? void 0 : overrides.maxHeight) !== null && _d !== void 0 ? _d : config.maxHeight,
2434
+ backgroundColor: (_e = overrides === null || overrides === void 0 ? void 0 : overrides.backgroundColor) !== null && _e !== void 0 ? _e : config.backgroundColor,
2435
+ padding: (_f = overrides === null || overrides === void 0 ? void 0 : overrides.padding) !== null && _f !== void 0 ? _f : config.padding,
2436
+ borderRadius: (_g = overrides === null || overrides === void 0 ? void 0 : overrides.borderRadius) !== null && _g !== void 0 ? _g : config.borderRadius,
2437
+ border: (_h = overrides === null || overrides === void 0 ? void 0 : overrides.border) !== null && _h !== void 0 ? _h : config.border,
2230
2438
  };
2231
- // 2. Link Style: Ensure no underline or color changes
2439
+ }
2440
+ // ---------------------------------------------------------------------------
2441
+ // Desktop table — JSX (same as original)
2442
+ // ---------------------------------------------------------------------------
2443
+ function renderDesktopTable({ config, className, devNode, devMode, }) {
2444
+ const { src, alt, href, target } = config;
2445
+ const { width, height, maxWidth, maxHeight, backgroundColor, padding, borderRadius, border, } = mergeConfig(config);
2446
+ const borderStyle = getBorderStyle$3(border);
2447
+ const imgStyle = Object.assign({ display: "block", objectFit: "cover", width: width || "100%", height: height || "auto", maxWidth: maxWidth || "100%", maxHeight: maxHeight, border: "0", borderRadius: borderRadius }, borderStyle);
2232
2448
  const linkStyle = {
2233
2449
  display: "block",
2234
2450
  textDecoration: "none",
2235
2451
  border: "0",
2236
2452
  outline: "none",
2237
2453
  };
2238
- // 3. TD Style: Where padding and background are reliably applied
2239
2454
  const tdStyle = {
2240
2455
  padding: padding,
2241
2456
  backgroundColor: backgroundColor,
2242
- fontSize: "0", // CRITICAL: Collapses extra space from Outlook/Gmail
2243
- lineHeight: "0", // CRITICAL: Collapses extra space from Outlook/Gmail
2457
+ fontSize: "0",
2458
+ lineHeight: "0",
2244
2459
  };
2245
- // Image element with proper attributes for email compatibility
2246
- const imageElement = (jsx("img", { draggable: false, src: src, alt: alt, style: imgStyle,
2247
- // For Outlook: Use the smaller of width or maxWidth for the HTML attribute
2248
- width: (() => {
2249
- const widthPx = (width === null || width === void 0 ? void 0 : width.endsWith("px")) ? parseInt(width, 10) : undefined;
2250
- const maxWidthPx = (maxWidth === null || maxWidth === void 0 ? void 0 : maxWidth.endsWith("px"))
2251
- ? parseInt(maxWidth, 10)
2252
- : undefined;
2253
- if (widthPx && maxWidthPx) {
2254
- return Math.min(widthPx, maxWidthPx);
2255
- }
2256
- return widthPx || maxWidthPx;
2257
- })(), height: (height === null || height === void 0 ? void 0 : height.endsWith("px")) ? parseInt(height, 10) : undefined, border: 0 }));
2258
- // Wrap image in link if href is provided and not in dev mode
2460
+ const widthNum = (width === null || width === void 0 ? void 0 : width.endsWith("px")) ? parseInt(width, 10) : undefined;
2461
+ const maxWidthNum = (maxWidth === null || maxWidth === void 0 ? void 0 : maxWidth.endsWith("px"))
2462
+ ? parseInt(maxWidth, 10)
2463
+ : undefined;
2464
+ const heightNum = (height === null || height === void 0 ? void 0 : height.endsWith("px")) ? parseInt(height, 10) : undefined;
2465
+ const imageElement = (jsx("img", { draggable: false, src: src, alt: alt, style: imgStyle, width: widthNum && maxWidthNum
2466
+ ? Math.min(widthNum, maxWidthNum)
2467
+ : widthNum || maxWidthNum, height: heightNum, border: 0 }));
2259
2468
  const content = href && !devMode ? (jsx("a", Object.assign({ href: href, target: target, style: linkStyle }, (target === "_blank" ? { rel: "noopener noreferrer" } : {}), { children: imageElement }))) : (imageElement);
2260
- return (
2261
- // We wrap the image in a table to reliably apply padding, background, and alignment.
2262
- jsxs("table", { "aria-label": `Image Wrapper for: ${alt}`, role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2263
- // --- Start dev
2469
+ return (jsxs("table", { "aria-label": `Image Wrapper for: ${alt}`, role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, className: className, style: {
2264
2470
  position: "relative",
2265
- // --- End dev
2266
2471
  width: width || "100%",
2267
2472
  borderCollapse: "collapse",
2268
2473
  }, onClick: devMode ? (e) => e.preventDefault() : undefined, children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: tdStyle, align: "center", children: content }) }) }), devMode && !!devNode && (jsx("tfoot", { children: jsx("tr", { children: jsx("td", { children: devNode }) }) }))] }));
2269
2474
  }
2475
+ // ---------------------------------------------------------------------------
2476
+ // Mobile table — HTML string (injected via NonMso, same pattern as Icon VML)
2477
+ // ---------------------------------------------------------------------------
2478
+ function buildMobileTableHTML({ config, overrides, className, }) {
2479
+ const { src, alt, href, target } = config;
2480
+ const { width, height, maxWidth, maxHeight, backgroundColor, padding, borderRadius, border, } = mergeConfig(config, overrides);
2481
+ const borderStyleStr = getBorderStyleString$1(border);
2482
+ const widthNum = (width === null || width === void 0 ? void 0 : width.endsWith("px")) ? parseInt(width, 10) : undefined;
2483
+ const maxWidthNum = (maxWidth === null || maxWidth === void 0 ? void 0 : maxWidth.endsWith("px"))
2484
+ ? parseInt(maxWidth, 10)
2485
+ : undefined;
2486
+ const heightNum = (height === null || height === void 0 ? void 0 : height.endsWith("px")) ? parseInt(height, 10) : undefined;
2487
+ const resolvedWidth = widthNum && maxWidthNum
2488
+ ? Math.min(widthNum, maxWidthNum)
2489
+ : widthNum || maxWidthNum;
2490
+ const imgTag = `<img
2491
+ draggable="false"
2492
+ src="${src}"
2493
+ alt="${alt}"
2494
+ ${resolvedWidth ? `width="${resolvedWidth}"` : ""}
2495
+ ${heightNum ? `height="${heightNum}"` : ""}
2496
+ border="0"
2497
+ style="display:block;object-fit:cover;width:${width || "100%"};height:${height || "auto"};max-width:${maxWidth || "100%"};${maxHeight ? `max-height:${maxHeight};` : ""}border:0;${borderRadius ? `border-radius:${borderRadius};` : ""}${borderStyleStr}"
2498
+ />`;
2499
+ const content = href
2500
+ ? `<a href="${href}" target="${target || "_self"}" style="display:block;text-decoration:none;border:0;outline:none;"${target === "_blank" ? ' rel="noopener noreferrer"' : ""}>${imgTag}</a>`
2501
+ : imgTag;
2502
+ return `
2503
+ <table
2504
+ aria-label="Image Wrapper for: ${alt}"
2505
+ role="presentation"
2506
+ cellpadding="0"
2507
+ cellspacing="0"
2508
+ border="0"
2509
+ class="${className}"
2510
+ style="position:relative;width:${width || "100%"};border-collapse:collapse;"
2511
+ >
2512
+ <tbody>
2513
+ <tr>
2514
+ <td
2515
+ align="center"
2516
+ style="padding:${padding || ""};background-color:${backgroundColor || ""};font-size:0;line-height:0;"
2517
+ >
2518
+ ${content}
2519
+ </td>
2520
+ </tr>
2521
+ </tbody>
2522
+ </table>
2523
+ `;
2524
+ }
2525
+ // ---------------------------------------------------------------------------
2526
+ // Component
2527
+ // ---------------------------------------------------------------------------
2528
+ function Image({ config, devNode, devMode }) {
2529
+ const { mobile } = config;
2530
+ const hasMobileOverrides = !!mobile && !mobile.hidden;
2531
+ const isHiddenOnMobile = !!(mobile === null || mobile === void 0 ? void 0 : mobile.hidden);
2532
+ return (jsxs(Fragment$1, { children: [renderDesktopTable({
2533
+ config,
2534
+ className: hasMobileOverrides || isHiddenOnMobile ? "hide-on-mobile" : undefined,
2535
+ devNode,
2536
+ devMode,
2537
+ }), hasMobileOverrides && !devMode && (jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: { width: "100%", borderCollapse: "collapse" }, children: jsx("tbody", { children: jsx("tr", { children: jsx(NonMso, { html: buildMobileTableHTML({
2538
+ config,
2539
+ overrides: mobile,
2540
+ className: "hide-on-desktop",
2541
+ }) }) }) }) }))] }));
2542
+ }
2270
2543
  var Image_default = memo(Image, arePropsEqual);
2271
2544
 
2272
2545
  const justifyMap$1 = {
@@ -2279,13 +2552,27 @@ const alignMap = {
2279
2552
  center: "middle",
2280
2553
  end: "bottom",
2281
2554
  };
2282
- function getBorderStyle$1(border) {
2555
+ function getBorderStyle$2(border) {
2283
2556
  if (!border)
2284
2557
  return {};
2285
2558
  const style = {};
2559
+ // If a full border is specified, apply it
2286
2560
  if (border.width && border.style && border.color) {
2287
2561
  style.border = `${border.width} ${border.style} ${border.color}`;
2288
2562
  }
2563
+ else {
2564
+ // If only individual borders are specified, explicitly set others to 'none'
2565
+ // to prevent Outlook Classic from showing black borders
2566
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
2567
+ if (hasIndividualBorders) {
2568
+ // Default all borders to none
2569
+ style.borderTop = "none";
2570
+ style.borderRight = "none";
2571
+ style.borderBottom = "none";
2572
+ style.borderLeft = "none";
2573
+ }
2574
+ }
2575
+ // Override with specific borders if provided
2289
2576
  if (border.top) {
2290
2577
  style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
2291
2578
  }
@@ -2300,23 +2587,50 @@ function getBorderStyle$1(border) {
2300
2587
  }
2301
2588
  return style;
2302
2589
  }
2303
- function Row({ children, config, devNode }) {
2304
- var _a, _b, _c, _d, _e, _f;
2590
+ function getHrefFromInnerLink(innerLink) {
2591
+ if (!innerLink || innerLink.type === "none")
2592
+ return undefined;
2593
+ switch (innerLink.type) {
2594
+ case "url":
2595
+ return innerLink.url;
2596
+ case "email":
2597
+ return innerLink.email ? `mailto:${innerLink.email}` : undefined;
2598
+ case "phone":
2599
+ return innerLink.phone ? `tel:${innerLink.phone}` : undefined;
2600
+ case "anchor":
2601
+ return innerLink.anchor ? `#${innerLink.anchor}` : undefined;
2602
+ case "page_top":
2603
+ return "#";
2604
+ case "page_bottom":
2605
+ return "#bottom";
2606
+ default:
2607
+ return undefined;
2608
+ }
2609
+ }
2610
+ function Row({ children, config, devNode, devMode }) {
2611
+ var _a, _b, _c, _d, _e, _f, _g;
2305
2612
  const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
2306
2613
  const numChildren = childrenArray.length;
2307
- // 1. Outer TD for Background and Border Radius (no border here)
2614
+ const href = getHrefFromInnerLink(config.innerLink);
2615
+ const target = (_a = config.innerLink) === null || _a === void 0 ? void 0 : _a.target;
2616
+ // 1. Outer TD for Background and Border Radius (no border here).
2617
+ // height declared here is the *total* outer height.
2308
2618
  const backgroundTdStyle = Object.assign({ backgroundColor: config.backgroundColor, borderRadius: config.borderRadius, width: config.width || "100%", height: config.height,
2309
2619
  // Background Image styles
2310
2620
  backgroundImage: config.backgroundImage
2311
2621
  ? `url(${config.backgroundImage.src})`
2312
- : undefined, backgroundRepeat: (_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.repeat, backgroundSize: (_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.size, backgroundPosition: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.position }, (config.borderRadius && { overflow: "hidden" }));
2313
- // 2. Inner Table for Border and Border Radius
2314
- const borderTableStyle = Object.assign({ width: "100%", height: "100%", borderCollapse: "separate", borderSpacing: 0, borderRadius: config.borderRadius }, getBorderStyle$1(config.border));
2315
- // 3. TD for Padding
2622
+ : undefined, backgroundRepeat: (_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.repeat, backgroundSize: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.size, backgroundPosition: (_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.position }, (config.borderRadius && { overflow: "hidden" }));
2623
+ // 2. Inner Table for Border and Border Radius.
2624
+ // height: 100% so it stretches to fill the outer TD.
2625
+ const borderTableStyle = Object.assign({ width: "100%", height: "100%", borderCollapse: "separate", borderSpacing: 0, borderRadius: config.borderRadius }, getBorderStyle$2(config.border));
2626
+ // 3. TD for Padding only — no height.
2627
+ // The outer TD owns the total height; setting height here would cause
2628
+ // browsers/email clients to treat it as content-box height and add
2629
+ // padding on top, making the row taller than the declared height.
2316
2630
  const paddingTdStyle = {
2317
2631
  padding: config.padding,
2318
2632
  width: "100%",
2319
- height: "100%",
2633
+ // height intentionally omitted — padding must be inner, not additive
2320
2634
  verticalAlign: "top",
2321
2635
  };
2322
2636
  // 4. Content Table - horizontal layout
@@ -2337,32 +2651,56 @@ function Row({ children, config, devNode }) {
2337
2651
  ? justifyMap$1[config.justifyContent]
2338
2652
  : "left";
2339
2653
  const tdValign = config.alignItems ? alignMap[config.alignItems] : "top";
2340
- return (jsxs("table", Object.assign({ "aria-label": "Row Outer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2654
+ // Content to render - wrapped in anchor if innerLink is defined
2655
+ const content = (jsxs("table", Object.assign({ "aria-label": "Row Outer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2341
2656
  position: "relative",
2342
2657
  width: config.width || "100%",
2343
2658
  height: config.height,
2344
2659
  borderCollapse: "collapse",
2345
- } }, (config.height && { height: config.height }), { "data-mobile-justify": (_d = config.mobile) === null || _d === void 0 ? void 0 : _d.justifyContent, "data-mobile-align": (_e = config.mobile) === null || _e === void 0 ? void 0 : _e.alignItems, "data-mobile-wrap": ((_f = config.mobile) === null || _f === void 0 ? void 0 : _f.wrap) ? "true" : undefined, "data-gap": config.gap, className: "responsive-row", children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", Object.assign({ style: backgroundTdStyle }, (config.height && { height: config.height }), { children: jsx("table", { "aria-label": "Row Border Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: borderTableStyle, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: paddingTdStyle, children: jsx("table", { "aria-label": "Row Justification Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2660
+ } }, (config.height && { height: config.height }), { children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", Object.assign({ style: backgroundTdStyle }, (config.height && { height: config.height }), { children: jsx("table", { "aria-label": "Row Border Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: borderTableStyle, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: paddingTdStyle, children: jsx("table", { "aria-label": "Row Justification Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
2346
2661
  width: "100%",
2347
2662
  height: "100%",
2348
2663
  borderCollapse: "collapse",
2349
- }, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { align: tdAlign, children: jsx("table", Object.assign({ "aria-label": "Row Content", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: contentTableStyle }, (config.height && { height: config.height }), { className: "content-table row-content-table", children: jsx("tbody", { children: jsx("tr", { className: "content-tr", children: childrenArray.map((child, index) => (jsxs(Fragment, { children: [jsx("td", { valign: tdValign, style: {
2664
+ }, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { align: tdAlign, children: jsx("table", Object.assign({ "aria-label": "Row Content", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: contentTableStyle }, (config.height && { height: config.height }), { className: "content-table row-content-table", "data-mobile-justify": (_e = config.mobile) === null || _e === void 0 ? void 0 : _e.justifyContent, "data-mobile-align": (_f = config.mobile) === null || _f === void 0 ? void 0 : _f.alignItems, "data-mobile-wrap": ((_g = config.mobile) === null || _g === void 0 ? void 0 : _g.wrap) ? "true" : undefined, "data-gap": config.gap, children: jsx("tbody", { children: jsx("tr", { className: "content-tr", children: childrenArray.map((child, index) => (jsxs(Fragment, { children: [jsx("td", { valign: tdValign, style: {
2350
2665
  verticalAlign: tdValign,
2351
2666
  textAlign: "left",
2352
2667
  padding: "0",
2353
2668
  margin: "0",
2354
2669
  }, className: "child-cell", children: child }), index < numChildren - 1 &&
2355
2670
  config.gap && (jsx("td", { width: config.gap, style: gapTdStyle, className: "row-gap-td", children: "\u00A0" }, `row-gap-${index}`))] }, `row-child-${index}`))) }) }) })) }) }) }) }) }) }) }) }) })) }) }), devNode && (jsx("tfoot", { children: jsx("tr", { children: jsx("td", { children: devNode }) }) }))] })));
2671
+ // Wrap in anchor tag if innerLink is defined and NOT in dev mode
2672
+ if (href && !devMode) {
2673
+ return (jsx("a", Object.assign({ href: href }, (target && { target }), { style: {
2674
+ textDecoration: "none",
2675
+ color: "inherit",
2676
+ display: "block",
2677
+ }, children: content })));
2678
+ }
2679
+ return content;
2356
2680
  }
2357
2681
  var Row_default = memo(Row, arePropsEqual);
2358
2682
 
2359
- function getBorderStyle(border) {
2683
+ function getBorderStyle$1(border) {
2360
2684
  if (!border)
2361
2685
  return {};
2362
2686
  const style = {};
2687
+ // If a full border is specified, apply it
2363
2688
  if (border.width && border.style && border.color) {
2364
2689
  style.border = `${border.width} ${border.style} ${border.color}`;
2365
2690
  }
2691
+ else {
2692
+ // If only individual borders are specified, explicitly set others to 'none'
2693
+ // to prevent Outlook Classic from showing black borders
2694
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
2695
+ if (hasIndividualBorders) {
2696
+ // Default all borders to none
2697
+ style.borderTop = "none";
2698
+ style.borderRight = "none";
2699
+ style.borderBottom = "none";
2700
+ style.borderLeft = "none";
2701
+ }
2702
+ }
2703
+ // Override with specific borders if provided
2366
2704
  if (border.top) {
2367
2705
  style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
2368
2706
  }
@@ -2380,7 +2718,7 @@ function getBorderStyle(border) {
2380
2718
  const Section = ({ config, children, devNode, }) => {
2381
2719
  var _a, _b, _c;
2382
2720
  const { sectionType, padding } = config;
2383
- return (jsxs("table", { "aria-label": `Section |Table | ${sectionType}`, role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: Object.assign(Object.assign({ position: "relative", width: "100%", backgroundColor: config.backgroundColor }, getBorderStyle(config.border)), { backgroundImage: config.backgroundImage
2721
+ return (jsxs("table", { "aria-label": `Section |Table | ${sectionType}`, role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: Object.assign(Object.assign({ position: "relative", width: "100%", backgroundColor: config.backgroundColor }, getBorderStyle$1(config.border)), { backgroundImage: config.backgroundImage
2384
2722
  ? `url(${config.backgroundImage.src})`
2385
2723
  : undefined, backgroundRepeat: (_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.repeat, backgroundSize: (_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.size, backgroundPosition: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.position }), children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: {
2386
2724
  padding: padding,
@@ -2397,7 +2735,7 @@ const Section = ({ config, children, devNode, }) => {
2397
2735
  var Section_default = memo(Section, arePropsEqual);
2398
2736
 
2399
2737
  function Spacer({ config, devNode }) {
2400
- const { height } = config;
2738
+ const { height, hideOnMobile } = config;
2401
2739
  // 1. Spacer Table Style
2402
2740
  const spacerTableStyle = {
2403
2741
  // Crucial for compatibility: Ensures no background or border interference
@@ -2405,7 +2743,6 @@ function Spacer({ config, devNode }) {
2405
2743
  borderCollapse: "collapse",
2406
2744
  border: "0",
2407
2745
  width: "100%",
2408
- // ✅ FIX: Use string literal indexing for MSO properties
2409
2746
  // Note the CSS standard dash convention: 'mso-table-lspace'
2410
2747
  // ["mso-table-lspace" as string]: "0pt",
2411
2748
  ["msoTableLspace"]: "0pt",
@@ -2426,14 +2763,14 @@ function Spacer({ config, devNode }) {
2426
2763
  // Outer table ensures the spacer spans the full width of its container
2427
2764
  jsxs("table", Object.assign({ "aria-label": "Vertical Spacer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: Object.assign({
2428
2765
  // --- Start dev
2429
- position: "relative" }, spacerTableStyle) }, { height: spacerHeightAttribute }, { children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: spacerTdStyle,
2766
+ position: "relative" }, spacerTableStyle) }, { height: spacerHeightAttribute }, { className: hideOnMobile ? "hide-on-mobile" : undefined, children: [jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: spacerTdStyle,
2430
2767
  // Explicit height attribute
2431
2768
  height: spacerHeightAttribute, children: "\u00A0" }) }) }), devNode && (jsx("tfoot", { children: jsx("tr", { children: jsx("td", { children: devNode }) }) }))] })));
2432
2769
  }
2433
2770
  var Spacer_default = memo(Spacer, arePropsEqual);
2434
2771
 
2435
2772
  function Text({ config, devMode, children }) {
2436
- const { text, padding, color, textAlign, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, opacity, whiteSpace, } = config;
2773
+ const { text, padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, opacity, whiteSpace, wordBreak = "break-all", } = config;
2437
2774
  // 1. TD Style: Where padding and background are reliably applied.
2438
2775
  const tdStyle = {
2439
2776
  padding: padding,
@@ -2445,6 +2782,7 @@ function Text({ config, devMode, children }) {
2445
2782
  const contentStyle = {
2446
2783
  color: color,
2447
2784
  textAlign: textAlign,
2785
+ fontFamily: fontFamily || "Arial, Helvetica, sans-serif",
2448
2786
  fontSize: fontSize,
2449
2787
  fontWeight: fontWeight,
2450
2788
  fontStyle: fontStyle,
@@ -2456,9 +2794,9 @@ function Text({ config, devMode, children }) {
2456
2794
  verticalAlign: verticalAlign,
2457
2795
  opacity: opacity,
2458
2796
  whiteSpace: whiteSpace,
2797
+ wordBreak: wordBreak,
2459
2798
  margin: "0",
2460
2799
  padding: "0",
2461
- fontFamily: "Arial, Helvetica, sans-serif",
2462
2800
  };
2463
2801
  // Determine content to render
2464
2802
  const content = text !== null && text !== void 0 ? text : children;
@@ -2476,18 +2814,96 @@ const justifyMap = {
2476
2814
  center: "center",
2477
2815
  end: "right",
2478
2816
  };
2817
+ function getBorderStyle(border) {
2818
+ if (!border)
2819
+ return {};
2820
+ const style = {};
2821
+ // If a full border is specified, apply it
2822
+ if (border.width && border.style && border.color) {
2823
+ style.border = `${border.width} ${border.style} ${border.color}`;
2824
+ }
2825
+ else {
2826
+ // If only individual borders are specified, explicitly set others to 'none'
2827
+ // to prevent Outlook Classic from showing black borders
2828
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
2829
+ if (hasIndividualBorders) {
2830
+ // Default all borders to none
2831
+ style.borderTop = "none";
2832
+ style.borderRight = "none";
2833
+ style.borderBottom = "none";
2834
+ style.borderLeft = "none";
2835
+ }
2836
+ }
2837
+ // Override with specific borders if provided
2838
+ if (border.top) {
2839
+ style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
2840
+ }
2841
+ if (border.right) {
2842
+ style.borderRight = `${border.right.width} ${border.right.style} ${border.right.color}`;
2843
+ }
2844
+ if (border.bottom) {
2845
+ style.borderBottom = `${border.bottom.width} ${border.bottom.style} ${border.bottom.color}`;
2846
+ }
2847
+ if (border.left) {
2848
+ style.borderLeft = `${border.left.width} ${border.left.style} ${border.left.color}`;
2849
+ }
2850
+ return style;
2851
+ }
2852
+ function getBorderStyleString(border) {
2853
+ if (!border)
2854
+ return "";
2855
+ const styles = [];
2856
+ // If a full border is specified, apply it
2857
+ if (border.width && border.style && border.color) {
2858
+ styles.push(`border: ${border.width} ${border.style} ${border.color};`);
2859
+ }
2860
+ else {
2861
+ // If only individual borders are specified
2862
+ const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
2863
+ if (hasIndividualBorders) {
2864
+ // Default all borders to none
2865
+ styles.push("border-top: none;");
2866
+ styles.push("border-right: none;");
2867
+ styles.push("border-bottom: none;");
2868
+ styles.push("border-left: none;");
2869
+ }
2870
+ }
2871
+ // Override with specific borders if provided
2872
+ if (border.top) {
2873
+ styles.push(`border-top: ${border.top.width} ${border.top.style} ${border.top.color};`);
2874
+ }
2875
+ if (border.right) {
2876
+ styles.push(`border-right: ${border.right.width} ${border.right.style} ${border.right.color};`);
2877
+ }
2878
+ if (border.bottom) {
2879
+ styles.push(`border-bottom: ${border.bottom.width} ${border.bottom.style} ${border.bottom.color};`);
2880
+ }
2881
+ if (border.left) {
2882
+ styles.push(`border-left: ${border.left.width} ${border.left.style} ${border.left.color};`);
2883
+ }
2884
+ return styles.join(" ");
2885
+ }
2479
2886
  // Helper to build Iconify API URL
2480
2887
  function buildIconifyUrl(config) {
2481
2888
  const { iconIdentifier, height = 24, color = "000000", rotate = 0, rotateOrientation = "cw", } = config;
2482
2889
  if (!iconIdentifier)
2483
2890
  return null;
2891
+ // Parse height to extract numeric value
2892
+ const parseHeight = (h) => {
2893
+ if (typeof h === "number")
2894
+ return h;
2895
+ // Extract numeric value from string (e.g., "24px" -> 24)
2896
+ const match = String(h).match(/^(-?\d*\.?\d+)/);
2897
+ return match ? parseFloat(match[1]) : 24;
2898
+ };
2899
+ const numericHeight = parseHeight(height);
2484
2900
  // Remove # from color if present
2485
2901
  const cleanColor = color.replace("#", "");
2486
2902
  // Build URL from template
2487
2903
  const template = process.env.ICONIFY_API_IMAGE_URI ||
2488
2904
  "https://iconify.pagenflow.com/api/image/{{height}}/{{color}}/{{rotate}}-{{rotate-orientation}}/{{icon-full-name}}.png";
2489
2905
  return template
2490
- .replace("{{height}}", String(Number(height) * Number(2)))
2906
+ .replace("{{height}}", String(numericHeight * 2))
2491
2907
  .replace("{{color}}", cleanColor)
2492
2908
  .replace("{{rotate}}", String(rotate))
2493
2909
  .replace("{{rotate-orientation}}", rotateOrientation)
@@ -2517,12 +2933,15 @@ function buildLinkHref(innerLink) {
2517
2933
  function Icon({ config, devNode, devMode, children }) {
2518
2934
  const {
2519
2935
  // base64Source,
2520
- width, height, backgroundColor, padding = "0", borderRadius = "0", innerLink, justifyContent = "center", } = config;
2936
+ width, height, backgroundColor, padding = "0", borderRadius = "0", border, innerLink, justifyContent = "center", } = config;
2521
2937
  // Determine icon source
2522
2938
  const iconSrc = buildIconifyUrl(config);
2523
2939
  const href = buildLinkHref(innerLink);
2524
2940
  const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_self";
2525
2941
  const align = justifyMap[justifyContent];
2942
+ // Get border styles
2943
+ const borderStyle = getBorderStyle(border);
2944
+ const borderStyleString = getBorderStyleString(border);
2526
2945
  // Convert width/height to string with px if number
2527
2946
  const widthStr = typeof width === "number" ? `${width}px` : width;
2528
2947
  const heightStr = typeof height === "number" ? `${height}px` : height;
@@ -2543,6 +2962,7 @@ function Icon({ config, devNode, devMode, children }) {
2543
2962
  border: 0, // No default border
2544
2963
  width: widthStr || "auto",
2545
2964
  height: heightStr || "auto",
2965
+ objectFit: "contain",
2546
2966
  };
2547
2967
  // 2. Link Style: No underline or color changes
2548
2968
  const linkStyle = {
@@ -2551,14 +2971,21 @@ function Icon({ config, devNode, devMode, children }) {
2551
2971
  border: 0,
2552
2972
  outline: "none",
2553
2973
  };
2554
- // 3. TD Style: Padding and background
2555
- const tdStyle = {
2556
- padding: padding,
2974
+ // 3. Outer TD Style: Background and border-radius wrapper with border
2975
+ const outerTdStyle = {
2557
2976
  backgroundColor: backgroundColor,
2558
- fontSize: "0", // CRITICAL: Collapses extra space
2559
- lineHeight: "0", // CRITICAL: Collapses extra space7
2560
2977
  borderRadius: borderRadius,
2561
2978
  overflow: "hidden",
2979
+ fontSize: "0",
2980
+ lineHeight: "0",
2981
+ };
2982
+ // 4. Inner Table Style: Apply border here with border-collapse: separate
2983
+ const innerTableStyle = Object.assign({ width: "100%", borderCollapse: "separate", borderSpacing: 0, borderRadius: borderRadius }, borderStyle);
2984
+ // 5. Inner TD Style: Padding
2985
+ const innerTdStyle = {
2986
+ padding: padding,
2987
+ fontSize: "0", // CRITICAL: Collapses extra space
2988
+ lineHeight: "0", // CRITICAL: Collapses extra space
2562
2989
  };
2563
2990
  // --- VML Calculation for Outlook Compatibility ---
2564
2991
  const numericPadding = parseInt(padding.split(" ")[0] || "0", 10);
@@ -2575,15 +3002,19 @@ function Icon({ config, devNode, devMode, children }) {
2575
3002
  const arcsize = numericBorderRadius > 0
2576
3003
  ? Math.min((numericBorderRadius / Math.min(vmlWidth, vmlHeight)) * 100, 100)
2577
3004
  : 0;
3005
+ // VML stroke color for border
3006
+ const vmlStrokeColor = (border === null || border === void 0 ? void 0 : border.color) || vmlFillColor;
3007
+ const vmlStrokeWeight = (border === null || border === void 0 ? void 0 : border.width) ? parseInt(border.width, 10) : 0;
3008
+ const hasVmlStroke = vmlStrokeWeight > 0;
2578
3009
  // Build VML code for Outlook
2579
3010
  const vmlIcon = backgroundColor && numericBorderRadius > 0
2580
3011
  ? `
2581
3012
  <!--[if mso]>
2582
- <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" ${href && !devMode ? `href="${href}"` : ""} style="height:${vmlHeight}px;width:${vmlWidth}px;v-text-anchor:middle;" arcsize="${arcsize}%" stroke="false" fillcolor="${vmlFillColor}">
3013
+ <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" ${href && !devMode ? `href="${href}"` : ""} style="height:${vmlHeight}px;width:${vmlWidth}px;v-text-anchor:middle;" arcsize="${arcsize}%" ${hasVmlStroke ? `strokecolor="${vmlStrokeColor}" strokeweight="${vmlStrokeWeight}px"` : 'stroke="false"'} fillcolor="${vmlFillColor}">
2583
3014
  <w:anchorlock/>
2584
3015
  <v:textbox inset="0,0,0,0" style="text-align: center;">
2585
3016
  <center style="padding:${padding};">
2586
- <img src="${iconSrc || ""}" alt="" width="${widthNum || 24}" height="${heightNum || 24}" border="0" style="display:block;border:0;" />
3017
+ <img src="${iconSrc || ""}" alt="" width="${widthNum || 24}" height="${heightNum || 24}" border="0" style="display:block;border:0;object-fit:contain;" />
2587
3018
  </center>
2588
3019
  </v:textbox>
2589
3020
  </v:roundrect>
@@ -2595,8 +3026,7 @@ function Icon({ config, devNode, devMode, children }) {
2595
3026
  return null;
2596
3027
  }
2597
3028
  // Icon image element
2598
- const iconElement = devMode && !!children ? (children) : iconSrc ? (jsx("img", { draggable: false, src: iconSrc, alt: "" // Icons are decorative, empty alt is appropriate
2599
- , style: imgStyle, width: widthNum, height: heightNum, border: 0 })) : (jsx(Fragment$1, {}));
3029
+ const iconElement = devMode && !!children ? (children) : iconSrc ? (jsx("img", { draggable: false, src: iconSrc, alt: "", style: imgStyle, width: widthNum, height: heightNum, border: 0 })) : (jsx(Fragment$1, {}));
2600
3030
  // Wrap in link if href exists and not in dev mode
2601
3031
  const content = href && !devMode ? (jsx("a", Object.assign({ href: href, target: target, style: linkStyle }, (target === "_blank" ? { rel: "noopener noreferrer" } : {}), { children: iconElement }))) : (iconElement);
2602
3032
  // Build the HTML content with VML support (only when NOT in dev mode)
@@ -2608,12 +3038,20 @@ function Icon({ config, devNode, devMode, children }) {
2608
3038
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; width: 100%;">
2609
3039
  <tbody>
2610
3040
  <tr>
2611
- <td style="background-color: ${backgroundColor}; border-radius: ${borderRadius}; padding: ${padding}; font-size: 0; line-height: 0; overflow: hidden;">
2612
- ${href
3041
+ <td style="background-color: ${backgroundColor}; border-radius: ${borderRadius}; overflow: hidden; font-size: 0; line-height: 0;">
3042
+ <table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: separate; border-spacing: 0; border-radius: ${borderRadius}; width: 100%; ${borderStyleString}">
3043
+ <tbody>
3044
+ <tr>
3045
+ <td style="padding: ${padding}; font-size: 0; line-height: 0;">
3046
+ ${href
2613
3047
  ? `<a href="${href}" target="${target}" style="display:block;text-decoration:none;border:0;outline:none;" ${target === "_blank" ? 'rel="noopener noreferrer"' : ""}>
2614
- <img draggable="false" src="${iconSrc}" alt="" width="${widthNum || 24}" height="${heightNum || 24}" border="0" style="display:block;border:0;width:${widthStr || "auto"};height:${heightStr || "auto"};" />
2615
- </a>`
2616
- : `<img draggable="false" src="${iconSrc}" alt="" width="${widthNum || 24}" height="${heightNum || 24}" border="0" style="display:block;border:0;width:${widthStr || "auto"};height:${heightStr || "auto"};" />`}
3048
+ <img draggable="false" src="${iconSrc}" alt="" width="${widthNum || 24}" height="${heightNum || 24}" border="0" style="display:block;border:0;width:${widthStr || "auto"};height:${heightStr || "auto"};object-fit:contain;" />
3049
+ </a>`
3050
+ : `<img draggable="false" src="${iconSrc}" alt="" width="${widthNum || 24}" height="${heightNum || 24}" border="0" style="display:block;border:0;width:${widthStr || "auto"};height:${heightStr || "auto"};object-fit:contain;" />`}
3051
+ </td>
3052
+ </tr>
3053
+ </tbody>
3054
+ </table>
2617
3055
  </td>
2618
3056
  </tr>
2619
3057
  </tbody>
@@ -2625,7 +3063,7 @@ function Icon({ config, devNode, devMode, children }) {
2625
3063
  // --- Start dev
2626
3064
  position: "relative",
2627
3065
  // --- End dev
2628
- width: widthStr || "auto",
3066
+ width: "auto",
2629
3067
  borderCollapse: "collapse",
2630
3068
  // base
2631
3069
  boxSizing: "border-box",
@@ -2634,9 +3072,9 @@ function Icon({ config, devNode, devMode, children }) {
2634
3072
  padding: 0,
2635
3073
  }, onClick: devMode ? (e) => e.preventDefault() : undefined, children: [jsx("tbody", { children: jsx("tr", { children: useVML ? (jsx("td", { dangerouslySetInnerHTML: {
2636
3074
  __html: htmlContent !== null && htmlContent !== void 0 ? htmlContent : "",
2637
- } })) : (jsx("td", { style: tdStyle, align: align, children: content })) }) }), devMode && !!devNode && (jsx("tfoot", { children: jsx("tr", { children: jsx("td", { children: devNode }) }) }))] }));
3075
+ } })) : (jsx("td", { style: outerTdStyle, align: align, children: jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: innerTableStyle, children: jsx("tbody", { children: jsx("tr", { children: jsx("td", { style: innerTdStyle, align: align, children: content }) }) }) }) })) }) }), devMode && !!devNode && (jsx("tfoot", { children: jsx("tr", { children: jsx("td", { children: devNode }) }) }))] }));
2638
3076
  }
2639
3077
  var Icon_default = memo(Icon, arePropsEqual);
2640
3078
 
2641
- export { Body, Button_default as Button, Column_default as Column, Container_default as Container, Divider_default as Divider, Head, Heading_default as Heading, Html, Icon_default as Icon, Image_default as Image, Row_default as Row, Section_default as Section, Spacer_default as Spacer, Text_default as Text };
3079
+ export { Body, Button_default as Button, Column_default as Column, Container_default as Container, Divider_default as Divider, Font, Head, Heading_default as Heading, Html, Icon_default as Icon, Image_default as Image, MsoOnly, NonMso, Row_default as Row, Section_default as Section, Spacer_default as Spacer, Text_default as Text };
2642
3080
  //# sourceMappingURL=index.esm.js.map