@savvycal/mjml-editor 0.0.1 → 0.0.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.
Files changed (173) hide show
  1. package/README.md +176 -0
  2. package/dist/components/editor/BlockIcon.d.ts +7 -0
  3. package/dist/components/editor/BlockIcon.d.ts.map +1 -0
  4. package/dist/components/editor/BlockInspector.d.ts +6 -0
  5. package/dist/components/editor/BlockInspector.d.ts.map +1 -0
  6. package/dist/components/editor/BlockInspector.js +380 -0
  7. package/dist/components/editor/EditorCanvas.d.ts +11 -0
  8. package/dist/components/editor/EditorCanvas.d.ts.map +1 -0
  9. package/dist/components/editor/EditorCanvas.js +116 -0
  10. package/dist/components/editor/FontEditor.d.ts +2 -0
  11. package/dist/components/editor/FontEditor.d.ts.map +1 -0
  12. package/dist/components/editor/FontEditor.js +227 -0
  13. package/dist/components/editor/GlobalStylesPanel.d.ts +7 -0
  14. package/dist/components/editor/GlobalStylesPanel.d.ts.map +1 -0
  15. package/dist/components/editor/GlobalStylesPanel.js +310 -0
  16. package/dist/components/editor/InteractivePreview.d.ts +8 -0
  17. package/dist/components/editor/InteractivePreview.d.ts.map +1 -0
  18. package/dist/components/editor/InteractivePreview.js +120 -0
  19. package/dist/components/editor/LiquidAutocomplete.d.ts +10 -0
  20. package/dist/components/editor/LiquidAutocomplete.d.ts.map +1 -0
  21. package/dist/components/editor/LiquidAutocomplete.js +70 -0
  22. package/dist/components/editor/LiquidInput.d.ts +12 -0
  23. package/dist/components/editor/LiquidInput.d.ts.map +1 -0
  24. package/dist/components/editor/LiquidInput.js +185 -0
  25. package/dist/components/editor/MjmlEditor.d.ts +11 -0
  26. package/dist/components/editor/MjmlEditor.d.ts.map +1 -0
  27. package/dist/components/editor/MjmlEditor.js +111 -0
  28. package/dist/components/editor/OutlineTree.d.ts +7 -0
  29. package/dist/components/editor/OutlineTree.d.ts.map +1 -0
  30. package/dist/components/editor/OutlineTree.js +282 -0
  31. package/dist/components/editor/SourceEditor.d.ts +2 -0
  32. package/dist/components/editor/SourceEditor.d.ts.map +1 -0
  33. package/dist/components/editor/SourceEditor.js +70 -0
  34. package/dist/components/editor/SourcePreview.d.ts +7 -0
  35. package/dist/components/editor/SourcePreview.d.ts.map +1 -0
  36. package/dist/components/editor/SourcePreview.js +55 -0
  37. package/dist/components/editor/TiptapEditor.d.ts +12 -0
  38. package/dist/components/editor/TiptapEditor.d.ts.map +1 -0
  39. package/dist/components/editor/TiptapEditor.js +330 -0
  40. package/dist/components/editor/VisualEditor.d.ts +7 -0
  41. package/dist/components/editor/VisualEditor.d.ts.map +1 -0
  42. package/dist/components/editor/VisualEditor.js +51 -0
  43. package/dist/components/editor/visual-blocks/VisualBlock.d.ts +7 -0
  44. package/dist/components/editor/visual-blocks/VisualBlock.d.ts.map +1 -0
  45. package/dist/components/editor/visual-blocks/VisualBlock.js +34 -0
  46. package/dist/components/editor/visual-blocks/VisualButton.d.ts +7 -0
  47. package/dist/components/editor/visual-blocks/VisualButton.d.ts.map +1 -0
  48. package/dist/components/editor/visual-blocks/VisualButton.js +111 -0
  49. package/dist/components/editor/visual-blocks/VisualColumn.d.ts +8 -0
  50. package/dist/components/editor/visual-blocks/VisualColumn.d.ts.map +1 -0
  51. package/dist/components/editor/visual-blocks/VisualColumn.js +44 -0
  52. package/dist/components/editor/visual-blocks/VisualDivider.d.ts +7 -0
  53. package/dist/components/editor/visual-blocks/VisualDivider.d.ts.map +1 -0
  54. package/dist/components/editor/visual-blocks/VisualDivider.js +41 -0
  55. package/dist/components/editor/visual-blocks/VisualImage.d.ts +7 -0
  56. package/dist/components/editor/visual-blocks/VisualImage.d.ts.map +1 -0
  57. package/dist/components/editor/visual-blocks/VisualImage.js +48 -0
  58. package/dist/components/editor/visual-blocks/VisualRaw.d.ts +7 -0
  59. package/dist/components/editor/visual-blocks/VisualRaw.d.ts.map +1 -0
  60. package/dist/components/editor/visual-blocks/VisualRaw.js +32 -0
  61. package/dist/components/editor/visual-blocks/VisualSection.d.ts +7 -0
  62. package/dist/components/editor/visual-blocks/VisualSection.d.ts.map +1 -0
  63. package/dist/components/editor/visual-blocks/VisualSection.js +131 -0
  64. package/dist/components/editor/visual-blocks/VisualSocial.d.ts +7 -0
  65. package/dist/components/editor/visual-blocks/VisualSocial.d.ts.map +1 -0
  66. package/dist/components/editor/visual-blocks/VisualSocial.js +62 -0
  67. package/dist/components/editor/visual-blocks/VisualSpacer.d.ts +7 -0
  68. package/dist/components/editor/visual-blocks/VisualSpacer.d.ts.map +1 -0
  69. package/dist/components/editor/visual-blocks/VisualSpacer.js +30 -0
  70. package/dist/components/editor/visual-blocks/VisualText.d.ts +7 -0
  71. package/dist/components/editor/visual-blocks/VisualText.d.ts.map +1 -0
  72. package/dist/components/editor/visual-blocks/VisualText.js +103 -0
  73. package/dist/components/editor/visual-blocks/helpers.d.ts +13 -0
  74. package/dist/components/editor/visual-blocks/helpers.d.ts.map +1 -0
  75. package/dist/components/editor/visual-blocks/helpers.js +44 -0
  76. package/dist/components/editor/visual-blocks/useResolvedAttributes.d.ts +7 -0
  77. package/dist/components/editor/visual-blocks/useResolvedAttributes.d.ts.map +1 -0
  78. package/dist/components/editor/visual-blocks/useResolvedAttributes.js +12 -0
  79. package/dist/components/ui/badge.d.ts +10 -0
  80. package/dist/components/ui/badge.d.ts.map +1 -0
  81. package/dist/components/ui/badge.js +26 -0
  82. package/dist/components/ui/button.d.ts +11 -0
  83. package/dist/components/ui/button.d.ts.map +1 -0
  84. package/dist/components/ui/button.js +54 -0
  85. package/dist/components/ui/card.d.ts +10 -0
  86. package/dist/components/ui/card.d.ts.map +1 -0
  87. package/dist/components/ui/collapsible.d.ts +6 -0
  88. package/dist/components/ui/collapsible.d.ts.map +1 -0
  89. package/dist/components/ui/collapsible.js +7 -0
  90. package/dist/components/ui/floating-panel.d.ts +12 -0
  91. package/dist/components/ui/floating-panel.d.ts.map +1 -0
  92. package/dist/components/ui/floating-panel.js +54 -0
  93. package/dist/components/ui/input.d.ts +4 -0
  94. package/dist/components/ui/input.d.ts.map +1 -0
  95. package/dist/components/ui/input.js +26 -0
  96. package/dist/components/ui/label.d.ts +5 -0
  97. package/dist/components/ui/label.d.ts.map +1 -0
  98. package/dist/components/ui/label.js +23 -0
  99. package/dist/components/ui/popover.d.ts +8 -0
  100. package/dist/components/ui/popover.d.ts.map +1 -0
  101. package/dist/components/ui/popover.js +39 -0
  102. package/dist/components/ui/resizable-split-pane.d.ts +10 -0
  103. package/dist/components/ui/resizable-split-pane.d.ts.map +1 -0
  104. package/dist/components/ui/resizable-split-pane.js +65 -0
  105. package/dist/components/ui/scroll-area.d.ts +10 -0
  106. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  107. package/dist/components/ui/scroll-area.js +69 -0
  108. package/dist/components/ui/select.d.ts +16 -0
  109. package/dist/components/ui/select.d.ts.map +1 -0
  110. package/dist/components/ui/select.js +145 -0
  111. package/dist/components/ui/separator.d.ts +5 -0
  112. package/dist/components/ui/separator.d.ts.map +1 -0
  113. package/dist/components/ui/tabs.d.ts +8 -0
  114. package/dist/components/ui/tabs.d.ts.map +1 -0
  115. package/dist/components/ui/tabs.js +68 -0
  116. package/dist/components/ui/theme-toggle.d.ts +2 -0
  117. package/dist/components/ui/theme-toggle.d.ts.map +1 -0
  118. package/dist/components/ui/theme-toggle.js +58 -0
  119. package/dist/context/EditorContext.d.ts +40 -0
  120. package/dist/context/EditorContext.d.ts.map +1 -0
  121. package/dist/context/EditorContext.js +576 -0
  122. package/dist/context/LiquidSchemaContext.d.ts +10 -0
  123. package/dist/context/LiquidSchemaContext.d.ts.map +1 -0
  124. package/dist/context/LiquidSchemaContext.js +16 -0
  125. package/dist/context/ThemeContext.d.ts +18 -0
  126. package/dist/context/ThemeContext.d.ts.map +1 -0
  127. package/dist/context/ThemeContext.js +53 -0
  128. package/dist/extensions/LiquidHighlight.d.ts +3 -0
  129. package/dist/extensions/LiquidHighlight.d.ts.map +1 -0
  130. package/dist/extensions/LiquidHighlight.js +58 -0
  131. package/dist/extensions/LiquidSuggestion.d.ts +18 -0
  132. package/dist/extensions/LiquidSuggestion.d.ts.map +1 -0
  133. package/dist/extensions/LiquidSuggestion.js +119 -0
  134. package/dist/hooks/useFontLoader.d.ts +6 -0
  135. package/dist/hooks/useFontLoader.d.ts.map +1 -0
  136. package/dist/hooks/useFontLoader.js +21 -0
  137. package/dist/hooks/useStyleLoader.d.ts +11 -0
  138. package/dist/hooks/useStyleLoader.d.ts.map +1 -0
  139. package/dist/hooks/useStyleLoader.js +26 -0
  140. package/dist/index.d.ts +6 -150
  141. package/dist/index.d.ts.map +1 -0
  142. package/dist/index.js +7 -57452
  143. package/dist/lib/html-utils.d.ts +23 -0
  144. package/dist/lib/html-utils.d.ts.map +1 -0
  145. package/dist/lib/html-utils.js +25 -0
  146. package/dist/lib/mjml/attributes.d.ts +100 -0
  147. package/dist/lib/mjml/attributes.d.ts.map +1 -0
  148. package/dist/lib/mjml/attributes.js +105 -0
  149. package/dist/lib/mjml/parser.d.ts +67 -0
  150. package/dist/lib/mjml/parser.d.ts.map +1 -0
  151. package/dist/lib/mjml/parser.js +184 -0
  152. package/dist/lib/mjml/parser.test.d.ts +2 -0
  153. package/dist/lib/mjml/parser.test.d.ts.map +1 -0
  154. package/dist/lib/mjml/renderer.d.ts +23 -0
  155. package/dist/lib/mjml/renderer.d.ts.map +1 -0
  156. package/dist/lib/mjml/renderer.js +72 -0
  157. package/dist/lib/mjml/schema.d.ts +21 -0
  158. package/dist/lib/mjml/schema.d.ts.map +1 -0
  159. package/dist/lib/mjml/schema.js +1307 -0
  160. package/dist/lib/mjml/scopeCSS.d.ts +21 -0
  161. package/dist/lib/mjml/scopeCSS.d.ts.map +1 -0
  162. package/dist/lib/mjml/scopeCSS.js +67 -0
  163. package/dist/lib/utils.d.ts +3 -0
  164. package/dist/lib/utils.d.ts.map +1 -0
  165. package/dist/lib/utils.js +8 -0
  166. package/dist/styles.d.ts +1 -0
  167. package/dist/styles.d.ts.map +1 -0
  168. package/dist/styles.js +1 -0
  169. package/dist/types/liquid.d.ts +28 -0
  170. package/dist/types/liquid.d.ts.map +1 -0
  171. package/dist/types/mjml.d.ts +101 -0
  172. package/dist/types/mjml.d.ts.map +1 -0
  173. package/package.json +12 -9
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Sanitize HTML output from Tiptap for MJML compatibility.
3
+ *
4
+ * Tiptap outputs semantic HTML with <p> tags that may not render well
5
+ * in all email clients. This function normalizes the output to use
6
+ * <br /> for line breaks.
7
+ */
8
+ export declare function sanitizeHtmlForMjml(html: string): string;
9
+ /**
10
+ * Convert MJML content to Tiptap-compatible HTML.
11
+ *
12
+ * MJML content uses <br /> for line breaks. Tiptap expects
13
+ * content wrapped in <p> tags.
14
+ */
15
+ export declare function mjmlToTiptapHtml(content: string): string;
16
+ /**
17
+ * Highlight Liquid template syntax in HTML content.
18
+ *
19
+ * Wraps {{ variable }} and {% tag %} patterns with a span
20
+ * that has the liquid-highlight class for visual styling.
21
+ */
22
+ export declare function highlightLiquidTags(html: string): string;
23
+ //# sourceMappingURL=html-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-utils.d.ts","sourceRoot":"","sources":["../../src/lib/html-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBxD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAcxD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBxD"}
@@ -0,0 +1,25 @@
1
+ function p(i) {
2
+ if (!i || i === "<p></p>")
3
+ return "";
4
+ let r = i.replace(/<p>/g, "");
5
+ return r = r.replace(/<\/p>/g, "<br />"), r = r.replace(/(<br\s*\/?>)+$/, ""), r = r.replace(/<br>/gi, "<br />"), r;
6
+ }
7
+ function l(i) {
8
+ return !i || i.trim() === "" ? "<p></p>" : i.includes("<p>") ? i : i.split(/<br\s*\/?>/gi).map((e) => `<p>${e}</p>`).join("");
9
+ }
10
+ function s(i) {
11
+ if (!i) return i;
12
+ let r = i.replace(
13
+ /(\{\{[^{}]*\}\})/g,
14
+ '<span class="liquid-highlight">$1</span>'
15
+ );
16
+ return r = r.replace(
17
+ /(\{%[^{}]*%\})/g,
18
+ '<span class="liquid-highlight">$1</span>'
19
+ ), r;
20
+ }
21
+ export {
22
+ s as highlightLiquidTags,
23
+ l as mjmlToTiptapHtml,
24
+ p as sanitizeHtmlForMjml
25
+ };
@@ -0,0 +1,100 @@
1
+ import { MjmlNode, ComponentSchema } from '../../types/mjml';
2
+ /**
3
+ * Configuration extracted from mj-attributes in mj-head
4
+ */
5
+ export interface MjmlAttributesConfig {
6
+ /** Attributes from mj-all that apply to all elements */
7
+ all: Record<string, string>;
8
+ /** Element-specific defaults (tagName -> attributes) */
9
+ elements: Record<string, Record<string, string>>;
10
+ /** Named classes (className -> attributes) */
11
+ classes: Record<string, Record<string, string>>;
12
+ }
13
+ /**
14
+ * Create an empty mj-attributes configuration
15
+ */
16
+ export declare function createEmptyConfig(): MjmlAttributesConfig;
17
+ /**
18
+ * Get the mj-head node from a document
19
+ */
20
+ export declare function getHead(document: MjmlNode): MjmlNode | null;
21
+ /**
22
+ * Get the mj-body node from a document
23
+ */
24
+ export declare function getBody(document: MjmlNode): MjmlNode | null;
25
+ /**
26
+ * Get the mj-attributes node from mj-head
27
+ */
28
+ export declare function getMjAttributes(document: MjmlNode): MjmlNode | null;
29
+ /**
30
+ * Extract mj-attributes configuration from a document's mj-head
31
+ */
32
+ export declare function extractMjmlAttributes(document: MjmlNode): MjmlAttributesConfig;
33
+ /**
34
+ * Parse space-separated class names from mj-class attribute value
35
+ */
36
+ export declare function parseClassNames(mjClassValue: string | undefined): string[];
37
+ /**
38
+ * Get list of defined class names from the document
39
+ */
40
+ export declare function getDefinedClasses(document: MjmlNode): string[];
41
+ /**
42
+ * Resolve effective attributes for a node by applying the MJML cascade.
43
+ *
44
+ * Order of precedence (later overrides earlier):
45
+ * 1. mj-all attributes
46
+ * 2. Element-type defaults (mj-text, mj-section, etc.)
47
+ * 3. mj-class attributes (if node has mj-class)
48
+ * 4. Per-element attributes
49
+ *
50
+ * Note: Schema defaults are NOT included here - they are handled
51
+ * at the component level for backward compatibility.
52
+ */
53
+ export declare function resolveAttributes(node: MjmlNode, mjmlAttributes: MjmlAttributesConfig): Record<string, string>;
54
+ /**
55
+ * Get the inherited value for a specific attribute (for placeholder display).
56
+ *
57
+ * This returns the value that would be used if the node doesn't override it,
58
+ * computed from the cascade (mj-all -> element-type -> mj-class -> schema default).
59
+ *
60
+ * Returns undefined if there is no inherited value.
61
+ */
62
+ export declare function getInheritedValue(node: MjmlNode, attributeKey: string, mjmlAttributes: MjmlAttributesConfig, schema: ComponentSchema | null): string | undefined;
63
+ /**
64
+ * Get the resolved value for a specific attribute.
65
+ * This is a convenience function that resolves a single attribute.
66
+ */
67
+ export declare function getResolvedValue(node: MjmlNode, attributeKey: string, mjmlAttributes: MjmlAttributesConfig, schema: ComponentSchema | null): string | undefined;
68
+ /**
69
+ * Helper function to resolve attributes with schema for a node.
70
+ * This is the main function visual blocks should use.
71
+ */
72
+ export declare function resolveNodeAttributes(node: MjmlNode, mjmlAttributes: MjmlAttributesConfig): Record<string, string>;
73
+ /**
74
+ * Check if a node has any mj-class applied
75
+ */
76
+ export declare function hasClasses(node: MjmlNode): boolean;
77
+ /**
78
+ * Add a class to a node's mj-class attribute
79
+ */
80
+ export declare function addClassToNode(node: MjmlNode, className: string): Record<string, string>;
81
+ /**
82
+ * Remove a class from a node's mj-class attribute
83
+ */
84
+ export declare function removeClassFromNode(node: MjmlNode, className: string): Record<string, string>;
85
+ /**
86
+ * Font configuration extracted from mj-font nodes in mj-head
87
+ */
88
+ export interface MjmlFontConfig {
89
+ name: string;
90
+ href: string;
91
+ }
92
+ /**
93
+ * Extract all mj-font configurations from mj-head
94
+ */
95
+ export declare function extractFonts(document: MjmlNode): MjmlFontConfig[];
96
+ /**
97
+ * Extract CSS content from all mj-style nodes in mj-head
98
+ */
99
+ export declare function extractStyles(document: MjmlNode): string[];
100
+ //# sourceMappingURL=attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/mjml/attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG9D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,oBAAoB,CAMxD;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAE3D;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAE3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAGnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,QAAQ,GACjB,oBAAoB,CA4BtB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAM1E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAG9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,QAAQ,EACd,cAAc,EAAE,oBAAoB,GACnC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBxB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,oBAAoB,EACpC,MAAM,EAAE,eAAe,GAAG,IAAI,GAC7B,MAAM,GAAG,SAAS,CA8BpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,oBAAoB,EACpC,MAAM,EAAE,eAAe,GAAG,IAAI,GAC7B,MAAM,GAAG,SAAS,CAQpB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,EACd,cAAc,EAAE,oBAAoB,GACnC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAElD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,cAAc,EAAE,CAWjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAQ1D"}
@@ -0,0 +1,105 @@
1
+ import { getSchemaForTag as u } from "./schema.js";
2
+ function m() {
3
+ return {
4
+ all: {},
5
+ elements: {},
6
+ classes: {}
7
+ };
8
+ }
9
+ function i(s) {
10
+ return s.children?.find((t) => t.tagName === "mj-head") || null;
11
+ }
12
+ function d(s) {
13
+ return i(s)?.children?.find((e) => e.tagName === "mj-attributes") || null;
14
+ }
15
+ function g(s) {
16
+ const t = m(), e = d(s);
17
+ if (!e?.children)
18
+ return t;
19
+ for (const n of e.children)
20
+ if (n.tagName === "mj-all")
21
+ Object.assign(t.all, n.attributes);
22
+ else if (n.tagName === "mj-class") {
23
+ const a = n.attributes.name;
24
+ if (a) {
25
+ const r = { ...n.attributes };
26
+ delete r.name, t.classes[a] = r;
27
+ }
28
+ } else n.tagName.startsWith("mj-") && (t.elements[n.tagName] = { ...n.attributes });
29
+ return t;
30
+ }
31
+ function l(s) {
32
+ return s ? s.split(/\s+/).map((t) => t.trim()).filter((t) => t.length > 0) : [];
33
+ }
34
+ function N(s) {
35
+ const t = g(s);
36
+ return Object.keys(t.classes);
37
+ }
38
+ function h(s, t) {
39
+ const e = {};
40
+ Object.assign(e, t.all);
41
+ const n = t.elements[s.tagName];
42
+ n && Object.assign(e, n);
43
+ const a = l(s.attributes["mj-class"]);
44
+ for (const r of a) {
45
+ const c = t.classes[r];
46
+ c && Object.assign(e, c);
47
+ }
48
+ return Object.assign(e, s.attributes), e;
49
+ }
50
+ function b(s, t, e, n) {
51
+ let a;
52
+ e.all[t] && (a = e.all[t]);
53
+ const r = e.elements[s.tagName];
54
+ r?.[t] && (a = r[t]);
55
+ const c = l(s.attributes["mj-class"]);
56
+ for (const f of c) {
57
+ const o = e.classes[f];
58
+ o?.[t] && (a = o[t]);
59
+ }
60
+ return a === void 0 && n && (a = n[t]?.default), a;
61
+ }
62
+ function p(s, t) {
63
+ const e = u(s.tagName), n = h(s, t);
64
+ if (e)
65
+ for (const [a, r] of Object.entries(e))
66
+ n[a] === void 0 && r.default !== void 0 && (n[a] = r.default);
67
+ return n;
68
+ }
69
+ function v(s, t) {
70
+ const e = l(s.attributes["mj-class"]);
71
+ return e.includes(t) || e.push(t), {
72
+ ...s.attributes,
73
+ "mj-class": e.join(" ")
74
+ };
75
+ }
76
+ function C(s, t) {
77
+ const n = l(s.attributes["mj-class"]).filter((r) => r !== t), a = { ...s.attributes };
78
+ return n.length === 0 ? delete a["mj-class"] : a["mj-class"] = n.join(" "), a;
79
+ }
80
+ function O(s) {
81
+ const t = i(s);
82
+ return t?.children ? t.children.filter((e) => e.tagName === "mj-font").map((e) => ({
83
+ name: e.attributes.name || "",
84
+ href: e.attributes.href || ""
85
+ })).filter((e) => e.name && e.href) : [];
86
+ }
87
+ function x(s) {
88
+ const t = i(s);
89
+ return t?.children ? t.children.filter((e) => e.tagName === "mj-style").map((e) => e.content || "").filter((e) => e.trim().length > 0) : [];
90
+ }
91
+ export {
92
+ v as addClassToNode,
93
+ m as createEmptyConfig,
94
+ O as extractFonts,
95
+ g as extractMjmlAttributes,
96
+ x as extractStyles,
97
+ N as getDefinedClasses,
98
+ i as getHead,
99
+ b as getInheritedValue,
100
+ d as getMjAttributes,
101
+ l as parseClassNames,
102
+ C as removeClassFromNode,
103
+ h as resolveAttributes,
104
+ p as resolveNodeAttributes
105
+ };
@@ -0,0 +1,67 @@
1
+ import { MjmlNode } from '../../types/mjml';
2
+ /**
3
+ * Parse MJML markup string into a JSON AST with internal IDs
4
+ * Browser-compatible implementation using DOMParser
5
+ */
6
+ export declare function parseMjml(mjmlString: string): MjmlNode;
7
+ /**
8
+ * Serialize JSON AST back to MJML markup string
9
+ */
10
+ export declare function serializeMjml(node: MjmlNode): string;
11
+ /**
12
+ * Add unique IDs to all nodes in the tree (for React keys and selection)
13
+ */
14
+ export declare function addIds(node: MjmlNode): MjmlNode;
15
+ /**
16
+ * Strip internal IDs from nodes before serialization
17
+ */
18
+ export declare function stripIds(node: MjmlNode): MjmlNode;
19
+ /**
20
+ * Find a node by ID in the tree
21
+ */
22
+ export declare function findNodeById(root: MjmlNode, id: string): MjmlNode | null;
23
+ /**
24
+ * Find parent node of a given node ID
25
+ */
26
+ export declare function findParentNode(root: MjmlNode, id: string): MjmlNode | null;
27
+ /**
28
+ * Get the mj-body node from the document
29
+ */
30
+ export declare function getBody(root: MjmlNode): MjmlNode | null;
31
+ /**
32
+ * Get all sections from the body
33
+ */
34
+ export declare function getSections(root: MjmlNode): MjmlNode[];
35
+ /**
36
+ * Create a deep clone of a node
37
+ */
38
+ export declare function cloneNode(node: MjmlNode): MjmlNode;
39
+ /**
40
+ * Update a node in the tree immutably
41
+ */
42
+ export declare function updateNode(root: MjmlNode, id: string, updater: (node: MjmlNode) => MjmlNode): MjmlNode;
43
+ /**
44
+ * Delete a node from the tree
45
+ */
46
+ export declare function deleteNode(root: MjmlNode, id: string): MjmlNode;
47
+ /**
48
+ * Insert a node at a specific position
49
+ */
50
+ export declare function insertNode(root: MjmlNode, parentId: string, index: number, newNode: MjmlNode): MjmlNode;
51
+ /**
52
+ * Move a node to a new parent at a specific index
53
+ */
54
+ export declare function moveNode(root: MjmlNode, nodeId: string, newParentId: string, newIndex: number): MjmlNode;
55
+ /**
56
+ * Create a default empty document
57
+ */
58
+ export declare function createEmptyDocument(): MjmlNode;
59
+ /**
60
+ * Create a new section with a single column
61
+ */
62
+ export declare function createSection(): MjmlNode;
63
+ /**
64
+ * Create a new column
65
+ */
66
+ export declare function createColumn(): MjmlNode;
67
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/lib/mjml/parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AA4D7C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAetD;AA+CD;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEpD;AA8CD;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAM/C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAOjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CASxE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAS1E;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAGvD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAItD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAElD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,QAAQ,EACd,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,QAAQ,GACpC,QAAQ,CAWV;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAS/D;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,GAChB,QAAQ,CAeV;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,QAAQ,CAeV;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,QAAQ,CA8B9C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,QAAQ,CAYxC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,QAAQ,CAMvC"}
@@ -0,0 +1,184 @@
1
+ import { v4 as $ } from "uuid";
2
+ function j(e) {
3
+ const t = e.match(
4
+ /XML Parsing Error:\s*(.+?)\nLocation:.*?\nLine Number\s*(\d+),\s*Column\s*(\d+)/i
5
+ );
6
+ if (t) {
7
+ const [, r, c, s] = t;
8
+ return `${u(r.trim())} (line ${c}, column ${s})`;
9
+ }
10
+ const n = e.match(
11
+ /error on line (\d+) at column (\d+): (.+?)(?:\n|Below|$)/i
12
+ );
13
+ if (n) {
14
+ const [, r, c, s] = n;
15
+ return `${u(s.trim())} (line ${r}, column ${c})`;
16
+ }
17
+ return e.replace(/\s+/g, " ").trim().slice(0, 200);
18
+ }
19
+ function u(e) {
20
+ return e.charAt(0).toUpperCase() + e.slice(1);
21
+ }
22
+ function N(e) {
23
+ const t = (r) => r.replace(
24
+ /&(?!(amp|lt|gt|quot|apos|#[0-9]+|#x[0-9a-fA-F]+);)/gi,
25
+ "&amp;"
26
+ );
27
+ let n = e.replace(/="([^"]*)"/g, (r, c) => `="${t(c)}"`);
28
+ return n = n.replace(/='([^']*)'/g, (r, c) => `='${t(c)}'`), n;
29
+ }
30
+ function _(e) {
31
+ const t = N(e), r = new DOMParser().parseFromString(t, "text/xml"), c = r.querySelector("parsererror");
32
+ if (c) {
33
+ const a = c.textContent || "Unknown parse error";
34
+ throw new Error(j(a));
35
+ }
36
+ const s = r.documentElement, i = m(s);
37
+ return l(i);
38
+ }
39
+ function m(e) {
40
+ const t = e.tagName.toLowerCase(), n = {};
41
+ for (const i of Array.from(e.attributes))
42
+ n[i.name] = i.value;
43
+ if ([
44
+ "mj-text",
45
+ "mj-button",
46
+ "mj-title",
47
+ "mj-preview",
48
+ "mj-style",
49
+ "mj-raw"
50
+ ].includes(t))
51
+ return {
52
+ tagName: t,
53
+ attributes: n,
54
+ content: e.innerHTML.trim()
55
+ };
56
+ const s = [];
57
+ for (const i of Array.from(e.children))
58
+ s.push(m(i));
59
+ return {
60
+ tagName: t,
61
+ attributes: n,
62
+ children: s.length > 0 ? s : void 0
63
+ };
64
+ }
65
+ function A(e) {
66
+ return d(f(e));
67
+ }
68
+ function d(e, t = 0) {
69
+ const n = " ".repeat(t), r = e.tagName, c = Object.entries(e.attributes || {}).filter(([, a]) => a !== "" && a !== void 0).map(([a, o]) => `${a}="${b(o)}"`).join(" "), s = c ? `<${r} ${c}>` : `<${r}>`, i = `</${r}>`;
70
+ if (e.content !== void 0)
71
+ return `${n}${s}${e.content}${i}`;
72
+ if (e.children && e.children.length > 0) {
73
+ const a = e.children.map((o) => d(o, t + 1)).join(`
74
+ `);
75
+ return `${n}${s}
76
+ ${a}
77
+ ${n}${i}`;
78
+ }
79
+ return `${n}${s}${i}`;
80
+ }
81
+ function b(e) {
82
+ return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
83
+ }
84
+ function l(e) {
85
+ return {
86
+ ...e,
87
+ _id: e._id || $(),
88
+ children: e.children?.map(l)
89
+ };
90
+ }
91
+ function f(e) {
92
+ const { _id: t, ...n } = e;
93
+ return {
94
+ ...n,
95
+ children: e.children?.map(f)
96
+ };
97
+ }
98
+ function p(e, t) {
99
+ if (e._id === t) return e;
100
+ if (!e.children) return null;
101
+ for (const n of e.children) {
102
+ const r = p(n, t);
103
+ if (r) return r;
104
+ }
105
+ return null;
106
+ }
107
+ function M(e) {
108
+ return JSON.parse(JSON.stringify(e));
109
+ }
110
+ function y(e, t, n) {
111
+ return e._id === t ? n(e) : e.children ? {
112
+ ...e,
113
+ children: e.children.map((r) => y(r, t, n))
114
+ } : e;
115
+ }
116
+ function h(e, t) {
117
+ return e.children ? {
118
+ ...e,
119
+ children: e.children.filter((n) => n._id !== t).map((n) => h(n, t))
120
+ } : e;
121
+ }
122
+ function g(e, t, n, r) {
123
+ if (e._id === t) {
124
+ const c = [...e.children || []];
125
+ return c.splice(n, 0, l(r)), { ...e, children: c };
126
+ }
127
+ return e.children ? {
128
+ ...e,
129
+ children: e.children.map(
130
+ (c) => g(c, t, n, r)
131
+ )
132
+ } : e;
133
+ }
134
+ function E(e, t, n, r) {
135
+ const c = p(e, t);
136
+ if (!c) return e;
137
+ const s = M(c);
138
+ let i = h(e, t);
139
+ return i = g(i, n, r, s), i;
140
+ }
141
+ function v() {
142
+ return l({
143
+ tagName: "mjml",
144
+ attributes: {},
145
+ children: [
146
+ {
147
+ tagName: "mj-body",
148
+ attributes: {},
149
+ children: [
150
+ {
151
+ tagName: "mj-section",
152
+ attributes: {},
153
+ children: [
154
+ {
155
+ tagName: "mj-column",
156
+ attributes: {},
157
+ children: [
158
+ {
159
+ tagName: "mj-text",
160
+ attributes: {},
161
+ content: "Start editing your email here..."
162
+ }
163
+ ]
164
+ }
165
+ ]
166
+ }
167
+ ]
168
+ }
169
+ ]
170
+ });
171
+ }
172
+ export {
173
+ l as addIds,
174
+ M as cloneNode,
175
+ v as createEmptyDocument,
176
+ h as deleteNode,
177
+ p as findNodeById,
178
+ g as insertNode,
179
+ E as moveNode,
180
+ _ as parseMjml,
181
+ A as serializeMjml,
182
+ f as stripIds,
183
+ y as updateNode
184
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.test.d.ts","sourceRoot":"","sources":["../../../src/lib/mjml/parser.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import { MjmlNode } from '../../types/mjml';
2
+ export interface RenderResult {
3
+ html: string;
4
+ errors: {
5
+ line: number;
6
+ message: string;
7
+ tagName: string;
8
+ }[];
9
+ }
10
+ /**
11
+ * Render MJML JSON to HTML
12
+ */
13
+ export declare function renderMjml(document: MjmlNode): RenderResult;
14
+ /**
15
+ * Render MJML string to HTML
16
+ */
17
+ export declare function renderMjmlString(mjmlString: string): RenderResult;
18
+ /**
19
+ * Render MJML JSON to HTML with block IDs preserved as CSS classes
20
+ * This allows clicking elements in the preview to identify the source block
21
+ */
22
+ export declare function renderMjmlInteractive(document: MjmlNode): RenderResult;
23
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/lib/mjml/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC9D;AAkFD;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAkB3D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAiBjE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAqBtE"}
@@ -0,0 +1,72 @@
1
+ import m from "mjml-browser";
2
+ import "uuid";
3
+ function c(r) {
4
+ if (!r._id || !r.tagName.startsWith("mj-"))
5
+ return {
6
+ ...r,
7
+ children: r.children?.map(c)
8
+ };
9
+ const t = r.attributes["mj-class"] || "", e = `block-${r._id}`, s = t ? `${t} ${e}` : e;
10
+ return {
11
+ ...r,
12
+ attributes: { ...r.attributes, "mj-class": s },
13
+ children: r.children?.map(c)
14
+ };
15
+ }
16
+ function g(r) {
17
+ return p(r);
18
+ }
19
+ function p(r, t = 0) {
20
+ const e = " ".repeat(t), s = r.tagName, o = Object.entries(r.attributes || {}).filter(
21
+ ([l, n]) => l !== "_id" && n !== "" && n !== void 0
22
+ ).map(([l, n]) => `${l}="${u(n)}"`).join(" "), i = o ? `<${s} ${o}>` : `<${s}>`, a = `</${s}>`;
23
+ if (r.content !== void 0)
24
+ return `${e}${i}${r.content}${a}`;
25
+ if (r.children && r.children.length > 0) {
26
+ const l = r.children.map((n) => p(n, t + 1)).join(`
27
+ `);
28
+ return `${e}${i}
29
+ ${l}
30
+ ${e}${a}`;
31
+ }
32
+ return `${e}${i}${a}`;
33
+ }
34
+ function u(r) {
35
+ return r.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
36
+ }
37
+ function j(r) {
38
+ try {
39
+ const t = m(r, {
40
+ validationLevel: "soft"
41
+ });
42
+ return {
43
+ html: t.html,
44
+ errors: t.errors || []
45
+ };
46
+ } catch (t) {
47
+ return console.error("MJML render error:", t), {
48
+ html: '<p style="color: red; padding: 20px;">Error rendering email preview</p>',
49
+ errors: [{ line: 0, message: String(t), tagName: "mjml" }]
50
+ };
51
+ }
52
+ }
53
+ function d(r) {
54
+ try {
55
+ const t = c(r), e = g(t), s = m(e, {
56
+ validationLevel: "soft"
57
+ });
58
+ return {
59
+ html: s.html,
60
+ errors: s.errors || []
61
+ };
62
+ } catch (t) {
63
+ return console.error("MJML render error:", t), {
64
+ html: '<p style="color: red; padding: 20px;">Error rendering email preview</p>',
65
+ errors: [{ line: 0, message: String(t), tagName: "mjml" }]
66
+ };
67
+ }
68
+ }
69
+ export {
70
+ d as renderMjmlInteractive,
71
+ j as renderMjmlString
72
+ };
@@ -0,0 +1,21 @@
1
+ import { ComponentSchema, ContentBlockType } from '../../types/mjml';
2
+ export declare const sectionSchema: ComponentSchema;
3
+ export declare const wrapperSchema: ComponentSchema;
4
+ export declare const columnSchema: ComponentSchema;
5
+ export declare const textSchema: ComponentSchema;
6
+ export declare const imageSchema: ComponentSchema;
7
+ export declare const buttonSchema: ComponentSchema;
8
+ export declare const dividerSchema: ComponentSchema;
9
+ export declare const spacerSchema: ComponentSchema;
10
+ export declare const bodySchema: ComponentSchema;
11
+ export declare function getSchemaForTag(tagName: string): ComponentSchema | null;
12
+ export declare const contentBlockTypes: {
13
+ type: ContentBlockType;
14
+ label: string;
15
+ icon: string;
16
+ }[];
17
+ export declare function getDefaultBlock(type: ContentBlockType): {
18
+ attributes: Record<string, string>;
19
+ content?: string;
20
+ };
21
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/mjml/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGtE,eAAO,MAAM,aAAa,EAAE,eA4K3B,CAAC;AAIF,eAAO,MAAM,aAAa,EAAE,eAwK3B,CAAC;AAGF,eAAO,MAAM,YAAY,EAAE,eA0J1B,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,eAmJxB,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,eAwMzB,CAAC;AAGF,eAAO,MAAM,YAAY,EAAE,eAsQ1B,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,eAuF3B,CAAC;AAGF,eAAO,MAAM,YAAY,EAAE,eAgD1B,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,eAsBxB,CAAC;AAGF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAuBvE;AAGD,eAAO,MAAM,iBAAiB,EAAE;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,EAMA,CAAC;AAGF,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG;IACvD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAgCA"}