mail-editor-pancake 0.0.7 → 0.0.8
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/README.md +50 -1
- package/package.json +1 -1
- package/packages/blocks/dist/index.js +88 -89
- package/packages/blocks/dist/index.js.map +1 -1
- package/packages/blocks/src/text.ts +21 -14
- package/packages/core/dist/index.d.ts +45 -4
- package/packages/core/dist/index.js +2252 -1449
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/style.css +1 -1
- package/packages/core/src/editor/Canvas.ts +68 -34
- package/packages/core/src/editor/ColorPickerPopover.ts +291 -0
- package/packages/core/src/editor/Editor.ts +72 -2
- package/packages/core/src/editor/ExportModal.ts +2 -1
- package/packages/core/src/editor/FocusBreadcrumb.ts +120 -0
- package/packages/core/src/editor/InlineEditor.ts +306 -65
- package/packages/core/src/editor/LeftPanel.ts +1 -2
- package/packages/core/src/editor/RichTextToolbar.ts +66 -44
- package/packages/core/src/editor/RightPanel.ts +491 -74
- package/packages/core/src/editor/SourceView.ts +2 -1
- package/packages/core/src/editor/Topbar.ts +98 -7
- package/packages/core/src/editor/styles.css +378 -25
- package/packages/core/src/index.ts +12 -1
- package/packages/core/src/store/store.ts +44 -3
- package/packages/core/src/types.ts +6 -0
- package/packages/core/src/utils/richTextCommand.ts +30 -0
- package/packages/core/src/utils/sectionLayout.ts +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/icons.ts","../src/button.ts","../src/divider.ts","../src/footer.ts","../src/hero.ts","../src/html.ts","../src/image.ts","../src/logo.ts","../src/socialShared.ts","../src/social.ts","../src/socialGroup.ts","../src/spacer.ts","../src/text.ts","../src/index.ts"],"sourcesContent":["/** 24x24 viewBox 的内置组件图标。集中放,避免散落到各 block 文件。 */\nexport const icons = {\n html: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\"><rect x=\"3.5\" y=\"4\" width=\"17\" height=\"16\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\"/><path d=\"M8 8.5l3 3.5-3 3.5M16 8.5l-3 3.5 3 3.5\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`,\n text: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M5 6h14M5 10h14M5 14h10M5 18h8\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" fill=\"none\"/></svg>`,\n image: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"14\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\"/><circle cx=\"9\" cy=\"10\" r=\"1.5\" fill=\"currentColor\"/><path d=\"M4 18l5-5 4 4 3-3 4 4\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`,\n hero: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"6\" width=\"18\" height=\"12\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\"/><path d=\"M6 14h5M6 17h8\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/></svg>`,\n button: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"4\" fill=\"currentColor\" opacity=\"0.75\"/></svg>`,\n divider: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M3 12h18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/></svg>`,\n spacer: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M5 8h14M5 16h14\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/><path d=\"M12 9v6\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/><path d=\"M9 12l3-3 3 3M9 12l3 3 3-3\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\" stroke-linejoin=\"round\"/></svg>`,\n logo: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M5 18V6l7 6 7-6v12\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\" stroke-linejoin=\"round\"/></svg>`,\n social: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><circle cx=\"6\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/><circle cx=\"12\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/><circle cx=\"18\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/></svg>`,\n footer: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/><path d=\"M5 18h14\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/></svg>`,\n socialGroup: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\"><rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.5\"/><circle cx=\"8\" cy=\"12\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.4\"/><circle cx=\"12\" cy=\"12\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.4\"/><circle cx=\"16\" cy=\"12\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.4\"/></svg>`,\n};\n","import { defineBlock, blockButtonWidthCss } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface ButtonProps {\n text: string;\n href: string;\n backgroundColor: string;\n color: string;\n borderRadius: number;\n align: 'left' | 'center' | 'right';\n /** 留空或 auto 为自适应;可填 200px、80% 等 */\n width: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n innerPaddingV: number;\n innerPaddingH: number;\n fontSize: string;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const buttonBlock = defineBlock<ButtonProps>({\n type: 'button',\n name: '按钮',\n category: 'content',\n icon: icons.button,\n defaultProps: {\n text: '立即查看',\n href: 'https://example.com',\n backgroundColor: '#4f46e5',\n color: '#ffffff',\n borderRadius: 6,\n align: 'center',\n width: '',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n innerPaddingV: 12,\n innerPaddingH: 24,\n fontSize: '14px',\n },\n schema: [\n { key: 'text', label: '文字', type: 'text' },\n { key: 'href', label: '链接', type: 'url' },\n { key: 'backgroundColor', label: '背景色', type: 'color' },\n { key: 'color', label: '文字颜色', type: 'color' },\n { key: 'borderRadius', label: '圆角 (px)', type: 'number', min: 0, max: 40 },\n { key: 'fontSize', label: '字号', type: 'text' },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n {\n key: 'width',\n label: '宽度',\n type: 'text',\n placeholder: '留空=自适应,如 280px、100%',\n help: '支持纯数字(按 px)、带 px 或百分比',\n },\n { key: 'innerPaddingV', label: '按钮内上下边距', type: 'number', min: 0, max: 40 },\n { key: 'innerPaddingH', label: '按钮内左右边距', type: 'number', min: 0, max: 60 },\n { key: 'paddingTop', label: '外边距', type: 'spacing' },\n ],\n inlineEditable: {\n selector: '.sm-button-text',\n mode: 'plain',\n multiline: false,\n propKey: 'text',\n placeholder: '按钮文字',\n },\n toMjml: (p) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const innerPadding = `${p.innerPaddingV}px ${p.innerPaddingH}px`;\n const bw = blockButtonWidthCss(p.width);\n const widthAttr = bw ? ` width=\"${escapeAttr(bw)}\"` : '';\n return `<mj-button href=\"${escapeAttr(p.href)}\" background-color=\"${escapeAttr(\n p.backgroundColor,\n )}\" color=\"${escapeAttr(p.color)}\" border-radius=\"${p.borderRadius}px\" font-size=\"${escapeAttr(\n p.fontSize,\n )}\" align=\"${p.align}\" padding=\"${padding}\" inner-padding=\"${innerPadding}\"${widthAttr}>${escapeAttr(\n p.text,\n )}</mj-button>`;\n },\n renderPreview: (p) => {\n const bw = blockButtonWidthCss(p.width);\n const wst = bw ? `width:${bw};max-width:100%;box-sizing:border-box;` : '';\n /* 画布对 .sm-canvas a 设置了带 !important 的链接色,文字颜色必须写在子节点上才能生效 */\n return `<div style=\"padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;text-align:${p.align};\">\n <a href=\"${escapeAttr(p.href)}\" style=\"display:inline-block;background:${\n p.backgroundColor\n };border-radius:${p.borderRadius}px;padding:${p.innerPaddingV}px ${\n p.innerPaddingH\n }px;text-decoration:none;font-size:${p.fontSize};line-height:1.2;${wst}\"><span class=\"sm-button-text\" style=\"color:${\n p.color\n }\">${escapeAttr(p.text)}</span></a>\n </div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface DividerProps {\n color: string;\n width: string;\n thickness: number;\n paddingTop: number;\n paddingBottom: number;\n}\n\nconst esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const dividerBlock = defineBlock<DividerProps>({\n type: 'divider',\n name: '分隔线',\n category: 'content',\n icon: icons.divider,\n defaultProps: {\n color: '#e6e8ec',\n width: '100%',\n thickness: 1,\n paddingTop: 8,\n paddingBottom: 8,\n },\n schema: [\n { key: 'color', label: '颜色', type: 'color' },\n { key: 'width', label: '宽度 (% 或 px)', type: 'text' },\n { key: 'thickness', label: '粗细 (px)', type: 'number', min: 1, max: 10 },\n { key: 'paddingTop', label: '上边距', type: 'number', min: 0, max: 80 },\n { key: 'paddingBottom', label: '下边距', type: 'number', min: 0, max: 80 },\n ],\n toMjml: (p) =>\n `<mj-divider border-color=\"${esc(p.color)}\" border-width=\"${p.thickness}px\" width=\"${esc(\n p.width,\n )}\" padding=\"${p.paddingTop}px 0px ${p.paddingBottom}px 0px\" />`,\n renderPreview: (p) =>\n `<div style=\"padding:${p.paddingTop}px 0 ${p.paddingBottom}px 0;\"><div style=\"border-top:${p.thickness}px solid ${p.color};width:${p.width};margin:0 auto;\"></div></div>`,\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface FooterProps {\n companyName: string;\n address: string;\n unsubscribeText: string;\n unsubscribeHref: string;\n textColor: string;\n}\n\nconst esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const footerBlock = defineBlock<FooterProps>({\n type: 'custom:footer',\n name: '页脚',\n category: 'custom',\n icon: icons.footer,\n defaultProps: {\n companyName: '你的公司',\n address: '上海市某区某路某号',\n unsubscribeText: '退订邮件',\n unsubscribeHref: '{{unsubscribeUrl}}',\n textColor: '#9aa0a6',\n },\n schema: [\n { key: 'companyName', label: '公司名称', type: 'text' },\n { key: 'address', label: '地址', type: 'text' },\n { key: 'unsubscribeText', label: '退订文案', type: 'text' },\n { key: 'unsubscribeHref', label: '退订链接', type: 'url' },\n { key: 'textColor', label: '文字颜色', type: 'color' },\n ],\n toMjml: (p) => {\n return `<mj-text align=\"center\" color=\"${esc(p.textColor)}\" font-size=\"12px\" line-height=\"1.6\" padding=\"8px 0px 8px 0px\">\n ${esc(p.companyName)}<br />\n ${esc(p.address)}<br />\n <a href=\"${esc(p.unsubscribeHref)}\" style=\"color:${esc(p.textColor)};\">${esc(p.unsubscribeText)}</a>\n</mj-text>`;\n },\n renderPreview: (p) => {\n return `<div style=\"padding:8px 0;text-align:center;font-size:12px;line-height:1.6;color:${p.textColor};\">\n ${esc(p.companyName)}<br/>\n ${esc(p.address)}<br/>\n <a href=\"${esc(p.unsubscribeHref)}\" style=\"color:${p.textColor};\">${esc(p.unsubscribeText)}</a>\n </div>`;\n },\n});\n","import { defineBlock, docContentWidthCss } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface HeroProps {\n backgroundUrl: string;\n backgroundColor: string;\n height: number;\n content: string;\n textAlign: 'left' | 'center' | 'right';\n textColor: string;\n verticalAlign: 'top' | 'middle' | 'bottom';\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const heroBlock = defineBlock<HeroProps>({\n type: 'hero',\n name: 'Hero 大图',\n category: 'content',\n icon: icons.hero,\n defaultProps: {\n backgroundUrl:\n 'https://placehold.co/600x320/312e81/c4b5fd/png?text=Hero+Background',\n backgroundColor: '#1e1b4b',\n height: 320,\n content:\n '<p style=\"margin:0;font-size:28px;font-weight:700;line-height:1.25;\">主标题落在大图上</p><p style=\"margin:12px 0 0;font-size:16px;font-weight:400;opacity:0.95;line-height:1.5;\">支援变量与 <strong>双击编辑</strong>,与正文组件一致。</p>',\n textAlign: 'center',\n textColor: '#ffffff',\n verticalAlign: 'middle',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n { key: 'backgroundUrl', label: '背景图', type: 'image' },\n { key: 'backgroundColor', label: '背景占位色', type: 'color', help: '图片加载失败时的底色' },\n { key: 'height', label: '区域高度 (px)', type: 'number', min: 120, max: 1200, step: 1 },\n {\n key: 'verticalAlign',\n label: '文字垂直位置',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '靠上', value: 'top' },\n { label: '居中', value: 'middle' },\n { label: '靠下', value: 'bottom' },\n ],\n },\n {\n key: 'textAlign',\n label: '文字水平对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'textColor', label: '文字颜色', type: 'color' },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n {\n key: 'content',\n label: '正文(HTML)',\n type: 'textarea',\n help: '建议在画布内双击编辑;此处供高级修改。',\n },\n ],\n inlineEditable: {\n selector: '.sm-hero-content',\n mode: 'rich',\n multiline: true,\n propKey: 'content',\n placeholder: '编写覆盖在图片上的文案…',\n },\n toMjml: (p, ctx) => {\n const w = docContentWidthCss(ctx.doc.meta.width);\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const h = `${p.height}px`;\n return `<mj-hero\n mode=\"fixed-height\"\n height=\"${h}\"\n background-width=\"${w}\"\n background-height=\"${h}\"\n background-url=\"${escapeAttr(p.backgroundUrl)}\"\n background-color=\"${escapeAttr(p.backgroundColor)}\"\n padding=\"${padding}\"\n vertical-align=\"${p.verticalAlign}\"\n >\n <mj-text\n align=\"${p.textAlign}\"\n color=\"${escapeAttr(p.textColor)}\"\n padding=\"0\"\n >${p.content}</mj-text>\n </mj-hero>`;\n },\n renderPreview: (p, ctx) => {\n const w = docContentWidthCss(ctx.doc.meta.width);\n const flexAlign =\n p.verticalAlign === 'top' ? 'flex-start' : p.verticalAlign === 'bottom' ? 'flex-end' : 'center';\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const url = escapeAttr(p.backgroundUrl);\n return `<div\n style=\"\n box-sizing:border-box;\n width:100%;\n max-width:${w};\n min-height:${p.height}px;\n margin:0 auto;\n background-image:linear-gradient(to bottom,rgba(0,0,0,0.25),rgba(0,0,0,0.35)),url(${url});\n background-size:cover;\n background-position:center;\n background-color:${p.backgroundColor};\n display:flex;\n align-items:${flexAlign};\n justify-content:${p.textAlign === 'right' ? 'flex-end' : p.textAlign === 'center' ? 'center' : 'flex-start'};\n padding:${padding};\n color:${escapeAttr(p.textColor)};\n overflow:hidden;\n border-radius:2px;\n \"\n >\n <div\n class=\"sm-hero-content\"\n style=\"\n width:100%;\n text-align:${p.textAlign};\n color:${escapeAttr(p.textColor)};\n text-shadow:0 1px 2px rgba(0,0,0,0.45);\n \"\n >${p.content}</div>\n </div>`;\n },\n});\n","import { defineBlock, mjRawCellTypographyFromStyles, mjRawEmailTableWrap } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface HtmlBlockProps {\n html: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nexport const htmlBlock = defineBlock<HtmlBlockProps>({\n type: 'html',\n name: 'HTML',\n category: 'content',\n icon: icons.html,\n defaultProps: {\n html: '<p style=\"margin:0;\">在此写入任意 HTML,将经 <strong>mj-raw</strong> 原样输出到邮件。支持变量 {{user.name}}</p>',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'html',\n label: 'HTML',\n type: 'textarea',\n help: '插入 MJML 的 mj-raw。邮件客户端常会过滤脚本与不支持的标签。',\n },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n ],\n inlineEditable: {\n selector: '.sm-html-content',\n mode: 'html',\n multiline: true,\n propKey: 'html',\n placeholder: '输入 HTML…',\n },\n toMjml: (p, ctx) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n return mjRawEmailTableWrap(padding, p.html, mjRawCellTypographyFromStyles(ctx.doc.styles));\n },\n renderPreview: (p) => {\n const pad = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n return `<div class=\"sm-html-content\" style=\"padding:${pad};min-height:1em;\">${p.html}</div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface ImageProps {\n src: string;\n alt: string;\n href: string;\n width: number;\n /** 0 表示不限制高度,按原图比例自适应(推荐邮件场景) */\n height: number;\n align: 'left' | 'center' | 'right';\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const imageBlock = defineBlock<ImageProps>({\n type: 'image',\n name: '图片',\n category: 'content',\n icon: icons.image,\n defaultProps: {\n src: 'https://placehold.co/600x240/EEF2FF/4F46E5/png?text=600x240',\n alt: '',\n href: '',\n width: 480,\n height: 0,\n align: 'center',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n { key: 'src', label: '图片地址', type: 'image' },\n { key: 'alt', label: '替代文本', type: 'text', placeholder: '图片描述' },\n { key: 'href', label: '点击跳转', type: 'url', placeholder: 'https://...' },\n { key: 'width', label: '宽度 (px)', type: 'number', min: 40, max: 600 },\n {\n key: 'height',\n label: '高度 (px)(0 为自适应)',\n type: 'number',\n min: 0,\n max: 1200,\n help: '0 为自适应高度;填写固定值时画布与 MJML 会限制显示高度(预览可用 object-fit: cover)',\n },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n ],\n toMjml: (p) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const href = p.href ? ` href=\"${escapeAttr(p.href)}\"` : '';\n const alt = ` alt=\"${escapeAttr(p.alt || '')}\"`;\n const h = p.height != null && p.height > 0 ? ` height=\"${p.height}px\"` : '';\n return `<mj-image src=\"${escapeAttr(p.src)}\"${alt}${href} width=\"${p.width}px\"${h} align=\"${p.align}\" padding=\"${padding}\" />`;\n },\n renderPreview: (p) => {\n const align = p.align === 'center' ? 'margin:0 auto;' : p.align === 'right' ? 'margin-left:auto;' : '';\n const fixedH = p.height != null && p.height > 0 ? p.height : 0;\n const sizeStyle =\n fixedH > 0\n ? `width:${p.width}px;height:${fixedH}px;object-fit:cover;object-position:center;`\n : `width:${p.width}px;height:auto;`;\n return `<div style=\"padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;text-align:${p.align};\"><img src=\"${escapeAttr(\n p.src,\n )}\" alt=\"${escapeAttr(p.alt)}\" style=\"display:block;${align}max-width:100%;${sizeStyle}border:0;outline:none;\" /></div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\n/** 公司 Logo —— 一个语义化的\"图片+链接\"封装,便于运营快速放置品牌资产。 */\ninterface LogoProps {\n src: string;\n href: string;\n width: number;\n align: 'left' | 'center' | 'right';\n}\n\nconst esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const logoBlock = defineBlock<LogoProps>({\n type: 'custom:logo',\n name: '公司 Logo',\n category: 'custom',\n icon: icons.logo,\n defaultProps: {\n src: 'https://placehold.co/240x60/1f2328/ffffff/png?text=YOUR+LOGO',\n href: 'https://example.com',\n width: 160,\n align: 'center',\n },\n schema: [\n { key: 'src', label: 'Logo 图片', type: 'image' },\n { key: 'href', label: '官网链接', type: 'url' },\n { key: 'width', label: '宽度 (px)', type: 'number', min: 60, max: 400 },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n ],\n toMjml: (p) =>\n `<mj-image src=\"${esc(p.src)}\" href=\"${esc(p.href)}\" width=\"${p.width}px\" align=\"${p.align}\" alt=\"logo\" padding=\"8px 0px 8px 0px\" />`,\n renderPreview: (p) => {\n const m =\n p.align === 'center' ? 'margin:0 auto;' : p.align === 'right' ? 'margin-left:auto;' : '';\n return `<div style=\"padding:8px 0;text-align:${p.align};\"><img src=\"${esc(\n p.src,\n )}\" alt=\"logo\" style=\"display:block;${m}width:${p.width}px;max-width:100%;height:auto;\" /></div>`;\n },\n});\n","import { normalizeFontWeightStep } from '@simple-mail/core';\n\n/** 生成 mj-social-element 的 name 属性(与 MJML 内置图标对齐;未知平台退化为 web)。 */\nexport function mjSocialElementName(network: string): string {\n const n = network.trim();\n if (n === 'ig') return 'instagram';\n if (n === 'rabbit' || n === 'tiktok' || n === 'reddit') return 'web';\n return n;\n}\n\n/** 业务示例:固定海外/垂类五平台(与 custom:social 块配套)。 */\nexport const BIZ_SOCIAL_NETWORK_OPTIONS: { label: string; value: string }[] = [\n { label: 'X', value: 'x' },\n { label: 'Rabbit', value: 'rabbit' },\n { label: 'Facebook', value: 'facebook' },\n { label: 'TikTok', value: 'tiktok' },\n { label: 'Instagram', value: 'ig' },\n];\n\n/** 社交平台与 MJML mj-social-element 的 name 对齐(含常用内置名)。 */\nexport const SOCIAL_NETWORK_OPTIONS: { label: string; value: string }[] = [\n { label: '微信', value: 'wechat' },\n { label: '微博', value: 'weibo' },\n { label: 'X', value: 'x' },\n { label: 'LinkedIn', value: 'linkedin' },\n { label: 'GitHub', value: 'github' },\n { label: 'Facebook', value: 'facebook' },\n { label: 'Instagram', value: 'instagram' },\n { label: 'YouTube', value: 'youtube' },\n { label: 'Reddit', value: 'reddit' },\n { label: '网页', value: 'web' },\n];\n\nconst NETWORK_META: Record<string, { color: string; preview: string }> = {\n wechat: { color: '#1AAD19', preview: '信' },\n weibo: { color: '#E6162D', preview: '微' },\n x: { color: '#000000', preview: 'X' },\n linkedin: { color: '#0A66C2', preview: 'in' },\n github: { color: '#181717', preview: 'GH' },\n facebook: { color: '#1877F2', preview: 'f' },\n instagram: { color: '#E4405F', preview: '◎' },\n ig: { color: '#E4405F', preview: '◎' },\n youtube: { color: '#FF0000', preview: '▶' },\n reddit: { color: '#FF4500', preview: 'r' },\n tiktok: { color: '#000000', preview: '♪' },\n rabbit: { color: '#FF2442', preview: 'R' },\n website: { color: '#6b7280', preview: '◇' },\n web: { color: '#6b7280', preview: '◇' },\n};\n\nexport const escAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\n/** mj-social-element 体内文本转义(非属性) */\nexport const escMjmlText = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\nexport interface SocialLinkItem {\n network: string;\n href: string;\n /** 图标旁文字,对应 mj-social-element 子内容 */\n label?: string;\n /** 自定义图标 URL,对应 mj-social-element src */\n iconSrc?: string;\n /** 图标区域背景色;未设则用平台预设 */\n backgroundColor?: string;\n}\n\n/** 社交组块级:所有带标签的链接共用同一套标签文字样式 */\nexport interface SocialGroupLabelStyle {\n labelFontSize: number;\n labelFontWeight: string;\n labelColor: string;\n}\n\nexport function socialMeta(network: string): { color: string; preview: string } {\n return NETWORK_META[network] ?? { color: '#6b7280', preview: '·' };\n}\n\nexport function paddingQuad(p: {\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}): string {\n return `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n}\n\n/** mj-social `border-radius`:0 直角;≥999 或 ≥图标半边 → 圆形裁切(999px) */\nexport function socialIconBorderRadiusMjml(iconSize: number, radiusPx: unknown): string {\n const size = Math.max(1, Number(iconSize) || 28);\n const r = Number(radiusPx);\n if (!Number.isFinite(r) || r <= 0) return '0px';\n const half = size / 2;\n if (r >= 999 || r >= half) return '999px';\n return `${Math.min(r, size)}px`;\n}\n\n/** 画布预览用图标圆角 CSS(与 {@link socialIconBorderRadiusMjml} 语义一致) */\nexport function socialIconBorderRadiusCss(iconSize: number, radiusPx: unknown): string {\n const size = Math.max(1, Number(iconSize) || 28);\n const r = Number(radiusPx);\n if (!Number.isFinite(r) || r <= 0) return '0';\n const half = size / 2;\n if (r >= 999 || r >= half) return '50%';\n return `${Math.min(r, size)}px`;\n}\n\n/** mj-social `inner-padding`,控制图标之间的可视间距 */\nexport function socialIconSpacingPx(spacing: unknown, fallback = 10): number {\n const n = Number(spacing);\n if (!Number.isFinite(n) || n < 0) return fallback;\n return Math.min(64, Math.round(n));\n}\n\nexport function flexJustifyFromAlign(align: 'left' | 'center' | 'right'): string {\n if (align === 'right') return 'flex-end';\n if (align === 'left') return 'flex-start';\n return 'center';\n}\n\nexport function mjSocialElementsLines(\n links: SocialLinkItem[],\n labelStyle: SocialGroupLabelStyle,\n): string {\n const fontSizeRaw = labelStyle.labelFontSize > 0 ? labelStyle.labelFontSize : 13;\n const fontSize = Math.max(8, Math.min(48, fontSizeRaw));\n const fontWeight = normalizeFontWeightStep(labelStyle.labelFontWeight);\n const textColor = labelStyle.labelColor?.trim() || '#333333';\n const fwEsc = escAttr(fontWeight);\n return links\n .map((l) => {\n const meta = socialMeta(l.network);\n const bgColor = l.backgroundColor?.trim() || meta.color;\n const attrs = [\n `name=\"${escAttr(mjSocialElementName(l.network))}\"`,\n `href=\"${escAttr(l.href)}\"`,\n `background-color=\"${escAttr(bgColor)}\"`,\n `color=\"${escAttr(textColor)}\"`,\n `font-size=\"${fontSize}px\"`,\n `font-weight=\"${fwEsc}\"`,\n ];\n const attrStr = attrs.join(' ');\n const src = l.iconSrc?.trim();\n const withSrc = src ? `${attrStr} src=\"${escAttr(src)}\"` : attrStr;\n const label = l.label?.trim() ?? '';\n if (!label) {\n return ` <mj-social-element ${withSrc} />`;\n }\n return ` <mj-social-element ${withSrc}>\\n ${escMjmlText(label)}\\n </mj-social-element>`;\n })\n .join('\\n');\n}\n","import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';\nimport { icons } from './icons';\nimport {\n BIZ_SOCIAL_NETWORK_OPTIONS,\n escAttr,\n flexJustifyFromAlign,\n mjSocialElementsLines,\n paddingQuad,\n socialIconBorderRadiusCss,\n socialIconBorderRadiusMjml,\n socialIconSpacingPx,\n socialMeta,\n type SocialLinkItem,\n} from './socialShared';\n\n/** 与社交组一致,仅平台选项收窄为业务五件套 */\ninterface SocialBizProps {\n elements: SocialLinkItem[];\n align: 'left' | 'center' | 'right';\n iconSize: number;\n iconBorderRadius: number;\n iconSpacing: number;\n labelFontSize: number;\n labelFontWeight: string;\n labelColor: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n /** 旧版自定义块:`links` + textarea,仅用于兼容读入 */\n links?: { network: string; href: string }[];\n}\n\nconst DEFAULT_BIZ_ELEMENTS: SocialLinkItem[] = [\n { network: 'x', href: 'https://x.com/' },\n { network: 'rabbit', href: 'https://example.com' },\n { network: 'facebook', href: 'https://facebook.com/' },\n { network: 'tiktok', href: 'https://www.tiktok.com/' },\n { network: 'ig', href: 'https://instagram.com/' },\n];\n\nfunction normalizeElements(p: SocialBizProps): SocialLinkItem[] {\n if (p.elements?.length) return p.elements;\n const legacy = p.links;\n if (Array.isArray(legacy) && legacy.length)\n return legacy.map((l) => ({\n network: String(l.network ?? 'web'),\n href: String(l.href ?? ''),\n }));\n return DEFAULT_BIZ_ELEMENTS;\n}\n\nexport const socialBlock = defineBlock<SocialBizProps>({\n type: 'custom:social',\n name: '社交链接',\n category: 'custom',\n icon: icons.social,\n defaultProps: {\n elements: DEFAULT_BIZ_ELEMENTS,\n align: 'center',\n iconSize: 28,\n iconBorderRadius: 999,\n iconSpacing: 10,\n labelFontSize: 13,\n labelFontWeight: '400',\n labelColor: '#333333',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'elements',\n label: '社交链接',\n type: 'socialLinkList',\n options: BIZ_SOCIAL_NETWORK_OPTIONS,\n help: '平台:X、Rabbit、Facebook、TikTok、Instagram (ig)。可填标签、自定义图标 URL。MJML 侧 Rabbit/TikTok 使用 web 占位图标,需要品牌图时请填「图标 URL」。',\n },\n {\n key: 'labelFontSize',\n label: '标签字号 (px)',\n type: 'number',\n min: 8,\n max: 48,\n step: 1,\n },\n {\n key: 'labelFontWeight',\n label: '标签字重',\n type: 'select',\n selectVariant: 'segmented',\n options: [...FONT_WEIGHT_STEP_OPTIONS],\n },\n { key: 'labelColor', label: '标签颜色', type: 'color' },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'iconSize', label: '图标尺寸 (px)', type: 'number', min: 16, max: 64 },\n {\n key: 'iconBorderRadius',\n label: '图标圆角 (px)',\n type: 'number',\n min: 0,\n max: 999,\n step: 1,\n help: '0 为方形直角;较大值(如 999)为圆形(默认)。',\n },\n {\n key: 'iconSpacing',\n label: '图标间距 (px)',\n type: 'number',\n min: 0,\n max: 64,\n step: 1,\n help: '图标之间的间隔(MJML inner-padding)。',\n },\n { key: 'paddingTop', label: '外边距', type: 'spacing' },\n ],\n toMjml: (p) => {\n const pad = paddingQuad(p);\n const br = socialIconBorderRadiusMjml(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const socAttrs = `align=\"${p.align}\" icon-size=\"${p.iconSize}px\" mode=\"horizontal\" border-radius=\"${br}\" inner-padding=\"${gap}px\" padding=\"${pad}\"`;\n const els = normalizeElements(p).filter((e) => e.href?.trim());\n const labelStyle = {\n labelFontSize: Number(p.labelFontSize ?? 13),\n labelFontWeight: normalizeFontWeightStep(String(p.labelFontWeight ?? '400')),\n labelColor: String(p.labelColor ?? '#333333'),\n };\n const inner = mjSocialElementsLines(els, labelStyle);\n if (!inner.trim()) {\n return `<mj-social ${socAttrs}></mj-social>`;\n }\n return `<mj-social ${socAttrs}>\n${inner}\n</mj-social>`;\n },\n renderPreview: (p) => {\n const fsRaw = p.labelFontSize != null && p.labelFontSize > 0 ? p.labelFontSize : 13;\n const fs = Math.max(8, Math.min(48, fsRaw));\n const fw = normalizeFontWeightStep(p.labelFontWeight);\n const textColor = p.labelColor?.trim() || '#333333';\n const radiusCss = socialIconBorderRadiusCss(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const jc = flexJustifyFromAlign(p.align);\n const items = normalizeElements(p)\n .filter((l) => l.href?.trim())\n .map((l) => {\n const meta = socialMeta(l.network);\n const bg = l.backgroundColor?.trim() || meta.color;\n const label = l.label?.trim() ?? '';\n const iconSrc = l.iconSrc?.trim();\n const iconHtml = iconSrc\n ? `<img src=\"${escAttr(iconSrc)}\" alt=\"\" style=\"width:${p.iconSize}px;height:${p.iconSize}px;object-fit:cover;border-radius:${radiusCss};flex-shrink:0;\" />`\n : `<span style=\"display:inline-flex;width:${p.iconSize}px;height:${p.iconSize}px;border-radius:${radiusCss};background:${bg};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(\n p.iconSize / 2,\n )}px;font-weight:600;flex-shrink:0;overflow:hidden;\">${meta.preview}</span>`;\n const textHtml = label\n ? `<span style=\"font-size:${fs}px !important;font-weight:${fw};color:${escAttr(\n textColor,\n )} !important;line-height:1.2;\">${escAttr(label)}</span>`\n : '';\n return `<span style=\"display:inline-flex;align-items:center;gap:6px;\"><a href=\"${escAttr(\n l.href,\n )}\" style=\"display:inline-flex;align-items:center;text-decoration:none;line-height:0;\">${iconHtml}</a>${textHtml}</span>`;\n })\n .join('');\n const pad = paddingQuad(p);\n return `<div style=\"display:flex;flex-wrap:wrap;justify-content:${jc};align-items:center;gap:${gap}px;padding:${pad};\">${items || '<span style=\"color:#9ca3af;font-size:12px;\">请填写链接 URL</span>'}</div>`;\n },\n});\n","import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';\nimport { icons } from './icons';\nimport {\n escAttr,\n flexJustifyFromAlign,\n mjSocialElementsLines,\n paddingQuad,\n socialIconBorderRadiusCss,\n socialIconBorderRadiusMjml,\n socialIconSpacingPx,\n socialMeta,\n SOCIAL_NETWORK_OPTIONS,\n type SocialLinkItem,\n} from './socialShared';\n\ninterface SocialGroupProps {\n elements: SocialLinkItem[];\n align: 'left' | 'center' | 'right';\n iconSize: number;\n /** 图标圆角 (px)。0 为方形;≥999 或不少于图标半边时为圆形(默认 999) */\n iconBorderRadius: number;\n /** 图标之间的间距 (px),对应 mj-social inner-padding */\n iconSpacing: number;\n /** 标签文字字号(整组统一) */\n labelFontSize: number;\n labelFontWeight: string;\n labelColor: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nexport const socialGroupBlock = defineBlock<SocialGroupProps>({\n type: 'social-group',\n name: '社交组',\n category: 'content',\n icon: icons.socialGroup,\n defaultProps: {\n elements: [\n { network: 'weibo', href: 'https://weibo.com' },\n { network: 'wechat', href: 'https://example.com' },\n ],\n align: 'center',\n iconSize: 28,\n iconBorderRadius: 999,\n iconSpacing: 10,\n labelFontSize: 13,\n labelFontWeight: '400',\n labelColor: '#333333',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'elements',\n label: '社交链接',\n type: 'socialLinkList',\n options: SOCIAL_NETWORK_OPTIONS,\n help: '每行:平台、链接、可选标签文字、自定义图标 URL、图标背景色。标签的字号/字重/颜色在下方统一设置。',\n },\n {\n key: 'labelFontSize',\n label: '标签字号 (px)',\n type: 'number',\n min: 8,\n max: 48,\n step: 1,\n },\n {\n key: 'labelFontWeight',\n label: '标签字重',\n type: 'select',\n selectVariant: 'segmented',\n options: [...FONT_WEIGHT_STEP_OPTIONS],\n },\n { key: 'labelColor', label: '标签颜色', type: 'color' },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'iconSize', label: '图标尺寸 (px)', type: 'number', min: 16, max: 64 },\n {\n key: 'iconBorderRadius',\n label: '图标圆角 (px)',\n type: 'number',\n min: 0,\n max: 999,\n step: 1,\n help: '0 为方形直角;填较大值(如 999)或与尺寸一半相当时为圆形(默认圆形)。',\n },\n {\n key: 'iconSpacing',\n label: '图标间距 (px)',\n type: 'number',\n min: 0,\n max: 64,\n step: 1,\n help: '每个图标周围的留白,横向即图标之间的间隔(MJML inner-padding)。',\n },\n { key: 'paddingTop', label: '外边距', type: 'spacing' },\n ],\n toMjml: (p) => {\n const pad = paddingQuad(p);\n const br = socialIconBorderRadiusMjml(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const socAttrs = `align=\"${p.align}\" icon-size=\"${p.iconSize}px\" mode=\"horizontal\" border-radius=\"${br}\" inner-padding=\"${gap}px\" padding=\"${pad}\"`;\n const filtered = p.elements.filter((e) => e.href?.trim());\n const labelStyle = {\n labelFontSize: Number(p.labelFontSize ?? 13),\n labelFontWeight: normalizeFontWeightStep(String(p.labelFontWeight ?? '400')),\n labelColor: String(p.labelColor ?? '#333333'),\n };\n const inner = mjSocialElementsLines(filtered, labelStyle);\n if (!inner.trim()) {\n return `<mj-social ${socAttrs}></mj-social>`;\n }\n return `<mj-social ${socAttrs}>\n${inner}\n</mj-social>`;\n },\n renderPreview: (p) => {\n const fsRaw = p.labelFontSize != null && p.labelFontSize > 0 ? p.labelFontSize : 13;\n const fs = Math.max(8, Math.min(48, fsRaw));\n const fw = normalizeFontWeightStep(p.labelFontWeight);\n const textColor = p.labelColor?.trim() || '#333333';\n const radiusCss = socialIconBorderRadiusCss(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const jc = flexJustifyFromAlign(p.align);\n const items = p.elements\n .filter((l) => l.href?.trim())\n .map((l) => {\n const meta = socialMeta(l.network);\n const bg = l.backgroundColor?.trim() || meta.color;\n const label = l.label?.trim() ?? '';\n const iconSrc = l.iconSrc?.trim();\n const iconHtml = iconSrc\n ? `<img src=\"${escAttr(iconSrc)}\" alt=\"\" style=\"width:${p.iconSize}px;height:${p.iconSize}px;object-fit:cover;border-radius:${radiusCss};flex-shrink:0;\" />`\n : `<span style=\"display:inline-flex;width:${p.iconSize}px;height:${p.iconSize}px;border-radius:${radiusCss};background:${bg};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(\n p.iconSize / 2,\n )}px;font-weight:600;flex-shrink:0;overflow:hidden;\">${meta.preview}</span>`;\n const textHtml = label\n ? `<span style=\"font-size:${fs}px !important;font-weight:${fw};color:${escAttr(\n textColor,\n )} !important;line-height:1.2;\">${escAttr(label)}</span>`\n : '';\n return `<span style=\"display:inline-flex;align-items:center;gap:6px;\"><a href=\"${escAttr(\n l.href,\n )}\" style=\"display:inline-flex;align-items:center;text-decoration:none;line-height:0;\">${iconHtml}</a>${textHtml}</span>`;\n })\n .join('');\n const pad = paddingQuad(p);\n return `<div style=\"display:flex;flex-wrap:wrap;justify-content:${jc};align-items:center;gap:${gap}px;padding:${pad};\">${items || '<span style=\"color:#9ca3af;font-size:12px;\">请添加社交链接</span>'}</div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface SpacerProps {\n height: number;\n}\n\nexport const spacerBlock = defineBlock<SpacerProps>({\n type: 'spacer',\n name: '间距',\n category: 'content',\n icon: icons.spacer,\n defaultProps: { height: 24 },\n schema: [{ key: 'height', label: '高度 (px)', type: 'number', min: 1, max: 200 }],\n toMjml: (p) => `<mj-spacer height=\"${p.height}px\" />`,\n renderPreview: (p) => `<div style=\"height:${p.height}px;line-height:${p.height}px;\"></div>`,\n});\n","import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface TextProps {\n content: string;\n align: 'left' | 'center' | 'right';\n color: string;\n fontSize: string;\n fontFamily: string;\n fontWeight: string;\n /** 空字符串:与邮件全局行距(mj-head)一致 */\n lineHeight: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const textBlock = defineBlock<TextProps>({\n type: 'text',\n name: '文本',\n category: 'content',\n icon: icons.text,\n defaultProps: {\n content:\n '<p style=\"margin:0;\">在此处输入文本。<strong>双击</strong>进入编辑模式,<em>选中文字</em>会出现工具条;支持变量 {{user.name}}</p>',\n align: 'left',\n color: '#433f3f',\n fontSize: '16px',\n fontFamily: '',\n fontWeight: '400',\n lineHeight: '',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'align',\n label: '默认对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'color', label: '默认颜色', type: 'color' },\n { key: 'fontSize', label: '默认字号', type: 'text', placeholder: '14px' },\n { key: 'fontFamily', label: '字体', type: 'text', placeholder: '继承全局' },\n {\n key: 'fontWeight',\n label: '字重',\n type: 'select',\n selectVariant: 'segmented',\n options: [...FONT_WEIGHT_STEP_OPTIONS],\n },\n {\n key: 'lineHeight',\n label: '行高',\n type: 'select',\n help: '留空则使用邮件设置里的全局行距',\n options: [\n { label: '继承全局', value: '' },\n { label: '1.0', value: '1' },\n { label: '1.15', value: '1.15' },\n { label: '1.25', value: '1.25' },\n { label: '1.4', value: '1.4' },\n { label: '1.5', value: '1.5' },\n { label: '1.75', value: '1.75' },\n { label: '2.0', value: '2' },\n { label: '22px', value: '22px' },\n { label: '24px', value: '24px' },\n { label: '28px', value: '28px' },\n { label: '32px', value: '32px' },\n ],\n },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n {\n key: 'content',\n label: '内容(HTML,备用)',\n type: 'textarea',\n help: '建议直接在画布双击编辑;这里保留为高级编辑入口。',\n },\n ],\n inlineEditable: {\n selector: '.sm-text-content',\n mode: 'rich',\n multiline: true,\n propKey: 'content',\n placeholder: '输入文本…',\n },\n toMjml: (p) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const ff = p.fontFamily ? ` font-family=\"${escapeAttr(p.fontFamily)}\"` : '';\n const fwN = normalizeFontWeightStep(p.fontWeight);\n const fw = fwN !== '400' ? ` font-weight=\"${escapeAttr(fwN)}\"` : '';\n const lh = String(p.lineHeight ?? '').trim();\n const lhAttr = lh ? ` line-height=\"${escapeAttr(lh)}\"` : '';\n return `<mj-text align=\"${p.align}\" color=\"${escapeAttr(p.color)}\" font-size=\"${escapeAttr(\n p.fontSize,\n )}\"${lhAttr}${ff}${fw} padding=\"${padding}\">${p.content}</mj-text>`;\n },\n renderPreview: (p) => {\n const ff = p.fontFamily ? `font-family:${p.fontFamily};` : '';\n const fwN = normalizeFontWeightStep(p.fontWeight);\n const fw = fwN !== '400' ? `font-weight:${fwN};` : '';\n const lhRaw = String(p.lineHeight ?? '').trim();\n const lh = lhRaw ? `line-height:${lhRaw};` : 'line-height:normal;';\n return `<div class=\"sm-text-content\" style=\"text-align:${p.align};color:${p.color};font-size:${p.fontSize};${lh}${ff}${fw}padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;\">${p.content}</div>`;\n },\n});\n","import type { BlockDefinition } from '@simple-mail/core';\nimport { buttonBlock } from './button';\nimport { dividerBlock } from './divider';\nimport { footerBlock } from './footer';\nimport { heroBlock } from './hero';\nimport { htmlBlock } from './html';\nimport { imageBlock } from './image';\nimport { logoBlock } from './logo';\nimport { socialBlock } from './social';\nimport { socialGroupBlock } from './socialGroup';\nimport { spacerBlock } from './spacer';\nimport { textBlock } from './text';\n\nexport {\n buttonBlock,\n dividerBlock,\n footerBlock,\n heroBlock,\n htmlBlock,\n imageBlock,\n logoBlock,\n socialBlock,\n socialGroupBlock,\n spacerBlock,\n textBlock,\n};\n\n/** 宿主拼装「社交组」类 block 时可复用(mj-social 序列化、侧栏 socialLinkList)。 */\nexport {\n escAttr,\n escMjmlText,\n flexJustifyFromAlign,\n mjSocialElementName,\n mjSocialElementsLines,\n paddingQuad,\n socialIconBorderRadiusCss,\n socialIconBorderRadiusMjml,\n socialIconSpacingPx,\n socialMeta,\n SOCIAL_NETWORK_OPTIONS,\n type SocialGroupLabelStyle,\n type SocialLinkItem,\n} from './socialShared';\n\n/** 内置组件(content 类)。可直接传给 MailEditor.blocks。 */\nexport const builtinBlocks: BlockDefinition<any>[] = [\n textBlock,\n htmlBlock,\n imageBlock,\n socialGroupBlock,\n heroBlock,\n buttonBlock,\n dividerBlock,\n spacerBlock,\n];\n\n/** 业务示例的“自定义”组件。可作为参考或直接使用;正式业务块应由宿主应用注册。 */\nexport const exampleCustomBlocks: BlockDefinition<any>[] = [logoBlock, socialBlock, footerBlock];\n\n/** 全部组件(内置 + 示例自定义)。业务相关块请在使用侧与 `allBlocks` 合并后传入 MailEditor。 */\nexport const allBlocks: BlockDefinition<any>[] = [...builtinBlocks, ...exampleCustomBlocks];\n"],"names":["icons","escapeAttr","s","buttonBlock","defineBlock","p","padding","innerPadding","bw","blockButtonWidthCss","widthAttr","wst","esc","dividerBlock","footerBlock","heroBlock","ctx","w","docContentWidthCss","h","flexAlign","url","htmlBlock","mjRawEmailTableWrap","mjRawCellTypographyFromStyles","imageBlock","href","alt","align","fixedH","sizeStyle","logoBlock","m","mjSocialElementName","network","n","BIZ_SOCIAL_NETWORK_OPTIONS","SOCIAL_NETWORK_OPTIONS","NETWORK_META","escAttr","escMjmlText","socialMeta","paddingQuad","socialIconBorderRadiusMjml","iconSize","radiusPx","size","r","half","socialIconBorderRadiusCss","socialIconSpacingPx","spacing","fallback","flexJustifyFromAlign","mjSocialElementsLines","links","labelStyle","fontSizeRaw","fontSize","fontWeight","normalizeFontWeightStep","textColor","_a","fwEsc","l","meta","bgColor","attrStr","src","_b","withSrc","label","_c","DEFAULT_BIZ_ELEMENTS","normalizeElements","legacy","socialBlock","FONT_WEIGHT_STEP_OPTIONS","pad","br","gap","socAttrs","els","e","inner","fsRaw","fs","fw","radiusCss","jc","items","bg","iconSrc","iconHtml","textHtml","socialGroupBlock","filtered","spacerBlock","textBlock","ff","fwN","lh","lhAttr","lhRaw","builtinBlocks","exampleCustomBlocks","allBlocks"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/icons.ts","../src/button.ts","../src/divider.ts","../src/footer.ts","../src/hero.ts","../src/html.ts","../src/image.ts","../src/logo.ts","../src/socialShared.ts","../src/social.ts","../src/socialGroup.ts","../src/spacer.ts","../src/text.ts","../src/index.ts"],"sourcesContent":["/** 24x24 viewBox 的内置组件图标。集中放,避免散落到各 block 文件。 */\nexport const icons = {\n html: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\"><rect x=\"3.5\" y=\"4\" width=\"17\" height=\"16\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\"/><path d=\"M8 8.5l3 3.5-3 3.5M16 8.5l-3 3.5 3 3.5\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`,\n text: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M5 6h14M5 10h14M5 14h10M5 18h8\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" fill=\"none\"/></svg>`,\n image: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"14\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\"/><circle cx=\"9\" cy=\"10\" r=\"1.5\" fill=\"currentColor\"/><path d=\"M4 18l5-5 4 4 3-3 4 4\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`,\n hero: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"6\" width=\"18\" height=\"12\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\"/><path d=\"M6 14h5M6 17h8\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/></svg>`,\n button: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"4\" fill=\"currentColor\" opacity=\"0.75\"/></svg>`,\n divider: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M3 12h18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/></svg>`,\n spacer: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M5 8h14M5 16h14\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/><path d=\"M12 9v6\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/><path d=\"M9 12l3-3 3 3M9 12l3 3 3-3\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\" stroke-linejoin=\"round\"/></svg>`,\n logo: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M5 18V6l7 6 7-6v12\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\" stroke-linejoin=\"round\"/></svg>`,\n social: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><circle cx=\"6\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/><circle cx=\"12\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/><circle cx=\"18\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/></svg>`,\n footer: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"10\" rx=\"1.5\" stroke=\"currentColor\" stroke-width=\"1.4\" fill=\"none\"/><path d=\"M5 18h14\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"/></svg>`,\n socialGroup: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\"><rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.5\"/><circle cx=\"8\" cy=\"12\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.4\"/><circle cx=\"12\" cy=\"12\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.4\"/><circle cx=\"16\" cy=\"12\" r=\"2\" stroke=\"currentColor\" stroke-width=\"1.4\"/></svg>`,\n};\n","import { defineBlock, blockButtonWidthCss } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface ButtonProps {\n text: string;\n href: string;\n backgroundColor: string;\n color: string;\n borderRadius: number;\n align: 'left' | 'center' | 'right';\n /** 留空或 auto 为自适应;可填 200px、80% 等 */\n width: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n innerPaddingV: number;\n innerPaddingH: number;\n fontSize: string;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const buttonBlock = defineBlock<ButtonProps>({\n type: 'button',\n name: '按钮',\n category: 'content',\n icon: icons.button,\n defaultProps: {\n text: '立即查看',\n href: 'https://example.com',\n backgroundColor: '#4f46e5',\n color: '#ffffff',\n borderRadius: 6,\n align: 'center',\n width: '',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n innerPaddingV: 12,\n innerPaddingH: 24,\n fontSize: '14px',\n },\n schema: [\n { key: 'text', label: '文字', type: 'text' },\n { key: 'href', label: '链接', type: 'url' },\n { key: 'backgroundColor', label: '背景色', type: 'color' },\n { key: 'color', label: '文字颜色', type: 'color' },\n { key: 'borderRadius', label: '圆角 (px)', type: 'number', min: 0, max: 40 },\n { key: 'fontSize', label: '字号', type: 'text' },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n {\n key: 'width',\n label: '宽度',\n type: 'text',\n placeholder: '留空=自适应,如 280px、100%',\n help: '支持纯数字(按 px)、带 px 或百分比',\n },\n { key: 'innerPaddingV', label: '按钮内上下边距', type: 'number', min: 0, max: 40 },\n { key: 'innerPaddingH', label: '按钮内左右边距', type: 'number', min: 0, max: 60 },\n { key: 'paddingTop', label: '外边距', type: 'spacing' },\n ],\n inlineEditable: {\n selector: '.sm-button-text',\n mode: 'plain',\n multiline: false,\n propKey: 'text',\n placeholder: '按钮文字',\n },\n toMjml: (p) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const innerPadding = `${p.innerPaddingV}px ${p.innerPaddingH}px`;\n const bw = blockButtonWidthCss(p.width);\n const widthAttr = bw ? ` width=\"${escapeAttr(bw)}\"` : '';\n return `<mj-button href=\"${escapeAttr(p.href)}\" background-color=\"${escapeAttr(\n p.backgroundColor,\n )}\" color=\"${escapeAttr(p.color)}\" border-radius=\"${p.borderRadius}px\" font-size=\"${escapeAttr(\n p.fontSize,\n )}\" align=\"${p.align}\" padding=\"${padding}\" inner-padding=\"${innerPadding}\"${widthAttr}>${escapeAttr(\n p.text,\n )}</mj-button>`;\n },\n renderPreview: (p) => {\n const bw = blockButtonWidthCss(p.width);\n const wst = bw ? `width:${bw};max-width:100%;box-sizing:border-box;` : '';\n /* 画布对 .sm-canvas a 设置了带 !important 的链接色,文字颜色必须写在子节点上才能生效 */\n return `<div style=\"padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;text-align:${p.align};\">\n <a href=\"${escapeAttr(p.href)}\" style=\"display:inline-block;background:${\n p.backgroundColor\n };border-radius:${p.borderRadius}px;padding:${p.innerPaddingV}px ${\n p.innerPaddingH\n }px;text-decoration:none;font-size:${p.fontSize};line-height:1.2;${wst}\"><span class=\"sm-button-text\" style=\"color:${\n p.color\n }\">${escapeAttr(p.text)}</span></a>\n </div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface DividerProps {\n color: string;\n width: string;\n thickness: number;\n paddingTop: number;\n paddingBottom: number;\n}\n\nconst esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const dividerBlock = defineBlock<DividerProps>({\n type: 'divider',\n name: '分隔线',\n category: 'content',\n icon: icons.divider,\n defaultProps: {\n color: '#e6e8ec',\n width: '100%',\n thickness: 1,\n paddingTop: 8,\n paddingBottom: 8,\n },\n schema: [\n { key: 'color', label: '颜色', type: 'color' },\n { key: 'width', label: '宽度 (% 或 px)', type: 'text' },\n { key: 'thickness', label: '粗细 (px)', type: 'number', min: 1, max: 10 },\n { key: 'paddingTop', label: '上边距', type: 'number', min: 0, max: 80 },\n { key: 'paddingBottom', label: '下边距', type: 'number', min: 0, max: 80 },\n ],\n toMjml: (p) =>\n `<mj-divider border-color=\"${esc(p.color)}\" border-width=\"${p.thickness}px\" width=\"${esc(\n p.width,\n )}\" padding=\"${p.paddingTop}px 0px ${p.paddingBottom}px 0px\" />`,\n renderPreview: (p) =>\n `<div style=\"padding:${p.paddingTop}px 0 ${p.paddingBottom}px 0;\"><div style=\"border-top:${p.thickness}px solid ${p.color};width:${p.width};margin:0 auto;\"></div></div>`,\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface FooterProps {\n companyName: string;\n address: string;\n unsubscribeText: string;\n unsubscribeHref: string;\n textColor: string;\n}\n\nconst esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const footerBlock = defineBlock<FooterProps>({\n type: 'custom:footer',\n name: '页脚',\n category: 'custom',\n icon: icons.footer,\n defaultProps: {\n companyName: '你的公司',\n address: '上海市某区某路某号',\n unsubscribeText: '退订邮件',\n unsubscribeHref: '{{unsubscribeUrl}}',\n textColor: '#9aa0a6',\n },\n schema: [\n { key: 'companyName', label: '公司名称', type: 'text' },\n { key: 'address', label: '地址', type: 'text' },\n { key: 'unsubscribeText', label: '退订文案', type: 'text' },\n { key: 'unsubscribeHref', label: '退订链接', type: 'url' },\n { key: 'textColor', label: '文字颜色', type: 'color' },\n ],\n toMjml: (p) => {\n return `<mj-text align=\"center\" color=\"${esc(p.textColor)}\" font-size=\"12px\" line-height=\"1.6\" padding=\"8px 0px 8px 0px\">\n ${esc(p.companyName)}<br />\n ${esc(p.address)}<br />\n <a href=\"${esc(p.unsubscribeHref)}\" style=\"color:${esc(p.textColor)};\">${esc(p.unsubscribeText)}</a>\n</mj-text>`;\n },\n renderPreview: (p) => {\n return `<div style=\"padding:8px 0;text-align:center;font-size:12px;line-height:1.6;color:${p.textColor};\">\n ${esc(p.companyName)}<br/>\n ${esc(p.address)}<br/>\n <a href=\"${esc(p.unsubscribeHref)}\" style=\"color:${p.textColor};\">${esc(p.unsubscribeText)}</a>\n </div>`;\n },\n});\n","import { defineBlock, docContentWidthCss } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface HeroProps {\n backgroundUrl: string;\n backgroundColor: string;\n height: number;\n content: string;\n textAlign: 'left' | 'center' | 'right';\n textColor: string;\n verticalAlign: 'top' | 'middle' | 'bottom';\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const heroBlock = defineBlock<HeroProps>({\n type: 'hero',\n name: 'Hero 大图',\n category: 'content',\n icon: icons.hero,\n defaultProps: {\n backgroundUrl:\n 'https://placehold.co/600x320/312e81/c4b5fd/png?text=Hero+Background',\n backgroundColor: '#1e1b4b',\n height: 320,\n content:\n '<p style=\"margin:0;font-size:28px;font-weight:700;line-height:1.25;\">主标题落在大图上</p><p style=\"margin:12px 0 0;font-size:16px;font-weight:400;opacity:0.95;line-height:1.5;\">支援变量与 <strong>双击编辑</strong>,与正文组件一致。</p>',\n textAlign: 'center',\n textColor: '#ffffff',\n verticalAlign: 'middle',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n { key: 'backgroundUrl', label: '背景图', type: 'image' },\n { key: 'backgroundColor', label: '背景占位色', type: 'color', help: '图片加载失败时的底色' },\n { key: 'height', label: '区域高度 (px)', type: 'number', min: 120, max: 1200, step: 1 },\n {\n key: 'verticalAlign',\n label: '文字垂直位置',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '靠上', value: 'top' },\n { label: '居中', value: 'middle' },\n { label: '靠下', value: 'bottom' },\n ],\n },\n {\n key: 'textAlign',\n label: '文字水平对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'textColor', label: '文字颜色', type: 'color' },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n {\n key: 'content',\n label: '正文(HTML)',\n type: 'textarea',\n help: '建议在画布内双击编辑;此处供高级修改。',\n },\n ],\n inlineEditable: {\n selector: '.sm-hero-content',\n mode: 'rich',\n multiline: true,\n propKey: 'content',\n placeholder: '编写覆盖在图片上的文案…',\n },\n toMjml: (p, ctx) => {\n const w = docContentWidthCss(ctx.doc.meta.width);\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const h = `${p.height}px`;\n return `<mj-hero\n mode=\"fixed-height\"\n height=\"${h}\"\n background-width=\"${w}\"\n background-height=\"${h}\"\n background-url=\"${escapeAttr(p.backgroundUrl)}\"\n background-color=\"${escapeAttr(p.backgroundColor)}\"\n padding=\"${padding}\"\n vertical-align=\"${p.verticalAlign}\"\n >\n <mj-text\n align=\"${p.textAlign}\"\n color=\"${escapeAttr(p.textColor)}\"\n padding=\"0\"\n >${p.content}</mj-text>\n </mj-hero>`;\n },\n renderPreview: (p, ctx) => {\n const w = docContentWidthCss(ctx.doc.meta.width);\n const flexAlign =\n p.verticalAlign === 'top' ? 'flex-start' : p.verticalAlign === 'bottom' ? 'flex-end' : 'center';\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const url = escapeAttr(p.backgroundUrl);\n return `<div\n style=\"\n box-sizing:border-box;\n width:100%;\n max-width:${w};\n min-height:${p.height}px;\n margin:0 auto;\n background-image:linear-gradient(to bottom,rgba(0,0,0,0.25),rgba(0,0,0,0.35)),url(${url});\n background-size:cover;\n background-position:center;\n background-color:${p.backgroundColor};\n display:flex;\n align-items:${flexAlign};\n justify-content:${p.textAlign === 'right' ? 'flex-end' : p.textAlign === 'center' ? 'center' : 'flex-start'};\n padding:${padding};\n color:${escapeAttr(p.textColor)};\n overflow:hidden;\n border-radius:2px;\n \"\n >\n <div\n class=\"sm-hero-content\"\n style=\"\n width:100%;\n text-align:${p.textAlign};\n color:${escapeAttr(p.textColor)};\n text-shadow:0 1px 2px rgba(0,0,0,0.45);\n \"\n >${p.content}</div>\n </div>`;\n },\n});\n","import { defineBlock, mjRawCellTypographyFromStyles, mjRawEmailTableWrap } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface HtmlBlockProps {\n html: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nexport const htmlBlock = defineBlock<HtmlBlockProps>({\n type: 'html',\n name: 'HTML',\n category: 'content',\n icon: icons.html,\n defaultProps: {\n html: '<p style=\"margin:0;\">在此写入任意 HTML,将经 <strong>mj-raw</strong> 原样输出到邮件。支持变量 {{user.name}}</p>',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'html',\n label: 'HTML',\n type: 'textarea',\n help: '插入 MJML 的 mj-raw。邮件客户端常会过滤脚本与不支持的标签。',\n },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n ],\n inlineEditable: {\n selector: '.sm-html-content',\n mode: 'html',\n multiline: true,\n propKey: 'html',\n placeholder: '输入 HTML…',\n },\n toMjml: (p, ctx) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n return mjRawEmailTableWrap(padding, p.html, mjRawCellTypographyFromStyles(ctx.doc.styles));\n },\n renderPreview: (p) => {\n const pad = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n return `<div class=\"sm-html-content\" style=\"padding:${pad};min-height:1em;\">${p.html}</div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface ImageProps {\n src: string;\n alt: string;\n href: string;\n width: number;\n /** 0 表示不限制高度,按原图比例自适应(推荐邮件场景) */\n height: number;\n align: 'left' | 'center' | 'right';\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const imageBlock = defineBlock<ImageProps>({\n type: 'image',\n name: '图片',\n category: 'content',\n icon: icons.image,\n defaultProps: {\n src: 'https://placehold.co/600x240/EEF2FF/4F46E5/png?text=600x240',\n alt: '',\n href: '',\n width: 480,\n height: 0,\n align: 'center',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n { key: 'src', label: '图片地址', type: 'image' },\n { key: 'alt', label: '替代文本', type: 'text', placeholder: '图片描述' },\n { key: 'href', label: '点击跳转', type: 'url', placeholder: 'https://...' },\n { key: 'width', label: '宽度 (px)', type: 'number', min: 40, max: 600 },\n {\n key: 'height',\n label: '高度 (px)(0 为自适应)',\n type: 'number',\n min: 0,\n max: 1200,\n help: '0 为自适应高度;填写固定值时画布与 MJML 会限制显示高度(预览可用 object-fit: cover)',\n },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n ],\n toMjml: (p) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const href = p.href ? ` href=\"${escapeAttr(p.href)}\"` : '';\n const alt = ` alt=\"${escapeAttr(p.alt || '')}\"`;\n const h = p.height != null && p.height > 0 ? ` height=\"${p.height}px\"` : '';\n return `<mj-image src=\"${escapeAttr(p.src)}\"${alt}${href} width=\"${p.width}px\"${h} align=\"${p.align}\" padding=\"${padding}\" />`;\n },\n renderPreview: (p) => {\n const align = p.align === 'center' ? 'margin:0 auto;' : p.align === 'right' ? 'margin-left:auto;' : '';\n const fixedH = p.height != null && p.height > 0 ? p.height : 0;\n const sizeStyle =\n fixedH > 0\n ? `width:${p.width}px;height:${fixedH}px;object-fit:cover;object-position:center;`\n : `width:${p.width}px;height:auto;`;\n return `<div style=\"padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;text-align:${p.align};\"><img src=\"${escapeAttr(\n p.src,\n )}\" alt=\"${escapeAttr(p.alt)}\" style=\"display:block;${align}max-width:100%;${sizeStyle}border:0;outline:none;\" /></div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\n/** 公司 Logo —— 一个语义化的\"图片+链接\"封装,便于运营快速放置品牌资产。 */\ninterface LogoProps {\n src: string;\n href: string;\n width: number;\n align: 'left' | 'center' | 'right';\n}\n\nconst esc = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const logoBlock = defineBlock<LogoProps>({\n type: 'custom:logo',\n name: '公司 Logo',\n category: 'custom',\n icon: icons.logo,\n defaultProps: {\n src: 'https://placehold.co/240x60/1f2328/ffffff/png?text=YOUR+LOGO',\n href: 'https://example.com',\n width: 160,\n align: 'center',\n },\n schema: [\n { key: 'src', label: 'Logo 图片', type: 'image' },\n { key: 'href', label: '官网链接', type: 'url' },\n { key: 'width', label: '宽度 (px)', type: 'number', min: 60, max: 400 },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n ],\n toMjml: (p) =>\n `<mj-image src=\"${esc(p.src)}\" href=\"${esc(p.href)}\" width=\"${p.width}px\" align=\"${p.align}\" alt=\"logo\" padding=\"8px 0px 8px 0px\" />`,\n renderPreview: (p) => {\n const m =\n p.align === 'center' ? 'margin:0 auto;' : p.align === 'right' ? 'margin-left:auto;' : '';\n return `<div style=\"padding:8px 0;text-align:${p.align};\"><img src=\"${esc(\n p.src,\n )}\" alt=\"logo\" style=\"display:block;${m}width:${p.width}px;max-width:100%;height:auto;\" /></div>`;\n },\n});\n","import { normalizeFontWeightStep } from '@simple-mail/core';\n\n/** 生成 mj-social-element 的 name 属性(与 MJML 内置图标对齐;未知平台退化为 web)。 */\nexport function mjSocialElementName(network: string): string {\n const n = network.trim();\n if (n === 'ig') return 'instagram';\n if (n === 'rabbit' || n === 'tiktok' || n === 'reddit') return 'web';\n return n;\n}\n\n/** 业务示例:固定海外/垂类五平台(与 custom:social 块配套)。 */\nexport const BIZ_SOCIAL_NETWORK_OPTIONS: { label: string; value: string }[] = [\n { label: 'X', value: 'x' },\n { label: 'Rabbit', value: 'rabbit' },\n { label: 'Facebook', value: 'facebook' },\n { label: 'TikTok', value: 'tiktok' },\n { label: 'Instagram', value: 'ig' },\n];\n\n/** 社交平台与 MJML mj-social-element 的 name 对齐(含常用内置名)。 */\nexport const SOCIAL_NETWORK_OPTIONS: { label: string; value: string }[] = [\n { label: '微信', value: 'wechat' },\n { label: '微博', value: 'weibo' },\n { label: 'X', value: 'x' },\n { label: 'LinkedIn', value: 'linkedin' },\n { label: 'GitHub', value: 'github' },\n { label: 'Facebook', value: 'facebook' },\n { label: 'Instagram', value: 'instagram' },\n { label: 'YouTube', value: 'youtube' },\n { label: 'Reddit', value: 'reddit' },\n { label: '网页', value: 'web' },\n];\n\nconst NETWORK_META: Record<string, { color: string; preview: string }> = {\n wechat: { color: '#1AAD19', preview: '信' },\n weibo: { color: '#E6162D', preview: '微' },\n x: { color: '#000000', preview: 'X' },\n linkedin: { color: '#0A66C2', preview: 'in' },\n github: { color: '#181717', preview: 'GH' },\n facebook: { color: '#1877F2', preview: 'f' },\n instagram: { color: '#E4405F', preview: '◎' },\n ig: { color: '#E4405F', preview: '◎' },\n youtube: { color: '#FF0000', preview: '▶' },\n reddit: { color: '#FF4500', preview: 'r' },\n tiktok: { color: '#000000', preview: '♪' },\n rabbit: { color: '#FF2442', preview: 'R' },\n website: { color: '#6b7280', preview: '◇' },\n web: { color: '#6b7280', preview: '◇' },\n};\n\nexport const escAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\n/** mj-social-element 体内文本转义(非属性) */\nexport const escMjmlText = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\nexport interface SocialLinkItem {\n network: string;\n href: string;\n /** 图标旁文字,对应 mj-social-element 子内容 */\n label?: string;\n /** 自定义图标 URL,对应 mj-social-element src */\n iconSrc?: string;\n /** 图标区域背景色;未设则用平台预设 */\n backgroundColor?: string;\n}\n\n/** 社交组块级:所有带标签的链接共用同一套标签文字样式 */\nexport interface SocialGroupLabelStyle {\n labelFontSize: number;\n labelFontWeight: string;\n labelColor: string;\n}\n\nexport function socialMeta(network: string): { color: string; preview: string } {\n return NETWORK_META[network] ?? { color: '#6b7280', preview: '·' };\n}\n\nexport function paddingQuad(p: {\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}): string {\n return `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n}\n\n/** mj-social `border-radius`:0 直角;≥999 或 ≥图标半边 → 圆形裁切(999px) */\nexport function socialIconBorderRadiusMjml(iconSize: number, radiusPx: unknown): string {\n const size = Math.max(1, Number(iconSize) || 28);\n const r = Number(radiusPx);\n if (!Number.isFinite(r) || r <= 0) return '0px';\n const half = size / 2;\n if (r >= 999 || r >= half) return '999px';\n return `${Math.min(r, size)}px`;\n}\n\n/** 画布预览用图标圆角 CSS(与 {@link socialIconBorderRadiusMjml} 语义一致) */\nexport function socialIconBorderRadiusCss(iconSize: number, radiusPx: unknown): string {\n const size = Math.max(1, Number(iconSize) || 28);\n const r = Number(radiusPx);\n if (!Number.isFinite(r) || r <= 0) return '0';\n const half = size / 2;\n if (r >= 999 || r >= half) return '50%';\n return `${Math.min(r, size)}px`;\n}\n\n/** mj-social `inner-padding`,控制图标之间的可视间距 */\nexport function socialIconSpacingPx(spacing: unknown, fallback = 10): number {\n const n = Number(spacing);\n if (!Number.isFinite(n) || n < 0) return fallback;\n return Math.min(64, Math.round(n));\n}\n\nexport function flexJustifyFromAlign(align: 'left' | 'center' | 'right'): string {\n if (align === 'right') return 'flex-end';\n if (align === 'left') return 'flex-start';\n return 'center';\n}\n\nexport function mjSocialElementsLines(\n links: SocialLinkItem[],\n labelStyle: SocialGroupLabelStyle,\n): string {\n const fontSizeRaw = labelStyle.labelFontSize > 0 ? labelStyle.labelFontSize : 13;\n const fontSize = Math.max(8, Math.min(48, fontSizeRaw));\n const fontWeight = normalizeFontWeightStep(labelStyle.labelFontWeight);\n const textColor = labelStyle.labelColor?.trim() || '#333333';\n const fwEsc = escAttr(fontWeight);\n return links\n .map((l) => {\n const meta = socialMeta(l.network);\n const bgColor = l.backgroundColor?.trim() || meta.color;\n const attrs = [\n `name=\"${escAttr(mjSocialElementName(l.network))}\"`,\n `href=\"${escAttr(l.href)}\"`,\n `background-color=\"${escAttr(bgColor)}\"`,\n `color=\"${escAttr(textColor)}\"`,\n `font-size=\"${fontSize}px\"`,\n `font-weight=\"${fwEsc}\"`,\n ];\n const attrStr = attrs.join(' ');\n const src = l.iconSrc?.trim();\n const withSrc = src ? `${attrStr} src=\"${escAttr(src)}\"` : attrStr;\n const label = l.label?.trim() ?? '';\n if (!label) {\n return ` <mj-social-element ${withSrc} />`;\n }\n return ` <mj-social-element ${withSrc}>\\n ${escMjmlText(label)}\\n </mj-social-element>`;\n })\n .join('\\n');\n}\n","import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';\nimport { icons } from './icons';\nimport {\n BIZ_SOCIAL_NETWORK_OPTIONS,\n escAttr,\n flexJustifyFromAlign,\n mjSocialElementsLines,\n paddingQuad,\n socialIconBorderRadiusCss,\n socialIconBorderRadiusMjml,\n socialIconSpacingPx,\n socialMeta,\n type SocialLinkItem,\n} from './socialShared';\n\n/** 与社交组一致,仅平台选项收窄为业务五件套 */\ninterface SocialBizProps {\n elements: SocialLinkItem[];\n align: 'left' | 'center' | 'right';\n iconSize: number;\n iconBorderRadius: number;\n iconSpacing: number;\n labelFontSize: number;\n labelFontWeight: string;\n labelColor: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n /** 旧版自定义块:`links` + textarea,仅用于兼容读入 */\n links?: { network: string; href: string }[];\n}\n\nconst DEFAULT_BIZ_ELEMENTS: SocialLinkItem[] = [\n { network: 'x', href: 'https://x.com/' },\n { network: 'rabbit', href: 'https://example.com' },\n { network: 'facebook', href: 'https://facebook.com/' },\n { network: 'tiktok', href: 'https://www.tiktok.com/' },\n { network: 'ig', href: 'https://instagram.com/' },\n];\n\nfunction normalizeElements(p: SocialBizProps): SocialLinkItem[] {\n if (p.elements?.length) return p.elements;\n const legacy = p.links;\n if (Array.isArray(legacy) && legacy.length)\n return legacy.map((l) => ({\n network: String(l.network ?? 'web'),\n href: String(l.href ?? ''),\n }));\n return DEFAULT_BIZ_ELEMENTS;\n}\n\nexport const socialBlock = defineBlock<SocialBizProps>({\n type: 'custom:social',\n name: '社交链接',\n category: 'custom',\n icon: icons.social,\n defaultProps: {\n elements: DEFAULT_BIZ_ELEMENTS,\n align: 'center',\n iconSize: 28,\n iconBorderRadius: 999,\n iconSpacing: 10,\n labelFontSize: 13,\n labelFontWeight: '400',\n labelColor: '#333333',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'elements',\n label: '社交链接',\n type: 'socialLinkList',\n options: BIZ_SOCIAL_NETWORK_OPTIONS,\n help: '平台:X、Rabbit、Facebook、TikTok、Instagram (ig)。可填标签、自定义图标 URL。MJML 侧 Rabbit/TikTok 使用 web 占位图标,需要品牌图时请填「图标 URL」。',\n },\n {\n key: 'labelFontSize',\n label: '标签字号 (px)',\n type: 'number',\n min: 8,\n max: 48,\n step: 1,\n },\n {\n key: 'labelFontWeight',\n label: '标签字重',\n type: 'select',\n selectVariant: 'segmented',\n options: [...FONT_WEIGHT_STEP_OPTIONS],\n },\n { key: 'labelColor', label: '标签颜色', type: 'color' },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'iconSize', label: '图标尺寸 (px)', type: 'number', min: 16, max: 64 },\n {\n key: 'iconBorderRadius',\n label: '图标圆角 (px)',\n type: 'number',\n min: 0,\n max: 999,\n step: 1,\n help: '0 为方形直角;较大值(如 999)为圆形(默认)。',\n },\n {\n key: 'iconSpacing',\n label: '图标间距 (px)',\n type: 'number',\n min: 0,\n max: 64,\n step: 1,\n help: '图标之间的间隔(MJML inner-padding)。',\n },\n { key: 'paddingTop', label: '外边距', type: 'spacing' },\n ],\n toMjml: (p) => {\n const pad = paddingQuad(p);\n const br = socialIconBorderRadiusMjml(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const socAttrs = `align=\"${p.align}\" icon-size=\"${p.iconSize}px\" mode=\"horizontal\" border-radius=\"${br}\" inner-padding=\"${gap}px\" padding=\"${pad}\"`;\n const els = normalizeElements(p).filter((e) => e.href?.trim());\n const labelStyle = {\n labelFontSize: Number(p.labelFontSize ?? 13),\n labelFontWeight: normalizeFontWeightStep(String(p.labelFontWeight ?? '400')),\n labelColor: String(p.labelColor ?? '#333333'),\n };\n const inner = mjSocialElementsLines(els, labelStyle);\n if (!inner.trim()) {\n return `<mj-social ${socAttrs}></mj-social>`;\n }\n return `<mj-social ${socAttrs}>\n${inner}\n</mj-social>`;\n },\n renderPreview: (p) => {\n const fsRaw = p.labelFontSize != null && p.labelFontSize > 0 ? p.labelFontSize : 13;\n const fs = Math.max(8, Math.min(48, fsRaw));\n const fw = normalizeFontWeightStep(p.labelFontWeight);\n const textColor = p.labelColor?.trim() || '#333333';\n const radiusCss = socialIconBorderRadiusCss(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const jc = flexJustifyFromAlign(p.align);\n const items = normalizeElements(p)\n .filter((l) => l.href?.trim())\n .map((l) => {\n const meta = socialMeta(l.network);\n const bg = l.backgroundColor?.trim() || meta.color;\n const label = l.label?.trim() ?? '';\n const iconSrc = l.iconSrc?.trim();\n const iconHtml = iconSrc\n ? `<img src=\"${escAttr(iconSrc)}\" alt=\"\" style=\"width:${p.iconSize}px;height:${p.iconSize}px;object-fit:cover;border-radius:${radiusCss};flex-shrink:0;\" />`\n : `<span style=\"display:inline-flex;width:${p.iconSize}px;height:${p.iconSize}px;border-radius:${radiusCss};background:${bg};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(\n p.iconSize / 2,\n )}px;font-weight:600;flex-shrink:0;overflow:hidden;\">${meta.preview}</span>`;\n const textHtml = label\n ? `<span style=\"font-size:${fs}px !important;font-weight:${fw};color:${escAttr(\n textColor,\n )} !important;line-height:1.2;\">${escAttr(label)}</span>`\n : '';\n return `<span style=\"display:inline-flex;align-items:center;gap:6px;\"><a href=\"${escAttr(\n l.href,\n )}\" style=\"display:inline-flex;align-items:center;text-decoration:none;line-height:0;\">${iconHtml}</a>${textHtml}</span>`;\n })\n .join('');\n const pad = paddingQuad(p);\n return `<div style=\"display:flex;flex-wrap:wrap;justify-content:${jc};align-items:center;gap:${gap}px;padding:${pad};\">${items || '<span style=\"color:#9ca3af;font-size:12px;\">请填写链接 URL</span>'}</div>`;\n },\n});\n","import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';\nimport { icons } from './icons';\nimport {\n escAttr,\n flexJustifyFromAlign,\n mjSocialElementsLines,\n paddingQuad,\n socialIconBorderRadiusCss,\n socialIconBorderRadiusMjml,\n socialIconSpacingPx,\n socialMeta,\n SOCIAL_NETWORK_OPTIONS,\n type SocialLinkItem,\n} from './socialShared';\n\ninterface SocialGroupProps {\n elements: SocialLinkItem[];\n align: 'left' | 'center' | 'right';\n iconSize: number;\n /** 图标圆角 (px)。0 为方形;≥999 或不少于图标半边时为圆形(默认 999) */\n iconBorderRadius: number;\n /** 图标之间的间距 (px),对应 mj-social inner-padding */\n iconSpacing: number;\n /** 标签文字字号(整组统一) */\n labelFontSize: number;\n labelFontWeight: string;\n labelColor: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nexport const socialGroupBlock = defineBlock<SocialGroupProps>({\n type: 'social-group',\n name: '社交组',\n category: 'content',\n icon: icons.socialGroup,\n defaultProps: {\n elements: [\n { network: 'weibo', href: 'https://weibo.com' },\n { network: 'wechat', href: 'https://example.com' },\n ],\n align: 'center',\n iconSize: 28,\n iconBorderRadius: 999,\n iconSpacing: 10,\n labelFontSize: 13,\n labelFontWeight: '400',\n labelColor: '#333333',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'elements',\n label: '社交链接',\n type: 'socialLinkList',\n options: SOCIAL_NETWORK_OPTIONS,\n help: '每行:平台、链接、可选标签文字、自定义图标 URL、图标背景色。标签的字号/字重/颜色在下方统一设置。',\n },\n {\n key: 'labelFontSize',\n label: '标签字号 (px)',\n type: 'number',\n min: 8,\n max: 48,\n step: 1,\n },\n {\n key: 'labelFontWeight',\n label: '标签字重',\n type: 'select',\n selectVariant: 'segmented',\n options: [...FONT_WEIGHT_STEP_OPTIONS],\n },\n { key: 'labelColor', label: '标签颜色', type: 'color' },\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'iconSize', label: '图标尺寸 (px)', type: 'number', min: 16, max: 64 },\n {\n key: 'iconBorderRadius',\n label: '图标圆角 (px)',\n type: 'number',\n min: 0,\n max: 999,\n step: 1,\n help: '0 为方形直角;填较大值(如 999)或与尺寸一半相当时为圆形(默认圆形)。',\n },\n {\n key: 'iconSpacing',\n label: '图标间距 (px)',\n type: 'number',\n min: 0,\n max: 64,\n step: 1,\n help: '每个图标周围的留白,横向即图标之间的间隔(MJML inner-padding)。',\n },\n { key: 'paddingTop', label: '外边距', type: 'spacing' },\n ],\n toMjml: (p) => {\n const pad = paddingQuad(p);\n const br = socialIconBorderRadiusMjml(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const socAttrs = `align=\"${p.align}\" icon-size=\"${p.iconSize}px\" mode=\"horizontal\" border-radius=\"${br}\" inner-padding=\"${gap}px\" padding=\"${pad}\"`;\n const filtered = p.elements.filter((e) => e.href?.trim());\n const labelStyle = {\n labelFontSize: Number(p.labelFontSize ?? 13),\n labelFontWeight: normalizeFontWeightStep(String(p.labelFontWeight ?? '400')),\n labelColor: String(p.labelColor ?? '#333333'),\n };\n const inner = mjSocialElementsLines(filtered, labelStyle);\n if (!inner.trim()) {\n return `<mj-social ${socAttrs}></mj-social>`;\n }\n return `<mj-social ${socAttrs}>\n${inner}\n</mj-social>`;\n },\n renderPreview: (p) => {\n const fsRaw = p.labelFontSize != null && p.labelFontSize > 0 ? p.labelFontSize : 13;\n const fs = Math.max(8, Math.min(48, fsRaw));\n const fw = normalizeFontWeightStep(p.labelFontWeight);\n const textColor = p.labelColor?.trim() || '#333333';\n const radiusCss = socialIconBorderRadiusCss(p.iconSize, p.iconBorderRadius ?? 999);\n const gap = socialIconSpacingPx(p.iconSpacing, 10);\n const jc = flexJustifyFromAlign(p.align);\n const items = p.elements\n .filter((l) => l.href?.trim())\n .map((l) => {\n const meta = socialMeta(l.network);\n const bg = l.backgroundColor?.trim() || meta.color;\n const label = l.label?.trim() ?? '';\n const iconSrc = l.iconSrc?.trim();\n const iconHtml = iconSrc\n ? `<img src=\"${escAttr(iconSrc)}\" alt=\"\" style=\"width:${p.iconSize}px;height:${p.iconSize}px;object-fit:cover;border-radius:${radiusCss};flex-shrink:0;\" />`\n : `<span style=\"display:inline-flex;width:${p.iconSize}px;height:${p.iconSize}px;border-radius:${radiusCss};background:${bg};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(\n p.iconSize / 2,\n )}px;font-weight:600;flex-shrink:0;overflow:hidden;\">${meta.preview}</span>`;\n const textHtml = label\n ? `<span style=\"font-size:${fs}px !important;font-weight:${fw};color:${escAttr(\n textColor,\n )} !important;line-height:1.2;\">${escAttr(label)}</span>`\n : '';\n return `<span style=\"display:inline-flex;align-items:center;gap:6px;\"><a href=\"${escAttr(\n l.href,\n )}\" style=\"display:inline-flex;align-items:center;text-decoration:none;line-height:0;\">${iconHtml}</a>${textHtml}</span>`;\n })\n .join('');\n const pad = paddingQuad(p);\n return `<div style=\"display:flex;flex-wrap:wrap;justify-content:${jc};align-items:center;gap:${gap}px;padding:${pad};\">${items || '<span style=\"color:#9ca3af;font-size:12px;\">请添加社交链接</span>'}</div>`;\n },\n});\n","import { defineBlock } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface SpacerProps {\n height: number;\n}\n\nexport const spacerBlock = defineBlock<SpacerProps>({\n type: 'spacer',\n name: '间距',\n category: 'content',\n icon: icons.spacer,\n defaultProps: { height: 24 },\n schema: [{ key: 'height', label: '高度 (px)', type: 'number', min: 1, max: 200 }],\n toMjml: (p) => `<mj-spacer height=\"${p.height}px\" />`,\n renderPreview: (p) => `<div style=\"height:${p.height}px;line-height:${p.height}px;\"></div>`,\n});\n","import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';\nimport { icons } from './icons';\n\ninterface TextProps {\n content: string;\n align: 'left' | 'center' | 'right';\n color: string;\n fontSize: string;\n fontFamily: string;\n fontWeight: string;\n /** 空字符串:与邮件全局行距(mj-head)一致 */\n lineHeight: string;\n paddingTop: number;\n paddingRight: number;\n paddingBottom: number;\n paddingLeft: number;\n}\n\nconst escapeAttr = (s: string) =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\nexport const textBlock = defineBlock<TextProps>({\n type: 'text',\n name: '文本',\n category: 'content',\n icon: icons.text,\n defaultProps: {\n content:\n '<p style=\"margin:0;\">在此处输入文本。<strong>双击</strong>进入编辑模式,<em>选中文字</em>会出现工具条;支持变量 {{user.name}}</p>',\n align: 'left',\n color: '',\n fontSize: '',\n fontFamily: '',\n fontWeight: '',\n lineHeight: '',\n paddingTop: 8,\n paddingRight: 0,\n paddingBottom: 8,\n paddingLeft: 0,\n },\n schema: [\n {\n key: 'align',\n label: '对齐',\n type: 'select',\n selectVariant: 'segmented',\n options: [\n { label: '左', value: 'left' },\n { label: '居中', value: 'center' },\n { label: '右', value: 'right' },\n ],\n },\n { key: 'color', label: '颜色', type: 'color', placeholder: '继承全局' },\n { key: 'fontSize', label: '字号', type: 'text', inheritGlobal: true },\n { key: 'fontFamily', label: '字体', type: 'text', placeholder: '继承全局' },\n {\n key: 'fontWeight',\n label: '字重',\n type: 'select',\n selectVariant: 'segmented',\n inheritGlobal: true,\n options: [...FONT_WEIGHT_STEP_OPTIONS],\n },\n {\n key: 'lineHeight',\n label: '行高',\n type: 'select',\n help: '留空则使用邮件设置里的全局行距',\n options: [\n { label: '继承全局', value: '' },\n { label: '1.0', value: '1' },\n { label: '1.15', value: '1.15' },\n { label: '1.25', value: '1.25' },\n { label: '1.4', value: '1.4' },\n { label: '1.5', value: '1.5' },\n { label: '1.75', value: '1.75' },\n { label: '2.0', value: '2' },\n { label: '22px', value: '22px' },\n { label: '24px', value: '24px' },\n { label: '28px', value: '28px' },\n { label: '32px', value: '32px' },\n ],\n },\n { key: 'paddingTop', label: '内边距', type: 'spacing' },\n {\n key: 'content',\n label: '内容(HTML,备用)',\n type: 'textarea',\n help: '建议直接在画布双击编辑;这里保留为高级编辑入口。',\n },\n ],\n inlineEditable: {\n selector: '.sm-text-content',\n mode: 'rich',\n multiline: true,\n propKey: 'content',\n placeholder: '输入文本…',\n },\n toMjml: (p) => {\n const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;\n const ff = p.fontFamily ? ` font-family=\"${escapeAttr(p.fontFamily)}\"` : '';\n const fwRaw = String(p.fontWeight ?? '').trim();\n const fw = fwRaw ? ` font-weight=\"${escapeAttr(normalizeFontWeightStep(fwRaw))}\"` : '';\n const lh = String(p.lineHeight ?? '').trim();\n const lhAttr = lh ? ` line-height=\"${escapeAttr(lh)}\"` : '';\n const colorRaw = String(p.color ?? '').trim();\n const colorAttr = colorRaw ? ` color=\"${escapeAttr(colorRaw)}\"` : '';\n const fsRaw = String(p.fontSize ?? '').trim();\n const fsAttr = fsRaw ? ` font-size=\"${escapeAttr(fsRaw)}\"` : '';\n return `<mj-text align=\"${p.align}\"${colorAttr}${fsAttr}${lhAttr}${ff}${fw} padding=\"${padding}\">${p.content}</mj-text>`;\n },\n renderPreview: (p) => {\n const ff = p.fontFamily ? `font-family:${p.fontFamily};` : '';\n const fwRaw = String(p.fontWeight ?? '').trim();\n const fwCss = fwRaw ? `font-weight:${normalizeFontWeightStep(fwRaw)};` : '';\n const lhRaw = String(p.lineHeight ?? '').trim();\n const lh = lhRaw ? `line-height:${lhRaw};` : 'line-height:normal;';\n const colorRaw = String(p.color ?? '').trim();\n const colorCss = colorRaw ? `color:${colorRaw};` : '';\n const fsRaw = String(p.fontSize ?? '').trim();\n const fsCss = fsRaw ? `font-size:${fsRaw};` : '';\n return `<div class=\"sm-text-content\" style=\"text-align:${p.align};${colorCss}${fsCss}${fwCss}${lh}${ff}padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;\">${p.content}</div>`;\n },\n});\n","import type { BlockDefinition } from '@simple-mail/core';\nimport { buttonBlock } from './button';\nimport { dividerBlock } from './divider';\nimport { footerBlock } from './footer';\nimport { heroBlock } from './hero';\nimport { htmlBlock } from './html';\nimport { imageBlock } from './image';\nimport { logoBlock } from './logo';\nimport { socialBlock } from './social';\nimport { socialGroupBlock } from './socialGroup';\nimport { spacerBlock } from './spacer';\nimport { textBlock } from './text';\n\nexport {\n buttonBlock,\n dividerBlock,\n footerBlock,\n heroBlock,\n htmlBlock,\n imageBlock,\n logoBlock,\n socialBlock,\n socialGroupBlock,\n spacerBlock,\n textBlock,\n};\n\n/** 宿主拼装「社交组」类 block 时可复用(mj-social 序列化、侧栏 socialLinkList)。 */\nexport {\n escAttr,\n escMjmlText,\n flexJustifyFromAlign,\n mjSocialElementName,\n mjSocialElementsLines,\n paddingQuad,\n socialIconBorderRadiusCss,\n socialIconBorderRadiusMjml,\n socialIconSpacingPx,\n socialMeta,\n SOCIAL_NETWORK_OPTIONS,\n type SocialGroupLabelStyle,\n type SocialLinkItem,\n} from './socialShared';\n\n/** 内置组件(content 类)。可直接传给 MailEditor.blocks。 */\nexport const builtinBlocks: BlockDefinition<any>[] = [\n textBlock,\n htmlBlock,\n imageBlock,\n socialGroupBlock,\n heroBlock,\n buttonBlock,\n dividerBlock,\n spacerBlock,\n];\n\n/** 业务示例的“自定义”组件。可作为参考或直接使用;正式业务块应由宿主应用注册。 */\nexport const exampleCustomBlocks: BlockDefinition<any>[] = [logoBlock, socialBlock, footerBlock];\n\n/** 全部组件(内置 + 示例自定义)。业务相关块请在使用侧与 `allBlocks` 合并后传入 MailEditor。 */\nexport const allBlocks: BlockDefinition<any>[] = [...builtinBlocks, ...exampleCustomBlocks];\n"],"names":["icons","escapeAttr","s","buttonBlock","defineBlock","p","padding","innerPadding","bw","blockButtonWidthCss","widthAttr","wst","esc","dividerBlock","footerBlock","heroBlock","ctx","w","docContentWidthCss","h","flexAlign","url","htmlBlock","mjRawEmailTableWrap","mjRawCellTypographyFromStyles","imageBlock","href","alt","align","fixedH","sizeStyle","logoBlock","m","mjSocialElementName","network","n","BIZ_SOCIAL_NETWORK_OPTIONS","SOCIAL_NETWORK_OPTIONS","NETWORK_META","escAttr","escMjmlText","socialMeta","paddingQuad","socialIconBorderRadiusMjml","iconSize","radiusPx","size","r","half","socialIconBorderRadiusCss","socialIconSpacingPx","spacing","fallback","flexJustifyFromAlign","mjSocialElementsLines","links","labelStyle","fontSizeRaw","fontSize","fontWeight","normalizeFontWeightStep","textColor","_a","fwEsc","meta","bgColor","attrStr","src","_b","withSrc","label","_c","DEFAULT_BIZ_ELEMENTS","normalizeElements","legacy","l","socialBlock","FONT_WEIGHT_STEP_OPTIONS","pad","br","gap","socAttrs","els","e","inner","fsRaw","fs","fw","radiusCss","jc","items","bg","iconSrc","iconHtml","textHtml","socialGroupBlock","filtered","spacerBlock","textBlock","ff","fwRaw","lh","lhAttr","colorRaw","colorAttr","fsAttr","fwCss","lhRaw","colorCss","fsCss","builtinBlocks","exampleCustomBlocks","allBlocks"],"mappings":"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"}
|
|
@@ -28,10 +28,10 @@ export const textBlock = defineBlock<TextProps>({
|
|
|
28
28
|
content:
|
|
29
29
|
'<p style="margin:0;">在此处输入文本。<strong>双击</strong>进入编辑模式,<em>选中文字</em>会出现工具条;支持变量 {{user.name}}</p>',
|
|
30
30
|
align: 'left',
|
|
31
|
-
color: '
|
|
32
|
-
fontSize: '
|
|
31
|
+
color: '',
|
|
32
|
+
fontSize: '',
|
|
33
33
|
fontFamily: '',
|
|
34
|
-
fontWeight: '
|
|
34
|
+
fontWeight: '',
|
|
35
35
|
lineHeight: '',
|
|
36
36
|
paddingTop: 8,
|
|
37
37
|
paddingRight: 0,
|
|
@@ -41,7 +41,7 @@ export const textBlock = defineBlock<TextProps>({
|
|
|
41
41
|
schema: [
|
|
42
42
|
{
|
|
43
43
|
key: 'align',
|
|
44
|
-
label: '
|
|
44
|
+
label: '对齐',
|
|
45
45
|
type: 'select',
|
|
46
46
|
selectVariant: 'segmented',
|
|
47
47
|
options: [
|
|
@@ -50,14 +50,15 @@ export const textBlock = defineBlock<TextProps>({
|
|
|
50
50
|
{ label: '右', value: 'right' },
|
|
51
51
|
],
|
|
52
52
|
},
|
|
53
|
-
{ key: 'color', label: '
|
|
54
|
-
{ key: 'fontSize', label: '
|
|
53
|
+
{ key: 'color', label: '颜色', type: 'color', placeholder: '继承全局' },
|
|
54
|
+
{ key: 'fontSize', label: '字号', type: 'text', inheritGlobal: true },
|
|
55
55
|
{ key: 'fontFamily', label: '字体', type: 'text', placeholder: '继承全局' },
|
|
56
56
|
{
|
|
57
57
|
key: 'fontWeight',
|
|
58
58
|
label: '字重',
|
|
59
59
|
type: 'select',
|
|
60
60
|
selectVariant: 'segmented',
|
|
61
|
+
inheritGlobal: true,
|
|
61
62
|
options: [...FONT_WEIGHT_STEP_OPTIONS],
|
|
62
63
|
},
|
|
63
64
|
{
|
|
@@ -98,20 +99,26 @@ export const textBlock = defineBlock<TextProps>({
|
|
|
98
99
|
toMjml: (p) => {
|
|
99
100
|
const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;
|
|
100
101
|
const ff = p.fontFamily ? ` font-family="${escapeAttr(p.fontFamily)}"` : '';
|
|
101
|
-
const
|
|
102
|
-
const fw =
|
|
102
|
+
const fwRaw = String(p.fontWeight ?? '').trim();
|
|
103
|
+
const fw = fwRaw ? ` font-weight="${escapeAttr(normalizeFontWeightStep(fwRaw))}"` : '';
|
|
103
104
|
const lh = String(p.lineHeight ?? '').trim();
|
|
104
105
|
const lhAttr = lh ? ` line-height="${escapeAttr(lh)}"` : '';
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
const colorRaw = String(p.color ?? '').trim();
|
|
107
|
+
const colorAttr = colorRaw ? ` color="${escapeAttr(colorRaw)}"` : '';
|
|
108
|
+
const fsRaw = String(p.fontSize ?? '').trim();
|
|
109
|
+
const fsAttr = fsRaw ? ` font-size="${escapeAttr(fsRaw)}"` : '';
|
|
110
|
+
return `<mj-text align="${p.align}"${colorAttr}${fsAttr}${lhAttr}${ff}${fw} padding="${padding}">${p.content}</mj-text>`;
|
|
108
111
|
},
|
|
109
112
|
renderPreview: (p) => {
|
|
110
113
|
const ff = p.fontFamily ? `font-family:${p.fontFamily};` : '';
|
|
111
|
-
const
|
|
112
|
-
const
|
|
114
|
+
const fwRaw = String(p.fontWeight ?? '').trim();
|
|
115
|
+
const fwCss = fwRaw ? `font-weight:${normalizeFontWeightStep(fwRaw)};` : '';
|
|
113
116
|
const lhRaw = String(p.lineHeight ?? '').trim();
|
|
114
117
|
const lh = lhRaw ? `line-height:${lhRaw};` : 'line-height:normal;';
|
|
115
|
-
|
|
118
|
+
const colorRaw = String(p.color ?? '').trim();
|
|
119
|
+
const colorCss = colorRaw ? `color:${colorRaw};` : '';
|
|
120
|
+
const fsRaw = String(p.fontSize ?? '').trim();
|
|
121
|
+
const fsCss = fsRaw ? `font-size:${fsRaw};` : '';
|
|
122
|
+
return `<div class="sm-text-content" style="text-align:${p.align};${colorCss}${fsCss}${fwCss}${lh}${ff}padding:${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px;">${p.content}</div>`;
|
|
116
123
|
},
|
|
117
124
|
});
|
|
@@ -72,6 +72,8 @@ export declare interface BlockSchemaField {
|
|
|
72
72
|
step?: number;
|
|
73
73
|
placeholder?: string;
|
|
74
74
|
help?: string;
|
|
75
|
+
/** 为 true 时右栏显示「继承全局」开关:开=留空跟随邮件全局,关=写入当前全局值为块级固定值 */
|
|
76
|
+
inheritGlobal?: boolean;
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
export declare interface Column {
|
|
@@ -162,6 +164,11 @@ declare interface EditorOptions {
|
|
|
162
164
|
imageAssets?: ImageAssetsHandlers;
|
|
163
165
|
/** 右栏控件形态等可选 UI 偏好。 */
|
|
164
166
|
ui?: EditorUiOptions;
|
|
167
|
+
/**
|
|
168
|
+
* 顶栏「重置内容」恢复的目标文档(与 `initialDoc` 独立;编辑已保存邮件时仍应指向业务预置模板)。
|
|
169
|
+
* 未传时与构造时的 `initialDoc` 合并结果一致。
|
|
170
|
+
*/
|
|
171
|
+
presetDoc?: Partial<EmailDoc>;
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
/** 编辑器 Chrome 配色:`system` 由 `prefers-color-scheme` 与 `data-sm-theme` 共同决定。邮件画布 `.sm-canvas` 默认仍为白纸以贴近成品。 */
|
|
@@ -194,6 +201,10 @@ export declare interface EditorUiOptions {
|
|
|
194
201
|
* 为 true 时隐藏顶栏「全屏」图标按钮(浏览器原生全屏 API,作用于编辑器根节点)。
|
|
195
202
|
*/
|
|
196
203
|
hideTopbarFullscreen?: boolean;
|
|
204
|
+
/** 为 true 时隐藏顶栏「清空画布」按钮。 */
|
|
205
|
+
hideTopbarClearCanvas?: boolean;
|
|
206
|
+
/** 为 true 时隐藏顶栏「重置内容」按钮。 */
|
|
207
|
+
hideTopbarResetContent?: boolean;
|
|
197
208
|
}
|
|
198
209
|
|
|
199
210
|
/**
|
|
@@ -335,6 +346,8 @@ declare interface InlineEditableConfig<P extends object = Record<string, unknown
|
|
|
335
346
|
placeholder?: string;
|
|
336
347
|
}
|
|
337
348
|
|
|
349
|
+
export declare function isTwoColumnLayout(layout: SectionLayout): layout is TwoColumnLayout;
|
|
350
|
+
|
|
338
351
|
declare type Listener = (detail?: DocChangedDetail) => void;
|
|
339
352
|
|
|
340
353
|
/**
|
|
@@ -366,6 +379,10 @@ export declare class MailEditor {
|
|
|
366
379
|
private changeTimer;
|
|
367
380
|
/** 显式品牌色时覆盖 CSS 变量;未设置则由 styles 按 light/dark 使用默认紫/靛 */
|
|
368
381
|
private accentColorOverride;
|
|
382
|
+
/** 顶栏开关:是否在画布上始终显示 Section / Block 轻量虚线边框 */
|
|
383
|
+
private showLayoutBorders;
|
|
384
|
+
/** 「重置内容」时恢复的文档快照(与当前画布内容无关) */
|
|
385
|
+
private presetContentDoc;
|
|
369
386
|
private systemThemeMq;
|
|
370
387
|
private readonly _onSystemThemeMqChange;
|
|
371
388
|
private readonly _onFullscreenChange;
|
|
@@ -379,6 +396,15 @@ export declare class MailEditor {
|
|
|
379
396
|
constructor(opts: EditorOptions);
|
|
380
397
|
setValue(doc: EmailDoc): void;
|
|
381
398
|
getValue(): EmailDoc;
|
|
399
|
+
/**
|
|
400
|
+
* 清空画布:移除所有 Section/Block,保留 meta、styles、variables。
|
|
401
|
+
* 会提交内联编辑并清空选中。
|
|
402
|
+
*/
|
|
403
|
+
clearCanvas(): void;
|
|
404
|
+
/** 将画布恢复为构造时 `presetDoc`(或 `initialDoc`)对应的预置内容。 */
|
|
405
|
+
resetToPreset(): void;
|
|
406
|
+
/** 更新「重置内容」的目标(例如宿主异步加载默认模板后)。 */
|
|
407
|
+
setPresetDoc(partial: Partial<EmailDoc>): void;
|
|
382
408
|
setVariables(vars: Variable[]): void;
|
|
383
409
|
getVariables(): Variable[];
|
|
384
410
|
/** 当前界面主题(`system` 不解析为 light/dark)。 */
|
|
@@ -410,6 +436,8 @@ export declare class MailEditor {
|
|
|
410
436
|
private _blurRightPanelIfFocused;
|
|
411
437
|
/** 提交内联编辑并清空选中,右栏回到文档级面板 */
|
|
412
438
|
private _focusMailSettings;
|
|
439
|
+
private _confirmClearCanvas;
|
|
440
|
+
private _confirmResetContent;
|
|
413
441
|
private _setMode;
|
|
414
442
|
private _bindKeyboard;
|
|
415
443
|
private _onChange;
|
|
@@ -420,6 +448,7 @@ export declare class MailEditor {
|
|
|
420
448
|
private _bindFullscreen;
|
|
421
449
|
private _unbindFullscreen;
|
|
422
450
|
private _toggleFullscreen;
|
|
451
|
+
private _toggleLayoutBorders;
|
|
423
452
|
}
|
|
424
453
|
|
|
425
454
|
export declare function metaWidthInputString(raw: unknown): string;
|
|
@@ -468,12 +497,16 @@ export declare function parseMetaWidthFromUserInput(input: string): number | str
|
|
|
468
497
|
/** Section 右栏输入;空字符串表示清除宽度 */
|
|
469
498
|
export declare function parseSectionWidthFromUserInput(input: string): string | number | undefined;
|
|
470
499
|
|
|
500
|
+
/** @deprecated 请改用 {@link pruneSectionIfEmpty},避免误删多个空 Section */
|
|
501
|
+
export declare function pruneEmptySections(draft: EmailDoc): void;
|
|
502
|
+
|
|
471
503
|
/**
|
|
472
|
-
*
|
|
473
|
-
* 在内容块被删除或拖走后调用,可与 `autoWrapSection`
|
|
474
|
-
*
|
|
504
|
+
* 若指定 Section 的每一列都没有 Block,则从文档中移除该 Section。
|
|
505
|
+
* 在内容块被删除或拖走后调用,可与 `autoWrapSection` 搭配,避免单列 Section 在唯一块离场后仍残留空壳;
|
|
506
|
+
* 多列 Section 始终保留,便于继续向各列拖入内容。
|
|
507
|
+
* 仅处理刚变空的 Section,不会误删用户事先添加、尚未拖入内容的空布局。
|
|
475
508
|
*/
|
|
476
|
-
export declare function
|
|
509
|
+
export declare function pruneSectionIfEmpty(draft: EmailDoc, sectionId: string): void;
|
|
477
510
|
|
|
478
511
|
/**
|
|
479
512
|
* 组件注册表。所有内置/自定义组件都通过 `defineBlock` 注册进来;
|
|
@@ -571,6 +604,9 @@ export { Selection_2 as Selection }
|
|
|
571
604
|
|
|
572
605
|
declare type SelectionListener = () => void;
|
|
573
606
|
|
|
607
|
+
/** 仅更新 layout 字段;两列间切换时列数不变,列内块按列下标保留 */
|
|
608
|
+
export declare function setSectionLayout(section: Section, layout: SectionLayout): void;
|
|
609
|
+
|
|
574
610
|
/**
|
|
575
611
|
* 极小的不可变 store + 发布订阅 + history。
|
|
576
612
|
* 所有变更都通过 `update(fn)` 走结构化克隆,保证:
|
|
@@ -607,6 +643,11 @@ export declare class Store {
|
|
|
607
643
|
private _notify;
|
|
608
644
|
}
|
|
609
645
|
|
|
646
|
+
/** 两列 Section 的列宽比例(左栏拖入默认 `1-1`,右栏可改为 `1-2` / `2-1`) */
|
|
647
|
+
export declare const TWO_COLUMN_LAYOUTS: readonly ["1-1", "1-2", "2-1"];
|
|
648
|
+
|
|
649
|
+
export declare type TwoColumnLayout = (typeof TWO_COLUMN_LAYOUTS)[number];
|
|
650
|
+
|
|
610
651
|
export declare interface Variable {
|
|
611
652
|
/** Mustache 风格变量名,例如 user.name */
|
|
612
653
|
key: string;
|