@maily-to/shared 0.0.2 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,95 @@
1
- //#region src/theme.ts
1
+ //#region src/alignment.ts
2
+ const TEXT_ALIGNMENTS = {
3
+ LEFT: "left",
4
+ CENTER: "center",
5
+ RIGHT: "right"
6
+ };
7
+ const allowedTextAligns = Object.freeze(Object.values(TEXT_ALIGNMENTS));
8
+ const DEFAULT_TEXT_ALIGN = TEXT_ALIGNMENTS.LEFT;
9
+ function isAllowedTextAlignment(value) {
10
+ return typeof value === "string" && allowedTextAligns.includes(value);
11
+ }
12
+ //#endregion
13
+ //#region src/field-mode.ts
14
+ /**
15
+ * Controls how multi-value fields (padding, margin, border) are edited.
16
+ * "none" disables the field, "uniform" links all sides to one value,
17
+ * "mixed" allows independent per-side values, "preset" uses predefined
18
+ * size options (e.g. small/medium/large).
19
+ */
20
+ const FIELD_MODE = {
21
+ NONE: "none",
22
+ MIXED: "mixed",
23
+ UNIFORM: "uniform",
24
+ PRESET: "preset"
25
+ };
26
+ const allowedFieldModes = Object.values(FIELD_MODE);
27
+ function isAllowedFieldMode(mode) {
28
+ return typeof mode === "string" && allowedFieldModes.includes(mode);
29
+ }
30
+ //#endregion
31
+ //#region src/border.ts
32
+ const BORDER_STYLES = {
33
+ SOLID: "solid",
34
+ DASHED: "dashed",
35
+ DOTTED: "dotted"
36
+ };
37
+ const DEFAULT_BORDER_STYLE = BORDER_STYLES.SOLID;
38
+ const DEFAULT_BORDER_COLOR = "#000000";
39
+ /**
40
+ * Converts a BorderStyleConfig into CSS properties for inline styles.
41
+ * When all widths or radii are equal (or the mode is "uniform"), emits
42
+ * shorthand CSS; otherwise emits per-side longhand properties.
43
+ */
44
+ function getBorderStyle(config) {
45
+ const { borderStyle = DEFAULT_BORDER_STYLE, borderColor = DEFAULT_BORDER_COLOR, borderWidthMode, borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth, borderRadiusMode, borderTopLeftRadius, borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius } = config;
46
+ const isBorderWidthUniform = borderWidthMode === FIELD_MODE.UNIFORM || borderLeftWidth === borderRightWidth && borderRightWidth === borderBottomWidth && borderBottomWidth === borderTopWidth;
47
+ const isBorderRadiusUniform = borderRadiusMode === FIELD_MODE.UNIFORM || borderTopLeftRadius === borderTopRightRadius && borderTopRightRadius === borderBottomRightRadius && borderBottomRightRadius === borderBottomLeftRadius;
48
+ return {
49
+ ...isBorderWidthUniform ? { border: `${borderTopWidth}px ${borderStyle} ${borderColor}` } : {
50
+ borderTopWidth: `${borderTopWidth}px`,
51
+ borderRightWidth: `${borderRightWidth}px`,
52
+ borderBottomWidth: `${borderBottomWidth}px`,
53
+ borderLeftWidth: `${borderLeftWidth}px`,
54
+ borderStyle,
55
+ borderColor
56
+ },
57
+ ...isBorderRadiusUniform ? { borderRadius: `${borderTopLeftRadius}px` } : { borderRadius: `${borderTopLeftRadius}px ${borderTopRightRadius}px ${borderBottomRightRadius}px ${borderBottomLeftRadius}px` }
58
+ };
59
+ }
60
+ //#endregion
61
+ //#region src/button-kind.ts
62
+ /**
63
+ * Button layout kinds.
64
+ * "tight" renders the button at its content width,
65
+ * "full-width" stretches it to fill the container.
66
+ */
67
+ const BUTTON_KINDS = {
68
+ TIGHT: "tight",
69
+ FULL_WIDTH: "full-width"
70
+ };
71
+ const allowedButtonKinds = Object.freeze(Object.values(BUTTON_KINDS));
72
+ const DEFAULT_BUTTON_KIND = BUTTON_KINDS.TIGHT;
73
+ function isAllowedButtonKind(value) {
74
+ return typeof value === "string" && allowedButtonKinds.includes(value);
75
+ }
76
+ //#endregion
77
+ //#region src/constants.ts
78
+ /** HTML data attribute key used to identify node types in rendered output. */
79
+ const DATA_NODE_TYPE_KEY = "data-node-type";
80
+ /** HTML data attribute key used to store serialized visibility rules. */
81
+ const DATA_VISIBILITY_RULE_KEY = "data-visibility-rule";
82
+ /** Prefix prepended to all Maily error messages for easy identification. */
83
+ const MAILY_ERROR_PREFIX = "[Maily Error]";
84
+ /** URL for filing bug reports against the Maily repository. */
85
+ const MAILY_BUG_REPORT_URL = "https://github.com/arikchakma/maily.to/issues/new";
86
+ //#endregion
87
+ //#region src/font.ts
88
+ /**
89
+ * List of allowed fallback font families. These are system fonts or
90
+ * generic font families that serve as fallbacks when a web font
91
+ * fails to load.
92
+ */
2
93
  const allowedFallbackFonts = [
3
94
  "Arial",
4
95
  "Helvetica",
@@ -19,185 +110,885 @@ const allowedFontFormats = [
19
110
  "embedded-opentype",
20
111
  "svg"
21
112
  ];
113
+ /**
114
+ * Default font configuration: Inter with sans-serif fallback,
115
+ * loaded from the Maily CDN as woff2.
116
+ */
22
117
  const DEFAULT_FONT = {
23
118
  fallbackFontFamily: "sans-serif",
24
119
  fontFamily: "Inter",
25
120
  webFont: {
26
- url: "https://rsms.me/inter/font-files/Inter-Regular.woff2?v=3.19",
121
+ url: "https://cdn.usemaily.com/fonts/v0/inter.woff2",
27
122
  format: "woff2"
28
123
  }
29
124
  };
125
+ /**
126
+ * Injects a @font-face style element into the document head to load
127
+ * the given font. Only works in browser environments.
128
+ */
129
+ function loadFont(font) {
130
+ const style = getFontFaceStyle(font);
131
+ const styleElement = document.createElement("style");
132
+ styleElement.textContent = style;
133
+ document.head.appendChild(styleElement);
134
+ }
135
+ /**
136
+ * Generates a @font-face CSS rule string for the given font configuration.
137
+ * Includes the font family, style, weight, MSO fallback, and web font
138
+ * source URL when available.
139
+ */
140
+ function getFontFaceStyle(font) {
141
+ const { fontFamily, fallbackFontFamily, webFont, fontWeight = 400, fontStyle = "normal" } = font;
142
+ return `@font-face {font-family: '${fontFamily}';font-style: ${fontStyle};font-weight: ${fontWeight};mso-font-alt: '${fallbackFontFamily}';${webFont ? `src: url(${webFont.url}) format('${webFont.format}');` : ""}}`;
143
+ }
144
+ //#endregion
145
+ //#region src/css-variables.ts
146
+ /**
147
+ * Returns a CSS variable object for the given name and value.
148
+ * If the value is nullish or empty, returns an empty object so that
149
+ * the default CSS variable value is not overridden. Numbers are
150
+ * automatically suffixed with "px".
151
+ */
152
+ function getVariableValue(name, value) {
153
+ if (value === void 0 || value === null || value === "") return {};
154
+ return { [name]: typeof value === "number" ? `${value}px` : value };
155
+ }
156
+ /**
157
+ * Converts an EditorThemeOptions object into a flat map of Maily CSS
158
+ * custom properties (--mly-*). Used to apply theme overrides as inline
159
+ * styles on the editor or renderer root element. Covers body background,
160
+ * container dimensions and borders, button colors, link color, and
161
+ * font family settings.
162
+ */
163
+ function getMailyCssVariables(theme) {
164
+ const font = theme.font || DEFAULT_FONT;
165
+ return {
166
+ ...getVariableValue("--mly-body-background-color", theme.body?.backgroundColor),
167
+ ...getVariableValue("--mly-body-padding-top", theme.body?.paddingTop),
168
+ ...getVariableValue("--mly-body-padding-right", theme.body?.paddingRight),
169
+ ...getVariableValue("--mly-body-padding-bottom", theme.body?.paddingBottom),
170
+ ...getVariableValue("--mly-body-padding-left", theme.body?.paddingLeft),
171
+ ...getVariableValue("--mly-container-background-color", theme.container?.backgroundColor),
172
+ ...getVariableValue("--mly-container-max-width", theme.container?.maxWidth),
173
+ ...getVariableValue("--mly-container-min-width", theme.container?.minWidth),
174
+ ...getVariableValue("--mly-container-padding-top", theme.container?.paddingTop),
175
+ ...getVariableValue("--mly-container-padding-right", theme.container?.paddingRight),
176
+ ...getVariableValue("--mly-container-padding-bottom", theme.container?.paddingBottom),
177
+ ...getVariableValue("--mly-container-padding-left", theme.container?.paddingLeft),
178
+ ...getVariableValue("--mly-container-border-radius", theme.container?.borderRadius),
179
+ ...getVariableValue("--mly-container-border-width", theme.container?.borderWidth),
180
+ ...getVariableValue("--mly-container-border-color", theme.container?.borderColor),
181
+ ...getVariableValue("--mly-button-background-color", theme.button?.backgroundColor),
182
+ ...getVariableValue("--mly-button-text-color", theme.button?.color),
183
+ ...getVariableValue("--mly-button-padding-top", theme.button?.paddingTop),
184
+ ...getVariableValue("--mly-button-padding-right", theme.button?.paddingRight),
185
+ ...getVariableValue("--mly-button-padding-bottom", theme.button?.paddingBottom),
186
+ ...getVariableValue("--mly-button-padding-left", theme.button?.paddingLeft),
187
+ ...getVariableValue("--mly-link-color", theme.link?.color),
188
+ ...getVariableValue("--mly-font-family", font.fontFamily),
189
+ ...getVariableValue("--mly-font-fallback-family", font.fallbackFontFamily),
190
+ "--mly-font": `var(--mly-font-family), var(--mly-font-fallback-family)`
191
+ };
192
+ }
193
+ //#endregion
194
+ //#region src/html-code-block.ts
195
+ /**
196
+ * Tab options for the HTML code block node.
197
+ * "code" shows the raw HTML source, "preview" renders it visually.
198
+ */
199
+ const HTML_CODE_BLOCK_TABS = {
200
+ CODE: "code",
201
+ PREVIEW: "preview"
202
+ };
203
+ const DEFAULT_HTML_CODE_BLOCK_TAB = HTML_CODE_BLOCK_TABS.CODE;
204
+ //#endregion
205
+ //#region src/math.ts
206
+ function clamp(value, [min, max]) {
207
+ return Math.min(Math.max(value, min), max);
208
+ }
209
+ function percentage(portion, total) {
210
+ return clamp(portion / total * 100, [0, 100]);
211
+ }
212
+ function absoluteFromPercentage(percentage, total) {
213
+ return Math.round(total * percentage / 100);
214
+ }
215
+ function roundTo(value, decimals) {
216
+ const factor = Math.pow(10, decimals);
217
+ return Math.round(value * factor) / factor;
218
+ }
219
+ //#endregion
220
+ //#region src/image-width.ts
221
+ const MIN_IMAGE_WIDTH_PERCENTAGE = 5;
222
+ const MAX_IMAGE_WIDTH_PERCENTAGE = 100;
223
+ const MAX_IMAGE_WIDTH_PIXELS = 600;
224
+ /**
225
+ * Converts any ImageWidth value to a clamped percentage number.
226
+ * Handles "auto" (→ 100), percentage strings (e.g. "50%" → 50),
227
+ * and legacy pixel numbers (converted relative to maxWidthPixels).
228
+ * Returns 100 for null or unrecognized values.
229
+ */
230
+ function parseWidthToPercentage(width, maxWidthPixels = MAX_IMAGE_WIDTH_PIXELS) {
231
+ if (typeof width === "string") {
232
+ if (width === "auto") return 100;
233
+ return width.endsWith("%") ? clampImageWidthPercentage(parseInt(width)) : 100;
234
+ }
235
+ if (typeof width === "number") return clampImageWidthPercentage(Math.round(100 * width / maxWidthPixels));
236
+ return 100;
237
+ }
238
+ function clampImageWidthPercentage(width) {
239
+ return clamp(width, [5, 100]);
240
+ }
241
+ //#endregion
242
+ //#region src/mark.ts
243
+ /** Registry of all inline mark type strings used in the document JSON. */
244
+ const MAILY_MARK_TYPES = {
245
+ BOLD: "bold",
246
+ ITALIC: "italic",
247
+ STRIKE: "strike",
248
+ UNDERLINE: "underline",
249
+ LINK: "link",
250
+ CODE: "code",
251
+ TEXT_STYLE: "textStyle",
252
+ HIGHLIGHT: "highlight"
253
+ };
254
+ const allowedMarkTypes = Object.values(MAILY_MARK_TYPES);
255
+ //#endregion
256
+ //#region src/node.ts
257
+ /**
258
+ * Registry of all document node type strings. These map 1:1 to
259
+ * Tiptap extension names and are used as discriminators in the
260
+ * document JSON.
261
+ */
262
+ const MAILY_NODE_TYPES = {
263
+ DOCUMENT: "doc",
264
+ PARAGRAPH: "paragraph",
265
+ TEXT: "text",
266
+ HEADING: "heading",
267
+ VARIABLE: "variable",
268
+ IMAGE: "image",
269
+ SPACER: "spacer",
270
+ SECTION: "section",
271
+ COLUMNS: "columns",
272
+ COLUMN: "column",
273
+ BULLET_LIST: "bulletList",
274
+ ORDERED_LIST: "orderedList",
275
+ LIST_ITEM: "listItem",
276
+ HORIZONTAL_RULE: "horizontalRule",
277
+ BUTTON: "button",
278
+ REPEAT: "repeat",
279
+ HTML_CODE_BLOCK: "htmlCodeBlock",
280
+ BLOCKQUOTE: "blockquote",
281
+ HARD_BREAK: "hardBreak",
282
+ FOOTER: "footer",
283
+ INLINE_IMAGE: "inlineImage",
284
+ LINK_CARD: "linkCard"
285
+ };
286
+ /**
287
+ * Tiptap extension types that attach attributes to nodes but are
288
+ * not document nodes themselves (e.g. fontStyle, visibility).
289
+ */
290
+ const MAILY_EXTENSION_TYPES = {
291
+ FONT_STYLE: "fontStyle",
292
+ VISIBILITY: "visibility"
293
+ };
294
+ const allowedNodeTypes = Object.values(MAILY_NODE_TYPES);
295
+ //#endregion
296
+ //#region src/is.ts
297
+ function guard(type) {
298
+ return (node) => node.type === type;
299
+ }
300
+ /**
301
+ * Type guards for Maily nodes and marks. Provides narrowing functions
302
+ * for every node type (is.paragraph, is.button, etc.) and mark type
303
+ * (is.bold, is.link, etc.), plus structural checks like is.parent
304
+ * and is.marked. Each guard narrows the input to its specific type.
305
+ *
306
+ * Example:
307
+ * if (is.paragraph(node)) {
308
+ * node.attrs.textAlign // narrowed to ParagraphNode
309
+ * }
310
+ */
311
+ const is = {
312
+ any(value) {
313
+ return this.node(value) || this.mark(value);
314
+ },
315
+ parent(node) {
316
+ return Array.isArray(node?.content);
317
+ },
318
+ marked(node) {
319
+ return Array.isArray(node?.marks);
320
+ },
321
+ node(node) {
322
+ return typeof node === "object" && node !== null && "type" in node && allowedNodeTypes.includes(node.type);
323
+ },
324
+ doc: guard(MAILY_NODE_TYPES.DOCUMENT),
325
+ paragraph: guard(MAILY_NODE_TYPES.PARAGRAPH),
326
+ text: guard(MAILY_NODE_TYPES.TEXT),
327
+ heading: guard(MAILY_NODE_TYPES.HEADING),
328
+ variable: guard(MAILY_NODE_TYPES.VARIABLE),
329
+ image: guard(MAILY_NODE_TYPES.IMAGE),
330
+ inlineImage: guard(MAILY_NODE_TYPES.INLINE_IMAGE),
331
+ spacer: guard(MAILY_NODE_TYPES.SPACER),
332
+ section: guard(MAILY_NODE_TYPES.SECTION),
333
+ button: guard(MAILY_NODE_TYPES.BUTTON),
334
+ columns: guard(MAILY_NODE_TYPES.COLUMNS),
335
+ column: guard(MAILY_NODE_TYPES.COLUMN),
336
+ repeat: guard(MAILY_NODE_TYPES.REPEAT),
337
+ bulletList: guard(MAILY_NODE_TYPES.BULLET_LIST),
338
+ orderedList: guard(MAILY_NODE_TYPES.ORDERED_LIST),
339
+ listItem: guard(MAILY_NODE_TYPES.LIST_ITEM),
340
+ horizontalRule: guard(MAILY_NODE_TYPES.HORIZONTAL_RULE),
341
+ htmlCodeBlock: guard(MAILY_NODE_TYPES.HTML_CODE_BLOCK),
342
+ blockquote: guard(MAILY_NODE_TYPES.BLOCKQUOTE),
343
+ hardBreak: guard(MAILY_NODE_TYPES.HARD_BREAK),
344
+ footer: guard(MAILY_NODE_TYPES.FOOTER),
345
+ linkCard: guard(MAILY_NODE_TYPES.LINK_CARD),
346
+ mark(mark) {
347
+ return typeof mark === "object" && mark !== null && "type" in mark && allowedMarkTypes.includes(mark.type);
348
+ },
349
+ bold: guard(MAILY_MARK_TYPES.BOLD),
350
+ italic: guard(MAILY_MARK_TYPES.ITALIC),
351
+ strike: guard(MAILY_MARK_TYPES.STRIKE),
352
+ underline: guard(MAILY_MARK_TYPES.UNDERLINE),
353
+ link: guard(MAILY_MARK_TYPES.LINK),
354
+ code: guard(MAILY_MARK_TYPES.CODE),
355
+ textStyle: guard(MAILY_MARK_TYPES.TEXT_STYLE),
356
+ highlight: guard(MAILY_MARK_TYPES.HIGHLIGHT)
357
+ };
358
+ /** Type guard that checks if a value is defined (not null or undefined). */
359
+ function isDef(val) {
360
+ return val !== void 0 && val !== null;
361
+ }
362
+ /** Type guard that checks if a value is a boolean. */
363
+ function isBoolean(val) {
364
+ return typeof val === "boolean";
365
+ }
366
+ /** Type guard that checks if a value is a number. */
367
+ function isNumber(val) {
368
+ return typeof val === "number";
369
+ }
370
+ /** Type guard that checks if a value is a string. */
371
+ function isString(val) {
372
+ return typeof val === "string";
373
+ }
374
+ /** Type guard that checks if a value is a non-null object. */
375
+ function isObject(val) {
376
+ return typeof val === "object" && val !== null;
377
+ }
378
+ //#endregion
379
+ //#region src/font-style.ts
380
+ /**
381
+ * Built-in font options served from the Maily CDN. System fonts
382
+ * (Arial, Helvetica, etc.) are included without a webFont field.
383
+ */
384
+ const DEFAULT_FONT_FAMILIES = [
385
+ {
386
+ fontFamily: "Inter",
387
+ webFont: {
388
+ url: "https://cdn.usemaily.com/fonts/v0/inter.woff2",
389
+ format: "woff2"
390
+ }
391
+ },
392
+ {
393
+ fontFamily: "Roboto",
394
+ webFont: {
395
+ url: "https://cdn.usemaily.com/fonts/v0/roboto.woff2",
396
+ format: "woff2"
397
+ }
398
+ },
399
+ {
400
+ fontFamily: "Open Sans",
401
+ webFont: {
402
+ url: "https://cdn.usemaily.com/fonts/v0/open-sans.woff2",
403
+ format: "woff2"
404
+ }
405
+ },
406
+ {
407
+ fontFamily: "Lato",
408
+ webFont: {
409
+ url: "https://cdn.usemaily.com/fonts/v0/lato.woff2",
410
+ format: "woff2"
411
+ }
412
+ },
413
+ {
414
+ fontFamily: "Montserrat",
415
+ webFont: {
416
+ url: "https://cdn.usemaily.com/fonts/v0/montserrat.woff2",
417
+ format: "woff2"
418
+ }
419
+ },
420
+ {
421
+ fontFamily: "Poppins",
422
+ webFont: {
423
+ url: "https://cdn.usemaily.com/fonts/v0/poppins.woff2",
424
+ format: "woff2"
425
+ }
426
+ },
427
+ {
428
+ fontFamily: "Raleway",
429
+ webFont: {
430
+ url: "https://cdn.usemaily.com/fonts/v0/raleway.woff2",
431
+ format: "woff2"
432
+ }
433
+ },
434
+ {
435
+ fontFamily: "Ubuntu",
436
+ webFont: {
437
+ url: "https://cdn.usemaily.com/fonts/v0/ubuntu.woff2",
438
+ format: "woff2"
439
+ }
440
+ },
441
+ { fontFamily: "Arial" },
442
+ { fontFamily: "Helvetica" },
443
+ { fontFamily: "Georgia" },
444
+ { fontFamily: "Times New Roman" },
445
+ { fontFamily: "Verdana" },
446
+ { fontFamily: "Courier New" },
447
+ { fontFamily: "Trebuchet MS" }
448
+ ];
449
+ const FONT_STYLES = {
450
+ NORMAL: "normal",
451
+ ITALIC: "italic"
452
+ };
453
+ /** Preset options for the font size dropdown in the editor. */
454
+ const FONT_SIZE_PRESETS = [
455
+ {
456
+ value: 12,
457
+ label: "Small"
458
+ },
459
+ {
460
+ value: 14,
461
+ label: "Normal"
462
+ },
463
+ {
464
+ value: 16,
465
+ label: "Medium"
466
+ },
467
+ {
468
+ value: 18,
469
+ label: "Large"
470
+ },
471
+ {
472
+ value: 24,
473
+ label: "XL"
474
+ },
475
+ {
476
+ value: 32,
477
+ label: "2XL"
478
+ }
479
+ ];
480
+ /** Preset options for the line height dropdown in the editor. */
481
+ const LINE_HEIGHT_PRESETS = [
482
+ {
483
+ value: 1,
484
+ label: "Tight"
485
+ },
486
+ {
487
+ value: 1.25,
488
+ label: "Snug"
489
+ },
490
+ {
491
+ value: 1.5,
492
+ label: "Normal"
493
+ },
494
+ {
495
+ value: 1.75,
496
+ label: "Relaxed"
497
+ },
498
+ {
499
+ value: 2,
500
+ label: "Loose"
501
+ }
502
+ ];
503
+ const DEFAULT_FONT_FAMILY = "Inter";
504
+ const DEFAULT_FONT_SIZE = 15;
505
+ const DEFAULT_FONT_WEIGHT = 400;
506
+ const DEFAULT_LINE_HEIGHT = 1.75;
507
+ const DEFAULT_FONT_FALLBACK = "sans-serif";
508
+ /**
509
+ * Builds a CSS properties object from a node's font attributes,
510
+ * falling back to the provided defaults for any null values.
511
+ * Only includes properties that have a resolved value.
512
+ */
513
+ function getFontStyle(attrs, defaults) {
514
+ const { fontFamily, fontFallback, fontSize, fontWeight, lineHeight, fontStyle } = attrs;
515
+ const size = fontSize ?? defaults?.fontSize;
516
+ const weight = fontWeight ?? defaults?.fontWeight;
517
+ const line = lineHeight ?? defaults?.lineHeight;
518
+ const style = fontStyle ?? defaults?.fontStyle;
519
+ const fontFamilyParts = [fontFamily, fontFallback].filter(Boolean);
520
+ return {
521
+ ...fontFamilyParts.length > 0 && { fontFamily: fontFamilyParts.join(", ") },
522
+ ...isDef(size) ? { fontSize: `${size}px` } : {},
523
+ ...isDef(weight) ? { fontWeight: weight } : {},
524
+ ...isDef(line) ? { lineHeight: line } : {},
525
+ ...isDef(style) ? { fontStyle: style } : {}
526
+ };
527
+ }
528
+ //#endregion
529
+ //#region src/font-weight.ts
530
+ /**
531
+ * Numeric font weight values mapped to semantic names.
532
+ * Normal (400), Medium (500), Semibold (600), Bold (700), Extra Bold (800).
533
+ */
534
+ const FONT_WEIGHTS = {
535
+ NORMAL: 400,
536
+ MEDIUM: 500,
537
+ SEMIBOLD: 600,
538
+ BOLD: 700,
539
+ EXTRA_BOLD: 800
540
+ };
541
+ //#endregion
542
+ //#region src/function.ts
543
+ /** A no-operation function. Useful as a default callback or placeholder. */
544
+ function noop() {}
545
+ //#endregion
546
+ //#region src/invariant.ts
547
+ function invariant(value, message) {
548
+ if (value === false || value === null || typeof value === "undefined") {
549
+ console.error(`${MAILY_ERROR_PREFIX}: The following error is a bug in Maily;
550
+ Please open an issue! ${MAILY_BUG_REPORT_URL}`);
551
+ throw new Error(message);
552
+ }
553
+ }
554
+ //#endregion
555
+ //#region src/margin.ts
556
+ /**
557
+ * Converts a MarginStyleConfig into CSS properties for inline styles.
558
+ * When all sides are equal (or mode is "uniform"), emits shorthand CSS;
559
+ * otherwise emits per-side longhand properties.
560
+ */
561
+ function getMarginStyle(config) {
562
+ const { marginMode, marginTop, marginRight, marginBottom, marginLeft } = config;
563
+ if (marginMode === FIELD_MODE.UNIFORM || marginLeft === marginRight && marginRight === marginBottom && marginBottom === marginTop) return { margin: `${marginTop}px` };
564
+ return {
565
+ marginTop: `${marginTop}px`,
566
+ marginRight: `${marginRight}px`,
567
+ marginBottom: `${marginBottom}px`,
568
+ marginLeft: `${marginLeft}px`
569
+ };
570
+ }
571
+ //#endregion
572
+ //#region src/object.ts
573
+ function isMergableObject(value) {
574
+ return value !== null && typeof value === "object" && !Array.isArray(value);
575
+ }
576
+ /**
577
+ * One-level deep merge of plain objects. Nested plain objects are
578
+ * shallow-merged; primitives, arrays, and null are replaced outright.
579
+ * Does not mutate the target — returns a new object.
580
+ *
581
+ * Example:
582
+ * deepMerge({ a: 1, nested: { x: 1, y: 2 } }, { nested: { y: 3 } })
583
+ * // => { a: 1, nested: { x: 1, y: 3 } }
584
+ */
585
+ function deepMerge(target, ...sources) {
586
+ const result = { ...target };
587
+ for (const source of sources) for (const [key, value] of Object.entries(source)) result[key] = isMergableObject(value) && isMergableObject(result[key]) ? {
588
+ ...result[key],
589
+ ...value
590
+ } : value;
591
+ return result;
592
+ }
593
+ function isObjectDeepEqual(first, second) {
594
+ if (first === second) return true;
595
+ for (const key of Object.keys(first)) if (first[key] !== second[key]) return false;
596
+ return true;
597
+ }
598
+ //#endregion
599
+ //#region src/padding.ts
600
+ /**
601
+ * Converts a PaddingStyleConfig into CSS properties for inline styles.
602
+ * When all sides are equal (or mode is "uniform"), emits shorthand CSS;
603
+ * otherwise emits per-side longhand properties.
604
+ */
605
+ function getPaddingStyle(config) {
606
+ const { paddingMode, paddingTop, paddingRight, paddingBottom, paddingLeft } = config;
607
+ if (paddingMode === FIELD_MODE.UNIFORM || paddingLeft === paddingRight && paddingRight === paddingBottom && paddingBottom === paddingTop) return { padding: `${paddingTop}px` };
608
+ return {
609
+ paddingTop: `${paddingTop}px`,
610
+ paddingRight: `${paddingRight}px`,
611
+ paddingBottom: `${paddingBottom}px`,
612
+ paddingLeft: `${paddingLeft}px`
613
+ };
614
+ }
615
+ //#endregion
616
+ //#region src/promise.ts
617
+ /** Returns a promise that resolves after the given number of milliseconds. */
618
+ function sleep(ms) {
619
+ return new Promise((resolve) => setTimeout(resolve, ms));
620
+ }
621
+ //#endregion
622
+ //#region src/text-direction.ts
623
+ /** Text direction values matching the HTML `dir` attribute: ltr, rtl, auto. */
624
+ const TEXT_DIRECTIONS = {
625
+ LTR: "ltr",
626
+ RTL: "rtl",
627
+ AUTO: "auto"
628
+ };
629
+ const allowedTextDirections = Object.freeze(Object.values(TEXT_DIRECTIONS));
630
+ const DEFAULT_TEXT_DIRECTION = TEXT_DIRECTIONS.AUTO;
631
+ function isAllowedTextDirection(value) {
632
+ return typeof value === "string" && allowedTextDirections.includes(value);
633
+ }
634
+ /**
635
+ * Returns a CSS `direction` property object for the given dir value.
636
+ * Returns an empty object for "auto" or nullish values, since the
637
+ * browser default is sufficient in those cases.
638
+ */
639
+ function getCssDirection(dir) {
640
+ if (dir && dir !== TEXT_DIRECTIONS.AUTO) return { direction: dir };
641
+ return {};
642
+ }
643
+ //#endregion
644
+ //#region src/theme.ts
30
645
  const DEFAULT_LINK_TEXT_COLOR = "#111827";
31
646
  const DEFAULT_RENDERER_THEME = {
32
- colors: {
33
- heading: "#111827",
34
- paragraph: "#374151",
35
- horizontal: "#EAEAEA",
36
- footer: "#64748B",
37
- blockquoteBorder: "#D1D5DB",
38
- codeBackground: "#EFEFEF",
39
- codeText: "#111827",
40
- linkCardTitle: "#111827",
41
- linkCardDescription: "#6B7280",
42
- linkCardBadgeText: "#111827",
43
- linkCardBadgeBackground: "#FEF08A",
44
- linkCardSubTitle: "#6B7280"
45
- },
46
- fontSize: {
47
- paragraph: {
48
- size: "15px",
49
- lineHeight: "26.25px"
647
+ paragraph: {
648
+ color: "#374151",
649
+ fontSize: 15,
650
+ lineHeight: 1.75,
651
+ fontWeight: FONT_WEIGHTS.NORMAL
652
+ },
653
+ heading: {
654
+ defaults: { color: "#111827" },
655
+ h1: {
656
+ fontSize: 36,
657
+ lineHeight: 1.1111111,
658
+ fontWeight: FONT_WEIGHTS.SEMIBOLD
659
+ },
660
+ h2: {
661
+ fontSize: 30,
662
+ lineHeight: 1.3333333,
663
+ fontWeight: FONT_WEIGHTS.SEMIBOLD
50
664
  },
51
- footer: {
52
- size: "14px",
53
- lineHeight: "24px"
665
+ h3: {
666
+ fontSize: 24,
667
+ lineHeight: 1.6,
668
+ fontWeight: FONT_WEIGHTS.SEMIBOLD
54
669
  }
55
670
  },
671
+ footer: {
672
+ color: "#64748B",
673
+ fontSize: 14,
674
+ lineHeight: 1.7142857,
675
+ fontWeight: FONT_WEIGHTS.NORMAL
676
+ },
677
+ blockquote: {
678
+ color: "#374151",
679
+ borderColor: "#D1D5DB",
680
+ fontSize: 15,
681
+ lineHeight: 1.75,
682
+ fontWeight: FONT_WEIGHTS.MEDIUM,
683
+ fontStyle: FONT_STYLES.ITALIC
684
+ },
685
+ horizontalRule: { color: "#EAEAEA" },
686
+ code: {
687
+ color: "#111827",
688
+ backgroundColor: "#EFEFEF"
689
+ },
690
+ linkCard: {
691
+ titleColor: "#111827",
692
+ descriptionColor: "#374151",
693
+ badgeTextColor: "#374151",
694
+ badgeBackgroundColor: "#fff085",
695
+ subTitleColor: "#6B7280",
696
+ borderColor: "#E5E7EB"
697
+ },
56
698
  container: {
57
699
  backgroundColor: "#ffffff",
58
- maxWidth: "600px",
59
- minWidth: "300px",
60
- paddingTop: "0.5rem",
61
- paddingRight: "0.5rem",
62
- paddingBottom: "0.5rem",
63
- paddingLeft: "0.5rem",
64
- borderRadius: "0px",
65
- borderWidth: "0px",
700
+ maxWidth: 600,
701
+ minWidth: 300,
702
+ paddingTop: 8,
703
+ paddingRight: 8,
704
+ paddingBottom: 8,
705
+ paddingLeft: 8,
706
+ borderRadius: 0,
707
+ borderWidth: 0,
66
708
  borderColor: "transparent"
67
709
  },
68
710
  body: {
69
711
  backgroundColor: "#ffffff",
70
- paddingTop: "0px",
71
- paddingRight: "0px",
72
- paddingBottom: "0px",
73
- paddingLeft: "0px"
712
+ paddingTop: 0,
713
+ paddingRight: 0,
714
+ paddingBottom: 0,
715
+ paddingLeft: 0
74
716
  },
75
717
  button: {
76
718
  backgroundColor: "#000000",
77
719
  color: "#ffffff",
78
- paddingTop: "10px",
79
- paddingRight: "32px",
80
- paddingBottom: "10px",
81
- paddingLeft: "32px"
720
+ paddingTop: 10,
721
+ paddingRight: 32,
722
+ paddingBottom: 10,
723
+ paddingLeft: 32,
724
+ fontSize: 14,
725
+ lineHeight: 1.4285714,
726
+ fontWeight: FONT_WEIGHTS.SEMIBOLD
82
727
  },
83
728
  link: { color: DEFAULT_LINK_TEXT_COLOR },
729
+ listMarker: { color: "#d1d5dc" },
84
730
  font: DEFAULT_FONT
85
731
  };
86
732
  const DEFAULT_EDITOR_THEME = {
87
733
  container: {
88
734
  backgroundColor: "#ffffff",
89
- maxWidth: "600px",
90
- minWidth: "300px",
91
- paddingTop: "8px",
92
- paddingRight: "8px",
93
- paddingBottom: "8px",
94
- paddingLeft: "8px",
95
- borderRadius: "0px",
96
- borderWidth: "0px",
735
+ maxWidth: 600,
736
+ minWidth: 300,
737
+ paddingTop: 8,
738
+ paddingRight: 8,
739
+ paddingBottom: 8,
740
+ paddingLeft: 8,
741
+ borderRadius: 0,
742
+ borderWidth: 0,
97
743
  borderColor: "transparent"
98
744
  },
99
745
  body: {
100
746
  backgroundColor: "#ffffff",
101
- paddingTop: "0px",
102
- paddingRight: "0px",
103
- paddingBottom: "0px",
104
- paddingLeft: "0px"
747
+ paddingTop: 0,
748
+ paddingRight: 0,
749
+ paddingBottom: 0,
750
+ paddingLeft: 0
105
751
  },
106
752
  button: {
107
753
  backgroundColor: "#000000",
108
754
  color: "#ffffff",
109
- paddingTop: "10px",
110
- paddingRight: "32px",
111
- paddingBottom: "10px",
112
- paddingLeft: "32px"
755
+ paddingTop: 10,
756
+ paddingRight: 32,
757
+ paddingBottom: 10,
758
+ paddingLeft: 32
113
759
  },
114
760
  link: { color: DEFAULT_LINK_TEXT_COLOR },
115
761
  font: DEFAULT_FONT
116
762
  };
117
-
763
+ /**
764
+ * Resolves the baseline font defaults for a node type from the
765
+ * renderer theme. Falls back to paragraph defaults for unknown types.
766
+ */
767
+ function getNodeFontStyleDefaults(nodeType, level) {
768
+ const paragraph = DEFAULT_RENDERER_THEME.paragraph;
769
+ const fallback = {
770
+ fontSize: paragraph.fontSize,
771
+ lineHeight: paragraph.lineHeight,
772
+ fontWeight: paragraph.fontWeight
773
+ };
774
+ if (nodeType === MAILY_NODE_TYPES.HEADING) {
775
+ const heading = DEFAULT_RENDERER_THEME.heading;
776
+ const key = `h${level ?? 1}`;
777
+ const entry = heading?.[key];
778
+ return {
779
+ fontSize: entry?.fontSize ?? fallback.fontSize,
780
+ lineHeight: entry?.lineHeight ?? fallback.lineHeight,
781
+ fontWeight: entry?.fontWeight ?? fallback.fontWeight
782
+ };
783
+ }
784
+ if (nodeType === MAILY_NODE_TYPES.BUTTON) {
785
+ const btn = DEFAULT_RENDERER_THEME.button;
786
+ return {
787
+ fontSize: btn?.fontSize ?? fallback.fontSize,
788
+ lineHeight: btn?.lineHeight ?? fallback.lineHeight,
789
+ fontWeight: btn?.fontWeight ?? fallback.fontWeight
790
+ };
791
+ }
792
+ if (nodeType === MAILY_NODE_TYPES.BLOCKQUOTE) {
793
+ const bq = DEFAULT_RENDERER_THEME.blockquote;
794
+ return {
795
+ fontSize: bq?.fontSize ?? fallback.fontSize,
796
+ lineHeight: bq?.lineHeight ?? fallback.lineHeight,
797
+ fontWeight: bq?.fontWeight ?? fallback.fontWeight,
798
+ fontStyle: bq?.fontStyle ?? void 0
799
+ };
800
+ }
801
+ if (nodeType === MAILY_NODE_TYPES.FOOTER) {
802
+ const ft = DEFAULT_RENDERER_THEME.footer;
803
+ return {
804
+ fontSize: ft?.fontSize ?? fallback.fontSize,
805
+ lineHeight: ft?.lineHeight ?? fallback.lineHeight,
806
+ fontWeight: ft?.fontWeight ?? fallback.fontWeight
807
+ };
808
+ }
809
+ return fallback;
810
+ }
118
811
  //#endregion
119
- //#region src/css-variables.ts
812
+ //#region src/variable.ts
813
+ /** Default opening delimiter for variable placeholders in text. */
814
+ const DEFAULT_VARIABLE_START_TRIGGER = "{{";
815
+ /** Default closing delimiter for variable placeholders in text. */
816
+ const DEFAULT_VARIABLE_END_TRIGGER = "}}";
120
817
  /**
121
- * if the value is undefined, it will return an empty object
122
- * so that we don't override the default value
123
- * @param name - The name of the CSS variable
124
- * @param value - The value of the CSS variable
125
- * @returns The CSS variable value
818
+ * Regex that matches variable placeholders like {{name}} in a string.
819
+ * Uses a non-greedy match to handle multiple variables in one string.
126
820
  */
127
- function getVariableValue(name, value) {
128
- if (value === void 0 || value === null || value === "") return {};
129
- return { [name]: value };
130
- }
131
- /**
132
- * Get the CSS variables for the theme
133
- * @param theme - The theme
134
- * @returns The CSS variables
135
- * @example
136
- * ```ts
137
- * const theme = {
138
- * body: {
139
- * backgroundColor: 'red',
140
- * },
141
- * };
142
- *
143
- * const cssVariables = getCssVariables(theme);
144
- *
145
- * console.log(cssVariables);
146
- * // { '--mly-body-background-color': 'red' }
821
+ const VARIABLE_PLACEHOLDER_REGEX = /({{.*?}})/g;
822
+ /**
823
+ * Delimiter used between fields inside a serialized variable string.
824
+ * Format: {{id|label|required|hideDefaultValue}}.
147
825
  */
148
- function getMailyCssVariables(theme) {
149
- const font = theme.font || DEFAULT_FONT;
826
+ const VARIABLE_TEXT_DELIMITER = "|";
827
+ /**
828
+ * Serializes a variable node's attributes into a delimited string.
829
+ * Output format: `{{id|label|required|hideDefaultValue}}`.
830
+ * Used to represent structured variable data as a template string
831
+ * in plain text contexts.
832
+ */
833
+ function serializeVariableToText(variable) {
834
+ const { id, label, required = true, hideDefaultValue = false } = variable;
835
+ return [
836
+ "{{",
837
+ defaultStringifyValue(id),
838
+ "|",
839
+ defaultStringifyValue(label),
840
+ "|",
841
+ required,
842
+ "|",
843
+ hideDefaultValue,
844
+ "}}"
845
+ ].join("");
846
+ }
847
+ function defaultStringifyValue(value) {
848
+ return value ?? "";
849
+ }
850
+ /**
851
+ * Deserializes a variable string back into VariableAttributes.
852
+ * Expected input format: `{{id|label|required|hideDefaultValue}}`.
853
+ * Missing fields default to undefined; boolean fields are parsed
854
+ * from "true"/"false" strings.
855
+ */
856
+ function deserializeVariableFromText(text) {
857
+ const [id, label, required, hideDefaultValue] = text.slice(2, text.length - 2).trim().split("|");
150
858
  return {
151
- ...getVariableValue("--mly-body-background-color", theme.body?.backgroundColor),
152
- ...getVariableValue("--mly-body-padding-top", theme.body?.paddingTop),
153
- ...getVariableValue("--mly-body-padding-right", theme.body?.paddingRight),
154
- ...getVariableValue("--mly-body-padding-bottom", theme.body?.paddingBottom),
155
- ...getVariableValue("--mly-body-padding-left", theme.body?.paddingLeft),
156
- ...getVariableValue("--mly-container-background-color", theme.container?.backgroundColor),
157
- ...getVariableValue("--mly-container-max-width", theme.container?.maxWidth),
158
- ...getVariableValue("--mly-container-min-width", theme.container?.minWidth),
159
- ...getVariableValue("--mly-container-padding-top", theme.container?.paddingTop),
160
- ...getVariableValue("--mly-container-padding-right", theme.container?.paddingRight),
161
- ...getVariableValue("--mly-container-padding-bottom", theme.container?.paddingBottom),
162
- ...getVariableValue("--mly-container-padding-left", theme.container?.paddingLeft),
163
- ...getVariableValue("--mly-container-border-radius", theme.container?.borderRadius),
164
- ...getVariableValue("--mly-container-border-width", theme.container?.borderWidth),
165
- ...getVariableValue("--mly-container-border-color", theme.container?.borderColor),
166
- ...getVariableValue("--mly-button-background-color", theme.button?.backgroundColor),
167
- ...getVariableValue("--mly-button-text-color", theme.button?.color),
168
- ...getVariableValue("--mly-button-padding-top", theme.button?.paddingTop),
169
- ...getVariableValue("--mly-button-padding-right", theme.button?.paddingRight),
170
- ...getVariableValue("--mly-button-padding-bottom", theme.button?.paddingBottom),
171
- ...getVariableValue("--mly-button-padding-left", theme.button?.paddingLeft),
172
- ...getVariableValue("--mly-link-color", theme.link?.color),
173
- ...getVariableValue("--mly-font-family", font.fontFamily),
174
- ...getVariableValue("--mly-font-fallback-family", font.fallbackFontFamily),
175
- "--mly-font": `var(--mly-font-family), var(--mly-font-fallback-family)`
859
+ id,
860
+ label: label || null,
861
+ required: parseBoolean(required, true),
862
+ hideDefaultValue: parseBoolean(hideDefaultValue, false)
176
863
  };
177
864
  }
178
-
179
- //#endregion
180
- //#region src/font.ts
181
- function loadFont(font) {
182
- const style = fontStyle(font);
183
- const styleElement = document.createElement("style");
184
- styleElement.textContent = style;
185
- document.head.appendChild(styleElement);
865
+ /**
866
+ * Parses a string containing variable placeholders (e.g. "Hello {{name}}")
867
+ * into a Tiptap-compatible document JSON with text and variable nodes.
868
+ * Splits on {{...}} boundaries and creates the appropriate node type
869
+ * for each segment.
870
+ */
871
+ function buildDocFromVariableText(content) {
872
+ const parts = content.split(VARIABLE_PLACEHOLDER_REGEX);
873
+ return {
874
+ type: MAILY_NODE_TYPES.DOCUMENT,
875
+ content: [{
876
+ type: MAILY_NODE_TYPES.PARAGRAPH,
877
+ content: parts.flatMap((part) => {
878
+ if (part.startsWith("{{") && part.endsWith("}}")) return {
879
+ type: MAILY_NODE_TYPES.VARIABLE,
880
+ attrs: deserializeVariableFromText(part)
881
+ };
882
+ if (part) return {
883
+ type: MAILY_NODE_TYPES.TEXT,
884
+ text: part
885
+ };
886
+ return [];
887
+ }).filter(Boolean)
888
+ }]
889
+ };
890
+ }
891
+ /**
892
+ * Checks if a string contains at least one variable placeholder.
893
+ * Returns true for strings like "Hello {{name}}", false for plain text.
894
+ * Uses index-based scanning instead of regex for performance.
895
+ */
896
+ function hasVariableInText(text) {
897
+ const start = text.indexOf("{{");
898
+ if (start === -1) return false;
899
+ return text.indexOf("}}", start + 2) !== -1;
186
900
  }
187
- function fontStyle(font) {
188
- const { fontFamily, fallbackFontFamily, webFont } = font;
189
- const src = webFont ? `src: url(${webFont.url}) format('${webFont.format}');` : "";
190
- const style = `
191
- @font-face {
192
- font-family: '${fontFamily}';
193
- font-style: normal;
194
- font-weight: 400;
195
- mso-font-alt: '${fallbackFontFamily}';
196
- ${src}
197
- }`;
198
- return style;
901
+ function parseBoolean(value, defaultValue) {
902
+ if (value === "true") return true;
903
+ if (value === "false") return false;
904
+ return defaultValue;
199
905
  }
200
-
201
906
  //#endregion
202
- export { DEFAULT_EDITOR_THEME, DEFAULT_FONT, DEFAULT_LINK_TEXT_COLOR, DEFAULT_RENDERER_THEME, allowedFallbackFonts, allowedFontFormats, fontStyle, getMailyCssVariables, getVariableValue, loadFont };
907
+ //#region src/visibility.ts
908
+ /**
909
+ * Comparison operators for conditional visibility rules.
910
+ * Used to evaluate a template variable against a value
911
+ * to decide whether a node should be shown or hidden.
912
+ */
913
+ const VISIBILITY_OPERATORS = {
914
+ IS_TRUE: "is_true",
915
+ IS_FALSE: "is_false",
916
+ EQUALS: "equals",
917
+ NOT_EQUALS: "not_equals",
918
+ CONTAINS: "contains",
919
+ NOT_CONTAINS: "not_contains",
920
+ STARTS_WITH: "starts_with",
921
+ ENDS_WITH: "ends_with",
922
+ GREATER_THAN: "greater_than",
923
+ LESS_THAN: "less_than"
924
+ };
925
+ const VISIBILITY_OPERATOR_OPTIONS = [
926
+ {
927
+ value: VISIBILITY_OPERATORS.IS_TRUE,
928
+ label: "Is true"
929
+ },
930
+ {
931
+ value: VISIBILITY_OPERATORS.IS_FALSE,
932
+ label: "Is false"
933
+ },
934
+ {
935
+ value: VISIBILITY_OPERATORS.EQUALS,
936
+ label: "Equals"
937
+ },
938
+ {
939
+ value: VISIBILITY_OPERATORS.NOT_EQUALS,
940
+ label: "Not equals"
941
+ },
942
+ {
943
+ value: VISIBILITY_OPERATORS.CONTAINS,
944
+ label: "Contains"
945
+ },
946
+ {
947
+ value: VISIBILITY_OPERATORS.NOT_CONTAINS,
948
+ label: "Not contains"
949
+ },
950
+ {
951
+ value: VISIBILITY_OPERATORS.STARTS_WITH,
952
+ label: "Starts with"
953
+ },
954
+ {
955
+ value: VISIBILITY_OPERATORS.ENDS_WITH,
956
+ label: "Ends with"
957
+ },
958
+ {
959
+ value: VISIBILITY_OPERATORS.GREATER_THAN,
960
+ label: "Greater than"
961
+ },
962
+ {
963
+ value: VISIBILITY_OPERATORS.LESS_THAN,
964
+ label: "Less than"
965
+ }
966
+ ];
967
+ /**
968
+ * Unary operators that don't require a comparison value.
969
+ * The UI hides the value input field when one of these is selected.
970
+ */
971
+ const OPERATORS_WITHOUT_VALUE = [VISIBILITY_OPERATORS.IS_TRUE, VISIBILITY_OPERATORS.IS_FALSE];
972
+ const VISIBILITY_ACTIONS = {
973
+ NONE: "none",
974
+ SHOW: "show",
975
+ HIDE: "hide"
976
+ };
977
+ const VISIBILITY_ACTION_OPTIONS = [
978
+ {
979
+ value: VISIBILITY_ACTIONS.NONE,
980
+ label: "None"
981
+ },
982
+ {
983
+ value: VISIBILITY_ACTIONS.SHOW,
984
+ label: "Show if"
985
+ },
986
+ {
987
+ value: VISIBILITY_ACTIONS.HIDE,
988
+ label: "Hide if"
989
+ }
990
+ ];
991
+ //#endregion
992
+ export { BORDER_STYLES, BUTTON_KINDS, DATA_NODE_TYPE_KEY, DATA_VISIBILITY_RULE_KEY, DEFAULT_BORDER_COLOR, DEFAULT_BORDER_STYLE, DEFAULT_BUTTON_KIND, DEFAULT_EDITOR_THEME, DEFAULT_FONT, DEFAULT_FONT_FALLBACK, DEFAULT_FONT_FAMILIES, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FONT_WEIGHT, DEFAULT_HTML_CODE_BLOCK_TAB, DEFAULT_LINE_HEIGHT, DEFAULT_LINK_TEXT_COLOR, DEFAULT_RENDERER_THEME, DEFAULT_TEXT_ALIGN, DEFAULT_TEXT_DIRECTION, DEFAULT_VARIABLE_END_TRIGGER, DEFAULT_VARIABLE_START_TRIGGER, FIELD_MODE, FONT_SIZE_PRESETS, FONT_STYLES, FONT_WEIGHTS, HTML_CODE_BLOCK_TABS, LINE_HEIGHT_PRESETS, MAILY_BUG_REPORT_URL, MAILY_ERROR_PREFIX, MAILY_EXTENSION_TYPES, MAILY_MARK_TYPES, MAILY_NODE_TYPES, MAX_IMAGE_WIDTH_PERCENTAGE, MIN_IMAGE_WIDTH_PERCENTAGE, OPERATORS_WITHOUT_VALUE, TEXT_ALIGNMENTS, TEXT_DIRECTIONS, VARIABLE_PLACEHOLDER_REGEX, VARIABLE_TEXT_DELIMITER, VISIBILITY_ACTIONS, VISIBILITY_ACTION_OPTIONS, VISIBILITY_OPERATORS, VISIBILITY_OPERATOR_OPTIONS, absoluteFromPercentage, allowedButtonKinds, allowedFallbackFonts, allowedFieldModes, allowedFontFormats, allowedMarkTypes, allowedNodeTypes, allowedTextAligns, allowedTextDirections, buildDocFromVariableText, clamp, clampImageWidthPercentage, deepMerge, deserializeVariableFromText, getBorderStyle, getCssDirection, getFontFaceStyle, getFontStyle, getMailyCssVariables, getMarginStyle, getNodeFontStyleDefaults, getPaddingStyle, getVariableValue, hasVariableInText, invariant, is, isAllowedButtonKind, isAllowedFieldMode, isAllowedTextAlignment, isAllowedTextDirection, isBoolean, isDef, isNumber, isObject, isObjectDeepEqual, isString, loadFont, noop, parseWidthToPercentage, percentage, roundTo, serializeVariableToText, sleep };
993
+
203
994
  //# sourceMappingURL=index.mjs.map