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