@pagenflow/email 1.4.7 → 1.4.9
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 -1
- package/dist/components/Column.d.ts +3 -1
- package/dist/components/Container.d.ts +4 -2
- package/dist/components/Divider.d.ts +3 -1
- package/dist/components/Heading.d.ts +6 -1
- package/dist/components/Icon.d.ts +4 -2
- package/dist/components/Image.d.ts +25 -2
- package/dist/components/Row.d.ts +20 -1
- package/dist/components/Section.d.ts +2 -0
- package/dist/components/Spacer.d.ts +6 -1
- package/dist/components/Text.d.ts +6 -1
- package/dist/components/utils/bindingAttribute.d.ts +38 -0
- package/dist/components/utils/injectParagraphReset.d.ts +1 -0
- package/dist/components/utils/isGapZero.d.ts +1 -0
- package/dist/components/utils/linearizeStyle.d.ts +10 -0
- package/dist/index.cjs.js +346 -138
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +346 -138
- package/dist/index.esm.js.map +1 -1
- package/dist/types/DataBindings.d.ts +87 -0
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1533,6 +1533,57 @@ function arePropsEqual(prevProps, nextProps) {
|
|
|
1533
1533
|
return isEqual(prevProps, nextProps);
|
|
1534
1534
|
}
|
|
1535
1535
|
|
|
1536
|
+
/**
|
|
1537
|
+
* bindingAttribute.ts
|
|
1538
|
+
* -------------------
|
|
1539
|
+
* Serialises DataBindings into discrete HTML attributes:
|
|
1540
|
+
*
|
|
1541
|
+
* data-bind-if → visible condition → stamped on the root element
|
|
1542
|
+
* data-bind-list → repeater (dataList + itemAlias) → stamped on the
|
|
1543
|
+
* direct parent of the children loop, NOT the root
|
|
1544
|
+
* data-bind → propertyMap → stamped on the root element
|
|
1545
|
+
*
|
|
1546
|
+
* Keeping the three concerns in separate attributes lets the post-processor
|
|
1547
|
+
* handle them independently without ambiguity.
|
|
1548
|
+
*/
|
|
1549
|
+
// ─── Root element props (visible + propertyMap) ───────────────────────────────
|
|
1550
|
+
/**
|
|
1551
|
+
* Props to spread onto the component's root element.
|
|
1552
|
+
* Carries `data-bind-if` and/or `data-bind` (propertyMap).
|
|
1553
|
+
*/
|
|
1554
|
+
function rootBindingProps(bindings) {
|
|
1555
|
+
if (!bindings)
|
|
1556
|
+
return {};
|
|
1557
|
+
const props = {};
|
|
1558
|
+
if (bindings.visible) {
|
|
1559
|
+
props['data-bind-if'] = bindings.visible;
|
|
1560
|
+
}
|
|
1561
|
+
if (bindings.propertyMap && Object.keys(bindings.propertyMap).length) {
|
|
1562
|
+
props['data-bind'] = JSON.stringify({ propertyMap: bindings.propertyMap });
|
|
1563
|
+
}
|
|
1564
|
+
return props;
|
|
1565
|
+
}
|
|
1566
|
+
// ─── List wrapper props (dataList + itemAlias) ────────────────────────────────
|
|
1567
|
+
/**
|
|
1568
|
+
* Props to spread onto the *direct parent* of the children loop.
|
|
1569
|
+
* Carries `data-bind-list` only when a repeater is defined.
|
|
1570
|
+
*
|
|
1571
|
+
* Usage inside a component:
|
|
1572
|
+
* <tbody {...listBindingProps(bindings)}>
|
|
1573
|
+
* {children}
|
|
1574
|
+
* </tbody>
|
|
1575
|
+
*/
|
|
1576
|
+
function listBindingProps(bindings) {
|
|
1577
|
+
if (!(bindings === null || bindings === void 0 ? void 0 : bindings.dataList))
|
|
1578
|
+
return {};
|
|
1579
|
+
return {
|
|
1580
|
+
'data-bind-list': JSON.stringify({
|
|
1581
|
+
dataList: bindings.dataList,
|
|
1582
|
+
...(bindings.itemAlias && { itemAlias: bindings.itemAlias }),
|
|
1583
|
+
}),
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1536
1587
|
// Map alignment to HTML 'align' attribute
|
|
1537
1588
|
const justifyMap$3 = {
|
|
1538
1589
|
start: "left",
|
|
@@ -1540,7 +1591,7 @@ const justifyMap$3 = {
|
|
|
1540
1591
|
end: "right",
|
|
1541
1592
|
};
|
|
1542
1593
|
// Helper to build link href based on innerLink type (mirrors Icon component)
|
|
1543
|
-
function buildLinkHref$
|
|
1594
|
+
function buildLinkHref$4(innerLink) {
|
|
1544
1595
|
if (!innerLink || innerLink.type === "none")
|
|
1545
1596
|
return null;
|
|
1546
1597
|
switch (innerLink.type) {
|
|
@@ -1594,10 +1645,10 @@ function getBorderStyleString$2(border) {
|
|
|
1594
1645
|
}
|
|
1595
1646
|
return styles.join(" ");
|
|
1596
1647
|
}
|
|
1597
|
-
function Button({ config, devMode }) {
|
|
1648
|
+
function Button({ config, devMode, bindings }) {
|
|
1598
1649
|
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
1650
|
// Resolve href from innerLink
|
|
1600
|
-
const href = buildLinkHref$
|
|
1651
|
+
const href = buildLinkHref$4(innerLink);
|
|
1601
1652
|
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
1602
1653
|
// Sanitize fontFamily early so safeFontFamily is available for all paths below.
|
|
1603
1654
|
const safeFontFamily = fontFamily
|
|
@@ -1681,7 +1732,7 @@ function Button({ config, devMode }) {
|
|
|
1681
1732
|
.join(" ");
|
|
1682
1733
|
return (
|
|
1683
1734
|
// Wrapper table for alignment - maintains proper positioning for hover indicators
|
|
1684
|
-
jsxRuntime.jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
1735
|
+
jsxRuntime.jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
1685
1736
|
width: "100%",
|
|
1686
1737
|
borderCollapse: "collapse",
|
|
1687
1738
|
boxSizing: "border-box",
|
|
@@ -1741,6 +1792,15 @@ function Button({ config, devMode }) {
|
|
|
1741
1792
|
}
|
|
1742
1793
|
var Button_default = React.memo(Button, arePropsEqual);
|
|
1743
1794
|
|
|
1795
|
+
function isGapZero(gap) {
|
|
1796
|
+
if (!gap)
|
|
1797
|
+
return true;
|
|
1798
|
+
// Remove whitespace and convert to lowercase
|
|
1799
|
+
const trimmedGap = gap.trim().toLowerCase();
|
|
1800
|
+
// Check for exact zero matches (0, 0px, 0%, 0em, 0rem, etc.)
|
|
1801
|
+
return /^0(px|%|em|rem|ex|ch|vw|vh|vmin|vmax)?$/.test(trimmedGap);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1744
1804
|
// Helper for vertical alignment
|
|
1745
1805
|
const vAlignMap = {
|
|
1746
1806
|
start: "top",
|
|
@@ -1789,7 +1849,7 @@ function getBorderStyle$5(border) {
|
|
|
1789
1849
|
}
|
|
1790
1850
|
return style;
|
|
1791
1851
|
}
|
|
1792
|
-
function Column({ children, config, devNode }) {
|
|
1852
|
+
function Column({ children, config, devNode, bindings }) {
|
|
1793
1853
|
var _a, _b, _c;
|
|
1794
1854
|
// Process children array for gap support
|
|
1795
1855
|
const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
|
|
@@ -1841,6 +1901,7 @@ function Column({ children, config, devNode }) {
|
|
|
1841
1901
|
// treat it as content-box height and add padding on top, causing the
|
|
1842
1902
|
// total to exceed the declared height in preview mode.
|
|
1843
1903
|
verticalAlign: config.alignItems ? alignMap$2[config.alignItems] : "top",
|
|
1904
|
+
background: "transparent",
|
|
1844
1905
|
};
|
|
1845
1906
|
// 4. Gap spacer style (used between children)
|
|
1846
1907
|
const gapSpacerStyle = {
|
|
@@ -1848,6 +1909,7 @@ function Column({ children, config, devNode }) {
|
|
|
1848
1909
|
lineHeight: "1px",
|
|
1849
1910
|
fontSize: "1px",
|
|
1850
1911
|
width: "100%",
|
|
1912
|
+
background: "transparent",
|
|
1851
1913
|
};
|
|
1852
1914
|
// 5. maxWidth constraining table style (modern clients).
|
|
1853
1915
|
// The `width` HTML attribute on this table is what Outlook Classic
|
|
@@ -1862,10 +1924,10 @@ function Column({ children, config, devNode }) {
|
|
|
1862
1924
|
borderCollapse: "collapse",
|
|
1863
1925
|
};
|
|
1864
1926
|
// Main content rendering
|
|
1865
|
-
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",
|
|
1927
|
+
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", ...(numChildren > 1 ? {} : listBindingProps(bindings)), children: numChildren > 1 ? (jsxRuntime.jsx("table", { "aria-label": "Column Gap Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
1866
1928
|
width: "100%",
|
|
1867
1929
|
borderCollapse: "collapse",
|
|
1868
|
-
}, children: jsxRuntime.jsx("tbody", { children: childrenArray.map((child, index) => (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: {
|
|
1930
|
+
}, children: jsxRuntime.jsx("tbody", { ...listBindingProps(bindings), children: childrenArray.map((child, index) => (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: {
|
|
1869
1931
|
verticalAlign: config.alignItems
|
|
1870
1932
|
? alignMap$2[config.alignItems]
|
|
1871
1933
|
: "top",
|
|
@@ -1873,8 +1935,8 @@ function Column({ children, config, devNode }) {
|
|
|
1873
1935
|
? vAlignMap[config.justifyContent]
|
|
1874
1936
|
: "top", align: config.alignItems
|
|
1875
1937
|
? alignMap$2[config.alignItems]
|
|
1876
|
-
: "left", children: child }) }), index < numChildren - 1 && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: gapSpacerStyle, children: "\u00A0" }) }))] }, `col-child-${index}`))) }) })) : (children) }) }) }) }));
|
|
1877
|
-
return (jsxRuntime.jsxs("table", { "aria-label": "Column Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
1938
|
+
: "left", children: child }) }), index < numChildren - 1 && !isGapZero(config.gap) && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: gapSpacerStyle, children: "\u00A0" }) }))] }, `col-child-${index}`))) }) })) : (children) }) }) }) }));
|
|
1939
|
+
return (jsxRuntime.jsxs("table", { "aria-label": "Column Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
1878
1940
|
position: "relative",
|
|
1879
1941
|
...outerTableStyle,
|
|
1880
1942
|
}, ...(config.height && { height: config.height }), children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: outerTdStyle, ...(config.width && { width: config.width }), ...(config.height && { height: config.height }), children: config.maxWidth ? (
|
|
@@ -1943,7 +2005,7 @@ function getBorderStyle$4(border) {
|
|
|
1943
2005
|
}
|
|
1944
2006
|
return style;
|
|
1945
2007
|
}
|
|
1946
|
-
function Container({ children, config, devMode, devNode }) {
|
|
2008
|
+
function Container({ children, config, bindings, devMode, devNode, }) {
|
|
1947
2009
|
var _a, _b, _c;
|
|
1948
2010
|
const { widthType, childrenConstraints } = config;
|
|
1949
2011
|
const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
|
|
@@ -1961,7 +2023,7 @@ function Container({ children, config, devMode, devNode }) {
|
|
|
1961
2023
|
return 0;
|
|
1962
2024
|
})();
|
|
1963
2025
|
const getChildWidths = (() => {
|
|
1964
|
-
const { widthDistributionType } = childrenConstraints;
|
|
2026
|
+
const { widthDistributionType } = childrenConstraints !== null && childrenConstraints !== void 0 ? childrenConstraints : {};
|
|
1965
2027
|
const totalGapSpace = gapWidthPx * (numChildren > 1 ? numChildren - 1 : 0);
|
|
1966
2028
|
const remainingContentSpace = containerWidthPx - totalGapSpace;
|
|
1967
2029
|
switch (widthDistributionType) {
|
|
@@ -2035,6 +2097,7 @@ function Container({ children, config, devMode, devNode }) {
|
|
|
2035
2097
|
width: config.gap || "0",
|
|
2036
2098
|
lineHeight: "1px",
|
|
2037
2099
|
fontSize: "1px",
|
|
2100
|
+
background: "transparent",
|
|
2038
2101
|
};
|
|
2039
2102
|
const justifyAlign = config.justifyContent
|
|
2040
2103
|
? justifyMap$2[config.justifyContent]
|
|
@@ -2050,19 +2113,20 @@ function Container({ children, config, devMode, devNode }) {
|
|
|
2050
2113
|
textAlign: "left",
|
|
2051
2114
|
};
|
|
2052
2115
|
if (config.gap && index < numChildren - 1) {
|
|
2053
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("td", { className: isStacking ? "stack-td" : undefined, width: getChildWidths[index], style: childTdStyle, children: [child, isStacking && (jsxRuntime.jsx("div", { className: "mobile-gap-spacer", style: {
|
|
2116
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("td", { className: isStacking ? "stack-td" : undefined, width: getChildWidths[index], style: childTdStyle, children: [child, isStacking && !isGapZero(config.gap) && (jsxRuntime.jsx("div", { className: "mobile-gap-spacer", style: {
|
|
2054
2117
|
display: "none",
|
|
2055
2118
|
fontSize: "0",
|
|
2056
2119
|
lineHeight: "0",
|
|
2057
2120
|
height: config.gap,
|
|
2058
|
-
|
|
2121
|
+
background: "transparent",
|
|
2122
|
+
}, children: "\u00A0" }))] }, `child-${index}`), !isGapZero(config.gap) && (jsxRuntime.jsx("td", { className: isStacking ? "desktop-gap-column" : undefined, width: config.gap, style: gapTdStyle, children: "\u00A0" }, `gap-${index}`))] }, `ctn:${index}`));
|
|
2059
2123
|
}
|
|
2060
2124
|
return (jsxRuntime.jsx("td", { className: isStacking ? "stack-td" : undefined, width: getChildWidths[index], style: childTdStyle, children: child }, `child-${index}`));
|
|
2061
2125
|
});
|
|
2062
2126
|
return (jsxRuntime.jsx("table", { "aria-label": `Container | Table Outer`, cellPadding: 0, cellSpacing: 0, role: "presentation", border: 0, style: {
|
|
2063
2127
|
position: "relative",
|
|
2064
2128
|
...outerTableStyle,
|
|
2065
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsxs("td", { align: justifyAlign, children: [jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: msoFixedWrapper } }), jsxRuntime.jsxs("table", { className: [
|
|
2129
|
+
}, ...rootBindingProps(bindings), children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsxs("td", { align: justifyAlign, children: [jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: msoFixedWrapper } }), jsxRuntime.jsxs("table", { className: [
|
|
2066
2130
|
widthType === "fixed" ? "container-fixed-width" : undefined,
|
|
2067
2131
|
devMode ? "main-wrapper relative" : undefined,
|
|
2068
2132
|
]
|
|
@@ -2071,22 +2135,22 @@ function Container({ children, config, devMode, devNode }) {
|
|
|
2071
2135
|
width: "100%",
|
|
2072
2136
|
maxWidth: widthType === "fixed" ? config.width || "600px" : undefined,
|
|
2073
2137
|
borderCollapse: "collapse",
|
|
2074
|
-
}, width: containerWidthAttr, children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: backgroundTdStyle, children: jsxRuntime.jsx("table", { "aria-label": `Container | Border Wrapper`, cellPadding: 0, cellSpacing: 0, role: "presentation", border: 0, style: borderTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: innerTdStyle, children: jsxRuntime.jsx("table", { "aria-label": `Container | Content Table`, cellPadding: 0, cellSpacing: 0, role: "presentation", border: 0, style: contentTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: rowElements }) }) }) }) }) }) }) }) }) }), !!devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }), jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: msoFixedFooter } })] }) }) }) }));
|
|
2138
|
+
}, width: containerWidthAttr, children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: backgroundTdStyle, children: jsxRuntime.jsx("table", { "aria-label": `Container | Border Wrapper`, cellPadding: 0, cellSpacing: 0, role: "presentation", border: 0, style: borderTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: innerTdStyle, children: jsxRuntime.jsx("table", { "aria-label": `Container | Content Table`, cellPadding: 0, cellSpacing: 0, role: "presentation", border: 0, style: contentTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { ...listBindingProps(bindings), children: rowElements }) }) }) }) }) }) }) }) }) }), !!devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }), jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: msoFixedFooter } })] }) }) }) }));
|
|
2075
2139
|
}
|
|
2076
2140
|
var Container_default = React.memo(Container, arePropsEqual);
|
|
2077
2141
|
|
|
2078
|
-
function Divider({ config, devNode }) {
|
|
2142
|
+
function Divider({ config, devNode, bindings }) {
|
|
2079
2143
|
const { height = "1px", color = "#cccccc", width = "100%", margin = "20px 0", align = "center", hideOnMobile, } = config;
|
|
2080
2144
|
const heightPx = parseInt(height, 10) || 1;
|
|
2081
2145
|
// Parse margin into paddingTop / paddingBottom for the outer TD.
|
|
2082
2146
|
// Outlook ignores shorthand "20px 0" on TDs — must be explicit.
|
|
2083
|
-
const [marginTopRaw = "0", marginRightRaw = "0", marginBottomRaw, marginLeftRaw] = margin.trim().split(/\s+/);
|
|
2147
|
+
const [marginTopRaw = "0", marginRightRaw = "0", marginBottomRaw, marginLeftRaw,] = margin.trim().split(/\s+/);
|
|
2084
2148
|
const marginTop = marginTopRaw;
|
|
2085
2149
|
const marginBottom = marginBottomRaw !== null && marginBottomRaw !== void 0 ? marginBottomRaw : marginTopRaw; // "20px 0" → top=20px, bottom=20px
|
|
2086
2150
|
// Outlook requires align on the outer TD to correctly position
|
|
2087
2151
|
// a fixed-width inner table (e.g. width="300px").
|
|
2088
2152
|
const alignAttr = align === "left" ? "left" : align === "right" ? "right" : "center";
|
|
2089
|
-
return (jsxRuntime.jsxs("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2153
|
+
return (jsxRuntime.jsxs("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
2090
2154
|
position: "relative", // dev overlay anchor
|
|
2091
2155
|
width: "100%",
|
|
2092
2156
|
borderCollapse: "collapse",
|
|
@@ -2183,7 +2247,13 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
|
|
|
2183
2247
|
line-height: inherit !important;
|
|
2184
2248
|
}
|
|
2185
2249
|
body { background-color: ${backgroundColor} !important; }
|
|
2186
|
-
p {
|
|
2250
|
+
p {
|
|
2251
|
+
margin: 0;
|
|
2252
|
+
margin-block-start: 0px;
|
|
2253
|
+
margin-block-end: 0px;
|
|
2254
|
+
margin-inline-start: 0px;
|
|
2255
|
+
margin-inline-end: 0px;
|
|
2256
|
+
}
|
|
2187
2257
|
`;
|
|
2188
2258
|
const globalStyles = `
|
|
2189
2259
|
@media screen and (max-width: 768px) {
|
|
@@ -2405,8 +2475,56 @@ function injectLinkStyles(html, fallback) {
|
|
|
2405
2475
|
return result;
|
|
2406
2476
|
}
|
|
2407
2477
|
|
|
2408
|
-
|
|
2409
|
-
|
|
2478
|
+
// injectParagraphReset.ts
|
|
2479
|
+
const P_RESET_STYLE = [
|
|
2480
|
+
"margin:0",
|
|
2481
|
+
"margin-block-start:0px",
|
|
2482
|
+
"margin-block-end:0px",
|
|
2483
|
+
"margin-inline-start:0px",
|
|
2484
|
+
"margin-inline-end:0px",
|
|
2485
|
+
].join(";");
|
|
2486
|
+
function injectParagraphReset(html) {
|
|
2487
|
+
if (!html || !html.includes("<p"))
|
|
2488
|
+
return html;
|
|
2489
|
+
return html.replace(/<p(\s[^>]*)?>/gi, (_, attrs = "") => {
|
|
2490
|
+
var _a, _b;
|
|
2491
|
+
const existingStyle = (_b = (_a = /style\s*=\s*"([^"]*)"/i.exec(attrs)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : "";
|
|
2492
|
+
const mergedStyle = existingStyle
|
|
2493
|
+
? `${existingStyle};${P_RESET_STYLE}`
|
|
2494
|
+
: P_RESET_STYLE;
|
|
2495
|
+
const cleanAttrs = attrs.replace(/\s*style\s*=\s*"[^"]*"/i, "").trim();
|
|
2496
|
+
return cleanAttrs
|
|
2497
|
+
? `<p ${cleanAttrs} style="${mergedStyle}">`
|
|
2498
|
+
: `<p style="${mergedStyle}">`;
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
// Helper to build link href based on innerLink type
|
|
2503
|
+
function buildLinkHref$3(innerLink) {
|
|
2504
|
+
if (!innerLink || innerLink.type === "none")
|
|
2505
|
+
return null;
|
|
2506
|
+
switch (innerLink.type) {
|
|
2507
|
+
case "url":
|
|
2508
|
+
return innerLink.url || null;
|
|
2509
|
+
case "email":
|
|
2510
|
+
return innerLink.email ? `mailto:${innerLink.email}` : null;
|
|
2511
|
+
case "phone":
|
|
2512
|
+
return innerLink.phone ? `tel:${innerLink.phone}` : null;
|
|
2513
|
+
case "anchor":
|
|
2514
|
+
return innerLink.anchor ? `#${innerLink.anchor}` : null;
|
|
2515
|
+
case "page_top":
|
|
2516
|
+
return "#top";
|
|
2517
|
+
case "page_bottom":
|
|
2518
|
+
return "#bottom";
|
|
2519
|
+
default:
|
|
2520
|
+
return null;
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
function Heading({ config, devMode, children, bindings }) {
|
|
2524
|
+
const { text, level = "h1", padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, wordBreak, whiteSpace, innerLink, } = config;
|
|
2525
|
+
// Resolve href and target from innerLink
|
|
2526
|
+
const href = buildLinkHref$3(innerLink);
|
|
2527
|
+
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
2410
2528
|
// Determine the content to render
|
|
2411
2529
|
const content = text !== null && text !== void 0 ? text : children;
|
|
2412
2530
|
const isString = typeof content === "string";
|
|
@@ -2439,16 +2557,21 @@ function Heading({ config, devMode, children }) {
|
|
|
2439
2557
|
["msoLineHeightRule"]: "exactly",
|
|
2440
2558
|
};
|
|
2441
2559
|
const processedHtml = isString
|
|
2442
|
-
? injectLinkStyles(content, headingStyle)
|
|
2560
|
+
? injectParagraphReset(injectLinkStyles(content, headingStyle))
|
|
2443
2561
|
: "";
|
|
2444
2562
|
// Dynamically create the Heading element
|
|
2445
2563
|
const HeadingTag = level;
|
|
2564
|
+
const headingElement = isString ? (jsxRuntime.jsx(HeadingTag, { style: headingStyle, dangerouslySetInnerHTML: { __html: processedHtml } })) : (jsxRuntime.jsx(HeadingTag, { style: headingStyle, children: content }));
|
|
2446
2565
|
return (
|
|
2447
2566
|
// Wrap the heading content in a table for padding/width/background management.
|
|
2448
|
-
jsxRuntime.jsx("table", { "aria-label": "Heading Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2567
|
+
jsxRuntime.jsx("table", { "aria-label": "Heading Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
2449
2568
|
width: "100%",
|
|
2450
2569
|
borderCollapse: "collapse",
|
|
2451
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children:
|
|
2570
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: href && !devMode ? (jsxRuntime.jsx("a", { href: href, target: target, ...(target === "_blank" ? { rel: "noopener noreferrer" } : {}), style: {
|
|
2571
|
+
display: "block",
|
|
2572
|
+
textDecoration: "none",
|
|
2573
|
+
color: "inherit",
|
|
2574
|
+
}, children: headingElement })) : (headingElement) }) }) }) }));
|
|
2452
2575
|
}
|
|
2453
2576
|
var Heading_default = React.memo(Heading, arePropsEqual);
|
|
2454
2577
|
|
|
@@ -2473,7 +2596,7 @@ function Html({ children, backgroundColor = "#ffffff", }) {
|
|
|
2473
2596
|
}
|
|
2474
2597
|
|
|
2475
2598
|
// Helper to build link href based on innerLink type
|
|
2476
|
-
function buildLinkHref$
|
|
2599
|
+
function buildLinkHref$2(innerLink) {
|
|
2477
2600
|
if (!innerLink || innerLink.type === "none")
|
|
2478
2601
|
return null;
|
|
2479
2602
|
switch (innerLink.type) {
|
|
@@ -2533,11 +2656,15 @@ function getBorderStyleString$1(border) {
|
|
|
2533
2656
|
styles.push(`border-left:${border.left.width} ${border.left.style} ${border.left.color} !important;`);
|
|
2534
2657
|
return styles.join(" ");
|
|
2535
2658
|
}
|
|
2536
|
-
function Image({ config, devNode, devMode }) {
|
|
2659
|
+
function Image({ config, devNode, devMode, bindings }) {
|
|
2537
2660
|
var _a, _b;
|
|
2538
|
-
const { src, alt, innerLink, mobile } = config;
|
|
2661
|
+
const { src: originalSrc, alt, innerLink, mobile } = config;
|
|
2662
|
+
// In dev mode, if there's no src, use the placeholder
|
|
2663
|
+
const src = devMode && !originalSrc
|
|
2664
|
+
? "https://placehold.co/300x200?text=select+an+image&font=poppins"
|
|
2665
|
+
: originalSrc;
|
|
2539
2666
|
// Resolve href and target from innerLink
|
|
2540
|
-
const href = buildLinkHref$
|
|
2667
|
+
const href = buildLinkHref$2(innerLink);
|
|
2541
2668
|
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
2542
2669
|
const seed = src + (alt || "");
|
|
2543
2670
|
const instanceId = seed
|
|
@@ -2551,43 +2678,37 @@ function Image({ config, devNode, devMode }) {
|
|
|
2551
2678
|
const widthAttr = desktopWidth.replace("px", "");
|
|
2552
2679
|
const heightAttr = (_a = config.height) === null || _a === void 0 ? void 0 : _a.replace("px", "");
|
|
2553
2680
|
// Determine the table's "initial" width.
|
|
2554
|
-
// If it's 300px, the table should be 300px, not 100%.
|
|
2555
2681
|
const tableWidth = isPercent ? desktopWidth : `${widthAttr}px`;
|
|
2556
|
-
//
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2682
|
+
// Calculate width attribute for Outlook
|
|
2683
|
+
let imgWidthAttr;
|
|
2684
|
+
if (config.outlookWidth) {
|
|
2685
|
+
// Use explicit outlookWidth if provided
|
|
2686
|
+
imgWidthAttr = parseInt(config.outlookWidth, 10);
|
|
2687
|
+
}
|
|
2688
|
+
else if (isPercent) {
|
|
2689
|
+
// For percentage widths, use maxWidth as fallback for Outlook
|
|
2690
|
+
const maxWidthPx = ((_b = config.maxWidth) === null || _b === void 0 ? void 0 : _b.endsWith("px"))
|
|
2691
|
+
? parseInt(config.maxWidth, 10)
|
|
2692
|
+
: undefined;
|
|
2693
|
+
imgWidthAttr = maxWidthPx !== null && maxWidthPx !== void 0 ? maxWidthPx : undefined;
|
|
2694
|
+
}
|
|
2695
|
+
else {
|
|
2696
|
+
// For fixed pixel widths, use that value
|
|
2697
|
+
imgWidthAttr = widthAttr ? parseInt(widthAttr, 10) : undefined;
|
|
2698
|
+
}
|
|
2699
|
+
// 2. Mobile Overrides
|
|
2573
2700
|
let mobileCss = "";
|
|
2574
2701
|
if (mobile) {
|
|
2575
|
-
|
|
2576
|
-
const wrapRules = [
|
|
2577
|
-
// Always reset min-width so the px lock from desktop can be overridden
|
|
2578
|
-
"min-width: 0 !important;",
|
|
2579
|
-
];
|
|
2702
|
+
const wrapRules = ["min-width: 0 !important;"];
|
|
2580
2703
|
if (mobile.width !== undefined)
|
|
2581
2704
|
wrapRules.push(`width: ${mobile.width} !important;`);
|
|
2582
2705
|
if (mobile.maxWidth !== undefined)
|
|
2583
2706
|
wrapRules.push(`max-width: ${mobile.maxWidth} !important;`);
|
|
2584
|
-
// .td-${imgClass} rules
|
|
2585
2707
|
const tdRules = [];
|
|
2586
2708
|
if (mobile.padding !== undefined)
|
|
2587
2709
|
tdRules.push(`padding: ${mobile.padding} !important;`);
|
|
2588
2710
|
if (mobile.backgroundColor !== undefined)
|
|
2589
2711
|
tdRules.push(`background-color: ${mobile.backgroundColor} !important;`);
|
|
2590
|
-
// .${imgClass} rules
|
|
2591
2712
|
const imgRules = [];
|
|
2592
2713
|
if (mobile.width !== undefined)
|
|
2593
2714
|
imgRules.push(`width: ${mobile.width} !important;`);
|
|
@@ -2610,7 +2731,6 @@ function Image({ config, devNode, devMode }) {
|
|
|
2610
2731
|
mobileCss = `
|
|
2611
2732
|
@media screen and (max-width: 768px) {
|
|
2612
2733
|
.wrap-${imgClass} {
|
|
2613
|
-
/* This breaks the px lock from desktop and makes it fluid */
|
|
2614
2734
|
${wrapRules.join("\n ")}
|
|
2615
2735
|
}
|
|
2616
2736
|
.td-${imgClass} {
|
|
@@ -2636,9 +2756,27 @@ function Image({ config, devNode, devMode }) {
|
|
|
2636
2756
|
objectPosition: config.objectPosition,
|
|
2637
2757
|
};
|
|
2638
2758
|
const imageElement = (jsxRuntime.jsx("img", { src: src, alt: alt, width: imgWidthAttr, height: heightAttr !== "auto" ? heightAttr : undefined, className: imgClass, style: imgStyle, draggable: !devMode }));
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2759
|
+
// Outlook Classic wrapper - only applied when outlookWidth is explicitly set
|
|
2760
|
+
// OR when we need to constrain a percentage-width image in Outlook
|
|
2761
|
+
const needsOutlookWrapper = config.outlookWidth || (isPercent && imgWidthAttr);
|
|
2762
|
+
const finalImageElement = needsOutlookWrapper ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: {
|
|
2763
|
+
__html: `</style>` +
|
|
2764
|
+
`<!--[if mso]>` +
|
|
2765
|
+
`<table cellpadding="0" cellspacing="0" border="0" style="width: ${imgWidthAttr}px;">` +
|
|
2766
|
+
`<tr>` +
|
|
2767
|
+
`<td style="padding: 0; margin: 0;" width="${imgWidthAttr}">` +
|
|
2768
|
+
`<img src="${src}" alt="${alt || ""}" width="${imgWidthAttr}" height="${heightAttr !== "auto" ? heightAttr : ""}" style="display: block; width: 100%; height: auto;" />` +
|
|
2769
|
+
`</td>` +
|
|
2770
|
+
`</tr>` +
|
|
2771
|
+
`</table>` +
|
|
2772
|
+
`<![endif]-->` +
|
|
2773
|
+
`<!--[if !mso]><!-->` +
|
|
2774
|
+
`<style>`,
|
|
2775
|
+
} }), imageElement, jsxRuntime.jsx("style", { dangerouslySetInnerHTML: {
|
|
2776
|
+
__html: `</style>` + `<!--<![endif]-->` + `<style>`,
|
|
2777
|
+
} })] })) : (imageElement);
|
|
2778
|
+
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", ...rootBindingProps(bindings), style: {
|
|
2779
|
+
width: tableWidth,
|
|
2642
2780
|
maxWidth: "100%",
|
|
2643
2781
|
borderCollapse: "collapse",
|
|
2644
2782
|
margin: "0 auto",
|
|
@@ -2647,10 +2785,10 @@ function Image({ config, devNode, devMode }) {
|
|
|
2647
2785
|
backgroundColor: config.backgroundColor,
|
|
2648
2786
|
fontSize: "0",
|
|
2649
2787
|
lineHeight: "0",
|
|
2650
|
-
width: tableWidth,
|
|
2788
|
+
width: tableWidth,
|
|
2651
2789
|
}, children: href && !devMode ? (jsxRuntime.jsx("a", { href: href, target: target, ...(target === "_blank"
|
|
2652
2790
|
? { rel: "noopener noreferrer" }
|
|
2653
|
-
: {}), style: { display: "block", width: "100%" }, children:
|
|
2791
|
+
: {}), style: { display: "block", width: "100%" }, children: finalImageElement })) : (finalImageElement) }) }) }), devMode && !!devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] })] }));
|
|
2654
2792
|
}
|
|
2655
2793
|
var Image_default = React.memo(Image, arePropsEqual);
|
|
2656
2794
|
|
|
@@ -2719,7 +2857,21 @@ function getHrefFromInnerLink(innerLink) {
|
|
|
2719
2857
|
return undefined;
|
|
2720
2858
|
}
|
|
2721
2859
|
}
|
|
2722
|
-
|
|
2860
|
+
/**
|
|
2861
|
+
* Resolves the width for a child <td> at the given index based on layoutColumns.
|
|
2862
|
+
*
|
|
2863
|
+
* - "equal" → equal percentage share across all children
|
|
2864
|
+
* - string[] → explicit value at the matching index (px, %, or mixed)
|
|
2865
|
+
* - undefined → undefined, so no width attribute is set (retrocompat)
|
|
2866
|
+
*/
|
|
2867
|
+
function resolveChildColumnWidth(layoutColumns, index, numChildren) {
|
|
2868
|
+
if (!layoutColumns)
|
|
2869
|
+
return undefined;
|
|
2870
|
+
if (layoutColumns === "equal")
|
|
2871
|
+
return `${100 / numChildren}%`;
|
|
2872
|
+
return layoutColumns[index];
|
|
2873
|
+
}
|
|
2874
|
+
function Row({ children, config, devNode, devMode, bindings }) {
|
|
2723
2875
|
var _a, _b, _c, _d, _e, _f;
|
|
2724
2876
|
const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
|
|
2725
2877
|
const numChildren = childrenArray.length;
|
|
@@ -2730,6 +2882,9 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2730
2882
|
// / mobile-gap-spacer class names so that stacking works via non-@media CSS
|
|
2731
2883
|
// rules that survive Gmail's stylesheet stripping.
|
|
2732
2884
|
const isStacking = ((_b = config.mobile) === null || _b === void 0 ? void 0 : _b.wrap) === true && numChildren > 1;
|
|
2885
|
+
// Whether layoutColumns is active. When true, table-layout:fixed is applied
|
|
2886
|
+
// to the content table so Outlook Classic honours the declared column widths.
|
|
2887
|
+
const hasLayoutColumns = config.layoutColumns !== undefined;
|
|
2733
2888
|
// 1. Outer TD: Background, Border Radius, Width, Height.
|
|
2734
2889
|
const backgroundTdStyle = {
|
|
2735
2890
|
backgroundColor: config.backgroundColor,
|
|
@@ -2770,24 +2925,34 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2770
2925
|
// Content table fills available space, giving Outlook Classic a hard
|
|
2771
2926
|
// boundary so text children get a constrained box and line wrapping
|
|
2772
2927
|
// triggers correctly. Use for rows containing text + image layouts.
|
|
2928
|
+
//
|
|
2929
|
+
// layoutColumns (any value) → additionally applies table-layout: fixed
|
|
2930
|
+
// so Outlook Classic honours the per-child width declarations.
|
|
2931
|
+
// Compatible with both fillWidth modes.
|
|
2773
2932
|
const contentTableStyle = {
|
|
2774
|
-
|
|
2933
|
+
// When layoutColumns is active, force 100% so Outlook Classic has a
|
|
2934
|
+
// concrete boundary to resolve percentage column widths against.
|
|
2935
|
+
// table-layout:fixed is meaningless without a fixed reference width.
|
|
2936
|
+
width: hasLayoutColumns || config.fillWidth ? "100%" : "auto",
|
|
2775
2937
|
height: "100%",
|
|
2776
2938
|
borderCollapse: "collapse",
|
|
2777
2939
|
minWidth: "1px",
|
|
2778
|
-
...(!config.fillWidth &&
|
|
2940
|
+
...(!config.fillWidth &&
|
|
2941
|
+
!hasLayoutColumns && { maxWidth: config.width || "100%" }),
|
|
2942
|
+
...(hasLayoutColumns && { tableLayout: "fixed" }),
|
|
2779
2943
|
};
|
|
2780
2944
|
// 5. Gap TD.
|
|
2781
2945
|
const gapTdStyle = {
|
|
2782
2946
|
width: config.gap || "0",
|
|
2783
2947
|
lineHeight: "1px",
|
|
2784
2948
|
fontSize: "1px",
|
|
2949
|
+
background: "transparent",
|
|
2785
2950
|
};
|
|
2786
2951
|
const tdAlign = config.justifyContent
|
|
2787
2952
|
? justifyMap$1[config.justifyContent]
|
|
2788
2953
|
: "left";
|
|
2789
2954
|
const tdValign = config.alignItems ? alignMap[config.alignItems] : "top";
|
|
2790
|
-
const content = (jsxRuntime.jsxs("table", { "aria-label": "Row Outer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2955
|
+
const content = (jsxRuntime.jsxs("table", { "aria-label": "Row Outer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...(!href ? rootBindingProps(bindings) : {}), style: {
|
|
2791
2956
|
position: "relative",
|
|
2792
2957
|
width: config.width || "100%",
|
|
2793
2958
|
height: config.height,
|
|
@@ -2796,32 +2961,44 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2796
2961
|
width: "100%",
|
|
2797
2962
|
height: "100%",
|
|
2798
2963
|
borderCollapse: "collapse",
|
|
2799
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { align: tdAlign, width: "100%", style: { width: "100%" }, children: jsxRuntime.jsx("table", { "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-wrap": ((_f = config.mobile) === null || _f === void 0 ? void 0 : _f.wrap) ? "true" : undefined, "data-gap": config.gap, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { className: "content-tr", children: childrenArray.map((child, index) =>
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2964
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { align: tdAlign, width: "100%", style: { width: "100%" }, children: jsxRuntime.jsx("table", { "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-wrap": ((_f = config.mobile) === null || _f === void 0 ? void 0 : _f.wrap) ? "true" : undefined, "data-gap": config.gap, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { className: "content-tr", ...listBindingProps(bindings), children: childrenArray.map((child, index) => {
|
|
2965
|
+
// Resolve the column width for this child based on
|
|
2966
|
+
// layoutColumns. undefined when layoutColumns is not set,
|
|
2967
|
+
// preserving the original behaviour (retrocompat).
|
|
2968
|
+
const columnWidth = resolveChildColumnWidth(config.layoutColumns, index, numChildren);
|
|
2969
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("td", { align: tdAlign, ...(columnWidth && {
|
|
2970
|
+
width: columnWidth,
|
|
2971
|
+
}), style: {
|
|
2972
|
+
verticalAlign: tdValign,
|
|
2973
|
+
textAlign: tdAlign,
|
|
2974
|
+
padding: "0",
|
|
2975
|
+
margin: "0",
|
|
2976
|
+
...(columnWidth && {
|
|
2977
|
+
width: columnWidth,
|
|
2978
|
+
}),
|
|
2979
|
+
},
|
|
2980
|
+
// Mirror of Container's stack-td pattern: when isStacking,
|
|
2981
|
+
// the non-@media .stack-td rule forces display:block +
|
|
2982
|
+
// width:100% on each child, which survives Gmail's
|
|
2983
|
+
// @media stripping and achieves true mobile stacking.
|
|
2984
|
+
className: `child-cell${isStacking ? " stack-td" : ""}`, children: [child, isStacking &&
|
|
2985
|
+
index < numChildren - 1 &&
|
|
2986
|
+
config.gap && (jsxRuntime.jsx("div", { className: "mobile-gap-spacer", style: {
|
|
2987
|
+
display: "none",
|
|
2988
|
+
fontSize: "0",
|
|
2989
|
+
lineHeight: "0",
|
|
2990
|
+
height: config.gap,
|
|
2991
|
+
background: "transparent",
|
|
2992
|
+
}, children: "\u00A0" }))] }), index < numChildren - 1 &&
|
|
2993
|
+
config.gap && (jsxRuntime.jsx("td", { width: config.gap, style: gapTdStyle,
|
|
2994
|
+
// Mirror of Container's desktop-gap-column pattern:
|
|
2995
|
+
// when isStacking, the non-@media .desktop-gap-column
|
|
2996
|
+
// rule collapses the between-column gap td so it does
|
|
2997
|
+
// not create phantom space while children are stacked.
|
|
2998
|
+
className: `row-gap-td${isStacking ? " desktop-gap-column" : ""}`, children: "\u00A0" }, `row-gap-${index}`))] }, `row-child-${index}`));
|
|
2999
|
+
}) }) }) }) }) }) }) }) }) }) }) }) }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }));
|
|
2823
3000
|
if (href && !devMode) {
|
|
2824
|
-
return (jsxRuntime.jsx("a", { href: href, ...({ target }), style: {
|
|
3001
|
+
return (jsxRuntime.jsx("a", { href: href, ...({ target }), ...rootBindingProps(bindings), style: {
|
|
2825
3002
|
textDecoration: "none",
|
|
2826
3003
|
color: "inherit",
|
|
2827
3004
|
display: "block",
|
|
@@ -2866,10 +3043,10 @@ function getBorderStyle$1(border) {
|
|
|
2866
3043
|
}
|
|
2867
3044
|
return style;
|
|
2868
3045
|
}
|
|
2869
|
-
const Section = ({ config, children, devNode, }) => {
|
|
3046
|
+
const Section = ({ config, children, devNode, bindings, }) => {
|
|
2870
3047
|
var _a, _b, _c;
|
|
2871
3048
|
const { sectionType, padding } = config;
|
|
2872
|
-
return (jsxRuntime.jsxs("table", { "aria-label": `Section |Table | ${sectionType}`, role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
3049
|
+
return (jsxRuntime.jsxs("table", { "aria-label": `Section |Table | ${sectionType}`, role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
2873
3050
|
position: "relative",
|
|
2874
3051
|
width: "100%",
|
|
2875
3052
|
backgroundColor: config.backgroundColor,
|
|
@@ -2882,58 +3059,84 @@ const Section = ({ config, children, devNode, }) => {
|
|
|
2882
3059
|
backgroundPosition: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.position,
|
|
2883
3060
|
}, children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: {
|
|
2884
3061
|
padding: padding,
|
|
2885
|
-
}, children: children }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
3062
|
+
}, ...listBindingProps(bindings), children: children }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: jsxRuntime.jsxs("span", { style: {
|
|
3063
|
+
backgroundColor: "black",
|
|
3064
|
+
color: "white",
|
|
3065
|
+
padding: "4px",
|
|
3066
|
+
fontSize: "14px",
|
|
3067
|
+
position: "absolute",
|
|
3068
|
+
left: 0,
|
|
3069
|
+
top: 0,
|
|
3070
|
+
}, children: ["Section | ", sectionType] }) }) }) }))] }));
|
|
2894
3071
|
};
|
|
2895
3072
|
var Section_default = React.memo(Section, arePropsEqual);
|
|
2896
3073
|
|
|
2897
|
-
function Spacer({ config, devNode }) {
|
|
2898
|
-
|
|
3074
|
+
function Spacer({ config, devNode, bindings }) {
|
|
3075
|
+
var _a, _b, _c;
|
|
3076
|
+
const { height, hideOnMobile, backgroundColor, backgroundImage } = config;
|
|
2899
3077
|
// 1. Spacer Table Style
|
|
2900
3078
|
const spacerTableStyle = {
|
|
2901
|
-
// Crucial for compatibility: Ensures no background or border interference
|
|
2902
|
-
backgroundColor: "transparent",
|
|
2903
3079
|
borderCollapse: "collapse",
|
|
2904
|
-
border: "0",
|
|
2905
3080
|
width: "100%",
|
|
2906
|
-
// Note the CSS standard dash convention: 'mso-table-lspace'
|
|
2907
|
-
// ["mso-table-lspace" as string]: "0pt",
|
|
2908
|
-
["msoTableLspace"]: "0pt",
|
|
2909
|
-
// ["mso-table-rspace" as string]: "0pt",
|
|
2910
|
-
["msoTableRspace"]: "0pt",
|
|
2911
3081
|
};
|
|
2912
3082
|
// 2. Spacer TD Style: The element that creates the actual vertical space
|
|
2913
3083
|
const spacerTdStyle = {
|
|
2914
3084
|
height: height,
|
|
2915
|
-
|
|
3085
|
+
maxHeight: height,
|
|
2916
3086
|
fontSize: "0",
|
|
2917
3087
|
lineHeight: "0",
|
|
2918
3088
|
padding: "0",
|
|
3089
|
+
margin: "0",
|
|
3090
|
+
border: "none",
|
|
3091
|
+
color: "transparent",
|
|
3092
|
+
// Background applied at TD level for Outlook Classic compatibility
|
|
3093
|
+
...(backgroundColor && { backgroundColor }),
|
|
3094
|
+
...(backgroundImage && {
|
|
3095
|
+
backgroundImage: `url(${backgroundImage.src})`,
|
|
3096
|
+
backgroundRepeat: (_a = backgroundImage.repeat) !== null && _a !== void 0 ? _a : "no-repeat",
|
|
3097
|
+
backgroundSize: (_b = backgroundImage.size) !== null && _b !== void 0 ? _b : "cover",
|
|
3098
|
+
backgroundPosition: (_c = backgroundImage.position) !== null && _c !== void 0 ? _c : "center",
|
|
3099
|
+
}),
|
|
2919
3100
|
};
|
|
2920
3101
|
// Parse height for the HTML attribute
|
|
2921
3102
|
const spacerHeightAttribute = parseInt(height, 10) || 1;
|
|
2922
|
-
return (
|
|
2923
|
-
// Outer table ensures the spacer spans the full width of its container
|
|
2924
|
-
jsxRuntime.jsxs("table", { "aria-label": "Vertical Spacer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
3103
|
+
return (jsxRuntime.jsxs("table", { "aria-label": "Vertical Spacer", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
2925
3104
|
// --- Start dev
|
|
2926
3105
|
position: "relative",
|
|
2927
3106
|
// --- End dev
|
|
2928
3107
|
...spacerTableStyle,
|
|
2929
|
-
}, ...{ height: spacerHeightAttribute }, className: hideOnMobile ? "hide-on-mobile" : undefined, children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: spacerTdStyle,
|
|
2930
|
-
|
|
2931
|
-
|
|
3108
|
+
}, ...{ height: spacerHeightAttribute }, className: hideOnMobile ? "hide-on-mobile" : undefined, children: [jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: spacerTdStyle, height: spacerHeightAttribute, ...(backgroundColor && !backgroundImage
|
|
3109
|
+
? { bgcolor: backgroundColor }
|
|
3110
|
+
: {}) }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }));
|
|
2932
3111
|
}
|
|
2933
3112
|
var Spacer_default = React.memo(Spacer, arePropsEqual);
|
|
2934
3113
|
|
|
2935
|
-
|
|
2936
|
-
|
|
3114
|
+
// Helper to build link href based on innerLink type
|
|
3115
|
+
function buildLinkHref$1(innerLink) {
|
|
3116
|
+
if (!innerLink || innerLink.type === "none")
|
|
3117
|
+
return null;
|
|
3118
|
+
switch (innerLink.type) {
|
|
3119
|
+
case "url":
|
|
3120
|
+
return innerLink.url || null;
|
|
3121
|
+
case "email":
|
|
3122
|
+
return innerLink.email ? `mailto:${innerLink.email}` : null;
|
|
3123
|
+
case "phone":
|
|
3124
|
+
return innerLink.phone ? `tel:${innerLink.phone}` : null;
|
|
3125
|
+
case "anchor":
|
|
3126
|
+
return innerLink.anchor ? `#${innerLink.anchor}` : null;
|
|
3127
|
+
case "page_top":
|
|
3128
|
+
return "#top";
|
|
3129
|
+
case "page_bottom":
|
|
3130
|
+
return "#bottom";
|
|
3131
|
+
default:
|
|
3132
|
+
return null;
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
function Text({ config, devMode, children, bindings }) {
|
|
3136
|
+
const { text, padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, opacity, whiteSpace, wordBreak = "break-all", maxWidth, innerLink, } = config;
|
|
3137
|
+
// Resolve href and target from innerLink
|
|
3138
|
+
const href = buildLinkHref$1(innerLink);
|
|
3139
|
+
const target = (innerLink === null || innerLink === void 0 ? void 0 : innerLink.target) || "_blank";
|
|
2937
3140
|
// 1. TD Style: Where padding and background are reliably applied.
|
|
2938
3141
|
// When maxWidth is set, this TD stays at width: 100% so it always fills
|
|
2939
3142
|
// its parent — the inner maxWidth table (see below) does the actual
|
|
@@ -2986,26 +3189,31 @@ function Text({ config, devMode, children }) {
|
|
|
2986
3189
|
? injectLinkStyles(content, contentStyle)
|
|
2987
3190
|
: "";
|
|
2988
3191
|
const innerContent = isString ? (jsxRuntime.jsx("div", { style: contentStyle, dangerouslySetInnerHTML: { __html: processedHtml } })) : (jsxRuntime.jsx("div", { style: contentStyle, children: content }));
|
|
2989
|
-
|
|
3192
|
+
const wrappedContent = maxWidth ? (
|
|
3193
|
+
/*
|
|
3194
|
+
* maxWidth wrapper — Outlook Classic compatibility pattern:
|
|
3195
|
+
*
|
|
3196
|
+
* <center> instructs the Word rendering engine to horizontally
|
|
3197
|
+
* centre its child block, equivalent to margin: 0 auto in CSS.
|
|
3198
|
+
*
|
|
3199
|
+
* The inner table carries the `width` HTML attribute set to the
|
|
3200
|
+
* maxWidth value. Outlook Classic reads `width` as a hard pixel
|
|
3201
|
+
* cap; it has no concept of max-width so this is the only lever
|
|
3202
|
+
* available. Modern clients receive the CSS max-width on the
|
|
3203
|
+
* same table and behave correctly.
|
|
3204
|
+
*
|
|
3205
|
+
* The outer TD remains at width: 100% so it always fills its
|
|
3206
|
+
* parent cell in every client — only the inner content is capped.
|
|
3207
|
+
*/
|
|
3208
|
+
jsxRuntime.jsx("center", { children: jsxRuntime.jsx("table", { "aria-label": "Text Max Width Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, width: maxWidth, style: maxWidthTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: innerContent }) }) }) }) })) : (innerContent);
|
|
3209
|
+
return (jsxRuntime.jsx("table", { "aria-label": "Text Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, ...rootBindingProps(bindings), style: {
|
|
2990
3210
|
width: "100%",
|
|
2991
3211
|
borderCollapse: "collapse",
|
|
2992
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children:
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
* centre its child block, equivalent to margin: 0 auto in CSS.
|
|
2998
|
-
*
|
|
2999
|
-
* The inner table carries the `width` HTML attribute set to the
|
|
3000
|
-
* maxWidth value. Outlook Classic reads `width` as a hard pixel
|
|
3001
|
-
* cap; it has no concept of max-width so this is the only lever
|
|
3002
|
-
* available. Modern clients receive the CSS max-width on the
|
|
3003
|
-
* same table and behave correctly.
|
|
3004
|
-
*
|
|
3005
|
-
* The outer TD remains at width: 100% so it always fills its
|
|
3006
|
-
* parent cell in every client — only the inner content is capped.
|
|
3007
|
-
*/
|
|
3008
|
-
jsxRuntime.jsx("center", { children: jsxRuntime.jsx("table", { "aria-label": "Text Max Width Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, width: maxWidth, style: maxWidthTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: innerContent }) }) }) }) })) : (innerContent) }) }) }) }));
|
|
3212
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: href && !devMode ? (jsxRuntime.jsx("a", { href: href, target: target, ...(target === "_blank" ? { rel: "noopener noreferrer" } : {}), style: {
|
|
3213
|
+
display: "block",
|
|
3214
|
+
textDecoration: "none",
|
|
3215
|
+
color: "inherit",
|
|
3216
|
+
}, children: wrappedContent })) : (wrappedContent) }) }) }) }));
|
|
3009
3217
|
}
|
|
3010
3218
|
var Text_default = React.memo(Text, arePropsEqual);
|
|
3011
3219
|
|
|
@@ -3131,7 +3339,7 @@ function buildLinkHref(innerLink) {
|
|
|
3131
3339
|
return null;
|
|
3132
3340
|
}
|
|
3133
3341
|
}
|
|
3134
|
-
function Icon({ config, devNode, devMode, children }) {
|
|
3342
|
+
function Icon({ config, devNode, devMode, children, bindings }) {
|
|
3135
3343
|
const {
|
|
3136
3344
|
// base64Source,
|
|
3137
3345
|
width, height, backgroundColor, padding = "0", borderRadius = "0", border, innerLink, justifyContent = "center", } = config;
|
|
@@ -3266,7 +3474,7 @@ function Icon({ config, devNode, devMode, children }) {
|
|
|
3266
3474
|
<!--<![endif]-->
|
|
3267
3475
|
`
|
|
3268
3476
|
: null;
|
|
3269
|
-
return (jsxRuntime.jsxs("table", { "aria-label": "Icon", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, align: align, style: {
|
|
3477
|
+
return (jsxRuntime.jsxs("table", { "aria-label": "Icon", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, align: align, ...rootBindingProps(bindings), style: {
|
|
3270
3478
|
// --- Start dev
|
|
3271
3479
|
position: "relative",
|
|
3272
3480
|
// --- End dev
|