email-builder-utils 1.1.22 → 1.1.24
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
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;CAChB;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;
|
|
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;CAChB;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;CAChB;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"}
|
|
@@ -8,6 +8,10 @@ interface BlockJsonProps {
|
|
|
8
8
|
altText: string;
|
|
9
9
|
imageUrl: string;
|
|
10
10
|
responsive?: boolean;
|
|
11
|
+
videoUrl?: string;
|
|
12
|
+
youtubeVideoUrl?: string;
|
|
13
|
+
thumbnailUrl?: string;
|
|
14
|
+
shape?: string;
|
|
11
15
|
}
|
|
12
16
|
interface IBlockData {
|
|
13
17
|
type: BlockType;
|
|
@@ -20,6 +24,5 @@ interface IBlockData {
|
|
|
20
24
|
export declare const tableCommonStyle = "border-collapse:collapse; table-layout:fixed;";
|
|
21
25
|
export declare function convertToHtml(blockData: IBlockData, rootData: any, cellWidthInPx: number): Promise<string>;
|
|
22
26
|
export declare function convertVideoBlock(blockData: any, cellWidthInPx: number): Promise<string>;
|
|
23
|
-
export declare function convertShapeBlock(blockData: IBlockData): Promise<string>;
|
|
24
27
|
export {};
|
|
25
28
|
//# sourceMappingURL=jsonToHTML.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAUrC,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;
|
|
1
|
+
{"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAUrC,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;CAChB;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;AAOD,eAAO,MAAM,gBAAgB,kDAAkD,CAAC;AAiDhF,wBAAsB,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAqB9F;AA2UD,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAgJ5E"}
|
package/dist/utils/jsonToHTML.js
CHANGED
|
@@ -3,16 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.tableCommonStyle = void 0;
|
|
4
4
|
exports.convertToHtml = convertToHtml;
|
|
5
5
|
exports.convertVideoBlock = convertVideoBlock;
|
|
6
|
-
exports.convertShapeBlock = convertShapeBlock;
|
|
7
6
|
const jimp_1 = require("jimp");
|
|
8
7
|
const types_1 = require("../types");
|
|
9
8
|
const common_1 = require("./common");
|
|
10
|
-
const addPxToAttributes = [
|
|
11
|
-
"fontSize",
|
|
12
|
-
"lineHeight",
|
|
13
|
-
"borderRadius",
|
|
14
|
-
"borderWidth",
|
|
15
|
-
];
|
|
9
|
+
const addPxToAttributes = ["fontSize", "lineHeight", "borderRadius", "borderWidth"];
|
|
16
10
|
const addPxOrPerToAttributes = ["width", "height"];
|
|
17
11
|
const allPxAttributes = [...addPxToAttributes, ...addPxOrPerToAttributes];
|
|
18
12
|
exports.tableCommonStyle = "border-collapse:collapse; table-layout:fixed;";
|
|
@@ -43,8 +37,7 @@ function buildStyles(style, { pxChanges, perChanges }) {
|
|
|
43
37
|
return;
|
|
44
38
|
if (value === undefined || value === null || value === "")
|
|
45
39
|
return;
|
|
46
|
-
if ((key === "padding" || key === "buttonPadding") &&
|
|
47
|
-
typeof value === "object") {
|
|
40
|
+
if ((key === "padding" || key === "buttonPadding") && typeof value === "object") {
|
|
48
41
|
const padding = value;
|
|
49
42
|
value = `${padding.top}px ${padding.right}px ${padding.bottom}px ${padding.left}px`;
|
|
50
43
|
}
|
|
@@ -140,15 +133,11 @@ function convertTextBlock(blockData) {
|
|
|
140
133
|
perChanges: [],
|
|
141
134
|
pxChanges: allPxAttributes,
|
|
142
135
|
});
|
|
143
|
-
const sanitizedText = (props.text ?? "")
|
|
144
|
-
.replaceAll(/<p>/g, "<div>")
|
|
145
|
-
.replaceAll(/<\/p>/g, "</div>");
|
|
136
|
+
const sanitizedText = (props.text ?? "").replaceAll(/<p>/g, "<div>").replaceAll(/<\/p>/g, "</div>");
|
|
146
137
|
const navigateToUrl = props.navigateToUrl || "";
|
|
147
138
|
const convertedTextBox = `<div style="display: inline-block; max-width: 100%; box-sizing: border-box; ${convertedTextStyle}">${sanitizedText.replaceAll(/\n/g, "<br>")}</div>`;
|
|
148
139
|
const textContent = appendOutlookSupport(convertedTextBox, styles);
|
|
149
|
-
return navigateToUrl
|
|
150
|
-
? `<a href="${navigateToUrl}" rel="noreferrer noopener" style="color:inherit; text-decoration:none; cursor:pointer;">${textContent}</a>`
|
|
151
|
-
: textContent;
|
|
140
|
+
return navigateToUrl ? `<a href="${navigateToUrl}" rel="noreferrer noopener" style="color:inherit; text-decoration:none; cursor:pointer;">${textContent}</a>` : textContent;
|
|
152
141
|
}
|
|
153
142
|
async function appendOutlookForImage(content, outerContainerWidth, innerContainerWidth, imageUrl, style = {}) {
|
|
154
143
|
const image = await jimp_1.Jimp.read(imageUrl);
|
|
@@ -161,12 +150,8 @@ async function appendOutlookForImage(content, outerContainerWidth, innerContaine
|
|
|
161
150
|
const borderColor = style?.borderColor || "transparent";
|
|
162
151
|
const borderRadius = parseInt(style?.borderRadius) || 0;
|
|
163
152
|
const useRoundRect = borderRadius > 0;
|
|
164
|
-
const arcsize = useRoundRect
|
|
165
|
-
|
|
166
|
-
: "";
|
|
167
|
-
const borderAttributes = borderWidth > 0
|
|
168
|
-
? `strokeweight="${borderWidth}px" strokecolor="${borderColor}"`
|
|
169
|
-
: `stroked="false"`;
|
|
153
|
+
const arcsize = useRoundRect ? Math.min(borderRadius / scaledHeight, 1).toFixed(2) : "";
|
|
154
|
+
const borderAttributes = borderWidth > 0 ? `strokeweight="${borderWidth}px" strokecolor="${borderColor}"` : `stroked="false"`;
|
|
170
155
|
const outlookImage = `<!--[if mso]>
|
|
171
156
|
<v:${useRoundRect ? "roundrect" : "rect"} xmlns:v="urn:schemas-microsoft-com:vml"
|
|
172
157
|
style="width:${scaledWidth}px;height:${scaledHeight}px;"
|
|
@@ -209,11 +194,7 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
209
194
|
pxChanges: addPxToAttributes,
|
|
210
195
|
});
|
|
211
196
|
const imageElement = `<img src="${imageUrl}" alt="${altText}" style="${imageTagStyles}; max-width: ${originalWidth}px; max-height: ${originalHeight}px;" />`;
|
|
212
|
-
const innerContainerWidth = ((typeof width === "string" ? parseInt(width.replace("%", "")) : width) /
|
|
213
|
-
100) *
|
|
214
|
-
(cellWidthInPx -
|
|
215
|
-
(style?.padding?.left || 0) -
|
|
216
|
-
(style?.padding?.right || 0));
|
|
197
|
+
const innerContainerWidth = ((typeof width === "string" ? parseInt(width.replace("%", "")) : width) / 100) * (cellWidthInPx - (style?.padding?.left || 0) - (style?.padding?.right || 0));
|
|
217
198
|
const outlookImage = await appendOutlookForImage(imageElement, cellWidthInPx, innerContainerWidth, imageUrl, style);
|
|
218
199
|
const imageContent = appendOutlookSupport(outlookImage, containerStyles);
|
|
219
200
|
return navigateToUrl
|
|
@@ -222,9 +203,7 @@ async function convertImageBlock(blockData, cellWidthInPx) {
|
|
|
222
203
|
}
|
|
223
204
|
function appendOutlookForButton(content, buttonStyle, navigateToUrl, text) {
|
|
224
205
|
const { width = 200, height = 44, borderRadius = 0, borderColor = "transparent", borderWidth = 0, buttonColor = "none", buttonPadding = { top: 0, bottom: 0, left: 0, right: 0 }, color = "#000000", fontFamily = "Arial, sans-serif", fontSize = 16, fontWeight = 400, } = buttonStyle;
|
|
225
|
-
const borderAttributes = borderWidth > 0
|
|
226
|
-
? `strokeweight="${borderWidth}px" strokecolor="${borderColor}"`
|
|
227
|
-
: `stroked="false"`;
|
|
206
|
+
const borderAttributes = borderWidth > 0 ? `strokeweight="${borderWidth}px" strokecolor="${borderColor}"` : `stroked="false"`;
|
|
228
207
|
return `
|
|
229
208
|
<!--[if mso]>
|
|
230
209
|
<v:${borderRadius ? "roundrect" : "rect"} xmlns:v="urn:schemas-microsoft-com:vml" href="${navigateToUrl}"
|
|
@@ -340,7 +319,7 @@ async function convertGridCellBlock(blockData, rootData, cellWidthPercent, paren
|
|
|
340
319
|
}
|
|
341
320
|
async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
342
321
|
const { style, props } = blockData.data;
|
|
343
|
-
const { videoUrl, youtubeVideoUrl, thumbnailUrl, altText } = props
|
|
322
|
+
const { videoUrl, youtubeVideoUrl, thumbnailUrl, altText } = props;
|
|
344
323
|
const videoLink = youtubeVideoUrl || videoUrl || "#";
|
|
345
324
|
let resolvedThumbnail = thumbnailUrl || "https://via.placeholder.com/480x360?text=No+Thumbnail";
|
|
346
325
|
if (youtubeVideoUrl) {
|
|
@@ -453,9 +432,15 @@ async function convertVideoBlock(blockData, cellWidthInPx) {
|
|
|
453
432
|
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0; padding:0; border-collapse: collapse;">
|
|
454
433
|
<tr>
|
|
455
434
|
<td align="center" style="padding:0; ${outerContainerStyles}">
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
435
|
+
<table border="0" cellpadding="0" cellspacing="0" role="presentation"
|
|
436
|
+
align="center"
|
|
437
|
+
style="margin:0 auto; max-width:${cellWidthInPx}px; width:${percentWidth}; border-collapse:collapse;">
|
|
438
|
+
<tr>
|
|
439
|
+
<td align="center" style="text-align:center; padding:0;">
|
|
440
|
+
${videoContent}
|
|
441
|
+
</td>
|
|
442
|
+
</tr>
|
|
443
|
+
</table>
|
|
459
444
|
</td>
|
|
460
445
|
</tr>
|
|
461
446
|
</table>
|
|
@@ -497,8 +482,7 @@ async function appendOutlookForShape(content, outerContainerWidth, innerContaine
|
|
|
497
482
|
// pass raw flag so buildVMLShape knows if image already has text baked-in
|
|
498
483
|
msoHasBakedText: Boolean(opts.msoBakeImageWithText),
|
|
499
484
|
});
|
|
500
|
-
const outlookAlignment = opts.alignment === "center" ? "center" :
|
|
501
|
-
opts.alignment === "right" ? "right" : "left";
|
|
485
|
+
const outlookAlignment = opts.alignment === "center" ? "center" : opts.alignment === "right" ? "right" : "left";
|
|
502
486
|
// Wrap the VML inside a table so Outlook aligns it correctly
|
|
503
487
|
return `<!--[if mso]>
|
|
504
488
|
<table align="${outlookAlignment}" border="0" cellpadding="0" cellspacing="0" style="display:inline-block;">
|
|
@@ -527,9 +511,7 @@ function buildVMLShape({ shape, widthPx, heightPx, imageUrl, backgroundColor, bo
|
|
|
527
511
|
extraAttr = ` arcsize="${computeArcSize(borderRadius, widthPx)}"`;
|
|
528
512
|
}
|
|
529
513
|
// image fill (if provided)
|
|
530
|
-
const fillMarkup = imageUrl
|
|
531
|
-
? `<v:fill src="${imageUrl}" type="frame" aspect="atleast" />`
|
|
532
|
-
: "";
|
|
514
|
+
const fillMarkup = imageUrl ? `<v:fill src="${imageUrl}" type="frame" aspect="atleast" />` : "";
|
|
533
515
|
// If MSO is given a baked image with text, don't produce a v:textbox overlay text (image already contains text)
|
|
534
516
|
const includeTextbox = !!text && !msoHasBakedText;
|
|
535
517
|
// v:textbox: use a table + cell to center the text; avoids many Word quirks
|
|
@@ -560,13 +542,13 @@ function buildVMLShape({ shape, widthPx, heightPx, imageUrl, backgroundColor, bo
|
|
|
560
542
|
// ---------- convertShapeBlock (updated, keeps your structure) ----------
|
|
561
543
|
async function convertShapeBlock(blockData) {
|
|
562
544
|
const { style, props } = blockData.data;
|
|
563
|
-
const { shape, text, textColor = "#000000", imageUrl } = props
|
|
545
|
+
const { shape, text, textColor = "#000000", imageUrl } = props;
|
|
564
546
|
const { width = "100", height = "150", padding = {}, backgroundColor = "#2F80ED", borderRadius, borderWidth = 0, borderStyle = "solid", borderColor = "transparent", customCss, shapeColor, alignment = "left", msoBakeImageWithText } = style || {};
|
|
565
547
|
const borderRadiusMap = {
|
|
566
548
|
rectangle: "0",
|
|
567
549
|
rounded: "10px",
|
|
568
550
|
circle: "50%",
|
|
569
|
-
oval: "50%",
|
|
551
|
+
oval: "50%", // Keep this for modern browsers
|
|
570
552
|
};
|
|
571
553
|
let resolvedBorderRadius = borderRadius || borderRadiusMap[shape] || "0";
|
|
572
554
|
let resolvedWidthPx = typeof width === "number"
|
|
@@ -575,13 +557,16 @@ async function convertShapeBlock(blockData) {
|
|
|
575
557
|
let resolvedHeightPx = typeof height === "number"
|
|
576
558
|
? height
|
|
577
559
|
: parseInt(height.toString().replace("px", ""), 10) || 150;
|
|
578
|
-
//
|
|
560
|
+
// Special handling for different shapes
|
|
579
561
|
if (shape === "circle") {
|
|
562
|
+
// Circle: make it a perfect square with 50% border radius
|
|
580
563
|
const side = Math.min(resolvedWidthPx, resolvedHeightPx);
|
|
581
564
|
resolvedWidthPx = side;
|
|
582
565
|
resolvedHeightPx = side;
|
|
583
566
|
resolvedBorderRadius = "50%";
|
|
584
567
|
}
|
|
568
|
+
else if (shape === "oval") {
|
|
569
|
+
}
|
|
585
570
|
const finalWidthPx = resolvedWidthPx;
|
|
586
571
|
const finalHeightPx = resolvedHeightPx;
|
|
587
572
|
const alignmentStyles = {
|
|
@@ -593,12 +578,14 @@ async function convertShapeBlock(blockData) {
|
|
|
593
578
|
const finalBackgroundColor = shapeColor || backgroundColor;
|
|
594
579
|
// --- Modern clients content ---
|
|
595
580
|
let nonMsoContent = "";
|
|
581
|
+
// For modern browsers, use CSS border-radius
|
|
582
|
+
const modernBorderRadius = shape === "oval" ? "50%" : resolvedBorderRadius;
|
|
596
583
|
// Case 1: Image + Text → use background-image
|
|
597
584
|
if (imageUrl && text) {
|
|
598
585
|
nonMsoContent = `
|
|
599
586
|
<div style="display:inline-block;width:${finalWidthPx}px;height:${finalHeightPx}px;
|
|
600
587
|
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
601
|
-
border-radius:${
|
|
588
|
+
border-radius:${modernBorderRadius};
|
|
602
589
|
background:${finalBackgroundColor} url('${imageUrl}') center/cover no-repeat;
|
|
603
590
|
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
604
591
|
<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;">
|
|
@@ -614,11 +601,11 @@ async function convertShapeBlock(blockData) {
|
|
|
614
601
|
nonMsoContent = `
|
|
615
602
|
<div style="display:inline-block;width:${finalWidthPx}px;height:${finalHeightPx}px;
|
|
616
603
|
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
617
|
-
border-radius:${
|
|
604
|
+
border-radius:${modernBorderRadius};
|
|
618
605
|
overflow:hidden;${alignmentStyle}${customCss || ""}">
|
|
619
606
|
<img src="${imageUrl}" alt="${text || "Shape image"}"
|
|
620
607
|
width="${finalWidthPx}" height="${finalHeightPx}"
|
|
621
|
-
style="width:100%;height:100%;object-fit:cover;border-radius:${
|
|
608
|
+
style="width:100%;height:100%;object-fit:cover;border-radius:${modernBorderRadius};display:block;" />
|
|
622
609
|
</div>`;
|
|
623
610
|
}
|
|
624
611
|
// Case 3: No image → solid background
|
|
@@ -627,7 +614,7 @@ async function convertShapeBlock(blockData) {
|
|
|
627
614
|
<div style="display:inline-block;width:${finalWidthPx}px;height:${finalHeightPx}px;
|
|
628
615
|
background:${finalBackgroundColor};
|
|
629
616
|
border:${borderWidth}px ${borderStyle} ${borderColor};
|
|
630
|
-
border-radius:${
|
|
617
|
+
border-radius:${modernBorderRadius};
|
|
631
618
|
${alignmentStyle}${customCss || ""}">
|
|
632
619
|
<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;
|
|
633
620
|
color:${textColor};text-align:center;padding:8px;box-sizing:border-box;word-break:break-word;">
|