mail-editor-pancake 0.0.8 → 0.1.0
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 +498 -218
- package/package.json +2 -2
- package/packages/blocks/dist/index.d.ts +12 -0
- package/packages/blocks/dist/index.js +187 -145
- package/packages/blocks/dist/index.js.map +1 -1
- package/packages/blocks/src/html.ts +11 -3
- package/packages/blocks/src/index.ts +2 -0
- package/packages/blocks/src/social.ts +8 -11
- package/packages/blocks/src/socialGroup.ts +8 -11
- package/packages/blocks/src/socialShared.ts +52 -0
- package/packages/blocks/src/text.ts +8 -3
- package/packages/core/dist/index.d.ts +275 -12
- package/packages/core/dist/index.js +4099 -2194
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/style.css +1 -1
- package/packages/core/package.json +1 -1
- package/packages/core/src/editor/BlockCodeModal.ts +84 -2
- package/packages/core/src/editor/Canvas.ts +191 -26
- package/packages/core/src/editor/Editor.ts +589 -76
- package/packages/core/src/editor/ExportModal.ts +1 -1
- package/packages/core/src/editor/ImportDocModal.ts +129 -0
- package/packages/core/src/editor/InlineEditor.ts +246 -22
- package/packages/core/src/editor/LeftPanel.ts +55 -14
- package/packages/core/src/editor/Modal.ts +20 -1
- package/packages/core/src/editor/PreviewModal.ts +2 -2
- package/packages/core/src/editor/RichTextToolbar.ts +125 -18
- package/packages/core/src/editor/RightPanel.ts +165 -7
- package/packages/core/src/editor/Topbar.ts +306 -132
- package/packages/core/src/editor/VariablePickerPanel.ts +145 -0
- package/packages/core/src/editor/styles.css +458 -59
- package/packages/core/src/index.ts +43 -2
- package/packages/core/src/renderer/index.ts +9 -1
- package/packages/core/src/renderer/mjml.ts +4 -5
- package/packages/core/src/store/store.ts +13 -2
- package/packages/core/src/types.ts +67 -2
- package/packages/core/src/utils/docClipboard.ts +89 -0
- package/packages/core/src/utils/dynamicVariantHtml.ts +45 -0
- package/packages/core/src/utils/dynamicVariantKey.ts +24 -0
- package/packages/core/src/utils/dynamicVariantSection.ts +98 -0
- package/packages/core/src/utils/emailListStyles.ts +188 -0
- package/packages/core/src/utils/inlineListEditing.ts +774 -0
- package/packages/core/src/utils/lockedMjml.ts +146 -12
- package/packages/core/src/utils/modalSize.ts +27 -0
- package/packages/core/src/utils/richHtmlEmpty.ts +43 -0
- package/packages/core/src/utils/richHtmlInsert.ts +16 -0
- package/packages/core/src/utils/sectionLayout.ts +2 -2
- package/packages/core/src/variables/index.ts +90 -0
- package/playground/vanilla/src/main.ts +26 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, normalizeFontWeightStep } from '@simple-mail/core';
|
|
1
|
+
import { defineBlock, FONT_WEIGHT_STEP_OPTIONS, isRichHtmlEffectivelyEmpty, normalizeFontWeightStep } from '@simple-mail/core';
|
|
2
2
|
import { icons } from './icons';
|
|
3
3
|
|
|
4
4
|
interface TextProps {
|
|
@@ -19,6 +19,8 @@ interface TextProps {
|
|
|
19
19
|
const escapeAttr = (s: string) =>
|
|
20
20
|
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
21
21
|
|
|
22
|
+
const TEXT_PLACEHOLDER = '输入文本…';
|
|
23
|
+
|
|
22
24
|
export const textBlock = defineBlock<TextProps>({
|
|
23
25
|
type: 'text',
|
|
24
26
|
name: '文本',
|
|
@@ -94,7 +96,7 @@ export const textBlock = defineBlock<TextProps>({
|
|
|
94
96
|
mode: 'rich',
|
|
95
97
|
multiline: true,
|
|
96
98
|
propKey: 'content',
|
|
97
|
-
placeholder:
|
|
99
|
+
placeholder: TEXT_PLACEHOLDER,
|
|
98
100
|
},
|
|
99
101
|
toMjml: (p) => {
|
|
100
102
|
const padding = `${p.paddingTop}px ${p.paddingRight}px ${p.paddingBottom}px ${p.paddingLeft}px`;
|
|
@@ -119,6 +121,9 @@ export const textBlock = defineBlock<TextProps>({
|
|
|
119
121
|
const colorCss = colorRaw ? `color:${colorRaw};` : '';
|
|
120
122
|
const fsRaw = String(p.fontSize ?? '').trim();
|
|
121
123
|
const fsCss = fsRaw ? `font-size:${fsRaw};` : '';
|
|
122
|
-
|
|
124
|
+
const empty = isRichHtmlEffectivelyEmpty(p.content);
|
|
125
|
+
const emptyClass = empty ? ' is-empty' : '';
|
|
126
|
+
const placeholderAttr = empty ? ` data-placeholder="${TEXT_PLACEHOLDER}"` : '';
|
|
127
|
+
return `<div class="sm-text-content${emptyClass}"${placeholderAttr} 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>`;
|
|
123
128
|
},
|
|
124
129
|
});
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 编译后为带 `dynamicVariantKey` 的 Section 根节点写入 `data-dv="{key}"`,供宿主 DOM 抽取。
|
|
3
|
+
*/
|
|
4
|
+
export declare function annotateDynamicVariantHtmlAttributes(html: string, doc: EmailDoc): string;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 向富文本 HTML 末尾「行内」追加内容,避免落在 `</p>` 外产生换行。
|
|
8
|
+
* 无块级标签时包一层 `<p style="margin:0;">`。
|
|
9
|
+
*/
|
|
10
|
+
export declare function appendInlineToRichHtml(html: string, insert: string): string;
|
|
11
|
+
|
|
1
12
|
/**
|
|
2
13
|
* Block 是注册表驱动的:所有内置/自定义组件都遵循同一个数据形状。
|
|
3
14
|
* 渲染、属性面板、代码模式三方都从注册表读取该 type 的定义。
|
|
@@ -22,8 +33,10 @@ export declare interface BlockDefinition<P extends object = Record<string, unkno
|
|
|
22
33
|
type: string;
|
|
23
34
|
/** 显示名(左栏) */
|
|
24
35
|
name: string;
|
|
25
|
-
/**
|
|
36
|
+
/** 分类,用于左栏分组与定制块角标 */
|
|
26
37
|
category: 'content' | 'custom';
|
|
38
|
+
/** 左栏卡片悬停提示;未设时 custom 类块使用 UI 默认后缀 */
|
|
39
|
+
paletteTooltip?: string;
|
|
27
40
|
/** 16x16 SVG 字符串 */
|
|
28
41
|
icon: string;
|
|
29
42
|
/** 默认 props(拖入时使用) */
|
|
@@ -49,7 +62,14 @@ export declare interface BlockDefinition<P extends object = Record<string, unkno
|
|
|
49
62
|
* 用于「组合模板」:画布内仅为通用 image/text 等,便于逐项修改。
|
|
50
63
|
* 文档里不会出现本定义的 `type`,仅作左栏入口;若需提供请返回内置块的实例。
|
|
51
64
|
*/
|
|
52
|
-
expandPaletteDrop?: (createBlock: (type: string) => Block) => Block[];
|
|
65
|
+
expandPaletteDrop?: (createBlock: (type: string) => Block) => Block[] | PaletteDropResult;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
declare interface BlockPaddingBox {
|
|
69
|
+
top: number;
|
|
70
|
+
right: number;
|
|
71
|
+
bottom: number;
|
|
72
|
+
left: number;
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
export declare interface BlockSchemaField {
|
|
@@ -76,6 +96,28 @@ export declare interface BlockSchemaField {
|
|
|
76
96
|
inheritGlobal?: boolean;
|
|
77
97
|
}
|
|
78
98
|
|
|
99
|
+
export declare interface BodyVariableInsert {
|
|
100
|
+
content: string;
|
|
101
|
+
asHtml: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** 插入链接 / 图片等元素片段 */
|
|
105
|
+
export declare function buildBodyVariableElementInsert(v: Variable, options?: {
|
|
106
|
+
linkColor?: string;
|
|
107
|
+
token?: string;
|
|
108
|
+
}): BodyVariableInsert;
|
|
109
|
+
|
|
110
|
+
/** @deprecated 使用 buildBodyVariableKeyInsert / buildBodyVariableElementInsert */
|
|
111
|
+
export declare function buildBodyVariableInsert(v: Variable, options?: {
|
|
112
|
+
linkColor?: string;
|
|
113
|
+
token?: string;
|
|
114
|
+
}): BodyVariableInsert;
|
|
115
|
+
|
|
116
|
+
/** 插入变量 key(`{{key}}`) */
|
|
117
|
+
export declare function buildBodyVariableKeyInsert(v: Variable): BodyVariableInsert;
|
|
118
|
+
|
|
119
|
+
export declare function buildLinkVariableHtml(token: string, linkColor: string): string;
|
|
120
|
+
|
|
79
121
|
export declare interface Column {
|
|
80
122
|
id: string;
|
|
81
123
|
attrs: ColumnAttrs;
|
|
@@ -89,14 +131,28 @@ declare interface ColumnAttrs {
|
|
|
89
131
|
|
|
90
132
|
export declare function createSection(layout: SectionLayout): Section;
|
|
91
133
|
|
|
134
|
+
/** 无显式 sample 时保留 Mustache 占位符;仅当宿主传入 sample 才用于可选的示例替换。 */
|
|
135
|
+
export declare function defaultVariableSample(v: Pick<Variable, 'key' | 'label' | 'kind' | 'sample'>): string;
|
|
136
|
+
|
|
92
137
|
/** 工厂函数,便于外部以函数式风格定义组件。 */
|
|
93
138
|
export declare function defineBlock<P extends object>(def: BlockDefinition<P>): BlockDefinition<P>;
|
|
94
139
|
|
|
140
|
+
export declare const DOC_CLIPBOARD_FORMAT_VERSION: 1;
|
|
141
|
+
|
|
142
|
+
/** 剪贴板 / 文件 interchange 信封标识 */
|
|
143
|
+
export declare const DOC_CLIPBOARD_KIND: "simple-mail/doc";
|
|
144
|
+
|
|
95
145
|
/** 文档变更通知来源(右栏等可按来源决定是否保留焦点) */
|
|
96
146
|
declare type DocChangedDetail = {
|
|
97
147
|
source: 'mutate' | 'history' | 'replace';
|
|
98
148
|
};
|
|
99
149
|
|
|
150
|
+
export declare interface DocClipboardEnvelope {
|
|
151
|
+
kind: typeof DOC_CLIPBOARD_KIND;
|
|
152
|
+
formatVersion: typeof DOC_CLIPBOARD_FORMAT_VERSION;
|
|
153
|
+
doc: EmailDoc;
|
|
154
|
+
}
|
|
155
|
+
|
|
100
156
|
/**
|
|
101
157
|
* 内容区 / 按钮等「布局宽度」解析:数字与无单位数字按 px;支持显式 `px` 与 `%`。
|
|
102
158
|
*/
|
|
@@ -111,6 +167,13 @@ export declare function docContentWidthCss(raw: unknown): string;
|
|
|
111
167
|
*/
|
|
112
168
|
export declare function docToMjml(doc: EmailDoc, registry: Registry): string;
|
|
113
169
|
|
|
170
|
+
/**
|
|
171
|
+
* 导出 HTML 上标记动态变量组合的宿主约定属性名(值为 `Section.attrs.dynamicVariantKey`)。
|
|
172
|
+
*/
|
|
173
|
+
export declare const DYNAMIC_VARIANT_HTML_ATTR = "data-dv";
|
|
174
|
+
|
|
175
|
+
export declare function dynamicVariantPlaceholder(key: string): string;
|
|
176
|
+
|
|
114
177
|
export declare interface EditorEvents {
|
|
115
178
|
change: {
|
|
116
179
|
doc: EmailDoc;
|
|
@@ -205,6 +268,45 @@ export declare interface EditorUiOptions {
|
|
|
205
268
|
hideTopbarClearCanvas?: boolean;
|
|
206
269
|
/** 为 true 时隐藏顶栏「重置内容」按钮。 */
|
|
207
270
|
hideTopbarResetContent?: boolean;
|
|
271
|
+
/** 为 true 时隐藏顶栏「复制设计稿」「导入设计稿」按钮。 */
|
|
272
|
+
hideTopbarDocClipboard?: boolean;
|
|
273
|
+
/** 为 true 时隐藏顶栏「插入变量」按钮(由宿主在编辑器外提供时可用)。 */
|
|
274
|
+
hideTopbarInsertVariable?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* 为 true 时顶栏默认可切换为仅图标(文案收入 `title` / `aria-label`),适合窄屏或嵌入宿主。
|
|
277
|
+
* 默认 false;嵌入场景可在宿主侧设为 true。
|
|
278
|
+
*/
|
|
279
|
+
topbarCompact?: boolean;
|
|
280
|
+
/**
|
|
281
|
+
* 顶栏按钮文案展示策略(在 `topbarCompact === true` 时生效)。
|
|
282
|
+
* - `auto`(默认):仅图标;根节点进入浏览器全屏或宽度 ≥ `topbarCompactMinWidth` 时展示文案。
|
|
283
|
+
* - `never`:始终仅图标(含全屏与宽屏)。
|
|
284
|
+
* - `always`:始终展示图标旁文案(等同不启用紧凑顶栏)。
|
|
285
|
+
*/
|
|
286
|
+
topbarLabels?: 'always' | 'never' | 'auto';
|
|
287
|
+
/**
|
|
288
|
+
* `topbarLabels: 'auto'` 时,根节点宽度不低于该值(px)则展示顶栏文案。默认 1200。
|
|
289
|
+
*/
|
|
290
|
+
topbarCompactMinWidth?: number;
|
|
291
|
+
/**
|
|
292
|
+
* @deprecated 左栏已合并为单组,请用 `paletteBlockGroupTitle`。
|
|
293
|
+
* 仍兼容:仅 `content` 键会作为合并后分组标题的回退。
|
|
294
|
+
*/
|
|
295
|
+
blockCategoryLabels?: Partial<Record<BlockDefinition['category'], string>>;
|
|
296
|
+
/** 左栏合并后的组件分组标题,默认「组件」。 */
|
|
297
|
+
paletteBlockGroupTitle?: string;
|
|
298
|
+
/** custom 类块无 `paletteTooltip` 时拼入 title 的说明后缀。 */
|
|
299
|
+
customPaletteTooltipSuffix?: string;
|
|
300
|
+
/**
|
|
301
|
+
* 仍注册、渲染、可被 palette 展开引用,但不显示在左栏的 block type(如组合块内部用的 divider)。
|
|
302
|
+
*/
|
|
303
|
+
hiddenPaletteBlockTypes?: string[];
|
|
304
|
+
/**
|
|
305
|
+
* 为 true 时:右栏 Section 可配置「动态变量名」、画布展示动态变量节标识,
|
|
306
|
+
* 左栏拖入带 `sectionAttrs.dynamicVariantKey` 的组合块会创建动态变量 Section。
|
|
307
|
+
* 默认 false;宿主(如后管)按需开启。已写入文档的 key 仍会在导出时生效。
|
|
308
|
+
*/
|
|
309
|
+
enableDynamicVariantKey?: boolean;
|
|
208
310
|
}
|
|
209
311
|
|
|
210
312
|
/**
|
|
@@ -231,6 +333,22 @@ export declare interface EmailMeta {
|
|
|
231
333
|
width: number | string;
|
|
232
334
|
}
|
|
233
335
|
|
|
336
|
+
/**
|
|
337
|
+
* 将带 `dynamicVariantKey` 的 Section 从全文 HTML 中替换为占位符,并返回各 key 的编译 HTML。
|
|
338
|
+
* 优先使用导出 HTML 上的 `data-dv="{key}"` 标记。
|
|
339
|
+
*/
|
|
340
|
+
export declare function extractDynamicVariantSlots(html: string, doc: EmailDoc, registry: Registry): ExtractDynamicVariantSlotsResult;
|
|
341
|
+
|
|
342
|
+
export declare interface ExtractDynamicVariantSlotsResult {
|
|
343
|
+
html: string;
|
|
344
|
+
variants: Record<string, string>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* 从锁定 MJML 片段提取可在画布内渲染的 HTML;无法识别时返回 null(回退源码视图)。
|
|
349
|
+
*/
|
|
350
|
+
export declare function extractPreviewHtmlFromLockedMjml(lockedMjml: string): string | null;
|
|
351
|
+
|
|
234
352
|
export declare function findBlockLocation(doc: EmailDoc, blockId: string): {
|
|
235
353
|
section: Section;
|
|
236
354
|
columnIndex: number;
|
|
@@ -258,6 +376,9 @@ export declare interface GalleryItem {
|
|
|
258
376
|
title?: string;
|
|
259
377
|
}
|
|
260
378
|
|
|
379
|
+
/** 本节导出后替换为 `{{dynamicVariantKey}}`,内容由宿主写入 dynamicVariant */
|
|
380
|
+
export declare function getSectionDynamicVariantKey(section: Section): string | undefined;
|
|
381
|
+
|
|
261
382
|
export declare interface GlobalStyles {
|
|
262
383
|
backgroundColor: string;
|
|
263
384
|
contentBackgroundColor: string;
|
|
@@ -269,8 +390,16 @@ export declare interface GlobalStyles {
|
|
|
269
390
|
linkColor: string;
|
|
270
391
|
/** 无单位倍数(如 1.25)或固定值(如 24px) */
|
|
271
392
|
lineHeight: string;
|
|
393
|
+
/**
|
|
394
|
+
* 未单独设置缩进的列表使用的全局左缩进(px)。
|
|
395
|
+
* 不设时等价于内置默认 24px。
|
|
396
|
+
*/
|
|
397
|
+
listIndentDefaultPx?: number;
|
|
272
398
|
}
|
|
273
399
|
|
|
400
|
+
/** HTML 块内容是否误含 MJML 标签(应只写 HTML,MJML 标签在 mj-raw 内不会被编译)。 */
|
|
401
|
+
export declare function htmlContainsMjmlTags(html: string): boolean;
|
|
402
|
+
|
|
274
403
|
export declare interface ImageAssetsHandlers {
|
|
275
404
|
/**
|
|
276
405
|
* 用户点击右侧「上传」并选择本地文件。宿主完成上传后返回 **绝对 HTTPS URL**。
|
|
@@ -346,6 +475,17 @@ declare interface InlineEditableConfig<P extends object = Record<string, unknown
|
|
|
346
475
|
placeholder?: string;
|
|
347
476
|
}
|
|
348
477
|
|
|
478
|
+
export declare function isDynamicVariantSection(section: Section): boolean;
|
|
479
|
+
|
|
480
|
+
export declare function isMultiColumnLayout(layout: SectionLayout): layout is MultiColumnLayout;
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* 富文本是否「完全无内容」。
|
|
484
|
+
* 空格、 、换行(<br>)均视为有效内容;仅空串或空标签壳子算空。
|
|
485
|
+
*/
|
|
486
|
+
export declare function isRichHtmlEffectivelyEmpty(html: string): boolean;
|
|
487
|
+
|
|
488
|
+
/** @deprecated 使用 isMultiColumnLayout */
|
|
349
489
|
export declare function isTwoColumnLayout(layout: SectionLayout): layout is TwoColumnLayout;
|
|
350
490
|
|
|
351
491
|
declare type Listener = (detail?: DocChangedDetail) => void;
|
|
@@ -376,6 +516,10 @@ export declare class MailEditor {
|
|
|
376
516
|
private sourceView;
|
|
377
517
|
private toolbar;
|
|
378
518
|
private body;
|
|
519
|
+
/** 浮层(变量列表、toast),避免挂到 grid 的 .sm-root 上被挤成窄条 */
|
|
520
|
+
private overlayLayer;
|
|
521
|
+
/** design 态右栏变量列表:未固定时点击外部收起 */
|
|
522
|
+
private variablePickerOutsideClick;
|
|
379
523
|
private changeTimer;
|
|
380
524
|
/** 显式品牌色时覆盖 CSS 变量;未设置则由 styles 按 light/dark 使用默认紫/靛 */
|
|
381
525
|
private accentColorOverride;
|
|
@@ -383,16 +527,27 @@ export declare class MailEditor {
|
|
|
383
527
|
private showLayoutBorders;
|
|
384
528
|
/** 「重置内容」时恢复的文档快照(与当前画布内容无关) */
|
|
385
529
|
private presetContentDoc;
|
|
530
|
+
/** 宿主通过 setVariables 注入的列表;setValue 恢复文档后仍会写回,避免被 doc JSON 里的空数组覆盖 */
|
|
531
|
+
private configuredVariables;
|
|
532
|
+
private importDocModal;
|
|
533
|
+
private topbarLayoutObserver;
|
|
534
|
+
private topbarLayoutRaf;
|
|
386
535
|
private systemThemeMq;
|
|
387
536
|
private readonly _onSystemThemeMqChange;
|
|
388
537
|
private readonly _onFullscreenChange;
|
|
389
538
|
/** design 态 Esc:块 → 父级 Section → 文档级面板(邮件设置或版式/全局样式,取决于 `ui.hideMailMeta`) */
|
|
390
539
|
private _mailEscHandler;
|
|
391
540
|
/**
|
|
392
|
-
*
|
|
393
|
-
*
|
|
541
|
+
* 文档级撤销/重做(捕获阶段)。
|
|
542
|
+
* - 画布内联 contenteditable:交给浏览器撤销文字,不走 store。
|
|
543
|
+
* - 右栏 input / CodeMirror:控件自带撤销,不走 store。
|
|
544
|
+
* - 其余区域:在 store 有历史时拦截并 undo/redo 整份文档。
|
|
394
545
|
*/
|
|
395
546
|
private _mailUndoRedoHandler;
|
|
547
|
+
/** 内联编辑、右栏表单等应使用控件/浏览器本地撤销,而非文档 history */
|
|
548
|
+
private _shouldDeferToLocalUndoRedo;
|
|
549
|
+
private _storeUndo;
|
|
550
|
+
private _storeRedo;
|
|
396
551
|
constructor(opts: EditorOptions);
|
|
397
552
|
setValue(doc: EmailDoc): void;
|
|
398
553
|
getValue(): EmailDoc;
|
|
@@ -401,12 +556,28 @@ export declare class MailEditor {
|
|
|
401
556
|
* 会提交内联编辑并清空选中。
|
|
402
557
|
*/
|
|
403
558
|
clearCanvas(): void;
|
|
404
|
-
/**
|
|
559
|
+
/**
|
|
560
|
+
* 将画布恢复为 `presetDoc` 快照(未传时等同构造时的预置合并结果)。
|
|
561
|
+
* 记入撤销栈(⌘Z 可恢复);与 `setValue` 不同,不会清空 history。
|
|
562
|
+
*/
|
|
405
563
|
resetToPreset(): void;
|
|
406
564
|
/** 更新「重置内容」的目标(例如宿主异步加载默认模板后)。 */
|
|
407
565
|
setPresetDoc(partial: Partial<EmailDoc>): void;
|
|
408
566
|
setVariables(vars: Variable[]): void;
|
|
409
567
|
getVariables(): Variable[];
|
|
568
|
+
private _applyConfiguredVariables;
|
|
569
|
+
/**
|
|
570
|
+
* 插入变量 key(`{{key}}`)。
|
|
571
|
+
* @returns 是否成功插入
|
|
572
|
+
*/
|
|
573
|
+
insertVariableKey(v: Variable): boolean;
|
|
574
|
+
/**
|
|
575
|
+
* 插入链接 / 图片变量对应元素(`<a>` / image 块等)。
|
|
576
|
+
* 非 link/image 时退化为 insertVariableKey。
|
|
577
|
+
*/
|
|
578
|
+
insertVariableElement(v: Variable): boolean;
|
|
579
|
+
/** 同 {@link insertVariableKey} */
|
|
580
|
+
insertVariable(v: Variable): boolean;
|
|
410
581
|
/** 当前界面主题(`system` 不解析为 light/dark)。 */
|
|
411
582
|
getTheme(): EditorTheme;
|
|
412
583
|
/** 切换界面主题;写入 `data-sm-theme`,顶栏选择器同步。 */
|
|
@@ -421,6 +592,17 @@ export declare class MailEditor {
|
|
|
421
592
|
export(opts?: {
|
|
422
593
|
withSampleVariables?: boolean;
|
|
423
594
|
}): RenderResult;
|
|
595
|
+
/**
|
|
596
|
+
* 将当前画布设计稿(EmailDoc JSON 信封)写入剪贴板,供另一实例「导入设计稿」使用。
|
|
597
|
+
*/
|
|
598
|
+
copyDocDesign(): Promise<boolean>;
|
|
599
|
+
/** 打开导入设计稿对话框(从剪贴板或手动粘贴 JSON,覆盖当前画布)。 */
|
|
600
|
+
openImportDocDesign(): void;
|
|
601
|
+
/**
|
|
602
|
+
* 程序化导入设计稿(与对话框「应用」相同逻辑)。
|
|
603
|
+
* @returns 是否成功解析并应用
|
|
604
|
+
*/
|
|
605
|
+
importDocDesignFromJson(raw: string): boolean;
|
|
424
606
|
registerBlock<P extends object>(def: BlockDefinition<P>): void;
|
|
425
607
|
setSelection(sel: Selection_2 | null): void;
|
|
426
608
|
destroy(): void;
|
|
@@ -436,15 +618,36 @@ export declare class MailEditor {
|
|
|
436
618
|
private _blurRightPanelIfFocused;
|
|
437
619
|
/** 提交内联编辑并清空选中,右栏回到文档级面板 */
|
|
438
620
|
private _focusMailSettings;
|
|
439
|
-
private _confirmClearCanvas;
|
|
440
|
-
private _confirmResetContent;
|
|
441
621
|
private _setMode;
|
|
442
622
|
private _bindKeyboard;
|
|
443
623
|
private _onChange;
|
|
444
|
-
private
|
|
445
|
-
private
|
|
624
|
+
private _unbindVariablePickerOutsideClick;
|
|
625
|
+
private _bindVariablePickerOutsideClick;
|
|
626
|
+
private _closeVariablePicker;
|
|
627
|
+
private _toggleVariablePanel;
|
|
628
|
+
private _dismissVariablePopover;
|
|
629
|
+
/** 源码模式无右栏时仍用浮层选择变量 */
|
|
630
|
+
private _toggleVariablePopover;
|
|
631
|
+
private _showToast;
|
|
632
|
+
private _insertImageVariable;
|
|
633
|
+
/**
|
|
634
|
+
* 按当前选中插入块:block → 其后;section → 该 section 首列末尾;无选中 → 文档最后一节首列末尾。
|
|
635
|
+
*/
|
|
636
|
+
private _insertBlockRelativeToSelection;
|
|
637
|
+
/** 链接变量:写入图片/按钮等块的 `href`(MJML 可点击),而非 alt 或右栏纯文本。 */
|
|
638
|
+
private _tryApplyLinkVariableToken;
|
|
639
|
+
private _schemaUrlPropKey;
|
|
640
|
+
private _setBlockUrlProp;
|
|
641
|
+
/** 在焦点处插入文本或 HTML;失败时返回 false */
|
|
642
|
+
private _insertAtFocus;
|
|
643
|
+
private _ensureImportDocModal;
|
|
644
|
+
private _applyImportedDoc;
|
|
446
645
|
private _showExport;
|
|
447
646
|
private _showPreview;
|
|
647
|
+
private _topbarLayoutContext;
|
|
648
|
+
private _syncTopbarLayout;
|
|
649
|
+
private _bindTopbarLayoutWatch;
|
|
650
|
+
private _unbindTopbarLayoutWatch;
|
|
448
651
|
private _bindFullscreen;
|
|
449
652
|
private _unbindFullscreen;
|
|
450
653
|
private _toggleFullscreen;
|
|
@@ -475,9 +678,20 @@ export declare function mjRawCellTypographyFromStyles(s: GlobalStyles): MjRawCel
|
|
|
475
678
|
*/
|
|
476
679
|
export declare function mjRawEmailTableWrap(paddingCss: string, cellInnerHtml: string, typo: MjRawCellTypography): string;
|
|
477
680
|
|
|
681
|
+
/** 多列 Section 的列布局(左栏拖入默认 `1-1`,右栏可切换列数/比例) */
|
|
682
|
+
export declare const MULTI_COLUMN_LAYOUTS: readonly ["1-1", "1-2", "2-1", "1-1-1"];
|
|
683
|
+
|
|
684
|
+
export declare type MultiColumnLayout = (typeof MULTI_COLUMN_LAYOUTS)[number];
|
|
685
|
+
|
|
478
686
|
/** 将任意历史写法映射到最近一档(normal→400,bold→700 等) */
|
|
479
687
|
export declare function normalizeFontWeightStep(raw: string | undefined | null): FontWeightStep;
|
|
480
688
|
|
|
689
|
+
/** 提交前:完全无内容时统一为 '' */
|
|
690
|
+
export declare function normalizeRichHtmlForCommit(html: string): string;
|
|
691
|
+
|
|
692
|
+
/** 规范化 Variable(补 kind、sample) */
|
|
693
|
+
export declare function normalizeVariable(v: Variable): Variable;
|
|
694
|
+
|
|
481
695
|
/**
|
|
482
696
|
* 打开内置图库弹层:搜索、分页、选图插入;可选「链接添加」「上传到图库」「删除」由 adapter 决定。
|
|
483
697
|
*/
|
|
@@ -491,6 +705,17 @@ export declare interface OpenImageGalleryModalOptions {
|
|
|
491
705
|
onClose?: () => void;
|
|
492
706
|
}
|
|
493
707
|
|
|
708
|
+
/** 左栏组合拖入:可附带新建 Section 的 attrs(如 meta 扩展袋) */
|
|
709
|
+
export declare interface PaletteDropResult {
|
|
710
|
+
blocks: Block[];
|
|
711
|
+
sectionAttrs?: Partial<SectionAttrs>;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* 解析剪贴板或手动粘贴的 JSON。支持信封格式与裸 `EmailDoc`(version: '1')。
|
|
716
|
+
*/
|
|
717
|
+
export declare function parseDocClipboard(raw: string): EmailDoc | null;
|
|
718
|
+
|
|
494
719
|
/** 右栏输入解析存库:纯整数可存 number,其它存 string */
|
|
495
720
|
export declare function parseMetaWidthFromUserInput(input: string): number | string;
|
|
496
721
|
|
|
@@ -508,6 +733,9 @@ export declare function pruneEmptySections(draft: EmailDoc): void;
|
|
|
508
733
|
*/
|
|
509
734
|
export declare function pruneSectionIfEmpty(draft: EmailDoc, sectionId: string): void;
|
|
510
735
|
|
|
736
|
+
/** 导入前重生成 section / column / block id,避免与当前文档冲突。 */
|
|
737
|
+
export declare function regenerateDocIds(doc: EmailDoc): EmailDoc;
|
|
738
|
+
|
|
511
739
|
/**
|
|
512
740
|
* 组件注册表。所有内置/自定义组件都通过 `defineBlock` 注册进来;
|
|
513
741
|
* 渲染、属性面板、左栏拖拽源、组件级代码模式四方都从这里读取。
|
|
@@ -538,7 +766,8 @@ declare interface RenderOptions {
|
|
|
538
766
|
/** 渲染引擎,目前仅 'mjml';'table' 预留作将来直输 table HTML。 */
|
|
539
767
|
engine?: RenderEngine;
|
|
540
768
|
/**
|
|
541
|
-
* 是否把 {{var}}
|
|
769
|
+
* 是否把 {{var}} 替换为变量的 sample 值。
|
|
770
|
+
* 设计态预览默认不替换,保持占位符;仅当变量显式配置了 sample 且调用方传 true 时才替换。
|
|
542
771
|
*/
|
|
543
772
|
withSampleVariables?: boolean;
|
|
544
773
|
}
|
|
@@ -551,12 +780,24 @@ declare interface RenderResult {
|
|
|
551
780
|
}[];
|
|
552
781
|
}
|
|
553
782
|
|
|
783
|
+
/** 仅编译某一 Section,返回邮件 body 内 HTML 片段 */
|
|
784
|
+
export declare function renderSectionBodyHtml(doc: EmailDoc, sectionId: string, registry: Registry): string;
|
|
785
|
+
|
|
554
786
|
/**
|
|
555
787
|
* 用 sample 值替换 `{{var.name}}` 占位符。仅做最简单的字符串替换,
|
|
556
788
|
* 不做任何沙箱式表达式求值(邮件场景里下游模板引擎会再处理一次)。
|
|
557
789
|
*/
|
|
558
790
|
export declare function replaceVariables(text: string, vars: Variable[]): string;
|
|
559
791
|
|
|
792
|
+
/** 锁定块在画布上的渲染结果:preview 为 WYSIWYG HTML,source 为无法解析时的源码回退。 */
|
|
793
|
+
export declare function resolveLockedMjmlCanvasContent(lockedMjml: string, padding: BlockPaddingBox): {
|
|
794
|
+
mode: 'preview';
|
|
795
|
+
html: string;
|
|
796
|
+
} | {
|
|
797
|
+
mode: 'source';
|
|
798
|
+
source: string;
|
|
799
|
+
};
|
|
800
|
+
|
|
560
801
|
export declare interface Section {
|
|
561
802
|
id: string;
|
|
562
803
|
type: 'section';
|
|
@@ -585,10 +826,21 @@ export declare interface SectionAttrs {
|
|
|
585
826
|
* 本节内容区最大宽度(窄于邮件 `meta.width` 时居中)。支持 `480`、`480px`、`90%`;留空则与邮件同宽。
|
|
586
827
|
*/
|
|
587
828
|
width?: string | number;
|
|
829
|
+
/**
|
|
830
|
+
* 动态变量组合:设置后本节编译结果在导出时替换为 `{{dynamicVariantKey}}`;
|
|
831
|
+
* 具体存贮与业务含义由宿主处理(如券包 couponGroup)。
|
|
832
|
+
*/
|
|
833
|
+
dynamicVariantKey?: string;
|
|
834
|
+
/**
|
|
835
|
+
* 宿主扩展元数据;编辑器不解释、不参与 MJML 编译,仅随 EmailDoc 序列化。
|
|
836
|
+
*/
|
|
837
|
+
meta?: Record<string, unknown>;
|
|
588
838
|
}
|
|
589
839
|
|
|
590
840
|
export declare type SectionLayout = '1' | '1-1' | '1-2' | '2-1' | '1-1-1';
|
|
591
841
|
|
|
842
|
+
export declare function sectionMjClassName(sectionId: string): string;
|
|
843
|
+
|
|
592
844
|
export declare function sectionWidthInputString(raw: unknown): string;
|
|
593
845
|
|
|
594
846
|
declare type Selection_2 = {
|
|
@@ -604,7 +856,9 @@ export { Selection_2 as Selection }
|
|
|
604
856
|
|
|
605
857
|
declare type SelectionListener = () => void;
|
|
606
858
|
|
|
607
|
-
|
|
859
|
+
export declare function serializeDocClipboard(doc: EmailDoc): string;
|
|
860
|
+
|
|
861
|
+
/** 更新 layout;列数变化时增删列,被删列内块并入最后一列 */
|
|
608
862
|
export declare function setSectionLayout(section: Section, layout: SectionLayout): void;
|
|
609
863
|
|
|
610
864
|
/**
|
|
@@ -643,7 +897,10 @@ export declare class Store {
|
|
|
643
897
|
private _notify;
|
|
644
898
|
}
|
|
645
899
|
|
|
646
|
-
/**
|
|
900
|
+
/** 从 Mustache token 提取 key,如 `{{username}}` → `username` */
|
|
901
|
+
export declare function tokenToVariableKey(token: string): string;
|
|
902
|
+
|
|
903
|
+
/** @deprecated 使用 MULTI_COLUMN_LAYOUTS */
|
|
647
904
|
export declare const TWO_COLUMN_LAYOUTS: readonly ["1-1", "1-2", "2-1"];
|
|
648
905
|
|
|
649
906
|
export declare type TwoColumnLayout = (typeof TWO_COLUMN_LAYOUTS)[number];
|
|
@@ -654,6 +911,12 @@ export declare interface Variable {
|
|
|
654
911
|
label: string;
|
|
655
912
|
/** 预览数据,仅设计态预览使用 */
|
|
656
913
|
sample?: string;
|
|
914
|
+
/** 插入语义:纯文本占位 / 链接片段 / 图片块 */
|
|
915
|
+
kind?: 'text' | 'link' | 'image';
|
|
657
916
|
}
|
|
658
917
|
|
|
918
|
+
export declare type VariableKind = 'text' | 'link' | 'image';
|
|
919
|
+
|
|
920
|
+
export declare function variablePlaceholder(key: string): string;
|
|
921
|
+
|
|
659
922
|
export { }
|