@savvycal/mjml-editor 0.0.1 → 0.0.3

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 +191 -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 +130 -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 +22 -0
  26. package/dist/components/editor/MjmlEditor.d.ts.map +1 -0
  27. package/dist/components/editor/MjmlEditor.js +137 -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 +69 -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/components.css +365 -0
  120. package/dist/context/EditorContext.d.ts +40 -0
  121. package/dist/context/EditorContext.d.ts.map +1 -0
  122. package/dist/context/EditorContext.js +576 -0
  123. package/dist/context/LiquidSchemaContext.d.ts +10 -0
  124. package/dist/context/LiquidSchemaContext.d.ts.map +1 -0
  125. package/dist/context/LiquidSchemaContext.js +16 -0
  126. package/dist/context/ThemeContext.d.ts +29 -0
  127. package/dist/context/ThemeContext.d.ts.map +1 -0
  128. package/dist/context/ThemeContext.js +55 -0
  129. package/dist/extensions/LiquidHighlight.d.ts +3 -0
  130. package/dist/extensions/LiquidHighlight.d.ts.map +1 -0
  131. package/dist/extensions/LiquidHighlight.js +58 -0
  132. package/dist/extensions/LiquidSuggestion.d.ts +18 -0
  133. package/dist/extensions/LiquidSuggestion.d.ts.map +1 -0
  134. package/dist/extensions/LiquidSuggestion.js +119 -0
  135. package/dist/hooks/useFontLoader.d.ts +6 -0
  136. package/dist/hooks/useFontLoader.d.ts.map +1 -0
  137. package/dist/hooks/useFontLoader.js +21 -0
  138. package/dist/hooks/useStyleLoader.d.ts +11 -0
  139. package/dist/hooks/useStyleLoader.d.ts.map +1 -0
  140. package/dist/hooks/useStyleLoader.js +26 -0
  141. package/dist/index.d.ts +6 -150
  142. package/dist/index.d.ts.map +1 -0
  143. package/dist/index.js +7 -57452
  144. package/dist/lib/html-utils.d.ts +23 -0
  145. package/dist/lib/html-utils.d.ts.map +1 -0
  146. package/dist/lib/html-utils.js +25 -0
  147. package/dist/lib/mjml/attributes.d.ts +100 -0
  148. package/dist/lib/mjml/attributes.d.ts.map +1 -0
  149. package/dist/lib/mjml/attributes.js +105 -0
  150. package/dist/lib/mjml/parser.d.ts +67 -0
  151. package/dist/lib/mjml/parser.d.ts.map +1 -0
  152. package/dist/lib/mjml/parser.js +184 -0
  153. package/dist/lib/mjml/parser.test.d.ts +2 -0
  154. package/dist/lib/mjml/parser.test.d.ts.map +1 -0
  155. package/dist/lib/mjml/renderer.d.ts +23 -0
  156. package/dist/lib/mjml/renderer.d.ts.map +1 -0
  157. package/dist/lib/mjml/renderer.js +75 -0
  158. package/dist/lib/mjml/schema.d.ts +21 -0
  159. package/dist/lib/mjml/schema.d.ts.map +1 -0
  160. package/dist/lib/mjml/schema.js +1307 -0
  161. package/dist/lib/mjml/scopeCSS.d.ts +21 -0
  162. package/dist/lib/mjml/scopeCSS.d.ts.map +1 -0
  163. package/dist/lib/mjml/scopeCSS.js +67 -0
  164. package/dist/lib/utils.d.ts +3 -0
  165. package/dist/lib/utils.d.ts.map +1 -0
  166. package/dist/lib/utils.js +8 -0
  167. package/dist/preset.css +150 -0
  168. package/dist/types/liquid.d.ts +28 -0
  169. package/dist/types/liquid.d.ts.map +1 -0
  170. package/dist/types/mjml.d.ts +101 -0
  171. package/dist/types/mjml.d.ts.map +1 -0
  172. package/package.json +14 -10
  173. package/dist/styles.css +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InteractivePreview.d.ts","sourceRoot":"","sources":["../../../src/components/editor/InteractivePreview.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAID,wBAAgB,kBAAkB,CAAC,EACjC,UAAiB,EACjB,WAAuB,GACxB,EAAE,uBAAuB,2CAkLzB"}
