@templatical/import-beefree 0.42.1 → 0.43.1

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/index.js CHANGED
@@ -3,6 +3,21 @@ import { createButtonBlock, createDefaultTemplateContent, createDividerBlock, cr
3
3
  /**
4
4
  * Parses CSS-like style values from BeeFree descriptors.
5
5
  */
6
+ /**
7
+ * The CSS-wide keywords. Each one defers to the cascade instead of naming a
8
+ * value, and a block field that carried one would reach the renderer
9
+ * verbatim, so the parsers read them as unset and the caller's fallback
10
+ * applies.
11
+ */
12
+ const CSS_WIDE_KEYWORDS = /* @__PURE__ */ new Set([
13
+ "inherit",
14
+ "initial",
15
+ "unset",
16
+ "revert"
17
+ ]);
18
+ function isCssWideKeyword(value) {
19
+ return CSS_WIDE_KEYWORDS.has(value.trim().toLowerCase());
20
+ }
6
21
  function parsePxValue(value) {
7
22
  if (!value) return 0;
8
23
  const match = value.match(/^(-?\d+(?:\.\d+)?)\s*px/);
@@ -34,9 +49,17 @@ function parseImageBorderRadius(value, width, height) {
34
49
  const px = parsePxValue(value);
35
50
  return px > 0 ? px : void 0;
36
51
  }
52
+ /**
53
+ * A color as lowercase 6-digit hex where it is hex, otherwise as written.
54
+ *
55
+ * `""` means unset: returned for transparent, `none` and the CSS-wide
56
+ * keywords, so the caller's fallback applies.
57
+ */
37
58
  function parseColor(value) {
38
- if (!value || value === "transparent") return "";
59
+ if (!value) return "";
39
60
  const trimmed = value.trim();
61
+ const keyword = trimmed.toLowerCase();
62
+ if (keyword === "transparent" || keyword === "none" || isCssWideKeyword(keyword)) return "";
40
63
  if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();
41
64
  if (/^#[0-9a-fA-F]{3}$/.test(trimmed)) {
42
65
  const r = trimmed[1];
@@ -103,18 +126,23 @@ function parseShorthandPadding(value) {
103
126
  };
104
127
  }
105
128
  }
106
- function parseWidthPercent(value) {
107
- if (!value) return 100;
108
- const match = value.match(/^(\d+(?:\.\d+)?)\s*%/);
109
- if (match) return Math.round(parseFloat(match[1]));
110
- return 100;
129
+ /**
130
+ * A divider's `width` as a number and its unit, or `undefined` when it is
131
+ * neither a px nor a % length (`auto`, a keyword, anything unreadable).
132
+ */
133
+ function parseDividerWidth(value) {
134
+ const match = value.trim().match(/^(-?\d+(?:\.\d+)?)\s*(%|px)$/);
135
+ if (!match) return void 0;
136
+ return {
137
+ value: parseFloat(match[1]),
138
+ unit: match[2] === "%" ? "%" : "px"
139
+ };
111
140
  }
112
141
  function parseFontFamily(value) {
113
142
  if (!value) return "";
114
- return value.split(",")[0].trim().replace(/['"]/g, "");
143
+ const family = value.split(",")[0].trim().replace(/['"]/g, "");
144
+ return isCssWideKeyword(family) ? "" : family;
115
145
  }
116
- //#endregion
117
- //#region src/block-mapper.ts
118
146
  /**
119
147
  * Maps BeeFree module type strings to short keys.
120
148
  */
@@ -200,12 +228,12 @@ function makeStyles(descriptor) {
200
228
  * - text-align → added to each <p> tag's style attribute
201
229
  * - color, font-size, font-weight, font-family → wrapped in <span style="..."> inside each <p>
202
230
  */
203
- function inlineStylesToHtml(html, style) {
231
+ function inlineStylesToHtml(html, style, textColor) {
204
232
  const spanParts = [];
205
233
  const fontSize = parsePxValue(style["font-size"]);
206
234
  if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);
207
235
  const color = parseColor(style.color);
208
- if (color && color !== "#1a1a1a") spanParts.push(`color: ${color}`);
236
+ if (color && color !== textColor) spanParts.push(`color: ${color}`);
209
237
  const fontWeight = style["font-weight"];
210
238
  if (fontWeight && fontWeight !== "normal" && fontWeight !== "400") spanParts.push(`font-weight: ${fontWeight}`);
211
239
  const fontFamily = parseFontFamily(style["font-family"]);
@@ -260,12 +288,12 @@ function wrapParagraphInner(html, spanStyle) {
260
288
  }
261
289
  return out;
262
290
  }
263
- function convertText(descriptor) {
291
+ function convertText(descriptor, textColor) {
264
292
  const textContent = descriptor.text ?? descriptor.paragraph ?? descriptor.list;
265
293
  const html = textContent?.html ?? "";
266
294
  const style = textContent?.style ?? {};
267
295
  return createParagraphBlock({
268
- content: inlineStylesToHtml(html, style),
296
+ content: inlineStylesToHtml(html, style, textColor),
269
297
  styles: makeStyles(descriptor)
270
298
  });
271
299
  }
@@ -277,9 +305,9 @@ function parseHeadingLevel(tag) {
277
305
  }
278
306
  return 2;
279
307
  }
280
- function convertHeading(descriptor) {
308
+ function convertHeading(descriptor, textColor) {
281
309
  const heading = descriptor.heading;
282
- if (!heading) return convertText(descriptor);
310
+ if (!heading) return convertText(descriptor, textColor);
283
311
  const style = heading.style ?? {};
284
312
  const tag = heading.title ?? "h2";
285
313
  const text = heading.text ?? "";
@@ -287,7 +315,7 @@ function convertHeading(descriptor) {
287
315
  return createTitleBlock({
288
316
  content: content ? `<p>${content}</p>` : "<p></p>",
289
317
  level: parseHeadingLevel(tag),
290
- color: parseColor(style.color) || "#1a1a1a",
318
+ color: parseColor(style.color) || void 0,
291
319
  textAlign: toAlign(style["text-align"]),
292
320
  fontFamily: parseFontFamily(style["font-family"]) || void 0,
293
321
  styles: makeStyles(descriptor)
@@ -332,16 +360,56 @@ function convertButton(descriptor) {
332
360
  styles: makeStyles(descriptor)
333
361
  });
334
362
  }
335
- function convertDivider(descriptor) {
363
+ /**
364
+ * `"full"` when the divider spans its column: no width, `100%`, or a px width
365
+ * that reaches `contentWidth`. Without a `contentWidth` a px width stands as
366
+ * stated. Any other percentage stays a percentage, clamped to 0–100%.
367
+ */
368
+ function resolveDividerWidth(value, contentWidth, notes) {
369
+ const raw = (value ?? "").trim();
370
+ if (!raw) return "full";
371
+ const parsed = parseDividerWidth(raw);
372
+ if (!parsed) {
373
+ notes.push(`Divider width "${raw}" could not be read; imported as full width.`);
374
+ return "full";
375
+ }
376
+ if (parsed.unit === "%") {
377
+ const percent = Math.min(100, Math.max(0, parsed.value));
378
+ if (percent !== parsed.value) notes.push(`Divider width ${raw} was clamped to ${percent}%.`);
379
+ const share = Math.round(percent * 100) / 100;
380
+ return share === 100 ? "full" : `${share}%`;
381
+ }
382
+ const px = Math.max(0, Math.round(parsed.value));
383
+ if (px !== Math.round(parsed.value)) notes.push(`Divider width ${raw} was clamped to 0px.`);
384
+ return contentWidth !== void 0 && px >= contentWidth ? "full" : px;
385
+ }
386
+ function convertDivider(descriptor, columnWidth) {
336
387
  const style = descriptor.divider?.style ?? {};
337
388
  const border = parseBorderTop(style["border-top"]);
338
- return createDividerBlock({
339
- lineStyle: toLineStyle(border.style),
340
- color: border.color,
341
- thickness: border.width || 1,
342
- width: parseWidthPercent(style.width),
343
- styles: makeStyles(descriptor)
344
- });
389
+ const styles = makeStyles(descriptor);
390
+ const notes = [];
391
+ const contentWidth = columnWidth === void 0 ? void 0 : columnWidth - styles.padding.left - styles.padding.right;
392
+ const width = resolveDividerWidth(style.width, contentWidth, notes);
393
+ const align = dividerAlign(descriptor);
394
+ if (width !== "full" && (align === "left" || align === "right")) notes.push(`BeeFree aligns this divider ${align}; Templatical centres every divider.`);
395
+ return {
396
+ block: createDividerBlock({
397
+ lineStyle: toLineStyle(border.style),
398
+ color: border.color,
399
+ thickness: border.width || 1,
400
+ width,
401
+ styles
402
+ }),
403
+ notes
404
+ };
405
+ }
406
+ /**
407
+ * BeeFree keeps a divider's alignment in `computedStyle.align`; some exports
408
+ * also write it to the module style's `text-align`.
409
+ */
410
+ function dividerAlign(descriptor) {
411
+ const computed = descriptor.computedStyle?.align;
412
+ return typeof computed === "string" ? computed : descriptor.style?.["text-align"];
345
413
  }
346
414
  function convertSpacer(descriptor) {
347
415
  const spacer = descriptor.spacer;
@@ -410,7 +478,7 @@ function convertMenu(descriptor) {
410
478
  separator: menu.separator || "|",
411
479
  separatorColor: parseColor(menu.separatorColor) || "#999999",
412
480
  fontSize: parsePxValue(style["font-size"]) || 14,
413
- color: parseColor(style.color) || "#1a1a1a",
481
+ color: parseColor(style.color) || void 0,
414
482
  fontFamily: parseFontFamily(style["font-family"]) || void 0,
415
483
  textAlign: toAlign(style["text-align"], "center"),
416
484
  styles: makeStyles(descriptor)
@@ -445,7 +513,7 @@ function convertTable(descriptor) {
445
513
  borderWidth: parsePxValue(style["border-width"]) || 1,
446
514
  cellPadding: typeof table.cellPadding === "number" ? table.cellPadding : parsePxValue(table.cellPadding) || 8,
447
515
  fontSize: parsePxValue(style["font-size"]) || 14,
448
- color: parseColor(style.color) || "#1a1a1a",
516
+ color: parseColor(style.color) || void 0,
449
517
  textAlign: toAlign(style["text-align"]),
450
518
  styles: makeStyles(descriptor)
451
519
  }),
@@ -468,9 +536,10 @@ function convertHtmlFallback(module) {
468
536
  * Converts a single BeeFree module to a Templatical block.
469
537
  * Returns the block and a report entry.
470
538
  */
471
- function convertModule(module, warnings) {
539
+ function convertModule(module, warnings, context = {}) {
472
540
  const mappedType = MODULE_TYPE_MAP[module.type];
473
541
  const descriptor = module.descriptor;
542
+ const textColor = context.textColor ?? "#1a1a1a";
474
543
  if (!mappedType) return {
475
544
  block: convertHtmlFallback(module),
476
545
  entry: {
@@ -482,13 +551,14 @@ function convertModule(module, warnings) {
482
551
  };
483
552
  let block;
484
553
  let isApproximation = false;
554
+ let notes = [];
485
555
  switch (mappedType) {
486
556
  case "paragraph":
487
557
  case "list":
488
- block = convertText(descriptor);
558
+ block = convertText(descriptor, textColor);
489
559
  break;
490
560
  case "title":
491
- block = convertHeading(descriptor);
561
+ block = convertHeading(descriptor, textColor);
492
562
  break;
493
563
  case "image":
494
564
  block = convertImage(descriptor);
@@ -496,9 +566,13 @@ function convertModule(module, warnings) {
496
566
  case "button":
497
567
  block = convertButton(descriptor);
498
568
  break;
499
- case "divider":
500
- block = convertDivider(descriptor);
569
+ case "divider": {
570
+ const result = convertDivider(descriptor, context.columnWidth);
571
+ block = result.block;
572
+ notes = result.notes;
573
+ isApproximation = notes.length > 0;
501
574
  break;
575
+ }
502
576
  case "spacer":
503
577
  block = convertSpacer(descriptor);
504
578
  break;
@@ -540,7 +614,8 @@ function convertModule(module, warnings) {
540
614
  entry: {
541
615
  beeFreeModuleType: module.type,
542
616
  templaticalBlockType: block.type,
543
- status: isApproximation ? "approximated" : "converted"
617
+ status: isApproximation ? "approximated" : "converted",
618
+ ...notes.length > 0 ? { note: notes.join(" ") } : {}
544
619
  }
545
620
  };
546
621
  }
@@ -566,12 +641,29 @@ function resolveColumnLayout(columns, warnings) {
566
641
  return "2";
567
642
  }
568
643
  /**
644
+ * Column widths in px for a layout, mirroring `renderer/src/columns.ts`, and
645
+ * floored as the renderer floors the width it hands each column.
646
+ */
647
+ function columnPixels(layout, bodyWidth) {
648
+ switch (layout) {
649
+ case "2": return [bodyWidth * .5, bodyWidth * .5].map(Math.floor);
650
+ case "3": return [
651
+ bodyWidth / 3,
652
+ bodyWidth / 3,
653
+ bodyWidth / 3
654
+ ].map(Math.floor);
655
+ case "1-2": return [bodyWidth / 3, bodyWidth * 2 / 3].map(Math.floor);
656
+ case "2-1": return [bodyWidth * 2 / 3, bodyWidth / 3].map(Math.floor);
657
+ default: return [Math.floor(bodyWidth)];
658
+ }
659
+ }
660
+ /**
569
661
  * Converts all modules in a column to Templatical blocks.
570
662
  */
571
- function convertColumnModules(column, entries, warnings) {
663
+ function convertColumnModules(column, context, entries, warnings) {
572
664
  const blocks = [];
573
665
  for (const module of column.modules) {
574
- const { block, entry } = convertModule(module, warnings);
666
+ const { block, entry } = convertModule(module, warnings, context);
575
667
  blocks.push(block);
576
668
  entries.push(entry);
577
669
  }
@@ -580,7 +672,7 @@ function convertColumnModules(column, entries, warnings) {
580
672
  /**
581
673
  * Processes a single BeeFree row into one or more Templatical blocks.
582
674
  */
583
- function processRow(row, entries, warnings) {
675
+ function processRow(row, settings, entries, warnings) {
584
676
  const columns = row.columns;
585
677
  if (!columns || columns.length === 0) return [];
586
678
  if (row.locked) warnings.push("A locked row was imported. Lock metadata was dropped; content is preserved.");
@@ -589,7 +681,11 @@ function processRow(row, entries, warnings) {
589
681
  const rowBg = parseColor(row.content?.style?.["background-color"]);
590
682
  if (!layout) {
591
683
  const blocks = [];
592
- for (const column of columns) blocks.push(...convertColumnModules(column, entries, warnings));
684
+ const context = {
685
+ columnWidth: settings.width,
686
+ textColor: settings.textColor
687
+ };
688
+ for (const column of columns) blocks.push(...convertColumnModules(column, context, entries, warnings));
593
689
  if (rowBg) return [createSectionBlock({
594
690
  columns: "1",
595
691
  children: [blocks],
@@ -605,7 +701,11 @@ function processRow(row, entries, warnings) {
605
701
  })];
606
702
  return blocks;
607
703
  }
608
- const children = columns.map((col) => convertColumnModules(col, entries, warnings));
704
+ const widths = columnPixels(layout, settings.width);
705
+ const children = columns.map((col, index) => convertColumnModules(col, {
706
+ columnWidth: widths[index],
707
+ textColor: settings.textColor
708
+ }, entries, warnings));
609
709
  return [createSectionBlock({
610
710
  columns: layout,
611
711
  children,
@@ -626,15 +726,18 @@ function processRow(row, entries, warnings) {
626
726
  function extractSettings(template) {
627
727
  const body = template.page.body;
628
728
  const contentStyle = body?.content?.style ?? {};
729
+ const computedStyle = body?.content?.computedStyle ?? {};
629
730
  const containerStyle = body?.container?.style ?? {};
630
- const width = parsePxValue(contentStyle["width"] ?? contentStyle.width);
731
+ const width = parsePxValue(computedStyle.messageWidth) || parsePxValue(contentStyle.width);
631
732
  const bgColor = parseColor(contentStyle["background-color"]) || parseColor(containerStyle["background-color"]) || "#ffffff";
632
733
  const fontFamily = parseFontFamily(contentStyle["font-family"]) || "Arial";
734
+ const linkColor = parseColor(computedStyle.linkColor);
633
735
  return {
634
736
  width: width || 600,
635
737
  backgroundColor: bgColor,
636
- textColor: "#1a1a1a",
637
- linkUnderline: false,
738
+ textColor: parseColor(contentStyle.color) || "#1a1a1a",
739
+ ...linkColor ? { linkColor } : {},
740
+ linkUnderline: true,
638
741
  fontFamily,
639
742
  locale: "en"
640
743
  };
@@ -667,15 +770,16 @@ function convertBeeFreeTemplate(template) {
667
770
  const blocks = [];
668
771
  const webFonts = template.page.body?.webFonts;
669
772
  if (webFonts && webFonts.length > 1) warnings.push(`Template uses ${webFonts.length} web fonts. Only the primary font is preserved; additional fonts may need to be configured via the fonts option.`);
773
+ const settings = extractSettings(template);
670
774
  for (const row of template.page.rows) {
671
775
  if (row.empty) continue;
672
- blocks.push(...processRow(row, entries, warnings));
776
+ blocks.push(...processRow(row, settings, entries, warnings));
673
777
  }
674
778
  return {
675
779
  content: {
676
780
  ...createDefaultTemplateContent(),
677
781
  blocks,
678
- settings: extractSettings(template)
782
+ settings
679
783
  },
680
784
  report: {
681
785
  entries,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/style-parser.ts","../src/block-mapper.ts","../src/converter.ts"],"sourcesContent":["import type { SpacingValue } from \"@templatical/types\";\n\n/**\n * Parses CSS-like style values from BeeFree descriptors.\n */\n\nexport function parsePxValue(value: string | undefined): number {\n if (!value) return 0;\n const match = value.match(/^(-?\\d+(?:\\.\\d+)?)\\s*px/);\n return match ? Math.round(parseFloat(match[1])) : 0;\n}\n\n/**\n * An image's corner radius in px, or `undefined` for square corners.\n *\n * Accepts a percentage as well as a px length, because `border-radius: 50%` is\n * the idiomatic way to write a circular avatar and the block stores px only. A\n * percentage resolves against the shorter rendered side, which is what turns a\n * square image into a circle and a wide one into a pill.\n *\n * `width` and `height` must be the dimensions actually read from the source. A\n * percentage with neither known is dropped rather than resolved against the\n * caller's fallback width, which would invent a radius the template never\n * expressed. A non-positive result is dropped for the same reason a px `0` is:\n * both mean square, and only absence keeps it out of the exported JSON.\n */\nexport function parseImageBorderRadius(\n value: string | undefined,\n width: number | undefined,\n height: number | undefined,\n): number | undefined {\n if (!value) return undefined;\n\n // Deliberately no `-?`: a negative percentage falls through to the px parse,\n // which rejects it too.\n const percent = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*%$/);\n if (percent) {\n const side = Math.min(width ?? Infinity, height ?? Infinity);\n if (!Number.isFinite(side)) return undefined;\n const radius = Math.round((parseFloat(percent[1]) / 100) * side);\n return radius > 0 ? radius : undefined;\n }\n\n const px = parsePxValue(value);\n return px > 0 ? px : undefined;\n}\n\nexport function parseColor(value: string | undefined): string {\n if (!value || value === \"transparent\") return \"\";\n\n const trimmed = value.trim();\n\n // Already a valid hex color\n if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();\n\n // 3-digit hex → 6-digit\n if (/^#[0-9a-fA-F]{3}$/.test(trimmed)) {\n const r = trimmed[1];\n const g = trimmed[2];\n const b = trimmed[3];\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n\n // Return as-is for rgb(), named colors, etc.\n return trimmed;\n}\n\nexport function parseBorderTop(value: string | undefined): {\n width: number;\n style: string;\n color: string;\n} {\n if (!value) return { width: 0, style: \"solid\", color: \"#000000\" };\n\n // \"2px solid #cccccc\"\n const parts = value.trim().split(/\\s+/);\n return {\n width: parsePxValue(parts[0]),\n style: parts[1] || \"solid\",\n color: parseColor(parts[2]) || \"#000000\",\n };\n}\n\nexport function extractPadding(\n style: Record<string, string> | undefined,\n): SpacingValue {\n if (!style) return { top: 0, right: 0, bottom: 0, left: 0 };\n\n // Check for shorthand `padding` first\n if (style.padding) {\n return parseShorthandPadding(style.padding);\n }\n\n return {\n top: parsePxValue(style[\"padding-top\"]),\n right: parsePxValue(style[\"padding-right\"]),\n bottom: parsePxValue(style[\"padding-bottom\"]),\n left: parsePxValue(style[\"padding-left\"]),\n };\n}\n\nfunction parseShorthandPadding(value: string): SpacingValue {\n const parts = value.trim().split(/\\s+/);\n const values = parts.map((p) => parsePxValue(p));\n\n switch (values.length) {\n case 1:\n return {\n top: values[0],\n right: values[0],\n bottom: values[0],\n left: values[0],\n };\n case 2:\n return {\n top: values[0],\n right: values[1],\n bottom: values[0],\n left: values[1],\n };\n case 3:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[1],\n };\n default:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[3],\n };\n }\n}\n\nexport function parseWidthPercent(value: string | undefined): number {\n if (!value) return 100;\n const match = value.match(/^(\\d+(?:\\.\\d+)?)\\s*%/);\n if (match) return Math.round(parseFloat(match[1]));\n // Might be px — return 100 as default\n return 100;\n}\n\nexport function parseFontFamily(value: string | undefined): string {\n if (!value) return \"\";\n // Take the first font in the stack\n return value.split(\",\")[0].trim().replace(/['\"]/g, \"\");\n}\n","import {\n createTitleBlock,\n createParagraphBlock,\n createImageBlock,\n createButtonBlock,\n createDividerBlock,\n createSpacerBlock,\n createHtmlBlock,\n createSocialIconsBlock,\n createMenuBlock,\n createTableBlock,\n createVideoBlock,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n HeadingLevel,\n SocialPlatform,\n SocialIcon,\n MenuItemData,\n TableRowData,\n TableCellData,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n ImportReportEntry,\n} from \"./types\";\nimport {\n parseImageBorderRadius,\n parsePxValue,\n parseColor,\n parseBorderTop,\n extractPadding,\n parseWidthPercent,\n parseFontFamily,\n} from \"./style-parser\";\n\n/**\n * Maps BeeFree module type strings to short keys.\n */\nconst MODULE_TYPE_MAP: Record<string, string> = {\n \"mailup-bee-newsletter-modules-text\": \"paragraph\",\n \"mailup-bee-newsletter-modules-paragraph\": \"paragraph\",\n \"mailup-bee-newsletter-modules-heading\": \"title\",\n \"mailup-bee-newsletter-modules-list\": \"list\",\n \"mailup-bee-newsletter-modules-image\": \"image\",\n \"mailup-bee-newsletter-modules-button\": \"button\",\n \"mailup-bee-newsletter-modules-divider\": \"divider\",\n \"mailup-bee-newsletter-modules-spacer\": \"spacer\",\n \"mailup-bee-newsletter-modules-html\": \"html\",\n \"mailup-bee-newsletter-modules-social\": \"social\",\n \"mailup-bee-newsletter-modules-video\": \"video\",\n \"mailup-bee-newsletter-modules-menu\": \"menu\",\n \"mailup-bee-newsletter-modules-table\": \"table\",\n};\n\nconst SOCIAL_PLATFORM_MAP: Record<string, SocialPlatform> = {\n facebook: \"facebook\",\n twitter: \"twitter\",\n x: \"twitter\",\n instagram: \"instagram\",\n linkedin: \"linkedin\",\n youtube: \"youtube\",\n tiktok: \"tiktok\",\n pinterest: \"pinterest\",\n email: \"email\",\n whatsapp: \"whatsapp\",\n telegram: \"telegram\",\n discord: \"discord\",\n snapchat: \"snapchat\",\n reddit: \"reddit\",\n github: \"github\",\n dribbble: \"dribbble\",\n behance: \"behance\",\n};\n\ntype Align = \"left\" | \"center\" | \"right\";\ntype LineStyle = \"solid\" | \"dashed\" | \"dotted\";\n\nfunction toAlign(value: string | undefined, fallback: Align = \"left\"): Align {\n if (value === \"left\" || value === \"center\" || value === \"right\") return value;\n return fallback;\n}\n\nfunction toLineStyle(\n value: string | undefined,\n fallback: LineStyle = \"solid\",\n): LineStyle {\n if (value === \"solid\" || value === \"dashed\" || value === \"dotted\")\n return value;\n return fallback;\n}\n\n/**\n * Strip every `<…>` from a button label and reject any stray `<` or `>`\n * left behind (e.g. a truncated `<script`). The original\n * `value.replace(/<[^>]*>/g, \"\")` was both polynomial-ReDoS over\n * `<<<<…` inputs and an incomplete sanitizer — an unterminated `<script`\n * would survive the strip. Downstream HTML-escapes the label at render\n * time, but stripping here keeps the imported JSON clean.\n */\nfunction stripTagsPlain(text: string): string {\n let out = \"\";\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"<\") {\n const close = text.indexOf(\">\", i + 1);\n if (close === -1) {\n // Unterminated tag — discard the rest.\n break;\n }\n i = close + 1;\n continue;\n }\n if (text[i] === \">\") {\n i++;\n continue;\n }\n out += text[i];\n i++;\n }\n return out;\n}\n\nfunction makeStyles(descriptor: BeeFreeeModuleDescriptor): Block[\"styles\"] {\n const padding = extractPadding(descriptor.style);\n const bg = parseColor(descriptor.style?.[\"background-color\"]);\n return {\n padding,\n ...(bg ? { backgroundColor: bg } : {}),\n };\n}\n\n/**\n * Apply BeeFree text styles as TipTap-compatible inline markup.\n * - text-align → added to each <p> tag's style attribute\n * - color, font-size, font-weight, font-family → wrapped in <span style=\"...\"> inside each <p>\n */\nfunction inlineStylesToHtml(\n html: string,\n style: Record<string, string | undefined>,\n): string {\n const spanParts: string[] = [];\n const fontSize = parsePxValue(style[\"font-size\"]);\n if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);\n const color = parseColor(style.color);\n if (color && color !== \"#1a1a1a\") spanParts.push(`color: ${color}`);\n const fontWeight = style[\"font-weight\"];\n // \"400\" is the numeric synonym for \"normal\" — neither needs an explicit\n // span (matches the import-unlayer importer).\n if (fontWeight && fontWeight !== \"normal\" && fontWeight !== \"400\")\n spanParts.push(`font-weight: ${fontWeight}`);\n const fontFamily = parseFontFamily(style[\"font-family\"]);\n if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);\n\n const textAlign = style[\"text-align\"];\n const pStyle =\n textAlign && textAlign !== \"left\" ? `text-align: ${textAlign}` : \"\";\n\n if (!pStyle && spanParts.length === 0) return html;\n\n const spanStyle = spanParts.join(\"; \");\n\n // Apply styles to each <p> tag in the HTML\n let result = html;\n\n if (pStyle) {\n // Add text-align to existing <p style=\"...\"> or add style to plain <p>\n result = result\n .replace(/<p style=\"([^\"]*)\">/g, `<p style=\"$1; ${pStyle}\">`)\n .replaceAll(\"<p>\", `<p style=\"${pStyle}\">`);\n }\n\n if (spanStyle) {\n // Wrap inner content of each <p> in a styled span.\n result = wrapParagraphInner(result, spanStyle);\n }\n\n return result;\n}\n\n/**\n * Wrap the inner content of every `<p …>…</p>` with `<span style=\"…\">…</span>`.\n *\n * Hand-rolled linear scanner instead of `/<p([^>]*)>([\\s\\S]*?)<\\/p>/g` because\n * the regex is polynomial-ReDoS: the engine retries `[\\s\\S]*?<\\/p>` at every\n * `<p` start, so inputs like `<p>a<p>a<p>a…` (no `</p>` ever) cost O(n²).\n * The scanner advances `i` monotonically via `indexOf`, keeping the work\n * strictly O(n).\n */\nfunction wrapParagraphInner(html: string, spanStyle: string): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<p\", i);\n if (open === -1) {\n out += html.substring(i);\n break;\n }\n const afterTagName = html[open + 2];\n if (\n afterTagName !== \">\" &&\n afterTagName !== \" \" &&\n afterTagName !== \"\\t\" &&\n afterTagName !== \"\\n\" &&\n afterTagName !== \"\\r\" &&\n afterTagName !== \"/\"\n ) {\n out += html.substring(i, open + 2);\n i = open + 2;\n continue;\n }\n const openEnd = html.indexOf(\">\", open + 2);\n if (openEnd === -1) {\n out += html.substring(i);\n break;\n }\n const closeStart = html.indexOf(\"</p>\", openEnd + 1);\n if (closeStart === -1) {\n out += html.substring(i);\n break;\n }\n const inner = html.substring(openEnd + 1, closeStart);\n out += html.substring(i, openEnd + 1);\n out += `<span style=\"${spanStyle}\">${inner}</span></p>`;\n i = closeStart + 4;\n }\n return out;\n}\n\nfunction convertText(descriptor: BeeFreeeModuleDescriptor): Block {\n const textContent =\n descriptor.text ?? descriptor.paragraph ?? descriptor.list;\n const html = textContent?.html ?? \"\";\n const style = textContent?.style ?? {};\n\n return createParagraphBlock({\n content: inlineStylesToHtml(html, style),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction parseHeadingLevel(tag: string): HeadingLevel {\n const match = tag.match(/^h(\\d)$/i);\n if (match) {\n const num = Number(match[1]);\n if (num >= 1 && num <= 4) return num as HeadingLevel;\n }\n return 2;\n}\n\nfunction convertHeading(descriptor: BeeFreeeModuleDescriptor): Block {\n const heading = descriptor.heading;\n if (!heading) return convertText(descriptor);\n\n const style = heading.style ?? {};\n const tag = heading.title ?? \"h2\";\n const text = heading.text ?? \"\";\n // Strip heading tags — content goes inside TipTap, heading tag is rendered by the block\n const content = text.startsWith(\"<\")\n ? text.replace(/^<h\\d[^>]*>|<\\/h\\d>$/gi, \"\")\n : text;\n\n return createTitleBlock({\n content: content ? `<p>${content}</p>` : \"<p></p>\",\n level: parseHeadingLevel(tag),\n color: parseColor(style.color) || \"#1a1a1a\",\n textAlign: toAlign(style[\"text-align\"]),\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertImage(descriptor: BeeFreeeModuleDescriptor): Block {\n const image = descriptor.image;\n if (!image) {\n return createImageBlock({ styles: makeStyles(descriptor) });\n }\n\n // Kept separate from the `?? 600` fallback below: a percentage radius has to\n // resolve against a width the template actually stated.\n const readWidth = parsePxValue(image.width) || undefined;\n const readHeight = parsePxValue(image.height) || undefined;\n\n return createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width: readWidth ?? 600,\n // No default, unlike width: an absent height is what keeps the aspect\n // ratio, and BeeFree's \"auto\" parses to 0, which reads the same way.\n height: readHeight,\n borderRadius: parseImageBorderRadius(\n image.style?.[\"border-radius\"],\n readWidth,\n readHeight,\n ),\n align: toAlign(image.style?.[\"text-align\"], \"center\"),\n linkUrl: image.href || undefined,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertButton(descriptor: BeeFreeeModuleDescriptor): Block {\n const button = descriptor.button;\n if (!button) {\n return createButtonBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = button.style ?? {};\n const label = button.label ? stripTagsPlain(button.label) : \"Button\";\n\n return createButtonBlock({\n text: label,\n url: button.href || \"#\",\n backgroundColor: parseColor(style[\"background-color\"]) || \"#4f46e5\",\n textColor: parseColor(style.color) || \"#ffffff\",\n borderRadius: parsePxValue(style[\"border-radius\"]),\n fontSize: parsePxValue(style[\"font-size\"]) || 16,\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n align: toAlign(style[\"text-align\"], \"center\"),\n buttonPadding: {\n top: parsePxValue(style[\"padding-top\"]) || 12,\n right: parsePxValue(style[\"padding-right\"]) || 24,\n bottom: parsePxValue(style[\"padding-bottom\"]) || 12,\n left: parsePxValue(style[\"padding-left\"]) || 24,\n },\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertDivider(descriptor: BeeFreeeModuleDescriptor): Block {\n const divider = descriptor.divider;\n const style = divider?.style ?? {};\n const border = parseBorderTop(style[\"border-top\"]);\n\n return createDividerBlock({\n lineStyle: toLineStyle(border.style),\n color: border.color,\n thickness: border.width || 1,\n width: parseWidthPercent(style.width),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertSpacer(descriptor: BeeFreeeModuleDescriptor): Block {\n const spacer = descriptor.spacer;\n const height = parsePxValue(spacer?.style?.height) || 24;\n\n return createSpacerBlock({\n height,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertHtml(descriptor: BeeFreeeModuleDescriptor): Block {\n const html = descriptor.html?.html ?? \"\";\n\n return createHtmlBlock({\n content: html,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertSocial(\n descriptor: BeeFreeeModuleDescriptor,\n warnings: string[],\n): Block {\n const iconsList = descriptor.iconsList;\n if (!iconsList?.icons) {\n return createSocialIconsBlock({ styles: makeStyles(descriptor) });\n }\n\n const icons: SocialIcon[] = [];\n\n for (const beeIcon of iconsList.icons) {\n const id = (beeIcon.id ?? beeIcon.name ?? \"\").toLowerCase();\n const platform = SOCIAL_PLATFORM_MAP[id];\n\n if (!platform) {\n warnings.push(\n `Unrecognized social icon \"${beeIcon.name || id}\" was skipped.`,\n );\n continue;\n }\n\n icons.push({\n id: generateId(),\n platform,\n url: beeIcon.image?.href || \"#\",\n });\n }\n\n return createSocialIconsBlock({\n icons,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertVideo(descriptor: BeeFreeeModuleDescriptor): Block {\n const video = descriptor.video;\n if (!video) {\n return createVideoBlock({ styles: makeStyles(descriptor) });\n }\n\n return createVideoBlock({\n url: video.src || \"\",\n thumbnailUrl: video.thumbnail || \"\",\n alt: video.alt || \"\",\n width: parsePxValue(video.style?.width) || 600,\n height: parsePxValue(video.style?.height) || undefined,\n align: toAlign(video.style?.[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertMenu(descriptor: BeeFreeeModuleDescriptor): Block {\n const menu = descriptor.menu;\n if (!menu) {\n return createMenuBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = menu.style ?? {};\n\n const items: MenuItemData[] = (menu.items ?? []).map((item) => ({\n id: generateId(),\n text: item.text || \"\",\n url: item.link || item.href || \"#\",\n openInNewTab: item.target === \"_blank\",\n bold: false,\n underline: false,\n }));\n\n return createMenuBlock({\n items,\n separator: menu.separator || \"|\",\n separatorColor: parseColor(menu.separatorColor) || \"#999999\",\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || \"#1a1a1a\",\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n textAlign: toAlign(style[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertTable(descriptor: BeeFreeeModuleDescriptor): {\n block: Block;\n approximated: boolean;\n} {\n const table = descriptor.table;\n if (!table) {\n return {\n block: createTableBlock({ styles: makeStyles(descriptor) }),\n approximated: false,\n };\n }\n\n const style = table.style ?? {};\n\n // Templatical table cells are a plain-text field (the editor stores the\n // cell's innerText), so strip any HTML a BeeFree cell carried the same way\n // button labels are stripped. If a strip actually removed markup, the cell\n // lost formatting or a link URL, so the conversion is an approximation.\n let approximated = false;\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map((cell): TableCellData => {\n const raw = cell.content ?? cell.html ?? \"\";\n const content = stripTagsPlain(raw);\n if (content !== raw) {\n approximated = true;\n }\n return { id: generateId(), content };\n }),\n }));\n\n return {\n block: createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor:\n parseColor(table.headerBackgroundColor) || undefined,\n borderColor: parseColor(style[\"border-color\"]) || \"#dddddd\",\n borderWidth: parsePxValue(style[\"border-width\"]) || 1,\n cellPadding:\n typeof table.cellPadding === \"number\"\n ? table.cellPadding\n : parsePxValue(table.cellPadding as string) || 8,\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || \"#1a1a1a\",\n textAlign: toAlign(style[\"text-align\"]),\n styles: makeStyles(descriptor),\n }),\n approximated,\n };\n}\n\nfunction convertHtmlFallback(module: BeeFreeeModule): Block {\n // Attempt to extract any HTML content from the descriptor\n const descriptor = module.descriptor;\n let html = \"\";\n\n // Try common content fields\n if (descriptor.text?.html) html = descriptor.text.html;\n else if (descriptor.html?.html) html = descriptor.html.html;\n else if (descriptor.heading?.text) html = descriptor.heading.text;\n else html = `<!-- Unsupported BeeFree module: ${module.type} -->`;\n\n return createHtmlBlock({\n content: html,\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * Converts a single BeeFree module to a Templatical block.\n * Returns the block and a report entry.\n */\nexport function convertModule(\n module: BeeFreeeModule,\n warnings: string[],\n): { block: Block; entry: ImportReportEntry } {\n const mappedType = MODULE_TYPE_MAP[module.type];\n const descriptor = module.descriptor;\n\n if (!mappedType) {\n return {\n block: convertHtmlFallback(module),\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: `Unknown module type \"${module.type}\" converted to HTML block.`,\n },\n };\n }\n\n let block: Block;\n let isApproximation = false;\n\n switch (mappedType) {\n case \"paragraph\":\n case \"list\":\n block = convertText(descriptor);\n break;\n case \"title\":\n block = convertHeading(descriptor);\n break;\n case \"image\":\n block = convertImage(descriptor);\n break;\n case \"button\":\n block = convertButton(descriptor);\n break;\n case \"divider\":\n block = convertDivider(descriptor);\n break;\n case \"spacer\":\n block = convertSpacer(descriptor);\n break;\n case \"html\":\n block = convertHtml(descriptor);\n break;\n case \"social\":\n block = convertSocial(descriptor, warnings);\n break;\n case \"video\":\n block = convertVideo(descriptor);\n break;\n case \"menu\":\n block = convertMenu(descriptor);\n isApproximation = true; // menu styles are approximate\n break;\n case \"table\": {\n const result = convertTable(descriptor);\n block = result.block;\n if (result.approximated) {\n isApproximation = true;\n warnings.push(\n \"HTML inside one or more table cells was reduced to plain text; any cell formatting or links were dropped.\",\n );\n }\n break;\n }\n default:\n block = convertHtmlFallback(module);\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n },\n };\n }\n\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: block.type,\n status: isApproximation ? \"approximated\" : \"converted\",\n },\n };\n}\n","import {\n createSectionBlock,\n createDefaultTemplateContent,\n} from \"@templatical/types\";\nimport type { Block, ColumnLayout, TemplateContent } from \"@templatical/types\";\nimport type {\n BeeFreeTemplate,\n BeeFreeeRow,\n BeeFreeeColumn,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n} from \"./types\";\nimport { convertModule } from \"./block-mapper\";\nimport { parsePxValue, parseColor, parseFontFamily } from \"./style-parser\";\n\n/**\n * Determines the Templatical ColumnLayout from BeeFree column grid values.\n */\nfunction resolveColumnLayout(\n columns: BeeFreeeColumn[],\n warnings: string[],\n): ColumnLayout | null {\n if (columns.length === 1) return null; // Single column — no section wrapper needed\n if (columns.length === 3) return \"3\";\n\n if (columns.length === 2) {\n const left = columns[0][\"grid-columns\"] ?? 6;\n const right = columns[1][\"grid-columns\"] ?? 6;\n const total = left + right;\n const ratio = left / total;\n\n if (ratio > 0.58) return \"2-1\";\n if (ratio < 0.42) return \"1-2\";\n return \"2\";\n }\n\n if (columns.length >= 4) {\n warnings.push(\n `Row with ${columns.length} columns was flattened to a single column. BeeFree supports arbitrary columns, but Templatical supports up to 3.`,\n );\n return null; // Flatten to single column\n }\n\n return \"2\";\n}\n\n/**\n * Converts all modules in a column to Templatical blocks.\n */\nfunction convertColumnModules(\n column: BeeFreeeColumn,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const blocks: Block[] = [];\n\n for (const module of column.modules) {\n const { block, entry } = convertModule(module, warnings);\n blocks.push(block);\n entries.push(entry);\n }\n\n return blocks;\n}\n\n/**\n * Processes a single BeeFree row into one or more Templatical blocks.\n */\nfunction processRow(\n row: BeeFreeeRow,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const columns = row.columns;\n if (!columns || columns.length === 0) return [];\n\n // Track locked/synced metadata\n if (row.locked) {\n warnings.push(\n \"A locked row was imported. Lock metadata was dropped; content is preserved.\",\n );\n }\n if (row.synced) {\n warnings.push(\n \"A synced row was imported. Sync metadata was dropped; content is preserved.\",\n );\n }\n\n const layout = resolveColumnLayout(columns, warnings);\n\n // Extract section-level background from row content styles.\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n\n if (!layout) {\n // Single column (or flattened 4+ columns) — return modules directly.\n const blocks: Block[] = [];\n for (const column of columns) {\n blocks.push(...convertColumnModules(column, entries, warnings));\n }\n // A non-transparent row background can't survive on bare modules; wrap\n // them in a one-column section so the colored band still renders. Mirrors\n // the multi-column path and the Unlayer importer (which wraps every row).\n if (rowBg) {\n return [\n createSectionBlock({\n columns: \"1\",\n children: [blocks],\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n backgroundColor: rowBg,\n },\n }),\n ];\n }\n return blocks;\n }\n\n // Multi-column — wrap in a SectionBlock\n const children: Block[][] = columns.map((col) =>\n convertColumnModules(col, entries, warnings),\n );\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n });\n\n return [section];\n}\n\n/**\n * Extracts template-level settings from the BeeFree body.\n */\nfunction extractSettings(\n template: BeeFreeTemplate,\n): TemplateContent[\"settings\"] {\n const body = template.page.body;\n const contentStyle = body?.content?.style ?? {};\n const containerStyle = body?.container?.style ?? {};\n\n const width = parsePxValue(contentStyle[\"width\"] ?? contentStyle.width);\n const bgColor =\n parseColor(contentStyle[\"background-color\"]) ||\n parseColor(containerStyle[\"background-color\"]) ||\n \"#ffffff\";\n const fontFamily = parseFontFamily(contentStyle[\"font-family\"]) || \"Arial\";\n\n return {\n width: width || 600,\n backgroundColor: bgColor,\n textColor: \"#1a1a1a\",\n linkUnderline: false,\n fontFamily,\n locale: \"en\",\n };\n}\n\n/**\n * Converts a BeeFree template JSON to Templatical TemplateContent.\n *\n * @param template - The parsed BeeFree JSON object\n * @returns An ImportResult with the converted content and a detailed report\n *\n * @example\n * ```ts\n * import { convertBeeFreeTemplate } from '@templatical/import-beefree';\n *\n * const beeFreeJson = JSON.parse(fileContent);\n * const { content, report } = convertBeeFreeTemplate(beeFreeJson);\n *\n * // Use the content with the editor\n * const editor = init({ container: '#editor', content });\n *\n * // Check the report for any issues\n * console.log(report.summary);\n * console.log(report.warnings);\n * ```\n */\nexport function convertBeeFreeTemplate(\n template: BeeFreeTemplate,\n): ImportResult {\n // Validate structure\n if (!template?.page?.rows) {\n throw new Error(\n \"Invalid BeeFree template: missing page.rows. Ensure you are passing a valid BeeFree JSON export.\",\n );\n }\n\n const entries: ImportReportEntry[] = [];\n const warnings: string[] = [];\n const blocks: Block[] = [];\n\n // Extract web font warnings\n const webFonts = template.page.body?.webFonts;\n if (webFonts && webFonts.length > 1) {\n warnings.push(\n `Template uses ${webFonts.length} web fonts. Only the primary font is preserved; additional fonts may need to be configured via the fonts option.`,\n );\n }\n\n // Process rows\n for (const row of template.page.rows) {\n if (row.empty) continue;\n blocks.push(...processRow(row, entries, warnings));\n }\n\n // Build template content\n const content: TemplateContent = {\n ...createDefaultTemplateContent(),\n blocks,\n settings: extractSettings(template),\n };\n\n // Build report summary\n const summary = {\n total: entries.length,\n converted: entries.filter((e) => e.status === \"converted\").length,\n approximated: entries.filter((e) => e.status === \"approximated\").length,\n htmlFallback: entries.filter((e) => e.status === \"html-fallback\").length,\n skipped: entries.filter((e) => e.status === \"skipped\").length,\n };\n\n const report: ImportReport = { entries, warnings, summary };\n\n return { content, report };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/style-parser.ts","../src/block-mapper.ts","../src/converter.ts"],"sourcesContent":["import type { SpacingValue } from \"@templatical/types\";\n\n/**\n * Parses CSS-like style values from BeeFree descriptors.\n */\n\n/**\n * The CSS-wide keywords. Each one defers to the cascade instead of naming a\n * value, and a block field that carried one would reach the renderer\n * verbatim, so the parsers read them as unset and the caller's fallback\n * applies.\n */\nconst CSS_WIDE_KEYWORDS = new Set([\"inherit\", \"initial\", \"unset\", \"revert\"]);\n\nfunction isCssWideKeyword(value: string): boolean {\n return CSS_WIDE_KEYWORDS.has(value.trim().toLowerCase());\n}\n\nexport function parsePxValue(value: string | undefined): number {\n if (!value) return 0;\n const match = value.match(/^(-?\\d+(?:\\.\\d+)?)\\s*px/);\n return match ? Math.round(parseFloat(match[1])) : 0;\n}\n\n/**\n * An image's corner radius in px, or `undefined` for square corners.\n *\n * Accepts a percentage as well as a px length, because `border-radius: 50%` is\n * the idiomatic way to write a circular avatar and the block stores px only. A\n * percentage resolves against the shorter rendered side, which is what turns a\n * square image into a circle and a wide one into a pill.\n *\n * `width` and `height` must be the dimensions actually read from the source. A\n * percentage with neither known is dropped rather than resolved against the\n * caller's fallback width, which would invent a radius the template never\n * expressed. A non-positive result is dropped for the same reason a px `0` is:\n * both mean square, and only absence keeps it out of the exported JSON.\n */\nexport function parseImageBorderRadius(\n value: string | undefined,\n width: number | undefined,\n height: number | undefined,\n): number | undefined {\n if (!value) return undefined;\n\n // Deliberately no `-?`: a negative percentage falls through to the px parse,\n // which rejects it too.\n const percent = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*%$/);\n if (percent) {\n const side = Math.min(width ?? Infinity, height ?? Infinity);\n if (!Number.isFinite(side)) return undefined;\n const radius = Math.round((parseFloat(percent[1]) / 100) * side);\n return radius > 0 ? radius : undefined;\n }\n\n const px = parsePxValue(value);\n return px > 0 ? px : undefined;\n}\n\n/**\n * A color as lowercase 6-digit hex where it is hex, otherwise as written.\n *\n * `\"\"` means unset: returned for transparent, `none` and the CSS-wide\n * keywords, so the caller's fallback applies.\n */\nexport function parseColor(value: string | undefined): string {\n if (!value) return \"\";\n\n const trimmed = value.trim();\n const keyword = trimmed.toLowerCase();\n if (\n keyword === \"transparent\" ||\n keyword === \"none\" ||\n isCssWideKeyword(keyword)\n )\n return \"\";\n\n // Already a valid hex color\n if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();\n\n // 3-digit hex → 6-digit\n if (/^#[0-9a-fA-F]{3}$/.test(trimmed)) {\n const r = trimmed[1];\n const g = trimmed[2];\n const b = trimmed[3];\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n\n // Return as-is for rgb(), named colors, etc.\n return trimmed;\n}\n\nexport function parseBorderTop(value: string | undefined): {\n width: number;\n style: string;\n color: string;\n} {\n if (!value) return { width: 0, style: \"solid\", color: \"#000000\" };\n\n // \"2px solid #cccccc\"\n const parts = value.trim().split(/\\s+/);\n return {\n width: parsePxValue(parts[0]),\n style: parts[1] || \"solid\",\n color: parseColor(parts[2]) || \"#000000\",\n };\n}\n\nexport function extractPadding(\n style: Record<string, string> | undefined,\n): SpacingValue {\n if (!style) return { top: 0, right: 0, bottom: 0, left: 0 };\n\n // Check for shorthand `padding` first\n if (style.padding) {\n return parseShorthandPadding(style.padding);\n }\n\n return {\n top: parsePxValue(style[\"padding-top\"]),\n right: parsePxValue(style[\"padding-right\"]),\n bottom: parsePxValue(style[\"padding-bottom\"]),\n left: parsePxValue(style[\"padding-left\"]),\n };\n}\n\nfunction parseShorthandPadding(value: string): SpacingValue {\n const parts = value.trim().split(/\\s+/);\n const values = parts.map((p) => parsePxValue(p));\n\n switch (values.length) {\n case 1:\n return {\n top: values[0],\n right: values[0],\n bottom: values[0],\n left: values[0],\n };\n case 2:\n return {\n top: values[0],\n right: values[1],\n bottom: values[0],\n left: values[1],\n };\n case 3:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[1],\n };\n default:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[3],\n };\n }\n}\n\n/**\n * A divider's `width` as a number and its unit, or `undefined` when it is\n * neither a px nor a % length (`auto`, a keyword, anything unreadable).\n */\nexport function parseDividerWidth(\n value: string,\n): { value: number; unit: \"px\" | \"%\" } | undefined {\n const match = value.trim().match(/^(-?\\d+(?:\\.\\d+)?)\\s*(%|px)$/);\n if (!match) return undefined;\n return { value: parseFloat(match[1]), unit: match[2] === \"%\" ? \"%\" : \"px\" };\n}\n\nexport function parseFontFamily(value: string | undefined): string {\n if (!value) return \"\";\n // Take the first font in the stack\n const family = value.split(\",\")[0].trim().replace(/['\"]/g, \"\");\n return isCssWideKeyword(family) ? \"\" : family;\n}\n","import {\n createTitleBlock,\n createParagraphBlock,\n createImageBlock,\n createButtonBlock,\n createDividerBlock,\n createSpacerBlock,\n createHtmlBlock,\n createSocialIconsBlock,\n createMenuBlock,\n createTableBlock,\n createVideoBlock,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n DividerBlock,\n HeadingLevel,\n SocialPlatform,\n SocialIcon,\n MenuItemData,\n TableRowData,\n TableCellData,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n ImportReportEntry,\n} from \"./types\";\nimport {\n parseImageBorderRadius,\n parsePxValue,\n parseColor,\n parseBorderTop,\n extractPadding,\n parseDividerWidth,\n parseFontFamily,\n} from \"./style-parser\";\n\n/**\n * The template text color the import writes when the body sets none.\n */\nexport const FALLBACK_TEXT_COLOR = \"#1a1a1a\";\n\n/**\n * What the caller knows about where a module lands.\n */\nexport interface ModuleContext {\n /**\n * Width in px of the Templatical column the block renders in. Without it a\n * px divider width is kept as pixels.\n */\n columnWidth?: number;\n /**\n * The template's `textColor`, which every text block without a color of\n * its own inherits. Defaults to `FALLBACK_TEXT_COLOR`.\n */\n textColor?: string;\n}\n\n/**\n * Maps BeeFree module type strings to short keys.\n */\nconst MODULE_TYPE_MAP: Record<string, string> = {\n \"mailup-bee-newsletter-modules-text\": \"paragraph\",\n \"mailup-bee-newsletter-modules-paragraph\": \"paragraph\",\n \"mailup-bee-newsletter-modules-heading\": \"title\",\n \"mailup-bee-newsletter-modules-list\": \"list\",\n \"mailup-bee-newsletter-modules-image\": \"image\",\n \"mailup-bee-newsletter-modules-button\": \"button\",\n \"mailup-bee-newsletter-modules-divider\": \"divider\",\n \"mailup-bee-newsletter-modules-spacer\": \"spacer\",\n \"mailup-bee-newsletter-modules-html\": \"html\",\n \"mailup-bee-newsletter-modules-social\": \"social\",\n \"mailup-bee-newsletter-modules-video\": \"video\",\n \"mailup-bee-newsletter-modules-menu\": \"menu\",\n \"mailup-bee-newsletter-modules-table\": \"table\",\n};\n\nconst SOCIAL_PLATFORM_MAP: Record<string, SocialPlatform> = {\n facebook: \"facebook\",\n twitter: \"twitter\",\n x: \"twitter\",\n instagram: \"instagram\",\n linkedin: \"linkedin\",\n youtube: \"youtube\",\n tiktok: \"tiktok\",\n pinterest: \"pinterest\",\n email: \"email\",\n whatsapp: \"whatsapp\",\n telegram: \"telegram\",\n discord: \"discord\",\n snapchat: \"snapchat\",\n reddit: \"reddit\",\n github: \"github\",\n dribbble: \"dribbble\",\n behance: \"behance\",\n};\n\ntype Align = \"left\" | \"center\" | \"right\";\ntype LineStyle = \"solid\" | \"dashed\" | \"dotted\";\n\nfunction toAlign(value: string | undefined, fallback: Align = \"left\"): Align {\n if (value === \"left\" || value === \"center\" || value === \"right\") return value;\n return fallback;\n}\n\nfunction toLineStyle(\n value: string | undefined,\n fallback: LineStyle = \"solid\",\n): LineStyle {\n if (value === \"solid\" || value === \"dashed\" || value === \"dotted\")\n return value;\n return fallback;\n}\n\n/**\n * Strip every `<…>` from a button label and reject any stray `<` or `>`\n * left behind (e.g. a truncated `<script`). The original\n * `value.replace(/<[^>]*>/g, \"\")` was both polynomial-ReDoS over\n * `<<<<…` inputs and an incomplete sanitizer — an unterminated `<script`\n * would survive the strip. Downstream HTML-escapes the label at render\n * time, but stripping here keeps the imported JSON clean.\n */\nfunction stripTagsPlain(text: string): string {\n let out = \"\";\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"<\") {\n const close = text.indexOf(\">\", i + 1);\n if (close === -1) {\n // Unterminated tag — discard the rest.\n break;\n }\n i = close + 1;\n continue;\n }\n if (text[i] === \">\") {\n i++;\n continue;\n }\n out += text[i];\n i++;\n }\n return out;\n}\n\nfunction makeStyles(descriptor: BeeFreeeModuleDescriptor): Block[\"styles\"] {\n const padding = extractPadding(descriptor.style);\n const bg = parseColor(descriptor.style?.[\"background-color\"]);\n return {\n padding,\n ...(bg ? { backgroundColor: bg } : {}),\n };\n}\n\n/**\n * Apply BeeFree text styles as TipTap-compatible inline markup.\n * - text-align → added to each <p> tag's style attribute\n * - color, font-size, font-weight, font-family → wrapped in <span style=\"...\"> inside each <p>\n */\nfunction inlineStylesToHtml(\n html: string,\n style: Record<string, string | undefined>,\n textColor: string,\n): string {\n const spanParts: string[] = [];\n const fontSize = parsePxValue(style[\"font-size\"]);\n if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);\n const color = parseColor(style.color);\n // A paragraph inherits the template's text color, so only a different\n // color needs a span to survive.\n if (color && color !== textColor) spanParts.push(`color: ${color}`);\n const fontWeight = style[\"font-weight\"];\n // \"400\" is the numeric synonym for \"normal\" — neither needs an explicit\n // span (matches the import-unlayer importer).\n if (fontWeight && fontWeight !== \"normal\" && fontWeight !== \"400\")\n spanParts.push(`font-weight: ${fontWeight}`);\n const fontFamily = parseFontFamily(style[\"font-family\"]);\n if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);\n\n const textAlign = style[\"text-align\"];\n const pStyle =\n textAlign && textAlign !== \"left\" ? `text-align: ${textAlign}` : \"\";\n\n if (!pStyle && spanParts.length === 0) return html;\n\n const spanStyle = spanParts.join(\"; \");\n\n // Apply styles to each <p> tag in the HTML\n let result = html;\n\n if (pStyle) {\n // Add text-align to existing <p style=\"...\"> or add style to plain <p>\n result = result\n .replace(/<p style=\"([^\"]*)\">/g, `<p style=\"$1; ${pStyle}\">`)\n .replaceAll(\"<p>\", `<p style=\"${pStyle}\">`);\n }\n\n if (spanStyle) {\n // Wrap inner content of each <p> in a styled span.\n result = wrapParagraphInner(result, spanStyle);\n }\n\n return result;\n}\n\n/**\n * Wrap the inner content of every `<p …>…</p>` with `<span style=\"…\">…</span>`.\n *\n * Hand-rolled linear scanner instead of `/<p([^>]*)>([\\s\\S]*?)<\\/p>/g` because\n * the regex is polynomial-ReDoS: the engine retries `[\\s\\S]*?<\\/p>` at every\n * `<p` start, so inputs like `<p>a<p>a<p>a…` (no `</p>` ever) cost O(n²).\n * The scanner advances `i` monotonically via `indexOf`, keeping the work\n * strictly O(n).\n */\nfunction wrapParagraphInner(html: string, spanStyle: string): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<p\", i);\n if (open === -1) {\n out += html.substring(i);\n break;\n }\n const afterTagName = html[open + 2];\n if (\n afterTagName !== \">\" &&\n afterTagName !== \" \" &&\n afterTagName !== \"\\t\" &&\n afterTagName !== \"\\n\" &&\n afterTagName !== \"\\r\" &&\n afterTagName !== \"/\"\n ) {\n out += html.substring(i, open + 2);\n i = open + 2;\n continue;\n }\n const openEnd = html.indexOf(\">\", open + 2);\n if (openEnd === -1) {\n out += html.substring(i);\n break;\n }\n const closeStart = html.indexOf(\"</p>\", openEnd + 1);\n if (closeStart === -1) {\n out += html.substring(i);\n break;\n }\n const inner = html.substring(openEnd + 1, closeStart);\n out += html.substring(i, openEnd + 1);\n out += `<span style=\"${spanStyle}\">${inner}</span></p>`;\n i = closeStart + 4;\n }\n return out;\n}\n\nfunction convertText(\n descriptor: BeeFreeeModuleDescriptor,\n textColor: string,\n): Block {\n const textContent =\n descriptor.text ?? descriptor.paragraph ?? descriptor.list;\n const html = textContent?.html ?? \"\";\n const style = textContent?.style ?? {};\n\n return createParagraphBlock({\n content: inlineStylesToHtml(html, style, textColor),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction parseHeadingLevel(tag: string): HeadingLevel {\n const match = tag.match(/^h(\\d)$/i);\n if (match) {\n const num = Number(match[1]);\n if (num >= 1 && num <= 4) return num as HeadingLevel;\n }\n return 2;\n}\n\nfunction convertHeading(\n descriptor: BeeFreeeModuleDescriptor,\n textColor: string,\n): Block {\n const heading = descriptor.heading;\n if (!heading) return convertText(descriptor, textColor);\n\n const style = heading.style ?? {};\n const tag = heading.title ?? \"h2\";\n const text = heading.text ?? \"\";\n // Strip heading tags — content goes inside TipTap, heading tag is rendered by the block\n const content = text.startsWith(\"<\")\n ? text.replace(/^<h\\d[^>]*>|<\\/h\\d>$/gi, \"\")\n : text;\n\n return createTitleBlock({\n content: content ? `<p>${content}</p>` : \"<p></p>\",\n level: parseHeadingLevel(tag),\n color: parseColor(style.color) || undefined,\n textAlign: toAlign(style[\"text-align\"]),\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertImage(descriptor: BeeFreeeModuleDescriptor): Block {\n const image = descriptor.image;\n if (!image) {\n return createImageBlock({ styles: makeStyles(descriptor) });\n }\n\n // Kept separate from the `?? 600` fallback below: a percentage radius has to\n // resolve against a width the template actually stated.\n const readWidth = parsePxValue(image.width) || undefined;\n const readHeight = parsePxValue(image.height) || undefined;\n\n return createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width: readWidth ?? 600,\n // No default, unlike width: an absent height is what keeps the aspect\n // ratio, and BeeFree's \"auto\" parses to 0, which reads the same way.\n height: readHeight,\n borderRadius: parseImageBorderRadius(\n image.style?.[\"border-radius\"],\n readWidth,\n readHeight,\n ),\n align: toAlign(image.style?.[\"text-align\"], \"center\"),\n linkUrl: image.href || undefined,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertButton(descriptor: BeeFreeeModuleDescriptor): Block {\n const button = descriptor.button;\n if (!button) {\n return createButtonBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = button.style ?? {};\n const label = button.label ? stripTagsPlain(button.label) : \"Button\";\n\n return createButtonBlock({\n text: label,\n url: button.href || \"#\",\n backgroundColor: parseColor(style[\"background-color\"]) || \"#4f46e5\",\n textColor: parseColor(style.color) || \"#ffffff\",\n borderRadius: parsePxValue(style[\"border-radius\"]),\n fontSize: parsePxValue(style[\"font-size\"]) || 16,\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n align: toAlign(style[\"text-align\"], \"center\"),\n buttonPadding: {\n top: parsePxValue(style[\"padding-top\"]) || 12,\n right: parsePxValue(style[\"padding-right\"]) || 24,\n bottom: parsePxValue(style[\"padding-bottom\"]) || 12,\n left: parsePxValue(style[\"padding-left\"]) || 24,\n },\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * `\"full\"` when the divider spans its column: no width, `100%`, or a px width\n * that reaches `contentWidth`. Without a `contentWidth` a px width stands as\n * stated. Any other percentage stays a percentage, clamped to 0–100%.\n */\nfunction resolveDividerWidth(\n value: string | undefined,\n contentWidth: number | undefined,\n notes: string[],\n): DividerBlock[\"width\"] {\n const raw = (value ?? \"\").trim();\n if (!raw) return \"full\";\n\n const parsed = parseDividerWidth(raw);\n if (!parsed) {\n notes.push(\n `Divider width \"${raw}\" could not be read; imported as full width.`,\n );\n return \"full\";\n }\n\n if (parsed.unit === \"%\") {\n const percent = Math.min(100, Math.max(0, parsed.value));\n if (percent !== parsed.value) {\n notes.push(`Divider width ${raw} was clamped to ${percent}%.`);\n }\n // Two decimals keep the value inside `DividerPercentWidth`'s pattern,\n // which a float printed in exponent form would leave.\n const share = Math.round(percent * 100) / 100;\n return share === 100 ? \"full\" : `${share}%`;\n }\n\n const px = Math.max(0, Math.round(parsed.value));\n if (px !== Math.round(parsed.value)) {\n notes.push(`Divider width ${raw} was clamped to 0px.`);\n }\n return contentWidth !== undefined && px >= contentWidth ? \"full\" : px;\n}\n\nfunction convertDivider(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n): { block: Block; notes: string[] } {\n const style = descriptor.divider?.style ?? {};\n const border = parseBorderTop(style[\"border-top\"]);\n const styles = makeStyles(descriptor);\n const notes: string[] = [];\n\n // MJML draws a full divider across its column less the divider's own\n // padding, so a px width that reaches that renders the same as \"full\", and\n // \"full\" keeps narrowing with the column on a phone.\n const contentWidth =\n columnWidth === undefined\n ? undefined\n : columnWidth - styles.padding.left - styles.padding.right;\n const width = resolveDividerWidth(style.width, contentWidth, notes);\n\n const align = dividerAlign(descriptor);\n if (width !== \"full\" && (align === \"left\" || align === \"right\")) {\n notes.push(\n `BeeFree aligns this divider ${align}; Templatical centres every divider.`,\n );\n }\n\n return {\n block: createDividerBlock({\n lineStyle: toLineStyle(border.style),\n color: border.color,\n thickness: border.width || 1,\n width,\n styles,\n }),\n notes,\n };\n}\n\n/**\n * BeeFree keeps a divider's alignment in `computedStyle.align`; some exports\n * also write it to the module style's `text-align`.\n */\nfunction dividerAlign(\n descriptor: BeeFreeeModuleDescriptor,\n): string | undefined {\n const computed = descriptor.computedStyle?.align;\n return typeof computed === \"string\"\n ? computed\n : descriptor.style?.[\"text-align\"];\n}\n\nfunction convertSpacer(descriptor: BeeFreeeModuleDescriptor): Block {\n const spacer = descriptor.spacer;\n const height = parsePxValue(spacer?.style?.height) || 24;\n\n return createSpacerBlock({\n height,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertHtml(descriptor: BeeFreeeModuleDescriptor): Block {\n const html = descriptor.html?.html ?? \"\";\n\n return createHtmlBlock({\n content: html,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertSocial(\n descriptor: BeeFreeeModuleDescriptor,\n warnings: string[],\n): Block {\n const iconsList = descriptor.iconsList;\n if (!iconsList?.icons) {\n return createSocialIconsBlock({ styles: makeStyles(descriptor) });\n }\n\n const icons: SocialIcon[] = [];\n\n for (const beeIcon of iconsList.icons) {\n const id = (beeIcon.id ?? beeIcon.name ?? \"\").toLowerCase();\n const platform = SOCIAL_PLATFORM_MAP[id];\n\n if (!platform) {\n warnings.push(\n `Unrecognized social icon \"${beeIcon.name || id}\" was skipped.`,\n );\n continue;\n }\n\n icons.push({\n id: generateId(),\n platform,\n url: beeIcon.image?.href || \"#\",\n });\n }\n\n return createSocialIconsBlock({\n icons,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertVideo(descriptor: BeeFreeeModuleDescriptor): Block {\n const video = descriptor.video;\n if (!video) {\n return createVideoBlock({ styles: makeStyles(descriptor) });\n }\n\n return createVideoBlock({\n url: video.src || \"\",\n thumbnailUrl: video.thumbnail || \"\",\n alt: video.alt || \"\",\n width: parsePxValue(video.style?.width) || 600,\n height: parsePxValue(video.style?.height) || undefined,\n align: toAlign(video.style?.[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertMenu(descriptor: BeeFreeeModuleDescriptor): Block {\n const menu = descriptor.menu;\n if (!menu) {\n return createMenuBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = menu.style ?? {};\n\n const items: MenuItemData[] = (menu.items ?? []).map((item) => ({\n id: generateId(),\n text: item.text || \"\",\n url: item.link || item.href || \"#\",\n openInNewTab: item.target === \"_blank\",\n bold: false,\n underline: false,\n }));\n\n return createMenuBlock({\n items,\n separator: menu.separator || \"|\",\n separatorColor: parseColor(menu.separatorColor) || \"#999999\",\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || undefined,\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n textAlign: toAlign(style[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertTable(descriptor: BeeFreeeModuleDescriptor): {\n block: Block;\n approximated: boolean;\n} {\n const table = descriptor.table;\n if (!table) {\n return {\n block: createTableBlock({ styles: makeStyles(descriptor) }),\n approximated: false,\n };\n }\n\n const style = table.style ?? {};\n\n // Templatical table cells are a plain-text field (the editor stores the\n // cell's innerText), so strip any HTML a BeeFree cell carried the same way\n // button labels are stripped. If a strip actually removed markup, the cell\n // lost formatting or a link URL, so the conversion is an approximation.\n let approximated = false;\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map((cell): TableCellData => {\n const raw = cell.content ?? cell.html ?? \"\";\n const content = stripTagsPlain(raw);\n if (content !== raw) {\n approximated = true;\n }\n return { id: generateId(), content };\n }),\n }));\n\n return {\n block: createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor:\n parseColor(table.headerBackgroundColor) || undefined,\n borderColor: parseColor(style[\"border-color\"]) || \"#dddddd\",\n borderWidth: parsePxValue(style[\"border-width\"]) || 1,\n cellPadding:\n typeof table.cellPadding === \"number\"\n ? table.cellPadding\n : parsePxValue(table.cellPadding as string) || 8,\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || undefined,\n textAlign: toAlign(style[\"text-align\"]),\n styles: makeStyles(descriptor),\n }),\n approximated,\n };\n}\n\nfunction convertHtmlFallback(module: BeeFreeeModule): Block {\n // Attempt to extract any HTML content from the descriptor\n const descriptor = module.descriptor;\n let html = \"\";\n\n // Try common content fields\n if (descriptor.text?.html) html = descriptor.text.html;\n else if (descriptor.html?.html) html = descriptor.html.html;\n else if (descriptor.heading?.text) html = descriptor.heading.text;\n else html = `<!-- Unsupported BeeFree module: ${module.type} -->`;\n\n return createHtmlBlock({\n content: html,\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * Converts a single BeeFree module to a Templatical block.\n * Returns the block and a report entry.\n */\nexport function convertModule(\n module: BeeFreeeModule,\n warnings: string[],\n context: ModuleContext = {},\n): { block: Block; entry: ImportReportEntry } {\n const mappedType = MODULE_TYPE_MAP[module.type];\n const descriptor = module.descriptor;\n const textColor = context.textColor ?? FALLBACK_TEXT_COLOR;\n\n if (!mappedType) {\n return {\n block: convertHtmlFallback(module),\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: `Unknown module type \"${module.type}\" converted to HTML block.`,\n },\n };\n }\n\n let block: Block;\n let isApproximation = false;\n let notes: string[] = [];\n\n switch (mappedType) {\n case \"paragraph\":\n case \"list\":\n block = convertText(descriptor, textColor);\n break;\n case \"title\":\n block = convertHeading(descriptor, textColor);\n break;\n case \"image\":\n block = convertImage(descriptor);\n break;\n case \"button\":\n block = convertButton(descriptor);\n break;\n case \"divider\": {\n const result = convertDivider(descriptor, context.columnWidth);\n block = result.block;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"spacer\":\n block = convertSpacer(descriptor);\n break;\n case \"html\":\n block = convertHtml(descriptor);\n break;\n case \"social\":\n block = convertSocial(descriptor, warnings);\n break;\n case \"video\":\n block = convertVideo(descriptor);\n break;\n case \"menu\":\n block = convertMenu(descriptor);\n isApproximation = true; // menu styles are approximate\n break;\n case \"table\": {\n const result = convertTable(descriptor);\n block = result.block;\n if (result.approximated) {\n isApproximation = true;\n warnings.push(\n \"HTML inside one or more table cells was reduced to plain text; any cell formatting or links were dropped.\",\n );\n }\n break;\n }\n default:\n block = convertHtmlFallback(module);\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n },\n };\n }\n\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: block.type,\n status: isApproximation ? \"approximated\" : \"converted\",\n ...(notes.length > 0 ? { note: notes.join(\" \") } : {}),\n },\n };\n}\n","import {\n createSectionBlock,\n createDefaultTemplateContent,\n} from \"@templatical/types\";\nimport type { Block, ColumnLayout, TemplateContent } from \"@templatical/types\";\nimport type {\n BeeFreeTemplate,\n BeeFreeeRow,\n BeeFreeeColumn,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n} from \"./types\";\nimport {\n convertModule,\n FALLBACK_TEXT_COLOR,\n type ModuleContext,\n} from \"./block-mapper\";\nimport { parsePxValue, parseColor, parseFontFamily } from \"./style-parser\";\n\n/**\n * Determines the Templatical ColumnLayout from BeeFree column grid values.\n */\nfunction resolveColumnLayout(\n columns: BeeFreeeColumn[],\n warnings: string[],\n): ColumnLayout | null {\n if (columns.length === 1) return null; // Single column — no section wrapper needed\n if (columns.length === 3) return \"3\";\n\n if (columns.length === 2) {\n const left = columns[0][\"grid-columns\"] ?? 6;\n const right = columns[1][\"grid-columns\"] ?? 6;\n const total = left + right;\n const ratio = left / total;\n\n if (ratio > 0.58) return \"2-1\";\n if (ratio < 0.42) return \"1-2\";\n return \"2\";\n }\n\n if (columns.length >= 4) {\n warnings.push(\n `Row with ${columns.length} columns was flattened to a single column. BeeFree supports arbitrary columns, but Templatical supports up to 3.`,\n );\n return null; // Flatten to single column\n }\n\n return \"2\";\n}\n\n/**\n * Column widths in px for a layout, mirroring `renderer/src/columns.ts`, and\n * floored as the renderer floors the width it hands each column.\n */\nfunction columnPixels(layout: ColumnLayout, bodyWidth: number): number[] {\n switch (layout) {\n case \"2\":\n return [bodyWidth * 0.5, bodyWidth * 0.5].map(Math.floor);\n case \"3\":\n return [bodyWidth / 3, bodyWidth / 3, bodyWidth / 3].map(Math.floor);\n case \"1-2\":\n return [bodyWidth / 3, (bodyWidth * 2) / 3].map(Math.floor);\n case \"2-1\":\n return [(bodyWidth * 2) / 3, bodyWidth / 3].map(Math.floor);\n default:\n return [Math.floor(bodyWidth)];\n }\n}\n\n/**\n * Converts all modules in a column to Templatical blocks.\n */\nfunction convertColumnModules(\n column: BeeFreeeColumn,\n context: ModuleContext,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const blocks: Block[] = [];\n\n for (const module of column.modules) {\n const { block, entry } = convertModule(module, warnings, context);\n blocks.push(block);\n entries.push(entry);\n }\n\n return blocks;\n}\n\n/**\n * Processes a single BeeFree row into one or more Templatical blocks.\n */\nfunction processRow(\n row: BeeFreeeRow,\n settings: TemplateContent[\"settings\"],\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const columns = row.columns;\n if (!columns || columns.length === 0) return [];\n\n // Track locked/synced metadata\n if (row.locked) {\n warnings.push(\n \"A locked row was imported. Lock metadata was dropped; content is preserved.\",\n );\n }\n if (row.synced) {\n warnings.push(\n \"A synced row was imported. Sync metadata was dropped; content is preserved.\",\n );\n }\n\n const layout = resolveColumnLayout(columns, warnings);\n\n // Extract section-level background from row content styles.\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n\n if (!layout) {\n // Single column (or flattened 4+ columns) — return modules directly.\n // Either way the modules end up spanning the body.\n const blocks: Block[] = [];\n const context = {\n columnWidth: settings.width,\n textColor: settings.textColor,\n };\n for (const column of columns) {\n blocks.push(...convertColumnModules(column, context, entries, warnings));\n }\n // A non-transparent row background can't survive on bare modules; wrap\n // them in a one-column section so the colored band still renders. Mirrors\n // the multi-column path and the Unlayer importer (which wraps every row).\n if (rowBg) {\n return [\n createSectionBlock({\n columns: \"1\",\n children: [blocks],\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n backgroundColor: rowBg,\n },\n }),\n ];\n }\n return blocks;\n }\n\n // Multi-column — wrap in a SectionBlock\n const widths = columnPixels(layout, settings.width);\n const children: Block[][] = columns.map((col, index) =>\n convertColumnModules(\n col,\n { columnWidth: widths[index], textColor: settings.textColor },\n entries,\n warnings,\n ),\n );\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n });\n\n return [section];\n}\n\n/**\n * Extracts template-level settings from the BeeFree body.\n */\nfunction extractSettings(\n template: BeeFreeTemplate,\n): TemplateContent[\"settings\"] {\n const body = template.page.body;\n const contentStyle = body?.content?.style ?? {};\n const computedStyle = body?.content?.computedStyle ?? {};\n const containerStyle = body?.container?.style ?? {};\n\n // Exports keep the body width in `computedStyle.messageWidth` and usually\n // carry no `style.width`.\n const width =\n parsePxValue(computedStyle.messageWidth) ||\n parsePxValue(contentStyle.width);\n const bgColor =\n parseColor(contentStyle[\"background-color\"]) ||\n parseColor(containerStyle[\"background-color\"]) ||\n \"#ffffff\";\n const fontFamily = parseFontFamily(contentStyle[\"font-family\"]) || \"Arial\";\n const linkColor = parseColor(computedStyle.linkColor);\n\n return {\n width: width || 600,\n backgroundColor: bgColor,\n textColor: parseColor(contentStyle.color) || FALLBACK_TEXT_COLOR,\n ...(linkColor ? { linkColor } : {}),\n // BeeFree underlines per link, in the link's own markup, and has no\n // template-wide switch, so links take the browser default: underlined.\n linkUnderline: true,\n fontFamily,\n locale: \"en\",\n };\n}\n\n/**\n * Converts a BeeFree template JSON to Templatical TemplateContent.\n *\n * @param template - The parsed BeeFree JSON object\n * @returns An ImportResult with the converted content and a detailed report\n *\n * @example\n * ```ts\n * import { convertBeeFreeTemplate } from '@templatical/import-beefree';\n *\n * const beeFreeJson = JSON.parse(fileContent);\n * const { content, report } = convertBeeFreeTemplate(beeFreeJson);\n *\n * // Use the content with the editor\n * const editor = init({ container: '#editor', content });\n *\n * // Check the report for any issues\n * console.log(report.summary);\n * console.log(report.warnings);\n * ```\n */\nexport function convertBeeFreeTemplate(\n template: BeeFreeTemplate,\n): ImportResult {\n // Validate structure\n if (!template?.page?.rows) {\n throw new Error(\n \"Invalid BeeFree template: missing page.rows. Ensure you are passing a valid BeeFree JSON export.\",\n );\n }\n\n const entries: ImportReportEntry[] = [];\n const warnings: string[] = [];\n const blocks: Block[] = [];\n\n // Extract web font warnings\n const webFonts = template.page.body?.webFonts;\n if (webFonts && webFonts.length > 1) {\n warnings.push(\n `Template uses ${webFonts.length} web fonts. Only the primary font is preserved; additional fonts may need to be configured via the fonts option.`,\n );\n }\n\n // Rows are measured against the width the imported template renders at.\n const settings = extractSettings(template);\n\n // Process rows\n for (const row of template.page.rows) {\n if (row.empty) continue;\n blocks.push(...processRow(row, settings, entries, warnings));\n }\n\n // Build template content\n const content: TemplateContent = {\n ...createDefaultTemplateContent(),\n blocks,\n settings,\n };\n\n // Build report summary\n const summary = {\n total: entries.length,\n converted: entries.filter((e) => e.status === \"converted\").length,\n approximated: entries.filter((e) => e.status === \"approximated\").length,\n htmlFallback: entries.filter((e) => e.status === \"html-fallback\").length,\n skipped: entries.filter((e) => e.status === \"skipped\").length,\n };\n\n const report: ImportReport = { entries, warnings, summary };\n\n return { content, report };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@templatical/import-beefree",
3
3
  "description": "Convert BeeFree email templates to Templatical format",
4
- "version": "0.42.1",
4
+ "version": "0.43.1",
5
5
  "bugs": "https://github.com/templatical/sdk/issues",
6
6
  "dependencies": {
7
- "@templatical/types": "0.42.1"
7
+ "@templatical/types": "0.43.1"
8
8
  },
9
9
  "devDependencies": {
10
10
  "typescript": "^6.0.3",