@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.
- package/README.md +70 -0
- package/dist/components/editor/BlockInspector.d.ts.map +1 -1
- package/dist/components/editor/BlockInspector.js +174 -164
- package/dist/components/editor/EditorCanvas.d.ts +2 -1
- package/dist/components/editor/EditorCanvas.d.ts.map +1 -1
- package/dist/components/editor/EditorCanvas.js +116 -54
- package/dist/components/editor/MjmlEditor.d.ts +23 -1
- package/dist/components/editor/MjmlEditor.d.ts.map +1 -1
- package/dist/components/editor/MjmlEditor.js +87 -76
- package/dist/components/editor/OutlineTree.d.ts.map +1 -1
- package/dist/components/editor/OutlineTree.js +108 -99
- package/dist/components/editor/SourceEditor.d.ts +6 -1
- package/dist/components/editor/SourceEditor.d.ts.map +1 -1
- package/dist/components/editor/SourceEditor.js +83 -38
- package/dist/components/editor/SourceEditor.test.d.ts +2 -0
- package/dist/components/editor/SourceEditor.test.d.ts.map +1 -0
- package/dist/components/editor/visual-blocks/ConditionalIndicator.d.ts +6 -0
- package/dist/components/editor/visual-blocks/ConditionalIndicator.d.ts.map +1 -0
- package/dist/components/editor/visual-blocks/ConditionalIndicator.js +14 -0
- package/dist/components/editor/visual-blocks/VisualBlock.d.ts.map +1 -1
- package/dist/components/editor/visual-blocks/VisualBlock.js +27 -18
- package/dist/components/editor/visual-blocks/VisualColumn.d.ts.map +1 -1
- package/dist/components/editor/visual-blocks/VisualColumn.js +35 -30
- package/dist/components/editor/visual-blocks/VisualSection.d.ts.map +1 -1
- package/dist/components/editor/visual-blocks/VisualSection.js +81 -70
- package/dist/components.css +53 -0
- package/dist/context/ExtensionsContext.d.ts +13 -0
- package/dist/context/ExtensionsContext.d.ts.map +1 -0
- package/dist/context/ExtensionsContext.js +25 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/html-utils.d.ts.map +1 -1
- package/dist/lib/html-utils.js +49 -19
- package/dist/lib/html-utils.test.d.ts +2 -0
- package/dist/lib/html-utils.test.d.ts.map +1 -0
- package/dist/lib/mjml/renderer.d.ts +7 -4
- package/dist/lib/mjml/renderer.d.ts.map +1 -1
- package/dist/lib/mjml/renderer.js +63 -41
- package/dist/lib/mjml/schema.d.ts +6 -1
- package/dist/lib/mjml/schema.d.ts.map +1 -1
- package/dist/lib/mjml/schema.js +102 -33
- package/dist/types/mjml.d.ts +19 -0
- package/dist/types/mjml.d.ts.map +1 -1
- 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":"
|
|
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
|
|
2
|
-
import { useState as
|
|
3
|
-
import { PanelRightClose as
|
|
4
|
-
import { useEditor as
|
|
5
|
-
import {
|
|
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
|
|
9
|
-
import { Badge as
|
|
10
|
-
import { Collapsible as
|
|
11
|
-
import { Select as
|
|
12
|
-
import { getSchemaForTag as
|
|
13
|
-
import { parseClassNames as
|
|
14
|
-
import { cn as
|
|
15
|
-
const
|
|
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
|
-
},
|
|
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
|
|
37
|
-
const { definedClasses:
|
|
38
|
-
if (
|
|
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 =
|
|
41
|
-
(
|
|
42
|
-
),
|
|
43
|
-
if (!
|
|
44
|
-
const
|
|
45
|
-
i
|
|
46
|
-
},
|
|
47
|
-
if (!
|
|
48
|
-
const
|
|
49
|
-
i
|
|
50
|
-
"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__ */
|
|
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((
|
|
56
|
-
|
|
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
|
-
|
|
62
|
+
r,
|
|
62
63
|
/* @__PURE__ */ e(
|
|
63
64
|
"button",
|
|
64
65
|
{
|
|
65
66
|
type: "button",
|
|
66
|
-
onClick: () =>
|
|
67
|
+
onClick: () => m(r),
|
|
67
68
|
className: "ml-1 hover:text-destructive transition-colors",
|
|
68
|
-
children: /* @__PURE__ */ e(
|
|
69
|
+
children: /* @__PURE__ */ e(E, { className: "h-3 w-3" })
|
|
69
70
|
}
|
|
70
71
|
)
|
|
71
72
|
]
|
|
72
73
|
},
|
|
73
|
-
|
|
74
|
+
r
|
|
74
75
|
)) }),
|
|
75
|
-
u.length > 0 && /* @__PURE__ */
|
|
76
|
-
/* @__PURE__ */ e(
|
|
77
|
-
/* @__PURE__ */ e(
|
|
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
|
|
82
|
-
const { selectedBlock:
|
|
83
|
-
if (!
|
|
84
|
-
return /* @__PURE__ */
|
|
85
|
-
/* @__PURE__ */ e("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: /* @__PURE__ */
|
|
86
|
-
|
|
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:
|
|
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(
|
|
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__ */
|
|
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
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
110
|
-
return 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
|
-
) : {},
|
|
117
|
+
) : {}, b = Object.keys(o).some(
|
|
114
118
|
(s) => s !== "primary"
|
|
115
119
|
);
|
|
116
|
-
return /* @__PURE__ */
|
|
117
|
-
/* @__PURE__ */ e("div", { className: "h-11 px-4 flex items-center justify-between border-b border-border bg-inspector-header", children: /* @__PURE__ */
|
|
118
|
-
|
|
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:
|
|
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(
|
|
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:
|
|
133
|
+
/* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-foreground", children: r })
|
|
130
134
|
] }) }),
|
|
131
|
-
/* @__PURE__ */ e(
|
|
132
|
-
u.length > 0 && /* @__PURE__ */ e(
|
|
133
|
-
|
|
134
|
-
|
|
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:
|
|
138
|
-
handleAttributeChange:
|
|
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(
|
|
141
|
-
|
|
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:
|
|
146
|
-
onChange: (h) =>
|
|
147
|
-
inheritedValue: d(
|
|
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
|
|
155
|
-
groupedAttributes:
|
|
156
|
-
selectedBlock:
|
|
157
|
-
handleAttributeChange:
|
|
159
|
+
function H({
|
|
160
|
+
groupedAttributes: i,
|
|
161
|
+
selectedBlock: t,
|
|
162
|
+
handleAttributeChange: c,
|
|
163
|
+
defaultOpenGroups: d = {}
|
|
158
164
|
}) {
|
|
159
|
-
const [
|
|
160
|
-
|
|
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:
|
|
163
|
-
const o =
|
|
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 (
|
|
175
|
+
if (l === "primary")
|
|
166
176
|
return /* @__PURE__ */ e("div", { className: "space-y-5", children: o.map(({ key: s, schema: p }) => /* @__PURE__ */ e(
|
|
167
|
-
|
|
177
|
+
N,
|
|
168
178
|
{
|
|
169
179
|
attributeKey: s,
|
|
170
180
|
schema: p,
|
|
171
|
-
value:
|
|
172
|
-
onChange: (h) =>
|
|
173
|
-
inheritedValue:
|
|
181
|
+
value: t.attributes[s] || "",
|
|
182
|
+
onChange: (h) => c(s, h),
|
|
183
|
+
inheritedValue: m(t, s)
|
|
174
184
|
},
|
|
175
185
|
s
|
|
176
|
-
)) },
|
|
177
|
-
const
|
|
178
|
-
return /* @__PURE__ */
|
|
179
|
-
|
|
186
|
+
)) }, l);
|
|
187
|
+
const b = u[l] || !1;
|
|
188
|
+
return /* @__PURE__ */ n(
|
|
189
|
+
V,
|
|
180
190
|
{
|
|
181
|
-
open:
|
|
182
|
-
onOpenChange: () =>
|
|
191
|
+
open: b,
|
|
192
|
+
onOpenChange: () => r(l),
|
|
183
193
|
children: [
|
|
184
|
-
/* @__PURE__ */
|
|
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:
|
|
198
|
+
className: D(
|
|
189
199
|
"h-3.5 w-3.5 transition-transform",
|
|
190
|
-
|
|
200
|
+
b && "rotate-90"
|
|
191
201
|
)
|
|
192
202
|
}
|
|
193
203
|
),
|
|
194
|
-
|
|
204
|
+
X[l]
|
|
195
205
|
] }),
|
|
196
|
-
/* @__PURE__ */ e(
|
|
197
|
-
|
|
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:
|
|
202
|
-
onChange: (h) =>
|
|
203
|
-
inheritedValue:
|
|
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
|
-
|
|
219
|
+
l
|
|
210
220
|
);
|
|
211
221
|
}) });
|
|
212
222
|
}
|
|
213
|
-
function
|
|
214
|
-
attributeKey:
|
|
215
|
-
schema:
|
|
216
|
-
value:
|
|
223
|
+
function N({
|
|
224
|
+
attributeKey: i,
|
|
225
|
+
schema: t,
|
|
226
|
+
value: c,
|
|
217
227
|
onChange: d,
|
|
218
228
|
inheritedValue: u
|
|
219
229
|
}) {
|
|
220
|
-
const
|
|
221
|
-
switch (
|
|
230
|
+
const a = `attr-${i}`, m = u || t.placeholder || t.default || "";
|
|
231
|
+
switch (t.type) {
|
|
222
232
|
case "select": {
|
|
223
|
-
const
|
|
224
|
-
d(
|
|
233
|
+
const r = c || u || t.default || t.options?.[0]?.value || "default", l = (o) => {
|
|
234
|
+
d(o === "false" ? "" : o);
|
|
225
235
|
};
|
|
226
|
-
return /* @__PURE__ */
|
|
236
|
+
return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
|
|
227
237
|
/* @__PURE__ */ e(
|
|
228
238
|
x,
|
|
229
239
|
{
|
|
230
|
-
htmlFor:
|
|
240
|
+
htmlFor: a,
|
|
231
241
|
className: "text-xs font-medium text-foreground-muted",
|
|
232
|
-
children:
|
|
242
|
+
children: t.label
|
|
233
243
|
}
|
|
234
244
|
),
|
|
235
|
-
/* @__PURE__ */
|
|
236
|
-
/* @__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 ${
|
|
249
|
+
placeholder: `Select ${t.label.toLowerCase()}`
|
|
240
250
|
}
|
|
241
251
|
) }),
|
|
242
|
-
/* @__PURE__ */ e(
|
|
243
|
-
|
|
252
|
+
/* @__PURE__ */ e(A, { children: t.options?.map((o) => /* @__PURE__ */ e(
|
|
253
|
+
F,
|
|
244
254
|
{
|
|
245
|
-
value:
|
|
255
|
+
value: o.value,
|
|
246
256
|
className: "text-xs",
|
|
247
|
-
children:
|
|
257
|
+
children: o.label
|
|
248
258
|
},
|
|
249
|
-
|
|
259
|
+
o.value
|
|
250
260
|
)) })
|
|
251
261
|
] })
|
|
252
262
|
] });
|
|
253
263
|
}
|
|
254
264
|
case "color":
|
|
255
|
-
return /* @__PURE__ */
|
|
265
|
+
return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
|
|
256
266
|
/* @__PURE__ */ e(
|
|
257
267
|
x,
|
|
258
268
|
{
|
|
259
|
-
htmlFor:
|
|
269
|
+
htmlFor: a,
|
|
260
270
|
className: "text-xs font-medium text-foreground-muted",
|
|
261
|
-
children:
|
|
271
|
+
children: t.label
|
|
262
272
|
}
|
|
263
273
|
),
|
|
264
|
-
/* @__PURE__ */
|
|
274
|
+
/* @__PURE__ */ n("div", { className: "flex gap-2", children: [
|
|
265
275
|
/* @__PURE__ */ e(
|
|
266
|
-
|
|
276
|
+
f,
|
|
267
277
|
{
|
|
268
|
-
id:
|
|
278
|
+
id: a,
|
|
269
279
|
type: "color",
|
|
270
|
-
value:
|
|
271
|
-
onChange: (
|
|
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
|
-
|
|
286
|
+
f,
|
|
277
287
|
{
|
|
278
288
|
type: "text",
|
|
279
|
-
value:
|
|
280
|
-
onChange: (
|
|
281
|
-
placeholder:
|
|
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__ */
|
|
298
|
+
return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
|
|
289
299
|
/* @__PURE__ */ e(
|
|
290
300
|
x,
|
|
291
301
|
{
|
|
292
|
-
htmlFor:
|
|
302
|
+
htmlFor: a,
|
|
293
303
|
className: "text-xs font-medium text-foreground-muted",
|
|
294
|
-
children:
|
|
304
|
+
children: t.label
|
|
295
305
|
}
|
|
296
306
|
),
|
|
297
307
|
/* @__PURE__ */ e(
|
|
298
|
-
|
|
308
|
+
f,
|
|
299
309
|
{
|
|
300
|
-
id:
|
|
310
|
+
id: a,
|
|
301
311
|
type: "text",
|
|
302
|
-
value:
|
|
303
|
-
onChange: (
|
|
304
|
-
placeholder:
|
|
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__ */
|
|
321
|
+
return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
|
|
312
322
|
/* @__PURE__ */ e(
|
|
313
323
|
x,
|
|
314
324
|
{
|
|
315
|
-
htmlFor:
|
|
325
|
+
htmlFor: a,
|
|
316
326
|
className: "text-xs font-medium text-foreground-muted",
|
|
317
|
-
children:
|
|
327
|
+
children: t.label
|
|
318
328
|
}
|
|
319
329
|
),
|
|
320
330
|
/* @__PURE__ */ e(
|
|
321
|
-
|
|
331
|
+
f,
|
|
322
332
|
{
|
|
323
|
-
id:
|
|
333
|
+
id: a,
|
|
324
334
|
type: "text",
|
|
325
|
-
value:
|
|
326
|
-
onChange: (
|
|
327
|
-
placeholder:
|
|
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__ */
|
|
343
|
+
return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
|
|
334
344
|
/* @__PURE__ */ e(
|
|
335
345
|
x,
|
|
336
346
|
{
|
|
337
|
-
htmlFor:
|
|
347
|
+
htmlFor: a,
|
|
338
348
|
className: "text-xs font-medium text-foreground-muted",
|
|
339
|
-
children:
|
|
349
|
+
children: t.label
|
|
340
350
|
}
|
|
341
351
|
),
|
|
342
352
|
/* @__PURE__ */ e(
|
|
343
|
-
|
|
353
|
+
f,
|
|
344
354
|
{
|
|
345
|
-
id:
|
|
355
|
+
id: a,
|
|
346
356
|
type: "url",
|
|
347
|
-
value:
|
|
348
|
-
onChange: (
|
|
349
|
-
placeholder:
|
|
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__ */
|
|
365
|
+
return /* @__PURE__ */ n("div", { className: "space-y-2", children: [
|
|
356
366
|
/* @__PURE__ */ e(
|
|
357
367
|
x,
|
|
358
368
|
{
|
|
359
|
-
htmlFor:
|
|
369
|
+
htmlFor: a,
|
|
360
370
|
className: "text-xs font-medium text-foreground-muted",
|
|
361
|
-
children:
|
|
371
|
+
children: t.label
|
|
362
372
|
}
|
|
363
373
|
),
|
|
364
374
|
/* @__PURE__ */ e(
|
|
365
|
-
|
|
375
|
+
f,
|
|
366
376
|
{
|
|
367
|
-
id:
|
|
377
|
+
id: a,
|
|
368
378
|
type: "text",
|
|
369
|
-
value:
|
|
370
|
-
onChange: (
|
|
371
|
-
placeholder:
|
|
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
|
-
|
|
389
|
+
de as BlockInspector
|
|
380
390
|
};
|