@@ -0,0 +1,130 @@
1
+ import { jsxs as r, jsx as s } from "react/jsx-runtime";
2
+ import { useRef as w, useState as b, useEffect as c, useCallback as E } from "react";
3
+ import { useEditor as y } from "../../context/EditorContext.js";
4
+ import { renderMjmlInteractive as C } from "../../lib/mjml/renderer.js";
5
+ const I = 375;
6
+ function S({
7
+ showHeader: p = !0,
8
+ previewMode: g = "desktop"
9
+ }) {
10
+ const { state: n, selectBlock: d } = y(), o = w(null), [m, x] = b(n.document), [v, k] = b({
11
+ html: "",
12
+ errors: []
13
+ });
14
+ c(() => {
15
+ const e = setTimeout(() => {
16
+ x(n.document);
17
+ }, 300);
18
+ return () => clearTimeout(e);
19
+ }, [n.document]), c(() => {
20
+ let e = !1;
21
+ return C(m).then((t) => {
22
+ e || k(t);
23
+ }), () => {
24
+ e = !0;
25
+ };
26
+ }, [m]);
27
+ const { html: u, errors: l } = v, i = E(
28
+ (e) => {
29
+ e.data?.type === "BLOCK_SELECTED" && d(e.data.blockId);
30
+ },
31
+ [d]
32
+ );
33
+ c(() => (window.addEventListener("message", i), () => window.removeEventListener("message", i)), [i]);
34
+ const a = n.selectedBlockId ? `.block-${n.selectedBlockId} { outline: 2px solid #6366f1 !important; outline-offset: -2px; position: relative; }` : "", f = `
35
+ (function() {
36
+ document.addEventListener('click', function(e) {
37
+ e.preventDefault();
38
+ e.stopPropagation();
39
+
40
+ // Find the closest element with a block- class
41
+ var target = e.target;
42
+ while (target && target !== document.body) {
43
+ var blockClass = Array.from(target.classList || []).find(function(c) {
44
+ return c.startsWith('block-');
45
+ });
46
+ if (blockClass) {
47
+ var blockId = blockClass.replace('block-', '');
48
+ window.parent.postMessage({ type: 'BLOCK_SELECTED', blockId: blockId }, '*');
49
+ return;
50
+ }
51
+ target = target.parentElement;
52
+ }
53
+ }, true);
54
+
55
+ // Prevent default link behavior
56
+ document.addEventListener('click', function(e) {
57
+ if (e.target.closest('a')) {
58
+ e.preventDefault();
59
+ }
60
+ }, true);
61
+ })();
62
+ `;
63
+ return c(() => {
64
+ if (o.current) {
65
+ const e = o.current.contentDocument;
66
+ if (e) {
67
+ e.open(), e.write(u), e.close();
68
+ const t = e.createElement("script");
69
+ t.textContent = f, e.body.appendChild(t);
70
+ const h = e.createElement("style");
71
+ h.textContent = `
72
+ [class*="block-"] {
73
+ cursor: pointer;
74
+ transition: outline 0.15s ease;
75
+ }
76
+ [class*="block-"]:hover {
77
+ outline: 1px dashed #94a3b8 !important;
78
+ outline-offset: -1px;
79
+ }
80
+ ${a}
81
+ `, e.head.appendChild(h);
82
+ }
83
+ }
84
+ }, [u, a, f]), c(() => {
85
+ if (o.current) {
86
+ const e = o.current.contentDocument;
87
+ if (e) {
88
+ let t = e.getElementById("selection-highlight");
89
+ t || (t = e.createElement("style"), t.id = "selection-highlight", e.head.appendChild(t)), t.textContent = a;
90
+ }
91
+ }
92
+ }, [n.selectedBlockId, a]), /* @__PURE__ */ r("div", { className: "flex flex-col h-full", children: [
93
+ p && /* @__PURE__ */ r("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-background", children: [
94
+ /* @__PURE__ */ s("span", { className: "text-sm font-semibold text-foreground", children: "Preview" }),
95
+ l.length > 0 && /* @__PURE__ */ r("span", { className: "text-xs font-medium text-amber-600 bg-amber-50 px-2 py-0.5 rounded-md", children: [
96
+ l.length,
97
+ " warning",
98
+ l.length !== 1 ? "s" : ""
99
+ ] })
100
+ ] }),
101
+ /* @__PURE__ */ s("div", { className: "flex-1 overflow-auto bg-muted flex justify-center", children: /* @__PURE__ */ s(
102
+ "iframe",
103
+ {
104
+ ref: o,
105
+ title: "Email Preview",
106
+ className: "h-full border-0 bg-white transition-all duration-200",
107
+ style: {
108
+ width: g === "mobile" ? I : "100%",
109
+ maxWidth: "100%"
110
+ },
111
+ sandbox: "allow-same-origin allow-scripts"
112
+ }
113
+ ) }),
114
+ l.length > 0 && /* @__PURE__ */ r("div", { className: "max-h-28 overflow-auto border-t border-border bg-amber-50/50 p-3", children: [
115
+ /* @__PURE__ */ s("div", { className: "text-xs font-semibold text-amber-700 mb-2", children: "Warnings" }),
116
+ /* @__PURE__ */ s("div", { className: "space-y-1", children: l.map((e, t) => /* @__PURE__ */ r("div", { className: "text-xs text-amber-600", children: [
117
+ /* @__PURE__ */ r("span", { className: "font-mono", children: [
118
+ "Line ",
119
+ e.line,
120
+ ":"
121
+ ] }),
122
+ " ",
123
+ e.message
124
+ ] }, t)) })
125
+ ] })
126
+ ] });
127
+ }
128
+ export {
129
+ S as InteractivePreview
130
+ };
@@ -0,0 +1,10 @@
1
+ import { LiquidSuggestion } from '../../types/liquid';
2
+ interface LiquidAutocompleteProps {
3
+ items: LiquidSuggestion[];
4
+ selectedIndex: number;
5
+ onSelect: (item: LiquidSuggestion) => void;
6
+ clientRect: (() => DOMRect | null) | null;
7
+ }
8
+ export declare function LiquidAutocomplete({ items, selectedIndex, onSelect, clientRect, }: LiquidAutocompleteProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=LiquidAutocomplete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiquidAutocomplete.d.ts","sourceRoot":"","sources":["../../../src/components/editor/LiquidAutocomplete.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,UAAU,uBAAuB;IAC/B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,aAAa,EACb,QAAQ,EACR,UAAU,GACX,EAAE,uBAAuB,2CAqFzB"}
@@ -0,0 +1,70 @@
1
+ import { jsx as o, jsxs as p } from "react/jsx-runtime";
2
+ import { useRef as l, useCallback as g, useLayoutEffect as b, useEffect as h } from "react";
3
+ import { useFloating as x, autoUpdate as v, offset as w, flip as y, shift as N } from "@floating-ui/react";
4
+ import { cn as E } from "../../lib/utils.js";
5
+ function j({
6
+ items: s,
7
+ selectedIndex: r,
8
+ onSelect: d,
9
+ clientRect: n
10
+ }) {
11
+ const a = l(null), m = l(null), f = l(null), { refs: t, floatingStyles: c } = x({
12
+ placement: "bottom-start",
13
+ middleware: [w(4), y(), N({ padding: 8 })],
14
+ whileElementsMounted: v
15
+ }), u = g(
16
+ (e) => {
17
+ m.current = e, t.setFloating(e);
18
+ },
19
+ [t]
20
+ );
21
+ return b(() => {
22
+ if (n) {
23
+ const e = n();
24
+ e && (f.current = {
25
+ getBoundingClientRect: () => e
26
+ }, t.setReference(f.current));
27
+ }
28
+ }, [n, t]), h(() => {
29
+ a.current?.scrollIntoView({
30
+ block: "nearest"
31
+ });
32
+ }, [r]), s.length === 0 ? /* @__PURE__ */ o(
33
+ "div",
34
+ {
35
+ ref: u,
36
+ style: c,
37
+ className: "light z-50 rounded-lg border border-border bg-popover p-2 shadow-lg text-sm text-muted-foreground",
38
+ children: "No matches found"
39
+ }
40
+ ) : /* @__PURE__ */ o(
41
+ "div",
42
+ {
43
+ ref: u,
44
+ style: c,
45
+ className: "light z-50 flex flex-col rounded-lg border border-border bg-popover shadow-lg max-h-64 overflow-y-auto",
46
+ onMouseDown: (e) => e.preventDefault(),
47
+ children: s.map((e, i) => /* @__PURE__ */ p(
48
+ "button",
49
+ {
50
+ ref: i === r ? a : null,
51
+ type: "button",
52
+ onClick: () => d(e),
53
+ className: E(
54
+ "flex flex-col items-start px-3 py-2 text-left text-sm transition-colors",
55
+ "hover:bg-accent",
56
+ i === r && "bg-accent"
57
+ ),
58
+ children: [
59
+ /* @__PURE__ */ o("span", { className: "font-medium text-foreground", children: e.name }),
60
+ e.description && /* @__PURE__ */ o("span", { className: "text-xs text-muted-foreground", children: e.description })
61
+ ]
62
+ },
63
+ e.id
64
+ ))
65
+ }
66
+ );
67
+ }
68
+ export {
69
+ j as LiquidAutocomplete
70
+ };
@@ -0,0 +1,12 @@
1
+ interface LiquidInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
2
+ value: string;
3
+ onChange: (value: string) => void;
4
+ }
5
+ export interface LiquidInputRef {
6
+ focus: () => void;
7
+ select: () => void;
8
+ blur: () => void;
9
+ }
10
+ export declare const LiquidInput: import('react').ForwardRefExoticComponent<LiquidInputProps & import('react').RefAttributes<LiquidInputRef>>;
11
+ export {};
12
+ //# sourceMappingURL=LiquidInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiquidInput.d.ts","sourceRoot":"","sources":["../../../src/components/editor/LiquidInput.tsx"],"names":[],"mappings":"AAoBA,UAAU,gBAAiB,SAAQ,IAAI,CACrC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAC3C,UAAU,CACX;IACC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,eAAO,MAAM,WAAW,6GAsQvB,CAAC"}
@@ -0,0 +1,185 @@
1
+ import { jsxs as I, Fragment as $, jsx as p } from "react/jsx-runtime";
2
+ import { forwardRef as F, useRef as L, useState as T, useCallback as c, useImperativeHandle as B, useEffect as E } from "react";
3
+ import { useFloating as K, autoUpdate as N, offset as j, flip as z, shift as A } from "@floating-ui/react";
4
+ import { cn as O } from "../../lib/utils.js";
5
+ import { useLiquidSchema as P } from "../../context/LiquidSchemaContext.js";
6
+ const W = F(
7
+ function({ value: d, onChange: g, className: S, style: v, ...i }, D) {
8
+ const o = L(null), h = P(), [n, s] = T(null), { refs: x, floatingStyles: k } = K({
9
+ placement: "bottom-start",
10
+ middleware: [j(4), z(), A({ padding: 8 })],
11
+ whileElementsMounted: N
12
+ }), q = c(
13
+ (e) => {
14
+ x.setFloating(e);
15
+ },
16
+ [x]
17
+ );
18
+ B(D, () => ({
19
+ focus: () => o.current?.focus(),
20
+ select: () => o.current?.select(),
21
+ blur: () => o.current?.blur()
22
+ }));
23
+ const y = c(
24
+ (e, t) => {
25
+ if (!h) return [];
26
+ const l = e === "variable" ? h.variables : h.tags, u = t.trim().toLowerCase();
27
+ return l.filter((r) => r.name.toLowerCase().includes(u)).map((r) => ({
28
+ id: `${e}-${r.name}`,
29
+ name: r.name,
30
+ description: r.description,
31
+ type: e
32
+ }));
33
+ },
34
+ [h]
35
+ ), w = c(
36
+ (e, t) => {
37
+ const l = e.slice(0, t), u = l.match(/\{\{([^{}]*)$/);
38
+ if (u) {
39
+ const f = l.lastIndexOf("{{"), a = u[1], m = y("variable", a);
40
+ if (m.length > 0 || a.trim() === "") {
41
+ s({
42
+ active: !0,
43
+ items: m,
44
+ selectedIndex: 0,
45
+ triggerType: "variable",
46
+ triggerStart: f
47
+ });
48
+ return;
49
+ }
50
+ }
51
+ const r = l.match(/\{%([^{}]*)$/);
52
+ if (r) {
53
+ const f = l.lastIndexOf("{%"), a = r[1], m = y("tag", a);
54
+ if (m.length > 0 || a.trim() === "") {
55
+ s({
56
+ active: !0,
57
+ items: m,
58
+ selectedIndex: 0,
59
+ triggerType: "tag",
60
+ triggerStart: f
61
+ });
62
+ return;
63
+ }
64
+ }
65
+ s(null);
66
+ },
67
+ [y]
68
+ ), C = c(
69
+ (e) => {
70
+ const t = e.target.value;
71
+ g(t), w(t, e.target.selectionStart || 0);
72
+ },
73
+ [g, w]
74
+ ), b = c(
75
+ (e) => {
76
+ if (!n || !o.current) return;
77
+ const { triggerStart: t, triggerType: l } = n, u = o.current.selectionStart || d.length, r = l === "variable" ? `{{ ${e.name} }}` : `{% ${e.name} %}`, f = d.slice(0, t) + r + d.slice(u);
78
+ g(f), s(null);
79
+ const a = t + r.length;
80
+ setTimeout(() => {
81
+ o.current?.setSelectionRange(a, a);
82
+ }, 0);
83
+ },
84
+ [n, d, g]
85
+ ), M = c(
86
+ (e) => {
87
+ if (!n?.active) {
88
+ i.onKeyDown?.(e);
89
+ return;
90
+ }
91
+ if (e.key === "ArrowDown") {
92
+ e.preventDefault(), s(
93
+ (t) => t ? {
94
+ ...t,
95
+ selectedIndex: Math.min(
96
+ t.selectedIndex + 1,
97
+ t.items.length - 1
98
+ )
99
+ } : null
100
+ );
101
+ return;
102
+ }
103
+ if (e.key === "ArrowUp") {
104
+ e.preventDefault(), s(
105
+ (t) => t ? {
106
+ ...t,
107
+ selectedIndex: Math.max(t.selectedIndex - 1, 0)
108
+ } : null
109
+ );
110
+ return;
111
+ }
112
+ if (e.key === "Enter" || e.key === "Tab") {
113
+ if (n.items.length > 0) {
114
+ e.preventDefault();
115
+ const t = n.items[n.selectedIndex];
116
+ t && b(t);
117
+ }
118
+ return;
119
+ }
120
+ if (e.key === "Escape") {
121
+ e.preventDefault(), s(null);
122
+ return;
123
+ }
124
+ i.onKeyDown?.(e);
125
+ },
126
+ [n, b, i]
127
+ ), R = c(
128
+ (e) => {
129
+ setTimeout(() => {
130
+ s(null);
131
+ }, 150), i.onBlur?.(e);
132
+ },
133
+ [i]
134
+ );
135
+ return E(() => {
136
+ x.setReference(o.current);
137
+ }, [x]), /* @__PURE__ */ I($, { children: [
138
+ /* @__PURE__ */ p(
139
+ "input",
140
+ {
141
+ ref: o,
142
+ type: "text",
143
+ value: d,
144
+ onChange: C,
145
+ onKeyDown: M,
146
+ onBlur: R,
147
+ className: S,
148
+ style: v,
149
+ autoComplete: "off",
150
+ "data-1p-ignore": !0,
151
+ ...i
152
+ }
153
+ ),
154
+ n?.active && n.items.length > 0 && /* @__PURE__ */ p(
155
+ "div",
156
+ {
157
+ ref: q,
158
+ style: k,
159
+ className: "light z-50 flex flex-col rounded-lg border border-border bg-popover shadow-lg max-h-64 overflow-y-auto",
160
+ onMouseDown: (e) => e.preventDefault(),
161
+ children: n.items.map((e, t) => /* @__PURE__ */ I(
162
+ "button",
163
+ {
164
+ type: "button",
165
+ onClick: () => b(e),
166
+ className: O(
167
+ "flex flex-col items-start px-3 py-2 text-left text-sm transition-colors",
168
+ "hover:bg-accent",
169
+ t === n.selectedIndex && "bg-accent"
170
+ ),
171
+ children: [
172
+ /* @__PURE__ */ p("span", { className: "font-medium text-foreground", children: e.name }),
173
+ e.description && /* @__PURE__ */ p("span", { className: "text-xs text-muted-foreground", children: e.description })
174
+ ]
175
+ },
176
+ e.id
177
+ ))
178
+ }
179
+ )
180
+ ] });
181
+ }
182
+ );
183
+ export {
184
+ W as LiquidInput
185
+ };
@@ -0,0 +1,22 @@
1
+ import { LiquidSchema } from '../../types/liquid';
2
+ interface MjmlEditorProps {
3
+ value: string;
4
+ onChange: (mjml: string) => void;
5
+ className?: string;
6
+ defaultTheme?: 'light' | 'dark' | 'system';
7
+ liquidSchema?: LiquidSchema;
8
+ /**
9
+ * Whether to apply the theme class to document.documentElement.
10
+ * This is needed for Radix UI portals (popovers, menus, etc.) which
11
+ * render outside the editor container.
12
+ *
13
+ * Set to false if your app manages document-level theme classes
14
+ * and you want to prevent conflicts.
15
+ *
16
+ * @default true
17
+ */
18
+ applyThemeToDocument?: boolean;
19
+ }
20
+ export declare function MjmlEditor({ value, onChange, className, defaultTheme, liquidSchema, applyThemeToDocument, }: MjmlEditorProps): import("react/jsx-runtime").JSX.Element;
21
+ export {};
22
+ //# sourceMappingURL=MjmlEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MjmlEditor.d.ts","sourceRoot":"","sources":["../../../src/components/editor/MjmlEditor.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAcnD,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAuJD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,SAAS,EACT,YAAuB,EACvB,YAAY,EACZ,oBAA2B,GAC5B,EAAE,eAAe,2CAuCjB"}
@@ -0,0 +1,137 @@
1
+ import { jsx as t, jsxs as T, Fragment as I } from "react/jsx-runtime";
2
+ import { useState as d, useEffect as c, useCallback as b, useRef as P } from "react";
3
+ import { EditorProvider as L, useEditor as D } from "../../context/EditorContext.js";
4
+ import { ThemeProvider as M, useTheme as O } from "../../context/ThemeContext.js";
5
+ import { LiquidSchemaProvider as j } from "../../context/LiquidSchemaContext.js";
6
+ import { OutlineTree as x, GLOBAL_STYLES_ID as y } from "./OutlineTree.js";
7
+ import { EditorCanvas as C } from "./EditorCanvas.js";
8
+ import { BlockInspector as S } from "./BlockInspector.js";
9
+ import { GlobalStylesPanel as K } from "./GlobalStylesPanel.js";
10
+ import { FloatingPanel as E } from "../ui/floating-panel.js";
11
+ import { createEmptyDocument as w, parseMjml as R, serializeMjml as A } from "../../lib/mjml/parser.js";
12
+ function F(n) {
13
+ if (!n || n.trim() === "")
14
+ return w();
15
+ try {
16
+ return R(n);
17
+ } catch (e) {
18
+ return console.error("Failed to parse MJML:", e), w();
19
+ }
20
+ }
21
+ function N({
22
+ className: n,
23
+ children: e
24
+ }) {
25
+ const { resolvedTheme: o } = O();
26
+ return /* @__PURE__ */ t(
27
+ "div",
28
+ {
29
+ className: `mjml-editor ${o} relative h-full w-full overflow-hidden bg-background text-foreground antialiased ${n || ""}`,
30
+ children: e
31
+ }
32
+ );
33
+ }
34
+ function $({ onChange: n }) {
35
+ const { state: e, undo: o, redo: s, canUndo: a, canRedo: u, deleteBlock: m, selectBlock: f } = D(), [l, p] = d(!0), [i, h] = d(!0), [k, B] = d("edit"), v = P(n);
36
+ return c(() => {
37
+ v.current = n;
38
+ }, [n]), c(() => {
39
+ e.selectedBlockId && h(!0);
40
+ }, [e.selectedBlockId]), c(() => {
41
+ const g = A(e.document);
42
+ v.current(g);
43
+ }, [e.document]), c(() => {
44
+ const g = (r) => {
45
+ if (!(r.target instanceof HTMLInputElement || r.target instanceof HTMLTextAreaElement || r.target?.isContentEditable)) {
46
+ if ((r.metaKey || r.ctrlKey) && r.key === "z") {
47
+ r.preventDefault(), r.shiftKey ? u && s() : a && o();
48
+ return;
49
+ }
50
+ if ((r.key === "Delete" || r.key === "Backspace") && e.selectedBlockId && e.selectedBlockId !== y) {
51
+ r.preventDefault(), m(e.selectedBlockId);
52
+ return;
53
+ }
54
+ if (r.key === "Escape" && e.selectedBlockId) {
55
+ r.preventDefault(), f(null);
56
+ return;
57
+ }
58
+ }
59
+ };
60
+ return window.addEventListener("keydown", g), () => window.removeEventListener("keydown", g);
61
+ }, [
62
+ o,
63
+ s,
64
+ a,
65
+ u,
66
+ m,
67
+ f,
68
+ e.selectedBlockId
69
+ ]), /* @__PURE__ */ T("div", { className: "relative h-full overflow-hidden", children: [
70
+ /* @__PURE__ */ t("div", { className: "absolute inset-0 bg-canvas", children: /* @__PURE__ */ t(
71
+ C,
72
+ {
73
+ activeTab: k,
74
+ onTabChange: B,
75
+ leftPanelOpen: l,
76
+ rightPanelOpen: i
77
+ }
78
+ ) }),
79
+ k === "edit" && /* @__PURE__ */ T(I, { children: [
80
+ /* @__PURE__ */ t(
81
+ E,
82
+ {
83
+ side: "left",
84
+ isOpen: l,
85
+ onToggle: () => p(!l),
86
+ width: 256,
87
+ children: /* @__PURE__ */ t(x, { onTogglePanel: () => p(!1) })
88
+ }
89
+ ),
90
+ /* @__PURE__ */ t(
91
+ E,
92
+ {
93
+ side: "right",
94
+ isOpen: i,
95
+ onToggle: () => h(!i),
96
+ width: 300,
97
+ children: e.selectedBlockId === y ? /* @__PURE__ */ t(
98
+ K,
99
+ {
100
+ onTogglePanel: () => h(!1)
101
+ }
102
+ ) : /* @__PURE__ */ t(S, { onTogglePanel: () => h(!1) })
103
+ }
104
+ )
105
+ ] })
106
+ ] });
107
+ }
108
+ function X({
109
+ value: n,
110
+ onChange: e,
111
+ className: o,
112
+ defaultTheme: s = "system",
113
+ liquidSchema: a,
114
+ applyThemeToDocument: u = !0
115
+ }) {
116
+ const [m, f] = d(!1);
117
+ c(() => {
118
+ f(!0);
119
+ }, []);
120
+ const [l] = d(() => F(n)), p = b(
121
+ (i) => {
122
+ e(i);
123
+ },
124
+ [e]
125
+ );
126
+ return m ? /* @__PURE__ */ t(
127
+ M,
128
+ {
129
+ defaultTheme: s,
130
+ applyToDocument: u,
131
+ children: /* @__PURE__ */ t(j, { schema: a, children: /* @__PURE__ */ t(N, { className: o, children: /* @__PURE__ */ t(L, { initialDocument: l, children: /* @__PURE__ */ t($, { onChange: p }) }) }) })
132
+ }
133
+ ) : /* @__PURE__ */ t("div", { className: `h-full w-full bg-background ${o || ""}` });
134
+ }
135
+ export {
136
+ X as MjmlEditor
137
+ };
@@ -0,0 +1,7 @@
1
+ export declare const GLOBAL_STYLES_ID = "__global_styles__";
2
+ interface OutlineTreeProps {
3
+ onTogglePanel?: () => void;
4
+ }
5
+ export declare function OutlineTree({ onTogglePanel }: OutlineTreeProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=OutlineTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OutlineTree.d.ts","sourceRoot":"","sources":["../../../src/components/editor/OutlineTree.tsx"],"names":[],"mappings":"AA8BA,eAAO,MAAM,gBAAgB,sBAAsB,CAAC;AA+NpD,UAAU,gBAAgB;IACxB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,WAAW,CAAC,EAAE,aAAa,EAAE,EAAE,gBAAgB,2CAiI9D"}