@templatical/import-beefree 0.0.1 → 0.0.2
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.cjs +46 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +48 -22
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.cjs
CHANGED
|
@@ -116,9 +116,9 @@ function parseFontFamily(value) {
|
|
|
116
116
|
|
|
117
117
|
// src/block-mapper.ts
|
|
118
118
|
var MODULE_TYPE_MAP = {
|
|
119
|
-
"mailup-bee-newsletter-modules-text": "
|
|
120
|
-
"mailup-bee-newsletter-modules-paragraph": "
|
|
121
|
-
"mailup-bee-newsletter-modules-heading": "
|
|
119
|
+
"mailup-bee-newsletter-modules-text": "paragraph",
|
|
120
|
+
"mailup-bee-newsletter-modules-paragraph": "paragraph",
|
|
121
|
+
"mailup-bee-newsletter-modules-heading": "title",
|
|
122
122
|
"mailup-bee-newsletter-modules-list": "list",
|
|
123
123
|
"mailup-bee-newsletter-modules-image": "image",
|
|
124
124
|
"mailup-bee-newsletter-modules-button": "button",
|
|
@@ -153,10 +153,6 @@ function toAlign(value, fallback = "left") {
|
|
|
153
153
|
if (value === "left" || value === "center" || value === "right") return value;
|
|
154
154
|
return fallback;
|
|
155
155
|
}
|
|
156
|
-
function toFontWeight(value, fallback = "normal") {
|
|
157
|
-
if (value === "bold") return "bold";
|
|
158
|
-
return fallback;
|
|
159
|
-
}
|
|
160
156
|
function toLineStyle(value, fallback = "solid") {
|
|
161
157
|
if (value === "solid" || value === "dashed" || value === "dotted")
|
|
162
158
|
return value;
|
|
@@ -174,33 +170,62 @@ function makeStyles(descriptor) {
|
|
|
174
170
|
...bg ? { backgroundColor: bg } : {}
|
|
175
171
|
};
|
|
176
172
|
}
|
|
173
|
+
function inlineStylesToHtml(html, style) {
|
|
174
|
+
const spanParts = [];
|
|
175
|
+
const fontSize = parsePxValue(style["font-size"]);
|
|
176
|
+
if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);
|
|
177
|
+
const color = parseColor(style.color);
|
|
178
|
+
if (color && color !== "#1a1a1a") spanParts.push(`color: ${color}`);
|
|
179
|
+
const fontWeight = style["font-weight"];
|
|
180
|
+
if (fontWeight && fontWeight !== "normal")
|
|
181
|
+
spanParts.push(`font-weight: ${fontWeight}`);
|
|
182
|
+
const fontFamily = parseFontFamily(style["font-family"]);
|
|
183
|
+
if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);
|
|
184
|
+
const textAlign = style["text-align"];
|
|
185
|
+
const pStyle = textAlign && textAlign !== "left" ? `text-align: ${textAlign}` : "";
|
|
186
|
+
if (!pStyle && spanParts.length === 0) return html;
|
|
187
|
+
const spanStyle = spanParts.join("; ");
|
|
188
|
+
let result = html;
|
|
189
|
+
if (pStyle) {
|
|
190
|
+
result = result.replace(/<p style="([^"]*)">/g, `<p style="$1; ${pStyle}">`).replaceAll("<p>", `<p style="${pStyle}">`);
|
|
191
|
+
}
|
|
192
|
+
if (spanStyle) {
|
|
193
|
+
result = result.replace(
|
|
194
|
+
/<p([^>]*)>([\s\S]*?)<\/p>/g,
|
|
195
|
+
`<p$1><span style="${spanStyle}">$2</span></p>`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
177
200
|
function convertText(descriptor) {
|
|
178
201
|
const textContent = descriptor.text ?? descriptor.paragraph ?? descriptor.list;
|
|
179
202
|
const html = textContent?.html ?? "";
|
|
180
203
|
const style = textContent?.style ?? {};
|
|
181
|
-
return (0, import_types.
|
|
182
|
-
content: html,
|
|
183
|
-
fontSize: parsePxValue(style["font-size"]) || 16,
|
|
184
|
-
color: parseColor(style.color) || "#1a1a1a",
|
|
185
|
-
textAlign: toAlign(style["text-align"]),
|
|
186
|
-
fontWeight: toFontWeight(style["font-weight"]),
|
|
187
|
-
fontFamily: parseFontFamily(style["font-family"]) || void 0,
|
|
204
|
+
return (0, import_types.createParagraphBlock)({
|
|
205
|
+
content: inlineStylesToHtml(html, style),
|
|
188
206
|
styles: makeStyles(descriptor)
|
|
189
207
|
});
|
|
190
208
|
}
|
|
209
|
+
function parseHeadingLevel(tag) {
|
|
210
|
+
const match = tag.match(/^h(\d)$/i);
|
|
211
|
+
if (match) {
|
|
212
|
+
const num = Number(match[1]);
|
|
213
|
+
if (num >= 1 && num <= 4) return num;
|
|
214
|
+
}
|
|
215
|
+
return 2;
|
|
216
|
+
}
|
|
191
217
|
function convertHeading(descriptor) {
|
|
192
218
|
const heading = descriptor.heading;
|
|
193
219
|
if (!heading) return convertText(descriptor);
|
|
194
220
|
const style = heading.style ?? {};
|
|
195
221
|
const tag = heading.title ?? "h2";
|
|
196
222
|
const text = heading.text ?? "";
|
|
197
|
-
const content = text.startsWith("<") ? text :
|
|
198
|
-
return (0, import_types.
|
|
199
|
-
content,
|
|
200
|
-
|
|
223
|
+
const content = text.startsWith("<") ? text.replace(/^<h\d[^>]*>|<\/h\d>$/gi, "") : text;
|
|
224
|
+
return (0, import_types.createTitleBlock)({
|
|
225
|
+
content: content ? `<p>${content}</p>` : "<p></p>",
|
|
226
|
+
level: parseHeadingLevel(tag),
|
|
201
227
|
color: parseColor(style.color) || "#1a1a1a",
|
|
202
228
|
textAlign: toAlign(style["text-align"]),
|
|
203
|
-
fontWeight: toFontWeight(style["font-weight"], "bold"),
|
|
204
229
|
fontFamily: parseFontFamily(style["font-family"]) || void 0,
|
|
205
230
|
styles: makeStyles(descriptor)
|
|
206
231
|
});
|
|
@@ -392,11 +417,11 @@ function convertModule(module2, warnings) {
|
|
|
392
417
|
let block;
|
|
393
418
|
let isApproximation = false;
|
|
394
419
|
switch (mappedType) {
|
|
395
|
-
case "
|
|
420
|
+
case "paragraph":
|
|
396
421
|
case "list":
|
|
397
422
|
block = convertText(descriptor);
|
|
398
423
|
break;
|
|
399
|
-
case "
|
|
424
|
+
case "title":
|
|
400
425
|
block = convertHeading(descriptor);
|
|
401
426
|
break;
|
|
402
427
|
case "image":
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/converter.ts","../src/block-mapper.ts","../src/style-parser.ts"],"sourcesContent":["export { convertBeeFreeTemplate } from \"./converter\";\nexport type {\n BeeFreeTemplate,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n ConversionStatus,\n} from \"./types\";\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 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 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 // Extract section-level background from row content styles\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n margin: { 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 fontFamily,\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","import {\n createTextBlock,\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 SocialPlatform,\n SocialIcon,\n MenuItemData,\n TableRowData,\n TableCellData,\n SpacingValue,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n ImportReportEntry,\n} from \"./types\";\nimport {\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\": \"text\",\n \"mailup-bee-newsletter-modules-paragraph\": \"text\",\n \"mailup-bee-newsletter-modules-heading\": \"heading\",\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 FontWeight = \"normal\" | \"bold\";\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 toFontWeight(\n value: string | undefined,\n fallback: FontWeight = \"normal\",\n): FontWeight {\n if (value === \"bold\") return \"bold\";\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\nfunction defaultMargin(): SpacingValue {\n return { top: 0, right: 0, bottom: 0, left: 0 };\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 margin: defaultMargin(),\n ...(bg ? { backgroundColor: bg } : {}),\n };\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 createTextBlock({\n content: html,\n fontSize: parsePxValue(style[\"font-size\"]) || 16,\n color: parseColor(style.color) || \"#1a1a1a\",\n textAlign: toAlign(style[\"text-align\"]),\n fontWeight: toFontWeight(style[\"font-weight\"]),\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n styles: makeStyles(descriptor),\n });\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 const content = text.startsWith(\"<\") ? text : `<${tag}>${text}</${tag}>`;\n\n return createTextBlock({\n content,\n fontSize: parsePxValue(style[\"font-size\"]) || 24,\n color: parseColor(style.color) || \"#1a1a1a\",\n textAlign: toAlign(style[\"text-align\"]),\n fontWeight: toFontWeight(style[\"font-weight\"], \"bold\"),\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 return createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width: parsePxValue(image.width) || 600,\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?.replace(/<[^>]*>/g, \"\") ?? \"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 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 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): Block {\n const table = descriptor.table;\n if (!table) {\n return createTableBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = table.style ?? {};\n\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map(\n (cell): TableCellData => ({\n id: generateId(),\n content: cell.content ?? cell.html ?? \"\",\n }),\n ),\n }));\n\n return createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor: 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}\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 \"text\":\n case \"list\":\n block = convertText(descriptor);\n break;\n case \"heading\":\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 block = convertTable(descriptor);\n break;\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 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\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"],"mappings":"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","names":["import_types","module","module"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/converter.ts","../src/block-mapper.ts","../src/style-parser.ts"],"sourcesContent":["export { convertBeeFreeTemplate } from \"./converter\";\nexport type {\n BeeFreeTemplate,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n ConversionStatus,\n} from \"./types\";\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 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 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 // Extract section-level background from row content styles\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n margin: { 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 fontFamily,\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","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 SpacingValue,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n ImportReportEntry,\n} from \"./types\";\nimport {\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\nfunction defaultMargin(): SpacingValue {\n return { top: 0, right: 0, bottom: 0, left: 0 };\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 margin: defaultMargin(),\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 if (fontWeight && fontWeight !== \"normal\")\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 = result.replace(\n /<p([^>]*)>([\\s\\S]*?)<\\/p>/g,\n `<p$1><span style=\"${spanStyle}\">$2</span></p>`,\n );\n }\n\n return result;\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 return createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width: parsePxValue(image.width) || 600,\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?.replace(/<[^>]*>/g, \"\") ?? \"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 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 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): Block {\n const table = descriptor.table;\n if (!table) {\n return createTableBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = table.style ?? {};\n\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map(\n (cell): TableCellData => ({\n id: generateId(),\n content: cell.content ?? cell.html ?? \"\",\n }),\n ),\n }));\n\n return createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor: 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}\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 block = convertTable(descriptor);\n break;\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 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\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"],"mappings":"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","names":["import_types","module","module"]}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
|
|
7
7
|
// src/block-mapper.ts
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
createTitleBlock,
|
|
10
|
+
createParagraphBlock,
|
|
10
11
|
createImageBlock,
|
|
11
12
|
createButtonBlock,
|
|
12
13
|
createDividerBlock,
|
|
@@ -105,9 +106,9 @@ function parseFontFamily(value) {
|
|
|
105
106
|
|
|
106
107
|
// src/block-mapper.ts
|
|
107
108
|
var MODULE_TYPE_MAP = {
|
|
108
|
-
"mailup-bee-newsletter-modules-text": "
|
|
109
|
-
"mailup-bee-newsletter-modules-paragraph": "
|
|
110
|
-
"mailup-bee-newsletter-modules-heading": "
|
|
109
|
+
"mailup-bee-newsletter-modules-text": "paragraph",
|
|
110
|
+
"mailup-bee-newsletter-modules-paragraph": "paragraph",
|
|
111
|
+
"mailup-bee-newsletter-modules-heading": "title",
|
|
111
112
|
"mailup-bee-newsletter-modules-list": "list",
|
|
112
113
|
"mailup-bee-newsletter-modules-image": "image",
|
|
113
114
|
"mailup-bee-newsletter-modules-button": "button",
|
|
@@ -142,10 +143,6 @@ function toAlign(value, fallback = "left") {
|
|
|
142
143
|
if (value === "left" || value === "center" || value === "right") return value;
|
|
143
144
|
return fallback;
|
|
144
145
|
}
|
|
145
|
-
function toFontWeight(value, fallback = "normal") {
|
|
146
|
-
if (value === "bold") return "bold";
|
|
147
|
-
return fallback;
|
|
148
|
-
}
|
|
149
146
|
function toLineStyle(value, fallback = "solid") {
|
|
150
147
|
if (value === "solid" || value === "dashed" || value === "dotted")
|
|
151
148
|
return value;
|
|
@@ -163,33 +160,62 @@ function makeStyles(descriptor) {
|
|
|
163
160
|
...bg ? { backgroundColor: bg } : {}
|
|
164
161
|
};
|
|
165
162
|
}
|
|
163
|
+
function inlineStylesToHtml(html, style) {
|
|
164
|
+
const spanParts = [];
|
|
165
|
+
const fontSize = parsePxValue(style["font-size"]);
|
|
166
|
+
if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);
|
|
167
|
+
const color = parseColor(style.color);
|
|
168
|
+
if (color && color !== "#1a1a1a") spanParts.push(`color: ${color}`);
|
|
169
|
+
const fontWeight = style["font-weight"];
|
|
170
|
+
if (fontWeight && fontWeight !== "normal")
|
|
171
|
+
spanParts.push(`font-weight: ${fontWeight}`);
|
|
172
|
+
const fontFamily = parseFontFamily(style["font-family"]);
|
|
173
|
+
if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);
|
|
174
|
+
const textAlign = style["text-align"];
|
|
175
|
+
const pStyle = textAlign && textAlign !== "left" ? `text-align: ${textAlign}` : "";
|
|
176
|
+
if (!pStyle && spanParts.length === 0) return html;
|
|
177
|
+
const spanStyle = spanParts.join("; ");
|
|
178
|
+
let result = html;
|
|
179
|
+
if (pStyle) {
|
|
180
|
+
result = result.replace(/<p style="([^"]*)">/g, `<p style="$1; ${pStyle}">`).replaceAll("<p>", `<p style="${pStyle}">`);
|
|
181
|
+
}
|
|
182
|
+
if (spanStyle) {
|
|
183
|
+
result = result.replace(
|
|
184
|
+
/<p([^>]*)>([\s\S]*?)<\/p>/g,
|
|
185
|
+
`<p$1><span style="${spanStyle}">$2</span></p>`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
166
190
|
function convertText(descriptor) {
|
|
167
191
|
const textContent = descriptor.text ?? descriptor.paragraph ?? descriptor.list;
|
|
168
192
|
const html = textContent?.html ?? "";
|
|
169
193
|
const style = textContent?.style ?? {};
|
|
170
|
-
return
|
|
171
|
-
content: html,
|
|
172
|
-
fontSize: parsePxValue(style["font-size"]) || 16,
|
|
173
|
-
color: parseColor(style.color) || "#1a1a1a",
|
|
174
|
-
textAlign: toAlign(style["text-align"]),
|
|
175
|
-
fontWeight: toFontWeight(style["font-weight"]),
|
|
176
|
-
fontFamily: parseFontFamily(style["font-family"]) || void 0,
|
|
194
|
+
return createParagraphBlock({
|
|
195
|
+
content: inlineStylesToHtml(html, style),
|
|
177
196
|
styles: makeStyles(descriptor)
|
|
178
197
|
});
|
|
179
198
|
}
|
|
199
|
+
function parseHeadingLevel(tag) {
|
|
200
|
+
const match = tag.match(/^h(\d)$/i);
|
|
201
|
+
if (match) {
|
|
202
|
+
const num = Number(match[1]);
|
|
203
|
+
if (num >= 1 && num <= 4) return num;
|
|
204
|
+
}
|
|
205
|
+
return 2;
|
|
206
|
+
}
|
|
180
207
|
function convertHeading(descriptor) {
|
|
181
208
|
const heading = descriptor.heading;
|
|
182
209
|
if (!heading) return convertText(descriptor);
|
|
183
210
|
const style = heading.style ?? {};
|
|
184
211
|
const tag = heading.title ?? "h2";
|
|
185
212
|
const text = heading.text ?? "";
|
|
186
|
-
const content = text.startsWith("<") ? text :
|
|
187
|
-
return
|
|
188
|
-
content,
|
|
189
|
-
|
|
213
|
+
const content = text.startsWith("<") ? text.replace(/^<h\d[^>]*>|<\/h\d>$/gi, "") : text;
|
|
214
|
+
return createTitleBlock({
|
|
215
|
+
content: content ? `<p>${content}</p>` : "<p></p>",
|
|
216
|
+
level: parseHeadingLevel(tag),
|
|
190
217
|
color: parseColor(style.color) || "#1a1a1a",
|
|
191
218
|
textAlign: toAlign(style["text-align"]),
|
|
192
|
-
fontWeight: toFontWeight(style["font-weight"], "bold"),
|
|
193
219
|
fontFamily: parseFontFamily(style["font-family"]) || void 0,
|
|
194
220
|
styles: makeStyles(descriptor)
|
|
195
221
|
});
|
|
@@ -381,11 +407,11 @@ function convertModule(module, warnings) {
|
|
|
381
407
|
let block;
|
|
382
408
|
let isApproximation = false;
|
|
383
409
|
switch (mappedType) {
|
|
384
|
-
case "
|
|
410
|
+
case "paragraph":
|
|
385
411
|
case "list":
|
|
386
412
|
block = convertText(descriptor);
|
|
387
413
|
break;
|
|
388
|
-
case "
|
|
414
|
+
case "title":
|
|
389
415
|
block = convertHeading(descriptor);
|
|
390
416
|
break;
|
|
391
417
|
case "image":
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/converter.ts","../src/block-mapper.ts","../src/style-parser.ts"],"sourcesContent":["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 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 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 // Extract section-level background from row content styles\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n margin: { 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 fontFamily,\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","import {\n createTextBlock,\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 SocialPlatform,\n SocialIcon,\n MenuItemData,\n TableRowData,\n TableCellData,\n SpacingValue,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n ImportReportEntry,\n} from \"./types\";\nimport {\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\": \"text\",\n \"mailup-bee-newsletter-modules-paragraph\": \"text\",\n \"mailup-bee-newsletter-modules-heading\": \"heading\",\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 FontWeight = \"normal\" | \"bold\";\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 toFontWeight(\n value: string | undefined,\n fallback: FontWeight = \"normal\",\n): FontWeight {\n if (value === \"bold\") return \"bold\";\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\nfunction defaultMargin(): SpacingValue {\n return { top: 0, right: 0, bottom: 0, left: 0 };\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 margin: defaultMargin(),\n ...(bg ? { backgroundColor: bg } : {}),\n };\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 createTextBlock({\n content: html,\n fontSize: parsePxValue(style[\"font-size\"]) || 16,\n color: parseColor(style.color) || \"#1a1a1a\",\n textAlign: toAlign(style[\"text-align\"]),\n fontWeight: toFontWeight(style[\"font-weight\"]),\n fontFamily: parseFontFamily(style[\"font-family\"]) || undefined,\n styles: makeStyles(descriptor),\n });\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 const content = text.startsWith(\"<\") ? text : `<${tag}>${text}</${tag}>`;\n\n return createTextBlock({\n content,\n fontSize: parsePxValue(style[\"font-size\"]) || 24,\n color: parseColor(style.color) || \"#1a1a1a\",\n textAlign: toAlign(style[\"text-align\"]),\n fontWeight: toFontWeight(style[\"font-weight\"], \"bold\"),\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 return createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width: parsePxValue(image.width) || 600,\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?.replace(/<[^>]*>/g, \"\") ?? \"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 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 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): Block {\n const table = descriptor.table;\n if (!table) {\n return createTableBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = table.style ?? {};\n\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map(\n (cell): TableCellData => ({\n id: generateId(),\n content: cell.content ?? cell.html ?? \"\",\n }),\n ),\n }));\n\n return createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor: 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}\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 \"text\":\n case \"list\":\n block = convertText(descriptor);\n break;\n case \"heading\":\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 block = convertTable(descriptor);\n break;\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 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\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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/converter.ts","../src/block-mapper.ts","../src/style-parser.ts"],"sourcesContent":["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 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 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 // Extract section-level background from row content styles\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n margin: { 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 fontFamily,\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","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 SpacingValue,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n ImportReportEntry,\n} from \"./types\";\nimport {\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\nfunction defaultMargin(): SpacingValue {\n return { top: 0, right: 0, bottom: 0, left: 0 };\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 margin: defaultMargin(),\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 if (fontWeight && fontWeight !== \"normal\")\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 = result.replace(\n /<p([^>]*)>([\\s\\S]*?)<\\/p>/g,\n `<p$1><span style=\"${spanStyle}\">$2</span></p>`,\n );\n }\n\n return result;\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 return createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width: parsePxValue(image.width) || 600,\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?.replace(/<[^>]*>/g, \"\") ?? \"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 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 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): Block {\n const table = descriptor.table;\n if (!table) {\n return createTableBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = table.style ?? {};\n\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map(\n (cell): TableCellData => ({\n id: generateId(),\n content: cell.content ?? cell.html ?? \"\",\n }),\n ),\n }));\n\n return createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor: 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}\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 block = convertTable(descriptor);\n break;\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 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\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"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@templatical/import-beefree",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"publishConfig": {
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
5
7
|
"description": "Convert BeeFree email templates to Templatical format",
|
|
6
8
|
"license": "MIT",
|
|
7
9
|
"type": "module",
|
|
@@ -27,8 +29,8 @@
|
|
|
27
29
|
"@templatical/types": "workspace:*"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
|
-
"tsup": "^8.
|
|
31
|
-
"typescript": "^
|
|
32
|
-
"vitest": "^
|
|
32
|
+
"tsup": "^8.5.0",
|
|
33
|
+
"typescript": "^6.0.0",
|
|
34
|
+
"vitest": "^4.0.0"
|
|
33
35
|
}
|
|
34
36
|
}
|