email-builder-utils 1.1.53 → 1.1.55
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/grid.d.ts.map +1 -1
- package/dist/utils/blocks/grid.js +20 -22
- package/dist/utils/blocks/image.d.ts.map +1 -1
- package/dist/utils/blocks/image.js +22 -13
- package/dist/utils/blocks/text.d.ts.map +1 -1
- package/dist/utils/blocks/text.js +33 -41
- package/package.json +1 -1
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":"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)
|
|
@@ -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,16 +167,10 @@ 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
|
-
const canApplyGridBgFallback = !cellHasBorderRadius && !divBorderStyle;
|
|
168
|
-
const effectiveCellBg = cellBgColor || (canApplyGridBgFallback ? msoBgColor : '');
|
|
169
|
-
const cellBgAttr = (0, common_1.buildOutlookBgAttr)(effectiveCellBg);
|
|
173
|
+
const cellBgAttr = (0, common_1.buildOutlookBgAttr)(cellBgColor);
|
|
170
174
|
html += `
|
|
171
175
|
<td
|
|
172
176
|
width="${Math.max(1, Math.round(widthPercent))}%"${cellBgAttr}
|
|
@@ -179,22 +183,18 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
|
|
|
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
|
-
const emptyBgAttr = divBorderStyle ? '' : (0, common_1.buildOutlookBgAttr)(msoBgColor);
|
|
189
191
|
html += `
|
|
190
192
|
<td width="${Math.max(1, Math.round(widthPercent))}%"
|
|
191
|
-
${emptyBgAttr}
|
|
192
193
|
${responsive ? 'class="stack-column"' : ""}
|
|
193
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
|
}
|
|
@@ -320,7 +320,7 @@ async function convertGridCellBlock(blockData, rootData, cellWidthPercent, paren
|
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
const borderRadius = cellBorderRadius || 0;
|
|
323
|
-
const bgColor = styleWithoutBorder?.backgroundColor || "";
|
|
323
|
+
const bgColor = styleWithoutBorder?.backgroundColor || "transparent";
|
|
324
324
|
// Build border CSS for the div wrapper.
|
|
325
325
|
// When the parent grid already has a divBorderStyle wrapper (border + border-radius +
|
|
326
326
|
// overflow:hidden), the cell must NOT duplicate the same border/radius — that causes
|
|
@@ -342,10 +342,8 @@ async function convertGridCellBlock(blockData, rootData, cellWidthPercent, paren
|
|
|
342
342
|
}
|
|
343
343
|
const cellDivBorderStyle = cellDivBorderParts.join(' ');
|
|
344
344
|
// Unconditional div — visible to all clients (Gmail, Outlook new/old, Apple Mail).
|
|
345
|
-
// background-color on the div covers modern clients
|
|
346
|
-
|
|
347
|
-
// defeats the bgcolor attribute on the parent <td> in Old Outlook's Word engine.
|
|
348
|
-
const divStyleParts = bgColor ? [`background-color:${bgColor};`] : [];
|
|
345
|
+
// background-color on the div covers modern clients; bgcolor on <td> covers Old Outlook.
|
|
346
|
+
const divStyleParts = [`background-color:${bgColor};`];
|
|
349
347
|
const formatPad = (value) => (typeof value === 'number' ? `${value}px` : (value || '0'));
|
|
350
348
|
const cellPadTop = formatPad(cellPad.top);
|
|
351
349
|
const cellPadBottom = formatPad(cellPad.bottom);
|
|
@@ -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.
|
|
@@ -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,UAsKtE"}
|
|
@@ -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,57 +58,53 @@ 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
|
-
//
|
|
70
|
-
//
|
|
65
|
+
// Links default to standard link blue + underline. Preserve any color or
|
|
66
|
+
// text-decoration the user explicitly set; only inject what is missing.
|
|
71
67
|
const blockTextColor = rest.color;
|
|
72
|
-
const processedText =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return `<a${attrs}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
const processedText = sanitizedText.replace(/<a(\s[^>]*)?>/gi, (_match, attrs = '') => {
|
|
69
|
+
const hasExistingColor = /style\s*=\s*["'][^"']*\bcolor\s*:/i.test(attrs);
|
|
70
|
+
const hasExistingDecoration = /style\s*=\s*["'][^"']*\btext-decoration\s*:/i.test(attrs);
|
|
71
|
+
const colorPart = hasExistingColor ? '' : 'color:#0066CC;';
|
|
72
|
+
const decorationPart = hasExistingDecoration ? '' : 'text-decoration:underline;';
|
|
73
|
+
const injected = `${colorPart}${decorationPart}`;
|
|
74
|
+
if (!injected)
|
|
75
|
+
return `<a${attrs}>`;
|
|
76
|
+
if (/\bstyle\s*=/i.test(attrs)) {
|
|
77
|
+
return `<a${attrs.replace(/(\bstyle\s*=\s*["'])/, `$1${injected}`)}>`;
|
|
78
|
+
}
|
|
79
|
+
return `<a${attrs} style="${injected}">`;
|
|
80
|
+
});
|
|
81
|
+
const colorStyle = blockTextColor ? `color:${blockTextColor};` : '';
|
|
83
82
|
// Use display:block + width:100% so text fills the column naturally.
|
|
84
83
|
// display:inline-block with a pixel width (e.g. 400px) breaks narrow grid cells.
|
|
85
84
|
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;
|
|
85
|
+
const safeCellWidth = cellWidthInPx ? Math.min(cellWidthInPx, 600) : undefined;
|
|
89
86
|
// 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;";
|
|
87
|
+
const textContent = (0, outlookSupport_1.appendOutlookSupport)(convertedTextBox, styles, hasBgImage ? '' : visibilityClass, safeCellWidth);
|
|
88
|
+
const linkColorStyle = blockTextColor ? `color:${blockTextColor};` : 'color:inherit;';
|
|
94
89
|
if (hasBgImage) {
|
|
95
90
|
const msoWidth = cellWidthInPx ? Math.min(cellWidthInPx, 600) : 600;
|
|
96
91
|
const vmlFill = isGradient
|
|
97
92
|
? (() => {
|
|
98
93
|
const vmlAngle = (0, gradientUtils_1.cssAngleToVml)(parsedGradient?.angle || 180);
|
|
99
|
-
const c1 = parsedGradient?.fallback ||
|
|
94
|
+
const c1 = parsedGradient?.fallback || '#ffffff';
|
|
100
95
|
const c2 = parsedGradient?.colors[parsedGradient.colors.length - 1] || c1;
|
|
101
96
|
return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
|
|
102
97
|
})()
|
|
103
98
|
: `<v:fill type="frame" src="${rawBgImageUrl}" color="${fallbackBgColor}" />`;
|
|
104
|
-
const bgPosition = rest.backgroundPosition || 'center center';
|
|
105
|
-
const bgSize = rest.backgroundSize || 'cover';
|
|
106
|
-
const bgRepeat = rest.backgroundRepeat || 'no-repeat';
|
|
107
99
|
const bgCss = isGradient
|
|
108
100
|
? `background:${effectiveGradient};`
|
|
109
|
-
: `background-image:url('${rawBgImageUrl}'); background-position
|
|
101
|
+
: `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`;
|
|
110
102
|
const wrappedContent = `
|
|
111
103
|
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
|
|
112
104
|
style="border-collapse:collapse;width:100%;max-width:${msoWidth}px;" class="${visibilityClass}">
|
|
113
105
|
<tr>
|
|
114
106
|
<td width="100%"${(0, common_1.buildOutlookBgAttr)(fallbackBgColor)} valign="top"
|
|
115
|
-
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` :
|
|
107
|
+
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` : ''}
|
|
116
108
|
style="width:100%;max-width:${msoWidth}px;background-color:${fallbackBgColor};${bgCss}">
|
|
117
109
|
|
|
118
110
|
<!--[if gte mso 9]>
|