@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 @@
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,2CAoKzB"}
@@ -0,0 +1,120 @@
1
+ import { jsxs as o, jsx as l } from "react/jsx-runtime";
2
+ import { useRef as x, useState as v, useEffect as i, useMemo as k, useCallback as w } from "react";
3
+ import { useEditor as E } from "../../context/EditorContext.js";
4
+ import { renderMjmlInteractive as y } from "../../lib/mjml/renderer.js";
5
+ const C = 375;
6
+ function B({
7
+ showHeader: h = !0,
8
+ previewMode: p = "desktop"
9
+ }) {
10
+ const { state: n, selectBlock: d } = E(), r = x(null), [m, g] = v(n.document);
11
+ i(() => {
12
+ const e = setTimeout(() => {
13
+ g(n.document);
14
+ }, 300);
15
+ return () => clearTimeout(e);
16
+ }, [n.document]);
17
+ const { html: u, errors: s } = k(() => y(m), [m]), a = w(
18
+ (e) => {
19
+ e.data?.type === "BLOCK_SELECTED" && d(e.data.blockId);
20
+ },
21
+ [d]
22
+ );
23
+ i(() => (window.addEventListener("message", a), () => window.removeEventListener("message", a)), [a]);
24
+ const c = n.selectedBlockId ? `.block-${n.selectedBlockId} { outline: 2px solid #6366f1 !important; outline-offset: -2px; position: relative; }` : "", f = `
25
+ (function() {
26
+ document.addEventListener('click', function(e) {
27
+ e.preventDefault();
28
+ e.stopPropagation();
29
+
30
+ // Find the closest element with a block- class
31
+ var target = e.target;
32
+ while (target && target !== document.body) {
33
+ var blockClass = Array.from(target.classList || []).find(function(c) {
34
+ return c.startsWith('block-');
35
+ });
36
+ if (blockClass) {
37
+ var blockId = blockClass.replace('block-', '');
38
+ window.parent.postMessage({ type: 'BLOCK_SELECTED', blockId: blockId }, '*');
39
+ return;
40
+ }
41
+ target = target.parentElement;
42
+ }
43
+ }, true);
44
+
45
+ // Prevent default link behavior
46
+ document.addEventListener('click', function(e) {
47
+ if (e.target.closest('a')) {
48
+ e.preventDefault();
49
+ }
50
+ }, true);
51
+ })();
52
+ `;
53
+ return i(() => {
54
+ if (r.current) {
55
+ const e = r.current.contentDocument;
56
+ if (e) {
57
+ e.open(), e.write(u), e.close();
58
+ const t = e.createElement("script");
59
+ t.textContent = f, e.body.appendChild(t);
60
+ const b = e.createElement("style");
61
+ b.textContent = `
62
+ [class*="block-"] {
63
+ cursor: pointer;
64
+ transition: outline 0.15s ease;
65
+ }
66
+ [class*="block-"]:hover {
67
+ outline: 1px dashed #94a3b8 !important;
68
+ outline-offset: -1px;
69
+ }
70
+ ${c}
71
+ `, e.head.appendChild(b);
72
+ }
73
+ }
74
+ }, [u, c, f]), i(() => {
75
+ if (r.current) {
76
+ const e = r.current.contentDocument;
77
+ if (e) {
78
+ let t = e.getElementById("selection-highlight");
79
+ t || (t = e.createElement("style"), t.id = "selection-highlight", e.head.appendChild(t)), t.textContent = c;
80
+ }
81
+ }
82
+ }, [n.selectedBlockId, c]), /* @__PURE__ */ o("div", { className: "flex flex-col h-full", children: [
83
+ h && /* @__PURE__ */ o("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-background", children: [
84
+ /* @__PURE__ */ l("span", { className: "text-sm font-semibold text-foreground", children: "Preview" }),
85
+ s.length > 0 && /* @__PURE__ */ o("span", { className: "text-xs font-medium text-amber-600 bg-amber-50 px-2 py-0.5 rounded-md", children: [
86
+ s.length,
87
+ " warning",
88
+ s.length !== 1 ? "s" : ""
89
+ ] })
90
+ ] }),
91
+ /* @__PURE__ */ l("div", { className: "flex-1 overflow-auto bg-muted flex justify-center", children: /* @__PURE__ */ l(
92
+ "iframe",
93
+ {
94
+ ref: r,
95
+ title: "Email Preview",
96
+ className: "h-full border-0 bg-white transition-all duration-200",
97
+ style: {
98
+ width: p === "mobile" ? C : "100%",
99
+ maxWidth: "100%"
100
+ },
101
+ sandbox: "allow-same-origin allow-scripts"
102
+ }
103
+ ) }),
104
+ s.length > 0 && /* @__PURE__ */ o("div", { className: "max-h-28 overflow-auto border-t border-border bg-amber-50/50 p-3", children: [
105
+ /* @__PURE__ */ l("div", { className: "text-xs font-semibold text-amber-700 mb-2", children: "Warnings" }),
106
+ /* @__PURE__ */ l("div", { className: "space-y-1", children: s.map((e, t) => /* @__PURE__ */ o("div", { className: "text-xs text-amber-600", children: [
107
+ /* @__PURE__ */ o("span", { className: "font-mono", children: [
108
+ "Line ",
109
+ e.line,
110
+ ":"
111
+ ] }),
112
+ " ",
113
+ e.message
114
+ ] }, t)) })
115
+ ] })
116
+ ] });
117
+ }
118
+ export {
119
+ B as InteractivePreview
120
+ };
@@ -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,11 @@
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
+ export declare function MjmlEditor({ value, onChange, className, defaultTheme, liquidSchema, }: MjmlEditorProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# 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;CAC7B;AA4HD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,SAAS,EACT,YAAuB,EACvB,YAAY,GACb,EAAE,eAAe,2CAuBjB"}
@@ -0,0 +1,111 @@
1
+ import { jsx as n, jsxs as v, Fragment as I } from "react/jsx-runtime";
2
+ import { useState as f, useCallback as P, useEffect as h } from "react";
3
+ import { EditorProvider as w, useEditor as L } from "../../context/EditorContext.js";
4
+ import { ThemeProvider as b } from "../../context/ThemeContext.js";
5
+ import { LiquidSchemaProvider as M } from "../../context/LiquidSchemaContext.js";
6
+ import { OutlineTree as D, GLOBAL_STYLES_ID as y } from "./OutlineTree.js";
7
+ import { EditorCanvas as O } from "./EditorCanvas.js";
8
+ import { BlockInspector as j } from "./BlockInspector.js";
9
+ import { GlobalStylesPanel as C } from "./GlobalStylesPanel.js";
10
+ import { FloatingPanel as E } from "../ui/floating-panel.js";
11
+ import { createEmptyDocument as T, parseMjml as S, serializeMjml as x } from "../../lib/mjml/parser.js";
12
+ function K(r) {
13
+ if (!r || r.trim() === "")
14
+ return T();
15
+ try {
16
+ return S(r);
17
+ } catch (e) {
18
+ return console.error("Failed to parse MJML:", e), T();
19
+ }
20
+ }
21
+ function A({ onChange: r }) {
22
+ const { state: e, undo: l, redo: i, canUndo: c, canRedo: a, deleteBlock: d, selectBlock: s } = L(), [u, g] = f(!0), [p, m] = f(!0), [k, B] = f("edit");
23
+ return h(() => {
24
+ e.selectedBlockId && m(!0);
25
+ }, [e.selectedBlockId]), h(() => {
26
+ const o = x(e.document);
27
+ console.log(`MJML markup updated:
28
+ `, o), r(o);
29
+ }, [e.document, r]), h(() => {
30
+ const o = (t) => {
31
+ if (!(t.target instanceof HTMLInputElement || t.target instanceof HTMLTextAreaElement || t.target?.isContentEditable)) {
32
+ if ((t.metaKey || t.ctrlKey) && t.key === "z") {
33
+ t.preventDefault(), t.shiftKey ? a && i() : c && l();
34
+ return;
35
+ }
36
+ if ((t.key === "Delete" || t.key === "Backspace") && e.selectedBlockId && e.selectedBlockId !== y) {
37
+ t.preventDefault(), d(e.selectedBlockId);
38
+ return;
39
+ }
40
+ if (t.key === "Escape" && e.selectedBlockId) {
41
+ t.preventDefault(), s(null);
42
+ return;
43
+ }
44
+ }
45
+ };
46
+ return window.addEventListener("keydown", o), () => window.removeEventListener("keydown", o);
47
+ }, [
48
+ l,
49
+ i,
50
+ c,
51
+ a,
52
+ d,
53
+ s,
54
+ e.selectedBlockId
55
+ ]), /* @__PURE__ */ v("div", { className: "relative h-full overflow-hidden", children: [
56
+ /* @__PURE__ */ n("div", { className: "absolute inset-0 bg-canvas", children: /* @__PURE__ */ n(
57
+ O,
58
+ {
59
+ activeTab: k,
60
+ onTabChange: B,
61
+ leftPanelOpen: u,
62
+ rightPanelOpen: p
63
+ }
64
+ ) }),
65
+ k === "edit" && /* @__PURE__ */ v(I, { children: [
66
+ /* @__PURE__ */ n(
67
+ E,
68
+ {
69
+ side: "left",
70
+ isOpen: u,
71
+ onToggle: () => g(!u),
72
+ width: 256,
73
+ children: /* @__PURE__ */ n(D, { onTogglePanel: () => g(!1) })
74
+ }
75
+ ),
76
+ /* @__PURE__ */ n(
77
+ E,
78
+ {
79
+ side: "right",
80
+ isOpen: p,
81
+ onToggle: () => m(!p),
82
+ width: 300,
83
+ children: e.selectedBlockId === y ? /* @__PURE__ */ n(
84
+ C,
85
+ {
86
+ onTogglePanel: () => m(!1)
87
+ }
88
+ ) : /* @__PURE__ */ n(j, { onTogglePanel: () => m(!1) })
89
+ }
90
+ )
91
+ ] })
92
+ ] });
93
+ }
94
+ function Y({
95
+ value: r,
96
+ onChange: e,
97
+ className: l,
98
+ defaultTheme: i = "system",
99
+ liquidSchema: c
100
+ }) {
101
+ const [a] = f(() => K(r)), d = P(
102
+ (s) => {
103
+ e(s);
104
+ },
105
+ [e]
106
+ );
107
+ return /* @__PURE__ */ n(b, { defaultTheme: i, children: /* @__PURE__ */ n(M, { schema: c, children: /* @__PURE__ */ n("div", { className: `h-full w-full bg-background ${l || ""}`, children: /* @__PURE__ */ n(w, { initialDocument: a, children: /* @__PURE__ */ n(A, { onChange: d }) }) }) }) });
108
+ }
109
+ export {
110
+ Y as MjmlEditor
111
+ };
@@ -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"}