email-builder-utils 1.1.46 → 1.1.48

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.
Files changed (39) hide show
  1. package/dist/utils/blocks/button.d.ts +29 -0
  2. package/dist/utils/blocks/button.d.ts.map +1 -0
  3. package/dist/utils/blocks/button.js +130 -0
  4. package/dist/utils/blocks/dividers.d.ts +4 -0
  5. package/dist/utils/blocks/dividers.d.ts.map +1 -0
  6. package/dist/utils/blocks/dividers.js +72 -0
  7. package/dist/utils/blocks/grid.d.ts +6 -0
  8. package/dist/utils/blocks/grid.d.ts.map +1 -0
  9. package/dist/utils/blocks/grid.js +248 -0
  10. package/dist/utils/blocks/image.d.ts +8 -0
  11. package/dist/utils/blocks/image.d.ts.map +1 -0
  12. package/dist/utils/blocks/image.js +58 -0
  13. package/dist/utils/blocks/shape.d.ts +2 -0
  14. package/dist/utils/blocks/shape.d.ts.map +1 -0
  15. package/dist/utils/blocks/shape.js +256 -0
  16. package/dist/utils/blocks/text.d.ts +2 -0
  17. package/dist/utils/blocks/text.d.ts.map +1 -0
  18. package/dist/utils/blocks/text.js +106 -0
  19. package/dist/utils/blocks/video.d.ts +2 -0
  20. package/dist/utils/blocks/video.d.ts.map +1 -0
  21. package/dist/utils/blocks/video.js +151 -0
  22. package/dist/utils/buildStyles.d.ts +10 -0
  23. package/dist/utils/buildStyles.d.ts.map +1 -0
  24. package/dist/utils/buildStyles.js +101 -0
  25. package/dist/utils/common.d.ts +1 -0
  26. package/dist/utils/common.d.ts.map +1 -1
  27. package/dist/utils/common.js +10 -0
  28. package/dist/utils/convertJsonToHtml.d.ts.map +1 -1
  29. package/dist/utils/convertJsonToHtml.js +135 -74
  30. package/dist/utils/gradientUtils.d.ts +8 -0
  31. package/dist/utils/gradientUtils.d.ts.map +1 -0
  32. package/dist/utils/gradientUtils.js +68 -0
  33. package/dist/utils/jsonToHTML.d.ts +2 -29
  34. package/dist/utils/jsonToHTML.d.ts.map +1 -1
  35. package/dist/utils/jsonToHTML.js +18 -1560
  36. package/dist/utils/outlookSupport.d.ts +4 -207
  37. package/dist/utils/outlookSupport.d.ts.map +1 -1
  38. package/dist/utils/outlookSupport.js +86 -453
  39. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ export declare function appendOutlookForButton(buttonData: {
2
+ style: any;
3
+ text: string;
4
+ navigateToUrl: string;
5
+ }): {
6
+ innerContent: string;
7
+ computed: {
8
+ fs: any;
9
+ fontWeight: any;
10
+ containerAlign: any;
11
+ padTop: any;
12
+ padRight: any;
13
+ padBottom: any;
14
+ padLeft: any;
15
+ explicitWidth: any;
16
+ vmlWidth: number;
17
+ safeColor: any;
18
+ bgColor: any;
19
+ safeFF: string;
20
+ finalHeight: any;
21
+ explicitHeight: any;
22
+ bw: any;
23
+ br: any;
24
+ bdColor: any;
25
+ bdStyle: any;
26
+ };
27
+ };
28
+ export declare function convertButtonBlock(blockData: any): string;
29
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/button.ts"],"names":[],"mappings":"AAIA,wBAAgB,sBAAsB,CAAC,UAAU,EAAE;IAAE,KAAK,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;EA6ErG;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,GAAG,UAgEhD"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendOutlookForButton = appendOutlookForButton;
4
+ exports.convertButtonBlock = convertButtonBlock;
5
+ const buildStyles_1 = require("../buildStyles");
6
+ const fontFallback_1 = require("../fontFallback");
7
+ const common_1 = require("../common");
8
+ function appendOutlookForButton(buttonData) {
9
+ const { style, text, navigateToUrl } = buttonData;
10
+ const pad = style.buttonPadding || {};
11
+ const padTop = Number.isFinite(pad.top) ? pad.top : 10;
12
+ const padBottom = Number.isFinite(pad.bottom) ? pad.bottom : 10;
13
+ const padLeft = Number.isFinite(pad.left) ? pad.left : 20;
14
+ const padRight = Number.isFinite(pad.right) ? pad.right : 20;
15
+ const fs = style.fontSize || 16;
16
+ const explicitHeight = typeof style.height === "number" && style.height > 0 ? style.height : 0;
17
+ const minHeight = padTop + padBottom + fs;
18
+ const finalHeight = explicitHeight > 0 ? Math.max(explicitHeight, minHeight) : minHeight;
19
+ const safeFF = (0, buildStyles_1.sanitizeFontFamily)((0, fontFallback_1.withFontFallback)(style.fontFamily));
20
+ const safeColor = style.color || "#ffffff";
21
+ const bgColor = style.buttonColor || "transparent";
22
+ const bdColor = style.borderColor || "transparent";
23
+ const bdStyle = style.borderStyle || "solid";
24
+ const bw = typeof style.borderWidth === "number" ? style.borderWidth : 0;
25
+ const br = typeof style.borderRadius === "number" ? style.borderRadius : 0;
26
+ const fontWeight = style.fontWeight || 400;
27
+ const containerAlign = style.alignment || style.textAlign || "left";
28
+ const explicitWidth = typeof style.width === "number" && style.width > 0 ? style.width : 0;
29
+ const estimatedTextWidth = Math.ceil((text || "").length * fs * 0.62);
30
+ const vmlWidthBase = explicitWidth || Math.max(120, estimatedTextWidth + padLeft + padRight + bw * 2);
31
+ const minPillWidth = br > 0 ? Math.ceil(finalHeight * 2) : 0;
32
+ const vmlWidth = Math.max(vmlWidthBase, minPillWidth);
33
+ const borderCss = bw > 0 ? `border:${bw}px ${bdStyle} ${bdColor};` : "";
34
+ const widthCss = explicitWidth ? `width:${explicitWidth}px;` : "";
35
+ const nonMsoVerticalSizing = explicitHeight > 0
36
+ ? `height:${finalHeight}px;line-height:${finalHeight}px;padding:0 ${padRight}px 0 ${padLeft}px;`
37
+ : `padding:${padTop}px ${padRight}px ${padBottom}px ${padLeft}px;line-height:${fs}px;`;
38
+ const nonMsoAnchor = `<!--[if !mso]><!-->
39
+ <a href="${navigateToUrl}"
40
+ target="_blank" rel="noreferrer noopener"
41
+ 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;${nonMsoVerticalSizing}text-align:center;white-space:nowrap;-webkit-text-size-adjust:none;box-sizing:border-box;${widthCss}mso-hide:all;">${text}</a>
42
+ <!--<![endif]-->`;
43
+ const arcSizePct = br > 0 ? Math.min(Math.round((br / (finalHeight / 2)) * 100), 50) : 0;
44
+ const strokeAttrs = bw > 0
45
+ ? `stroke="true" strokecolor="${bdColor}" strokeweight="${bw}px"`
46
+ : `stroke="false"`;
47
+ const msoButton = `<!--[if mso]>
48
+ <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
49
+ href="${navigateToUrl}"
50
+ style="height:${finalHeight}px;v-text-anchor:middle;width:${vmlWidth}px;"
51
+ arcsize="${arcSizePct}%"
52
+ ${strokeAttrs}
53
+ fillcolor="${bgColor}">
54
+ <w:anchorlock/>
55
+ <v:textbox inset="0,0,0,0">
56
+ <center style="color:${safeColor};font-family:${safeFF};font-size:${fs}px;font-weight:${fontWeight};mso-line-height-rule:exactly;line-height:${finalHeight}px;text-decoration:none;">${text}</center>
57
+ </v:textbox>
58
+ </v:roundrect>
59
+ <![endif]-->`;
60
+ const innerContent = containerAlign === "center"
61
+ ? `<center>${msoButton}${nonMsoAnchor}</center>`
62
+ : `<div style="text-align:${containerAlign};">${msoButton}${nonMsoAnchor}</div>`;
63
+ return {
64
+ innerContent,
65
+ computed: {
66
+ fs, fontWeight, containerAlign,
67
+ padTop, padRight, padBottom, padLeft,
68
+ explicitWidth, vmlWidth,
69
+ safeColor, bgColor, safeFF,
70
+ finalHeight, explicitHeight,
71
+ bw, br, bdColor, bdStyle,
72
+ },
73
+ };
74
+ }
75
+ function convertButtonBlock(blockData) {
76
+ const { style, props } = blockData.data;
77
+ const { text, navigateToUrl } = props;
78
+ const { fontFamily, fontSize, fontWeight, textAlign, borderColor, borderRadius, borderWidth, borderStyle, buttonPadding, color, buttonColor, width, height, alignment, padding, backgroundColor: containerBg, } = style;
79
+ const visibilityClass = (0, common_1.getVisibilityClass)(props);
80
+ const { innerContent, computed } = appendOutlookForButton({
81
+ style: {
82
+ fontFamily, fontSize, fontWeight, textAlign,
83
+ borderColor, borderRadius, borderWidth, borderStyle,
84
+ buttonPadding, color, buttonColor, width, height, alignment,
85
+ },
86
+ text: text || "",
87
+ navigateToUrl: navigateToUrl || "",
88
+ });
89
+ const buttonBlockProps = (0, common_1.encodeBlockPropsAttr)({
90
+ buttonText: text || "",
91
+ navigateToUrl: navigateToUrl || "",
92
+ buttonColor: computed.bgColor,
93
+ color: computed.safeColor,
94
+ fontFamily: fontFamily || "",
95
+ fontSize: computed.fs,
96
+ fontWeight: computed.fontWeight,
97
+ alignment: computed.containerAlign,
98
+ padding: {
99
+ top: padding?.top || 0,
100
+ right: padding?.right || 0,
101
+ bottom: padding?.bottom || 0,
102
+ left: padding?.left || 0,
103
+ },
104
+ buttonPadding: {
105
+ top: computed.padTop,
106
+ right: computed.padRight,
107
+ bottom: computed.padBottom,
108
+ left: computed.padLeft,
109
+ },
110
+ width: computed.explicitWidth,
111
+ height: typeof height === "number" && height > 0 ? height : 0,
112
+ backgroundColor: containerBg || "",
113
+ borderRadius: computed.br,
114
+ borderColor: computed.bdColor,
115
+ borderWidth: computed.bw,
116
+ borderStyle: computed.bdStyle,
117
+ hideOnDesktop: Boolean(props.hideOnDesktop),
118
+ hideOnMobile: Boolean(props.hideOnMobile),
119
+ });
120
+ return `
121
+ <table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" class="${visibilityClass}" data-block-type="button" data-block-props="${buttonBlockProps}">
122
+ <tr>
123
+ <td align="${computed.containerAlign}"
124
+ style="padding:${padding?.top || 0}px ${padding?.right || 0}px ${padding?.bottom || 0}px ${padding?.left || 0}px;background-color:${containerBg || 'transparent'};">
125
+ ${innerContent}
126
+ </td>
127
+ </tr>
128
+ </table>
129
+ `;
130
+ }
@@ -0,0 +1,4 @@
1
+ export declare function convertDividerBlockToHtml(blockData: any): string;
2
+ export declare function convertSpacerBlockToHtml(blockData: any): string;
3
+ export declare function convertVerticalDividerBlockToHtml(blockData: any): string;
4
+ //# sourceMappingURL=dividers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dividers.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/dividers.ts"],"names":[],"mappings":"AAIA,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,GAAG,UAuCvD;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,GAAG,UAKtD;AAED,wBAAgB,iCAAiC,CAAC,SAAS,EAAE,GAAG,UAwB/D"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertDividerBlockToHtml = convertDividerBlockToHtml;
4
+ exports.convertSpacerBlockToHtml = convertSpacerBlockToHtml;
5
+ exports.convertVerticalDividerBlockToHtml = convertVerticalDividerBlockToHtml;
6
+ const buildStyles_1 = require("../buildStyles");
7
+ const outlookSupport_1 = require("../outlookSupport");
8
+ const common_1 = require("../common");
9
+ function convertDividerBlockToHtml(blockData) {
10
+ const { style, props } = blockData.data;
11
+ const { hideOnMobile, hideOnDesktop } = props;
12
+ const { thickness, dividerColor, width, alignment, ...rest } = style;
13
+ const convertedStyle = (0, buildStyles_1.buildStyles)(rest, { perChanges: [], pxChanges: buildStyles_1.allPxAttributes });
14
+ const dividerWidth = width || 100;
15
+ const alignAttr = alignment === 'center' ? 'center' : alignment === 'right' ? 'right' : 'left';
16
+ const alignMargin = alignAttr === 'center' ? '0 auto' : alignAttr === 'right' ? '0 0 0 auto' : '0 auto 0 0';
17
+ const contentStyle = convertedStyle
18
+ ? `${convertedStyle}; text-align:${alignAttr};`
19
+ : `text-align:${alignAttr};`;
20
+ const visibilityClass = [
21
+ hideOnMobile ? "hide-mobile" : "",
22
+ hideOnDesktop ? "hide-desktop" : "",
23
+ ].filter(Boolean).join(" ");
24
+ const dividerContent = `
25
+ <table
26
+ align="${alignAttr}"
27
+ width="${dividerWidth}%"
28
+ cellpadding="0"
29
+ cellspacing="0"
30
+ style="margin:${alignMargin};"
31
+ >
32
+ <tr>
33
+ <td
34
+ height="${thickness}"
35
+ style="font-size:1px; line-height:1px; background:${dividerColor}; width:100%;"
36
+ >
37
+ &nbsp;
38
+ </td>
39
+ </tr>
40
+ </table>
41
+ `;
42
+ return (0, outlookSupport_1.appendOutlookSupport)(dividerContent, contentStyle, visibilityClass);
43
+ }
44
+ function convertSpacerBlockToHtml(blockData) {
45
+ const { style, props } = blockData.data;
46
+ const visibilityClass = (0, common_1.getVisibilityClass)(props);
47
+ const styles = (0, buildStyles_1.buildStyles)(style, { perChanges: [], pxChanges: buildStyles_1.allPxAttributes });
48
+ return (0, outlookSupport_1.appendOutlookSupport)(``, styles, visibilityClass);
49
+ }
50
+ function convertVerticalDividerBlockToHtml(blockData) {
51
+ const { style, props } = blockData.data;
52
+ const { width, height, dividerColor, padding, backgroundColor } = style;
53
+ const visibilityClass = (0, common_1.getVisibilityClass)(props);
54
+ const outerStyles = (0, buildStyles_1.buildStyles)({ padding, backgroundColor }, {
55
+ perChanges: [],
56
+ pxChanges: buildStyles_1.allPxAttributes,
57
+ });
58
+ return `
59
+ <table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
60
+ style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}" data-block-type="vdivider">
61
+ <tr>
62
+ <td style="${outerStyles}; text-align:center; vertical-align:middle;">
63
+ <!--[if mso | IE]>
64
+ <v:rect xmlns:v="urn:schemas-microsoft-com:vml" fillcolor="${dividerColor}" style="width:${width}px;height:${height}px;" stroke="f"></v:rect>
65
+ <![endif]-->
66
+ <!--[if !mso]><!-->
67
+ <div style="display:inline-block;width:${width}px;height:${height}px;background:${dividerColor};line-height:0;font-size:0;">&nbsp;</div>
68
+ <!--<![endif]-->
69
+ </td>
70
+ </tr>
71
+ </table>`;
72
+ }
@@ -0,0 +1,6 @@
1
+ export declare function convertGridBlock(blockData: any, rootData: any, cellWidthInPx: number): Promise<string>;
2
+ export declare function convertGridCellBlock(blockData: any, rootData: any, cellWidthPercent: number, parentCellWidthPx: number, parentGridHasBorder?: boolean): Promise<{
3
+ html: string;
4
+ styles: string;
5
+ }>;
6
+ //# sourceMappingURL=grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/grid.ts"],"names":[],"mappings":"AAKA,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAiO1F;AAED,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE,GAAG,EACb,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,EACzB,mBAAmB,UAAQ;;;GAuD5B"}
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertGridBlock = convertGridBlock;
4
+ exports.convertGridCellBlock = convertGridCellBlock;
5
+ const buildStyles_1 = require("../buildStyles");
6
+ const gradientUtils_1 = require("../gradientUtils");
7
+ const common_1 = require("../common");
8
+ const jsonToHTML_1 = require("../jsonToHTML");
9
+ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
10
+ const { style = {}, childrenIds = [], props } = blockData.data;
11
+ const { columns = 1, cellWidths = [], responsive = true } = props;
12
+ const { columnGap = 0, backgroundImage, backgroundColor, ...restStyle } = style;
13
+ const gridVisibilityClass = (0, common_1.getVisibilityClass)(props);
14
+ const bgImageStr = typeof backgroundImage === "string" ? backgroundImage : '';
15
+ const customCssStr = restStyle.customCss || '';
16
+ const gradientInCustomCss = !bgImageStr.includes('gradient(') && customCssStr.includes('gradient(')
17
+ ? (customCssStr.match(/(?:linear|radial|conic)-gradient\([^)]+(?:\([^)]*\)[^)]*)*\)/)?.[0] || '')
18
+ : '';
19
+ const effectiveGradient = bgImageStr.includes('gradient(') ? bgImageStr : gradientInCustomCss;
20
+ const isGradient = Boolean(effectiveGradient);
21
+ const parsedGradient = isGradient ? (0, gradientUtils_1.parseGradient)(effectiveGradient) : null;
22
+ const fallbackBgColor = backgroundColor ||
23
+ parsedGradient?.fallback ||
24
+ (0, gradientUtils_1.extractCssFallbackColor)(customCssStr) ||
25
+ "#ffffff";
26
+ const rawBgImageUrl = !isGradient && bgImageStr
27
+ ? bgImageStr.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "")
28
+ : null;
29
+ const innerCustomCss = gradientInCustomCss
30
+ ? customCssStr.replace(/background-image\s*:[^;]+;?/gi, '').trim()
31
+ : customCssStr;
32
+ const innerRestStyleRaw = (rawBgImageUrl || isGradient)
33
+ ? { ...restStyle, customCss: innerCustomCss, backgroundSize: undefined, backgroundPosition: undefined, backgroundRepeat: undefined }
34
+ : { ...restStyle, customCss: innerCustomCss };
35
+ const { borderRadius, border, borderColor, borderWidth, borderStyle: borderStyleProp, ...innerRestStyle } = innerRestStyleRaw;
36
+ const divBorderParts = [];
37
+ if (borderRadius)
38
+ divBorderParts.push(`border-radius:${typeof borderRadius === 'number' ? borderRadius + 'px' : borderRadius};`, `overflow:hidden;`);
39
+ if (border) {
40
+ divBorderParts.push(`border:${border};`);
41
+ }
42
+ else if (borderWidth || borderColor || borderStyleProp) {
43
+ const bw = borderWidth ? (typeof borderWidth === 'number' ? borderWidth + 'px' : borderWidth) : '1px';
44
+ const bs = borderStyleProp || 'solid';
45
+ const bc = borderColor || '#000000';
46
+ divBorderParts.push(`border:${bw} ${bs} ${bc};`);
47
+ }
48
+ const divBorderStyle = divBorderParts.join(' ');
49
+ const tableBgForNonMso = divBorderStyle
50
+ ? 'transparent'
51
+ : ((rawBgImageUrl || isGradient) ? undefined : backgroundColor);
52
+ const tableStyles = (0, buildStyles_1.buildStyles)({ backgroundColor: tableBgForNonMso, ...innerRestStyle }, {
53
+ perChanges: [], pxChanges: buildStyles_1.allPxAttributes,
54
+ });
55
+ const total = childrenIds.length;
56
+ const visualRows = Math.ceil(total / columns);
57
+ const msoTableWidth = Math.min(cellWidthInPx, 600);
58
+ const msoBgColor = !rawBgImageUrl && !isGradient ? (backgroundColor || '') : '';
59
+ const msoBgAttr = msoBgColor ? ` bgcolor="${msoBgColor}"` : '';
60
+ const msoBgStyle = msoBgColor ? `background-color:${msoBgColor};` : '';
61
+ const innerBgTransparent = (rawBgImageUrl || isGradient) ? 'background-color:transparent;' : '';
62
+ const nonMsoBgAttr = !rawBgImageUrl && !isGradient && backgroundColor && !divBorderStyle ? ` bgcolor="${backgroundColor}"` : '';
63
+ const divWrapBg = divBorderStyle && backgroundColor && !rawBgImageUrl && !isGradient
64
+ ? ` background-color:${backgroundColor};`
65
+ : '';
66
+ const divWrapOpen = divBorderStyle ? `<div style="${divBorderStyle}${divWrapBg}">` : '';
67
+ const divWrapClose = divBorderStyle ? `</div>` : '';
68
+ let html = `
69
+ <!--[if mso]>
70
+ <table border="0" cellpadding="0" cellspacing="0" width="${msoTableWidth}"${msoBgAttr}
71
+ style="border-collapse:collapse;width:${msoTableWidth}px;${msoBgStyle}${innerBgTransparent}"
72
+ class="${gridVisibilityClass}">
73
+ <![endif]-->
74
+ <!--[if !mso]><!-->
75
+ <table border="0" cellpadding="0" cellspacing="0" width="100%"
76
+ role="presentation"${nonMsoBgAttr}
77
+ style="border-collapse:collapse; ${innerBgTransparent}${tableStyles}; max-width:600px;"
78
+ class="${gridVisibilityClass}">
79
+ <!--<![endif]-->
80
+ `;
81
+ for (let r = 0; r < visualRows; r++) {
82
+ html += "<tr>";
83
+ let visibleCells = 0;
84
+ let lastVisibleCol = 0;
85
+ const rowIds = [];
86
+ for (let c = 0; c < columns; c++) {
87
+ const idx = r * columns + c;
88
+ const id = childrenIds[idx] ?? null;
89
+ rowIds.push(id);
90
+ const child = id ? rootData[id] : null;
91
+ if (!child?.data?.props?.hideOnDesktop) {
92
+ visibleCells++;
93
+ lastVisibleCol = c;
94
+ }
95
+ }
96
+ const safeWidth = visibleCells > 0 ? 100 / visibleCells : 100 / columns;
97
+ const totalGapPx = columnGap * Math.max(visibleCells - 1, 0);
98
+ const adjustedTableWidth = Math.max(msoTableWidth - totalGapPx, 1);
99
+ let totalWidth = 0;
100
+ const cellWidthPercents = [];
101
+ for (let c = 0; c < columns; c++) {
102
+ const id = rowIds[c];
103
+ let widthPercent = cellWidths[c] ?? safeWidth;
104
+ if (widthPercent <= 0 || widthPercent > 100)
105
+ widthPercent = safeWidth;
106
+ cellWidthPercents.push(widthPercent);
107
+ if (id) {
108
+ const child = rootData[id];
109
+ if (!child?.data?.props?.hideOnDesktop)
110
+ totalWidth += widthPercent;
111
+ }
112
+ }
113
+ const scaleFactor = totalWidth > 0 && totalWidth < 100 ? 100 / totalWidth : 1;
114
+ for (let c = 0; c < columns; c++) {
115
+ const id = rowIds[c];
116
+ let widthPercent = Math.min(cellWidthPercents[c] * scaleFactor, 100);
117
+ const cellWidthPx = Math.round((widthPercent / 100) * adjustedTableWidth);
118
+ if (id) {
119
+ const child = rootData[id];
120
+ const { style: cellStyle = {}, props: childProps = {} } = child.data;
121
+ const verticalAlign = cellStyle.verticalAlign || "top";
122
+ const childVisible = !childProps.hideOnDesktop;
123
+ const visibilityClass = (0, common_1.getVisibilityClass)(childProps);
124
+ if (childVisible) {
125
+ const { html: childHtml, styles } = await convertGridCellBlock(child, rootData, widthPercent, adjustedTableWidth, Boolean(divBorderStyle));
126
+ const cellBgColor = cellStyle.backgroundColor || '';
127
+ const cellBgAttr = cellBgColor ? ` bgcolor="${cellBgColor}"` : '';
128
+ html += `
129
+ <td
130
+ width="${cellWidthPx}"${cellBgAttr}
131
+ class="${[responsive ? "stack-column" : "", visibilityClass].filter(Boolean).join(" ")}"
132
+ style="width:${cellWidthPx}px;vertical-align:${verticalAlign};word-break:break-word;${styles}"
133
+ >
134
+ ${childHtml}
135
+ </td>`;
136
+ if (columnGap > 0 && c !== lastVisibleCol) {
137
+ html += `<td width="${columnGap}" style="width:${columnGap}px;font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
138
+ }
139
+ }
140
+ }
141
+ else {
142
+ html += `
143
+ <td width="${cellWidthPx}"
144
+ ${responsive ? 'class="stack-column"' : ""}
145
+ style="width:${cellWidthPx}px;vertical-align:top;">
146
+ </td>`;
147
+ if (columnGap > 0 && c !== lastVisibleCol) {
148
+ html += `<td width="${columnGap}" style="width:${columnGap}px;font-size:0;line-height:0;padding:0;" aria-hidden="true"></td>`;
149
+ }
150
+ }
151
+ }
152
+ html += "</tr>";
153
+ }
154
+ html += `
155
+ <!--[if mso]>
156
+ </table>
157
+ <![endif]-->
158
+ <!--[if !mso]><!-->
159
+ </table>
160
+ <!--<![endif]-->
161
+ `;
162
+ if (rawBgImageUrl || isGradient) {
163
+ const vmlFill = isGradient
164
+ ? (() => {
165
+ const vmlAngle = (0, gradientUtils_1.cssAngleToVml)(parsedGradient?.angle || 180);
166
+ const c1 = parsedGradient?.fallback || '#ffffff';
167
+ const c2 = parsedGradient?.colors[parsedGradient.colors.length - 1] || c1;
168
+ return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
169
+ })()
170
+ : `<v:fill type="frame" src="${rawBgImageUrl}" color="${fallbackBgColor}" />`;
171
+ html = `
172
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
173
+ style="border-collapse:collapse;width:100%;max-width:${msoTableWidth}px;">
174
+ <tr>
175
+ <td width="100%" bgcolor="${fallbackBgColor}" valign="top"
176
+ ${!isGradient && rawBgImageUrl ? `background="${rawBgImageUrl}"` : ""}
177
+ style="
178
+ width:100%;max-width:${msoTableWidth}px;
179
+ background-color:${fallbackBgColor};
180
+ ${isGradient ? `background:${effectiveGradient};` : `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`}
181
+ ">
182
+
183
+ <!--[if gte mso 9]>
184
+ <v:rect xmlns:v="urn:schemas-microsoft-com:vml"
185
+ fill="true" stroke="false"
186
+ style="width:${msoTableWidth}px;">
187
+ ${vmlFill}
188
+ <v:textbox inset="0,0,0,0">
189
+ <![endif]-->
190
+
191
+ ${html}
192
+
193
+ <!--[if gte mso 9]>
194
+ </v:textbox>
195
+ </v:rect>
196
+ <![endif]-->
197
+
198
+ </td>
199
+ </tr>
200
+ </table>`;
201
+ }
202
+ if (divBorderStyle)
203
+ html = `${divWrapOpen}${html}${divWrapClose}`;
204
+ return html;
205
+ }
206
+ async function convertGridCellBlock(blockData, rootData, cellWidthPercent, parentCellWidthPx, parentGridHasBorder = false) {
207
+ const { style = {}, childrenIds = [], props = {} } = blockData.data;
208
+ const { borderRadius: cellBorderRadius, borderWidth: cellBorderWidth, borderStyle: cellBorderStyleProp, borderColor: cellBorderColor, border: cellBorderShorthand, ...styleWithoutBorder } = style;
209
+ const stripBgFromTd = Boolean(cellBorderRadius) || parentGridHasBorder;
210
+ const styleForTd = stripBgFromTd
211
+ ? { ...styleWithoutBorder, backgroundColor: 'transparent' }
212
+ : styleWithoutBorder;
213
+ const styles = (0, buildStyles_1.buildStyles)(styleForTd, { perChanges: [], pxChanges: buildStyles_1.allPxAttributes });
214
+ const parts = [];
215
+ const cellWidthPx = Math.round((cellWidthPercent / 100) * parentCellWidthPx);
216
+ const cellPad = styleWithoutBorder?.padding || {};
217
+ const cellPadLeft = Number.isFinite(cellPad.left) ? cellPad.left : 0;
218
+ const cellPadRight = Number.isFinite(cellPad.right) ? cellPad.right : 0;
219
+ const contentWidthPx = Math.max(cellWidthPx - cellPadLeft - cellPadRight, 20);
220
+ const safeCellWidthPx = Math.min(contentWidthPx, 600);
221
+ for (const childId of childrenIds) {
222
+ const child = rootData[childId];
223
+ if (child)
224
+ parts.push(await (0, jsonToHTML_1.convertToHtml)(child, rootData, safeCellWidthPx));
225
+ }
226
+ const borderRadius = cellBorderRadius || 0;
227
+ const bgColor = styleWithoutBorder?.backgroundColor || "transparent";
228
+ const cellDivBorderParts = [];
229
+ if (!parentGridHasBorder) {
230
+ if (borderRadius)
231
+ cellDivBorderParts.push(`border-radius:${typeof borderRadius === 'number' ? borderRadius + 'px' : borderRadius};`, `overflow:hidden;`);
232
+ if (cellBorderShorthand) {
233
+ cellDivBorderParts.push(`border:${cellBorderShorthand};`);
234
+ }
235
+ else if (cellBorderWidth || cellBorderColor || cellBorderStyleProp) {
236
+ const bw = cellBorderWidth ? (typeof cellBorderWidth === 'number' ? cellBorderWidth + 'px' : cellBorderWidth) : '1px';
237
+ const bs = cellBorderStyleProp || 'solid';
238
+ const bc = cellBorderColor || '#000000';
239
+ cellDivBorderParts.push(`border:${bw} ${bs} ${bc};`);
240
+ }
241
+ }
242
+ const cellDivBorderStyle = cellDivBorderParts.join(' ');
243
+ const divStyleParts = [`background-color:${bgColor};`];
244
+ if (cellDivBorderStyle)
245
+ divStyleParts.push(cellDivBorderStyle);
246
+ const wrapped = `<div style="${divStyleParts.join(' ')}">${parts.join("")}</div>`;
247
+ return { html: wrapped, styles };
248
+ }
@@ -0,0 +1,8 @@
1
+ export declare function computeScaledDimensions(imageUrl: string, maxContainerWidthPx: number): Promise<{
2
+ originalWidth: number;
3
+ originalHeight: number;
4
+ scaledWidth: number;
5
+ scaledHeight: number;
6
+ }>;
7
+ export declare function convertImageBlock(blockData: any, cellWidthInPx: number): Promise<string>;
8
+ //# sourceMappingURL=image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/image.ts"],"names":[],"mappings":"AAIA,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM;;;;;GAiB1F;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBA2D5E"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeScaledDimensions = computeScaledDimensions;
4
+ exports.convertImageBlock = convertImageBlock;
5
+ const buildStyles_1 = require("../buildStyles");
6
+ const outlookSupport_1 = require("../outlookSupport");
7
+ const common_1 = require("../common");
8
+ async function computeScaledDimensions(imageUrl, maxContainerWidthPx) {
9
+ if (!imageUrl) {
10
+ const w = Math.max(maxContainerWidthPx, 1);
11
+ const h = Math.round(w * (2 / 3));
12
+ return { originalWidth: w, originalHeight: h, scaledWidth: w, scaledHeight: h };
13
+ }
14
+ try {
15
+ const { width: originalWidth, height: originalHeight } = await (0, outlookSupport_1.loadImageNaturalDimensions)(imageUrl);
16
+ const widthScalingFactor = Math.min(maxContainerWidthPx / originalWidth, 1);
17
+ const scaledWidth = Math.round(originalWidth * widthScalingFactor);
18
+ const scaledHeight = Math.round(originalHeight * widthScalingFactor);
19
+ return { originalWidth, originalHeight, scaledWidth, scaledHeight };
20
+ }
21
+ catch {
22
+ const w = Math.max(maxContainerWidthPx, 1);
23
+ const h = Math.round(w * (2 / 3));
24
+ return { originalWidth: w, originalHeight: h, scaledWidth: w, scaledHeight: h };
25
+ }
26
+ }
27
+ async function convertImageBlock(blockData, cellWidthInPx) {
28
+ const { style, props } = blockData.data;
29
+ const { altText, imageUrl, navigateToUrl } = props;
30
+ const visibilityClass = (0, common_1.getVisibilityClass)(props);
31
+ const { width, height, objectFit, borderRadius, borderWidth, borderColor, borderStyle, ...containerStyle } = style;
32
+ const containerStyles = (0, buildStyles_1.buildStyles)({ ...containerStyle }, { perChanges: [], pxChanges: buildStyles_1.addPxToAttributes });
33
+ const safeCellWidth = Math.min(cellWidthInPx, 600);
34
+ const widthPercent = typeof width === "string" && width.includes("%")
35
+ ? parseInt(width.replace("%", ""))
36
+ : typeof width === "number" ? width : 100;
37
+ const paddingLeft = style?.padding?.left || 0;
38
+ const paddingRight = style?.padding?.right || 0;
39
+ const availableWidth = safeCellWidth - paddingLeft - paddingRight;
40
+ const innerContainerWidth = Math.round((widthPercent / 100) * availableWidth);
41
+ const { originalWidth, originalHeight, scaledWidth, scaledHeight } = await computeScaledDimensions(imageUrl, innerContainerWidth);
42
+ const finalWidth = Math.min(scaledWidth, innerContainerWidth, originalWidth);
43
+ const finalHeight = Math.round((finalWidth / originalWidth) * originalHeight);
44
+ const imageTagStyles = (0, buildStyles_1.buildStyles)({ borderStyle, borderRadius, borderColor, borderWidth }, { perChanges: [], pxChanges: buildStyles_1.addPxToAttributes });
45
+ const imageElement = `<img src="${imageUrl}" alt="${altText || "Image"}" border="0" width="${finalWidth}" height="${finalHeight}" style="${imageTagStyles}; display:block; max-width:100%; height:auto; line-height: 0;" />`;
46
+ const percentWidth = typeof width === "string" && width.endsWith("%")
47
+ ? width
48
+ : typeof width === "number" ? `${width}%` : "100%";
49
+ const imgTextAlign = containerStyle.textAlign || "left";
50
+ const imgMargin = imgTextAlign === "center" ? "margin:0 auto;" :
51
+ imgTextAlign === "right" ? "margin-left:auto; margin-right:0;" : "";
52
+ const nonMsoWrapper = `<div style="display:block; width:${percentWidth}; max-width:${finalWidth}px; line-height:0; font-size:0; ${imgMargin}">${imageElement}</div>`;
53
+ const outlookImage = await (0, outlookSupport_1.appendOutlookForImage)(nonMsoWrapper, safeCellWidth, innerContainerWidth, imageUrl, style, finalWidth, finalHeight);
54
+ const imageContent = (0, outlookSupport_1.appendOutlookSupport)(outlookImage, containerStyles, visibilityClass, safeCellWidth);
55
+ return navigateToUrl
56
+ ? `<a href="${navigateToUrl}" target="_blank" rel="noreferrer noopener" style="display:block;">${imageContent}</a>`
57
+ : imageContent;
58
+ }
@@ -0,0 +1,2 @@
1
+ export declare function convertShapeBlock(blockData: any): Promise<string>;
2
+ //# sourceMappingURL=shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/shape.ts"],"names":[],"mappings":"AAuHA,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,mBA2MrD"}