email-builder-utils 1.1.45 → 1.1.46
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/utils/jsonToHTML.d.ts.map +1 -1
- package/dist/utils/jsonToHTML.js +230 -160
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAIrC,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,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,UAAU;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,KAAK,EAAE,cAAc,CAAC;QACtB,KAAK,EAAE,GAAG,CAAC;QACX,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;KAC7B,CAAC;CACH;AAYD,eAAO,MAAM,gBAAgB,iDAAiD,CAAC;AA2I/E,wBAAsB,aAAa,CACjC,SAAS,EAAE,UAAU,EACrB,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,MAAM,mBAwBtB;
|
|
1
|
+
{"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAIrC,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,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,UAAU;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,KAAK,EAAE,cAAc,CAAC;QACtB,KAAK,EAAE,GAAG,CAAC;QACX,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;KAC7B,CAAC;CACH;AAYD,eAAO,MAAM,gBAAgB,iDAAiD,CAAC;AA2I/E,wBAAsB,aAAa,CACjC,SAAS,EAAE,UAAU,EACrB,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,MAAM,mBAwBtB;AAqoCD,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAwM5E"}
|
package/dist/utils/jsonToHTML.js
CHANGED
|
@@ -8,7 +8,6 @@ const common_1 = require("./common");
|
|
|
8
8
|
const fontFallback_1 = require("./fontFallback");
|
|
9
9
|
const addPxToAttributes = [
|
|
10
10
|
"fontSize",
|
|
11
|
-
"lineHeight",
|
|
12
11
|
"borderRadius",
|
|
13
12
|
"borderWidth",
|
|
14
13
|
];
|
|
@@ -209,6 +208,7 @@ function convertDividerBlockToHtml(blockData) {
|
|
|
209
208
|
});
|
|
210
209
|
const dividerWidth = width || 100;
|
|
211
210
|
const alignAttr = alignment === 'center' ? 'center' : alignment === 'right' ? 'right' : 'left';
|
|
211
|
+
const alignMargin = alignAttr === 'center' ? '0 auto' : alignAttr === 'right' ? '0 0 0 auto' : '0 auto 0 0';
|
|
212
212
|
// Append text-align so the import parser can recover alignment via inheritance
|
|
213
213
|
const contentStyle = convertedStyle
|
|
214
214
|
? `${convertedStyle}; text-align:${alignAttr};`
|
|
@@ -226,6 +226,7 @@ function convertDividerBlockToHtml(blockData) {
|
|
|
226
226
|
width="${dividerWidth}%"
|
|
227
227
|
cellpadding="0"
|
|
228
228
|
cellspacing="0"
|
|
229
|
+
style="margin:${alignMargin};"
|
|
229
230
|
>
|
|
230
231
|
<tr>
|
|
231
232
|
<td
|
|
@@ -251,8 +252,27 @@ function convertSpacerBlockToHtml(blockData) {
|
|
|
251
252
|
function convertTextBlock(blockData, cellWidthInPx) {
|
|
252
253
|
const { style, props } = blockData.data;
|
|
253
254
|
const visibilityClass = (0, common_1.getVisibilityClass)(props);
|
|
254
|
-
const { width, backgroundColor, padding, borderRadius, borderStyle, borderColor, borderWidth, textContainerBackgroundColor, textContainerPadding, fontSize, whiteSpace: _whiteSpace, // strip from outer td — pre-wrap on a td preserves editor whitespace
|
|
255
|
+
const { width, backgroundColor, padding, borderRadius, borderStyle, borderColor, borderWidth, textContainerBackgroundColor, textContainerPadding, fontSize, backgroundImage, whiteSpace: _whiteSpace, // strip from outer td — pre-wrap on a td preserves editor whitespace
|
|
255
256
|
...rest } = style;
|
|
257
|
+
// Detect background image or gradient (may live in backgroundImage or customCss).
|
|
258
|
+
// Same multi-client approach as Grid block: outer wrapper <td> carries the background
|
|
259
|
+
// via CSS (Gmail/New Outlook), background attribute (Yahoo), and VML (Old Outlook).
|
|
260
|
+
const bgImageStr = typeof backgroundImage === 'string' ? backgroundImage : '';
|
|
261
|
+
const customCssStr = rest.customCss || '';
|
|
262
|
+
const gradientInCustomCss = !bgImageStr.includes('gradient(') && customCssStr.includes('gradient(')
|
|
263
|
+
? (customCssStr.match(/(?:linear|radial|conic)-gradient\([^)]+(?:\([^)]*\)[^)]*)*\)/)?.[0] || '')
|
|
264
|
+
: '';
|
|
265
|
+
const effectiveGradient = bgImageStr.includes('gradient(') ? bgImageStr : gradientInCustomCss;
|
|
266
|
+
const isGradient = Boolean(effectiveGradient);
|
|
267
|
+
const parsedGradient = isGradient ? parseGradient(effectiveGradient) : null;
|
|
268
|
+
const rawBgImageUrl = !isGradient && bgImageStr
|
|
269
|
+
? bgImageStr.replace(/^url\(['"]?/, '').replace(/['"]?\)$/, '')
|
|
270
|
+
: null;
|
|
271
|
+
const hasBgImage = Boolean(rawBgImageUrl || isGradient);
|
|
272
|
+
const fallbackBgColor = textContainerBackgroundColor ||
|
|
273
|
+
parsedGradient?.fallback ||
|
|
274
|
+
extractCssFallbackColor(customCssStr) ||
|
|
275
|
+
'#ffffff';
|
|
256
276
|
// Text box decoration styles (border, background, padding) — no width
|
|
257
277
|
const textBoxStyle = {
|
|
258
278
|
backgroundColor,
|
|
@@ -266,11 +286,17 @@ function convertTextBlock(blockData, cellWidthInPx) {
|
|
|
266
286
|
perChanges: [],
|
|
267
287
|
pxChanges: allPxAttributes,
|
|
268
288
|
});
|
|
269
|
-
//
|
|
289
|
+
// Strip gradient from customCss when it is hoisted to the outer bg wrapper.
|
|
290
|
+
const innerCustomCss = gradientInCustomCss
|
|
291
|
+
? customCssStr.replace(/background-image\s*:[^;]+;?/gi, '').trim()
|
|
292
|
+
: customCssStr;
|
|
293
|
+
const restForStyles = gradientInCustomCss ? { ...rest, customCss: innerCustomCss } : rest;
|
|
294
|
+
// Outer td styles: strip container background when a bg-image wrapper is present
|
|
295
|
+
// so the outer wrapper's background is not double-applied.
|
|
270
296
|
const styles = buildStyles({
|
|
271
297
|
padding: textContainerPadding,
|
|
272
|
-
backgroundColor: textContainerBackgroundColor,
|
|
273
|
-
...
|
|
298
|
+
backgroundColor: hasBgImage ? undefined : textContainerBackgroundColor,
|
|
299
|
+
...restForStyles,
|
|
274
300
|
}, {
|
|
275
301
|
perChanges: [],
|
|
276
302
|
pxChanges: allPxAttributes,
|
|
@@ -298,8 +324,52 @@ function convertTextBlock(blockData, cellWidthInPx) {
|
|
|
298
324
|
// display:inline-block with a pixel width (e.g. 400px) breaks narrow grid cells.
|
|
299
325
|
const convertedTextBox = `<div style="display:block; width:100%; box-sizing:border-box; ${colorStyle}${fontSizeStyle}${convertedTextStyle}">${processedText.replaceAll(/\n/g, "<br>")}</div>`;
|
|
300
326
|
const safeCellWidth = cellWidthInPx ? Math.min(cellWidthInPx, 600) : undefined;
|
|
301
|
-
|
|
327
|
+
// When a bg-image wrapper is present, visibilityClass moves to the outer table.
|
|
328
|
+
const textContent = appendOutlookSupport(convertedTextBox, styles, hasBgImage ? '' : visibilityClass, safeCellWidth);
|
|
302
329
|
const linkColorStyle = blockTextColor ? `color:${blockTextColor};` : 'color:inherit;';
|
|
330
|
+
if (hasBgImage) {
|
|
331
|
+
const msoWidth = cellWidthInPx ? Math.min(cellWidthInPx, 600) : 600;
|
|
332
|
+
const vmlFill = isGradient
|
|
333
|
+
? (() => {
|
|
334
|
+
const vmlAngle = cssAngleToVml(parsedGradient?.angle || 180);
|
|
335
|
+
const c1 = parsedGradient?.fallback || '#ffffff';
|
|
336
|
+
const c2 = parsedGradient?.colors[parsedGradient.colors.length - 1] || c1;
|
|
337
|
+
return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
|
|
338
|
+
})()
|
|
339
|
+
: `<v:fill type="frame" src="${rawBgImageUrl}" color="${fallbackBgColor}" />`;
|
|
340
|
+
const bgCss = isGradient
|
|
341
|
+
? `background:${effectiveGradient};`
|
|
342
|
+
: `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`;
|
|
343
|
+
const wrappedContent = `
|
|
344
|
+
<table border="0" cellpadding="0" cellspacing="0" width="${msoWidth}" role="presentation"
|
|
345
|
+
style="border-collapse:collapse;width:${msoWidth}px;" class="${visibilityClass}">
|
|
346
|
+
<tr>
|
|
347
|
+
<td width="${msoWidth}" bgcolor="${fallbackBgColor}" valign="top"
|
|
348
|
+
${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` : ''}
|
|
349
|
+
style="width:${msoWidth}px;background-color:${fallbackBgColor};${bgCss}">
|
|
350
|
+
|
|
351
|
+
<!--[if gte mso 9]>
|
|
352
|
+
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
|
353
|
+
fill="true" stroke="false"
|
|
354
|
+
style="width:${msoWidth}px;">
|
|
355
|
+
${vmlFill}
|
|
356
|
+
<v:textbox inset="0,0,0,0">
|
|
357
|
+
<![endif]-->
|
|
358
|
+
|
|
359
|
+
${textContent}
|
|
360
|
+
|
|
361
|
+
<!--[if gte mso 9]>
|
|
362
|
+
</v:textbox>
|
|
363
|
+
</v:rect>
|
|
364
|
+
<![endif]-->
|
|
365
|
+
|
|
366
|
+
</td>
|
|
367
|
+
</tr>
|
|
368
|
+
</table>`;
|
|
369
|
+
return navigateToUrl
|
|
370
|
+
? `<a href="${navigateToUrl}" rel="noreferrer noopener" style="${linkColorStyle}text-decoration:none;cursor:pointer;">${wrappedContent}</a>`
|
|
371
|
+
: wrappedContent;
|
|
372
|
+
}
|
|
303
373
|
return navigateToUrl
|
|
304
374
|
? `<a href="${navigateToUrl}" rel="noreferrer noopener" style="${linkColorStyle}text-decoration:none;cursor:pointer;">${textContent}</a>`
|
|
305
375
|
: textContent;
|
|
@@ -469,161 +539,138 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
469
539
|
? `<a href="${navigateToUrl}" target="_blank" rel="noreferrer noopener" style="display:block;">${imageContent}</a>`
|
|
470
540
|
: imageContent;
|
|
471
541
|
}
|
|
472
|
-
function appendOutlookForButton(
|
|
473
|
-
const
|
|
542
|
+
function appendOutlookForButton(buttonData) {
|
|
543
|
+
const { style, text, navigateToUrl } = buttonData;
|
|
544
|
+
const pad = style.buttonPadding || {};
|
|
474
545
|
const padTop = Number.isFinite(pad.top) ? pad.top : 10;
|
|
475
546
|
const padBottom = Number.isFinite(pad.bottom) ? pad.bottom : 10;
|
|
476
547
|
const padLeft = Number.isFinite(pad.left) ? pad.left : 20;
|
|
477
548
|
const padRight = Number.isFinite(pad.right) ? pad.right : 20;
|
|
478
|
-
const
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
const
|
|
485
|
-
const
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
const
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
const
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
<
|
|
549
|
+
const fs = style.fontSize || 16;
|
|
550
|
+
const minHeight = padTop + padBottom + fs;
|
|
551
|
+
const finalHeight = typeof style.height === "number" && style.height > 0
|
|
552
|
+
? Math.max(style.height, minHeight)
|
|
553
|
+
: minHeight;
|
|
554
|
+
const safeFF = sanitizeFontFamily((0, fontFallback_1.withFontFallback)(style.fontFamily));
|
|
555
|
+
const safeColor = style.color || "#ffffff";
|
|
556
|
+
const bgColor = style.buttonColor || "transparent";
|
|
557
|
+
const bdColor = style.borderColor || "transparent";
|
|
558
|
+
const bdStyle = style.borderStyle || "solid";
|
|
559
|
+
const bw = typeof style.borderWidth === "number" ? style.borderWidth : 0;
|
|
560
|
+
const br = typeof style.borderRadius === "number" ? style.borderRadius : 0;
|
|
561
|
+
const fontWeight = style.fontWeight || 400;
|
|
562
|
+
const containerAlign = style.alignment || style.textAlign || "left";
|
|
563
|
+
const explicitWidth = typeof style.width === "number" && style.width > 0 ? style.width : 0;
|
|
564
|
+
const borderCss = bw > 0 ? `border:${bw}px ${bdStyle} ${bdColor};` : "";
|
|
565
|
+
const widthCss = explicitWidth ? `width:${explicitWidth}px;` : "";
|
|
566
|
+
// ── Non-MSO: <a display:inline-block> — border-radius works in modern clients ──
|
|
567
|
+
const nonMsoAnchor = `<!--[if !mso]><!-->
|
|
568
|
+
<a href="${navigateToUrl}"
|
|
569
|
+
target="_blank" rel="noreferrer noopener"
|
|
570
|
+
style="display:inline-block;background-color:${bgColor};border-radius:${br}px;${borderCss}color:${safeColor};font-family:${safeFF};font-size:${fs}px;font-weight:${fontWeight};text-decoration:none;padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;line-height:${fs}px;text-align:center;white-space:nowrap;-webkit-text-size-adjust:none;box-sizing:border-box;${widthCss}mso-hide:all;">${text}</a>
|
|
571
|
+
<!--<![endif]-->`;
|
|
572
|
+
// ── MSO: table-based bulletproof button.
|
|
573
|
+
// <v:roundrect arcsize="50%"> renders its half-circle arcs as visible bracket shapes
|
|
574
|
+
// in Outlook, so we use a plain <table>+<td> instead. bgcolor on <td> is reliable in
|
|
575
|
+
// all classic Outlook versions; border-radius is not (square corners in Outlook).
|
|
576
|
+
const tdStyleParts = [`padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`];
|
|
577
|
+
if (bw > 0)
|
|
578
|
+
tdStyleParts.push(`border:${bw}px ${bdStyle} ${bdColor}`);
|
|
579
|
+
if (explicitWidth)
|
|
580
|
+
tdStyleParts.push(`width:${explicitWidth}px`);
|
|
581
|
+
const tdStyle = tdStyleParts.join(";");
|
|
582
|
+
const msoButton = `<!--[if mso]>
|
|
583
|
+
<table cellspacing="0" cellpadding="0" border="0">
|
|
498
584
|
<tr>
|
|
499
|
-
<td
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
${finalHeight ? `height="${finalHeight}"` : ""}
|
|
503
|
-
bgcolor="${bgColor}"
|
|
504
|
-
style="
|
|
505
|
-
${finalHeight ? `height:${finalHeight}px;` : ""}
|
|
506
|
-
background-color:${bgColor};
|
|
507
|
-
border-radius:${borderRadius}px;
|
|
508
|
-
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
509
|
-
overflow:hidden;
|
|
510
|
-
mso-line-height-rule:exactly;
|
|
511
|
-
">
|
|
512
|
-
|
|
513
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
|
|
514
|
-
<tr>
|
|
515
|
-
<td align="center" valign="middle"
|
|
516
|
-
style="padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;">
|
|
517
|
-
|
|
518
|
-
<a href="${navigateToUrl}"
|
|
519
|
-
style="
|
|
520
|
-
display:inline-block;
|
|
521
|
-
color:${color};
|
|
522
|
-
text-decoration:none;
|
|
523
|
-
font-family:${fontFamily};
|
|
524
|
-
font-size:${fontSize}px;
|
|
525
|
-
font-weight:${fontWeight};
|
|
526
|
-
line-height:normal;
|
|
527
|
-
">
|
|
528
|
-
${text}
|
|
529
|
-
</a>
|
|
530
|
-
|
|
531
|
-
</td>
|
|
532
|
-
</tr>
|
|
533
|
-
</table>
|
|
534
|
-
|
|
585
|
+
<td bgcolor="${bgColor}" style="${tdStyle};">
|
|
586
|
+
<a href="${navigateToUrl}" target="_blank" rel="noreferrer noopener"
|
|
587
|
+
style="color:${safeColor};font-family:${safeFF};font-size:${fs}px;font-weight:${fontWeight};text-decoration:none;display:inline-block;line-height:${fs}px;">${text}</a>
|
|
535
588
|
</td>
|
|
536
589
|
</tr>
|
|
537
590
|
</table>
|
|
538
|
-
<![endif]
|
|
539
|
-
|
|
540
|
-
${
|
|
541
|
-
|
|
591
|
+
<![endif]-->`;
|
|
592
|
+
const innerContent = containerAlign === "center"
|
|
593
|
+
? `<center>${msoButton}${nonMsoAnchor}</center>`
|
|
594
|
+
: `<div style="text-align:${containerAlign};">${msoButton}${nonMsoAnchor}</div>`;
|
|
595
|
+
return {
|
|
596
|
+
innerContent,
|
|
597
|
+
computed: {
|
|
598
|
+
fs,
|
|
599
|
+
fontWeight,
|
|
600
|
+
containerAlign,
|
|
601
|
+
padTop,
|
|
602
|
+
padRight,
|
|
603
|
+
padBottom,
|
|
604
|
+
padLeft,
|
|
605
|
+
explicitWidth,
|
|
606
|
+
safeColor,
|
|
607
|
+
bgColor,
|
|
608
|
+
safeFF,
|
|
609
|
+
finalHeight,
|
|
610
|
+
bw,
|
|
611
|
+
br,
|
|
612
|
+
bdColor,
|
|
613
|
+
bdStyle,
|
|
614
|
+
},
|
|
615
|
+
};
|
|
542
616
|
}
|
|
543
617
|
function convertButtonBlock(blockData) {
|
|
544
618
|
const { style, props } = blockData.data;
|
|
545
619
|
const { text, navigateToUrl } = props;
|
|
546
|
-
const { fontFamily, fontSize, fontWeight, textAlign, borderColor, borderRadius, borderWidth, borderStyle, buttonPadding, color, buttonColor, width, height, alignment, padding, backgroundColor: containerBg,
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
<a href="${navigateToUrl}"
|
|
595
|
-
style="
|
|
596
|
-
display:inline-block;
|
|
597
|
-
color:${safeColor};
|
|
598
|
-
text-decoration:none;
|
|
599
|
-
font-family:${safeFF};
|
|
600
|
-
font-size:${fs}px;
|
|
601
|
-
font-weight:${fontWeight || 400};
|
|
602
|
-
line-height:normal;
|
|
603
|
-
white-space:nowrap;
|
|
604
|
-
">
|
|
605
|
-
${text}
|
|
606
|
-
</a>
|
|
607
|
-
|
|
608
|
-
</td>
|
|
609
|
-
</tr>
|
|
610
|
-
</table>
|
|
611
|
-
|
|
612
|
-
</td>
|
|
613
|
-
</tr>
|
|
614
|
-
</table>
|
|
615
|
-
`;
|
|
616
|
-
const aligned = containerAlign === "center"
|
|
617
|
-
? `<center>${buttonTable}</center>`
|
|
618
|
-
: `<div style="text-align:${containerAlign};">${buttonTable}</div>`;
|
|
619
|
-
const buttonWithOutlook = appendOutlookForButton(aligned, style, navigateToUrl, text);
|
|
620
|
+
const { fontFamily, fontSize, fontWeight, textAlign, borderColor, borderRadius, borderWidth, borderStyle, buttonPadding, color, buttonColor, width, height, alignment, padding, backgroundColor: containerBg, } = style;
|
|
621
|
+
const visibilityClass = (0, common_1.getVisibilityClass)(props);
|
|
622
|
+
const { innerContent, computed } = appendOutlookForButton({
|
|
623
|
+
style: {
|
|
624
|
+
fontFamily,
|
|
625
|
+
fontSize,
|
|
626
|
+
fontWeight,
|
|
627
|
+
textAlign,
|
|
628
|
+
borderColor,
|
|
629
|
+
borderRadius,
|
|
630
|
+
borderWidth,
|
|
631
|
+
borderStyle,
|
|
632
|
+
buttonPadding,
|
|
633
|
+
color,
|
|
634
|
+
buttonColor,
|
|
635
|
+
width,
|
|
636
|
+
height,
|
|
637
|
+
alignment,
|
|
638
|
+
},
|
|
639
|
+
text: text || "",
|
|
640
|
+
navigateToUrl: navigateToUrl || "",
|
|
641
|
+
});
|
|
642
|
+
const buttonBlockProps = encodeBlockProps({
|
|
643
|
+
buttonText: text || '',
|
|
644
|
+
navigateToUrl: navigateToUrl || '',
|
|
645
|
+
buttonColor: computed.bgColor,
|
|
646
|
+
color: computed.safeColor,
|
|
647
|
+
fontFamily: fontFamily || '',
|
|
648
|
+
fontSize: computed.fs,
|
|
649
|
+
fontWeight: computed.fontWeight,
|
|
650
|
+
alignment: computed.containerAlign,
|
|
651
|
+
padding: {
|
|
652
|
+
top: padding?.top || 0,
|
|
653
|
+
right: padding?.right || 0,
|
|
654
|
+
bottom: padding?.bottom || 0,
|
|
655
|
+
left: padding?.left || 0,
|
|
656
|
+
},
|
|
657
|
+
buttonPadding: { top: computed.padTop, right: computed.padRight, bottom: computed.padBottom, left: computed.padLeft },
|
|
658
|
+
width: computed.explicitWidth,
|
|
659
|
+
height: typeof height === 'number' && height > 0 ? height : 0,
|
|
660
|
+
backgroundColor: containerBg || '',
|
|
661
|
+
borderRadius: computed.br,
|
|
662
|
+
borderColor: computed.bdColor,
|
|
663
|
+
borderWidth: computed.bw,
|
|
664
|
+
borderStyle: computed.bdStyle,
|
|
665
|
+
hideOnDesktop: Boolean(props.hideOnDesktop),
|
|
666
|
+
hideOnMobile: Boolean(props.hideOnMobile),
|
|
667
|
+
});
|
|
620
668
|
return `
|
|
621
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
|
669
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" class="${visibilityClass}" data-block-type="button" data-block-props="${buttonBlockProps}">
|
|
622
670
|
<tr>
|
|
623
|
-
<td align="${containerAlign}"
|
|
624
|
-
style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;
|
|
625
|
-
|
|
626
|
-
${buttonWithOutlook}
|
|
671
|
+
<td align="${computed.containerAlign}"
|
|
672
|
+
style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;background-color:${containerBg || 'transparent'};">
|
|
673
|
+
${innerContent}
|
|
627
674
|
</td>
|
|
628
675
|
</tr>
|
|
629
676
|
</table>
|
|
@@ -1142,16 +1189,28 @@ async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
|
1142
1189
|
<![endif]-->`;
|
|
1143
1190
|
// Non-Outlook: use a real <img> for the thumbnail so it renders in Gmail / Yahoo / webmail.
|
|
1144
1191
|
// background-image on <table> is stripped by virtually every email client.
|
|
1145
|
-
// position:absolute for the play-button overlay is safe here because this block
|
|
1146
|
-
// is already inside <!--[if !mso]> — Outlook is handled separately via VML above.
|
|
1147
1192
|
const thumbnailW = Math.round(innerContainerWidth);
|
|
1148
1193
|
const thumbnailH = Math.round(calculatedHeight);
|
|
1149
|
-
const playMarginTop = -Math.round(playIconHeight / 2);
|
|
1150
|
-
const playMarginLeft = -Math.round(playIconWidth / 2);
|
|
1151
1194
|
const borderAttr = borderWidth > 0 ? `border:${borderWidth}px ${style?.borderStyle || "solid"} ${borderColor};` : "border:0;";
|
|
1152
1195
|
const radiusAttr = borderRadius > 0 ? `border-radius:${borderRadius}px; overflow:hidden;` : "";
|
|
1196
|
+
// Overlay the play button using negative margin-top + line-height centering.
|
|
1197
|
+
// This avoids both position:absolute (stripped by Gmail/Yahoo) and
|
|
1198
|
+
// height:0/overflow:visible (clipped by New Outlook at <td> boundaries).
|
|
1199
|
+
// The play button <a> is pulled up by margin-top:-thumbnailH to sit over the thumbnail,
|
|
1200
|
+
// then line-height:thumbnailH + vertical-align:middle centres the icon vertically.
|
|
1201
|
+
// Elements later in DOM flow render on top of earlier ones, so the play icon overlays the image.
|
|
1202
|
+
const playButtonHtml = `<a href="${videoLink}" target="_blank" data-play-button="true"
|
|
1203
|
+
style="display:block; margin-top:-${thumbnailH}px; text-align:center; line-height:${thumbnailH}px; font-size:0; text-decoration:none; border:0; outline:none;">
|
|
1204
|
+
<img
|
|
1205
|
+
src="https://app-rsrc.getbee.io/public/resources/components/widgetBar/video-content-icon-sets/light/type-01.png"
|
|
1206
|
+
width="${playIconWidth}"
|
|
1207
|
+
height="${playIconHeight}"
|
|
1208
|
+
alt="Play"
|
|
1209
|
+
style="display:inline-block; vertical-align:middle; border:0; outline:none;"
|
|
1210
|
+
/>
|
|
1211
|
+
</a>`;
|
|
1153
1212
|
const nonOutlookVideoContent = `<!--[if !mso]><!-->
|
|
1154
|
-
<div style="display:block; width:100%; max-width:${thumbnailW}px;
|
|
1213
|
+
<div style="display:block; width:100%; max-width:${thumbnailW}px; line-height:0; font-size:0; ${borderAttr}${radiusAttr}">
|
|
1155
1214
|
<a href="${videoLink}" target="_blank" style="display:block; text-decoration:none; line-height:0; font-size:0;">
|
|
1156
1215
|
<img
|
|
1157
1216
|
src="${resolvedThumbnail}"
|
|
@@ -1160,21 +1219,32 @@ async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
|
1160
1219
|
alt="${altText || "Video"}"
|
|
1161
1220
|
style="display:block; width:100%; max-width:${thumbnailW}px; height:auto; border:0;"
|
|
1162
1221
|
/>
|
|
1163
|
-
<img
|
|
1164
|
-
src="https://app-rsrc.getbee.io/public/resources/components/widgetBar/video-content-icon-sets/light/type-01.png"
|
|
1165
|
-
width="${playIconWidth}"
|
|
1166
|
-
alt="Play"
|
|
1167
|
-
style="display:block; position:absolute; top:50%; left:50%; margin-top:${playMarginTop}px; margin-left:${playMarginLeft}px; border:0; outline:none;"
|
|
1168
|
-
/>
|
|
1169
1222
|
</a>
|
|
1223
|
+
${playButtonHtml}
|
|
1170
1224
|
</div>
|
|
1171
1225
|
<!--<![endif]-->`;
|
|
1172
1226
|
const videoContent = `${outlookVideoContent}${nonOutlookVideoContent}`;
|
|
1227
|
+
const videoBlockProps = encodeBlockProps({
|
|
1228
|
+
videoUrl: videoUrl || '',
|
|
1229
|
+
youtubeVideoUrl: youtubeVideoUrl || '',
|
|
1230
|
+
thumbnailUrl: thumbnailUrl || resolvedThumbnail,
|
|
1231
|
+
altText: altText || '',
|
|
1232
|
+
width: parseFloat(percentWidth) || 100,
|
|
1233
|
+
padding: style?.padding || { top: 0, right: 0, bottom: 0, left: 0 },
|
|
1234
|
+
backgroundColor: style?.backgroundColor || '',
|
|
1235
|
+
textAlign: style?.textAlign || 'left',
|
|
1236
|
+
borderRadius: style?.borderRadius || 0,
|
|
1237
|
+
borderColor: style?.borderColor || '',
|
|
1238
|
+
borderWidth: style?.borderWidth || 0,
|
|
1239
|
+
borderStyle: style?.borderStyle || 'none',
|
|
1240
|
+
hideOnDesktop: Boolean(props.hideOnDesktop),
|
|
1241
|
+
hideOnMobile: Boolean(props.hideOnMobile),
|
|
1242
|
+
});
|
|
1173
1243
|
const wrapperHtml = `
|
|
1174
|
-
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0; padding:0; border-collapse: collapse; max-width:600px;" class="${visibilityClass}">
|
|
1244
|
+
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0; padding:0; border-collapse: collapse; max-width:600px;" class="${visibilityClass}" data-block-type="video" data-block-props="${videoBlockProps}">
|
|
1175
1245
|
<tr>
|
|
1176
1246
|
<td align="${style?.textAlign || "left"}" style="padding:0; ${outerContainerStyles}">
|
|
1177
|
-
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
1247
|
+
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
1178
1248
|
align="${style?.textAlign || "left"}"
|
|
1179
1249
|
style="
|
|
1180
1250
|
margin:0;
|