@marlinjai/email-editor-core 0.2.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/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/TemplateModel-Dq4GoWpl.d.mts +14743 -0
- package/dist/TemplateModel-Dq4GoWpl.d.ts +14743 -0
- package/dist/TemplateModel-v__r5Nvi.d.mts +8786 -0
- package/dist/TemplateModel-v__r5Nvi.d.ts +8786 -0
- package/dist/chunk-2ZL7A2I6.mjs +1029 -0
- package/dist/chunk-MBTNU2JZ.mjs +395 -0
- package/dist/index.d.mts +35664 -0
- package/dist/index.d.ts +35664 -0
- package/dist/index.js +3299 -0
- package/dist/index.mjs +2287 -0
- package/dist/server.d.mts +341 -0
- package/dist/server.d.ts +341 -0
- package/dist/server.js +2492 -0
- package/dist/server.mjs +1966 -0
- package/package.json +73 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { E as EmailTemplate, y as CompileResult, a4 as TemplateInstance } from './TemplateModel-v__r5Nvi.mjs';
|
|
2
|
+
import 'mobx-state-tree';
|
|
3
|
+
|
|
4
|
+
/** The `<mj-attributes>` a document gets unless it brings its own (`metadata.mjmlHead.attributes`). */
|
|
5
|
+
declare const DEFAULT_MJML_ATTRIBUTES = "\n <mj-all font-family=\"Georgia, serif\" />\n <mj-text font-size=\"14px\" line-height=\"1.6\" />\n ";
|
|
6
|
+
/** Marks the editor's own raw markup so the MJML import can read the block back exactly. */
|
|
7
|
+
declare const EDITOR_DATA_ATTRIBUTE: {
|
|
8
|
+
readonly social: "data-ee-social";
|
|
9
|
+
readonly subColumns: "data-ee-subcols";
|
|
10
|
+
};
|
|
11
|
+
/** A block's (or sub-columns') JSON, base64-encoded, for an {@link EDITOR_DATA_ATTRIBUTE}. */
|
|
12
|
+
declare function encodeEditorData(value: unknown): string;
|
|
13
|
+
/** Options for one {@link MJMLCompiler.compile} call. */
|
|
14
|
+
interface CompileOptions {
|
|
15
|
+
/**
|
|
16
|
+
* MJML adds a Google Fonts `<link>` and `@import` on its own whenever a font
|
|
17
|
+
* family it knows (Open Sans, Droid Sans, Lato, Roboto, Ubuntu) appears in
|
|
18
|
+
* the document. `false` leaves them out, so the font falls back to the rest
|
|
19
|
+
* of its stack and the mail loads nothing from Google. Fonts the document
|
|
20
|
+
* declares itself (`metadata.fonts`) are always emitted. Default `true`.
|
|
21
|
+
*/
|
|
22
|
+
webFonts?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* MJML Compiler class
|
|
26
|
+
* Converts EmailTemplate to MJML markup and compiles to HTML
|
|
27
|
+
*/
|
|
28
|
+
declare class MJMLCompiler {
|
|
29
|
+
/**
|
|
30
|
+
* Set true while emitting a column with sub-columns. Causes generateHead
|
|
31
|
+
* to inject the responsive media query exactly once per template.
|
|
32
|
+
*/
|
|
33
|
+
private needsSubColumnStyles;
|
|
34
|
+
/**
|
|
35
|
+
* Compile email template to MJML and HTML
|
|
36
|
+
*/
|
|
37
|
+
compile(template: EmailTemplate, options?: CompileOptions): CompileResult;
|
|
38
|
+
/**
|
|
39
|
+
* The MJML markup for a document, without compiling it to HTML.
|
|
40
|
+
*/
|
|
41
|
+
toMJML(template: EmailTemplate): string;
|
|
42
|
+
/**
|
|
43
|
+
* Convert template to MJML markup
|
|
44
|
+
*/
|
|
45
|
+
private templateToMJML;
|
|
46
|
+
/**
|
|
47
|
+
* Generate MJML head section with all head components
|
|
48
|
+
* Supports: mj-title, mj-preview, mj-font, mj-breakpoint, mj-style
|
|
49
|
+
*/
|
|
50
|
+
private generateHead;
|
|
51
|
+
/**
|
|
52
|
+
* Collect background-image CSS rules for all wrappers, sections and columns that have gradients.
|
|
53
|
+
* Returns a string of CSS rules to inject as a single mj-style block.
|
|
54
|
+
*/
|
|
55
|
+
private collectGradientStyles;
|
|
56
|
+
/**
|
|
57
|
+
* Convert a wrapper to an `<mj-wrapper>` around its sections. The wrapper's
|
|
58
|
+
* attributes are MJML's own for `mj-wrapper`; the sections inside follow
|
|
59
|
+
* MJML's rules there (a full-width section inside a full-width wrapper
|
|
60
|
+
* renders at standard width, which the inspector explains).
|
|
61
|
+
*/
|
|
62
|
+
private wrapperToMJML;
|
|
63
|
+
/** Background attributes shared by sections and wrappers: a gradient (with its Outlook fallback colour), or colour and image. */
|
|
64
|
+
private pushBackground;
|
|
65
|
+
/**
|
|
66
|
+
* Convert section to MJML
|
|
67
|
+
* Supports background images, full-width, and mj-group for non-stacking columns
|
|
68
|
+
*/
|
|
69
|
+
private sectionToMJML;
|
|
70
|
+
/**
|
|
71
|
+
* Convert column to MJML
|
|
72
|
+
*/
|
|
73
|
+
private columnToMJML;
|
|
74
|
+
/**
|
|
75
|
+
* Emit a group column as an mj-column wrapping a hand-built nested
|
|
76
|
+
* table inside an mj-raw island. The parent mj-section structure
|
|
77
|
+
* stays standard MJML; only the nested area escapes MJML's parser.
|
|
78
|
+
*
|
|
79
|
+
* The responsive media query (table.ee-sub-cols td.ee-sub-col) is
|
|
80
|
+
* injected once at document head via generateHead when the
|
|
81
|
+
* needsSubColumnStyles flag is set.
|
|
82
|
+
*/
|
|
83
|
+
private subColumnsToMJML;
|
|
84
|
+
/**
|
|
85
|
+
* Convert block to MJML based on type
|
|
86
|
+
*/
|
|
87
|
+
private blockToMJML;
|
|
88
|
+
/**
|
|
89
|
+
* Convert text block to MJML
|
|
90
|
+
*
|
|
91
|
+
* Note: MJML applies styles to the container <td>, but TipTap content
|
|
92
|
+
* (wrapped in <p> tags) doesn't inherit these styles. We solve this by
|
|
93
|
+
* wrapping the content in a <div> with explicit inline styles.
|
|
94
|
+
*/
|
|
95
|
+
private textBlockToMJML;
|
|
96
|
+
/**
|
|
97
|
+
* Convert image block to MJML
|
|
98
|
+
*/
|
|
99
|
+
private imageBlockToMJML;
|
|
100
|
+
/**
|
|
101
|
+
* Convert button block to MJML
|
|
102
|
+
*/
|
|
103
|
+
private buttonBlockToMJML;
|
|
104
|
+
/**
|
|
105
|
+
* Convert divider block to MJML
|
|
106
|
+
*/
|
|
107
|
+
private dividerBlockToMJML;
|
|
108
|
+
/**
|
|
109
|
+
* Convert spacer block to MJML
|
|
110
|
+
*/
|
|
111
|
+
private spacerBlockToMJML;
|
|
112
|
+
/**
|
|
113
|
+
* Platform brand colors for social icons
|
|
114
|
+
*/
|
|
115
|
+
private readonly SOCIAL_COLORS;
|
|
116
|
+
/**
|
|
117
|
+
* Get white SVG icon as data URI for a platform
|
|
118
|
+
* Uses clean, minimal SVGs optimized for email
|
|
119
|
+
*/
|
|
120
|
+
private getSocialIconDataUri;
|
|
121
|
+
/**
|
|
122
|
+
* Convert social block to MJML using raw HTML table for reliable horizontal layout
|
|
123
|
+
* Uses styled anchor tags with background colors for full width control
|
|
124
|
+
*/
|
|
125
|
+
private socialBlockToMJML;
|
|
126
|
+
/**
|
|
127
|
+
* Convert hero block to MJML
|
|
128
|
+
*/
|
|
129
|
+
private heroBlockToMJML;
|
|
130
|
+
/**
|
|
131
|
+
* Convert accordion block to MJML
|
|
132
|
+
*/
|
|
133
|
+
private accordionBlockToMJML;
|
|
134
|
+
/**
|
|
135
|
+
* Convert raw HTML block to MJML
|
|
136
|
+
*/
|
|
137
|
+
private rawBlockToMJML;
|
|
138
|
+
/**
|
|
139
|
+
* Convert navbar block to MJML
|
|
140
|
+
*/
|
|
141
|
+
private navbarBlockToMJML;
|
|
142
|
+
/**
|
|
143
|
+
* Convert carousel block to MJML
|
|
144
|
+
*/
|
|
145
|
+
private carouselBlockToMJML;
|
|
146
|
+
/**
|
|
147
|
+
* Convert table block to MJML
|
|
148
|
+
*/
|
|
149
|
+
private tableBlockToMJML;
|
|
150
|
+
/**
|
|
151
|
+
* Generate the locked header block.
|
|
152
|
+
*
|
|
153
|
+
* It used to render one client's company name and a logo from an image host;
|
|
154
|
+
* both are gone. What is left is a placeholder image slot. Keep this in step
|
|
155
|
+
* with `headerBlockDefinition` in `packages/blocks/src/branded/index.ts`:
|
|
156
|
+
* which of the two runs depends on how the registry is configured.
|
|
157
|
+
*
|
|
158
|
+
* The placeholder is a `data:` URI rather than an address on an image host,
|
|
159
|
+
* so a workspace whose `asset_policy` is `service_only` can still send a mail
|
|
160
|
+
* that contains this block.
|
|
161
|
+
*/
|
|
162
|
+
private headerBlockToMJML;
|
|
163
|
+
/**
|
|
164
|
+
* Generate the locked footer block: the unsubscribe link and nothing else.
|
|
165
|
+
*
|
|
166
|
+
* It used to carry a copyright line naming one client's company. A locked
|
|
167
|
+
* block carries no props, so whoever sends the mail cannot correct a name
|
|
168
|
+
* that is not theirs; the line is gone rather than replaced with a fake one.
|
|
169
|
+
* Keep this in step with `footerBlockDefinition` in
|
|
170
|
+
* `packages/blocks/src/branded/index.ts`.
|
|
171
|
+
*/
|
|
172
|
+
private footerBlockToMJML;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a new MJML compiler instance
|
|
176
|
+
*/
|
|
177
|
+
declare function createMJMLCompiler(): MJMLCompiler;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* MJML Exporter - Converts a live MST template to MJML/HTML
|
|
181
|
+
*
|
|
182
|
+
* This exporter is called ONLY when the user clicks Export/Send,
|
|
183
|
+
* NOT during editing. This separation is key to achieving instant
|
|
184
|
+
* visual feedback during editing.
|
|
185
|
+
*
|
|
186
|
+
* It compiles the store's snapshot with `MJMLCompiler`, the one compiler the
|
|
187
|
+
* editor has, so an export from the store and a compile of the saved document
|
|
188
|
+
* give the same mail (wrappers, sub-columns, kept attributes and all).
|
|
189
|
+
*
|
|
190
|
+
* IMPORTANT: This file should only be imported on the server side
|
|
191
|
+
* as it uses the mjml package which is not browser-safe.
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Result of MJML export
|
|
196
|
+
*/
|
|
197
|
+
interface ExportResult {
|
|
198
|
+
/** Raw MJML markup */
|
|
199
|
+
mjml: string;
|
|
200
|
+
/** Compiled HTML */
|
|
201
|
+
html: string;
|
|
202
|
+
/** Any compilation errors */
|
|
203
|
+
errors?: string[];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Export options
|
|
207
|
+
*/
|
|
208
|
+
interface ExportOptions {
|
|
209
|
+
/** MJML validation level */
|
|
210
|
+
validationLevel?: 'strict' | 'soft' | 'skip';
|
|
211
|
+
/** Minify output HTML */
|
|
212
|
+
minify?: boolean;
|
|
213
|
+
/** Add beautiful comments for debugging */
|
|
214
|
+
beautify?: boolean;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* MJMLExporter - Exports MST template to MJML and HTML
|
|
218
|
+
*/
|
|
219
|
+
declare class MJMLExporter {
|
|
220
|
+
private options;
|
|
221
|
+
private compiler;
|
|
222
|
+
constructor(options?: ExportOptions);
|
|
223
|
+
/**
|
|
224
|
+
* Export template to MJML + HTML
|
|
225
|
+
*/
|
|
226
|
+
export(template: TemplateInstance): ExportResult;
|
|
227
|
+
/**
|
|
228
|
+
* Export only MJML (without HTML compilation)
|
|
229
|
+
*/
|
|
230
|
+
exportMJML(template: TemplateInstance): string;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Create a new MJML exporter with default options
|
|
234
|
+
*/
|
|
235
|
+
declare function createMJMLExporter(options?: ExportOptions): MJMLExporter;
|
|
236
|
+
/**
|
|
237
|
+
* Quick export function for simple use cases
|
|
238
|
+
*/
|
|
239
|
+
declare function exportTemplate(template: TemplateInstance, options?: ExportOptions): ExportResult;
|
|
240
|
+
|
|
241
|
+
/** The largest MJML source `importMjml` reads, in UTF-8 bytes. */
|
|
242
|
+
declare const MAX_MJML_BYTES: number;
|
|
243
|
+
/** The deepest nesting of MJML elements it reads (`<mjml>` is depth 1). */
|
|
244
|
+
declare const MAX_MJML_DEPTH = 32;
|
|
245
|
+
/** The most MJML elements (outside content such as an `mj-text`'s HTML) it reads. */
|
|
246
|
+
declare const MAX_MJML_ELEMENTS = 5000;
|
|
247
|
+
type MjmlImportWarningSeverity = 'info' | 'warning';
|
|
248
|
+
/**
|
|
249
|
+
* Something the import could not carry over exactly, or wants the author to
|
|
250
|
+
* know. Nothing is dropped silently: every change from the source is one of
|
|
251
|
+
* these, with where it happened.
|
|
252
|
+
*
|
|
253
|
+
* - `info`: the compiled mail is unchanged, but the editor shows or edits it
|
|
254
|
+
* differently (a document-wide default the canvas does not render, a
|
|
255
|
+
* comment left out of the structure).
|
|
256
|
+
* - `warning`: the construct is kept so the compiled mail stays faithful, but
|
|
257
|
+
* not as an editable block (compiled to a Raw HTML block), or something the
|
|
258
|
+
* source asked for could not be honoured at all (an unknown component).
|
|
259
|
+
*/
|
|
260
|
+
interface MjmlImportWarning {
|
|
261
|
+
severity: MjmlImportWarningSeverity;
|
|
262
|
+
/** A stable identifier of the kind of warning, e.g. `kept_as_html`. */
|
|
263
|
+
code: MjmlImportWarningCode;
|
|
264
|
+
/** Where in the source, e.g. `mj-body > mj-section[2] > mj-column[1] > mj-social[1]`. */
|
|
265
|
+
path: string;
|
|
266
|
+
/** 1-based line of the element in the source, when known. */
|
|
267
|
+
line?: number;
|
|
268
|
+
message: string;
|
|
269
|
+
/** The MJML the warning is about, shortened to at most 2000 characters. */
|
|
270
|
+
fragment?: string;
|
|
271
|
+
}
|
|
272
|
+
type MjmlImportWarningCode =
|
|
273
|
+
/** Kept as compiled HTML in a Raw block: renders as before, not editable as a block. */
|
|
274
|
+
'kept_as_html'
|
|
275
|
+
/** A component MJML itself does not know: it renders nothing, its source is kept in a Raw block. */
|
|
276
|
+
| 'unknown_component'
|
|
277
|
+
/** Document-wide defaults (`mj-attributes`, `mj-class`) apply to the mail but not to the editor canvas. */
|
|
278
|
+
| 'document_defaults'
|
|
279
|
+
/** An attribute the editor has no control for, kept and emitted again. */
|
|
280
|
+
| 'attribute_kept'
|
|
281
|
+
/** An attribute name MJML does not accept either; left out (MJML ignored it too). */
|
|
282
|
+
| 'attribute_dropped'
|
|
283
|
+
/** A comment between columns, left out (comments render nothing). */
|
|
284
|
+
| 'comment_dropped'
|
|
285
|
+
/** Text outside any content element, which MJML ignores. */
|
|
286
|
+
| 'stray_text'
|
|
287
|
+
/** A head element the editor has no field for, kept verbatim. */
|
|
288
|
+
| 'head_element_kept'
|
|
289
|
+
/** A column width in pixels: kept, but the editor's width controls work in percent. */
|
|
290
|
+
| 'column_width_px';
|
|
291
|
+
interface MjmlImportResult {
|
|
292
|
+
/** A valid document at the current schema version (it passed `migrateTemplate`). */
|
|
293
|
+
document: EmailTemplate;
|
|
294
|
+
warnings: MjmlImportWarning[];
|
|
295
|
+
}
|
|
296
|
+
type MjmlImportErrorCode =
|
|
297
|
+
/** Not well-formed: an unclosed or mismatched tag, a malformed attribute, stray markup. */
|
|
298
|
+
'invalid_xml'
|
|
299
|
+
/** Well-formed, but not an MJML document (no `<mjml>` root, no `<mj-body>`). */
|
|
300
|
+
| 'not_mjml'
|
|
301
|
+
/** `mj-include` needs files next to the source; an import has none. */
|
|
302
|
+
| 'include_not_supported'
|
|
303
|
+
/** Larger than {@link MAX_MJML_BYTES}. */
|
|
304
|
+
| 'too_large'
|
|
305
|
+
/** Nested deeper than {@link MAX_MJML_DEPTH}. */
|
|
306
|
+
| 'too_deep'
|
|
307
|
+
/** More than {@link MAX_MJML_ELEMENTS} elements. */
|
|
308
|
+
| 'too_many_elements'
|
|
309
|
+
/** The mapped document failed the schema (a bug in the import, reported rather than hidden). */
|
|
310
|
+
| 'invalid_document';
|
|
311
|
+
/** Why an MJML source cannot be imported at all, with where, when it is one place. */
|
|
312
|
+
declare class MjmlImportError extends Error {
|
|
313
|
+
readonly code: MjmlImportErrorCode;
|
|
314
|
+
readonly line: number | undefined;
|
|
315
|
+
readonly column: number | undefined;
|
|
316
|
+
constructor(code: MjmlImportErrorCode, message: string, position?: {
|
|
317
|
+
line?: number;
|
|
318
|
+
column?: number;
|
|
319
|
+
});
|
|
320
|
+
/** A plain object that survives a worker thread boundary. */
|
|
321
|
+
toJSON(): {
|
|
322
|
+
code: MjmlImportErrorCode;
|
|
323
|
+
message: string;
|
|
324
|
+
line?: number;
|
|
325
|
+
column?: number;
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
declare function isMjmlImportError(error: unknown): error is MjmlImportError;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Reads an MJML document into the editor's document model.
|
|
332
|
+
*
|
|
333
|
+
* Throws {@link MjmlImportError} when the source cannot be read at all (not
|
|
334
|
+
* well-formed, not MJML, an `mj-include`, over a limit). Everything else
|
|
335
|
+
* imports: what the editor cannot hold as a block is kept as compiled HTML,
|
|
336
|
+
* and every such change is in `warnings`. The document has passed
|
|
337
|
+
* `migrateTemplate`. Server only: it compiles fallbacks with mjml.
|
|
338
|
+
*/
|
|
339
|
+
declare function importMjml(source: string): MjmlImportResult;
|
|
340
|
+
|
|
341
|
+
export { type CompileOptions, DEFAULT_MJML_ATTRIBUTES, EDITOR_DATA_ATTRIBUTE, type ExportOptions, type ExportResult, MAX_MJML_BYTES, MAX_MJML_DEPTH, MAX_MJML_ELEMENTS, MJMLCompiler, MJMLExporter, MjmlImportError, type MjmlImportErrorCode, type MjmlImportResult, type MjmlImportWarning, type MjmlImportWarningCode, type MjmlImportWarningSeverity, createMJMLCompiler, createMJMLExporter, encodeEditorData, exportTemplate, importMjml, isMjmlImportError };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { E as EmailTemplate, y as CompileResult, a4 as TemplateInstance } from './TemplateModel-v__r5Nvi.js';
|
|
2
|
+
import 'mobx-state-tree';
|
|
3
|
+
|
|
4
|
+
/** The `<mj-attributes>` a document gets unless it brings its own (`metadata.mjmlHead.attributes`). */
|
|
5
|
+
declare const DEFAULT_MJML_ATTRIBUTES = "\n <mj-all font-family=\"Georgia, serif\" />\n <mj-text font-size=\"14px\" line-height=\"1.6\" />\n ";
|
|
6
|
+
/** Marks the editor's own raw markup so the MJML import can read the block back exactly. */
|
|
7
|
+
declare const EDITOR_DATA_ATTRIBUTE: {
|
|
8
|
+
readonly social: "data-ee-social";
|
|
9
|
+
readonly subColumns: "data-ee-subcols";
|
|
10
|
+
};
|
|
11
|
+
/** A block's (or sub-columns') JSON, base64-encoded, for an {@link EDITOR_DATA_ATTRIBUTE}. */
|
|
12
|
+
declare function encodeEditorData(value: unknown): string;
|
|
13
|
+
/** Options for one {@link MJMLCompiler.compile} call. */
|
|
14
|
+
interface CompileOptions {
|
|
15
|
+
/**
|
|
16
|
+
* MJML adds a Google Fonts `<link>` and `@import` on its own whenever a font
|
|
17
|
+
* family it knows (Open Sans, Droid Sans, Lato, Roboto, Ubuntu) appears in
|
|
18
|
+
* the document. `false` leaves them out, so the font falls back to the rest
|
|
19
|
+
* of its stack and the mail loads nothing from Google. Fonts the document
|
|
20
|
+
* declares itself (`metadata.fonts`) are always emitted. Default `true`.
|
|
21
|
+
*/
|
|
22
|
+
webFonts?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* MJML Compiler class
|
|
26
|
+
* Converts EmailTemplate to MJML markup and compiles to HTML
|
|
27
|
+
*/
|
|
28
|
+
declare class MJMLCompiler {
|
|
29
|
+
/**
|
|
30
|
+
* Set true while emitting a column with sub-columns. Causes generateHead
|
|
31
|
+
* to inject the responsive media query exactly once per template.
|
|
32
|
+
*/
|
|
33
|
+
private needsSubColumnStyles;
|
|
34
|
+
/**
|
|
35
|
+
* Compile email template to MJML and HTML
|
|
36
|
+
*/
|
|
37
|
+
compile(template: EmailTemplate, options?: CompileOptions): CompileResult;
|
|
38
|
+
/**
|
|
39
|
+
* The MJML markup for a document, without compiling it to HTML.
|
|
40
|
+
*/
|
|
41
|
+
toMJML(template: EmailTemplate): string;
|
|
42
|
+
/**
|
|
43
|
+
* Convert template to MJML markup
|
|
44
|
+
*/
|
|
45
|
+
private templateToMJML;
|
|
46
|
+
/**
|
|
47
|
+
* Generate MJML head section with all head components
|
|
48
|
+
* Supports: mj-title, mj-preview, mj-font, mj-breakpoint, mj-style
|
|
49
|
+
*/
|
|
50
|
+
private generateHead;
|
|
51
|
+
/**
|
|
52
|
+
* Collect background-image CSS rules for all wrappers, sections and columns that have gradients.
|
|
53
|
+
* Returns a string of CSS rules to inject as a single mj-style block.
|
|
54
|
+
*/
|
|
55
|
+
private collectGradientStyles;
|
|
56
|
+
/**
|
|
57
|
+
* Convert a wrapper to an `<mj-wrapper>` around its sections. The wrapper's
|
|
58
|
+
* attributes are MJML's own for `mj-wrapper`; the sections inside follow
|
|
59
|
+
* MJML's rules there (a full-width section inside a full-width wrapper
|
|
60
|
+
* renders at standard width, which the inspector explains).
|
|
61
|
+
*/
|
|
62
|
+
private wrapperToMJML;
|
|
63
|
+
/** Background attributes shared by sections and wrappers: a gradient (with its Outlook fallback colour), or colour and image. */
|
|
64
|
+
private pushBackground;
|
|
65
|
+
/**
|
|
66
|
+
* Convert section to MJML
|
|
67
|
+
* Supports background images, full-width, and mj-group for non-stacking columns
|
|
68
|
+
*/
|
|
69
|
+
private sectionToMJML;
|
|
70
|
+
/**
|
|
71
|
+
* Convert column to MJML
|
|
72
|
+
*/
|
|
73
|
+
private columnToMJML;
|
|
74
|
+
/**
|
|
75
|
+
* Emit a group column as an mj-column wrapping a hand-built nested
|
|
76
|
+
* table inside an mj-raw island. The parent mj-section structure
|
|
77
|
+
* stays standard MJML; only the nested area escapes MJML's parser.
|
|
78
|
+
*
|
|
79
|
+
* The responsive media query (table.ee-sub-cols td.ee-sub-col) is
|
|
80
|
+
* injected once at document head via generateHead when the
|
|
81
|
+
* needsSubColumnStyles flag is set.
|
|
82
|
+
*/
|
|
83
|
+
private subColumnsToMJML;
|
|
84
|
+
/**
|
|
85
|
+
* Convert block to MJML based on type
|
|
86
|
+
*/
|
|
87
|
+
private blockToMJML;
|
|
88
|
+
/**
|
|
89
|
+
* Convert text block to MJML
|
|
90
|
+
*
|
|
91
|
+
* Note: MJML applies styles to the container <td>, but TipTap content
|
|
92
|
+
* (wrapped in <p> tags) doesn't inherit these styles. We solve this by
|
|
93
|
+
* wrapping the content in a <div> with explicit inline styles.
|
|
94
|
+
*/
|
|
95
|
+
private textBlockToMJML;
|
|
96
|
+
/**
|
|
97
|
+
* Convert image block to MJML
|
|
98
|
+
*/
|
|
99
|
+
private imageBlockToMJML;
|
|
100
|
+
/**
|
|
101
|
+
* Convert button block to MJML
|
|
102
|
+
*/
|
|
103
|
+
private buttonBlockToMJML;
|
|
104
|
+
/**
|
|
105
|
+
* Convert divider block to MJML
|
|
106
|
+
*/
|
|
107
|
+
private dividerBlockToMJML;
|
|
108
|
+
/**
|
|
109
|
+
* Convert spacer block to MJML
|
|
110
|
+
*/
|
|
111
|
+
private spacerBlockToMJML;
|
|
112
|
+
/**
|
|
113
|
+
* Platform brand colors for social icons
|
|
114
|
+
*/
|
|
115
|
+
private readonly SOCIAL_COLORS;
|
|
116
|
+
/**
|
|
117
|
+
* Get white SVG icon as data URI for a platform
|
|
118
|
+
* Uses clean, minimal SVGs optimized for email
|
|
119
|
+
*/
|
|
120
|
+
private getSocialIconDataUri;
|
|
121
|
+
/**
|
|
122
|
+
* Convert social block to MJML using raw HTML table for reliable horizontal layout
|
|
123
|
+
* Uses styled anchor tags with background colors for full width control
|
|
124
|
+
*/
|
|
125
|
+
private socialBlockToMJML;
|
|
126
|
+
/**
|
|
127
|
+
* Convert hero block to MJML
|
|
128
|
+
*/
|
|
129
|
+
private heroBlockToMJML;
|
|
130
|
+
/**
|
|
131
|
+
* Convert accordion block to MJML
|
|
132
|
+
*/
|
|
133
|
+
private accordionBlockToMJML;
|
|
134
|
+
/**
|
|
135
|
+
* Convert raw HTML block to MJML
|
|
136
|
+
*/
|
|
137
|
+
private rawBlockToMJML;
|
|
138
|
+
/**
|
|
139
|
+
* Convert navbar block to MJML
|
|
140
|
+
*/
|
|
141
|
+
private navbarBlockToMJML;
|
|
142
|
+
/**
|
|
143
|
+
* Convert carousel block to MJML
|
|
144
|
+
*/
|
|
145
|
+
private carouselBlockToMJML;
|
|
146
|
+
/**
|
|
147
|
+
* Convert table block to MJML
|
|
148
|
+
*/
|
|
149
|
+
private tableBlockToMJML;
|
|
150
|
+
/**
|
|
151
|
+
* Generate the locked header block.
|
|
152
|
+
*
|
|
153
|
+
* It used to render one client's company name and a logo from an image host;
|
|
154
|
+
* both are gone. What is left is a placeholder image slot. Keep this in step
|
|
155
|
+
* with `headerBlockDefinition` in `packages/blocks/src/branded/index.ts`:
|
|
156
|
+
* which of the two runs depends on how the registry is configured.
|
|
157
|
+
*
|
|
158
|
+
* The placeholder is a `data:` URI rather than an address on an image host,
|
|
159
|
+
* so a workspace whose `asset_policy` is `service_only` can still send a mail
|
|
160
|
+
* that contains this block.
|
|
161
|
+
*/
|
|
162
|
+
private headerBlockToMJML;
|
|
163
|
+
/**
|
|
164
|
+
* Generate the locked footer block: the unsubscribe link and nothing else.
|
|
165
|
+
*
|
|
166
|
+
* It used to carry a copyright line naming one client's company. A locked
|
|
167
|
+
* block carries no props, so whoever sends the mail cannot correct a name
|
|
168
|
+
* that is not theirs; the line is gone rather than replaced with a fake one.
|
|
169
|
+
* Keep this in step with `footerBlockDefinition` in
|
|
170
|
+
* `packages/blocks/src/branded/index.ts`.
|
|
171
|
+
*/
|
|
172
|
+
private footerBlockToMJML;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a new MJML compiler instance
|
|
176
|
+
*/
|
|
177
|
+
declare function createMJMLCompiler(): MJMLCompiler;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* MJML Exporter - Converts a live MST template to MJML/HTML
|
|
181
|
+
*
|
|
182
|
+
* This exporter is called ONLY when the user clicks Export/Send,
|
|
183
|
+
* NOT during editing. This separation is key to achieving instant
|
|
184
|
+
* visual feedback during editing.
|
|
185
|
+
*
|
|
186
|
+
* It compiles the store's snapshot with `MJMLCompiler`, the one compiler the
|
|
187
|
+
* editor has, so an export from the store and a compile of the saved document
|
|
188
|
+
* give the same mail (wrappers, sub-columns, kept attributes and all).
|
|
189
|
+
*
|
|
190
|
+
* IMPORTANT: This file should only be imported on the server side
|
|
191
|
+
* as it uses the mjml package which is not browser-safe.
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Result of MJML export
|
|
196
|
+
*/
|
|
197
|
+
interface ExportResult {
|
|
198
|
+
/** Raw MJML markup */
|
|
199
|
+
mjml: string;
|
|
200
|
+
/** Compiled HTML */
|
|
201
|
+
html: string;
|
|
202
|
+
/** Any compilation errors */
|
|
203
|
+
errors?: string[];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Export options
|
|
207
|
+
*/
|
|
208
|
+
interface ExportOptions {
|
|
209
|
+
/** MJML validation level */
|
|
210
|
+
validationLevel?: 'strict' | 'soft' | 'skip';
|
|
211
|
+
/** Minify output HTML */
|
|
212
|
+
minify?: boolean;
|
|
213
|
+
/** Add beautiful comments for debugging */
|
|
214
|
+
beautify?: boolean;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* MJMLExporter - Exports MST template to MJML and HTML
|
|
218
|
+
*/
|
|
219
|
+
declare class MJMLExporter {
|
|
220
|
+
private options;
|
|
221
|
+
private compiler;
|
|
222
|
+
constructor(options?: ExportOptions);
|
|
223
|
+
/**
|
|
224
|
+
* Export template to MJML + HTML
|
|
225
|
+
*/
|
|
226
|
+
export(template: TemplateInstance): ExportResult;
|
|
227
|
+
/**
|
|
228
|
+
* Export only MJML (without HTML compilation)
|
|
229
|
+
*/
|
|
230
|
+
exportMJML(template: TemplateInstance): string;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Create a new MJML exporter with default options
|
|
234
|
+
*/
|
|
235
|
+
declare function createMJMLExporter(options?: ExportOptions): MJMLExporter;
|
|
236
|
+
/**
|
|
237
|
+
* Quick export function for simple use cases
|
|
238
|
+
*/
|
|
239
|
+
declare function exportTemplate(template: TemplateInstance, options?: ExportOptions): ExportResult;
|
|
240
|
+
|
|
241
|
+
/** The largest MJML source `importMjml` reads, in UTF-8 bytes. */
|
|
242
|
+
declare const MAX_MJML_BYTES: number;
|
|
243
|
+
/** The deepest nesting of MJML elements it reads (`<mjml>` is depth 1). */
|
|
244
|
+
declare const MAX_MJML_DEPTH = 32;
|
|
245
|
+
/** The most MJML elements (outside content such as an `mj-text`'s HTML) it reads. */
|
|
246
|
+
declare const MAX_MJML_ELEMENTS = 5000;
|
|
247
|
+
type MjmlImportWarningSeverity = 'info' | 'warning';
|
|
248
|
+
/**
|
|
249
|
+
* Something the import could not carry over exactly, or wants the author to
|
|
250
|
+
* know. Nothing is dropped silently: every change from the source is one of
|
|
251
|
+
* these, with where it happened.
|
|
252
|
+
*
|
|
253
|
+
* - `info`: the compiled mail is unchanged, but the editor shows or edits it
|
|
254
|
+
* differently (a document-wide default the canvas does not render, a
|
|
255
|
+
* comment left out of the structure).
|
|
256
|
+
* - `warning`: the construct is kept so the compiled mail stays faithful, but
|
|
257
|
+
* not as an editable block (compiled to a Raw HTML block), or something the
|
|
258
|
+
* source asked for could not be honoured at all (an unknown component).
|
|
259
|
+
*/
|
|
260
|
+
interface MjmlImportWarning {
|
|
261
|
+
severity: MjmlImportWarningSeverity;
|
|
262
|
+
/** A stable identifier of the kind of warning, e.g. `kept_as_html`. */
|
|
263
|
+
code: MjmlImportWarningCode;
|
|
264
|
+
/** Where in the source, e.g. `mj-body > mj-section[2] > mj-column[1] > mj-social[1]`. */
|
|
265
|
+
path: string;
|
|
266
|
+
/** 1-based line of the element in the source, when known. */
|
|
267
|
+
line?: number;
|
|
268
|
+
message: string;
|
|
269
|
+
/** The MJML the warning is about, shortened to at most 2000 characters. */
|
|
270
|
+
fragment?: string;
|
|
271
|
+
}
|
|
272
|
+
type MjmlImportWarningCode =
|
|
273
|
+
/** Kept as compiled HTML in a Raw block: renders as before, not editable as a block. */
|
|
274
|
+
'kept_as_html'
|
|
275
|
+
/** A component MJML itself does not know: it renders nothing, its source is kept in a Raw block. */
|
|
276
|
+
| 'unknown_component'
|
|
277
|
+
/** Document-wide defaults (`mj-attributes`, `mj-class`) apply to the mail but not to the editor canvas. */
|
|
278
|
+
| 'document_defaults'
|
|
279
|
+
/** An attribute the editor has no control for, kept and emitted again. */
|
|
280
|
+
| 'attribute_kept'
|
|
281
|
+
/** An attribute name MJML does not accept either; left out (MJML ignored it too). */
|
|
282
|
+
| 'attribute_dropped'
|
|
283
|
+
/** A comment between columns, left out (comments render nothing). */
|
|
284
|
+
| 'comment_dropped'
|
|
285
|
+
/** Text outside any content element, which MJML ignores. */
|
|
286
|
+
| 'stray_text'
|
|
287
|
+
/** A head element the editor has no field for, kept verbatim. */
|
|
288
|
+
| 'head_element_kept'
|
|
289
|
+
/** A column width in pixels: kept, but the editor's width controls work in percent. */
|
|
290
|
+
| 'column_width_px';
|
|
291
|
+
interface MjmlImportResult {
|
|
292
|
+
/** A valid document at the current schema version (it passed `migrateTemplate`). */
|
|
293
|
+
document: EmailTemplate;
|
|
294
|
+
warnings: MjmlImportWarning[];
|
|
295
|
+
}
|
|
296
|
+
type MjmlImportErrorCode =
|
|
297
|
+
/** Not well-formed: an unclosed or mismatched tag, a malformed attribute, stray markup. */
|
|
298
|
+
'invalid_xml'
|
|
299
|
+
/** Well-formed, but not an MJML document (no `<mjml>` root, no `<mj-body>`). */
|
|
300
|
+
| 'not_mjml'
|
|
301
|
+
/** `mj-include` needs files next to the source; an import has none. */
|
|
302
|
+
| 'include_not_supported'
|
|
303
|
+
/** Larger than {@link MAX_MJML_BYTES}. */
|
|
304
|
+
| 'too_large'
|
|
305
|
+
/** Nested deeper than {@link MAX_MJML_DEPTH}. */
|
|
306
|
+
| 'too_deep'
|
|
307
|
+
/** More than {@link MAX_MJML_ELEMENTS} elements. */
|
|
308
|
+
| 'too_many_elements'
|
|
309
|
+
/** The mapped document failed the schema (a bug in the import, reported rather than hidden). */
|
|
310
|
+
| 'invalid_document';
|
|
311
|
+
/** Why an MJML source cannot be imported at all, with where, when it is one place. */
|
|
312
|
+
declare class MjmlImportError extends Error {
|
|
313
|
+
readonly code: MjmlImportErrorCode;
|
|
314
|
+
readonly line: number | undefined;
|
|
315
|
+
readonly column: number | undefined;
|
|
316
|
+
constructor(code: MjmlImportErrorCode, message: string, position?: {
|
|
317
|
+
line?: number;
|
|
318
|
+
column?: number;
|
|
319
|
+
});
|
|
320
|
+
/** A plain object that survives a worker thread boundary. */
|
|
321
|
+
toJSON(): {
|
|
322
|
+
code: MjmlImportErrorCode;
|
|
323
|
+
message: string;
|
|
324
|
+
line?: number;
|
|
325
|
+
column?: number;
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
declare function isMjmlImportError(error: unknown): error is MjmlImportError;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Reads an MJML document into the editor's document model.
|
|
332
|
+
*
|
|
333
|
+
* Throws {@link MjmlImportError} when the source cannot be read at all (not
|
|
334
|
+
* well-formed, not MJML, an `mj-include`, over a limit). Everything else
|
|
335
|
+
* imports: what the editor cannot hold as a block is kept as compiled HTML,
|
|
336
|
+
* and every such change is in `warnings`. The document has passed
|
|
337
|
+
* `migrateTemplate`. Server only: it compiles fallbacks with mjml.
|
|
338
|
+
*/
|
|
339
|
+
declare function importMjml(source: string): MjmlImportResult;
|
|
340
|
+
|
|
341
|
+
export { type CompileOptions, DEFAULT_MJML_ATTRIBUTES, EDITOR_DATA_ATTRIBUTE, type ExportOptions, type ExportResult, MAX_MJML_BYTES, MAX_MJML_DEPTH, MAX_MJML_ELEMENTS, MJMLCompiler, MJMLExporter, MjmlImportError, type MjmlImportErrorCode, type MjmlImportResult, type MjmlImportWarning, type MjmlImportWarningCode, type MjmlImportWarningSeverity, createMJMLCompiler, createMJMLExporter, encodeEditorData, exportTemplate, importMjml, isMjmlImportError };
|