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 CHANGED
@@ -23,6 +23,7 @@ Doc → Section → Column → Block // 仅四层,不允许 Block 再含
23
23
  - **界面主题**:顶栏 **太阳 / 月亮 / 显示器** 图标切换浅色、深色、跟随系统(`prefers-color-scheme`);中间邮件画布仍为白纸以贴近成品
24
24
  - **品牌色**:可选 `accentColor` / `setAccentColor`,覆盖强调色与选区色;可选顶栏拾色器
25
25
  - **仅搭正文**:`ui.hideMailMeta` 隐藏主题 / Preheader 与顶栏「邮件设置」,保留版式宽度与全局样式
26
+ - **画布清空 / 重置**:顶栏「清空画布」「重置内容」;`presetDoc` 与 `initialDoc` 分离,编辑已保存邮件时重置仍回到业务预置模板
26
27
  - 包体可控:核心 + MJML + CodeMirror + 富文本,gzip ≈ 586KB
27
28
 
28
29
  ## 仓库结构
@@ -67,6 +68,12 @@ const editor = new MailEditor({
67
68
  variables: [{ key: 'user.name', label: '用户名', sample: '张三' }],
68
69
  sections: [],
69
70
  },
71
+ /**
72
+ * 顶栏「重置内容」恢复的目标(与 initialDoc 独立)。
73
+ * 编辑页打开已保存邮件时:initialDoc = 当前稿,presetDoc = 业务默认模板。
74
+ * 未传时与 initialDoc 合并结果一致。
75
+ */
76
+ // presetDoc: defaultTemplatePartial,
70
77
  /** 右栏控件形态等,见下文「UI 选项 ui」 */
71
78
  // ui: { preferSliderControls: true, hideMailMeta: true },
72
79
  // autoWrapSection: true(默认)— 把 Block 拖到 Section 之间空白处时
@@ -85,6 +92,36 @@ const { mjml, html } = editor.export({ withSampleVariables: true });
85
92
 
86
93
  // 整份替换文档(例如切换模板);会先失焦右栏避免旧值残留
87
94
  // editor.setValue(nextDoc);
95
+
96
+ // 清空画布(仅 sections 置空,保留 meta / styles / variables;可 ⌘Z 撤销)
97
+ // editor.clearCanvas();
98
+
99
+ // 恢复为 presetDoc(或构造时 initialDoc)快照
100
+ // editor.resetToPreset();
101
+
102
+ // 异步加载默认模板后更新重置目标
103
+ // editor.setPresetDoc(defaultTemplatePartial);
104
+ ```
105
+
106
+ ### 画布清空与重置
107
+
108
+ 顶栏位于 **撤销 / 重做** 右侧(可用 `ui` 隐藏,见下表):
109
+
110
+ | 按钮 | 行为 |
111
+ |------|------|
112
+ | **清空画布** | 移除所有 Section / Block;`meta`、`styles`、`variables` 不变。操作前浏览器 `confirm` 确认;记入撤销栈(⌘Z 可恢复)。 |
113
+ | **重置内容** | 整份替换为 **`presetDoc`** 快照(未传 `presetDoc` 时等同构造时的 `initialDoc` 合并结果)。操作前 `confirm` 确认;**不**走撤销栈(与 `setValue` 相同,会清空 history)。 |
114
+
115
+ **宿主常见写法**:新建页 `initialDoc` 与 `presetDoc` 同为默认模板;编辑页 `initialDoc` 为接口返回的 `jsonContent`,`presetDoc` 仍为业务预置结构,避免「重置」把用户带回打开时的草稿。
116
+
117
+ ```ts
118
+ const editor = new MailEditor({
119
+ container: el,
120
+ blocks: allBlocks,
121
+ initialDoc: loadedFromApi, // 当前画布
122
+ presetDoc: businessDefaultTemplate, // 顶栏「重置内容」
123
+ onChange: (doc) => save(doc),
124
+ });
88
125
  ```
89
126
 
90
127
  ### 界面主题
@@ -120,6 +157,11 @@ editor.getTheme();
120
157
  |------|------|
121
158
  | `preferSliderControls?: boolean` | 为 `true` 时右栏数值、内边距、全局/组件字号等使用滑块等增强控件。默认 `false`。 |
122
159
  | `hideMailMeta?: boolean` | 为 `true` 时:**不展示**右栏「主题」「Preheader」以及顶栏「邮件设置」按钮;右栏文档级面板改为 **「版式」(内容宽度)+「全局样式」**。`doc.meta.subject` / `preheader` 仍在数据模型中,导出 MJML 仍会生成 `<mj-title>`(可为空)、有值时才生成 `<mj-preview>`,适合发件主题由宿主系统单独维护的场景。 |
160
+ | `hideTopbarTitle?: boolean` | 隐藏顶栏左侧产品标题(嵌入宿主页时常用)。 |
161
+ | `hideTopbarMailSettings?: boolean` | 隐藏顶栏「邮件设置」按钮(与 `hideMailMeta` 叠加使用)。 |
162
+ | `hideTopbarFullscreen?: boolean` | 隐藏顶栏全屏按钮。 |
163
+ | `hideTopbarClearCanvas?: boolean` | 隐藏顶栏「清空画布」。 |
164
+ | `hideTopbarResetContent?: boolean` | 隐藏顶栏「重置内容」。 |
123
165
 
124
166
  ### 图片资源 `imageAssets`
125
167
 
@@ -317,6 +359,8 @@ expandPaletteDrop?: (createBlock: (type: string) => Block) => Block[];
317
359
  | 删除 | 选中后按 Delete/Backspace;或工具条 🗑 |
318
360
  | 复制 | 工具条 ⎘ 图标 |
319
361
  | 撤销 / 重做 | ⌘Z / ⌘⇧Z(顶栏按钮也行) |
362
+ | 清空画布 | 顶栏「清空画布」;移除全部 Section/Block,保留全局样式与变量(可撤销) |
363
+ | 重置内容 | 顶栏「重置内容」;恢复为 `presetDoc`(或构造时的 `initialDoc`) |
320
364
  | 插入变量 | 顶栏 `{{ }}`:编辑中插到光标处;否则插到聚焦输入框 |
321
365
  | 切换源码 / 设计 | 顶栏切换 |
322
366
  | 导出 HTML | 顶栏右上 |
@@ -332,7 +376,12 @@ expandPaletteDrop?: (createBlock: (type: string) => Block) => Block[];
332
376
 
333
377
  ## 数据模型 速览
334
378
 
335
- `EmailDoc` 为单一事实来源;设计 / 导出 / 宿主保存均围绕该 JSON。构造器中的 `initialDoc` 为 `Partial<EmailDoc>`,会与默认空邮件合并。**预置模板**可传入完整或部分 `sections`、`styles`、`variables` 等。运行时用 **`editor.setValue(doc)`** 可整份替换(例如切换模板),调用前会尽量失焦右栏输入,避免面板显示旧值。
379
+ `EmailDoc` 为单一事实来源;设计 / 导出 / 宿主保存均围绕该 JSON
380
+
381
+ - **`initialDoc`**:`Partial<EmailDoc>`,与默认空邮件合并,作为**首次进入画布**的内容。
382
+ - **`presetDoc`**:可选,与默认空邮件合并,作为顶栏 **「重置内容」** 的目标;未传时与 `initialDoc` 相同。编辑已保存邮件时应单独传入业务默认模板,勿与 `initialDoc` 混用。
383
+ - **`editor.setValue(doc)`**:运行期整份替换(如切换模板);会清空撤销栈;调用前会尽量失焦右栏输入。
384
+ - **`editor.clearCanvas()`** / **`editor.resetToPreset()`** / **`editor.setPresetDoc(partial)`**:与顶栏按钮等价,供宿主程序化调用。
336
385
 
337
386
  ```ts
338
387
  interface EmailDoc {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mail-editor-pancake",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "private": false,
5
5
  "description": "面向运营的轻量邮件可视化编辑器(monorepo 根)",
6
6
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- import { defineBlock as h, blockButtonWidthCss as A, docContentWidthCss as H, mjRawEmailTableWrap as _, mjRawCellTypographyFromStyles as q, normalizeFontWeightStep as k, FONT_WEIGHT_STEP_OPTIONS as L } from "@simple-mail/core";
1
+ import { defineBlock as h, blockButtonWidthCss as A, docContentWidthCss as H, mjRawEmailTableWrap as _, mjRawCellTypographyFromStyles as G, normalizeFontWeightStep as k, FONT_WEIGHT_STEP_OPTIONS as L } from "@simple-mail/core";
2
2
  const m = {
3
3
  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>',
4
4
  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>',
@@ -11,7 +11,7 @@ const m = {
11
11
  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>',
12
12
  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>',
13
13
  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>'
14
- }, y = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), G = h({
14
+ }, $ = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), q = h({
15
15
  type: "button",
16
16
  name: "按钮",
17
17
  category: "content",
@@ -69,19 +69,19 @@ const m = {
69
69
  placeholder: "按钮文字"
70
70
  },
71
71
  toMjml: (e) => {
72
- const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = `${e.innerPaddingV}px ${e.innerPaddingH}px`, n = A(e.width), i = n ? ` width="${y(n)}"` : "";
73
- return `<mj-button href="${y(e.href)}" background-color="${y(
72
+ const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = `${e.innerPaddingV}px ${e.innerPaddingH}px`, n = A(e.width), i = n ? ` width="${$(n)}"` : "";
73
+ return `<mj-button href="${$(e.href)}" background-color="${$(
74
74
  e.backgroundColor
75
- )}" color="${y(e.color)}" border-radius="${e.borderRadius}px" font-size="${y(
75
+ )}" color="${$(e.color)}" border-radius="${e.borderRadius}px" font-size="${$(
76
76
  e.fontSize
77
- )}" align="${e.align}" padding="${t}" inner-padding="${o}"${i}>${y(
77
+ )}" align="${e.align}" padding="${t}" inner-padding="${o}"${i}>${$(
78
78
  e.text
79
79
  )}</mj-button>`;
80
80
  },
81
81
  renderPreview: (e) => {
82
82
  const t = A(e.width), o = t ? `width:${t};max-width:100%;box-sizing:border-box;` : "";
83
83
  return `<div style="padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;text-align:${e.align};">
