email-builder-utils 1.1.48 → 1.1.49

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.
@@ -1 +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"}
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/grid.ts"],"names":[],"mappings":"AAMA,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;;;GAoE5B"}
@@ -6,6 +6,7 @@ const buildStyles_1 = require("../buildStyles");
6
6
  const gradientUtils_1 = require("../gradientUtils");
7
7
  const common_1 = require("../common");
8
8
  const jsonToHTML_1 = require("../jsonToHTML");
9
+ const outlookSupport_1 = require("../outlookSupport");
9
10
  async function convertGridBlock(blockData, rootData, cellWidthInPx) {
10
11
  const { style = {}, childrenIds = [], props } = blockData.data;
11
12
  const { columns = 1, cellWidths = [], responsive = true } = props;
@@ -56,10 +57,10 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
56
57
  const visualRows = Math.ceil(total / columns);
57
58
  const msoTableWidth = Math.min(cellWidthInPx, 600);
58
59
  const msoBgColor = !rawBgImageUrl && !isGradient ? (backgroundColor || '') : '';
59
- const msoBgAttr = msoBgColor ? ` bgcolor="${msoBgColor}"` : '';
60
+ const msoBgAttr = msoBgColor ? ` bgcolor="${(0, outlookSupport_1.toOutlookBgColor)(msoBgColor)}"` : '';
60
61
  const msoBgStyle = msoBgColor ? `background-color:${msoBgColor};` : '';
61
62
  const innerBgTransparent = (rawBgImageUrl || isGradient) ? 'background-color:transparent;' : '';
62
- const nonMsoBgAttr = !rawBgImageUrl && !isGradient && backgroundColor && !divBorderStyle ? ` bgcolor="${backgroundColor}"` : '';
63
+ const nonMsoBgAttr = !rawBgImageUrl && !isGradient && backgroundColor && !divBorderStyle ? ` bgcolor="${(0, outlookSupport_1.toOutlookBgColor)(backgroundColor)}"` : '';
63
64
  const divWrapBg = divBorderStyle && backgroundColor && !rawBgImageUrl && !isGradient
64
65
  ? ` background-color:${backgroundColor};`
65
66
  : '';
@@ -124,7 +125,7 @@ async function convertGridBlock(blockData, rootData, cellWidthInPx) {
124
125
  if (childVisible) {
125
126
  const { html: childHtml, styles } = await convertGridCellBlock(child, rootData, widthPercent, adjustedTableWidth, Boolean(divBorderStyle));
126
127
  const cellBgColor = cellStyle.backgroundColor || '';
127
- const cellBgAttr = cellBgColor ? ` bgcolor="${cellBgColor}"` : '';
128
+ const cellBgAttr = cellBgColor ? ` bgcolor="${(0, outlookSupport_1.toOutlookBgColor)(cellBgColor)}"` : '';
128
129
  html += `
129
130
  <td
130
131
  width="${cellWidthPx}"${cellBgAttr}
@@ -207,15 +208,41 @@ async function convertGridCellBlock(blockData, rootData, cellWidthPercent, paren
207
208
  const { style = {}, childrenIds = [], props = {} } = blockData.data;
208
209
  const { borderRadius: cellBorderRadius, borderWidth: cellBorderWidth, borderStyle: cellBorderStyleProp, borderColor: cellBorderColor, border: cellBorderShorthand, ...styleWithoutBorder } = style;
209
210
  const stripBgFromTd = Boolean(cellBorderRadius) || parentGridHasBorder;
211
+ // Omit backgroundColor entirely rather than setting 'transparent' — an explicit
212
+ // background-color:transparent can defeat the bgcolor HTML attribute in Old Outlook
213
+ // (Word engine), leaving the cell with no background at all.
210
214
  const styleForTd = stripBgFromTd
211
- ? { ...styleWithoutBorder, backgroundColor: 'transparent' }
215
+ ? { ...styleWithoutBorder, backgroundColor: undefined }
212
216
  : styleWithoutBorder;
213
217
  const styles = (0, buildStyles_1.buildStyles)(styleForTd, { perChanges: [], pxChanges: buildStyles_1.allPxAttributes });
214
218
  const parts = [];
215
219
  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;
220
+ const rawPad = styleWithoutBorder?.padding;
221
+ let cellPadLeft = 0;
222
+ let cellPadRight = 0;
223
+ if (rawPad && typeof rawPad === 'object') {
224
+ cellPadLeft = Number.isFinite(rawPad.left) ? rawPad.left : 0;
225
+ cellPadRight = Number.isFinite(rawPad.right) ? rawPad.right : 0;
226
+ }
227
+ else if (typeof rawPad === 'string') {
228
+ const parts = rawPad.trim().split(/\s+/).map(v => parseFloat(v) || 0);
229
+ if (parts.length >= 4) {
230
+ cellPadRight = parts[1];
231
+ cellPadLeft = parts[3];
232
+ }
233
+ else if (parts.length === 3) {
234
+ cellPadRight = parts[1];
235
+ cellPadLeft = parts[1];
236
+ }
237
+ else if (parts.length === 2) {
238
+ cellPadRight = parts[1];
239
+ cellPadLeft = parts[1];
240
+ }
241
+ else if (parts.length === 1) {
242
+ cellPadRight = parts[0];
243
+ cellPadLeft = parts[0];
244
+ }
245
+ }
219
246
  const contentWidthPx = Math.max(cellWidthPx - cellPadLeft - cellPadRight, 20);
220
247
  const safeCellWidthPx = Math.min(contentWidthPx, 600);
221
248
  for (const childId of childrenIds) {
@@ -42,7 +42,7 @@ async function convertImageBlock(blockData, cellWidthInPx) {
42
42
  const finalWidth = Math.min(scaledWidth, innerContainerWidth, originalWidth);
43
43
  const finalHeight = Math.round((finalWidth / originalWidth) * originalHeight);
44
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;" />`;
45
+ 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;" />`;
46
46
  const percentWidth = typeof width === "string" && width.endsWith("%")
47
47
  ? width
48
48
  : typeof width === "number" ? `${width}%` : "100%";
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/text.ts"],"names":[],"mappings":"AAKA,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,MAAM,UAsItE"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/utils/blocks/text.ts"],"names":[],"mappings":"AAKA,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,MAAM,UA4ItE"}
@@ -8,7 +8,7 @@ const common_1 = require("../common");
8
8
  function convertTextBlock(blockData, cellWidthInPx) {
9
9
  const { style, props } = blockData.data;
10
10
  const visibilityClass = (0, common_1.getVisibilityClass)(props);
11
- const { width, backgroundColor, padding, borderRadius, borderStyle, borderColor, borderWidth, textContainerBackgroundColor, textContainerPadding, fontSize, backgroundImage, whiteSpace: _whiteSpace, ...rest } = style;
11
+ const { width, backgroundColor, padding, borderRadius, borderStyle, borderColor, borderWidth, textContainerBackgroundColor, textContainerPadding, fontSize, backgroundImage, backgroundPosition, backgroundRepeat, backgroundSize, whiteSpace: _whiteSpace, ...rest } = style;
12
12
  const bgImageStr = typeof backgroundImage === 'string' ? backgroundImage : '';
13
13
  const customCssStr = rest.customCss || '';
14
14
  const gradientInCustomCss = !bgImageStr.includes('gradient(') && customCssStr.includes('gradient(')
@@ -67,9 +67,12 @@ function convertTextBlock(blockData, cellWidthInPx) {
67
67
  return `<v:fill type="gradient" color="${c1}" color2="${c2}" angle="${vmlAngle}" />`;
68
68
  })()
69
69
  : `<v:fill type="frame" src="${rawBgImageUrl}" color="${fallbackBgColor}" />`;
70
+ const bgPosition = backgroundPosition ?? 'center center';
71
+ const bgSize = backgroundSize ?? 'cover';
72
+ const bgRepeat = backgroundRepeat ?? 'no-repeat';
70
73
  const bgCss = isGradient
71
74
  ? `background:${effectiveGradient};`
72
- : `background-image:url('${rawBgImageUrl}'); background-position:center center; background-size:cover; background-repeat:no-repeat;`;
75
+ : `background-image:url('${rawBgImageUrl}'); background-position:${bgPosition}; background-size:${bgSize}; background-repeat:${bgRepeat};`;
73
76
  const wrappedContent = `
74
77
  <table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation"
75
78
  style="border-collapse:collapse;width:100%;max-width:${msoWidth}px;" class="${visibilityClass}">
@@ -1 +1 @@
1
- {"version":3,"file":"convertJsonToHtml.d.ts","sourceRoot":"","sources":["../../src/utils/convertJsonToHtml.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,GAAU,UAAU,GAAG,oBAqLpD,CAAC"}
1
+ {"version":3,"file":"convertJsonToHtml.d.ts","sourceRoot":"","sources":["../../src/utils/convertJsonToHtml.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,GAAU,UAAU,GAAG,oBAuLpD,CAAC"}
@@ -88,6 +88,7 @@ const convertJsonToHtml = async (jsonData) => {
88
88
  @media only screen and (max-width: 600px) {
89
89
  .email-container {
90
90
  width: 100% !important;
91
+ max-width: 100% !important;
91
92
  }
92
93
 
93
94
  .stack-column,
@@ -138,6 +139,7 @@ const convertJsonToHtml = async (jsonData) => {
138
139
  table-layout: fixed;
139
140
  width: 100%;
140
141
  max-width: 600px;
142
+ margin: 0 auto;
141
143
  background-color: ${canvasColor || '#ffffff'};
142
144
  ${textColor ? `color: ${textColor};` : ''}
143
145
  ${borderWidth ? `border: ${borderWidth}px ${borderStyle || 'solid'} ${borderColor || 'transparent'};` : ''}
@@ -1,3 +1,2 @@
1
- export { tableCommonStyle } from "./buildStyles";
2
1
  export declare function convertToHtml(blockData: any, rootData: any, cellWidthInPx: number): Promise<string>;
3
2
  //# sourceMappingURL=jsonToHTML.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,wBAAsB,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAuBvF"}
1
+ {"version":3,"file":"jsonToHTML.d.ts","sourceRoot":"","sources":["../../src/utils/jsonToHTML.ts"],"names":[],"mappings":"AAaA,wBAAsB,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,mBAuBvF"}
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tableCommonStyle = void 0;
4
3
  exports.convertToHtml = convertToHtml;
5
4
  const types_1 = require("../types");
6
5
  const text_1 = require("./blocks/text");
@@ -10,8 +9,8 @@ const grid_1 = require("./blocks/grid");
10
9
  const dividers_1 = require("./blocks/dividers");
11
10
  const video_1 = require("./blocks/video");
12
11
  const shape_1 = require("./blocks/shape");
13
- var buildStyles_1 = require("./buildStyles");
14
- Object.defineProperty(exports, "tableCommonStyle", { enumerable: true, get: function () { return buildStyles_1.tableCommonStyle; } });
12
+ // Update: Use Gmail Mobile friendly tableCommonStyle
13
+ // export const tableCommonStyle = "border-collapse:collapse; table-layout:fixed; width:100%; max-width:600px; margin:0 auto;";
15
14
  async function convertToHtml(blockData, rootData, cellWidthInPx) {
16
15
  switch (blockData.type) {
17
16
  case types_1.BlockType.TEXT:
@@ -1,3 +1,4 @@
1
+ export declare function toOutlookBgColor(color: string): string;
1
2
  export declare function appendOutlookSupport(content: string, contentStyle: string, className?: string, msoWidth?: number): string;
2
3
  export declare function appendOutlookForImage(content: string, outerContainerWidth: number, innerContainerWidth: number, imageUrl: string, style?: any, finalWidth?: number, finalHeight?: number): Promise<string>;
3
4
  export declare function loadImageNaturalDimensions(imageUrl: string): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"outlookSupport.d.ts","sourceRoot":"","sources":["../../src/utils/outlookSupport.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,UAgClB;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,EAC3B,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,GAAQ,EACf,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,mBA2ErB;AAED,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAO7G"}
1
+ {"version":3,"file":"outlookSupport.d.ts","sourceRoot":"","sources":["../../src/utils/outlookSupport.ts"],"names":[],"mappings":"AAIA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtD;AAOD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,UAqClB;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,EAC3B,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,GAAQ,EACf,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,mBA2ErB;AAED,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAO7G"}
@@ -1,26 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toOutlookBgColor = toOutlookBgColor;
3
4
  exports.appendOutlookSupport = appendOutlookSupport;
4
5
  exports.appendOutlookForImage = appendOutlookForImage;
5
6
  exports.loadImageNaturalDimensions = loadImageNaturalDimensions;
6
7
  const buildStyles_1 = require("./buildStyles");
8
+ // Converts rgba(r,g,b,a) → #rrggbb for use in HTML bgcolor attributes.
9
+ // Old Outlook's bgcolor attribute only accepts solid hex or named colors — rgba is silently ignored.
10
+ function toOutlookBgColor(color) {
11
+ if (!color || color === 'transparent')
12
+ return '';
13
+ const m = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*[\d.]+)?\s*\)/);
14
+ if (m) {
15
+ return '#' + [m[1], m[2], m[3]].map(n => parseInt(n).toString(16).padStart(2, '0')).join('');
16
+ }
17
+ return color;
18
+ }
19
+ function extractBgColor(styleStr) {
20
+ const m = styleStr.match(/background-color\s*:\s*([^;]+)/i);
21
+ return m ? m[1].trim() : '';
22
+ }
7
23
  function appendOutlookSupport(content, contentStyle, className, msoWidth) {
8
24
  const visibilityClass = className || "";
9
25
  const shouldHideInOutlook = visibilityClass.includes("hide-desktop");
26
+ // bgcolor attribute is the reliable fallback for solid colors in Outlook and webmail
27
+ // forwarding chains where CSS background-color gets stripped.
28
+ const rawBg = extractBgColor(contentStyle);
29
+ const bgAttr = rawBg ? ` bgcolor="${toOutlookBgColor(rawBg)}"` : '';
10
30
  if (shouldHideInOutlook) {
11
31
  return `
12
32
  <!--[if !mso]><!-->
13
- <table data-ebr-role="wrapper" role="presentation" width="100%" style="${buildStyles_1.tableCommonStyle}" class="${visibilityClass}"><tr><td style="${contentStyle}">${content}</td></tr></table>
33
+ <table data-ebr-role="wrapper" role="presentation" width="100%" style="${buildStyles_1.tableCommonStyle}" class="${visibilityClass}"><tr><td${bgAttr} style="${contentStyle}">${content}</td></tr></table>
14
34
  <!--<![endif]-->
15
35
  `;
16
36
  }
17
37
  if (msoWidth) {
18
38
  return `
19
39
  <!--[if mso]>
20
- <table role="presentation" border="0" cellpadding="0" cellspacing="0" width="${msoWidth}" style="border-collapse:collapse;width:${msoWidth}px;"><tr><td width="${msoWidth}" style="${contentStyle}">
40
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0" width="${msoWidth}" style="border-collapse:collapse;width:${msoWidth}px;"><tr><td width="${msoWidth}"${bgAttr} style="${contentStyle}">
21
41
  <![endif]-->
22
42
  <!--[if !mso]><!-->
23
- <table data-ebr-role="wrapper" role="presentation" width="100%" border="0" cellpadding="0" cellspacing="0" style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%" style="${contentStyle}">
43
+ <table data-ebr-role="wrapper" role="presentation" width="100%" border="0" cellpadding="0" cellspacing="0" style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%"${bgAttr} style="${contentStyle}">
24
44
  <!--<![endif]-->
25
45
  ${content}
26
46
  <!--[if mso]></td></tr></table><![endif]-->
@@ -30,7 +50,7 @@ ${content}
30
50
  `;
31
51
  }
32
52
  return `
33
- <table data-ebr-role="wrapper" role="presentation" width="100%" border="0" cellpadding="0" cellspacing="0" style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%" style="${contentStyle}">${content}</td></tr></table>
53
+ <table data-ebr-role="wrapper" role="presentation" width="100%" border="0" cellpadding="0" cellspacing="0" style="${buildStyles_1.tableCommonStyle}; max-width:600px;" class="${visibilityClass}"><tr><td width="100%"${bgAttr} style="${contentStyle}">${content}</td></tr></table>
34
54
  `;
35
55
  }
36
56
  async function appendOutlookForImage(content, outerContainerWidth, innerContainerWidth, imageUrl, style = {}, finalWidth, finalHeight) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "email-builder-utils",
3
- "version": "1.1.48",
3
+ "version": "1.1.49",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [