@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,330 @@
1
+ import { jsxs as w, jsx as i, Fragment as J } from "react/jsx-runtime";
2
+ import { forwardRef as Q, useMemo as _, useState as x, useRef as d, useCallback as u, useImperativeHandle as G } from "react";
3
+ import { useEditor as W, EditorContent as X } from "@tiptap/react";
4
+ import Y from "@tiptap/starter-kit";
5
+ import Z from "@tiptap/extension-link";
6
+ import ee from "@tiptap/extension-underline";
7
+ import { useFloating as te, autoUpdate as ne, offset as ie, flip as re, shift as oe } from "@floating-ui/react";
8
+ import { Check as le, Unlink as se, Bold as ce, Italic as ae, Underline as ue, Strikethrough as fe, Link as de } from "lucide-react";
9
+ import { cn as me } from "../../lib/utils.js";
10
+ import { Input as pe } from "../ui/input.js";
11
+ import { Button as H } from "../ui/button.js";
12
+ import { mjmlToTiptapHtml as ge, sanitizeHtmlForMjml as he } from "../../lib/html-utils.js";
13
+ import { useLiquidSchema as ke } from "../../context/LiquidSchemaContext.js";
14
+ import { LiquidSuggestion as be } from "../../extensions/LiquidSuggestion.js";
15
+ import { LiquidHighlight as xe } from "../../extensions/LiquidHighlight.js";
16
+ import { LiquidAutocomplete as ve } from "./LiquidAutocomplete.js";
17
+ const $e = Q(
18
+ function({ content: v, onUpdate: S, style: L, className: $ }, j) {
19
+ const q = _(() => ge(v), []), [F, R] = x(!1), [U, p] = x(!1), [g, f] = x(""), C = d(null), h = d(null), k = ke(), [a, c] = x(null), I = d(a);
20
+ I.current = a;
21
+ const z = d(null), N = u(
22
+ (e, r) => {
23
+ if (!k) return [];
24
+ const n = e === "variable" ? k.variables : k.tags, l = r.trim().toLowerCase();
25
+ return n.filter((o) => o.name.toLowerCase().includes(l)).map((o) => ({
26
+ id: `${e}-${o.name}`,
27
+ name: o.name,
28
+ description: o.description,
29
+ type: e
30
+ }));
31
+ },
32
+ [k]
33
+ ), E = d(null), { refs: D, floatingStyles: V } = te({
34
+ placement: "top",
35
+ middleware: [ie(8), re(), oe({ padding: 8 })],
36
+ whileElementsMounted: ne
37
+ }), t = W({
38
+ extensions: [
39
+ Y.configure({
40
+ heading: !1,
41
+ blockquote: !1,
42
+ bulletList: !1,
43
+ orderedList: !1,
44
+ codeBlock: !1,
45
+ code: !1,
46
+ horizontalRule: !1,
47
+ bold: {},
48
+ italic: {},
49
+ strike: {},
50
+ hardBreak: {}
51
+ }),
52
+ ee,
53
+ Z.configure({
54
+ openOnClick: !1,
55
+ HTMLAttributes: {
56
+ target: "_blank",
57
+ rel: "noopener noreferrer"
58
+ }
59
+ }),
60
+ xe,
61
+ be.configure({
62
+ onStart: ({
63
+ query: e,
64
+ triggerType: r,
65
+ range: n,
66
+ clientRect: l
67
+ }) => {
68
+ const o = N(r, e);
69
+ o.length === 0 && e.trim() === "" || c({
70
+ active: !0,
71
+ items: o,
72
+ selectedIndex: 0,
73
+ triggerType: r,
74
+ range: n,
75
+ clientRect: l
76
+ });
77
+ },
78
+ onUpdate: ({
79
+ query: e,
80
+ triggerType: r,
81
+ range: n,
82
+ clientRect: l
83
+ }) => {
84
+ const o = N(r, e);
85
+ c(
86
+ (s) => s ? {
87
+ ...s,
88
+ items: o,
89
+ selectedIndex: 0,
90
+ range: n,
91
+ clientRect: l
92
+ } : null
93
+ );
94
+ },
95
+ onExit: () => {
96
+ c(null);
97
+ },
98
+ onKeyDown: (e) => {
99
+ const r = I.current;
100
+ if (!r?.active) return !1;
101
+ if (e.key === "ArrowDown")
102
+ return e.preventDefault(), c(
103
+ (n) => n ? {
104
+ ...n,
105
+ selectedIndex: Math.min(
106
+ n.selectedIndex + 1,
107
+ n.items.length - 1
108
+ )
109
+ } : null
110
+ ), !0;
111
+ if (e.key === "ArrowUp")
112
+ return e.preventDefault(), c(
113
+ (n) => n ? {
114
+ ...n,
115
+ selectedIndex: Math.max(n.selectedIndex - 1, 0)
116
+ } : null
117
+ ), !0;
118
+ if (e.key === "Enter" || e.key === "Tab") {
119
+ if (e.preventDefault(), r.items.length > 0) {
120
+ const n = r.items[r.selectedIndex];
121
+ n && z.current?.(n);
122
+ }
123
+ return !0;
124
+ }
125
+ return e.key === "Escape" ? (e.preventDefault(), c(null), !0) : !1;
126
+ }
127
+ })
128
+ ],
129
+ content: q,
130
+ autofocus: !1,
131
+ immediatelyRender: !1,
132
+ editorProps: {
133
+ attributes: {
134
+ class: "outline-none"
135
+ }
136
+ },
137
+ onUpdate: ({ editor: e }) => {
138
+ const r = e.getHTML();
139
+ S(he(r));
140
+ },
141
+ onSelectionUpdate: ({ editor: e }) => {
142
+ const { from: r, to: n, empty: l } = e.state.selection;
143
+ if (h.current && (clearTimeout(h.current), h.current = null), l) {
144
+ U || (h.current = setTimeout(() => {
145
+ R(!1);
146
+ }, 100));
147
+ return;
148
+ }
149
+ const { view: o } = e, s = o.coordsAtPos(r), b = o.coordsAtPos(n), M = {
150
+ x: s.left,
151
+ y: s.top,
152
+ width: b.left - s.left,
153
+ height: b.bottom - s.top,
154
+ top: s.top,
155
+ left: s.left,
156
+ right: b.left,
157
+ bottom: b.bottom,
158
+ toJSON: () => M
159
+ };
160
+ E.current = {
161
+ getBoundingClientRect: () => M
162
+ }, D.setReference(E.current), R(!0);
163
+ }
164
+ }), K = u(() => {
165
+ if (!t) return;
166
+ const e = t.getAttributes("link").href || "";
167
+ f(e), p(!0), setTimeout(() => {
168
+ C.current?.focus(), C.current?.select();
169
+ }, 0);
170
+ }, [t]), T = u(() => {
171
+ t && (g && t.chain().focus().extendMarkRange("link").setLink({ href: g }).run(), p(!1), f(""));
172
+ }, [t, g]), P = u(() => {
173
+ t && (t.chain().focus().unsetLink().run(), p(!1), f(""));
174
+ }, [t]), O = u(() => {
175
+ p(!1), f(""), t?.commands.focus();
176
+ }, [t]), B = u(
177
+ (e) => {
178
+ const r = I.current;
179
+ if (!t || !r) return;
180
+ const { range: n, triggerType: l } = r, o = l === "variable" ? `{{ ${e.name} }}` : `{% ${e.name} %}`;
181
+ t.chain().focus().deleteRange(n).insertContent(o).run(), c(null);
182
+ },
183
+ [t]
184
+ );
185
+ if (z.current = B, G(j, () => ({
186
+ focus: () => {
187
+ t?.commands.focus();
188
+ }
189
+ })), !t)
190
+ return null;
191
+ const y = t.isActive("link");
192
+ return /* @__PURE__ */ w("div", { className: "relative cursor-text", children: [
193
+ F && /* @__PURE__ */ i(
194
+ "div",
195
+ {
196
+ ref: D.setFloating,
197
+ style: V,
198
+ className: "light z-50 flex items-center gap-0.5 rounded-lg border border-border bg-popover p-1 shadow-lg",
199
+ onMouseDown: (e) => e.preventDefault(),
200
+ children: U ? (
201
+ // Link input mode
202
+ /* @__PURE__ */ w("div", { className: "flex items-center gap-1 px-1", children: [
203
+ /* @__PURE__ */ i(
204
+ pe,
205
+ {
206
+ ref: C,
207
+ type: "url",
208
+ placeholder: "https://...",
209
+ value: g,
210
+ onChange: (e) => f(e.target.value),
211
+ onKeyDown: (e) => {
212
+ e.key === "Enter" ? (e.preventDefault(), T()) : e.key === "Escape" && (e.preventDefault(), O());
213
+ },
214
+ className: "h-7 w-48 text-sm"
215
+ }
216
+ ),
217
+ /* @__PURE__ */ i(
218
+ H,
219
+ {
220
+ size: "icon-sm",
221
+ variant: "ghost",
222
+ onClick: T,
223
+ title: "Apply link",
224
+ children: /* @__PURE__ */ i(le, { className: "size-4" })
225
+ }
226
+ ),
227
+ y && /* @__PURE__ */ i(
228
+ H,
229
+ {
230
+ size: "icon-sm",
231
+ variant: "ghost",
232
+ onClick: P,
233
+ title: "Remove link",
234
+ children: /* @__PURE__ */ i(se, { className: "size-4" })
235
+ }
236
+ )
237
+ ] })
238
+ ) : (
239
+ // Format buttons mode
240
+ /* @__PURE__ */ w(J, { children: [
241
+ /* @__PURE__ */ i(
242
+ m,
243
+ {
244
+ active: t.isActive("bold"),
245
+ onClick: () => t.chain().focus().toggleBold().run(),
246
+ title: "Bold (Cmd+B)",
247
+ children: /* @__PURE__ */ i(ce, { className: "size-4" })
248
+ }
249
+ ),
250
+ /* @__PURE__ */ i(
251
+ m,
252
+ {
253
+ active: t.isActive("italic"),
254
+ onClick: () => t.chain().focus().toggleItalic().run(),
255
+ title: "Italic (Cmd+I)",
256
+ children: /* @__PURE__ */ i(ae, { className: "size-4" })
257
+ }
258
+ ),
259
+ /* @__PURE__ */ i(
260
+ m,
261
+ {
262
+ active: t.isActive("underline"),
263
+ onClick: () => t.chain().focus().toggleUnderline().run(),
264
+ title: "Underline (Cmd+U)",
265
+ children: /* @__PURE__ */ i(ue, { className: "size-4" })
266
+ }
267
+ ),
268
+ /* @__PURE__ */ i(
269
+ m,
270
+ {
271
+ active: t.isActive("strike"),
272
+ onClick: () => t.chain().focus().toggleStrike().run(),
273
+ title: "Strikethrough",
274
+ children: /* @__PURE__ */ i(fe, { className: "size-4" })
275
+ }
276
+ ),
277
+ /* @__PURE__ */ i(Se, {}),
278
+ /* @__PURE__ */ i(
279
+ m,
280
+ {
281
+ active: y,
282
+ onClick: K,
283
+ title: y ? "Edit link" : "Add link",
284
+ children: /* @__PURE__ */ i(de, { className: "size-4" })
285
+ }
286
+ )
287
+ ] })
288
+ )
289
+ }
290
+ ),
291
+ /* @__PURE__ */ i(X, { editor: t, style: L, className: $ }),
292
+ a?.active && /* @__PURE__ */ i(
293
+ ve,
294
+ {
295
+ items: a.items,
296
+ selectedIndex: a.selectedIndex,
297
+ onSelect: B,
298
+ clientRect: a.clientRect
299
+ }
300
+ )
301
+ ] });
302
+ }
303
+ );
304
+ function m({
305
+ active: A,
306
+ onClick: v,
307
+ title: S,
308
+ children: L
309
+ }) {
310
+ return /* @__PURE__ */ i(
311
+ "button",
312
+ {
313
+ type: "button",
314
+ onClick: v,
315
+ title: S,
316
+ className: me(
317
+ "flex items-center justify-center size-7 rounded-md transition-colors",
318
+ "text-foreground hover:bg-accent",
319
+ A && "bg-accent text-accent-foreground"
320
+ ),
321
+ children: L
322
+ }
323
+ );
324
+ }
325
+ function Se() {
326
+ return /* @__PURE__ */ i("div", { className: "w-px h-5 bg-border mx-1" });
327
+ }
328
+ export {
329
+ $e as TiptapEditor
330
+ };
@@ -0,0 +1,7 @@
1
+ interface VisualEditorProps {
2
+ leftPanelOpen?: boolean;
3
+ rightPanelOpen?: boolean;
4
+ }
5
+ export declare function VisualEditor({ leftPanelOpen, rightPanelOpen, }: VisualEditorProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=VisualEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualEditor.d.ts","sourceRoot":"","sources":["../../../src/components/editor/VisualEditor.tsx"],"names":[],"mappings":"AAeA,UAAU,iBAAiB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,YAAY,CAAC,EAC3B,aAAa,EACb,cAAc,GACf,EAAE,iBAAiB,2CAwEnB"}
@@ -0,0 +1,51 @@
1
+ import { jsx as r, jsxs as g } from "react/jsx-runtime";
2
+ import { useEditor as b } from "../../context/EditorContext.js";
3
+ import { ScrollArea as p } from "../ui/scroll-area.js";
4
+ import { VisualSection as N } from "./visual-blocks/VisualSection.js";
5
+ import { useFontLoader as y } from "../../hooks/useFontLoader.js";
6
+ import { useStyleLoader as _, VISUAL_EDITOR_SCOPE_CLASS as A } from "../../hooks/useStyleLoader.js";
7
+ const E = 256, L = 300, i = 12, c = 24;
8
+ function G({
9
+ leftPanelOpen: s,
10
+ rightPanelOpen: l
11
+ }) {
12
+ const { state: a, selectBlock: m } = b();
13
+ y(), _();
14
+ const o = a.document.children?.find((t) => t.tagName === "mj-body"), e = o?.attributes.width || "600px", u = o?.attributes["background-color"], h = (t) => {
15
+ t.target === t.currentTarget && m(null);
16
+ }, d = s ? E + i + c : 16, n = l ? L + i + c : 16, f = (parseInt(e, 10) || 600) + d + n;
17
+ return /* @__PURE__ */ r(
18
+ p,
19
+ {
20
+ className: "h-full",
21
+ orientation: "both",
22
+ viewportStyle: { backgroundColor: u || "#ffffff" },
23
+ children: /* @__PURE__ */ r(
24
+ "div",
25
+ {
26
+ className: "py-8",
27
+ style: {
28
+ paddingLeft: d,
29
+ paddingRight: n,
30
+ minWidth: f
31
+ },
32
+ onClick: h,
33
+ children: /* @__PURE__ */ g(
34
+ "div",
35
+ {
36
+ className: `light mx-auto w-full ${A}`,
37
+ style: { maxWidth: e },
38
+ children: [
39
+ o?.children?.map((t) => /* @__PURE__ */ r(N, { node: t }, t._id)),
40
+ (!o?.children || o.children.length === 0) && /* @__PURE__ */ r("div", { className: "bg-surface rounded-lg border-2 border-dashed border-border p-12 text-center", children: /* @__PURE__ */ r("p", { className: "text-muted-foreground", children: "Add a section to get started" }) })
41
+ ]
42
+ }
43
+ )
44
+ }
45
+ )
46
+ }
47
+ );
48
+ }
49
+ export {
50
+ G as VisualEditor
51
+ };
@@ -0,0 +1,7 @@
1
+ import { MjmlNode } from '../../../types/mjml';
2
+ interface VisualBlockProps {
3
+ node: MjmlNode;
4
+ }
5
+ export declare function VisualBlock({ node }: VisualBlockProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=VisualBlock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/editor/visual-blocks/VisualBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAS7C,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAuBrD"}
@@ -0,0 +1,34 @@
1
+ import { jsxs as a, jsx as t } from "react/jsx-runtime";
2
+ import { VisualText as m } from "./VisualText.js";
3
+ import { VisualImage as e } from "./VisualImage.js";
4
+ import { VisualButton as i } from "./VisualButton.js";
5
+ import { VisualDivider as s } from "./VisualDivider.js";
6
+ import { VisualSpacer as u } from "./VisualSpacer.js";
7
+ import { VisualSocial as o } from "./VisualSocial.js";
8
+ import { VisualRaw as c } from "./VisualRaw.js";
9
+ function g({ node: r }) {
10
+ switch (r.tagName) {
11
+ case "mj-text":
12
+ return /* @__PURE__ */ t(m, { node: r });
13
+ case "mj-image":
14
+ return /* @__PURE__ */ t(e, { node: r });
15
+ case "mj-button":
16
+ return /* @__PURE__ */ t(i, { node: r });
17
+ case "mj-divider":
18
+ return /* @__PURE__ */ t(s, { node: r });
19
+ case "mj-spacer":
20
+ return /* @__PURE__ */ t(u, { node: r });
21
+ case "mj-social":
22
+ return /* @__PURE__ */ t(o, { node: r });
23
+ case "mj-raw":
24
+ return /* @__PURE__ */ t(c, { node: r });
25
+ default:
26
+ return /* @__PURE__ */ a("div", { className: "p-2 bg-amber-50 border border-amber-200 text-amber-700 text-sm", children: [
27
+ "Unsupported block: ",
28
+ r.tagName
29
+ ] });
30
+ }
31
+ }
32
+ export {
33
+ g as VisualBlock
34
+ };
@@ -0,0 +1,7 @@
1
+ import { MjmlNode } from '../../../types/mjml';
2
+ interface VisualButtonProps {
3
+ node: MjmlNode;
4
+ }
5
+ export declare function VisualButton({ node }: VisualButtonProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=VisualButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualButton.d.ts","sourceRoot":"","sources":["../../../../src/components/editor/visual-blocks/VisualButton.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,UAAU,iBAAiB;IACzB,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,iBAAiB,2CAmLvD"}
@@ -0,0 +1,111 @@
1
+ import { jsxs as I, jsx as c } from "react/jsx-runtime";
2
+ import { useState as L, useRef as O, useEffect as Q, useMemo as X } from "react";
3
+ import { useEditor as Y } from "../../../context/EditorContext.js";
4
+ import { cn as a } from "../../../lib/utils.js";
5
+ import { highlightLiquidTags as Z } from "../../../lib/html-utils.js";
6
+ import { buildPadding as $ } from "./helpers.js";
7
+ import { useResolvedAttributes as tt } from "./useResolvedAttributes.js";
8
+ import { LiquidInput as et } from "../LiquidInput.js";
9
+ function dt({ node: o }) {
10
+ const { state: N, selectBlock: T, updateContent: _ } = Y(), d = N.selectedBlockId === o._id, [n, s] = L(!1), [l, f] = L(""), i = O(null), t = tt(o), A = (e) => {
11
+ e.stopPropagation(), e.preventDefault(), T(o._id);
12
+ }, P = (e) => {
13
+ e.stopPropagation(), e.preventDefault(), f(o.content || ""), s(!0);
14
+ }, j = () => {
15
+ s(!1), l !== o.content && _(o._id, l);
16
+ }, H = (e) => {
17
+ e.key === "Escape" ? s(!1) : e.key === "Enter" && (e.preventDefault(), i.current?.blur());
18
+ };
19
+ Q(() => {
20
+ n && i.current && (i.current.focus(), i.current.select());
21
+ }, [n]);
22
+ const V = t["background-color"] || "#414141", u = t.color || "#ffffff", g = t["font-size"] || "13px", p = t["font-family"] || "Ubuntu, Helvetica, Arial, sans-serif", b = t["font-weight"] || "normal", h = t["font-style"] || "normal", m = t["line-height"] || "120%", x = t["letter-spacing"], v = t["text-align"] || "center", y = t["text-decoration"] || "none", k = t["text-transform"] || "none", q = t["border-radius"] || "3px", C = t.border, w = t["border-top"], B = t["border-right"], D = t["border-bottom"], S = t["border-left"], E = t.align || "center", R = t["vertical-align"] || "middle", z = t["inner-padding"] || "10px 25px", K = $(t, "10px 25px"), M = t.width, F = t.height, U = t["container-background-color"], W = E === "left" ? "flex-start" : E === "right" ? "flex-end" : "center", G = R === "top" ? "flex-start" : R === "bottom" ? "flex-end" : "center", r = {
23
+ backgroundColor: V,
24
+ color: u,
25
+ fontSize: g,
26
+ fontFamily: p,
27
+ fontWeight: b,
28
+ fontStyle: h,
29
+ lineHeight: m,
30
+ letterSpacing: x || void 0,
31
+ textAlign: v,
32
+ textDecoration: y,
33
+ textTransform: k,
34
+ padding: z,
35
+ borderRadius: q,
36
+ width: M || void 0,
37
+ height: F || void 0
38
+ };
39
+ C && (r.border = C), w && (r.borderTop = w), B && (r.borderRight = B), D && (r.borderBottom = D), S && (r.borderLeft = S);
40
+ const J = X(
41
+ () => Z(o.content || "") || "Button",
42
+ [o.content]
43
+ );
44
+ return /* @__PURE__ */ I(
45
+ "div",
46
+ {
47
+ className: a(
48
+ "relative transition-all",
49
+ d && !n && "ring-2 ring-indigo-500 ring-offset-2",
50
+ t["css-class"]
51
+ ),
52
+ style: {
53
+ padding: K,
54
+ display: "flex",
55
+ justifyContent: W,
56
+ alignItems: G,
57
+ backgroundColor: U || void 0
58
+ },
59
+ onClick: A,
60
+ onDoubleClick: P,
61
+ children: [
62
+ /* @__PURE__ */ I(
63
+ "span",
64
+ {
65
+ className: a(
66
+ "relative inline-block cursor-pointer",
67
+ n && "ring-2 ring-indigo-500"
68
+ ),
69
+ style: r,
70
+ children: [
71
+ /* @__PURE__ */ c(
72
+ "span",
73
+ {
74
+ className: a(n && "invisible"),
75
+ dangerouslySetInnerHTML: { __html: J }
76
+ }
77
+ ),
78
+ n && /* @__PURE__ */ c(
79
+ et,
80
+ {
81
+ ref: i,
82
+ value: l,
83
+ onChange: f,
84
+ onBlur: j,
85
+ onKeyDown: H,
86
+ className: "absolute inset-0 w-full h-full outline-none bg-transparent",
87
+ style: {
88
+ color: u,
89
+ fontSize: g,
90
+ fontFamily: p,
91
+ fontWeight: b,
92
+ fontStyle: h,
93
+ lineHeight: m,
94
+ letterSpacing: x || void 0,
95
+ textAlign: v,
96
+ textDecoration: y,
97
+ textTransform: k
98
+ }
99
+ }
100
+ )
101
+ ]
102
+ }
103
+ ),
104
+ d && !n && /* @__PURE__ */ c("div", { className: "absolute -top-6 left-1/2 -translate-x-1/2 text-xs text-indigo-600 bg-white px-1 rounded shadow-sm whitespace-nowrap", children: "Double-click to edit" })
105
+ ]
106
+ }
107
+ );
108
+ }
109
+ export {
110
+ dt as VisualButton
111
+ };
@@ -0,0 +1,8 @@
1
+ import { MjmlNode } from '../../../types/mjml';
2
+ interface VisualColumnProps {
3
+ node: MjmlNode;
4
+ totalColumns: number;
5
+ }
6
+ export declare function VisualColumn({ node, totalColumns }: VisualColumnProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=VisualColumn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualColumn.d.ts","sourceRoot":"","sources":["../../../../src/components/editor/visual-blocks/VisualColumn.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,UAAU,iBAAiB;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,iBAAiB,2CA4HrE"}
@@ -0,0 +1,44 @@
1
+ import { jsx as n, jsxs as S, Fragment as P } from "react/jsx-runtime";
2
+ import { useEditor as V } from "../../../context/EditorContext.js";
3
+ import { VisualBlock as x } from "./VisualBlock.js";
4
+ import { cn as E } from "../../../lib/utils.js";
5
+ import { buildPadding as F } from "./helpers.js";
6
+ import { useResolvedAttributes as $ } from "./useResolvedAttributes.js";
7
+ function M({ node: i, totalColumns: L }) {
8
+ const { state: T, selectBlock: _ } = V(), w = T.selectedBlockId === i._id, r = $(i), s = (e) => {
9
+ e.stopPropagation(), _(i._id);
10
+ }, u = r.width;
11
+ let c;
12
+ u ? c = u : c = `${100 / L}%`;
13
+ const A = r["background-color"] || "transparent", N = F(r, "0"), h = r["vertical-align"] || "top", B = r.border, k = r["border-top"], C = r["border-right"], R = r["border-bottom"], v = r["border-left"], y = r["border-radius"], l = r["inner-background-color"], a = r["inner-border"], b = r["inner-border-top"], f = r["inner-border-right"], g = r["inner-border-bottom"], m = r["inner-border-left"], p = r["inner-border-radius"], j = r.direction || "ltr", I = l || a || b || f || g || m || p, d = i.children || [], t = {
14
+ width: c,
15
+ backgroundColor: A,
16
+ padding: N,
17
+ alignSelf: h === "top" ? "flex-start" : h === "bottom" ? "flex-end" : "center",
18
+ direction: j
19
+ };
20
+ B && (t.border = B), k && (t.borderTop = k), C && (t.borderRight = C), R && (t.borderBottom = R), v && (t.borderLeft = v), y && (t.borderRadius = y);
21
+ const o = {};
22
+ return l && (o.backgroundColor = l), a && (o.border = a), b && (o.borderTop = b), f && (o.borderRight = f), g && (o.borderBottom = g), m && (o.borderLeft = m), p && (o.borderRadius = p), /* @__PURE__ */ n(
23
+ "div",
24
+ {
25
+ className: E(
26
+ "relative transition-all",
27
+ w && "ring-2 ring-indigo-500 ring-inset",
28
+ r["css-class"]
29
+ ),
30
+ style: t,
31
+ onClick: s,
32
+ children: I ? /* @__PURE__ */ S("div", { style: o, children: [
33
+ d.map((e) => /* @__PURE__ */ n(x, { node: e }, e._id)),
34
+ d.length === 0 && /* @__PURE__ */ n("div", { className: "py-4", onClick: s })
35
+ ] }) : /* @__PURE__ */ S(P, { children: [
36
+ d.map((e) => /* @__PURE__ */ n(x, { node: e }, e._id)),
37
+ d.length === 0 && /* @__PURE__ */ n("div", { className: "py-4", onClick: s })
38
+ ] })
39
+ }
40
+ );
41
+ }
42
+ export {
43
+ M as VisualColumn
44
+ };
@@ -0,0 +1,7 @@
1
+ import { MjmlNode } from '../../../types/mjml';
2
+ interface VisualDividerProps {
3
+ node: MjmlNode;
4
+ }
5
+ export declare function VisualDivider({ node }: VisualDividerProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=VisualDivider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisualDivider.d.ts","sourceRoot":"","sources":["../../../../src/components/editor/visual-blocks/VisualDivider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,UAAU,kBAAkB;IAC1B,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE,kBAAkB,2CAoDzD"}
@@ -0,0 +1,41 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import { useEditor as f } from "../../../context/EditorContext.js";
3
+ import { cn as k } from "../../../lib/utils.js";
4
+ import { buildPadding as C } from "./helpers.js";
5
+ import { useResolvedAttributes as v } from "./useResolvedAttributes.js";
6
+ function T({ node: r }) {
7
+ const { state: n, selectBlock: s } = f(), c = n.selectedBlockId === r._id, o = v(r), d = (h) => {
8
+ h.stopPropagation(), s(r._id);
9
+ }, l = o["border-color"] || "#000000", a = o["border-width"] || "4px", g = o["border-style"] || "solid", p = o.width || "100%", t = o.align || "center", u = C(o, "10px 25px"), i = o["container-background-color"], b = t === "right" || t === "center" ? "auto" : "0", m = t === "left" || t === "center" ? "auto" : "0";
10
+ return /* @__PURE__ */ e(
11
+ "div",
12
+ {
13
+ className: k(
14
+ "relative cursor-pointer transition-all",
15
+ c && "ring-2 ring-indigo-500 ring-inset",
16
+ o["css-class"]
17
+ ),
18
+ style: {
19
+ padding: u,
20
+ ...i && { backgroundColor: i }
21
+ },
22
+ onClick: d,
23
+ children: /* @__PURE__ */ e(
24
+ "div",
25
+ {
26
+ style: {
27
+ width: p,
28
+ marginLeft: b,
29
+ marginRight: m,
30
+ borderTopColor: l,
31
+ borderTopWidth: a,
32
+ borderTopStyle: g
33
+ }
34
+ }
35
+ )
36
+ }
37
+ );
38
+ }
39
+ export {
40
+ T as VisualDivider
41
+ };