84
- <a href="${y(e.href)}" style="display:inline-block;background:${e.backgroundColor};border-radius:${e.borderRadius}px;padding:${e.innerPaddingV}px ${e.innerPaddingH}px;text-decoration:none;font-size:${e.fontSize};line-height:1.2;${o}"><span class="sm-button-text" style="color:${e.color}">${y(e.text)}</span></a>
84
+ <a href="${$(e.href)}" style="display:inline-block;background:${e.backgroundColor};border-radius:${e.borderRadius}px;padding:${e.innerPaddingV}px ${e.innerPaddingH}px;text-decoration:none;font-size:${e.fontSize};line-height:1.2;${o}"><span class="sm-button-text" style="color:${e.color}">${$(e.text)}</span></a>
85
85
  </div>`;
86
86
  }
87
87
  }), E = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), K = h({
@@ -136,7 +136,7 @@ const m = {
136
136
  ${b(e.address)}<br/>
137
137
  <a href="${b(e.unsubscribeHref)}" style="color:${e.textColor};">${b(e.unsubscribeText)}</a>
138
138
  </div>`
139
- }), z = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), X = h({
139
+ }), C = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), X = h({
140
140
  type: "hero",
141
141
  name: "Hero 大图",
142
142
  category: "content",
@@ -203,20 +203,20 @@ const m = {
203
203
  height="${i}"
204
204
  background-width="${o}"
205
205
  background-height="${i}"
206
- background-url="${z(e.backgroundUrl)}"
207
- background-color="${z(e.backgroundColor)}"
206
+ background-url="${C(e.backgroundUrl)}"
207
+ background-color="${C(e.backgroundColor)}"
208
208
  padding="${n}"
209
209
  vertical-align="${e.verticalAlign}"
210
210
  >
211
211
  <mj-text
212
212
  align="${e.textAlign}"
213
- color="${z(e.textColor)}"
213
+ color="${C(e.textColor)}"
214
214
  padding="0"
215
215
  >${e.content}</mj-text>
216
216
  </mj-hero>`;
217
217
  },
218
218
  renderPreview: (e, t) => {
219
- const o = H(t.doc.meta.width), n = e.verticalAlign === "top" ? "flex-start" : e.verticalAlign === "bottom" ? "flex-end" : "center", i = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, l = z(e.backgroundUrl);
219
+ const o = H(t.doc.meta.width), n = e.verticalAlign === "top" ? "flex-start" : e.verticalAlign === "bottom" ? "flex-end" : "center", i = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, r = C(e.backgroundUrl);
220
220
  return `<div
221
221
  style="
222
222
  box-sizing:border-box;
@@ -224,7 +224,7 @@ const m = {
224
224
  max-width:${o};
225
225
  min-height:${e.height}px;
226
226
  margin:0 auto;
227
- background-image:linear-gradient(to bottom,rgba(0,0,0,0.25),rgba(0,0,0,0.35)),url(${l});
227
+ background-image:linear-gradient(to bottom,rgba(0,0,0,0.25),rgba(0,0,0,0.35)),url(${r});
228
228
  background-size:cover;
229
229
  background-position:center;
230
230
  background-color:${e.backgroundColor};
@@ -232,7 +232,7 @@ const m = {
232
232
  align-items:${n};
233
233
  justify-content:${e.textAlign === "right" ? "flex-end" : e.textAlign === "center" ? "center" : "flex-start"};
234
234
  padding:${i};
235
- color:${z(e.textColor)};
235
+ color:${C(e.textColor)};
236
236
  overflow:hidden;
237
237
  border-radius:2px;
238
238
  "
@@ -242,7 +242,7 @@ const m = {
242
242
  style="
243
243
  width:100%;
244
244
  text-align:${e.textAlign};
245
- color:${z(e.textColor)};
245
+ color:${C(e.textColor)};
246
246
  text-shadow:0 1px 2px rgba(0,0,0,0.45);
247
247
  "
248
248
  >${e.content}</div>
@@ -278,7 +278,7 @@ const m = {
278
278
  },
279
279
  toMjml: (e, t) => {
280
280
  const o = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`;
281
- return _(o, e.html, q(t.doc.styles));
281
+ return _(o, e.html, G(t.doc.styles));
282
282
  },
283
283
  renderPreview: (e) => `<div class="sm-html-content" style="padding:${`${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`};min-height:1em;">${e.html}</div>`
284
284
  }), M = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), Y = h({
@@ -405,14 +405,14 @@ const ee = [
405
405
  rabbit: { color: "#FF2442", preview: "R" },
406
406
  website: { color: "#6b7280", preview: "◇" },
407
407
  web: { color: "#6b7280", preview: "◇" }
408
- }, s = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), ne = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
408
+ }, p = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), ne = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
409
409
  function P(e) {
410
410
  return oe[e] ?? { color: "#6b7280", preview: "·" };
411
411
  }
412
412
  function T(e) {
413
413
  return `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`;
414
414
  }
415
- function W(e, t) {
415
+ function N(e, t) {
416
416
  const o = Math.max(1, Number(e) || 28), n = Number(t);
417
417
  if (!Number.isFinite(n) || n <= 0) return "0px";
418
418
  const i = o / 2;
@@ -432,21 +432,21 @@ function I(e) {
432
432
  return e === "right" ? "flex-end" : e === "left" ? "flex-start" : "center";
433
433
  }
434
434
  function O(e, t) {
435
- var d;
436
- const o = t.labelFontSize > 0 ? t.labelFontSize : 13, n = Math.max(8, Math.min(48, o)), i = k(t.labelFontWeight), l = ((d = t.labelColor) == null ? void 0 : d.trim()) || "#333333", g = s(i);
437
- return e.map((a) => {
438
- var v, S, f;
439
- const p = P(a.network), $ = ((v = a.backgroundColor) == null ? void 0 : v.trim()) || p.color, c = [
440
- `name="${s(Q(a.network))}"`,
441
- `href="${s(a.href)}"`,
442
- `background-color="${s($)}"`,
443
- `color="${s(l)}"`,
435
+ var a;
436
+ const o = t.labelFontSize > 0 ? t.labelFontSize : 13, n = Math.max(8, Math.min(48, o)), i = k(t.labelFontWeight), r = ((a = t.labelColor) == null ? void 0 : a.trim()) || "#333333", d = p(i);
437
+ return e.map((l) => {
438
+ var v, S, y;
439
+ const c = P(l.network), u = ((v = l.backgroundColor) == null ? void 0 : v.trim()) || c.color, g = [
440
+ `name="${p(Q(l.network))}"`,
441
+ `href="${p(l.href)}"`,
442
+ `background-color="${p(u)}"`,
443
+ `color="${p(r)}"`,
444
444
  `font-size="${n}px"`,
445
- `font-weight="${g}"`
446
- ].join(" "), w = (S = a.iconSrc) == null ? void 0 : S.trim(), u = w ? `${c} src="${s(w)}"` : c, x = ((f = a.label) == null ? void 0 : f.trim()) ?? "";
447
- return x ? ` <mj-social-element ${u}>
448
- ${ne(x)}
449
- </mj-social-element>` : ` <mj-social-element ${u} />`;
445
+ `font-weight="${d}"`
446
+ ].join(" "), w = (S = l.iconSrc) == null ? void 0 : S.trim(), x = w ? `${g} src="${p(w)}"` : g, f = ((y = l.label) == null ? void 0 : y.trim()) ?? "";
447
+ return f ? ` <mj-social-element ${x}>
448
+ ${ne(f)}
449
+ </mj-social-element>` : ` <mj-social-element ${x} />`;
450
450
  }).join(`
451
451
  `);
452
452
  }
@@ -457,7 +457,7 @@ const U = [
457
457
  { network: "tiktok", href: "https://www.tiktok.com/" },
458
458
  { network: "ig", href: "https://instagram.com/" }
459
459
  ];
460
- function N(e) {
460
+ function W(e) {
461
461
  var o;
462
462
  if ((o = e.elements) != null && o.length) return e.elements;
463
463
  const t = e.links;
@@ -542,35 +542,35 @@ const ie = h({
542
542
  { key: "paddingTop", label: "外边距", type: "spacing" }
543
543
  ],
544
544
  toMjml: (e) => {
545
- const t = T(e), o = W(e.iconSize, e.iconBorderRadius ?? 999), n = F(e.iconSpacing, 10), i = `align="${e.align}" icon-size="${e.iconSize}px" mode="horizontal" border-radius="${o}" inner-padding="${n}px" padding="${t}"`, l = N(e).filter((a) => {
546
- var p;
547
- return (p = a.href) == null ? void 0 : p.trim();
548
- }), g = {
545
+ const t = T(e), o = N(e.iconSize, e.iconBorderRadius ?? 999), n = F(e.iconSpacing, 10), i = `align="${e.align}" icon-size="${e.iconSize}px" mode="horizontal" border-radius="${o}" inner-padding="${n}px" padding="${t}"`, r = W(e).filter((l) => {
546
+ var c;
547
+ return (c = l.href) == null ? void 0 : c.trim();
548
+ }), d = {
549
549
  labelFontSize: Number(e.labelFontSize ?? 13),
550
550
  labelFontWeight: k(String(e.labelFontWeight ?? "400")),
551
551
  labelColor: String(e.labelColor ?? "#333333")
552
- }, d = O(l, g);
553
- return d.trim() ? `<mj-social ${i}>
554
- ${d}
552
+ }, a = O(r, d);
553
+ return a.trim() ? `<mj-social ${i}>
554
+ ${a}
555
555
  </mj-social>` : `<mj-social ${i}></mj-social>`;
556
556
  },
557
557
  renderPreview: (e) => {
558
- var $;
559
- const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n = k(e.labelFontWeight), i = (($ = e.labelColor) == null ? void 0 : $.trim()) || "#333333", l = V(e.iconSize, e.iconBorderRadius ?? 999), g = F(e.iconSpacing, 10), d = I(e.align), a = N(e).filter((r) => {
560
- var c;
561
- return (c = r.href) == null ? void 0 : c.trim();
562
- }).map((r) => {
563
- var f, C, j;
564
- const c = P(r.network), w = ((f = r.backgroundColor) == null ? void 0 : f.trim()) || c.color, u = ((C = r.label) == null ? void 0 : C.trim()) ?? "", x = (j = r.iconSrc) == null ? void 0 : j.trim(), v = x ? `<img src="${s(x)}" alt="" style="width:${e.iconSize}px;height:${e.iconSize}px;object-fit:cover;border-radius:${l};flex-shrink:0;" />` : `<span style="display:inline-flex;width:${e.iconSize}px;height:${e.iconSize}px;border-radius:${l};background:${w};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(
558
+ var u;
559
+ const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n = k(e.labelFontWeight), i = ((u = e.labelColor) == null ? void 0 : u.trim()) || "#333333", r = V(e.iconSize, e.iconBorderRadius ?? 999), d = F(e.iconSpacing, 10), a = I(e.align), l = W(e).filter((s) => {
560
+ var g;
561
+ return (g = s.href) == null ? void 0 : g.trim();
562
+ }).map((s) => {
563
+ var y, z, j;
564
+ const g = P(s.network), w = ((y = s.backgroundColor) == null ? void 0 : y.trim()) || g.color, x = ((z = s.label) == null ? void 0 : z.trim()) ?? "", f = (j = s.iconSrc) == null ? void 0 : j.trim(), v = f ? `<img src="${p(f)}" alt="" style="width:${e.iconSize}px;height:${e.iconSize}px;object-fit:cover;border-radius:${r};flex-shrink:0;" />` : `<span style="display:inline-flex;width:${e.iconSize}px;height:${e.iconSize}px;border-radius:${r};background:${w};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(
565
565
  e.iconSize / 2
566
- )}px;font-weight:600;flex-shrink:0;overflow:hidden;">${c.preview}</span>`, S = u ? `<span style="font-size:${o}px !important;font-weight:${n};color:${s(
566
+ )}px;font-weight:600;flex-shrink:0;overflow:hidden;">${g.preview}</span>`, S = x ? `<span style="font-size:${o}px !important;font-weight:${n};color:${p(
567
567
  i
568
- )} !important;line-height:1.2;">${s(u)}</span>` : "";
569
- return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${s(
570
- r.href
568
+ )} !important;line-height:1.2;">${p(x)}</span>` : "";
569
+ return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${p(
570
+ s.href
571
571
  )}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${v}</a>${S}</span>`;
572
- }).join(""), p = T(e);
573
- return `<div style="display:flex;flex-wrap:wrap;justify-content:${d};align-items:center;gap:${g}px;padding:${p};">${a || '<span style="color:#9ca3af;font-size:12px;">请填写链接 URL</span>'}</div>`;
572
+ }).join(""), c = T(e);
573
+ return `<div style="display:flex;flex-wrap:wrap;justify-content:${a};align-items:center;gap:${d}px;padding:${c};">${l || '<span style="color:#9ca3af;font-size:12px;">请填写链接 URL</span>'}</div>`;
574
574
  }
575
575
  }), le = h({
576
576
  type: "social-group",
@@ -651,35 +651,35 @@ ${d}
651
651
  { key: "paddingTop", label: "外边距", type: "spacing" }
652
652
  ],
653
653
  toMjml: (e) => {
654
- const t = T(e), o = W(e.iconSize, e.iconBorderRadius ?? 999), n = F(e.iconSpacing, 10), i = `align="${e.align}" icon-size="${e.iconSize}px" mode="horizontal" border-radius="${o}" inner-padding="${n}px" padding="${t}"`, l = e.elements.filter((a) => {
655
- var p;
656
- return (p = a.href) == null ? void 0 : p.trim();
657
- }), g = {
654
+ const t = T(e), o = N(e.iconSize, e.iconBorderRadius ?? 999), n = F(e.iconSpacing, 10), i = `align="${e.align}" icon-size="${e.iconSize}px" mode="horizontal" border-radius="${o}" inner-padding="${n}px" padding="${t}"`, r = e.elements.filter((l) => {
655
+ var c;
656
+ return (c = l.href) == null ? void 0 : c.trim();
657
+ }), d = {
658
658
  labelFontSize: Number(e.labelFontSize ?? 13),
659
659
  labelFontWeight: k(String(e.labelFontWeight ?? "400")),
660
660
  labelColor: String(e.labelColor ?? "#333333")
661
- }, d = O(l, g);
662
- return d.trim() ? `<mj-social ${i}>
663
- ${d}
661
+ }, a = O(r, d);
662
+ return a.trim() ? `<mj-social ${i}>
663
+ ${a}
664
664
  </mj-social>` : `<mj-social ${i}></mj-social>`;
665
665
  },
666
666
  renderPreview: (e) => {
667
- var $;
668
- const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n = k(e.labelFontWeight), i = (($ = e.labelColor) == null ? void 0 : $.trim()) || "#333333", l = V(e.iconSize, e.iconBorderRadius ?? 999), g = F(e.iconSpacing, 10), d = I(e.align), a = e.elements.filter((r) => {
669
- var c;
670
- return (c = r.href) == null ? void 0 : c.trim();
671
- }).map((r) => {
672
- var f, C, j;
673
- const c = P(r.network), w = ((f = r.backgroundColor) == null ? void 0 : f.trim()) || c.color, u = ((C = r.label) == null ? void 0 : C.trim()) ?? "", x = (j = r.iconSrc) == null ? void 0 : j.trim(), v = x ? `<img src="${s(x)}" alt="" style="width:${e.iconSize}px;height:${e.iconSize}px;object-fit:cover;border-radius:${l};flex-shrink:0;" />` : `<span style="display:inline-flex;width:${e.iconSize}px;height:${e.iconSize}px;border-radius:${l};background:${w};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(
667
+ var u;
668
+ const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n = k(e.labelFontWeight), i = ((u = e.labelColor) == null ? void 0 : u.trim()) || "#333333", r = V(e.iconSize, e.iconBorderRadius ?? 999), d = F(e.iconSpacing, 10), a = I(e.align), l = e.elements.filter((s) => {
669
+ var g;
670
+ return (g = s.href) == null ? void 0 : g.trim();
671
+ }).map((s) => {
672
+ var y, z, j;
673
+ const g = P(s.network), w = ((y = s.backgroundColor) == null ? void 0 : y.trim()) || g.color, x = ((z = s.label) == null ? void 0 : z.trim()) ?? "", f = (j = s.iconSrc) == null ? void 0 : j.trim(), v = f ? `<img src="${p(f)}" alt="" style="width:${e.iconSize}px;height:${e.iconSize}px;object-fit:cover;border-radius:${r};flex-shrink:0;" />` : `<span style="display:inline-flex;width:${e.iconSize}px;height:${e.iconSize}px;border-radius:${r};background:${w};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(
674
674
  e.iconSize / 2
675
- )}px;font-weight:600;flex-shrink:0;overflow:hidden;">${c.preview}</span>`, S = u ? `<span style="font-size:${o}px !important;font-weight:${n};color:${s(
675
+ )}px;font-weight:600;flex-shrink:0;overflow:hidden;">${g.preview}</span>`, S = x ? `<span style="font-size:${o}px !important;font-weight:${n};color:${p(
676
676
  i
677
- )} !important;line-height:1.2;">${s(u)}</span>` : "";
678
- return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${s(
679
- r.href
677
+ )} !important;line-height:1.2;">${p(x)}</span>` : "";
678
+ return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${p(
679
+ s.href
680
680
  )}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${v}</a>${S}</span>`;
681
- }).join(""), p = T(e);
682
- return `<div style="display:flex;flex-wrap:wrap;justify-content:${d};align-items:center;gap:${g}px;padding:${p};">${a || '<span style="color:#9ca3af;font-size:12px;">请添加社交链接</span>'}</div>`;
681
+ }).join(""), c = T(e);
682
+ return `<div style="display:flex;flex-wrap:wrap;justify-content:${a};align-items:center;gap:${d}px;padding:${c};">${l || '<span style="color:#9ca3af;font-size:12px;">请添加社交链接</span>'}</div>`;
683
683
  }
684
684
  }), re = h({
685
685
  type: "spacer",
@@ -698,10 +698,10 @@ ${d}
698
698
  defaultProps: {
699
699
  content: '<p style="margin:0;">在此处输入文本。<strong>双击</strong>进入编辑模式,<em>选中文字</em>会出现工具条;支持变量 {{user.name}}</p>',
700
700
  align: "left",
701
- color: "#433f3f",
702
- fontSize: "16px",
701
+ color: "",
702
+ fontSize: "",
703
703
  fontFamily: "",
704
- fontWeight: "400",
704
+ fontWeight: "",
705
705
  lineHeight: "",
706
706
  paddingTop: 8,
707
707
  paddingRight: 0,
@@ -711,7 +711,7 @@ ${d}
711
711
  schema: [
712
712
  {
713
713
  key: "align",
714
- label: "默认对齐",
714
+ label: "对齐",
715
715
  type: "select",
716
716
  selectVariant: "segmented",
717
717
  options: [
@@ -720,14 +720,15 @@ ${d}
720
720
  { label: "右", value: "right" }
721
721
  ]
722
722
  },
723
- { key: "color", label: "默认颜色", type: "color" },
724
- { key: "fontSize", label: "默认字号", type: "text", placeholder: "14px" },
723
+ { key: "color", label: "颜色", type: "color", placeholder: "继承全局" },
724
+ { key: "fontSize", label: "字号", type: "text", inheritGlobal: !0 },
725
725
  { key: "fontFamily", label: "字体", type: "text", placeholder: "继承全局" },
726
726
  {
727
727
  key: "fontWeight",
728
728
  label: "字重",
729
729
  type: "select",
730
730
  selectVariant: "segmented",
731
+ inheritGlobal: !0,
731
732
  options: [...L]
732
733
  },
733
734
  {
@@ -766,14 +767,12 @@ ${d}
766
767
  placeholder: "输入文本…"
767
768
  },
768
769
  toMjml: (e) => {
769
- const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = e.fontFamily ? ` font-family="${B(e.fontFamily)}"` : "", n = k(e.fontWeight), i = n !== "400" ? ` font-weight="${B(n)}"` : "", l = String(e.lineHeight ?? "").trim(), g = l ? ` line-height="${B(l)}"` : "";
770
- return `<mj-text align="${e.align}" color="${B(e.color)}" font-size="${B(
771
- e.fontSize
772
- )}"${g}${o}${i} padding="${t}">${e.content}</mj-text>`;
770
+ const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = e.fontFamily ? ` font-family="${B(e.fontFamily)}"` : "", n = String(e.fontWeight ?? "").trim(), i = n ? ` font-weight="${B(k(n))}"` : "", r = String(e.lineHeight ?? "").trim(), d = r ? ` line-height="${B(r)}"` : "", a = String(e.color ?? "").trim(), l = a ? ` color="${B(a)}"` : "", c = String(e.fontSize ?? "").trim(), u = c ? ` font-size="${B(c)}"` : "";
771
+ return `<mj-text align="${e.align}"${l}${u}${d}${o}${i} padding="${t}">${e.content}</mj-text>`;
773
772
  },
774
773
  renderPreview: (e) => {
775
- const t = e.fontFamily ? `font-family:${e.fontFamily};` : "", o = k(e.fontWeight), n = o !== "400" ? `font-weight:${o};` : "", i = String(e.lineHeight ?? "").trim(), l = i ? `line-height:${i};` : "line-height:normal;";
776
- return `<div class="sm-text-content" style="text-align:${e.align};color:${e.color};font-size:${e.fontSize};${l}${t}${n}padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;">${e.content}</div>`;
774
+ const t = e.fontFamily ? `font-family:${e.fontFamily};` : "", o = String(e.fontWeight ?? "").trim(), n = o ? `font-weight:${k(o)};` : "", i = String(e.lineHeight ?? "").trim(), r = i ? `line-height:${i};` : "line-height:normal;", d = String(e.color ?? "").trim(), a = d ? `color:${d};` : "", l = String(e.fontSize ?? "").trim(), c = l ? `font-size:${l};` : "";
775
+ return `<div class="sm-text-content" style="text-align:${e.align};${a}${c}${n}${r}${t}padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;">${e.content}</div>`;
777
776
  }
778
777
  }), ce = [
779
778
  ae,
@@ -781,7 +780,7 @@ ${d}
781
780
  Y,
782
781
  le,
783
782
  X,
784
- G,
783
+ q,
785
784
  K,
786
785
  re
787
786
  ], se = [Z, ie, J], ge = [...ce, ...se];
@@ -789,9 +788,9 @@ export {
789
788
  te as SOCIAL_NETWORK_OPTIONS,
790
789
  ge as allBlocks,
791
790
  ce as builtinBlocks,
792
- G as buttonBlock,
791
+ q as buttonBlock,
793
792
  K as dividerBlock,
794
- s as escAttr,
793
+ p as escAttr,
795
794
  ne as escMjmlText,
796
795
  se as exampleCustomBlocks,
797
796
  I as flexJustifyFromAlign,
@@ -806,7 +805,7 @@ export {
806
805
  ie as socialBlock,
807
806
  le as socialGroupBlock,
808
807
  V as socialIconBorderRadiusCss,
809
- W as socialIconBorderRadiusMjml,
808
+ N as socialIconBorderRadiusMjml,
810
809
  F as socialIconSpacingPx,
811
810
  P as socialMeta,
812
811
  re as spacerBlock,