email-builder-utils 1.1.52 → 1.1.54
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/types/Template.d.ts +2 -0
- package/dist/types/Template.d.ts.map +1 -1
- package/dist/utils/blocks/button.d.ts.map +1 -1
- package/dist/utils/blocks/button.js +28 -30
- package/dist/utils/blocks/dividers.js +30 -30
- package/dist/utils/blocks/grid.d.ts.map +1 -1
- package/dist/utils/blocks/grid.js +76 -76
- package/dist/utils/blocks/image.d.ts.map +1 -1
- package/dist/utils/blocks/image.js +22 -13
- package/dist/utils/blocks/shape.js +89 -89
- package/dist/utils/blocks/text.d.ts.map +1 -1
- package/dist/utils/blocks/text.js +53 -61
- package/dist/utils/blocks/video.js +56 -56
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +4 -1
- package/dist/utils/convertJsonToHtml.js +183 -183
- package/dist/utils/outlookSupport.d.ts.map +1 -1
- package/dist/utils/outlookSupport.js +50 -47
- package/package.json +34 -34
package/dist/types/Template.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Template.d.ts","sourceRoot":"","sources":["../../src/types/Template.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,IAAI,YAAY;IAChB,KAAK,UAAU;IACf,QAAQ,WAAW;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,WAAW,gBAAgB;IAC3B,KAAK,UAAU;IACf,KAAK,UAAU;IACf,QAAQ,aAAa;CACtB;AAED,oBAAY,UAAU;IACpB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,WAAW,gBAAgB;CAC5B;AAED,UAAU,MAAM;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,UAAU,MAAM;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH"}
|
|
1
|
+
{"version":3,"file":"Template.d.ts","sourceRoot":"","sources":["../../src/types/Template.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,IAAI,YAAY;IAChB,KAAK,UAAU;IACf,QAAQ,WAAW;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,WAAW,gBAAgB;IAC3B,KAAK,UAAU;IACf,KAAK,UAAU;IACf,QAAQ,aAAa;CACtB;AAED,oBAAY,UAAU;IACpB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,WAAW,gBAAgB;CAC5B;AAED,UAAU,MAAM;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC;IAC3B,SAAS,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC;CACxB;AAED,UAAU,MAAM;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/button.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/button.ts"],"names":[],"mappings":"AA2IA,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,GAAG,UAuFhD"}
|
|
@@ -55,15 +55,15 @@ function appendOutlookForButton(buttonData) {
|
|
|
55
55
|
const tableMargin = containerAlign === 'center' ? 'margin:0 auto;'
|
|
56
56
|
: containerAlign === 'right' ? 'margin-left:auto;margin-right:0;'
|
|
57
57
|
: '';
|
|
58
|
-
const nonMsoAnchor = `<!--[if !mso]><!-->
|
|
59
|
-
<table border="0" cellpadding="0" cellspacing="0" role="presentation"${tableAlignAttr} style="border-collapse:separate;${tableMargin}">
|
|
60
|
-
<tr>
|
|
61
|
-
<td bgcolor="${bgColor}" align="center" valign="middle"${tdWidthAttr}${tdHeightAttr} style="background-color:${bgColor};border-radius:${br}px;${borderCss}${tdWidthCss}${tdHeightCss}box-sizing:border-box;mso-padding-alt:0;text-align:center;">
|
|
62
|
-
<a href="${safeHref}" target="_blank" rel="noreferrer noopener"
|
|
63
|
-
style="${anchorBoxStyles}color:${safeColor};font-family:${safeFF};font-size:${fs}px;font-weight:${fontWeight};text-decoration:none;text-align:center;white-space:nowrap;-webkit-text-size-adjust:none;box-sizing:border-box;">${text}</a>
|
|
64
|
-
</td>
|
|
65
|
-
</tr>
|
|
66
|
-
</table>
|
|
58
|
+
const nonMsoAnchor = `<!--[if !mso]><!-->
|
|
59
|
+
<table border="0" cellpadding="0" cellspacing="0" role="presentation"${tableAlignAttr} style="border-collapse:separate;${tableMargin}">
|
|
60
|
+
<tr>
|
|
61
|
+
<td bgcolor="${bgColor}" align="center" valign="middle"${tdWidthAttr}${tdHeightAttr} style="background-color:${bgColor};border-radius:${br}px;${borderCss}${tdWidthCss}${tdHeightCss}box-sizing:border-box;mso-padding-alt:0;text-align:center;">
|
|
62
|
+
<a href="${safeHref}" target="_blank" rel="noreferrer noopener"
|
|
63
|
+
style="${anchorBoxStyles}color:${safeColor};font-family:${safeFF};font-size:${fs}px;font-weight:${fontWeight};text-decoration:none;text-align:center;white-space:nowrap;-webkit-text-size-adjust:none;box-sizing:border-box;">${text}</a>
|
|
64
|
+
</td>
|
|
65
|
+
</tr>
|
|
66
|
+
</table>
|
|
67
67
|
<!--<![endif]-->`;
|
|
68
68
|
// ── MSO: VML bulletproof button (classic Outlook / Word engine) ──
|
|
69
69
|
// VML arcsize is a percentage of half the shorter side. Clamp to 50% (pill).
|
|
@@ -71,18 +71,16 @@ function appendOutlookForButton(buttonData) {
|
|
|
71
71
|
const strokeAttrs = bw > 0
|
|
72
72
|
? `stroke="true" strokecolor="${bdColor}" strokeweight="${bw}px"`
|
|
73
73
|
: `stroke="false"`;
|
|
74
|
-
const msoButton = `<!--[if mso]>
|
|
75
|
-
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
|
|
76
|
-
href="${safeHref}"
|
|
77
|
-
style="height:${finalHeight}px;v-text-anchor:middle;width:${vmlWidth}px;"
|
|
78
|
-
arcsize="${arcSizePct}%"
|
|
79
|
-
${strokeAttrs}
|
|
80
|
-
fillcolor="${bgColor}">
|
|
81
|
-
<w:anchorlock/>
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
</v:textbox>
|
|
85
|
-
</v:roundrect>
|
|
74
|
+
const msoButton = `<!--[if mso]>
|
|
75
|
+
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
|
|
76
|
+
href="${safeHref}"
|
|
77
|
+
style="height:${finalHeight}px;v-text-anchor:middle;width:${vmlWidth}px;"
|
|
78
|
+
arcsize="${arcSizePct}%"
|
|
79
|
+
${strokeAttrs}
|
|
80
|
+
fillcolor="${bgColor}">
|
|
81
|
+
<w:anchorlock/>
|
|
82
|
+
<center style="color:${safeColor};font-family:${safeFF};font-size:${fs}px;font-weight:${fontWeight};mso-line-height-rule:exactly;line-height:${fs}px;text-decoration:none;">${text}</center>
|
|
83
|
+
</v:roundrect>
|
|
86
84
|
<![endif]-->`;
|
|
87
85
|
const innerContent = containerAlign === "center"
|
|
88
86
|
? `<center>${msoButton}${nonMsoAnchor}</center>`
|
|
@@ -167,14 +165,14 @@ function convertButtonBlock(blockData) {
|
|
|
167
165
|
hideOnDesktop: Boolean(props.hideOnDesktop),
|
|
168
166
|
hideOnMobile: Boolean(props.hideOnMobile),
|
|
169
167
|
});
|
|
170
|
-
return `
|
|
171
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" class="${visibilityClass}" data-block-type="button" data-block-props="${buttonBlockProps}" style="border-collapse:collapse;table-layout:fixed;">
|
|
172
|
-
<tr>
|
|
173
|
-
<td align="${computed.containerAlign}"${(0, common_1.buildOutlookBgAttr)(containerBg)}
|
|
174
|
-
style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;background-color:${containerBg || 'transparent'};">
|
|
175
|
-
${innerContent}
|
|
176
|
-
</td>
|
|
177
|
-
</tr>
|
|
178
|
-
</table>
|
|
168
|
+
return `
|
|
169
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" class="${visibilityClass}" data-block-type="button" data-block-props="${buttonBlockProps}" style="border-collapse:collapse;table-layout:fixed;">
|
|
170
|
+
<tr>
|
|
171
|
+
<td align="${computed.containerAlign}"${(0, common_1.buildOutlookBgAttr)(containerBg)}
|
|
172
|
+
style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;background-color:${containerBg || 'transparent'};">
|
|
173
|
+
${innerContent}
|
|
174
|
+
</td>
|
|
175
|
+
</tr>
|
|
176
|
+
</table>
|
|
179
177
|
`;
|
|
180
178
|
}
|
|
@@ -21,23 +21,23 @@ function convertDividerBlockToHtml(blockData) {
|
|
|
21
21
|
hideOnMobile ? "hide-mobile" : "",
|
|
22
22
|
hideOnDesktop ? "hide-desktop" : "",
|
|
23
23
|
].filter(Boolean).join(" ");
|
|
24
|
-
const dividerContent = `
|
|
25
|
-
<table
|
|
26
|
-
align="${alignAttr}"
|
|
27
|
-
width="${dividerWidth}%"
|
|
28
|
-
cellpadding="0"
|
|
29
|
-
cellspacing="0"
|
|
30
|
-
style="margin:${alignMargin};"
|
|
31
|
-
>
|
|
32
|
-
<tr>
|
|
33
|
-
<td
|
|
34
|
-
height="${thickness}"
|
|
35
|
-
style="font-size:1px; line-height:1px; background:${dividerColor}; width:100%;"
|
|
36
|
-
>
|
|
37
|
-
|
|
38
|
-
</td>
|
|
39
|
-
</tr>
|
|
40
|
-
</table>
|
|
24
|
+
const dividerContent = `
|
|
25
|
+
<table
|
|
26
|
+
align="${alignAttr}"
|
|
27
|
+
width="${dividerWidth}%"
|
|
28
|
+
cellpadding="0"
|
|
29
|
+
cellspacing="0"
|
|
30
|
+
style="margin:${alignMargin};"
|
|
31
|
+
>
|
|
32
|
+
<tr>
|
|
33
|
+
<td
|
|
34
|
+
height="${thickness}"
|
|
35
|
+
style="font-size:1px; line-height:1px; background:${dividerColor}; width:100%;"
|
|
36
|
+
>
|
|
37
|
+
|
|
38
|
+
</td>
|
|
39
|
+
</tr>
|
|
40
|
+
</table>
|
|
41
41
|
`;
|
|
42
42
|
return (0, outlookSupport_1.appendOutlookSupport)(dividerContent, contentStyle, visibilityClass);
|
|
43
43
|
}
|
|
@@ -55,18 +55,18 @@ function convertVerticalDividerBlockToHtml(blockData) {
|
|
|
55
55
|
perChanges: [],
|
|
56
56
|
pxChanges: buildStyles_1.allPxAttributes,
|
|
57
57
|
});
|
|
58
|
-
return `
|
|
59
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
60
|
-
style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}" data-block-type="vdivider">
|
|
61
|
-
<tr>
|
|
62
|
-
<td style="${outerStyles}; text-align:center; vertical-align:middle;">
|
|
63
|
-
<!--[if mso | IE]>
|
|
64
|
-
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fillcolor="${dividerColor}" style="width:${width}px;height:${height}px;" stroke="f"></v:rect>
|
|
65
|
-
<![endif]-->
|
|
66
|
-
<!--[if !mso]><!-->
|
|
67
|
-
<div style="display:inline-block;width:${width}px;height:${height}px;background:${dividerColor};line-height:0;font-size:0;"> </div>
|
|
68
|
-
<!--<![endif]-->
|
|
69
|
-
</td>
|
|
70
|
-
</tr>
|
|
58
|
+
return `
|
|
59
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
60
|
+
style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}" data-block-type="vdivider">
|
|
61
|
+
<tr>
|
|
62
|
+
<td style="${outerStyles}; text-align:center; vertical-align:middle;">
|
|
63
|
+
<!--[if mso | IE]>
|
|
64
|
+
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fillcolor="${dividerColor}" style="width:${width}px;height:${height}px;" stroke="f"></v:rect>
|
|
65
|
+
<![endif]-->
|
|
66
|
+
<!--[if !mso]><!-->
|
|
67
|
+
<div style="display:inline-block;width:${width}px;height:${height}px;background:${dividerColor};line-height:0;font-size:0;"> </div>
|
|
68
|
+
<!--<![endif]-->
|
|
69
|
+
</td>
|
|
70
|
+
</tr>
|
|
71
71
|
</table>`;
|
|
72
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/grid.ts"],"names":[],"mappings":"AAMA,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/grid.ts"],"names":[],"mappings":"AAMA,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,MAAM,mBA2TtB;AAED,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE,GAAG,EACb,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,EACzB,mBAAmB,UAAQ;;;GAwG5B"}
|
|
@@ -9,7 +9,7 @@ const jsonToHTML_1 = require("../jsonToHTML");
|
|
|
9
9
|
async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
10
10
|
const { style = {}, childrenIds = [], props } = blockData.data;
|
|
11
11
|
const { columns = 1, cellWidths = [], responsive = true } = props;
|
|
12
|
-
const { columnGap = 0, backgroundImage, backgroundColor, ...restStyle } = style;
|
|
12
|
+
const { columnGap = 0, backgroundImage, backgroundColor, cellWidthUnit, ...restStyle } = style;
|
|
13
13
|
const gridVisibilityClass = (0, common_1.getVisibilityClass)(props);
|
|
14
14
|
// Detect gradient — check both backgroundImage prop and customCss (gradient may land in
|
|
15
15
|
// customCss when the block was built via CSS shorthand or custom CSS input).
|
|
@@ -64,6 +64,16 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
64
64
|
perChanges: [],
|
|
65
65
|
pxChanges: buildStyles_1.allPxAttributes,
|
|
66
66
|
});
|
|
67
|
+
// When cellWidthUnit is 'px', convert the stored pixel values to percentage ratios
|
|
68
|
+
// so the rest of the grid export logic (which works entirely in %) is unchanged.
|
|
69
|
+
const effectiveCellWidths = (cellWidthUnit || '%') === 'px'
|
|
70
|
+
? (() => {
|
|
71
|
+
const total = cellWidths.reduce((s, w) => s + w, 0);
|
|
72
|
+
return total > 0
|
|
73
|
+
? cellWidths.map((w) => Number(((w / total) * 100).toFixed(2)))
|
|
74
|
+
: cellWidths.map(() => 100 / columns);
|
|
75
|
+
})()
|
|
76
|
+
: cellWidths;
|
|
67
77
|
const total = childrenIds.length;
|
|
68
78
|
const visualRows = Math.ceil(total / columns);
|
|
69
79
|
// OUTLOOK FIX: Use explicit pixel width for Old Outlook (Word engine)
|
|
@@ -91,18 +101,18 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
91
101
|
: '';
|
|
92
102
|
const divWrapOpen = divBorderStyle ? `<div style="${divBorderStyle}${divWrapBg}">` : '';
|
|
93
103
|
const divWrapClose = divBorderStyle ? `</div>` : '';
|
|
94
|
-
let html = `
|
|
95
|
-
<!--[if mso]>
|
|
96
|
-
<table border="0" cellpadding="0" cellspacing="0" width="${msoTableWidth}"${msoBgAttr}
|
|
97
|
-
style="border-collapse:collapse;width:${msoTableWidth}px;${msoBgStyle}${innerBgTransparent}"
|
|
98
|
-
class="${gridVisibilityClass}">
|
|
99
|
-
<![endif]-->
|
|
100
|
-
<!--[if !mso]><!-->
|
|
101
|
-
<table border="0" cellpadding="0" cellspacing="0" width="100%" align="center"
|
|
102
|
-
role="presentation"${nonMsoBgAttr}
|
|
103
|
-
style="border-collapse:collapse; table-layout:fixed; ${innerBgTransparent}${tableStyles}; max-width:600px;"
|
|
104
|
-
class="${gridVisibilityClass}">
|
|
105
|
-
<!--<![endif]-->
|
|
104
|
+
let html = `
|
|
105
|
+
<!--[if mso]>
|
|
106
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${msoTableWidth}"${msoBgAttr}
|
|
107
|
+
style="border-collapse:collapse;width:${msoTableWidth}px;${msoBgStyle}${innerBgTransparent}"
|
|
108
|
+
class="${gridVisibilityClass}">
|
|
109
|
+
<![endif]-->
|
|
110
|
+
<!--[if !mso]><!-->
|
|
111
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" align="center"
|
|
112
|
+
role="presentation"${nonMsoBgAttr}
|
|
113
|
+
style="border-collapse:collapse; table-layout:fixed; ${innerBgTransparent}${tableStyles}; max-width:600px;"
|
|
114
|
+
class="${gridVisibilityClass}">
|
|
115
|
+
<!--<![endif]-->
|
|
106
116
|
`;
|
|
107
117
|
for (let r = 0; r < visualRows; r++) {
|
|
108
118
|
html += "<tr>";
|
|
@@ -129,7 +139,7 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
129
139
|
const cellWidthPercents = [];
|
|
130
140
|
for (let c = 0; c < columns; c++) {
|
|
131
141
|
const id = rowIds[c];
|
|
132
|
-
let widthPercent =
|
|
142
|
+
let widthPercent = effectiveCellWidths[c] ?? safeWidth;
|
|
133
143
|
if (widthPercent <= 0 || widthPercent > 100) {
|
|
134
144
|
widthPercent = safeWidth;
|
|
135
145
|
}
|
|
@@ -157,57 +167,47 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
157
167
|
const visibilityClass = (0, common_1.getVisibilityClass)(childProps);
|
|
158
168
|
if (childVisible) {
|
|
159
169
|
const { html: childHtml, styles } = await convertGridCellBlock(child, rootData, widthPercent, adjustedTableWidth, Boolean(divBorderStyle));
|
|
160
|
-
// bgcolor on the cell <td>
|
|
161
|
-
//
|
|
162
|
-
// backgroundColor as the fallback so the grid background shows through empty cells.
|
|
163
|
-
// Skipped for border-radius cells — bgcolor is rectangular and would bleed through
|
|
164
|
-
// the div's rounded-corner clip in CSS-capable clients (corner squares).
|
|
170
|
+
// bgcolor on the cell <td> ensures background-color survives Outlook
|
|
171
|
+
// compose paste (Word/Web editors strip CSS but keep bgcolor attribute).
|
|
165
172
|
const cellBgColor = cellStyle.backgroundColor || '';
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
style="width:${widthPercent}%;vertical-align:${verticalAlign};word-break:break-word;${styles}"
|
|
175
|
-
>
|
|
176
|
-
${childHtml}
|
|
173
|
+
const cellBgAttr = (0, common_1.buildOutlookBgAttr)(cellBgColor);
|
|
174
|
+
html += `
|
|
175
|
+
<td
|
|
176
|
+
width="${Math.max(1, Math.round(widthPercent))}%"${cellBgAttr}
|
|
177
|
+
class="${[responsive ? "stack-column" : "", visibilityClass].filter(Boolean).join(" ")}"
|
|
178
|
+
style="width:${widthPercent}%;vertical-align:${verticalAlign};word-break:break-word;${styles}"
|
|
179
|
+
>
|
|
180
|
+
${childHtml}
|
|
177
181
|
</td>`;
|
|
178
182
|
// Spacer td between columns — uses width attribute only (no inline style width) so
|
|
179
183
|
// Outlook mobile (which strips <style>) treats it proportionally, not as a fixed blocker.
|
|
180
184
|
// col-gap-spacer class hides it when columns stack via CSS media query.
|
|
181
185
|
if (columnGap > 0 && c !== lastVisibleCol) {
|
|
182
|
-
|
|
183
|
-
html += `<td width="${columnGap}"${gapBgAttr} class="col-gap-spacer" style="font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
|
|
186
|
+
html += `<td width="${columnGap}" class="col-gap-spacer" style="font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
|
|
184
187
|
}
|
|
185
188
|
}
|
|
186
189
|
}
|
|
187
190
|
else {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
${responsive ? 'class="stack-column"' : ""}
|
|
193
|
-
style="width:${widthPercent}%;vertical-align:top;">
|
|
191
|
+
html += `
|
|
192
|
+
<td width="${Math.max(1, Math.round(widthPercent))}%"
|
|
193
|
+
${responsive ? 'class="stack-column"' : ""}
|
|
194
|
+
style="width:${widthPercent}%;vertical-align:top;">
|
|
194
195
|
</td>`;
|
|
195
196
|
if (columnGap > 0 && c !== lastVisibleCol) {
|
|
196
|
-
|
|
197
|
-
html += `<td width="${columnGap}"${gapBgAttr} class="col-gap-spacer" style="font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
|
|
197
|
+
html += `<td width="${columnGap}" class="col-gap-spacer" style="font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
html += "</tr>";
|
|
202
202
|
}
|
|
203
203
|
// Close both MSO and non-MSO tables
|
|
204
|
-
html += `
|
|
205
|
-
<!--[if mso]>
|
|
206
|
-
</table>
|
|
207
|
-
<![endif]-->
|
|
208
|
-
<!--[if !mso]><!-->
|
|
209
|
-
</table>
|
|
210
|
-
<!--<![endif]-->
|
|
204
|
+
html += `
|
|
205
|
+
<!--[if mso]>
|
|
206
|
+
</table>
|
|
207
|
+
<![endif]-->
|
|
208
|
+
<!--[if !mso]><!-->
|
|
209
|
+
</table>
|
|
210
|
+
<!--<![endif]-->
|
|
211
211
|
`;
|
|
212
212
|
// ── Background image: canonical multi-client approach ────────────────────
|
|
213
213
|
//
|
|
@@ -233,35 +233,35 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
233
233
|
return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
|
|
234
234
|
})()
|
|
235
235
|
: `<v:fill type="frame" src="${rawBgImageUrl}" color="${fallbackBgColor}" />`;
|
|
236
|
-
html = `
|
|
237
|
-
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
|
|
238
|
-
style="border-collapse:collapse;table-layout:fixed;width:100%;max-width:${msoTableWidth}px;">
|
|
239
|
-
<tr>
|
|
240
|
-
<td width="100%"${(0, common_1.buildOutlookBgAttr)(fallbackBgColor)} valign="top"
|
|
241
|
-
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` : ""}
|
|
242
|
-
style="
|
|
243
|
-
width:100%;max-width:${msoTableWidth}px;
|
|
244
|
-
background-color:${fallbackBgColor};
|
|
245
|
-
${isGradient ? `background:${effectiveGradient};` : `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`}
|
|
246
|
-
">
|
|
247
|
-
|
|
248
|
-
<!--[if gte mso 9]>
|
|
249
|
-
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
250
|
-
fill="true" stroke="false"
|
|
251
|
-
style="width:${msoTableWidth}px;">
|
|
252
|
-
${vmlFill}
|
|
253
|
-
<v:textbox inset="0,0,0,0">
|
|
254
|
-
<![endif]-->
|
|
255
|
-
|
|
256
|
-
${html}
|
|
257
|
-
|
|
258
|
-
<!--[if gte mso 9]>
|
|
259
|
-
</v:textbox>
|
|
260
|
-
</v:rect>
|
|
261
|
-
<![endif]-->
|
|
262
|
-
|
|
263
|
-
</td>
|
|
264
|
-
</tr>
|
|
236
|
+
html = `
|
|
237
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
|
|
238
|
+
style="border-collapse:collapse;table-layout:fixed;width:100%;max-width:${msoTableWidth}px;">
|
|
239
|
+
<tr>
|
|
240
|
+
<td width="100%"${(0, common_1.buildOutlookBgAttr)(fallbackBgColor)} valign="top"
|
|
241
|
+
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` : ""}
|
|
242
|
+
style="
|
|
243
|
+
width:100%;max-width:${msoTableWidth}px;
|
|
244
|
+
background-color:${fallbackBgColor};
|
|
245
|
+
${isGradient ? `background:${effectiveGradient};` : `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`}
|
|
246
|
+
">
|
|
247
|
+
|
|
248
|
+
<!--[if gte mso 9]>
|
|
249
|
+
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
250
|
+
fill="true" stroke="false"
|
|
251
|
+
style="width:${msoTableWidth}px;">
|
|
252
|
+
${vmlFill}
|
|
253
|
+
<v:textbox inset="0,0,0,0">
|
|
254
|
+
<![endif]-->
|
|
255
|
+
|
|
256
|
+
${html}
|
|
257
|
+
|
|
258
|
+
<!--[if gte mso 9]>
|
|
259
|
+
</v:textbox>
|
|
260
|
+
</v:rect>
|
|
261
|
+
<![endif]-->
|
|
262
|
+
|
|
263
|
+
</td>
|
|
264
|
+
</tr>
|
|
265
265
|
</table>`;
|
|
266
266
|
}
|
|
267
267
|
// Wrap the entire grid (including any bg-image outer table) in a div when the block
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/image.ts"],"names":[],"mappings":"AAIA,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,mBAAmB,EAAE,MAAM;;;;;GAoB5B;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/image.ts"],"names":[],"mappings":"AAIA,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,mBAAmB,EAAE,MAAM;;;;;GAoB5B;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAyH5E"}
|
|
@@ -28,24 +28,31 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
28
28
|
const { style, props } = blockData.data;
|
|
29
29
|
const { altText, imageUrl, navigateToUrl } = props;
|
|
30
30
|
const visibilityClass = (0, common_1.getVisibilityClass)(props);
|
|
31
|
-
const { width, height, objectFit, borderRadius, borderWidth, borderColor, borderStyle, ...containerStyle } = style;
|
|
31
|
+
const { width, widthUnit, height, objectFit, borderRadius, borderWidth, borderColor, borderStyle, ...containerStyle } = style;
|
|
32
32
|
// Add border styles to container for fallback clients
|
|
33
33
|
const containerStyles = (0, buildStyles_1.buildStyles)({
|
|
34
34
|
...containerStyle,
|
|
35
35
|
}, { perChanges: [], pxChanges: buildStyles_1.addPxToAttributes });
|
|
36
36
|
// OUTLOOK FIX: Ensure cellWidthInPx never exceeds 600px
|
|
37
37
|
const safeCellWidth = Math.min(cellWidthInPx, 600);
|
|
38
|
-
// Parse width percentage (default 100%)
|
|
39
|
-
const widthPercent = typeof width === "string" && width.includes("%")
|
|
40
|
-
? parseInt(width.replace("%", ""))
|
|
41
|
-
: typeof width === "number"
|
|
42
|
-
? width
|
|
43
|
-
: 100;
|
|
44
38
|
// OUTLOOK FIX: Calculate inner container width based on safe cell width
|
|
45
39
|
const paddingLeft = style?.padding?.left || 0;
|
|
46
40
|
const paddingRight = style?.padding?.right || 0;
|
|
47
41
|
const availableWidth = safeCellWidth - paddingLeft - paddingRight;
|
|
48
|
-
|
|
42
|
+
// Resolve inner container width — px values are capped to the available space;
|
|
43
|
+
// % values are a fraction of available space.
|
|
44
|
+
let innerContainerWidth;
|
|
45
|
+
if ((widthUnit || '%') === 'px') {
|
|
46
|
+
innerContainerWidth = Math.min(Math.round(Number(width) || availableWidth), availableWidth);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const widthPercent = typeof width === "string" && width.includes("%")
|
|
50
|
+
? parseInt(width.replace("%", ""))
|
|
51
|
+
: typeof width === "number"
|
|
52
|
+
? width
|
|
53
|
+
: 100;
|
|
54
|
+
innerContainerWidth = Math.round((widthPercent / 100) * availableWidth);
|
|
55
|
+
}
|
|
49
56
|
// Get image dimensions and calculate scaled sizes
|
|
50
57
|
const { originalWidth, originalHeight, scaledWidth, scaledHeight } = await computeScaledDimensions(imageUrl, innerContainerWidth);
|
|
51
58
|
// OUTLOOK FIX: For Outlook, we need exact pixel dimensions
|
|
@@ -71,11 +78,13 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
71
78
|
// -ms-interpolation-mode → inline fallback; the <style> block is stripped by
|
|
72
79
|
// Outlook during forward/reply MIME rewriting
|
|
73
80
|
const imageElement = `<img src="${imageUrl}" alt="${altText || "Image"}" border="0" width="${finalWidth}" height="${finalHeight}" style="${imageTagStyles}; display:block; width:${finalWidth}px; height:${finalHeight}px; max-width:100%; line-height:0; -ms-interpolation-mode:bicubic;" />`;
|
|
74
|
-
const percentWidth =
|
|
75
|
-
?
|
|
76
|
-
: typeof width === "
|
|
77
|
-
?
|
|
78
|
-
: "
|
|
81
|
+
const percentWidth = (widthUnit || '%') === 'px'
|
|
82
|
+
? `${innerContainerWidth}px`
|
|
83
|
+
: typeof width === "string" && width.endsWith("%")
|
|
84
|
+
? width
|
|
85
|
+
: typeof width === "number"
|
|
86
|
+
? `${width}%`
|
|
87
|
+
: "100%";
|
|
79
88
|
// Non-MSO wrapper: display:block removes the phantom inline-baseline gap that
|
|
80
89
|
// display:inline-block creates in Gmail / Apple Mail / Yahoo between images.
|
|
81
90
|
// margin handles alignment since text-align won't move block elements.
|