@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,116 @@
1
+ import { jsxs as r, jsx as e } from "react/jsx-runtime";
2
+ import { useState as g } from "react";
3
+ import { Monitor as x, Smartphone as v, Undo2 as N, Redo2 as b } from "lucide-react";
4
+ import { VisualEditor as w } from "./VisualEditor.js";
5
+ import { InteractivePreview as k } from "./InteractivePreview.js";
6
+ import { SourceEditor as C } from "./SourceEditor.js";
7
+ import { useEditor as y } from "../../context/EditorContext.js";
8
+ import { Button as i } from "../ui/button.js";
9
+ import { Tabs as E, TabsList as S, TabsTrigger as s } from "../ui/tabs.js";
10
+ import { ThemeToggle as M } from "../ui/theme-toggle.js";
11
+ import { cn as d } from "../../lib/utils.js";
12
+ function L({
13
+ activeTab: o,
14
+ onTabChange: t,
15
+ leftPanelOpen: a,
16
+ rightPanelOpen: l
17
+ }) {
18
+ const { undo: c, redo: m, canUndo: u, canRedo: h } = y(), [n, f] = g("desktop");
19
+ return /* @__PURE__ */ r("div", { className: "flex flex-col h-full", children: [
20
+ /* @__PURE__ */ r("div", { className: "h-11 px-4 flex items-center gap-1 border-b border-border bg-background relative", children: [
21
+ /* @__PURE__ */ e(
22
+ "button",
23
+ {
24
+ onClick: () => t("edit"),
25
+ className: d(
26
+ "px-3 py-1.5 text-sm font-medium rounded-md transition-colors",
27
+ o === "edit" ? "bg-accent text-foreground" : "text-foreground-muted hover:text-foreground hover:bg-accent/50"
28
+ ),
29
+ children: "Edit"
30
+ }
31
+ ),
32
+ /* @__PURE__ */ e(
33
+ "button",
34
+ {
35
+ onClick: () => t("preview"),
36
+ className: d(
37
+ "px-3 py-1.5 text-sm font-medium rounded-md transition-colors",
38
+ o === "preview" ? "bg-accent text-foreground" : "text-foreground-muted hover:text-foreground hover:bg-accent/50"
39
+ ),
40
+ children: "Preview"
41
+ }
42
+ ),
43
+ /* @__PURE__ */ e(
44
+ "button",
45
+ {
46
+ onClick: () => t("source"),
47
+ className: d(
48
+ "px-3 py-1.5 text-sm font-medium rounded-md transition-colors",
49
+ o === "source" ? "bg-accent text-foreground" : "text-foreground-muted hover:text-foreground hover:bg-accent/50"
50
+ ),
51
+ children: "Source"
52
+ }
53
+ ),
54
+ o === "preview" && /* @__PURE__ */ e(
55
+ E,
56
+ {
57
+ value: n,
58
+ onValueChange: (p) => f(p),
59
+ className: "absolute left-1/2 -translate-x-1/2",
60
+ children: /* @__PURE__ */ r(S, { className: "h-8", children: [
61
+ /* @__PURE__ */ r(s, { value: "desktop", className: "h-7 px-2 gap-1.5", children: [
62
+ /* @__PURE__ */ e(x, { className: "h-3.5 w-3.5" }),
63
+ /* @__PURE__ */ e("span", { className: "hidden md:inline", children: "Desktop" })
64
+ ] }),
65
+ /* @__PURE__ */ r(s, { value: "mobile", className: "h-7 px-2 gap-1.5", children: [
66
+ /* @__PURE__ */ e(v, { className: "h-3.5 w-3.5" }),
67
+ /* @__PURE__ */ e("span", { className: "hidden md:inline", children: "Mobile" })
68
+ ] })
69
+ ] })
70
+ }
71
+ ),
72
+ /* @__PURE__ */ e("div", { className: "flex-1" }),
73
+ /* @__PURE__ */ r("div", { className: "flex items-center gap-0.5", children: [
74
+ /* @__PURE__ */ e(
75
+ i,
76
+ {
77
+ variant: "ghost",
78
+ size: "icon-sm",
79
+ onClick: c,
80
+ disabled: !u,
81
+ className: "h-7 w-7 rounded-md text-foreground-muted hover:text-foreground hover:bg-accent disabled:opacity-40",
82
+ title: "Undo (Cmd+Z)",
83
+ children: /* @__PURE__ */ e(N, { className: "h-4 w-4" })
84
+ }
85
+ ),
86
+ /* @__PURE__ */ e(
87
+ i,
88
+ {
89
+ variant: "ghost",
90
+ size: "icon-sm",
91
+ onClick: m,
92
+ disabled: !h,
93
+ className: "h-7 w-7 rounded-md text-foreground-muted hover:text-foreground hover:bg-accent disabled:opacity-40",
94
+ title: "Redo (Cmd+Shift+Z)",
95
+ children: /* @__PURE__ */ e(b, { className: "h-4 w-4" })
96
+ }
97
+ ),
98
+ /* @__PURE__ */ e(M, {})
99
+ ] })
100
+ ] }),
101
+ /* @__PURE__ */ r("div", { className: "flex-1 min-h-0 overflow-hidden", children: [
102
+ o === "edit" && /* @__PURE__ */ e(
103
+ w,
104
+ {
105
+ leftPanelOpen: a,
106
+ rightPanelOpen: l
107
+ }
108
+ ),
109
+ o === "preview" && /* @__PURE__ */ e(k, { showHeader: !1, previewMode: n }),
110
+ o === "source" && /* @__PURE__ */ e(C, {})
111
+ ] })
112
+ ] });
113
+ }
114
+ export {
115
+ L as EditorCanvas
116
+ };
@@ -0,0 +1,2 @@
1
+ export declare function FontEditor(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=FontEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontEditor.d.ts","sourceRoot":"","sources":["../../../src/components/editor/FontEditor.tsx"],"names":[],"mappings":"AAkDA,wBAAgB,UAAU,4CAoNzB"}
@@ -0,0 +1,227 @@
1
+ import { jsx as s, jsxs as t } from "react/jsx-runtime";
2
+ import { useState as i } from "react";
3
+ import { Plus as A, ChevronRight as S, X as k, ExternalLink as R } from "lucide-react";
4
+ import { useEditor as P } from "../../context/EditorContext.js";
5
+ import { ScrollArea as D } from "../ui/scroll-area.js";
6
+ import { Label as m } from "../ui/label.js";
7
+ import { Input as f } from "../ui/input.js";
8
+ import { Button as c } from "../ui/button.js";
9
+ import { Collapsible as E, CollapsibleTrigger as L, CollapsibleContent as O } from "../ui/collapsible.js";
10
+ import { cn as z } from "../../lib/utils.js";
11
+ const I = [
12
+ {
13
+ name: "Roboto",
14
+ href: "https://fonts.googleapis.com/css?family=Roboto:400,700"
15
+ },
16
+ {
17
+ name: "Open Sans",
18
+ href: "https://fonts.googleapis.com/css?family=Open+Sans:400,700"
19
+ },
20
+ {
21
+ name: "Lato",
22
+ href: "https://fonts.googleapis.com/css?family=Lato:400,700"
23
+ },
24
+ {
25
+ name: "Montserrat",
26
+ href: "https://fonts.googleapis.com/css?family=Montserrat:400,700"
27
+ },
28
+ {
29
+ name: "Raleway",
30
+ href: "https://fonts.googleapis.com/css?family=Raleway:400,700"
31
+ },
32
+ {
33
+ name: "Poppins",
34
+ href: "https://fonts.googleapis.com/css?family=Poppins:400,700"
35
+ },
36
+ {
37
+ name: "Inter",
38
+ href: "https://fonts.googleapis.com/css?family=Inter:400,700"
39
+ },
40
+ {
41
+ name: "Playfair Display",
42
+ href: "https://fonts.googleapis.com/css?family=Playfair+Display:400,700"
43
+ }
44
+ ];
45
+ function X() {
46
+ const { fonts: o, addFont: u, removeFont: N, updateFont: v } = P(), [n, d] = i(""), [r, p] = i(""), [F, g] = i({}), [w, h] = i(!1), C = (e) => {
47
+ g((a) => ({ ...a, [e]: !a[e] }));
48
+ }, x = () => {
49
+ n.trim() && r.trim() && (u(n.trim(), r.trim()), d(""), p(""), h(!1), g((e) => ({ ...e, [n.trim()]: !0 })));
50
+ }, y = (e) => {
51
+ e.key === "Enter" && n.trim() && r.trim() && (e.preventDefault(), x());
52
+ }, b = (e) => {
53
+ o.find((a) => a.name === e.name) || u(e.name, e.href);
54
+ };
55
+ return /* @__PURE__ */ s(D, { className: "flex-1 min-h-0", children: /* @__PURE__ */ t("div", { className: "p-4 space-y-4", children: [
56
+ /* @__PURE__ */ s("p", { className: "text-xs text-foreground-muted", children: "Add web fonts to use in your email. Custom fonts have limited email client support, so always include fallback fonts." }),
57
+ /* @__PURE__ */ t("div", { className: "space-y-2", children: [
58
+ /* @__PURE__ */ s(m, { className: "text-xs font-medium text-foreground-muted", children: "Quick Add (Google Fonts)" }),
59
+ /* @__PURE__ */ s("div", { className: "flex flex-wrap gap-1.5", children: I.map((e) => {
60
+ const a = o.some((l) => l.name === e.name);
61
+ return /* @__PURE__ */ t(
62
+ c,
63
+ {
64
+ size: "sm",
65
+ variant: a ? "secondary" : "outline",
66
+ disabled: a,
67
+ onClick: () => b(e),
68
+ className: "h-7 text-xs",
69
+ children: [
70
+ e.name,
71
+ a && /* @__PURE__ */ s("span", { className: "ml-1 text-muted-foreground", children: "✓" })
72
+ ]
73
+ },
74
+ e.name
75
+ );
76
+ }) })
77
+ ] }),
78
+ /* @__PURE__ */ s("div", { className: "space-y-2", children: w ? /* @__PURE__ */ t("div", { className: "border border-border rounded-md p-3 space-y-3", children: [
79
+ /* @__PURE__ */ t("div", { className: "space-y-2", children: [
80
+ /* @__PURE__ */ s(m, { className: "text-xs", children: "Font Name" }),
81
+ /* @__PURE__ */ s(
82
+ f,
83
+ {
84
+ type: "text",
85
+ placeholder: "e.g., Raleway",
86
+ value: n,
87
+ onChange: (e) => d(e.target.value),
88
+ onKeyDown: y,
89
+ className: "h-8 text-xs"
90
+ }
91
+ )
92
+ ] }),
93
+ /* @__PURE__ */ t("div", { className: "space-y-2", children: [
94
+ /* @__PURE__ */ s(m, { className: "text-xs", children: "CSS URL" }),
95
+ /* @__PURE__ */ s(
96
+ f,
97
+ {
98
+ type: "url",
99
+ placeholder: "https://fonts.googleapis.com/css?family=...",
100
+ value: r,
101
+ onChange: (e) => p(e.target.value),
102
+ onKeyDown: y,
103
+ className: "h-8 text-xs"
104
+ }
105
+ )
106
+ ] }),
107
+ /* @__PURE__ */ t("div", { className: "flex gap-2", children: [
108
+ /* @__PURE__ */ s(
109
+ c,
110
+ {
111
+ size: "sm",
112
+ onClick: x,
113
+ disabled: !n.trim() || !r.trim(),
114
+ children: "Add Font"
115
+ }
116
+ ),
117
+ /* @__PURE__ */ s(
118
+ c,
119
+ {
120
+ size: "sm",
121
+ variant: "ghost",
122
+ onClick: () => {
123
+ h(!1), d(""), p("");
124
+ },
125
+ children: "Cancel"
126
+ }
127
+ )
128
+ ] })
129
+ ] }) : /* @__PURE__ */ t(
130
+ c,
131
+ {
132
+ size: "sm",
133
+ variant: "outline",
134
+ onClick: () => h(!0),
135
+ className: "w-full",
136
+ children: [
137
+ /* @__PURE__ */ s(A, { className: "h-4 w-4 mr-2" }),
138
+ "Add Custom Font"
139
+ ]
140
+ }
141
+ ) }),
142
+ o.length > 0 && /* @__PURE__ */ t("div", { className: "space-y-2", children: [
143
+ /* @__PURE__ */ s(m, { className: "text-xs font-medium text-foreground-muted", children: "Added Fonts" }),
144
+ o.map((e) => {
145
+ const a = F[e.name] || !1;
146
+ return /* @__PURE__ */ t(
147
+ E,
148
+ {
149
+ open: a,
150
+ onOpenChange: () => C(e.name),
151
+ children: [
152
+ /* @__PURE__ */ t("div", { className: "flex items-center gap-1", children: [
153
+ /* @__PURE__ */ t(L, { className: "flex items-center gap-2 flex-1 py-2 px-2 text-sm font-medium text-foreground hover:bg-muted/50 rounded-md transition-colors", children: [
154
+ /* @__PURE__ */ s(
155
+ S,
156
+ {
157
+ className: z(
158
+ "h-4 w-4 transition-transform",
159
+ a && "rotate-90"
160
+ )
161
+ }
162
+ ),
163
+ /* @__PURE__ */ s(
164
+ "span",
165
+ {
166
+ style: { fontFamily: `"${e.name}", sans-serif` },
167
+ children: e.name
168
+ }
169
+ )
170
+ ] }),
171
+ /* @__PURE__ */ s(
172
+ "button",
173
+ {
174
+ onClick: (l) => {
175
+ l.stopPropagation(), N(e.name);
176
+ },
177
+ className: "p-1 text-foreground-muted hover:text-destructive transition-colors",
178
+ children: /* @__PURE__ */ s(k, { className: "h-4 w-4" })
179
+ }
180
+ )
181
+ ] }),
182
+ /* @__PURE__ */ s(O, { children: /* @__PURE__ */ t("div", { className: "pl-6 pr-2 py-2 space-y-3", children: [
183
+ /* @__PURE__ */ t("div", { className: "space-y-2", children: [
184
+ /* @__PURE__ */ s(m, { className: "text-xs", children: "CSS URL" }),
185
+ /* @__PURE__ */ t("div", { className: "flex gap-2", children: [
186
+ /* @__PURE__ */ s(
187
+ f,
188
+ {
189
+ type: "url",
190
+ value: e.href,
191
+ onChange: (l) => v(e.name, l.target.value),
192
+ className: "h-8 text-xs flex-1 font-mono"
193
+ }
194
+ ),
195
+ /* @__PURE__ */ s(
196
+ "a",
197
+ {
198
+ href: e.href,
199
+ target: "_blank",
200
+ rel: "noopener noreferrer",
201
+ className: "p-2 text-foreground-muted hover:text-foreground transition-colors",
202
+ children: /* @__PURE__ */ s(R, { className: "h-4 w-4" })
203
+ }
204
+ )
205
+ ] })
206
+ ] }),
207
+ /* @__PURE__ */ t("div", { className: "text-xs text-foreground-muted", children: [
208
+ "Use in font-family:",
209
+ " ",
210
+ /* @__PURE__ */ t("code", { className: "bg-muted px-1 py-0.5 rounded", children: [
211
+ e.name,
212
+ ", sans-serif"
213
+ ] })
214
+ ] })
215
+ ] }) })
216
+ ]
217
+ },
218
+ e.name
219
+ );
220
+ })
221
+ ] }),
222
+ o.length === 0 && /* @__PURE__ */ s("p", { className: "text-xs text-foreground-muted text-center py-4", children: "No custom fonts added yet" })
223
+ ] }) });
224
+ }
225
+ export {
226
+ X as FontEditor
227
+ };
@@ -0,0 +1,7 @@
1
+ interface GlobalStylesPanelProps {
2
+ onClose?: () => void;
3
+ onTogglePanel?: () => void;
4
+ }
5
+ export declare function GlobalStylesPanel({ onClose, onTogglePanel, }: GlobalStylesPanelProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=GlobalStylesPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlobalStylesPanel.d.ts","sourceRoot":"","sources":["../../../src/components/editor/GlobalStylesPanel.tsx"],"names":[],"mappings":"AA+CA,UAAU,sBAAsB;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,aAAa,GACd,EAAE,sBAAsB,2CA8DxB"}
@@ -0,0 +1,310 @@
1
+ import { jsxs as t, jsx as e } from "react/jsx-runtime";
2
+ import { useState as v } from "react";
3
+ import { PanelRightClose as H, X as S, ChevronRight as F, Plus as I } from "lucide-react";
4
+ import { useEditor as j } from "../../context/EditorContext.js";
5
+ import { ScrollArea as E } from "../ui/scroll-area.js";
6
+ import { Label as O } from "../ui/label.js";
7
+ import { Input as g } from "../ui/input.js";
8
+ import { Button as L } from "../ui/button.js";
9
+ import { Tabs as _, TabsList as G, TabsTrigger as x, TabsContent as b } from "../ui/tabs.js";
10
+ import { Collapsible as M, CollapsibleTrigger as K, CollapsibleContent as P } from "../ui/collapsible.js";
11
+ import { cn as z } from "../../lib/utils.js";
12
+ import { FontEditor as R } from "./FontEditor.js";
13
+ const w = {
14
+ "font-family": {
15
+ type: "text",
16
+ label: "Font Family",
17
+ placeholder: "Ubuntu, Helvetica, Arial, sans-serif"
18
+ },
19
+ "font-size": { type: "dimension", label: "Font Size", placeholder: "13px" },
20
+ color: { type: "color", label: "Text Color" },
21
+ "line-height": {
22
+ type: "dimension",
23
+ label: "Line Height",
24
+ placeholder: "1.5"
25
+ },
26
+ padding: { type: "padding", label: "Padding", placeholder: "10px 25px" }
27
+ }, V = [
28
+ { value: "mj-text", label: "Text" },
29
+ { value: "mj-button", label: "Button" },
30
+ { value: "mj-image", label: "Image" },
31
+ { value: "mj-section", label: "Section" },
32
+ { value: "mj-column", label: "Column" },
33
+ { value: "mj-divider", label: "Divider" },
34
+ { value: "mj-spacer", label: "Spacer" }
35
+ ];
36
+ function ae({
37
+ onClose: o,
38
+ onTogglePanel: s
39
+ }) {
40
+ const [c, a] = v("all");
41
+ return /* @__PURE__ */ t("div", { className: "flex flex-col h-full", children: [
42
+ /* @__PURE__ */ t("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: [
43
+ /* @__PURE__ */ t("div", { className: "flex items-center gap-2", children: [
44
+ s && /* @__PURE__ */ e(
45
+ L,
46
+ {
47
+ variant: "ghost",
48
+ size: "icon-sm",
49
+ onClick: s,
50
+ className: "h-7 w-7 rounded-md text-foreground-muted hover:text-foreground hover:bg-accent",
51
+ title: "Collapse panel",
52
+ children: /* @__PURE__ */ e(H, { className: "h-4 w-4" })
53
+ }
54
+ ),
55
+ /* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-foreground", children: "Global Styles" })
56
+ ] }),
57
+ o && /* @__PURE__ */ e(
58
+ "button",
59
+ {
60
+ onClick: o,
61
+ className: "text-foreground-muted hover:text-foreground transition-colors",
62
+ children: /* @__PURE__ */ e(S, { className: "h-4 w-4" })
63
+ }
64
+ )
65
+ ] }),
66
+ /* @__PURE__ */ t(
67
+ _,
68
+ {
69
+ value: c,
70
+ onValueChange: a,
71
+ className: "flex-1 flex flex-col min-h-0",
72
+ children: [
73
+ /* @__PURE__ */ t(G, { className: "mx-4 mt-3 w-auto", children: [
74
+ /* @__PURE__ */ e(x, { value: "all", children: "All" }),
75
+ /* @__PURE__ */ e(x, { value: "elements", children: "By Type" }),
76
+ /* @__PURE__ */ e(x, { value: "classes", children: "Classes" }),
77
+ /* @__PURE__ */ e(x, { value: "fonts", children: "Fonts" })
78
+ ] }),
79
+ /* @__PURE__ */ e(b, { value: "all", className: "flex-1 min-h-0", children: /* @__PURE__ */ e(U, {}) }),
80
+ /* @__PURE__ */ e(b, { value: "elements", className: "flex-1 min-h-0", children: /* @__PURE__ */ e(X, {}) }),
81
+ /* @__PURE__ */ e(b, { value: "classes", className: "flex-1 min-h-0", children: /* @__PURE__ */ e(Y, {}) }),
82
+ /* @__PURE__ */ e(b, { value: "fonts", className: "flex-1 min-h-0", children: /* @__PURE__ */ e(R, {}) })
83
+ ]
84
+ }
85
+ )
86
+ ] });
87
+ }
88
+ function U() {
89
+ const { mjmlAttributes: o, updateMjmlAttribute: s } = j(), c = (a, i) => {
90
+ s("all", null, { [a]: i });
91
+ };
92
+ return /* @__PURE__ */ e(E, { className: "flex-1 min-h-0", children: /* @__PURE__ */ t("div", { className: "p-4 space-y-4", children: [
93
+ /* @__PURE__ */ e("p", { className: "text-xs text-foreground-muted", children: "These styles apply to all elements in your email." }),
94
+ Object.entries(w).map(([a, i]) => /* @__PURE__ */ e(
95
+ A,
96
+ {
97
+ attributeKey: a,
98
+ schema: i,
99
+ value: o.all[a] || "",
100
+ onChange: (n) => c(a, n)
101
+ },
102
+ a
103
+ ))
104
+ ] }) });
105
+ }
106
+ function X() {
107
+ const { mjmlAttributes: o, updateMjmlAttribute: s } = j(), [c, a] = v({}), i = (r) => {
108
+ a((d) => ({ ...d, [r]: !d[r] }));
109
+ }, n = (r, d, m) => {
110
+ s("element", r, { [d]: m });
111
+ };
112
+ return /* @__PURE__ */ e(E, { className: "flex-1 min-h-0", children: /* @__PURE__ */ t("div", { className: "p-4 space-y-2", children: [
113
+ /* @__PURE__ */ e("p", { className: "text-xs text-foreground-muted mb-4", children: "Set default styles for specific element types." }),
114
+ V.map(({ value: r, label: d }) => {
115
+ const m = c[r] || !1, N = Object.keys(o.elements[r] || {}).length > 0;
116
+ return /* @__PURE__ */ t(
117
+ M,
118
+ {
119
+ open: m,
120
+ onOpenChange: () => i(r),
121
+ children: [
122
+ /* @__PURE__ */ t(K, { className: "flex items-center gap-2 w-full py-2 px-2 text-sm font-medium text-foreground hover:bg-muted/50 rounded-md transition-colors", children: [
123
+ /* @__PURE__ */ e(
124
+ F,
125
+ {
126
+ className: z(
127
+ "h-4 w-4 transition-transform",
128
+ m && "rotate-90"
129
+ )
130
+ }
131
+ ),
132
+ d,
133
+ N && /* @__PURE__ */ t("span", { className: "ml-auto text-xs text-foreground-muted", children: [
134
+ Object.keys(o.elements[r] || {}).length,
135
+ " ",
136
+ "style(s)"
137
+ ] })
138
+ ] }),
139
+ /* @__PURE__ */ e(P, { children: /* @__PURE__ */ e("div", { className: "pl-6 pr-2 py-2 space-y-4", children: Object.entries(w).map(([u, y]) => /* @__PURE__ */ e(
140
+ A,
141
+ {
142
+ attributeKey: u,
143
+ schema: y,
144
+ value: o.elements[r]?.[u] || "",
145
+ onChange: (C) => n(r, u, C)
146
+ },
147
+ u
148
+ )) }) })
149
+ ]
150
+ },
151
+ r
152
+ );
153
+ })
154
+ ] }) });
155
+ }
156
+ function Y() {
157
+ const {
158
+ mjmlAttributes: o,
159
+ definedClasses: s,
160
+ addClass: c,
161
+ removeClass: a,
162
+ updateMjmlAttribute: i
163
+ } = j(), [n, r] = v(""), [d, m] = v({}), N = (l) => {
164
+ m((h) => ({ ...h, [l]: !h[l] }));
165
+ }, u = () => {
166
+ n.trim() && !s.includes(n.trim()) && (c(n.trim()), r(""), m((l) => ({ ...l, [n.trim()]: !0 })));
167
+ }, y = (l) => {
168
+ l.key === "Enter" && (l.preventDefault(), u());
169
+ }, C = (l, h, f) => {
170
+ i("class", l, { [h]: f });
171
+ };
172
+ return /* @__PURE__ */ e(E, { className: "flex-1 min-h-0", children: /* @__PURE__ */ t("div", { className: "p-4 space-y-4", children: [
173
+ /* @__PURE__ */ e("p", { className: "text-xs text-foreground-muted", children: "Create reusable style classes that can be applied to elements." }),
174
+ /* @__PURE__ */ t("div", { className: "flex gap-2", children: [
175
+ /* @__PURE__ */ e(
176
+ g,
177
+ {
178
+ type: "text",
179
+ placeholder: "New class name",
180
+ value: n,
181
+ onChange: (l) => r(l.target.value),
182
+ onKeyDown: y,
183
+ className: "h-8 text-xs flex-1"
184
+ }
185
+ ),
186
+ /* @__PURE__ */ e(
187
+ L,
188
+ {
189
+ size: "sm",
190
+ onClick: u,
191
+ disabled: !n.trim() || s.includes(n.trim()),
192
+ className: "h-8",
193
+ children: /* @__PURE__ */ e(I, { className: "h-4 w-4" })
194
+ }
195
+ )
196
+ ] }),
197
+ s.length === 0 ? /* @__PURE__ */ e("p", { className: "text-xs text-foreground-muted text-center py-4", children: "No classes defined yet" }) : /* @__PURE__ */ e("div", { className: "space-y-2", children: s.map((l) => {
198
+ const h = d[l] || !1, f = o.classes[l] || {}, T = Object.keys(f).length;
199
+ return /* @__PURE__ */ t(
200
+ M,
201
+ {
202
+ open: h,
203
+ onOpenChange: () => N(l),
204
+ children: [
205
+ /* @__PURE__ */ t("div", { className: "flex items-center gap-1", children: [
206
+ /* @__PURE__ */ t(K, { className: "flex items-center gap-2 flex-1 py-2 px-2 text-sm font-medium text-foreground hover:bg-muted/50 rounded-md transition-colors", children: [
207
+ /* @__PURE__ */ e(
208
+ F,
209
+ {
210
+ className: z(
211
+ "h-4 w-4 transition-transform",
212
+ h && "rotate-90"
213
+ )
214
+ }
215
+ ),
216
+ /* @__PURE__ */ t("span", { className: "font-mono", children: [
217
+ ".",
218
+ l
219
+ ] }),
220
+ T > 0 && /* @__PURE__ */ t("span", { className: "ml-auto text-xs text-foreground-muted", children: [
221
+ T,
222
+ " style(s)"
223
+ ] })
224
+ ] }),
225
+ /* @__PURE__ */ e(
226
+ "button",
227
+ {
228
+ onClick: (p) => {
229
+ p.stopPropagation(), a(l);
230
+ },
231
+ className: "p-1 text-foreground-muted hover:text-destructive transition-colors",
232
+ children: /* @__PURE__ */ e(S, { className: "h-4 w-4" })
233
+ }
234
+ )
235
+ ] }),
236
+ /* @__PURE__ */ e(P, { children: /* @__PURE__ */ e("div", { className: "pl-6 pr-2 py-2 space-y-4", children: Object.entries(w).map(
237
+ ([p, D]) => /* @__PURE__ */ e(
238
+ A,
239
+ {
240
+ attributeKey: p,
241
+ schema: D,
242
+ value: f[p] || "",
243
+ onChange: (B) => C(l, p, B)
244
+ },
245
+ p
246
+ )
247
+ ) }) })
248
+ ]
249
+ },
250
+ l
251
+ );
252
+ }) })
253
+ ] }) });
254
+ }
255
+ function A({
256
+ attributeKey: o,
257
+ schema: s,
258
+ value: c,
259
+ onChange: a
260
+ }) {
261
+ const i = `global-${o}`;
262
+ return s.type === "color" ? /* @__PURE__ */ t("div", { className: "space-y-2", children: [
263
+ /* @__PURE__ */ e(
264
+ O,
265
+ {
266
+ htmlFor: i,
267
+ className: "text-xs font-medium text-foreground-muted",
268
+ children: s.label
269
+ }
270
+ ),
271
+ /* @__PURE__ */ t("div", { className: "flex gap-2", children: [
272
+ /* @__PURE__ */ e(
273
+ g,
274
+ {
275
+ id: i,
276
+ type: "color",
277
+ value: c || "#000000",
278
+ onChange: (n) => a(n.target.value),
279
+ className: "h-8 w-10 p-0.5 cursor-pointer rounded-md border-border-subtle"
280
+ }
281
+ ),
282
+ /* @__PURE__ */ e(
283
+ g,
284
+ {
285
+ type: "text",
286
+ value: c || "",
287
+ onChange: (n) => a(n.target.value),
288
+ placeholder: s.placeholder || "#000000",
289
+ className: "h-8 text-xs flex-1 font-mono border-border-subtle"
290
+ }
291
+ )
292
+ ] })
293
+ ] }) : /* @__PURE__ */ t("div", { className: "space-y-2", children: [
294
+ /* @__PURE__ */ e(O, { htmlFor: i, className: "text-xs font-medium text-foreground-muted", children: s.label }),
295
+ /* @__PURE__ */ e(
296
+ g,
297
+ {
298
+ id: i,
299
+ type: "text",
300
+ value: c || "",
301
+ onChange: (n) => a(n.target.value),
302
+ placeholder: s.placeholder || "",
303
+ className: "h-8 text-xs border-border-subtle"
304
+ }
305
+ )
306
+ ] });
307
+ }
308
+ export {
309
+ ae as GlobalStylesPanel
310
+ };
@@ -0,0 +1,8 @@
1
+ import { PreviewMode } from './EditorCanvas';
2
+ interface InteractivePreviewProps {
3
+ showHeader?: boolean;
4
+ previewMode?: PreviewMode;
5
+ }
6
+ export declare function InteractivePreview({ showHeader, previewMode, }: InteractivePreviewProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=InteractivePreview.d.ts.map