@pagenflow/email 1.4.3 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Button.d.ts +3 -2
- package/dist/components/Divider.d.ts +0 -5
- package/dist/components/Image.d.ts +7 -2
- package/dist/index.cjs.js +179 -86
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +179 -86
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { BorderConfig } from "../types";
|
|
3
|
+
import IInnerLink from "../types/IInnerLink";
|
|
3
4
|
export interface ButtonConfig {
|
|
4
|
-
/**
|
|
5
|
-
|
|
5
|
+
/** Link configuration for the button destination. Required. */
|
|
6
|
+
innerLink?: IInnerLink;
|
|
6
7
|
/** Button text. */
|
|
7
8
|
children: ReactNode;
|
|
8
9
|
/** Background color. Required for VML compatibility. */
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
export interface DividerConfig {
|
|
3
|
-
/** Thickness of the line (e.g., "1px"). */
|
|
4
3
|
height?: string;
|
|
5
|
-
/** Color of the line. */
|
|
6
4
|
color?: string;
|
|
7
|
-
/** Width of the line (e.g., "100%" or "300px"). */
|
|
8
5
|
width?: string;
|
|
9
|
-
/** Spacing above and below the divider (e.g., "20px 0"). */
|
|
10
6
|
margin?: string;
|
|
11
|
-
/** Horizontal alignment of the divider. */
|
|
12
7
|
align?: "left" | "center" | "right";
|
|
13
8
|
hideOnMobile?: boolean;
|
|
14
9
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from "react";
|
|
2
2
|
import { BorderConfig } from "../types";
|
|
3
|
+
import IInnerLink from "../types/IInnerLink";
|
|
4
|
+
/**
|
|
5
|
+
* RULES NOT TO BE REMOVED
|
|
6
|
+
* -------------------
|
|
7
|
+
* - Image should not be draggable in dev mode as we don't want to disrupt the builder dnd behavior
|
|
8
|
+
*/
|
|
3
9
|
export interface ImageMobileConfig {
|
|
4
10
|
width?: string;
|
|
5
11
|
height?: string;
|
|
@@ -24,8 +30,7 @@ export interface ImageConfig {
|
|
|
24
30
|
padding?: string;
|
|
25
31
|
borderRadius?: string;
|
|
26
32
|
border?: BorderConfig;
|
|
27
|
-
|
|
28
|
-
target?: string;
|
|
33
|
+
innerLink?: IInnerLink;
|
|
29
34
|
objectFit?: CSSProperties["objectFit"];
|
|
30
35
|
objectPosition?: string;
|
|
31
36
|
mobile?: ImageMobileConfig;
|
package/dist/index.cjs.js
CHANGED
|
@@ -1539,6 +1539,27 @@ const justifyMap$3 = {
|
|
|
1539
1539
|
center: "center",
|
|
1540
1540
|
end: "right",
|
|
1541
1541
|
};
|
|
1542
|
+
// Helper to build link href based on innerLink type (mirrors Icon component)
|
|
1543
|
+
function buildLinkHref$2(innerLink) {
|
|
1544
|
+
if (!innerLink || innerLink.type === "none")
|
|
1545
|
+
return null;
|
|
1546
|
+
switch (innerLink.type) {
|
|
1547
|
+
case "url":
|
|
1548
|
+
return innerLink.url || null;
|
|
1549
|
+
case "email":
|
|
1550
|
+
return innerLink.email ? `mailto:${innerLink.email}` : null;
|
|
1551
|
+
case "phone":
|
|
1552
|
+
return innerLink.phone ? `tel:${innerLink.phone}` : null;
|
|
1553
|
+
case "anchor":
|
|
1554
|
+
return innerLink.anchor ? `#${innerLink.anchor}` : null;
|
|
1555
|
+
case "page_top":
|
|
1556
|
+
return "#top";
|
|
1557
|
+
case "page_bottom":
|
|
1558
|
+
return "#bottom";
|
|
1559
|
+
default:
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1542
1563
|
function getBorderStyleString$2(border) {
|
|
1543
1564
|
if (!border)
|
|
1544
1565
|
return "";
|
|
@@ -1574,8 +1595,10 @@ function getBorderStyleString$2(border) {
|
|
|
1574
1595
|
return styles.join(" ");
|
|
1575
1596
|
}
|
|
1576
1597
|
function Button({ config, devMode }) {
|
|
1577
|
-
const {
|
|
1578
|
-
|
|
1598
|
+
const { innerLink, children, backgroundColor, color, padding, borderRadius, border, width, maxWidth, justifyContent, textAlign, fontSize, fontWeight, fontStyle, fontFamily, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, opacity, whiteSpace, wordBreak, } = config;
|
|
1599
|
+
// Resolve href from innerLink
|
|
1600
|
+
const href = buildLinkHref$2(innerLink);
|
|
1601
|
+
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
1579
1602
|
// Sanitize fontFamily early so safeFontFamily is available for all paths below.
|
|
1580
1603
|
const safeFontFamily = fontFamily
|
|
1581
1604
|
? fontFamily.replace(/['"]/g, "")
|
|
@@ -1595,23 +1618,25 @@ function Button({ config, devMode }) {
|
|
|
1595
1618
|
// Check if width is percentage-based or not defined
|
|
1596
1619
|
const isPercentageWidth = !width || width.includes("%");
|
|
1597
1620
|
const useSimpleOutlookApproach = isPercentageWidth;
|
|
1598
|
-
const align = justifyMap$3[justifyContent];
|
|
1621
|
+
const align = justifyContent ? justifyMap$3[justifyContent] : undefined;
|
|
1599
1622
|
// --- VML Calculation and Code for Outlook Compatibility (Fixed Width Only) ---
|
|
1600
1623
|
let vmlButton = "";
|
|
1601
1624
|
if (!useSimpleOutlookApproach) {
|
|
1602
1625
|
// VML needs fixed pixel height. We estimate it based on padding and potential wrapping.
|
|
1603
|
-
const numericPadding = parseInt(padding.split(" ")[0] || "12", 10);
|
|
1604
|
-
const numericFontSize = parseInt(fontSize, 10);
|
|
1605
|
-
const numericLineHeight = lineHeight
|
|
1606
|
-
?
|
|
1607
|
-
|
|
1626
|
+
const numericPadding = padding ? parseInt(padding.split(" ")[0] || "12", 10) : 12;
|
|
1627
|
+
const numericFontSize = fontSize ? parseInt(fontSize, 10) : 0;
|
|
1628
|
+
const numericLineHeight = lineHeight
|
|
1629
|
+
? lineHeight.includes("px")
|
|
1630
|
+
? parseInt(lineHeight, 10)
|
|
1631
|
+
: numericFontSize * parseFloat(lineHeight)
|
|
1632
|
+
: numericFontSize;
|
|
1608
1633
|
// Trust user's explicit pixel width - no calculation needed
|
|
1609
1634
|
const vmlWidth = parseInt(width, 10);
|
|
1610
1635
|
// Calculate VML height - trust user's padding and let text wrap naturally
|
|
1611
1636
|
// VML v:textbox will handle text wrapping automatically
|
|
1612
1637
|
const textContent = typeof children === "string" ? children : "";
|
|
1613
1638
|
// Estimate number of lines based on text length and button width
|
|
1614
|
-
const horizontalPadding = padding.split(" ")[1]
|
|
1639
|
+
const horizontalPadding = (padding === null || padding === void 0 ? void 0 : padding.split(" ")[1])
|
|
1615
1640
|
? parseInt(padding.split(" ")[1], 10) * 2
|
|
1616
1641
|
: numericPadding * 2;
|
|
1617
1642
|
const availableTextWidth = vmlWidth - horizontalPadding;
|
|
@@ -1624,15 +1649,17 @@ function Button({ config, devMode }) {
|
|
|
1624
1649
|
// Add extra 4px buffer to prevent bottom cropping in VML
|
|
1625
1650
|
const vmlHeight = Math.max(numericPadding * 2 + textHeight + 4, 40);
|
|
1626
1651
|
// VML colors must use the full hex format (e.g., #000000)
|
|
1627
|
-
const vmlFillColor = backgroundColor
|
|
1628
|
-
? backgroundColor
|
|
1629
|
-
|
|
1652
|
+
const vmlFillColor = backgroundColor
|
|
1653
|
+
? backgroundColor.startsWith("#")
|
|
1654
|
+
? backgroundColor
|
|
1655
|
+
: `#${backgroundColor}`
|
|
1656
|
+
: undefined;
|
|
1630
1657
|
// VML stroke color for border
|
|
1631
1658
|
const vmlStrokeColor = (border === null || border === void 0 ? void 0 : border.color) || vmlFillColor;
|
|
1632
1659
|
const vmlStrokeWeight = (border === null || border === void 0 ? void 0 : border.width) ? parseInt(border.width, 10) : 0;
|
|
1633
1660
|
const hasVmlStroke = vmlStrokeWeight > 0;
|
|
1634
1661
|
// Build VML font styles - consistent with other rendering paths
|
|
1635
|
-
const vmlFontWeight = fontWeight
|
|
1662
|
+
const vmlFontWeight = fontWeight;
|
|
1636
1663
|
const vmlFontStyle = fontStyle === "italic" ? "font-style:italic;" : "";
|
|
1637
1664
|
const vmlLetterSpacing = letterSpacing
|
|
1638
1665
|
? `letter-spacing:${letterSpacing};`
|
|
@@ -1643,12 +1670,12 @@ function Button({ config, devMode }) {
|
|
|
1643
1670
|
const vmlTextDecoration = textDecoration && textDecoration !== "none"
|
|
1644
1671
|
? `text-decoration:${textDecoration};`
|
|
1645
1672
|
: "";
|
|
1646
|
-
const vmlWhiteSpace = whiteSpace
|
|
1673
|
+
const vmlWhiteSpace = whiteSpace ? `white-space:${whiteSpace};` : "";
|
|
1647
1674
|
const vmlDirection = direction ? `direction:${direction};` : "";
|
|
1648
1675
|
const vmlOpacity = opacity !== undefined ? `opacity:${opacity};` : "";
|
|
1649
1676
|
// VML code uses MSO conditional comments to render only in Outlook
|
|
1650
1677
|
// Use table with explicit MSO height for vertical centering
|
|
1651
|
-
const horizontalPaddingValue = padding.split(" ")[1]
|
|
1678
|
+
const horizontalPaddingValue = (padding === null || padding === void 0 ? void 0 : padding.split(" ")[1])
|
|
1652
1679
|
? parseInt(padding.split(" ")[1], 10)
|
|
1653
1680
|
: numericPadding;
|
|
1654
1681
|
// For VML, we need to use a table inside to properly apply padding and centering
|
|
@@ -1657,7 +1684,7 @@ function Button({ config, devMode }) {
|
|
|
1657
1684
|
if (textAlign === "center") {
|
|
1658
1685
|
vmlAlignAttr = 'align="center"';
|
|
1659
1686
|
}
|
|
1660
|
-
else {
|
|
1687
|
+
else if (textAlign) {
|
|
1661
1688
|
vmlAlignStyle = `text-align:${textAlign};`;
|
|
1662
1689
|
}
|
|
1663
1690
|
// Border radius is intentionally omitted (arcsize="0%") for Outlook Classic.
|
|
@@ -1665,12 +1692,12 @@ function Button({ config, devMode }) {
|
|
|
1665
1692
|
// is inconsistent, so we render sharp corners there instead.
|
|
1666
1693
|
vmlButton = `
|
|
1667
1694
|
<!--[if mso]>
|
|
1668
|
-
<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="0%" strokecolor="${vmlStrokeColor}" ${hasVmlStroke ? `strokeweight="${vmlStrokeWeight}px"` : 'stroke="f"'} fillcolor="${vmlFillColor}">
|
|
1695
|
+
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" ${href ? `href="${href}"` : ""} style="height:${vmlHeight}px;width:${vmlWidth}px;" arcsize="0%" ${vmlStrokeColor ? `strokecolor="${vmlStrokeColor}"` : ""} ${hasVmlStroke ? `strokeweight="${vmlStrokeWeight}px"` : 'stroke="f"'} ${vmlFillColor ? `fillcolor="${vmlFillColor}"` : ""}>
|
|
1669
1696
|
<w:anchorlock/>
|
|
1670
1697
|
<v:textbox inset="${horizontalPaddingValue}px,${numericPadding}px,${horizontalPaddingValue}px,${numericPadding}px">
|
|
1671
1698
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
|
|
1672
1699
|
<tr>
|
|
1673
|
-
<td ${vmlAlignAttr} valign="middle" style="${vmlAlignStyle}color:${color}
|
|
1700
|
+
<td ${vmlAlignAttr} valign="middle" style="${vmlAlignStyle}${color ? `color:${color};` : ""}${safeFontFamily ? `font-family:${safeFontFamily};` : ""}${fontSize ? `font-size:${fontSize};` : ""}${vmlFontWeight ? `font-weight:${vmlFontWeight};` : ""}${vmlFontStyle}${vmlLetterSpacing}${vmlTextTransform}${vmlTextDecoration}${vmlWhiteSpace}${vmlDirection}${vmlOpacity}${lineHeight ? `line-height:${lineHeight};` : ""}mso-line-height-rule:exactly;">
|
|
1674
1701
|
${typeof children === "string" ? children : ""}
|
|
1675
1702
|
</td>
|
|
1676
1703
|
</tr>
|
|
@@ -1694,10 +1721,10 @@ function Button({ config, devMode }) {
|
|
|
1694
1721
|
const textTransformProp = textTransform
|
|
1695
1722
|
? `text-transform: ${textTransform};`
|
|
1696
1723
|
: "";
|
|
1697
|
-
const whiteSpaceProp = whiteSpace
|
|
1724
|
+
const whiteSpaceProp = whiteSpace ? `white-space: ${whiteSpace};` : "";
|
|
1698
1725
|
const directionProp = direction ? `direction: ${direction};` : "";
|
|
1699
1726
|
const opacityProp = opacity !== undefined ? `opacity: ${opacity};` : "";
|
|
1700
|
-
const wordBreakProp = wordBreak
|
|
1727
|
+
const wordBreakProp = wordBreak ? `word-break: ${wordBreak};` : "";
|
|
1701
1728
|
// Border radius is intentionally omitted from the Outlook Classic table cell.
|
|
1702
1729
|
// Outlook Classic ignores border-radius on table cells anyway, and including it
|
|
1703
1730
|
// can cause unexpected rendering artifacts, so we explicitly leave it out.
|
|
@@ -1705,13 +1732,17 @@ function Button({ config, devMode }) {
|
|
|
1705
1732
|
<!--[if mso]>
|
|
1706
1733
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse: collapse;">
|
|
1707
1734
|
<tr>
|
|
1708
|
-
<td align="${align}" style="padding: 0;">
|
|
1735
|
+
<td ${align ? `align="${align}"` : ""} style="padding: 0;">
|
|
1709
1736
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="${width || "auto"}" style="border-collapse: collapse;">
|
|
1710
1737
|
<tr>
|
|
1711
|
-
<td bgcolor="${backgroundColor}" align="${textAlign}" style="padding: ${padding}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1738
|
+
<td ${backgroundColor ? `bgcolor="${backgroundColor}"` : ""} ${textAlign ? `align="${textAlign}"` : ""} style="${padding ? `padding: ${padding};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${borderStyleString}">
|
|
1739
|
+
${href
|
|
1740
|
+
? `<a href="${href}" target="${target}" rel="noopener noreferrer" style="${color ? `color: ${color};` : ""} ${textDecorationStyle} display: block; ${safeFontFamily ? `font-family: ${safeFontFamily};` : ""} ${fontSize ? `font-size: ${fontSize};` : ""} ${fontWeight ? `font-weight: ${fontWeight};` : ""} ${fontStyleProp} ${lineHeight ? `line-height: ${lineHeight};` : ""} ${letterSpacingProp} ${textTransformProp} ${textAlign ? `text-align: ${textAlign};` : ""} ${whiteSpaceProp} ${directionProp} ${opacityProp} ${wordBreakProp} mso-line-height-rule: exactly;">
|
|
1741
|
+
${typeof children === "string" ? children : ""}
|
|
1742
|
+
</a>`
|
|
1743
|
+
: `<span style="${color ? `color: ${color};` : ""} ${textDecorationStyle} display: block; ${safeFontFamily ? `font-family: ${safeFontFamily};` : ""} ${fontSize ? `font-size: ${fontSize};` : ""} ${fontWeight ? `font-weight: ${fontWeight};` : ""} ${fontStyleProp} ${lineHeight ? `line-height: ${lineHeight};` : ""} ${letterSpacingProp} ${textTransformProp} ${textAlign ? `text-align: ${textAlign};` : ""} ${whiteSpaceProp} ${directionProp} ${opacityProp} ${wordBreakProp} mso-line-height-rule: exactly;">
|
|
1744
|
+
${typeof children === "string" ? children : ""}
|
|
1745
|
+
</span>`}
|
|
1715
1746
|
</td>
|
|
1716
1747
|
</tr>
|
|
1717
1748
|
</table>
|
|
@@ -1725,7 +1756,7 @@ function Button({ config, devMode }) {
|
|
|
1725
1756
|
// fontFamily uses the sanitized value so embedded quotes never break the
|
|
1726
1757
|
// style attribute string (which is always wrapped in double quotes).
|
|
1727
1758
|
const sharedTextStyles = [
|
|
1728
|
-
`color: ${color}
|
|
1759
|
+
color ? `color: ${color};` : "",
|
|
1729
1760
|
safeFontFamily ? `font-family: ${safeFontFamily};` : "",
|
|
1730
1761
|
fontSize ? `font-size: ${fontSize};` : "",
|
|
1731
1762
|
fontWeight ? `font-weight: ${fontWeight};` : "",
|
|
@@ -1738,7 +1769,7 @@ function Button({ config, devMode }) {
|
|
|
1738
1769
|
: "",
|
|
1739
1770
|
direction ? `direction: ${direction};` : "",
|
|
1740
1771
|
opacity !== undefined ? `opacity: ${opacity};` : "",
|
|
1741
|
-
whiteSpace
|
|
1772
|
+
whiteSpace ? `white-space: ${whiteSpace};` : "",
|
|
1742
1773
|
]
|
|
1743
1774
|
.filter(Boolean)
|
|
1744
1775
|
.join(" ");
|
|
@@ -1772,20 +1803,24 @@ function Button({ config, devMode }) {
|
|
|
1772
1803
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; width: 100%;">
|
|
1773
1804
|
<tbody>
|
|
1774
1805
|
<tr>
|
|
1775
|
-
<td style="background-color: ${backgroundTdStyle.backgroundColor}
|
|
1776
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: separate; border-spacing: 0; border-radius: ${borderRadius}
|
|
1806
|
+
<td style="${backgroundTdStyle.backgroundColor ? `background-color: ${backgroundTdStyle.backgroundColor};` : ""} ${backgroundTdStyle.borderRadius ? `border-radius: ${backgroundTdStyle.borderRadius};` : ""} width: ${backgroundTdStyle.width}; ${maxWidth ? `max-width: ${maxWidth};` : ""} ${borderRadius ? "overflow: hidden;" : ""}">
|
|
1807
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: separate; border-spacing: 0; ${borderRadius ? `border-radius: ${borderRadius};` : ""} width: 100%; ${borderStyleString}">
|
|
1777
1808
|
<tbody>
|
|
1778
1809
|
<tr>
|
|
1779
1810
|
<td style="padding: 0;">
|
|
1780
1811
|
${devMode
|
|
1781
|
-
? `<span style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; word-break: ${wordBreak}
|
|
1812
|
+
? `<span style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; ${wordBreak ? `word-break: ${wordBreak};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${padding ? `padding: ${padding};` : ""}">
|
|
1782
1813
|
${typeof children === "string" ? children : ""}
|
|
1783
1814
|
</span>`
|
|
1784
|
-
:
|
|
1785
|
-
|
|
1815
|
+
: href
|
|
1816
|
+
? `<a href="${href}" target="${target}" rel="noopener noreferrer" style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; ${wordBreak ? `word-break: ${wordBreak};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${padding ? `padding: ${padding};` : ""}">
|
|
1817
|
+
<span>
|
|
1818
|
+
${typeof children === "string" ? children : ""}
|
|
1819
|
+
</span>
|
|
1820
|
+
</a>`
|
|
1821
|
+
: `<span style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; ${wordBreak ? `word-break: ${wordBreak};` : ""} ${textAlign ? `text-align: ${textAlign};` : ""} ${padding ? `padding: ${padding};` : ""}">
|
|
1786
1822
|
${typeof children === "string" ? children : ""}
|
|
1787
|
-
</span
|
|
1788
|
-
</a>`}
|
|
1823
|
+
</span>`}
|
|
1789
1824
|
</td>
|
|
1790
1825
|
</tr>
|
|
1791
1826
|
</tbody>
|
|
@@ -2104,40 +2139,48 @@ var Container_default = React.memo(Container, arePropsEqual);
|
|
|
2104
2139
|
|
|
2105
2140
|
function Divider({ config, devNode }) {
|
|
2106
2141
|
const { height = "1px", color = "#cccccc", width = "100%", margin = "20px 0", align = "center", hideOnMobile, } = config;
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
//
|
|
2115
|
-
const
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
backgroundColor: color,
|
|
2119
|
-
borderCollapse: "collapse",
|
|
2120
|
-
border: "0",
|
|
2121
|
-
// ✅ FIX 1: Use string literal indexing for MSO properties
|
|
2122
|
-
// ["mso-table-lspace" as string]: "0pt",
|
|
2123
|
-
["msoTableLspace"]: "0pt",
|
|
2124
|
-
// ["mso-table-rspace" as string]: "0pt",
|
|
2125
|
-
["msoTableRspace"]: "0pt",
|
|
2126
|
-
};
|
|
2127
|
-
// Parse height for the HTML attribute
|
|
2128
|
-
const dividerHeightAttribute = parseInt(height, 10) || 1;
|
|
2129
|
-
return (jsxRuntime.jsxs("table", { "aria-label": "Divider Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2130
|
-
// --- Start dev
|
|
2131
|
-
position: "relative",
|
|
2132
|
-
// --- End dev
|
|
2142
|
+
const heightPx = parseInt(height, 10) || 1;
|
|
2143
|
+
// Parse margin into paddingTop / paddingBottom for the outer TD.
|
|
2144
|
+
// Outlook ignores shorthand "20px 0" on TDs — must be explicit.
|
|
2145
|
+
const [marginTopRaw = "0", marginRightRaw = "0", marginBottomRaw, marginLeftRaw] = margin.trim().split(/\s+/);
|
|
2146
|
+
const marginTop = marginTopRaw;
|
|
2147
|
+
const marginBottom = marginBottomRaw !== null && marginBottomRaw !== void 0 ? marginBottomRaw : marginTopRaw; // "20px 0" → top=20px, bottom=20px
|
|
2148
|
+
// Outlook requires align on the outer TD to correctly position
|
|
2149
|
+
// a fixed-width inner table (e.g. width="300px").
|
|
2150
|
+
const alignAttr = align === "left" ? "left" : align === "right" ? "right" : "center";
|
|
2151
|
+
return (jsxRuntime.jsxs("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2152
|
+
position: "relative", // dev overlay anchor
|
|
2133
2153
|
width: "100%",
|
|
2134
2154
|
borderCollapse: "collapse",
|
|
2135
|
-
|
|
2155
|
+
border: "0",
|
|
2156
|
+
}, className: hideOnMobile ? "hide-on-mobile" : undefined, children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { align: alignAttr, style: {
|
|
2157
|
+
paddingTop: marginTop,
|
|
2158
|
+
paddingBottom: marginBottom,
|
|
2159
|
+
paddingLeft: "0",
|
|
2160
|
+
paddingRight: "0",
|
|
2161
|
+
fontSize: "0",
|
|
2162
|
+
lineHeight: "0",
|
|
2163
|
+
}, children: jsxRuntime.jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, align: alignAttr, style: {
|
|
2164
|
+
width: width,
|
|
2165
|
+
borderCollapse: "collapse",
|
|
2166
|
+
border: "0",
|
|
2167
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { ...{ height: heightPx }, ref: (el) => {
|
|
2168
|
+
if (!el)
|
|
2169
|
+
return;
|
|
2170
|
+
el.setAttribute("style", `height:${height};` +
|
|
2171
|
+
`line-height:${height};` +
|
|
2172
|
+
`font-size:0;` +
|
|
2173
|
+
`padding:0;` +
|
|
2174
|
+
`background-color:${color};` +
|
|
2175
|
+
`mso-line-height-rule:exactly;`);
|
|
2176
|
+
}, style: {
|
|
2177
|
+
// Fallback for non-Outlook clients (React-rendered style object).
|
|
2136
2178
|
height: height,
|
|
2179
|
+
lineHeight: height,
|
|
2137
2180
|
fontSize: "0",
|
|
2138
|
-
lineHeight: "0",
|
|
2139
2181
|
padding: "0",
|
|
2140
|
-
|
|
2182
|
+
backgroundColor: color,
|
|
2183
|
+
} }) }) }) }) }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }));
|
|
2141
2184
|
}
|
|
2142
2185
|
var Divider_default = React.memo(Divider, arePropsEqual);
|
|
2143
2186
|
|
|
@@ -2382,6 +2425,27 @@ function Html({ children, backgroundColor = "#ffffff", }) {
|
|
|
2382
2425
|
);
|
|
2383
2426
|
}
|
|
2384
2427
|
|
|
2428
|
+
// Helper to build link href based on innerLink type
|
|
2429
|
+
function buildLinkHref$1(innerLink) {
|
|
2430
|
+
if (!innerLink || innerLink.type === "none")
|
|
2431
|
+
return null;
|
|
2432
|
+
switch (innerLink.type) {
|
|
2433
|
+
case "url":
|
|
2434
|
+
return innerLink.url || null;
|
|
2435
|
+
case "email":
|
|
2436
|
+
return innerLink.email ? `mailto:${innerLink.email}` : null;
|
|
2437
|
+
case "phone":
|
|
2438
|
+
return innerLink.phone ? `tel:${innerLink.phone}` : null;
|
|
2439
|
+
case "anchor":
|
|
2440
|
+
return innerLink.anchor ? `#${innerLink.anchor}` : null;
|
|
2441
|
+
case "page_top":
|
|
2442
|
+
return "#top";
|
|
2443
|
+
case "page_bottom":
|
|
2444
|
+
return "#bottom";
|
|
2445
|
+
default:
|
|
2446
|
+
return null;
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2385
2449
|
function getBorderStyle$3(border) {
|
|
2386
2450
|
if (!border)
|
|
2387
2451
|
return {};
|
|
@@ -2424,7 +2488,10 @@ function getBorderStyleString$1(border) {
|
|
|
2424
2488
|
}
|
|
2425
2489
|
function Image({ config, devNode, devMode }) {
|
|
2426
2490
|
var _a, _b;
|
|
2427
|
-
const { src, alt,
|
|
2491
|
+
const { src, alt, innerLink, mobile } = config;
|
|
2492
|
+
// Resolve href and target from innerLink
|
|
2493
|
+
const href = buildLinkHref$1(innerLink);
|
|
2494
|
+
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
2428
2495
|
const seed = src + (alt || "");
|
|
2429
2496
|
const instanceId = seed
|
|
2430
2497
|
.split("")
|
|
@@ -2454,32 +2521,56 @@ function Image({ config, devNode, devMode }) {
|
|
|
2454
2521
|
? parseInt(config.maxWidth, 10)
|
|
2455
2522
|
: undefined;
|
|
2456
2523
|
const imgWidthAttr = isPercent ? (maxWidthPx !== null && maxWidthPx !== void 0 ? maxWidthPx : undefined) : widthAttr;
|
|
2457
|
-
// 2. Mobile Overrides
|
|
2524
|
+
// 2. Mobile Overrides — only emit CSS properties that are explicitly set,
|
|
2525
|
+
// so unspecified properties are left untouched (no forced defaults).
|
|
2458
2526
|
let mobileCss = "";
|
|
2459
2527
|
if (mobile) {
|
|
2528
|
+
// .wrap-${imgClass} rules
|
|
2529
|
+
const wrapRules = [
|
|
2530
|
+
// Always reset min-width so the px lock from desktop can be overridden
|
|
2531
|
+
"min-width: 0 !important;",
|
|
2532
|
+
];
|
|
2533
|
+
if (mobile.width !== undefined)
|
|
2534
|
+
wrapRules.push(`width: ${mobile.width} !important;`);
|
|
2535
|
+
if (mobile.maxWidth !== undefined)
|
|
2536
|
+
wrapRules.push(`max-width: ${mobile.maxWidth} !important;`);
|
|
2537
|
+
// .td-${imgClass} rules
|
|
2538
|
+
const tdRules = [];
|
|
2539
|
+
if (mobile.padding !== undefined)
|
|
2540
|
+
tdRules.push(`padding: ${mobile.padding} !important;`);
|
|
2541
|
+
if (mobile.backgroundColor !== undefined)
|
|
2542
|
+
tdRules.push(`background-color: ${mobile.backgroundColor} !important;`);
|
|
2543
|
+
// .${imgClass} rules
|
|
2544
|
+
const imgRules = [];
|
|
2545
|
+
if (mobile.width !== undefined)
|
|
2546
|
+
imgRules.push(`width: ${mobile.width} !important;`);
|
|
2547
|
+
if (mobile.height !== undefined)
|
|
2548
|
+
imgRules.push(`height: ${mobile.height} !important;`);
|
|
2549
|
+
if (mobile.maxWidth !== undefined)
|
|
2550
|
+
imgRules.push(`max-width: ${mobile.maxWidth} !important;`);
|
|
2551
|
+
if (mobile.maxHeight !== undefined)
|
|
2552
|
+
imgRules.push(`max-height: ${mobile.maxHeight} !important;`);
|
|
2553
|
+
if (mobile.borderRadius !== undefined)
|
|
2554
|
+
imgRules.push(`border-radius: ${mobile.borderRadius} !important;`);
|
|
2555
|
+
if (mobile.hidden !== undefined)
|
|
2556
|
+
imgRules.push(`display: ${mobile.hidden ? "none" : "block"} !important;`);
|
|
2557
|
+
if (mobile.objectFit !== undefined)
|
|
2558
|
+
imgRules.push(`object-fit: ${mobile.objectFit} !important;`);
|
|
2559
|
+
if (mobile.objectPosition !== undefined)
|
|
2560
|
+
imgRules.push(`object-position: ${mobile.objectPosition} !important;`);
|
|
2561
|
+
if (mobile.border !== undefined)
|
|
2562
|
+
imgRules.push(getBorderStyleString$1(mobile.border));
|
|
2460
2563
|
mobileCss = `
|
|
2461
2564
|
@media screen and (max-width: 768px) {
|
|
2462
2565
|
.wrap-${imgClass} {
|
|
2463
2566
|
/* This breaks the px lock from desktop and makes it fluid */
|
|
2464
|
-
|
|
2465
|
-
max-width: ${mobile.maxWidth || "100%"} !important;
|
|
2466
|
-
min-width: 0 !important;
|
|
2567
|
+
${wrapRules.join("\n ")}
|
|
2467
2568
|
}
|
|
2468
2569
|
.td-${imgClass} {
|
|
2469
|
-
|
|
2470
|
-
background-color: ${mobile.backgroundColor || "transparent"} !important;
|
|
2471
|
-
width: 100% !important;
|
|
2570
|
+
${tdRules.join("\n ")}
|
|
2472
2571
|
}
|
|
2473
2572
|
.${imgClass} {
|
|
2474
|
-
|
|
2475
|
-
height: ${mobile.height || "auto"} !important;
|
|
2476
|
-
max-width: ${mobile.maxWidth || "100%"} !important;
|
|
2477
|
-
max-height: ${mobile.maxHeight || "none"} !important;
|
|
2478
|
-
border-radius: ${mobile.borderRadius || "0"} !important;
|
|
2479
|
-
display: ${mobile.hidden ? "none" : "block"} !important;
|
|
2480
|
-
object-fit: ${mobile.objectFit || "fill"} !important;
|
|
2481
|
-
object-position: ${mobile.objectPosition || "center"} !important;
|
|
2482
|
-
${getBorderStyleString$1(mobile.border)}
|
|
2573
|
+
${imgRules.join("\n ")}
|
|
2483
2574
|
}
|
|
2484
2575
|
}
|
|
2485
2576
|
`;
|
|
@@ -2497,7 +2588,7 @@ function Image({ config, devNode, devMode }) {
|
|
|
2497
2588
|
objectFit: config.objectFit,
|
|
2498
2589
|
objectPosition: config.objectPosition,
|
|
2499
2590
|
};
|
|
2500
|
-
const imageElement = (jsxRuntime.jsx("img", { src: src, alt: alt, width: imgWidthAttr, height: heightAttr !== "auto" ? heightAttr : undefined, className: imgClass, style: imgStyle }));
|
|
2591
|
+
const imageElement = (jsxRuntime.jsx("img", { src: src, alt: alt, width: imgWidthAttr, height: heightAttr !== "auto" ? heightAttr : undefined, className: imgClass, style: imgStyle, draggable: !devMode }));
|
|
2501
2592
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [mobile && jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: mobileCss } }), jsxRuntime.jsxs("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, className: `wrap-${imgClass}`, align: "center" // Ensures a 300px image stays centered in its parent
|
|
2502
2593
|
, style: {
|
|
2503
2594
|
width: tableWidth, // Fixed px here prevents the 100% "ghost space"
|
|
@@ -2510,7 +2601,9 @@ function Image({ config, devNode, devMode }) {
|
|
|
2510
2601
|
fontSize: "0",
|
|
2511
2602
|
lineHeight: "0",
|
|
2512
2603
|
width: tableWidth, // Lock the cell as well
|
|
2513
|
-
}, children: href && !devMode ? (jsxRuntime.jsx("a", { href: href, target: target,
|
|
2604
|
+
}, children: href && !devMode ? (jsxRuntime.jsx("a", { href: href, target: target, ...(target === "_blank"
|
|
2605
|
+
? { rel: "noopener noreferrer" }
|
|
2606
|
+
: {}), style: { display: "block", width: "100%" }, children: imageElement })) : (imageElement) }) }) }), devMode && !!devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] })] }));
|
|
2514
2607
|
}
|
|
2515
2608
|
var Image_default = React.memo(Image, arePropsEqual);
|
|
2516
2609
|
|
|
@@ -2584,7 +2677,7 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2584
2677
|
const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
|
|
2585
2678
|
const numChildren = childrenArray.length;
|
|
2586
2679
|
const href = getHrefFromInnerLink(config.innerLink);
|
|
2587
|
-
const target = (_a = config.innerLink) === null || _a === void 0 ? void 0 : _a.target;
|
|
2680
|
+
const target = ((_a = config.innerLink) === null || _a === void 0 ? void 0 : _a.target) || "_blank";
|
|
2588
2681
|
// 1. Outer TD: Background, Border Radius, Width, Height.
|
|
2589
2682
|
const backgroundTdStyle = {
|
|
2590
2683
|
backgroundColor: config.backgroundColor,
|
|
@@ -2659,7 +2752,7 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2659
2752
|
}, className: "child-cell", children: child }), index < numChildren - 1 &&
|
|
2660
2753
|
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 }) }) }))] }));
|
|
2661
2754
|
if (href && !devMode) {
|
|
2662
|
-
return (jsxRuntime.jsx("a", { href: href, ...(
|
|
2755
|
+
return (jsxRuntime.jsx("a", { href: href, ...({ target }), style: {
|
|
2663
2756
|
textDecoration: "none",
|
|
2664
2757
|
color: "inherit",
|
|
2665
2758
|
display: "block",
|
|
@@ -2905,7 +2998,7 @@ function buildIconifyUrl(config) {
|
|
|
2905
2998
|
const template = process.env.ICONIFY_API_IMAGE_URI ||
|
|
2906
2999
|
"https://iconify.pagenflow.com/api/image/{{height}}/{{color}}/{{rotate}}-{{rotate-orientation}}/{{icon-full-name}}.png";
|
|
2907
3000
|
return template
|
|
2908
|
-
.replace("{{height}}", String(numericHeight *
|
|
3001
|
+
.replace("{{height}}", String(numericHeight * 4))
|
|
2909
3002
|
.replace("{{color}}", cleanColor)
|
|
2910
3003
|
.replace("{{rotate}}", String(rotate))
|
|
2911
3004
|
.replace("{{rotate-orientation}}", rotateOrientation)
|
|
@@ -2939,7 +3032,7 @@ function Icon({ config, devNode, devMode, children }) {
|
|
|
2939
3032
|
// Determine icon source
|
|
2940
3033
|
const iconSrc = buildIconifyUrl(config);
|
|
2941
3034
|
const href = buildLinkHref(innerLink);
|
|
2942
|
-
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "
|
|
3035
|
+
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
2943
3036
|
const align = justifyMap[justifyContent];
|
|
2944
3037
|
// Get border styles
|
|
2945
3038
|
const borderStyle = getBorderStyle(border);
|