@pagenflow/email 1.4.6 → 1.4.7
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/Column.d.ts +1 -0
- package/dist/components/Text.d.ts +7 -0
- package/dist/index.cjs.js +104 -43
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +104 -43
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -36,6 +36,13 @@ export interface TextConfig {
|
|
|
36
36
|
whiteSpace?: string;
|
|
37
37
|
/** Word break behavior (e.g., 'break-all', 'break-word', 'keep-all', 'normal'). */
|
|
38
38
|
wordBreak?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Constrains the text block width in modern clients via CSS, and in
|
|
41
|
+
* Outlook Classic (Word rendering engine) via a <center> + table `width`
|
|
42
|
+
* HTML attribute pattern — identical to the Column maxWidth approach.
|
|
43
|
+
* The outer table always stays at 100% so no retro layout is disturbed;
|
|
44
|
+
* only the inner constrained table is capped.
|
|
45
|
+
*/
|
|
39
46
|
maxWidth?: string;
|
|
40
47
|
listStyle?: string;
|
|
41
48
|
}
|
package/dist/index.cjs.js
CHANGED
|
@@ -1803,6 +1803,9 @@ function Column({ children, config, devNode }) {
|
|
|
1803
1803
|
};
|
|
1804
1804
|
// 2. Outer TD style: Background and Border Radius (no border here).
|
|
1805
1805
|
// height is set so the TD occupies the full declared height.
|
|
1806
|
+
// When maxWidth is set, the outer TD stays at its normal width so it
|
|
1807
|
+
// always fills its parent — the inner maxWidth table (see below) does
|
|
1808
|
+
// the actual capping.
|
|
1806
1809
|
const outerTdStyle = {
|
|
1807
1810
|
width: config.width,
|
|
1808
1811
|
height: config.height,
|
|
@@ -1846,6 +1849,18 @@ function Column({ children, config, devNode }) {
|
|
|
1846
1849
|
fontSize: "1px",
|
|
1847
1850
|
width: "100%",
|
|
1848
1851
|
};
|
|
1852
|
+
// 5. maxWidth constraining table style (modern clients).
|
|
1853
|
+
// The `width` HTML attribute on this table is what Outlook Classic
|
|
1854
|
+
// (Word engine) reads — it has no concept of max-width, but it does
|
|
1855
|
+
// honour the `width` attribute as a hard column cap.
|
|
1856
|
+
// The CSS max-width here handles modern web/email clients correctly.
|
|
1857
|
+
// <center> around it ensures the constrained block stays horizontally
|
|
1858
|
+
// centred in both the Word engine and standards-based renderers.
|
|
1859
|
+
const maxWidthTableStyle = {
|
|
1860
|
+
width: "100%",
|
|
1861
|
+
maxWidth: config.maxWidth,
|
|
1862
|
+
borderCollapse: "collapse",
|
|
1863
|
+
};
|
|
1849
1864
|
// Main content rendering
|
|
1850
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", children: config.gap && numChildren > 1 ? (jsxRuntime.jsx("table", { "aria-label": "Column Gap Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
1851
1866
|
width: "100%",
|
|
@@ -1862,7 +1877,24 @@ function Column({ children, config, devNode }) {
|
|
|
1862
1877
|
return (jsxRuntime.jsxs("table", { "aria-label": "Column Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
1863
1878
|
position: "relative",
|
|
1864
1879
|
...outerTableStyle,
|
|
1865
|
-
}, ...(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:
|
|
1880
|
+
}, ...(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 ? (
|
|
1881
|
+
/*
|
|
1882
|
+
* maxWidth wrapper — Outlook Classic compatibility pattern:
|
|
1883
|
+
*
|
|
1884
|
+
* <center> instructs the Word rendering engine to horizontally
|
|
1885
|
+
* centre its child block, equivalent to margin: 0 auto in CSS.
|
|
1886
|
+
*
|
|
1887
|
+
* The inner table carries the `width` HTML attribute set to the
|
|
1888
|
+
* maxWidth value. Outlook Classic reads `width` as a hard pixel
|
|
1889
|
+
* cap; it has no concept of max-width so this is the only lever
|
|
1890
|
+
* available. Modern clients receive the CSS max-width on the
|
|
1891
|
+
* same table and behave correctly.
|
|
1892
|
+
*
|
|
1893
|
+
* The outer column remains at its normal width so it always
|
|
1894
|
+
* fills its parent cell in every client — only the inner
|
|
1895
|
+
* content is capped.
|
|
1896
|
+
*/
|
|
1897
|
+
jsxRuntime.jsx("center", { children: jsxRuntime.jsx("table", { "aria-label": "Column Max Width Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, width: config.maxWidth, style: maxWidthTableStyle, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: renderContent() }) }) }) }) })) : (renderContent()) }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }));
|
|
1866
1898
|
}
|
|
1867
1899
|
var Column_default = React.memo(Column, arePropsEqual);
|
|
1868
1900
|
|
|
@@ -2194,36 +2226,7 @@ function Head({ children, backgroundColor = "#ffffff", title = "Email Preview",
|
|
|
2194
2226
|
mso-line-height-rule: exactly;
|
|
2195
2227
|
}
|
|
2196
2228
|
}
|
|
2197
|
-
|
|
2198
|
-
.row-content-table[data-mobile-justify="center"] { margin: 0 auto !important; float: none !important; }
|
|
2199
|
-
.row-content-table[data-mobile-justify="start"] { margin: 0 !important; float: left !important; }
|
|
2200
|
-
.row-content-table[data-mobile-justify="end"] { margin: 0 0 0 auto !important; float: right !important; }
|
|
2201
|
-
.row-content-table[data-mobile-align="center"] .child-cell { vertical-align: middle !important; }
|
|
2202
|
-
.row-content-table[data-mobile-align="start"] .child-cell { vertical-align: top !important; }
|
|
2203
|
-
.row-content-table[data-mobile-align="end"] .child-cell { vertical-align: bottom !important; }
|
|
2204
|
-
.row-content-table[data-mobile-wrap="true"] { width: 100% !important; max-width: 100% !important; }
|
|
2205
|
-
.row-content-table[data-mobile-wrap="true"] > tbody > .content-tr { display: block !important; }
|
|
2206
|
-
.row-content-table[data-mobile-wrap="true"] > tbody > .content-tr > .child-cell {
|
|
2207
|
-
display: block !important;
|
|
2208
|
-
width: 100% !important;
|
|
2209
|
-
box-sizing: border-box !important;
|
|
2210
|
-
}
|
|
2211
|
-
.row-content-table[data-mobile-wrap="true"] > tbody > .content-tr > .row-gap-td {
|
|
2212
|
-
display: none !important;
|
|
2213
|
-
width: 0 !important;
|
|
2214
|
-
height: 0 !important;
|
|
2215
|
-
}
|
|
2216
|
-
.row-content-table[data-mobile-wrap="true"] > tbody > .content-tr > .child-cell:not(:last-child) {
|
|
2217
|
-
margin-bottom: 20px !important;
|
|
2218
|
-
}
|
|
2219
|
-
${["10px", "15px", "20px", "24px", "30px", "40px", ...rowGaps]
|
|
2220
|
-
.filter((gap, index, self) => self.indexOf(gap) === index)
|
|
2221
|
-
.map((gap) => `
|
|
2222
|
-
.row-content-table[data-mobile-wrap="true"][data-gap="${gap}"] > tbody > .content-tr > .child-cell:not(:last-child) {
|
|
2223
|
-
margin-bottom: ${gap} !important;
|
|
2224
|
-
}`)
|
|
2225
|
-
.join("\n")}
|
|
2226
|
-
}
|
|
2229
|
+
|
|
2227
2230
|
a { color: inherit; text-decoration: none; }
|
|
2228
2231
|
ol, ul { margin: 0px; padding: 0px; list-style: none; }
|
|
2229
2232
|
li {
|
|
@@ -2375,7 +2378,9 @@ function resolveAnchorStyles(anchor, fallback) {
|
|
|
2375
2378
|
else if (fallback === null || fallback === void 0 ? void 0 : fallback[prop]) {
|
|
2376
2379
|
resolved[prop] = fallback[prop];
|
|
2377
2380
|
}
|
|
2378
|
-
|
|
2381
|
+
else if (prop === "text-decoration") {
|
|
2382
|
+
resolved[prop] = "none";
|
|
2383
|
+
}
|
|
2379
2384
|
}
|
|
2380
2385
|
return Object.entries(resolved)
|
|
2381
2386
|
.map(([k, v]) => `${k}:${v}`)
|
|
@@ -2715,11 +2720,16 @@ function getHrefFromInnerLink(innerLink) {
|
|
|
2715
2720
|
}
|
|
2716
2721
|
}
|
|
2717
2722
|
function Row({ children, config, devNode, devMode }) {
|
|
2718
|
-
var _a, _b, _c, _d, _e, _f
|
|
2723
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2719
2724
|
const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
|
|
2720
2725
|
const numChildren = childrenArray.length;
|
|
2721
2726
|
const href = getHrefFromInnerLink(config.innerLink);
|
|
2722
2727
|
const target = ((_a = config.innerLink) === null || _a === void 0 ? void 0 : _a.target) || "_blank";
|
|
2728
|
+
// Whether children should stack on mobile.
|
|
2729
|
+
// Mirrors Container's isStacking pattern: drives stack-td / desktop-gap-column
|
|
2730
|
+
// / mobile-gap-spacer class names so that stacking works via non-@media CSS
|
|
2731
|
+
// rules that survive Gmail's stylesheet stripping.
|
|
2732
|
+
const isStacking = ((_b = config.mobile) === null || _b === void 0 ? void 0 : _b.wrap) === true && numChildren > 1;
|
|
2723
2733
|
// 1. Outer TD: Background, Border Radius, Width, Height.
|
|
2724
2734
|
const backgroundTdStyle = {
|
|
2725
2735
|
backgroundColor: config.backgroundColor,
|
|
@@ -2729,9 +2739,9 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2729
2739
|
backgroundImage: config.backgroundImage
|
|
2730
2740
|
? `url(${config.backgroundImage.src})`
|
|
2731
2741
|
: undefined,
|
|
2732
|
-
backgroundRepeat: (
|
|
2733
|
-
backgroundSize: (
|
|
2734
|
-
backgroundPosition: (
|
|
2742
|
+
backgroundRepeat: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.repeat,
|
|
2743
|
+
backgroundSize: (_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.size,
|
|
2744
|
+
backgroundPosition: (_e = config.backgroundImage) === null || _e === void 0 ? void 0 : _e.position,
|
|
2735
2745
|
...(config.borderRadius && { overflow: "hidden" }),
|
|
2736
2746
|
};
|
|
2737
2747
|
// 2. Inner Table: Border and Border Radius.
|
|
@@ -2786,13 +2796,30 @@ function Row({ children, config, devNode, devMode }) {
|
|
|
2786
2796
|
width: "100%",
|
|
2787
2797
|
height: "100%",
|
|
2788
2798
|
borderCollapse: "collapse",
|
|
2789
|
-
}, 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-
|
|
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) => (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("td", { align: tdAlign, style: {
|
|
2790
2800
|
verticalAlign: tdValign,
|
|
2791
|
-
textAlign:
|
|
2801
|
+
textAlign: tdAlign,
|
|
2792
2802
|
padding: "0",
|
|
2793
2803
|
margin: "0",
|
|
2794
|
-
},
|
|
2795
|
-
|
|
2804
|
+
},
|
|
2805
|
+
// Mirror of Container's stack-td pattern: when isStacking,
|
|
2806
|
+
// the non-@media .stack-td rule forces display:block +
|
|
2807
|
+
// width:100% on each child, which survives Gmail's
|
|
2808
|
+
// @media stripping and achieves true mobile stacking.
|
|
2809
|
+
className: `child-cell${isStacking ? " stack-td" : ""}`, children: [child, isStacking &&
|
|
2810
|
+
index < numChildren - 1 &&
|
|
2811
|
+
config.gap && (jsxRuntime.jsx("div", { className: "mobile-gap-spacer", style: {
|
|
2812
|
+
display: "none",
|
|
2813
|
+
fontSize: "0",
|
|
2814
|
+
lineHeight: "0",
|
|
2815
|
+
height: config.gap,
|
|
2816
|
+
}, children: "\u00A0" }))] }), index < numChildren - 1 &&
|
|
2817
|
+
config.gap && (jsxRuntime.jsx("td", { width: config.gap, style: gapTdStyle,
|
|
2818
|
+
// Mirror of Container's desktop-gap-column pattern:
|
|
2819
|
+
// when isStacking, the non-@media .desktop-gap-column
|
|
2820
|
+
// rule collapses the between-column gap td so it does
|
|
2821
|
+
// not create phantom space while children are stacked.
|
|
2822
|
+
className: `row-gap-td${isStacking ? " desktop-gap-column" : ""}`, children: "\u00A0" }, `row-gap-${index}`))] }, `row-child-${index}`))) }) }) }) }) }) }) }) }) }) }) }) }) }) }), devNode && (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { children: devNode }) }) }))] }));
|
|
2796
2823
|
if (href && !devMode) {
|
|
2797
2824
|
return (jsxRuntime.jsx("a", { href: href, ...({ target }), style: {
|
|
2798
2825
|
textDecoration: "none",
|
|
@@ -2908,13 +2935,19 @@ var Spacer_default = React.memo(Spacer, arePropsEqual);
|
|
|
2908
2935
|
function Text({ config, devMode, children }) {
|
|
2909
2936
|
const { text, padding, color, textAlign, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, textTransform, textDecoration, direction, verticalAlign, backgroundColor, opacity, whiteSpace, wordBreak = "break-all", maxWidth, } = config;
|
|
2910
2937
|
// 1. TD Style: Where padding and background are reliably applied.
|
|
2938
|
+
// When maxWidth is set, this TD stays at width: 100% so it always fills
|
|
2939
|
+
// its parent — the inner maxWidth table (see below) does the actual
|
|
2940
|
+
// capping, keeping the outer layout intact in all clients.
|
|
2911
2941
|
const tdStyle = {
|
|
2912
2942
|
padding: padding,
|
|
2913
2943
|
backgroundColor: backgroundColor,
|
|
2914
2944
|
width: "100%",
|
|
2915
2945
|
verticalAlign: "top",
|
|
2916
2946
|
};
|
|
2917
|
-
// 2. Content Style: Applied directly to
|
|
2947
|
+
// 2. Content Style: Applied directly to the inner div wrapper.
|
|
2948
|
+
// maxWidth is intentionally omitted here — putting it on a div has no
|
|
2949
|
+
// effect in Outlook Classic (Word engine ignores CSS on div elements).
|
|
2950
|
+
// The constraint is enforced at the table level instead (see below).
|
|
2918
2951
|
const contentStyle = {
|
|
2919
2952
|
color: color,
|
|
2920
2953
|
textAlign: textAlign,
|
|
@@ -2933,7 +2966,18 @@ function Text({ config, devMode, children }) {
|
|
|
2933
2966
|
wordBreak: wordBreak,
|
|
2934
2967
|
margin: "0",
|
|
2935
2968
|
padding: "0",
|
|
2936
|
-
|
|
2969
|
+
};
|
|
2970
|
+
// 3. maxWidth constraining table style (modern clients).
|
|
2971
|
+
// The `width` HTML attribute on this table is what Outlook Classic
|
|
2972
|
+
// (Word engine) reads — it has no concept of max-width, but it does
|
|
2973
|
+
// honour the `width` attribute as a hard column cap.
|
|
2974
|
+
// The CSS max-width here handles modern web/email clients correctly.
|
|
2975
|
+
// <center> around it ensures the constrained block stays horizontally
|
|
2976
|
+
// centred in both the Word engine and standards-based renderers.
|
|
2977
|
+
const maxWidthTableStyle = {
|
|
2978
|
+
width: "100%",
|
|
2979
|
+
maxWidth: maxWidth,
|
|
2980
|
+
borderCollapse: "collapse",
|
|
2937
2981
|
};
|
|
2938
2982
|
// Determine content to render
|
|
2939
2983
|
const content = text !== null && text !== void 0 ? text : children;
|
|
@@ -2941,10 +2985,27 @@ function Text({ config, devMode, children }) {
|
|
|
2941
2985
|
const processedHtml = isString
|
|
2942
2986
|
? injectLinkStyles(content, contentStyle)
|
|
2943
2987
|
: "";
|
|
2988
|
+
const innerContent = isString ? (jsxRuntime.jsx("div", { style: contentStyle, dangerouslySetInnerHTML: { __html: processedHtml } })) : (jsxRuntime.jsx("div", { style: contentStyle, children: content }));
|
|
2944
2989
|
return (jsxRuntime.jsx("table", { "aria-label": "Text Block Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
2945
2990
|
width: "100%",
|
|
2946
2991
|
borderCollapse: "collapse",
|
|
2947
|
-
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children:
|
|
2992
|
+
}, children: jsxRuntime.jsx("tbody", { children: jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { style: tdStyle, align: textAlign, children: maxWidth ? (
|
|
2993
|
+
/*
|
|
2994
|
+
* maxWidth wrapper — Outlook Classic compatibility pattern:
|
|
2995
|
+
*
|
|
2996
|
+
* <center> instructs the Word rendering engine to horizontally
|
|
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) }) }) }) }));
|
|
2948
3009
|
}
|
|
2949
3010
|
var Text_default = React.memo(Text, arePropsEqual);
|
|
2950
3011
|
|