@savvycal/mjml-editor 0.3.0 → 0.5.0

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 (44) hide show
  1. package/README.md +70 -0
  2. package/dist/components/editor/BlockInspector.d.ts.map +1 -1
  3. package/dist/components/editor/BlockInspector.js +174 -164
  4. package/dist/components/editor/EditorCanvas.d.ts +2 -1
  5. package/dist/components/editor/EditorCanvas.d.ts.map +1 -1
  6. package/dist/components/editor/EditorCanvas.js +116 -54
  7. package/dist/components/editor/MjmlEditor.d.ts +23 -1
  8. package/dist/components/editor/MjmlEditor.d.ts.map +1 -1
  9. package/dist/components/editor/MjmlEditor.js +87 -76
  10. package/dist/components/editor/OutlineTree.d.ts.map +1 -1
  11. package/dist/components/editor/OutlineTree.js +108 -99
  12. package/dist/components/editor/SourceEditor.d.ts +6 -1
  13. package/dist/components/editor/SourceEditor.d.ts.map +1 -1
  14. package/dist/components/editor/SourceEditor.js +83 -38
  15. package/dist/components/editor/SourceEditor.test.d.ts +2 -0
  16. package/dist/components/editor/SourceEditor.test.d.ts.map +1 -0
  17. package/dist/components/editor/visual-blocks/ConditionalIndicator.d.ts +6 -0
  18. package/dist/components/editor/visual-blocks/ConditionalIndicator.d.ts.map +1 -0
  19. package/dist/components/editor/visual-blocks/ConditionalIndicator.js +14 -0
  20. package/dist/components/editor/visual-blocks/VisualBlock.d.ts.map +1 -1
  21. package/dist/components/editor/visual-blocks/VisualBlock.js +27 -18
  22. package/dist/components/editor/visual-blocks/VisualColumn.d.ts.map +1 -1
  23. package/dist/components/editor/visual-blocks/VisualColumn.js +35 -30
  24. package/dist/components/editor/visual-blocks/VisualSection.d.ts.map +1 -1
  25. package/dist/components/editor/visual-blocks/VisualSection.js +81 -70
  26. package/dist/components.css +53 -0
  27. package/dist/context/ExtensionsContext.d.ts +13 -0
  28. package/dist/context/ExtensionsContext.d.ts.map +1 -0
  29. package/dist/context/ExtensionsContext.js +25 -0
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/lib/html-utils.d.ts.map +1 -1
  33. package/dist/lib/html-utils.js +49 -19
  34. package/dist/lib/html-utils.test.d.ts +2 -0
  35. package/dist/lib/html-utils.test.d.ts.map +1 -0
  36. package/dist/lib/mjml/renderer.d.ts +7 -4
  37. package/dist/lib/mjml/renderer.d.ts.map +1 -1
  38. package/dist/lib/mjml/renderer.js +63 -41
  39. package/dist/lib/mjml/schema.d.ts +6 -1
  40. package/dist/lib/mjml/schema.d.ts.map +1 -1
  41. package/dist/lib/mjml/schema.js +102 -33
  42. package/dist/types/mjml.d.ts +19 -0
  43. package/dist/types/mjml.d.ts.map +1 -1
  44. package/package.json +10 -1
