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

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