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
|
@@ -33,23 +33,23 @@ function buildVMLShape({ shape, widthPx, heightPx, imageUrl, backgroundColor, bo
|
|
|
33
33
|
const hAlign = hAlignMap[textAlign] || "center";
|
|
34
34
|
const safeFontSize = Math.max(Math.round(textSize), 10);
|
|
35
35
|
const textboxMarkup = text && !msoHasBakedText
|
|
36
|
-
? `<v:textbox inset="6pt,6pt,6pt,6pt" style="mso-fit-shape-to-text:false;">
|
|
37
|
-
<div style="display:table;width:100%;height:100%;">
|
|
38
|
-
<div style="display:table-cell;vertical-align:${vAlign};text-align:${hAlign};padding:0 6px;">
|
|
39
|
-
<div style="color:${textColor};font-family:Arial, sans-serif;font-size:${safeFontSize}px;line-height:1.3;word-wrap:break-word;">
|
|
40
|
-
${text}
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
36
|
+
? `<v:textbox inset="6pt,6pt,6pt,6pt" style="mso-fit-shape-to-text:false;">
|
|
37
|
+
<div style="display:table;width:100%;height:100%;">
|
|
38
|
+
<div style="display:table-cell;vertical-align:${vAlign};text-align:${hAlign};padding:0 6px;">
|
|
39
|
+
<div style="color:${textColor};font-family:Arial, sans-serif;font-size:${safeFontSize}px;line-height:1.3;word-wrap:break-word;">
|
|
40
|
+
${text}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
44
|
</v:textbox>`
|
|
45
45
|
: `<v:textbox inset="0,0,0,0"><div style="display:none;">.</div></v:textbox>`;
|
|
46
|
-
return `
|
|
47
|
-
<v:${tag} xmlns:v="urn:schemas-microsoft-com:vml"
|
|
48
|
-
style="width:${widthPx}px;height:${heightPx}px;display:inline-block;"
|
|
49
|
-
${borderAttrs}
|
|
50
|
-
fill="true" fillcolor="${fillColor}"${extraAttr}>
|
|
51
|
-
${fillMarkup}
|
|
52
|
-
${textboxMarkup}
|
|
46
|
+
return `
|
|
47
|
+
<v:${tag} xmlns:v="urn:schemas-microsoft-com:vml"
|
|
48
|
+
style="width:${widthPx}px;height:${heightPx}px;display:inline-block;"
|
|
49
|
+
${borderAttrs}
|
|
50
|
+
fill="true" fillcolor="${fillColor}"${extraAttr}>
|
|
51
|
+
${fillMarkup}
|
|
52
|
+
${textboxMarkup}
|
|
53
53
|
</v:${tag}>`;
|
|
54
54
|
}
|
|
55
55
|
function appendOutlookForShape(content, outerContainerWidth, innerContainerWidth, opts, visibilityClass) {
|
|
@@ -70,28 +70,28 @@ function appendOutlookForShape(content, outerContainerWidth, innerContainerWidth
|
|
|
70
70
|
const valign = opts.verticalAlign || "middle";
|
|
71
71
|
const shouldHideInOutlook = visibilityClass.includes("hide-desktop");
|
|
72
72
|
if (shouldHideInOutlook) {
|
|
73
|
-
return `<!--[if !mso]><!-->
|
|
74
|
-
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
75
|
-
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
76
|
-
<tr>
|
|
77
|
-
<td valign="${valign}"
|
|
78
|
-
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
79
|
-
${vml}
|
|
80
|
-
</td>
|
|
81
|
-
</tr>
|
|
82
|
-
</table>
|
|
73
|
+
return `<!--[if !mso]><!-->
|
|
74
|
+
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
75
|
+
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
76
|
+
<tr>
|
|
77
|
+
<td valign="${valign}"
|
|
78
|
+
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
79
|
+
${vml}
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
</table>
|
|
83
83
|
<!--<![endif]-->`;
|
|
84
84
|
}
|
|
85
|
-
return `<!--[if mso]>
|
|
86
|
-
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
87
|
-
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
88
|
-
<tr>
|
|
89
|
-
<td valign="${valign}"
|
|
90
|
-
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
91
|
-
${vml}
|
|
92
|
-
</td>
|
|
93
|
-
</tr>
|
|
94
|
-
</table>
|
|
85
|
+
return `<!--[if mso]>
|
|
86
|
+
<table align="${align}" border="0" cellpadding="0" cellspacing="0"
|
|
87
|
+
style="width:${widthPx}px;height:${heightPx}px;border-collapse:collapse;" class="${visibilityClass}">
|
|
88
|
+
<tr>
|
|
89
|
+
<td valign="${valign}"
|
|
90
|
+
style="padding:${pad.top || 0}px ${pad.right || 0}px ${pad.bottom || 0}px ${pad.left || 0}px;">
|
|
91
|
+
${vml}
|
|
92
|
+
</td>
|
|
93
|
+
</tr>
|
|
94
|
+
</table>
|
|
95
95
|
<![endif]-->`;
|
|
96
96
|
}
|
|
97
97
|
async function convertShapeBlock(blockData) {
|
|
@@ -146,58 +146,58 @@ async function convertShapeBlock(blockData) {
|
|
|
146
146
|
let nonMsoContent = "";
|
|
147
147
|
// --- Case 1: Image + Text ---
|
|
148
148
|
if (imageUrl && text) {
|
|
149
|
-
nonMsoContent = `
|
|
150
|
-
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;max-width:100%;box-sizing:border-box;
|
|
151
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
152
|
-
border-radius:${resolvedBorderRadius};
|
|
153
|
-
background-color:${finalBackgroundColor};
|
|
154
|
-
background-image:url('${imageUrl}');
|
|
155
|
-
background-position:center center;
|
|
156
|
-
background-size:cover;
|
|
157
|
-
background-repeat:no-repeat;
|
|
158
|
-
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
159
|
-
<table border="0" cellpadding="0" cellspacing="0" width="100%"
|
|
160
|
-
style="width:100%;height:${resolvedHeightPx}px;border-collapse:collapse;">
|
|
161
|
-
<tr>
|
|
162
|
-
<td align="${textAlignStyle}" valign="${verticalAlign}"
|
|
163
|
-
height="${resolvedHeightPx}"
|
|
164
|
-
style="padding:6px;vertical-align:${verticalAlign};text-align:${textAlignStyle};overflow:hidden;box-sizing:border-box;">
|
|
165
|
-
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">${text}</div>
|
|
166
|
-
</td>
|
|
167
|
-
</tr>
|
|
168
|
-
</table>
|
|
149
|
+
nonMsoContent = `
|
|
150
|
+
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;max-width:100%;box-sizing:border-box;
|
|
151
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
152
|
+
border-radius:${resolvedBorderRadius};
|
|
153
|
+
background-color:${finalBackgroundColor};
|
|
154
|
+
background-image:url('${imageUrl}');
|
|
155
|
+
background-position:center center;
|
|
156
|
+
background-size:cover;
|
|
157
|
+
background-repeat:no-repeat;
|
|
158
|
+
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
159
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%"
|
|
160
|
+
style="width:100%;height:${resolvedHeightPx}px;border-collapse:collapse;">
|
|
161
|
+
<tr>
|
|
162
|
+
<td align="${textAlignStyle}" valign="${verticalAlign}"
|
|
163
|
+
height="${resolvedHeightPx}"
|
|
164
|
+
style="padding:6px;vertical-align:${verticalAlign};text-align:${textAlignStyle};overflow:hidden;box-sizing:border-box;">
|
|
165
|
+
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">${text}</div>
|
|
166
|
+
</td>
|
|
167
|
+
</tr>
|
|
168
|
+
</table>
|
|
169
169
|
</div>`;
|
|
170
170
|
}
|
|
171
171
|
// --- Case 2: Image only ---
|
|
172
172
|
else if (imageUrl) {
|
|
173
|
-
nonMsoContent = `
|
|
174
|
-
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;max-width:100%;box-sizing:border-box;
|
|
175
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
176
|
-
border-radius:${resolvedBorderRadius};
|
|
177
|
-
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
178
|
-
<img src="${imageUrl}" alt="${text || "shape image"}"
|
|
179
|
-
width="${resolvedWidthPx}" height="${resolvedHeightPx}"
|
|
180
|
-
style="width:100%;height:100%;object-fit:cover;border-radius:${resolvedBorderRadius};display:block;" />
|
|
173
|
+
nonMsoContent = `
|
|
174
|
+
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;max-width:100%;box-sizing:border-box;
|
|
175
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
176
|
+
border-radius:${resolvedBorderRadius};
|
|
177
|
+
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
178
|
+
<img src="${imageUrl}" alt="${text || "shape image"}"
|
|
179
|
+
width="${resolvedWidthPx}" height="${resolvedHeightPx}"
|
|
180
|
+
style="width:100%;height:100%;object-fit:cover;border-radius:${resolvedBorderRadius};display:block;" />
|
|
181
181
|
</div>`;
|
|
182
182
|
}
|
|
183
183
|
// --- Case 3: Text only ---
|
|
184
184
|
else {
|
|
185
|
-
nonMsoContent = `
|
|
186
|
-
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;max-width:100%;box-sizing:border-box;
|
|
187
|
-
background-color:${finalBackgroundColor};
|
|
188
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
189
|
-
border-radius:${resolvedBorderRadius};
|
|
190
|
-
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
191
|
-
<table border="0" cellpadding="0" cellspacing="0" width="100%"
|
|
192
|
-
style="width:100%;height:${resolvedHeightPx}px;border-collapse:collapse;">
|
|
193
|
-
<tr>
|
|
194
|
-
<td align="${textAlignStyle}" valign="${verticalAlign}"
|
|
195
|
-
height="${resolvedHeightPx}"
|
|
196
|
-
style="padding:8px;vertical-align:${verticalAlign};text-align:${textAlignStyle};box-sizing:border-box;">
|
|
197
|
-
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">${text || ""}</div>
|
|
198
|
-
</td>
|
|
199
|
-
</tr>
|
|
200
|
-
</table>
|
|
185
|
+
nonMsoContent = `
|
|
186
|
+
<div style="display:inline-block;width:${resolvedWidthPx}px;height:${resolvedHeightPx}px;max-width:100%;box-sizing:border-box;
|
|
187
|
+
background-color:${finalBackgroundColor};
|
|
188
|
+
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
189
|
+
border-radius:${resolvedBorderRadius};
|
|
190
|
+
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
191
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%"
|
|
192
|
+
style="width:100%;height:${resolvedHeightPx}px;border-collapse:collapse;">
|
|
193
|
+
<tr>
|
|
194
|
+
<td align="${textAlignStyle}" valign="${verticalAlign}"
|
|
195
|
+
height="${resolvedHeightPx}"
|
|
196
|
+
style="padding:8px;vertical-align:${verticalAlign};text-align:${textAlignStyle};box-sizing:border-box;">
|
|
197
|
+
<div style="${textSizeStyle}text-align:${textAlignStyle};max-width:90%;overflow:hidden;">${text || ""}</div>
|
|
198
|
+
</td>
|
|
199
|
+
</tr>
|
|
200
|
+
</table>
|
|
201
201
|
</div>`;
|
|
202
202
|
}
|
|
203
203
|
// Outlook (VML) fallback
|
|
@@ -242,15 +242,15 @@ async function convertShapeBlock(blockData) {
|
|
|
242
242
|
hideOnMobile: Boolean(props.hideOnMobile),
|
|
243
243
|
});
|
|
244
244
|
// Combine into table wrapper
|
|
245
|
-
return `
|
|
246
|
-
<table width="100%" style="border-collapse:collapse;table-layout:fixed;max-width:600px;" class="${visibilityClass}" data-block-type="shape" data-block-props="${shapeBlockProps}">
|
|
247
|
-
<tr>
|
|
248
|
-
<td style="padding:${padding.top || 0}px ${padding.right || 0}px ${padding.bottom || 0}px ${padding.left || 0}px;text-align:${alignment};">
|
|
249
|
-
${outlookContent}
|
|
250
|
-
<!--[if !mso]><!-->
|
|
251
|
-
${nonMsoContent}
|
|
252
|
-
<!--<![endif]-->
|
|
253
|
-
</td>
|
|
254
|
-
</tr>
|
|
245
|
+
return `
|
|
246
|
+
<table width="100%" style="border-collapse:collapse;table-layout:fixed;max-width:600px;" class="${visibilityClass}" data-block-type="shape" data-block-props="${shapeBlockProps}">
|
|
247
|
+
<tr>
|
|
248
|
+
<td style="padding:${padding.top || 0}px ${padding.right || 0}px ${padding.bottom || 0}px ${padding.left || 0}px;text-align:${alignment};">
|
|
249
|
+
${outlookContent}
|
|
250
|
+
<!--[if !mso]><!-->
|
|
251
|
+
${nonMsoContent}
|
|
252
|
+
<!--<![endif]-->
|
|
253
|
+
</td>
|
|
254
|
+
</tr>
|
|
255
255
|
</table>`;
|
|
256
256
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/text.ts"],"names":[],"mappings":"AASA,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/text.ts"],"names":[],"mappings":"AASA,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,MAAM,UAoKtE"}
|
|
@@ -13,24 +13,22 @@ function convertTextBlock(blockData, cellWidthInPx) {
|
|
|
13
13
|
// Detect background image or gradient (may live in backgroundImage or customCss).
|
|
14
14
|
// Same multi-client approach as Grid block: outer wrapper <td> carries the background
|
|
15
15
|
// via CSS (Gmail/New Outlook), background attribute (Yahoo), and VML (Old Outlook).
|
|
16
|
-
const bgImageStr = typeof backgroundImage ===
|
|
17
|
-
const customCssStr = rest.customCss ||
|
|
18
|
-
const gradientInCustomCss = !bgImageStr.includes(
|
|
19
|
-
? customCssStr.match(/(?:linear|radial|conic)-gradient\([^)]+(?:\([^)]*\)[^)]*)*\)/)?.[0] ||
|
|
20
|
-
:
|
|
21
|
-
const effectiveGradient = bgImageStr.includes(
|
|
22
|
-
? bgImageStr
|
|
23
|
-
: gradientInCustomCss;
|
|
16
|
+
const bgImageStr = typeof backgroundImage === 'string' ? backgroundImage : '';
|
|
17
|
+
const customCssStr = rest.customCss || '';
|
|
18
|
+
const gradientInCustomCss = !bgImageStr.includes('gradient(') && customCssStr.includes('gradient(')
|
|
19
|
+
? (customCssStr.match(/(?:linear|radial|conic)-gradient\([^)]+(?:\([^)]*\)[^)]*)*\)/)?.[0] || '')
|
|
20
|
+
: '';
|
|
21
|
+
const effectiveGradient = bgImageStr.includes('gradient(') ? bgImageStr : gradientInCustomCss;
|
|
24
22
|
const isGradient = Boolean(effectiveGradient);
|
|
25
23
|
const parsedGradient = isGradient ? (0, gradientUtils_1.parseGradient)(effectiveGradient) : null;
|
|
26
24
|
const rawBgImageUrl = !isGradient && bgImageStr
|
|
27
|
-
? bgImageStr.replace(/^url\(['"]?/,
|
|
25
|
+
? bgImageStr.replace(/^url\(['"]?/, '').replace(/['"]?\)$/, '')
|
|
28
26
|
: null;
|
|
29
27
|
const hasBgImage = Boolean(rawBgImageUrl || isGradient);
|
|
30
28
|
const fallbackBgColor = textContainerBackgroundColor ||
|
|
31
29
|
parsedGradient?.fallback ||
|
|
32
30
|
(0, gradientUtils_1.extractCssFallbackColor)(customCssStr) ||
|
|
33
|
-
|
|
31
|
+
'#ffffff';
|
|
34
32
|
// Text box decoration styles (border, background, padding) — no width
|
|
35
33
|
const textBoxStyle = {
|
|
36
34
|
backgroundColor,
|
|
@@ -46,11 +44,9 @@ function convertTextBlock(blockData, cellWidthInPx) {
|
|
|
46
44
|
});
|
|
47
45
|
// Strip gradient from customCss when it is hoisted to the outer bg wrapper.
|
|
48
46
|
const innerCustomCss = gradientInCustomCss
|
|
49
|
-
? customCssStr.replace(/background-image\s*:[^;]+;?/gi,
|
|
47
|
+
? customCssStr.replace(/background-image\s*:[^;]+;?/gi, '').trim()
|
|
50
48
|
: customCssStr;
|
|
51
|
-
const restForStyles = gradientInCustomCss
|
|
52
|
-
? { ...rest, customCss: innerCustomCss }
|
|
53
|
-
: rest;
|
|
49
|
+
const restForStyles = gradientInCustomCss ? { ...rest, customCss: innerCustomCss } : rest;
|
|
54
50
|
// Outer td styles: strip container background when a bg-image wrapper is present
|
|
55
51
|
// so the outer wrapper's background is not double-applied.
|
|
56
52
|
const styles = (0, buildStyles_1.buildStyles)({
|
|
@@ -62,41 +58,37 @@ function convertTextBlock(blockData, cellWidthInPx) {
|
|
|
62
58
|
pxChanges: buildStyles_1.allPxAttributes,
|
|
63
59
|
});
|
|
64
60
|
const sanitizedText = (props.text ?? "")
|
|
65
|
-
.replace(/<p(\s[^>]*)?>/gi, (_, attrs) => `<div${attrs || ""}>`)
|
|
61
|
+
.replace(/<p(\s[^>]*)?>/gi, (_, attrs = "") => `<div${attrs || ""}>`)
|
|
66
62
|
.replace(/<\/p>/gi, "</div>");
|
|
67
63
|
const navigateToUrl = props.navigateToUrl || "";
|
|
68
64
|
const fontSizeStyle = fontSize != null ? `font-size:${fontSize}px;` : "";
|
|
69
|
-
// Email clients apply `a { color: blue }` which
|
|
70
|
-
// Inject
|
|
65
|
+
// Email clients apply `a { color: blue; text-decoration: underline }` which
|
|
66
|
+
// overrides inherited styles. Inject block color (if available) and reset
|
|
67
|
+
// text-decoration so inline links match the surrounding text appearance.
|
|
71
68
|
const blockTextColor = rest.color;
|
|
72
|
-
const processedText =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const colorStyle = blockTextColor ? `color:${blockTextColor};` : "";
|
|
69
|
+
const processedText = sanitizedText.replace(/<a(\s[^>]*)?>/gi, (_match, attrs = '') => {
|
|
70
|
+
const hasExistingColor = /style\s*=\s*["'][^"']*\bcolor\s*:/i.test(attrs);
|
|
71
|
+
const colorPart = (!hasExistingColor && blockTextColor) ? `color:${blockTextColor};` : '';
|
|
72
|
+
const injected = `${colorPart}text-decoration:none;`;
|
|
73
|
+
if (/\bstyle\s*=/i.test(attrs)) {
|
|
74
|
+
return `<a${attrs.replace(/(\bstyle\s*=\s*["'])/, `$1${injected}`)}>`;
|
|
75
|
+
}
|
|
76
|
+
return `<a${attrs} style="${injected}">`;
|
|
77
|
+
});
|
|
78
|
+
const colorStyle = blockTextColor ? `color:${blockTextColor};` : '';
|
|
83
79
|
// Use display:block + width:100% so text fills the column naturally.
|
|
84
80
|
// display:inline-block with a pixel width (e.g. 400px) breaks narrow grid cells.
|
|
85
81
|
const convertedTextBox = `<div style="display:block; width:100%; box-sizing:border-box; ${colorStyle}${fontSizeStyle}${convertedTextStyle}">${processedText.replaceAll(/\n/g, "<br>")}</div>`;
|
|
86
|
-
const safeCellWidth = cellWidthInPx
|
|
87
|
-
? Math.min(cellWidthInPx, 600)
|
|
88
|
-
: undefined;
|
|
82
|
+
const safeCellWidth = cellWidthInPx ? Math.min(cellWidthInPx, 600) : undefined;
|
|
89
83
|
// When a bg-image wrapper is present, visibilityClass moves to the outer table.
|
|
90
|
-
const textContent = (0, outlookSupport_1.appendOutlookSupport)(convertedTextBox, styles, hasBgImage ?
|
|
91
|
-
const linkColorStyle = blockTextColor
|
|
92
|
-
? `color:${blockTextColor};`
|
|
93
|
-
: "color:inherit;";
|
|
84
|
+
const textContent = (0, outlookSupport_1.appendOutlookSupport)(convertedTextBox, styles, hasBgImage ? '' : visibilityClass, safeCellWidth);
|
|
85
|
+
const linkColorStyle = blockTextColor ? `color:${blockTextColor};` : 'color:inherit;';
|
|
94
86
|
if (hasBgImage) {
|
|
95
87
|
const msoWidth = cellWidthInPx ? Math.min(cellWidthInPx, 600) : 600;
|
|
96
88
|
const vmlFill = isGradient
|
|
97
89
|
? (() => {
|
|
98
90
|
const vmlAngle = (0, gradientUtils_1.cssAngleToVml)(parsedGradient?.angle || 180);
|
|
99
|
-
const c1 = parsedGradient?.fallback ||
|
|
91
|
+
const c1 = parsedGradient?.fallback || '#ffffff';
|
|
100
92
|
const c2 = parsedGradient?.colors[parsedGradient.colors.length - 1] || c1;
|
|
101
93
|
return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
|
|
102
94
|
})()
|
|
@@ -104,31 +96,31 @@ function convertTextBlock(blockData, cellWidthInPx) {
|
|
|
104
96
|
const bgCss = isGradient
|
|
105
97
|
? `background:${effectiveGradient};`
|
|
106
98
|
: `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`;
|
|
107
|
-
const wrappedContent = `
|
|
108
|
-
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
|
|
109
|
-
style="border-collapse:collapse;width:100%;max-width:${msoWidth}px;" class="${visibilityClass}">
|
|
110
|
-
<tr>
|
|
111
|
-
<td width="100%"${(0, common_1.buildOutlookBgAttr)(fallbackBgColor)} valign="top"
|
|
112
|
-
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` :
|
|
113
|
-
style="width:100%;max-width:${msoWidth}px;background-color:${fallbackBgColor};${bgCss}">
|
|
114
|
-
|
|
115
|
-
<!--[if gte mso 9]>
|
|
116
|
-
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
117
|
-
fill="true" stroke="false"
|
|
118
|
-
style="width:${msoWidth}px;">
|
|
119
|
-
${vmlFill}
|
|
120
|
-
<v:textbox inset="0,0,0,0">
|
|
121
|
-
<![endif]-->
|
|
122
|
-
|
|
123
|
-
${textContent}
|
|
124
|
-
|
|
125
|
-
<!--[if gte mso 9]>
|
|
126
|
-
</v:textbox>
|
|
127
|
-
</v:rect>
|
|
128
|
-
<![endif]-->
|
|
129
|
-
|
|
130
|
-
</td>
|
|
131
|
-
</tr>
|
|
99
|
+
const wrappedContent = `
|
|
100
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
|
|
101
|
+
style="border-collapse:collapse;width:100%;max-width:${msoWidth}px;" class="${visibilityClass}">
|
|
102
|
+
<tr>
|
|
103
|
+
<td width="100%"${(0, common_1.buildOutlookBgAttr)(fallbackBgColor)} valign="top"
|
|
104
|
+
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` : ''}
|
|
105
|
+
style="width:100%;max-width:${msoWidth}px;background-color:${fallbackBgColor};${bgCss}">
|
|
106
|
+
|
|
107
|
+
<!--[if gte mso 9]>
|
|
108
|
+
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
109
|
+
fill="true" stroke="false"
|
|
110
|
+
style="width:${msoWidth}px;">
|
|
111
|
+
${vmlFill}
|
|
112
|
+
<v:textbox inset="0,0,0,0">
|
|
113
|
+
<![endif]-->
|
|
114
|
+
|
|
115
|
+
${textContent}
|
|
116
|
+
|
|
117
|
+
<!--[if gte mso 9]>
|
|
118
|
+
</v:textbox>
|
|
119
|
+
</v:rect>
|
|
120
|
+
<![endif]-->
|
|
121
|
+
|
|
122
|
+
</td>
|
|
123
|
+
</tr>
|
|
132
124
|
</table>`;
|
|
133
125
|
return navigateToUrl
|
|
134
126
|
? `<a href="${navigateToUrl}" rel="noreferrer noopener" style="${linkColorStyle}text-decoration:none;cursor:pointer;">${wrappedContent}</a>`
|
|
@@ -88,64 +88,64 @@ async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
|
88
88
|
// min-height fallback for clients that ignore the spacer GIF (e.g. some webmail).
|
|
89
89
|
const minHeight = Math.round(thumbnailW * 0.3);
|
|
90
90
|
// VML block — shown only in Outlook (Word engine supports VML, not standard HTML).
|
|
91
|
-
const outlookContent = hideOnDesktop ? '' : `<!--[if vml]>
|
|
92
|
-
<v:group xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
|
|
93
|
-
coordsize="${thumbnailW},${thumbnailH}" coordorigin="0,0"
|
|
94
|
-
href="${videoLink}"
|
|
95
|
-
style="width:${thumbnailW}px;height:${thumbnailH}px;">
|
|
96
|
-
<v:rect fill="t" stroked="f" style="position:absolute;width:${thumbnailW};height:${thumbnailH};">
|
|
97
|
-
<v:fill src="${resolvedThumbnail}" type="frame"/>
|
|
98
|
-
</v:rect>
|
|
99
|
-
<v:oval fill="t" strokecolor="#ffffff" strokeweight="3px"
|
|
100
|
-
style="position:absolute;left:${ovalLeft};top:${ovalTop};width:${ovalSize};height:${ovalSize}">
|
|
101
|
-
<v:fill color="#ffffff" opacity="100%" />
|
|
102
|
-
</v:oval>
|
|
103
|
-
<v:shape coordsize="24,32" path="m,l,32,24,16,xe" fillcolor="#000000" stroked="f"
|
|
104
|
-
style="position:absolute;left:${triLeft};top:${triTop};width:${triW};height:${triH};" />
|
|
105
|
-
</v:group>
|
|
91
|
+
const outlookContent = hideOnDesktop ? '' : `<!--[if vml]>
|
|
92
|
+
<v:group xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
|
|
93
|
+
coordsize="${thumbnailW},${thumbnailH}" coordorigin="0,0"
|
|
94
|
+
href="${videoLink}"
|
|
95
|
+
style="width:${thumbnailW}px;height:${thumbnailH}px;">
|
|
96
|
+
<v:rect fill="t" stroked="f" style="position:absolute;width:${thumbnailW};height:${thumbnailH};">
|
|
97
|
+
<v:fill src="${resolvedThumbnail}" type="frame"/>
|
|
98
|
+
</v:rect>
|
|
99
|
+
<v:oval fill="t" strokecolor="#ffffff" strokeweight="3px"
|
|
100
|
+
style="position:absolute;left:${ovalLeft};top:${ovalTop};width:${ovalSize};height:${ovalSize}">
|
|
101
|
+
<v:fill color="#ffffff" opacity="100%" />
|
|
102
|
+
</v:oval>
|
|
103
|
+
<v:shape coordsize="24,32" path="m,l,32,24,16,xe" fillcolor="#000000" stroked="f"
|
|
104
|
+
style="position:absolute;left:${triLeft};top:${triTop};width:${triW};height:${triH};" />
|
|
105
|
+
</v:group>
|
|
106
106
|
<![endif]-->`;
|
|
107
107
|
// Non-VML block — shown in all clients except Outlook.
|
|
108
|
-
const nonMsoContent = `<!--[if !vml]><!-->
|
|
109
|
-
<a href="${videoLink}" target="_blank"
|
|
110
|
-
style="display:block; text-decoration:none; background-image:url('${resolvedThumbnail}'); background-size:cover; background-position:center; ${borderCss}${radiusCss}">
|
|
111
|
-
<table cellpadding="0" cellspacing="0" border="0" width="100%"
|
|
112
|
-
background="${resolvedThumbnail}"
|
|
113
|
-
role="presentation"
|
|
114
|
-
style="background-image:url('${resolvedThumbnail}'); background-size:cover; background-position:center center; background-repeat:no-repeat; min-height:${minHeight}px;">
|
|
115
|
-
<tr>
|
|
116
|
-
<td width="25%" style="line-height:0; font-size:0; padding:0;">
|
|
117
|
-
<img src="${SPACER_GIF_URL}" width="100%" border="0" alt=""
|
|
118
|
-
style="display:block; height:auto; opacity:0; visibility:hidden;" />
|
|
119
|
-
</td>
|
|
120
|
-
<td width="50%" align="center" valign="middle"
|
|
121
|
-
style="text-align:center; vertical-align:middle; padding:0;">
|
|
122
|
-
<img src="${PLAY_ICON_URL}" width="${playIconW}" height="${playIconH}" alt="Play"
|
|
123
|
-
style="display:block; width:${playIconW}px; height:${playIconH}px; border:0; margin:0 auto;" />
|
|
124
|
-
</td>
|
|
125
|
-
<td width="25%" style="padding:0;"> </td>
|
|
126
|
-
</tr>
|
|
127
|
-
</table>
|
|
128
|
-
</a>
|
|
108
|
+
const nonMsoContent = `<!--[if !vml]><!-->
|
|
109
|
+
<a href="${videoLink}" target="_blank"
|
|
110
|
+
style="display:block; text-decoration:none; background-image:url('${resolvedThumbnail}'); background-size:cover; background-position:center; ${borderCss}${radiusCss}">
|
|
111
|
+
<table cellpadding="0" cellspacing="0" border="0" width="100%"
|
|
112
|
+
background="${resolvedThumbnail}"
|
|
113
|
+
role="presentation"
|
|
114
|
+
style="background-image:url('${resolvedThumbnail}'); background-size:cover; background-position:center center; background-repeat:no-repeat; min-height:${minHeight}px;">
|
|
115
|
+
<tr>
|
|
116
|
+
<td width="25%" style="line-height:0; font-size:0; padding:0;">
|
|
117
|
+
<img src="${SPACER_GIF_URL}" width="100%" border="0" alt=""
|
|
118
|
+
style="display:block; height:auto; opacity:0; visibility:hidden;" />
|
|
119
|
+
</td>
|
|
120
|
+
<td width="50%" align="center" valign="middle"
|
|
121
|
+
style="text-align:center; vertical-align:middle; padding:0;">
|
|
122
|
+
<img src="${PLAY_ICON_URL}" width="${playIconW}" height="${playIconH}" alt="Play"
|
|
123
|
+
style="display:block; width:${playIconW}px; height:${playIconH}px; border:0; margin:0 auto;" />
|
|
124
|
+
</td>
|
|
125
|
+
<td width="25%" style="padding:0;"> </td>
|
|
126
|
+
</tr>
|
|
127
|
+
</table>
|
|
128
|
+
</a>
|
|
129
129
|
<!--<![endif]-->`;
|
|
130
|
-
return `
|
|
131
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
132
|
-
style="border-collapse:collapse; max-width:600px; margin:0; padding:0;"
|
|
133
|
-
class="${visibilityClass}" data-block-type="video"
|
|
134
|
-
data-video-url="${videoUrl || ''}" data-youtube-url="${youtubeVideoUrl || ''}"
|
|
135
|
-
data-thumbnail-url="${thumbnailUrl || ''}" data-alt-text="${altText || ''}"
|
|
136
|
-
data-width="${typeof style?.width === 'number' ? style.width : 100}">
|
|
137
|
-
<tr>
|
|
138
|
-
<td align="${align}" style="${outerContainerStyles}">
|
|
139
|
-
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
140
|
-
align="${align}"
|
|
141
|
-
style="border-collapse:collapse; max-width:${thumbnailW}px; width:${percentWidth};">
|
|
142
|
-
<tr>
|
|
143
|
-
<td align="${align}" style="padding:0;">
|
|
144
|
-
${outlookContent}${nonMsoContent}
|
|
145
|
-
</td>
|
|
146
|
-
</tr>
|
|
147
|
-
</table>
|
|
148
|
-
</td>
|
|
149
|
-
</tr>
|
|
130
|
+
return `
|
|
131
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
132
|
+
style="border-collapse:collapse; max-width:600px; margin:0; padding:0;"
|
|
133
|
+
class="${visibilityClass}" data-block-type="video"
|
|
134
|
+
data-video-url="${videoUrl || ''}" data-youtube-url="${youtubeVideoUrl || ''}"
|
|
135
|
+
data-thumbnail-url="${thumbnailUrl || ''}" data-alt-text="${altText || ''}"
|
|
136
|
+
data-width="${typeof style?.width === 'number' ? style.width : 100}">
|
|
137
|
+
<tr>
|
|
138
|
+
<td align="${align}" style="${outerContainerStyles}">
|
|
139
|
+
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
140
|
+
align="${align}"
|
|
141
|
+
style="border-collapse:collapse; max-width:${thumbnailW}px; width:${percentWidth};">
|
|
142
|
+
<tr>
|
|
143
|
+
<td align="${align}" style="padding:0;">
|
|
144
|
+
${outlookContent}${nonMsoContent}
|
|
145
|
+
</td>
|
|
146
|
+
</tr>
|
|
147
|
+
</table>
|
|
148
|
+
</td>
|
|
149
|
+
</tr>
|
|
150
150
|
</table>`;
|
|
151
151
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAqBvD,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAIrD,CAAC;AAGF,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,UASA;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAQvE;
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAqBvD,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAIrD,CAAC;AAGF,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,UASA;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAQvE;AAcD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGxD"}
|
package/dist/utils/common.js
CHANGED
|
@@ -57,8 +57,11 @@ function encodeBlockPropsAttr(props) {
|
|
|
57
57
|
function toOutlookBgColor(color) {
|
|
58
58
|
if (!color || color === 'transparent')
|
|
59
59
|
return '';
|
|
60
|
-
const m = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*[\d.]+)?\s*\)/);
|
|
60
|
+
const m = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/);
|
|
61
61
|
if (m) {
|
|
62
|
+
const alpha = m[4] !== undefined ? parseFloat(m[4]) : 1;
|
|
63
|
+
if (alpha < 1)
|
|
64
|
+
return '';
|
|
62
65
|
return '#' + [m[1], m[2], m[3]].map(n => parseInt(n).toString(16).padStart(2, '0')).join('');
|
|
63
66
|
}
|
|
64
67
|
return color;
|