package/README.md CHANGED
@@ -89,9 +89,11 @@ function App() {
89
89
  |------|------|-------------|
90
90
  | `value` | `string` | MJML markup string (required) |
91
91
  | `onChange` | `(mjml: string) => void` | Called when the document changes (required) |
92
+ | `onSourceApply` | `(mjml: string) => void` | Called when Source tab **Apply** succeeds with valid MJML (optional) |
92
93
  | `className` | `string` | Optional CSS class for the container |
93
94
  | `defaultTheme` | `'light' \| 'dark' \| 'system'` | Theme preference (default: `'system'`) |
94
95
  | `liquidSchema` | `LiquidSchema` | Optional schema for Liquid template autocomplete |
96
+ | `extensions` | `EditorExtensions` | Optional extensions for custom features beyond standard MJML |
95
97
  | `applyThemeToDocument` | `boolean` | Whether to apply theme class to `document.documentElement`. Needed for dropdown/popover theming. Set to `false` if your app manages document-level theme classes. (default: `true`) |
96
98
 
97
99
  ## Liquid Template Support
@@ -129,6 +131,65 @@ function App() {
129
131
 
130
132
  When editing text content, typing `{{` will trigger variable autocomplete and `{%` will trigger tag autocomplete.
131
133
 
134
+ ## Extensions
135
+
136
+ Extensions provide opt-in features beyond standard MJML. All extensions are disabled by default to maintain compatibility with stock MJML.
137
+
138
+ ```tsx
139
+ import { MjmlEditor, type EditorExtensions } from '@savvycal/mjml-editor';
140
+
141
+ function App() {
142
+ const [mjml, setMjml] = useState(initialMjml);
143
+
144
+ return (
145
+ <MjmlEditor
146
+ value={mjml}
147
+ onChange={setMjml}
148
+ extensions={{
149
+ conditionalBlocks: true,
150
+ }}
151
+ />
152
+ );
153
+ }
154
+ ```
155
+
156
+ ### Available Extensions
157
+
158
+ #### `conditionalBlocks`
159
+
160
+ Enables the `sc-if` attribute for server-side conditional rendering using Liquid expressions.
161
+
162
+ When enabled:
163
+ - A "Condition (Liquid)" field appears in the Advanced section of the inspector for all block types
164
+ - Blocks with conditions display an "if" badge indicator in both the canvas and outline tree
165
+ - The Advanced section auto-expands when a block has a condition
166
+
167
+ **How it works:**
168
+ - The `sc-if` attribute is preserved in the MJML output for server-side processing
169
+ - The attribute is stripped from preview rendering to avoid MJML validation warnings
170
+ - Your server processes the Liquid condition and conditionally renders the block
171
+
172
+ **Example MJML output:**
173
+
174
+ ```xml
175
+ <mj-section sc-if="event.is_recurring">
176
+ <mj-column>
177
+ <mj-text>This section only appears for recurring events.</mj-text>
178
+ </mj-column>
179
+ </mj-section>
180
+ ```
181
+
182
+ **Server-side processing example (Ruby/Liquid):**
183
+
184
+ ```ruby
185
+ # Before sending, wrap sc-if blocks with Liquid conditionals
186
+ mjml = mjml.gsub(/<(mj-\w+)([^>]*)\ssc-if="([^"]+)"([^>]*)>/) do
187
+ tag, before, condition, after = $1, $2, $3, $4
188
+ "{% if #{condition} %}<#{tag}#{before}#{after}>"
189
+ end
190
+ # Don't forget to add closing {% endif %} tags as well
191
+ ```
192
+
132
193
  ## Exported Types
133
194
 
134
195
  The library exports TypeScript types for integration:
@@ -138,11 +199,20 @@ import type {
138
199
  MjmlNode, // MJML document node structure
139
200
  MjmlTagName, // Union of supported MJML tag names
140
201
  ContentBlockType, // Union of content block types
202
+ EditorExtensions, // Extensions configuration
141
203
  LiquidSchema, // Schema for Liquid autocomplete
142
204
  LiquidSchemaItem, // Individual variable/tag definition
143
205
  } from '@savvycal/mjml-editor';
144
206
  ```
145
207
 
208
+ ### EditorExtensions
209
+
210
+ ```typescript
211
+ interface EditorExtensions {
212
+ conditionalBlocks?: boolean; // Enable sc-if attribute for conditional rendering
213
+ }
214
+ ```
215
+
146
216
  ### LiquidSchema
147
217
 
148
218
  ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"BlockInspector.d.ts","sourceRoot":"","sources":["../../../src/components/editor/BlockInspector.tsx"],"names":[],"mappings":"AA8HA,UAAU,mBAAmB;IAC3B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,EAAE,aAAa,EAAE,EAAE,mBAAmB,2CAuHpE"}
1
+ {"version":3,"file":"BlockInspector.d.ts","sourceRoot":"","sources":["../../../src/components/editor/BlockInspector.tsx"],"names":[],"mappings":"AA+HA,UAAU,mBAAmB;IAC3B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,EAAE,aAAa,EAAE,EAAE,mBAAmB,2CAiIpE"}
@@ -1,18 +1,19 @@
1
- import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
- import { useState as F } from "react";
3
- import { PanelRightClose as v, X as O, ChevronRight as _ } from "lucide-react";
4
- import { useEditor as N } from "../../context/EditorContext.js";
5
- import { ScrollArea as G } from "../ui/scroll-area.js";
1
+ import { jsxs as n, jsx as e } from "react/jsx-runtime";
2
+ import { useState as O, useEffect as _ } from "react";
3
+ import { PanelRightClose as y, X as E, ChevronRight as G } from "lucide-react";
4
+ import { useEditor as v } from "../../context/EditorContext.js";
5
+ import { useExtensions as I } from "../../context/ExtensionsContext.js";
6
+ import { ScrollArea as R } from "../ui/scroll-area.js";
6
7
  import { Button as C } from "../ui/button.js";
7
8
  import { Label as x } from "../ui/label.js";
8
- import { Input as b } from "../ui/input.js";
9
- import { Badge as I } from "../ui/badge.js";
10
- import { Collapsible as R, CollapsibleTrigger as L, CollapsibleContent as V } from "../ui/collapsible.js";
11
- import { Select as y, SelectTrigger as j, SelectValue as w, SelectContent as S, SelectItem as A } from "../ui/select.js";
12
- import { getSchemaForTag as z } from "../../lib/mjml/schema.js";
13
- import { parseClassNames as E, removeClassFromNode as B, addClassToNode as K } from "../../lib/mjml/attributes.js";
14
- import { cn as U } from "../../lib/utils.js";
15
- const P = {
9
+ import { Input as f } from "../ui/input.js";
10
+ import { Badge as L } from "../ui/badge.js";
11
+ import { Collapsible as V, CollapsibleTrigger as z, CollapsibleContent as B } from "../ui/collapsible.js";
12
+ import { Select as j, SelectTrigger as S, SelectValue as w, SelectContent as A, SelectItem as F } from "../ui/select.js";
13
+ import { filterSchemaByExtensions as K, getSchemaForTag as U } from "../../lib/mjml/schema.js";
14
+ import { parseClassNames as P, removeClassFromNode as T, addClassToNode as $ } from "../../lib/mjml/attributes.js";
15
+ import { cn as D } from "../../lib/utils.js";
16
+ const X = {
16
17
  primary: "Primary",
17
18
  background: "Background",
18
19
  typography: "Typography",
@@ -22,7 +23,7 @@ const P = {
22
23
  spacing: "Spacing",
23
24
  link: "Link",
24
25
  advanced: "Advanced"
25
- }, T = [
26
+ }, k = [
26
27
  "primary",
27
28
  "background",
28
29
  "typography",
@@ -33,342 +34,351 @@ const P = {
33
34
  "link",
34
35
  "advanced"
35
36
  ];
36
- function $({ node: n }) {
37
- const { definedClasses: r, updateAttributes: i } = N(), d = E(n.attributes["mj-class"]);
38
- if (r.length === 0)
37
+ function q({ node: i }) {
38
+ const { definedClasses: t, updateAttributes: c } = v(), d = P(i.attributes["mj-class"]);
39
+ if (t.length === 0)
39
40
  return null;
40
- const u = r.filter(
41
- (t) => !d.includes(t)
42
- ), l = (t) => {
43
- if (!n._id || !t) return;
44
- const o = K(n, t);
45
- i(n._id, { "mj-class": o["mj-class"] || "" });
46
- }, c = (t) => {
47
- if (!n._id) return;
48
- const o = B(n, t);
49
- i(n._id, {
50
- "mj-class": o["mj-class"] || ""
41
+ const u = t.filter(
42
+ (r) => !d.includes(r)
43
+ ), a = (r) => {
44
+ if (!i._id || !r) return;
45
+ const l = $(i, r);
46
+ c(i._id, { "mj-class": l["mj-class"] || "" });
47
+ }, m = (r) => {
48
+ if (!i._id) return;
49
+ const l = T(i, r);
50
+ c(i._id, {
51
+ "mj-class": l["mj-class"] || ""
51
52
  });
52
53
  };
53
- return /* @__PURE__ */ a("div", { className: "space-y-2 pb-4 mb-4 border-b border-border", children: [
54
+ return /* @__PURE__ */ n("div", { className: "space-y-2 pb-4 mb-4 border-b border-border", children: [
54
55
  /* @__PURE__ */ e(x, { className: "text-xs font-medium text-foreground-muted", children: "Classes" }),
55
- d.length > 0 && /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1", children: d.map((t) => /* @__PURE__ */ a(
56
- I,
56
+ d.length > 0 && /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1", children: d.map((r) => /* @__PURE__ */ n(
57
+ L,
57
58
  {
58
59
  variant: "secondary",
59
60
  className: "text-xs gap-1 pr-1",
60
61
  children: [
61
- t,
62
+ r,
62
63
  /* @__PURE__ */ e(
63
64
  "button",
64
65
  {
65
66
  type: "button",
66
- onClick: () => c(t),
67
+ onClick: () => m(r),
67
68
  className: "ml-1 hover:text-destructive transition-colors",
68
- children: /* @__PURE__ */ e(O, { className: "h-3 w-3" })
69
+ children: /* @__PURE__ */ e(E, { className: "h-3 w-3" })
69
70
  }
70
71
  )
71
72
  ]
72
73
  },
73
- t
74
+ r
74
75
  )) }),
75
- u.length > 0 && /* @__PURE__ */ a(y, { onValueChange: l, value: "", children: [
76
- /* @__PURE__ */ e(j, { className: "h-8 text-xs border-border-subtle", children: /* @__PURE__ */ e(w, { placeholder: "Add class..." }) }),
77
- /* @__PURE__ */ e(S, { children: u.map((t) => /* @__PURE__ */ e(A, { value: t, className: "text-xs", children: t }, t)) })
76
+ u.length > 0 && /* @__PURE__ */ n(j, { onValueChange: a, value: "", children: [
77
+ /* @__PURE__ */ e(S, { className: "h-8 text-xs border-border-subtle", children: /* @__PURE__ */ e(w, { placeholder: "Add class..." }) }),
78
+ /* @__PURE__ */ e(A, { children: u.map((r) => /* @__PURE__ */ e(F, { value: r, className: "text-xs", children: r }, r)) })
78
79
  ] })
79
80
  ] });
80
81
  }
81
- function le({ onTogglePanel: n }) {
82
- const { selectedBlock: r, updateAttributes: i, getInheritedValue: d, definedClasses: u } = N();
83
- if (!r)
84
- return /* @__PURE__ */ a("div", { className: "flex flex-col h-full", children: [
85
- /* @__PURE__ */ e("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: /* @__PURE__ */ a("div", { className: "flex items-center gap-2", children: [
86
- n && /* @__PURE__ */ e(
82
+ function de({ onTogglePanel: i }) {
83
+ const { selectedBlock: t, updateAttributes: c, getInheritedValue: d, definedClasses: u } = v(), a = I();
84
+ if (!t)
85
+ return /* @__PURE__ */ n("div", { className: "flex flex-col h-full", children: [
86
+ /* @__PURE__ */ e("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: /* @__PURE__ */ n("div", { className: "flex items-center gap-2", children: [
87
+ i && /* @__PURE__ */ e(
87
88
  C,
88
89
  {
89
90
  variant: "ghost",
90
91
  size: "icon-sm",
91
- onClick: n,
92
+ onClick: i,
92
93
  className: "h-7 w-7 rounded-md text-foreground-muted hover:text-foreground hover:bg-accent",
93
94
  title: "Collapse panel",
94
- children: /* @__PURE__ */ e(v, { className: "h-4 w-4" })
95
+ children: /* @__PURE__ */ e(y, { className: "h-4 w-4" })
95
96
  }
96
97
  ),
97
98
  /* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-foreground", children: "Inspector" })
98
99
  ] }) }),
99
- /* @__PURE__ */ e("div", { className: "flex-1 flex items-center justify-center p-6", children: /* @__PURE__ */ a("p", { className: "text-sm text-foreground-muted text-center leading-relaxed", children: [
100
+ /* @__PURE__ */ e("div", { className: "flex-1 flex items-center justify-center p-6", children: /* @__PURE__ */ n("p", { className: "text-sm text-foreground-muted text-center leading-relaxed", children: [
100
101
  "Select a block to",
101
102
  /* @__PURE__ */ e("br", {}),
102
103
  "edit its properties"
103
104
  ] }) })
104
105
  ] });
105
- const l = z(r.tagName), c = r.tagName.replace("mj-", "").charAt(0).toUpperCase() + r.tagName.replace("mj-", "").slice(1), t = (s, p) => {
106
- r._id && i(r._id, { [s]: p });
107
- }, o = l ? Object.entries(l).reduce(
106
+ const m = K(
107
+ U(t.tagName),
108
+ a
109
+ ), r = t.tagName.replace("mj-", "").charAt(0).toUpperCase() + t.tagName.replace("mj-", "").slice(1), l = (s, p) => {
110
+ t._id && c(t._id, { [s]: p });
111
+ }, o = m ? Object.entries(m).reduce(
108
112
  (s, [p, h]) => {
109
- const f = h.group || "primary";
110
- return s[f] || (s[f] = []), s[f].push({ key: p, schema: h }), s;
113
+ const g = h.group || "primary";
114
+ return s[g] || (s[g] = []), s[g].push({ key: p, schema: h }), s;
111
115
  },
112
116
  {}
113
- ) : {}, m = Object.keys(o).some(
117
+ ) : {}, b = Object.keys(o).some(
114
118
  (s) => s !== "primary"
115
119
  );
116
- return /* @__PURE__ */ a("div", { className: "flex flex-col h-full", children: [
117
- /* @__PURE__ */ e("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: /* @__PURE__ */ a("div", { className: "flex items-center gap-2", children: [
118
- n && /* @__PURE__ */ e(
120
+ return /* @__PURE__ */ n("div", { className: "flex flex-col h-full", children: [
121
+ /* @__PURE__ */ e("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: /* @__PURE__ */ n("div", { className: "flex items-center gap-2", children: [
122
+ i && /* @__PURE__ */ e(
119
123
  C,
120
124
  {
121
125
  variant: "ghost",
122
126
  size: "icon-sm",
123
- onClick: n,
127
+ onClick: i,
124
128
  className: "h-7 w-7 rounded-md text-foreground-muted hover:text-foreground hover:bg-accent",
125
129
  title: "Collapse panel",
126
- children: /* @__PURE__ */ e(v, { className: "h-4 w-4" })
130
+ children: /* @__PURE__ */ e(y, { className: "h-4 w-4" })
127
131
  }
128
132
  ),
129
- /* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-foreground", children: c })
133
+ /* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-foreground", children: r })
130
134
  ] }) }),
131
- /* @__PURE__ */ e(G, { className: "flex-1 min-h-0", children: /* @__PURE__ */ a("div", { className: "p-4", children: [
132
- u.length > 0 && /* @__PURE__ */ e($, { node: r }),
133
- l ? m ? /* @__PURE__ */ e(
134
- D,
135
+ /* @__PURE__ */ e(R, { className: "flex-1 min-h-0", children: /* @__PURE__ */ n("div", { className: "p-4", children: [
136
+ u.length > 0 && /* @__PURE__ */ e(q, { node: t }),
137
+ m ? b ? /* @__PURE__ */ e(
138
+ H,
135
139
  {
136
140
  groupedAttributes: o,
137
- selectedBlock: r,
138
- handleAttributeChange: t
141
+ selectedBlock: t,
142
+ handleAttributeChange: l,
143
+ defaultOpenGroups: a.conditionalBlocks && t.attributes["sc-if"] ? { advanced: !0 } : {}
139
144
  }
140
- ) : /* @__PURE__ */ e("div", { className: "space-y-5", children: Object.entries(l).map(([s, p]) => /* @__PURE__ */ e(
141
- g,
145
+ ) : /* @__PURE__ */ e("div", { className: "space-y-5", children: Object.entries(m).map(([s, p]) => /* @__PURE__ */ e(
146
+ N,
142
147
  {
143
148
  attributeKey: s,
144
149
  schema: p,
145
- value: r.attributes[s] || "",
146
- onChange: (h) => t(s, h),
147
- inheritedValue: d(r, s)
150
+ value: t.attributes[s] || "",
151
+ onChange: (h) => l(s, h),
152
+ inheritedValue: d(t, s)
148
153
  },
149
154
  s
150
155
  )) }) : /* @__PURE__ */ e("p", { className: "text-sm text-foreground-muted py-4 text-center", children: "No editable properties for this block type." })
151
156
  ] }) })
152
157
  ] });
153
158
  }
154
- function D({
155
- groupedAttributes: n,
156
- selectedBlock: r,
157
- handleAttributeChange: i
159
+ function H({
160
+ groupedAttributes: i,
161
+ selectedBlock: t,
162
+ handleAttributeChange: c,
163
+ defaultOpenGroups: d = {}
158
164
  }) {
159
- const [d, u] = F({}), { getInheritedValue: l } = N(), c = (t) => {
160
- u((o) => ({ ...o, [t]: !o[t] }));
165
+ const [u, a] = O(d), { getInheritedValue: m } = v();
166
+ _(() => {
167
+ a(d);
168
+ }, [t._id]);
169
+ const r = (l) => {
170
+ a((o) => ({ ...o, [l]: !o[l] }));
161
171
  };
162
- return /* @__PURE__ */ e("div", { className: "space-y-4", children: T.map((t) => {
163
- const o = n[t];
172
+ return /* @__PURE__ */ e("div", { className: "space-y-4", children: k.map((l) => {
173
+ const o = i[l];
164
174
  if (!o || o.length === 0) return null;
165
- if (t === "primary")
175
+ if (l === "primary")
166
176
  return /* @__PURE__ */ e("div", { className: "space-y-5", children: o.map(({ key: s, schema: p }) => /* @__PURE__ */ e(
167
- g,
177
+ N,
168
178
  {
169
179
  attributeKey: s,
170
180
  schema: p,
171
- value: r.attributes[s] || "",
172
- onChange: (h) => i(s, h),
173
- inheritedValue: l(r, s)
181
+ value: t.attributes[s] || "",
182
+ onChange: (h) => c(s, h),
183
+ inheritedValue: m(t, s)
174
184
  },
175
185
  s
176
- )) }, t);
177
- const m = d[t] || !1;
178
- return /* @__PURE__ */ a(
179
- R,
186
+ )) }, l);
187
+ const b = u[l] || !1;
188
+ return /* @__PURE__ */ n(
189
+ V,
180
190
  {
181
- open: m,
182
- onOpenChange: () => c(t),
191
+ open: b,
192
+ onOpenChange: () => r(l),
183
193
  children: [
184
- /* @__PURE__ */ a(L, { className: "flex items-center gap-1 w-full py-2 text-xs font-medium text-foreground-muted hover:text-foreground transition-colors", children: [
194
+ /* @__PURE__ */ n(z, { className: "flex items-center gap-1 w-full py-2 text-xs font-medium text-foreground-muted hover:text-foreground transition-colors", children: [
185
195
  /* @__PURE__ */ e(
186
- _,
196
+ G,
187
197
  {
188
- className: U(
198
+ className: D(
189
199
  "h-3.5 w-3.5 transition-transform",
190
- m && "rotate-90"
200
+ b && "rotate-90"
191
201
  )
192
202
  }
193
203
  ),
194
- P[t]
204
+ X[l]
195
205
  ] }),
196
- /* @__PURE__ */ e(V, { children: /* @__PURE__ */ e("div", { className: "space-y-5 pt-2 pb-1", children: o.map(({ key: s, schema: p }) => /* @__PURE__ */ e(
197
- g,
206
+ /* @__PURE__ */ e(B, { children: /* @__PURE__ */ e("div", { className: "space-y-5 pt-2 pb-1", children: o.map(({ key: s, schema: p }) => /* @__PURE__ */ e(
207
+ N,
198
208
  {
199
209
  attributeKey: s,
200
210
  schema: p,
201
- value: r.attributes[s] || "",
202
- onChange: (h) => i(s, h),
203
- inheritedValue: l(r, s)
211
+ value: t.attributes[s] || "",
212
+ onChange: (h) => c(s, h),
213
+ inheritedValue: m(t, s)
204
214
  },
205
215
  s
206
216
  )) }) })
207
217
  ]
208
218
  },
209
- t
219
+ l
210
220
  );
211
221
  }) });
212
222
  }
213
- function g({
214
- attributeKey: n,
215
- schema: r,
216
- value: i,
223
+ function N({
224
+ attributeKey: i,
225
+ schema: t,
226
+ value: c,
217
227
  onChange: d,
218
228
  inheritedValue: u
219
229
  }) {
220
- const l = `attr-${n}`, c = u || r.placeholder || r.default || "";
221
- switch (r.type) {
230
+ const a = `attr-${i}`, m = u || t.placeholder || t.default || "";
231
+ switch (t.type) {
222
232
  case "select": {
223
- const t = i || u || r.default || r.options?.[0]?.value || "default", o = (m) => {
224
- d(m === "false" ? "" : m);
233
+ const r = c || u || t.default || t.options?.[0]?.value || "default", l = (o) => {
234
+ d(o === "false" ? "" : o);
225
235
  };
226
- return /* @__PURE__ */ a("div", { className: "space-y-2", children: [
236
+ return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
227
237
  /* @__PURE__ */ e(
228
238
  x,
229
239
  {
230
- htmlFor: l,
240
+ htmlFor: a,
231
241
  className: "text-xs font-medium text-foreground-muted",
232
- children: r.label
242
+ children: t.label
233
243
  }
234
244
  ),
235
- /* @__PURE__ */ a(y, { value: t, onValueChange: o, children: [
236
- /* @__PURE__ */ e(j, { id: l, className: "h-8 text-xs border-border-subtle", children: /* @__PURE__ */ e(
245
+ /* @__PURE__ */ n(j, { value: r, onValueChange: l, children: [
246
+ /* @__PURE__ */ e(S, { id: a, className: "h-8 text-xs border-border-subtle", children: /* @__PURE__ */ e(
237
247
  w,
238
248
  {
239
- placeholder: `Select ${r.label.toLowerCase()}`
249
+ placeholder: `Select ${t.label.toLowerCase()}`
240
250
  }
241
251
  ) }),
242
- /* @__PURE__ */ e(S, { children: r.options?.map((m) => /* @__PURE__ */ e(
243
- A,
252
+ /* @__PURE__ */ e(A, { children: t.options?.map((o) => /* @__PURE__ */ e(
253
+ F,
244
254
  {
245
- value: m.value,
255
+ value: o.value,
246
256
  className: "text-xs",
247
- children: m.label
257
+ children: o.label
248
258
  },
249
- m.value
259
+ o.value
250
260
  )) })
251
261
  ] })
252
262
  ] });
253
263
  }
254
264
  case "color":
255
- return /* @__PURE__ */ a("div", { className: "space-y-2", children: [
265
+ return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
256
266
  /* @__PURE__ */ e(
257
267
  x,
258
268
  {
259
- htmlFor: l,
269
+ htmlFor: a,
260
270
  className: "text-xs font-medium text-foreground-muted",
261
- children: r.label
271
+ children: t.label
262
272
  }
263
273
  ),
264
- /* @__PURE__ */ a("div", { className: "flex gap-2", children: [
274
+ /* @__PURE__ */ n("div", { className: "flex gap-2", children: [
265
275
  /* @__PURE__ */ e(
266
- b,
276
+ f,
267
277
  {
268
- id: l,
278
+ id: a,
269
279
  type: "color",
270
- value: i || u || r.default || "#000000",
271
- onChange: (t) => d(t.target.value),
280
+ value: c || u || t.default || "#000000",
281
+ onChange: (r) => d(r.target.value),
272
282
  className: "h-8 w-10 p-0.5 cursor-pointer rounded-md border-border-subtle"
273
283
  }
274
284
  ),
275
285
  /* @__PURE__ */ e(
276
- b,
286
+ f,
277
287
  {
278
288
  type: "text",
279
- value: i || "",
280
- onChange: (t) => d(t.target.value),
281
- placeholder: c || "#000000",
289
+ value: c || "",
290
+ onChange: (r) => d(r.target.value),
291
+ placeholder: m || "#000000",
282
292
  className: "h-8 text-xs flex-1 font-mono border-border-subtle"
283
293
  }
284
294
  )
285
295
  ] })
286
296
  ] });
287
297
  case "padding":
288
- return /* @__PURE__ */ a("div", { className: "space-y-2", children: [
298
+ return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
289
299
  /* @__PURE__ */ e(
290
300
  x,
291
301
  {
292
- htmlFor: l,
302
+ htmlFor: a,
293
303
  className: "text-xs font-medium text-foreground-muted",
294
- children: r.label
304
+ children: t.label
295
305
  }
296
306
  ),
297
307
  /* @__PURE__ */ e(
298
- b,
308
+ f,
299
309
  {
300
- id: l,
310
+ id: a,
301
311
  type: "text",
302
- value: i || "",
303
- onChange: (t) => d(t.target.value),
304
- placeholder: c || "10px 25px",
312
+ value: c || "",
313
+ onChange: (r) => d(r.target.value),
314
+ placeholder: m || "10px 25px",
305
315
  className: "h-8 text-xs border-border-subtle"
306
316
  }
307
317
  ),
308
318
  /* @__PURE__ */ e("p", { className: "text-[10px] text-foreground-subtle", children: "Format: top right bottom left (e.g., 10px 20px)" })
309
319
  ] });
310
320
  case "dimension":
311
- return /* @__PURE__ */ a("div", { className: "space-y-2", children: [
321
+ return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
312
322
  /* @__PURE__ */ e(
313
323
  x,
314
324
  {
315
- htmlFor: l,
325
+ htmlFor: a,
316
326
  className: "text-xs font-medium text-foreground-muted",
317
- children: r.label
327
+ children: t.label
318
328
  }
319
329
  ),
320
330
  /* @__PURE__ */ e(
321
- b,
331
+ f,
322
332
  {
323
- id: l,
333
+ id: a,
324
334
  type: "text",
325
- value: i || "",
326
- onChange: (t) => d(t.target.value),
327
- placeholder: c,
335
+ value: c || "",
336
+ onChange: (r) => d(r.target.value),
337
+ placeholder: m,
328
338
  className: "h-8 text-xs border-border-subtle"
329
339
  }
330
340
  )
331
341
  ] });
332
342
  case "url":
333
- return /* @__PURE__ */ a("div", { className: "space-y-2", children: [
343
+ return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
334
344
  /* @__PURE__ */ e(
335
345
  x,
336
346
  {
337
- htmlFor: l,
347
+ htmlFor: a,
338
348
  className: "text-xs font-medium text-foreground-muted",
339
- children: r.label
349
+ children: t.label
340
350
  }
341
351
  ),
342
352
  /* @__PURE__ */ e(
343
- b,
353
+ f,
344
354
  {
345
- id: l,
355
+ id: a,
346
356
  type: "url",
347
- value: i || "",
348
- onChange: (t) => d(t.target.value),
349
- placeholder: c || "https://...",
357
+ value: c || "",
358
+ onChange: (r) => d(r.target.value),
359
+ placeholder: m || "https://...",
350
360
  className: "h-8 text-xs border-border-subtle"
351
361
  }
352
362
  )
353
363
  ] });
354
364
  default:
355
- return /* @__PURE__ */ a("div", { className: "space-y-2", children: [
365
+ return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
356
366
  /* @__PURE__ */ e(
357
367
  x,
358
368
  {
359
- htmlFor: l,
369
+ htmlFor: a,
360
370
  className: "text-xs font-medium text-foreground-muted",
361
- children: r.label
371
+ children: t.label
362
372
  }
363
373
  ),
364
374
  /* @__PURE__ */ e(
365
- b,
375
+ f,
366
376
  {
367
- id: l,
377
+ id: a,
368
378
  type: "text",
369
- value: i || "",
370
- onChange: (t) => d(t.target.value),
371
- placeholder: c,
379
+ value: c || "",
380
+ onChange: (r) => d(r.target.value),
381
+ placeholder: m,
372
382
  className: "h-8 text-xs border-border-subtle"
373
383
  }
374
384
  )
@@ -376,5 +386,5 @@ function g({
376
386
  }
377
387
  }
378
388
  export {
379
- le as BlockInspector
389
+ de as BlockInspector
380
390
  };