@agent-native/core 0.42.0 → 0.44.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 +17 -56
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +71 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +13 -13
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -6
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +21 -79
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +76 -18
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/blocks/index.d.ts +9 -0
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +9 -0
- package/dist/client/blocks/index.js.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +3 -3
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +128 -19
- package/dist/client/blocks/library/DiffBlock.js.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.js +31 -4
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.js +1 -1
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
- package/dist/client/blocks/library/callout.config.d.ts +29 -0
- package/dist/client/blocks/library/callout.config.d.ts.map +1 -0
- package/dist/client/blocks/library/callout.config.js +33 -0
- package/dist/client/blocks/library/callout.config.js.map +1 -0
- package/dist/client/blocks/library/callout.d.ts +20 -0
- package/dist/client/blocks/library/callout.d.ts.map +1 -0
- package/dist/client/blocks/library/callout.js +61 -0
- package/dist/client/blocks/library/callout.js.map +1 -0
- package/dist/client/blocks/library/checklist.d.ts.map +1 -1
- package/dist/client/blocks/library/checklist.js +3 -3
- package/dist/client/blocks/library/checklist.js.map +1 -1
- package/dist/client/blocks/library/code-tabs.js +1 -1
- package/dist/client/blocks/library/code-tabs.js.map +1 -1
- package/dist/client/blocks/library/diagram.config.d.ts +64 -0
- package/dist/client/blocks/library/diagram.config.d.ts.map +1 -0
- package/dist/client/blocks/library/diagram.config.js +111 -0
- package/dist/client/blocks/library/diagram.config.js.map +1 -0
- package/dist/client/blocks/library/diagram.d.ts +16 -0
- package/dist/client/blocks/library/diagram.d.ts.map +1 -0
- package/dist/client/blocks/library/diagram.js +261 -0
- package/dist/client/blocks/library/diagram.js.map +1 -0
- package/dist/client/blocks/library/question-form.config.d.ts +69 -0
- package/dist/client/blocks/library/question-form.config.d.ts.map +1 -0
- package/dist/client/blocks/library/question-form.config.js +58 -0
- package/dist/client/blocks/library/question-form.config.js.map +1 -0
- package/dist/client/blocks/library/question-form.d.ts +20 -0
- package/dist/client/blocks/library/question-form.d.ts.map +1 -0
- package/dist/client/blocks/library/question-form.js +286 -0
- package/dist/client/blocks/library/question-form.js.map +1 -0
- package/dist/client/blocks/library/sanitize-html.d.ts +5 -0
- package/dist/client/blocks/library/sanitize-html.d.ts.map +1 -0
- package/dist/client/blocks/library/sanitize-html.js +240 -0
- package/dist/client/blocks/library/sanitize-html.js.map +1 -0
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
- package/dist/client/blocks/library/server-specs.js +49 -0
- package/dist/client/blocks/library/server-specs.js.map +1 -1
- package/dist/client/blocks/library/specs.d.ts.map +1 -1
- package/dist/client/blocks/library/specs.js +9 -0
- package/dist/client/blocks/library/specs.js.map +1 -1
- package/dist/client/blocks/library/tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.js +12 -12
- package/dist/client/blocks/library/tabs.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +260 -0
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe-kit.js +920 -0
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -0
- package/dist/client/blocks/library/wireframe.config.d.ts +123 -0
- package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe.config.js +311 -0
- package/dist/client/blocks/library/wireframe.config.js.map +1 -0
- package/dist/client/blocks/library/wireframe.d.ts +15 -0
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe.js +206 -0
- package/dist/client/blocks/library/wireframe.js.map +1 -0
- package/dist/client/blocks/mdx.d.ts.map +1 -1
- package/dist/client/blocks/mdx.js +11 -0
- package/dist/client/blocks/mdx.js.map +1 -1
- package/dist/client/blocks/registry.d.ts +9 -0
- package/dist/client/blocks/registry.d.ts.map +1 -1
- package/dist/client/blocks/registry.js +12 -5
- package/dist/client/blocks/registry.js.map +1 -1
- package/dist/client/blocks/server.d.ts +1 -0
- package/dist/client/blocks/server.d.ts.map +1 -1
- package/dist/client/blocks/server.js +1 -0
- package/dist/client/blocks/server.js.map +1 -1
- package/dist/client/blocks/types.d.ts +8 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.js +112 -84
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +9 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +3 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/extensions.d.ts +13 -1
- package/dist/client/rich-markdown-editor/extensions.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/extensions.js +4 -2
- package/dist/client/rich-markdown-editor/extensions.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +30 -14
- package/dist/server/poll.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/blocks.css +1388 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
- package/docs/content/plan-plugin.md +8 -8
- package/docs/content/pr-visual-recap.md +2 -2
- package/docs/content/template-plan.md +94 -17
- package/package.json +2 -1
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
- package/docs/content/visual-plans.md +0 -82
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { prop, attributeValue } from "../mdx.js";
|
|
3
|
+
export const WIREFRAME_SURFACES = [
|
|
4
|
+
"desktop",
|
|
5
|
+
"mobile",
|
|
6
|
+
"popover",
|
|
7
|
+
"panel",
|
|
8
|
+
"browser",
|
|
9
|
+
];
|
|
10
|
+
export const WIREFRAME_EL_NAMES = [
|
|
11
|
+
"screen",
|
|
12
|
+
"browserBar",
|
|
13
|
+
"statusBar",
|
|
14
|
+
"toolbar",
|
|
15
|
+
"row",
|
|
16
|
+
"col",
|
|
17
|
+
"sidebar",
|
|
18
|
+
"navItem",
|
|
19
|
+
"main",
|
|
20
|
+
"title",
|
|
21
|
+
"text",
|
|
22
|
+
"lines",
|
|
23
|
+
"section",
|
|
24
|
+
"taskRow",
|
|
25
|
+
"chips",
|
|
26
|
+
"chip",
|
|
27
|
+
"pill",
|
|
28
|
+
"check",
|
|
29
|
+
"field",
|
|
30
|
+
"btn",
|
|
31
|
+
"fab",
|
|
32
|
+
"card",
|
|
33
|
+
"column",
|
|
34
|
+
"avatar",
|
|
35
|
+
"iconSquare",
|
|
36
|
+
"kv",
|
|
37
|
+
"searchBar",
|
|
38
|
+
"box",
|
|
39
|
+
"divider",
|
|
40
|
+
];
|
|
41
|
+
/* -------------------------------------------------------------------------- */
|
|
42
|
+
/* Schema (mirrors the plan-content wireframeDataSchema) */
|
|
43
|
+
/* -------------------------------------------------------------------------- */
|
|
44
|
+
const toneSchema = z.enum(["default", "accent", "warn", "ok", "muted"]);
|
|
45
|
+
const elNameSchema = z.enum(WIREFRAME_EL_NAMES);
|
|
46
|
+
const idSchema = z.string().trim().min(1).max(120);
|
|
47
|
+
/**
|
|
48
|
+
* Reject full-document HTML (html/head/body/script/style tags) in the `html` /
|
|
49
|
+
* `css` fields. Wireframe content must be a bounded fragment; document or script
|
|
50
|
+
* tags are a stored-XSS and layout-escape hazard.
|
|
51
|
+
*/
|
|
52
|
+
function noFullHtmlDocument(value) {
|
|
53
|
+
return !/<\s*(?:!doctype|html|head|body|script|style)\b/i.test(value);
|
|
54
|
+
}
|
|
55
|
+
const wireframeNodeSchema = z.lazy(() => z
|
|
56
|
+
.object({
|
|
57
|
+
id: idSchema.optional(),
|
|
58
|
+
el: elNameSchema,
|
|
59
|
+
children: z.array(wireframeNodeSchema).max(60).optional(),
|
|
60
|
+
text: z.string().trim().max(400).optional(),
|
|
61
|
+
value: z.string().trim().max(400).optional(),
|
|
62
|
+
label: z.string().trim().max(200).optional(),
|
|
63
|
+
placeholder: z.string().trim().max(200).optional(),
|
|
64
|
+
title: z.string().trim().max(200).optional(),
|
|
65
|
+
tone: toneSchema.optional(),
|
|
66
|
+
color: toneSchema.optional(),
|
|
67
|
+
weight: z.enum(["normal", "medium", "bold"]).optional(),
|
|
68
|
+
active: z.boolean().optional(),
|
|
69
|
+
done: z.boolean().optional(),
|
|
70
|
+
emphasis: z.boolean().optional(),
|
|
71
|
+
full: z.boolean().optional(),
|
|
72
|
+
solid: z.boolean().optional(),
|
|
73
|
+
dashed: z.boolean().optional(),
|
|
74
|
+
dot: z.boolean().optional(),
|
|
75
|
+
script: z.boolean().optional(),
|
|
76
|
+
area: z.boolean().optional(),
|
|
77
|
+
shape: z.enum(["square", "circle"]).optional(),
|
|
78
|
+
count: z.number().int().min(0).max(9_999).optional(),
|
|
79
|
+
prio: z.number().int().min(0).max(9).optional(),
|
|
80
|
+
n: z.number().int().min(0).max(20).optional(),
|
|
81
|
+
widths: z.array(z.number().min(0).max(100)).max(20).optional(),
|
|
82
|
+
icon: z.string().trim().max(40).optional(),
|
|
83
|
+
note: z.string().trim().max(400).optional(),
|
|
84
|
+
due: z.string().trim().max(120).optional(),
|
|
85
|
+
dueTone: toneSchema.optional(),
|
|
86
|
+
items: z
|
|
87
|
+
.array(z.object({
|
|
88
|
+
label: z.string().trim().min(1).max(200),
|
|
89
|
+
active: z.boolean().optional(),
|
|
90
|
+
count: z.number().int().min(0).max(9_999).optional(),
|
|
91
|
+
dot: z.boolean().optional(),
|
|
92
|
+
}))
|
|
93
|
+
.max(40)
|
|
94
|
+
.optional(),
|
|
95
|
+
rows: z
|
|
96
|
+
.array(z.object({
|
|
97
|
+
k: z.string().trim().min(1).max(200),
|
|
98
|
+
v: z.string().trim().max(400),
|
|
99
|
+
}))
|
|
100
|
+
.max(40)
|
|
101
|
+
.optional(),
|
|
102
|
+
})
|
|
103
|
+
.passthrough());
|
|
104
|
+
export const wireframeSchema = z
|
|
105
|
+
.object({
|
|
106
|
+
surface: z.enum(["desktop", "mobile", "popover", "panel", "browser"]),
|
|
107
|
+
renderMode: z.enum(["wireframe", "design"]).optional(),
|
|
108
|
+
caption: z.string().trim().max(400).optional(),
|
|
109
|
+
skeleton: z.boolean().optional(),
|
|
110
|
+
html: z
|
|
111
|
+
.string()
|
|
112
|
+
.max(40_000)
|
|
113
|
+
.refine(noFullHtmlDocument, {
|
|
114
|
+
message: "Wireframe html must be a bounded fragment without html/head/body/script/style tags.",
|
|
115
|
+
})
|
|
116
|
+
.optional(),
|
|
117
|
+
css: z
|
|
118
|
+
.string()
|
|
119
|
+
.max(20_000)
|
|
120
|
+
.refine(noFullHtmlDocument, {
|
|
121
|
+
message: "Wireframe css must not include document or script tags.",
|
|
122
|
+
})
|
|
123
|
+
.optional(),
|
|
124
|
+
screen: z.array(wireframeNodeSchema).max(200).optional(),
|
|
125
|
+
})
|
|
126
|
+
.passthrough();
|
|
127
|
+
/* -------------------------------------------------------------------------- */
|
|
128
|
+
/* Stable node-id derivation (verbatim from plan-mdx.ts) */
|
|
129
|
+
/* -------------------------------------------------------------------------- */
|
|
130
|
+
/**
|
|
131
|
+
* Derive a stable node id from the element name and tree path. Re-runs identically
|
|
132
|
+
* to the legacy plan derivation so stored plans round-trip without changing ids.
|
|
133
|
+
*/
|
|
134
|
+
export function createStableWireframeNodeId(el, path) {
|
|
135
|
+
return `node-${el}-${path}`
|
|
136
|
+
.toLowerCase()
|
|
137
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
138
|
+
.replace(/^-+|-+$/g, "")
|
|
139
|
+
.slice(0, 80);
|
|
140
|
+
}
|
|
141
|
+
/* -------------------------------------------------------------------------- */
|
|
142
|
+
/* Kit node <-> MDX component name maps (mirrors plan-mdx.ts NODE_TO_COMPONENT) */
|
|
143
|
+
/* -------------------------------------------------------------------------- */
|
|
144
|
+
const NODE_TO_COMPONENT = {
|
|
145
|
+
screen: "FrameScreen",
|
|
146
|
+
browserBar: "BrowserBar",
|
|
147
|
+
statusBar: "StatusBar",
|
|
148
|
+
toolbar: "Toolbar",
|
|
149
|
+
row: "Row",
|
|
150
|
+
col: "Col",
|
|
151
|
+
sidebar: "Sidebar",
|
|
152
|
+
navItem: "NavItem",
|
|
153
|
+
main: "Main",
|
|
154
|
+
title: "Title",
|
|
155
|
+
text: "Text",
|
|
156
|
+
lines: "Lines",
|
|
157
|
+
section: "SectionLabel",
|
|
158
|
+
taskRow: "TaskRow",
|
|
159
|
+
chips: "Chips",
|
|
160
|
+
chip: "Chip",
|
|
161
|
+
pill: "Pill",
|
|
162
|
+
check: "Check",
|
|
163
|
+
field: "Field",
|
|
164
|
+
btn: "Btn",
|
|
165
|
+
fab: "Fab",
|
|
166
|
+
card: "Card",
|
|
167
|
+
column: "Column",
|
|
168
|
+
avatar: "Avatar",
|
|
169
|
+
iconSquare: "IconSquare",
|
|
170
|
+
kv: "KV",
|
|
171
|
+
searchBar: "SearchBar",
|
|
172
|
+
box: "Box",
|
|
173
|
+
divider: "Divider",
|
|
174
|
+
};
|
|
175
|
+
const COMPONENT_TO_NODE = Object.fromEntries(Object.entries(NODE_TO_COMPONENT).map(([el, component]) => [component, el]));
|
|
176
|
+
/* -------------------------------------------------------------------------- */
|
|
177
|
+
/* Serialize (verbatim port of plan-mdx.ts serializeNode/serializeScreen) */
|
|
178
|
+
/* -------------------------------------------------------------------------- */
|
|
179
|
+
function serializeNode(node, indent = "") {
|
|
180
|
+
const name = NODE_TO_COMPONENT[node.el] ?? "Box";
|
|
181
|
+
const attrs = Object.entries(node)
|
|
182
|
+
.filter(([key]) => key !== "children" && key !== "el")
|
|
183
|
+
.map(([key, value]) => prop(key, value))
|
|
184
|
+
.join("");
|
|
185
|
+
if (!node.children?.length)
|
|
186
|
+
return `${indent}<${name}${attrs} />`;
|
|
187
|
+
const children = node.children
|
|
188
|
+
.map((child) => serializeNode(child, `${indent} `))
|
|
189
|
+
.join("\n");
|
|
190
|
+
return `${indent}<${name}${attrs}>\n${children}\n${indent}</${name}>`;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Serialize the wireframe data to its inner `<Screen>` MDX subtree. The registry
|
|
194
|
+
* serializer wraps this between the `<WireframeBlock …>` open/close tags, so the
|
|
195
|
+
* total output equals the legacy `serializeBlock` wireframe branch exactly.
|
|
196
|
+
*/
|
|
197
|
+
function serializeScreen(data) {
|
|
198
|
+
const attrs = [
|
|
199
|
+
prop("surface", data.surface),
|
|
200
|
+
prop("renderMode", data.renderMode),
|
|
201
|
+
prop("caption", data.caption),
|
|
202
|
+
prop("html", data.html),
|
|
203
|
+
prop("css", data.css),
|
|
204
|
+
prop("skeleton", data.skeleton),
|
|
205
|
+
].join("");
|
|
206
|
+
const children = (data.screen ?? [])
|
|
207
|
+
.map((node) => serializeNode(node, " "))
|
|
208
|
+
.join("\n");
|
|
209
|
+
if (!children)
|
|
210
|
+
return `<Screen${attrs} />`;
|
|
211
|
+
return `<Screen${attrs}>\n${children}\n</Screen>`;
|
|
212
|
+
}
|
|
213
|
+
function elementName(node) {
|
|
214
|
+
return node?.type === "mdxJsxFlowElement" ||
|
|
215
|
+
node?.type === "mdxJsxTextElement"
|
|
216
|
+
? node.name
|
|
217
|
+
: undefined;
|
|
218
|
+
}
|
|
219
|
+
function findAttribute(node, name) {
|
|
220
|
+
return node.attributes?.find((attr) => attr.type === "mdxJsxAttribute" && attr.name === name);
|
|
221
|
+
}
|
|
222
|
+
function stringAttr(node, name) {
|
|
223
|
+
const value = attributeValue(findAttribute(node, name));
|
|
224
|
+
return typeof value === "string" ? value : undefined;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Resolve a required-when-present string attribute on a `<Screen>`. If the
|
|
228
|
+
* attribute is absent we return undefined, but if it is present yet cannot be
|
|
229
|
+
* resolved to a string (e.g. a number, an object, or an unevaluable expression)
|
|
230
|
+
* we THROW so a malformed wireframe fails the import instead of silently
|
|
231
|
+
* dropping the value and rendering an empty wireframe.
|
|
232
|
+
*/
|
|
233
|
+
function requiredStringAttr(node, name) {
|
|
234
|
+
const attr = findAttribute(node, name);
|
|
235
|
+
if (!attr)
|
|
236
|
+
return undefined;
|
|
237
|
+
const value = attributeValue(attr);
|
|
238
|
+
if (typeof value !== "string") {
|
|
239
|
+
throw new Error(`Wireframe <Screen> attribute "${name}" must resolve to a string, got ${typeof value}. Use a quoted string or a static template literal.`);
|
|
240
|
+
}
|
|
241
|
+
return value;
|
|
242
|
+
}
|
|
243
|
+
function boolAttr(node, name) {
|
|
244
|
+
const value = attributeValue(findAttribute(node, name));
|
|
245
|
+
return typeof value === "boolean" ? value : undefined;
|
|
246
|
+
}
|
|
247
|
+
function parseWireframeNode(node, path = "node") {
|
|
248
|
+
const component = elementName(node);
|
|
249
|
+
if (!component)
|
|
250
|
+
return null;
|
|
251
|
+
const el = COMPONENT_TO_NODE[component];
|
|
252
|
+
if (!el)
|
|
253
|
+
return null;
|
|
254
|
+
const attrs = node.attributes ?? [];
|
|
255
|
+
const parsed = { el };
|
|
256
|
+
for (const attr of attrs) {
|
|
257
|
+
if (attr.type !== "mdxJsxAttribute")
|
|
258
|
+
continue;
|
|
259
|
+
const value = attributeValue(attr);
|
|
260
|
+
if (value !== undefined)
|
|
261
|
+
parsed[attr.name] = value;
|
|
262
|
+
}
|
|
263
|
+
parsed.el = el;
|
|
264
|
+
parsed.id ??= createStableWireframeNodeId(el, path);
|
|
265
|
+
const children = (node.children ?? [])
|
|
266
|
+
.map((child, index) => parseWireframeNode(child, `${path}-${index}`))
|
|
267
|
+
.filter(Boolean);
|
|
268
|
+
if (children.length > 0)
|
|
269
|
+
parsed.children = children;
|
|
270
|
+
return parsed;
|
|
271
|
+
}
|
|
272
|
+
function parseScreen(node, idContext) {
|
|
273
|
+
return {
|
|
274
|
+
surface: stringAttr(node, "surface") ?? "desktop",
|
|
275
|
+
renderMode: stringAttr(node, "renderMode"),
|
|
276
|
+
caption: stringAttr(node, "caption"),
|
|
277
|
+
html: requiredStringAttr(node, "html"),
|
|
278
|
+
css: requiredStringAttr(node, "css"),
|
|
279
|
+
skeleton: boolAttr(node, "skeleton"),
|
|
280
|
+
screen: (node.children ?? [])
|
|
281
|
+
.map((child, index) => parseWireframeNode(child, `${idContext}-screen-${index}`))
|
|
282
|
+
.filter(Boolean),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/* -------------------------------------------------------------------------- */
|
|
286
|
+
/* MDX config */
|
|
287
|
+
/* -------------------------------------------------------------------------- */
|
|
288
|
+
/**
|
|
289
|
+
* Registry MDX config for the wireframe block. `tag` matches the legacy
|
|
290
|
+
* `WireframeBlock`. The block has no flat attributes (`toAttrs` → `{}`); all data
|
|
291
|
+
* lives in the nested `<Screen>` subtree handled by `serializeChildren` /
|
|
292
|
+
* `parseChildren`. The registry serializer wraps `serializeChildren` between the
|
|
293
|
+
* `<WireframeBlock>` open/close, producing the exact legacy bytes. On parse, the
|
|
294
|
+
* registry passes the already-extended `${idContext}-${blockId}` to
|
|
295
|
+
* `parseChildren` — the same id base the legacy `parseScreen` receives — so node
|
|
296
|
+
* ids are reproduced identically.
|
|
297
|
+
*/
|
|
298
|
+
export const wireframeMdx = {
|
|
299
|
+
tag: "WireframeBlock",
|
|
300
|
+
toAttrs: () => ({}),
|
|
301
|
+
fromAttrs: () => ({ surface: "desktop", screen: [] }),
|
|
302
|
+
serializeChildren: (data) => serializeScreen(data),
|
|
303
|
+
parseChildren: (childNodes, idContext) => {
|
|
304
|
+
const nodes = childNodes;
|
|
305
|
+
const screen = nodes.find((child) => elementName(child) === "Screen");
|
|
306
|
+
if (!screen)
|
|
307
|
+
return { surface: "desktop", screen: [] };
|
|
308
|
+
return parseScreen(screen, idContext);
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
//# sourceMappingURL=wireframe.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireframe.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/wireframe.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AA4JjD,MAAM,CAAC,MAAM,kBAAkB,GAAuB;IACpD,SAAS;IACT,QAAQ;IACR,SAAS;IACT,OAAO;IACP,SAAS;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,QAAQ;IACR,YAAY;IACZ,WAAW;IACX,SAAS;IACT,KAAK;IACL,KAAK;IACL,SAAS;IACT,SAAS;IACT,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,SAAS;IACT,SAAS;IACT,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,KAAK;IACL,KAAK;IACL,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,YAAY;IACZ,IAAI;IACJ,WAAW;IACX,KAAK;IACL,SAAS;CACV,CAAC;AAEF,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACxE,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CACzB,kBAA6D,CAC9D,CAAC;AACF,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEnD;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,CAAC,iDAAiD,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,mBAAmB,GAA6B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAChE,CAAC;KACE,MAAM,CAAC;IACN,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE;IACvB,EAAE,EAAE,YAAY;IAChB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAEzD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAClD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAE5C,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE;IAC3B,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE;IAC5B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvD,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC5B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC7B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC9B,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;IAE9C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC/C,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC7C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC9D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAE1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,UAAU,CAAC,QAAQ,EAAE;IAE9B,KAAK,EAAE,CAAC;SACL,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACxC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;QACpD,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KAC5B,CAAC,CACH;SACA,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,EAAE;IACb,IAAI,EAAE,CAAC;SACJ,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;KAC9B,CAAC,CACH;SACA,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,EAAE;CACd,CAAC;KACD,WAAW,EAAE,CACW,CAAC;AAE9B,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACrE,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC9C,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,MAAM,CAAC;SACX,MAAM,CAAC,kBAAkB,EAAE;QAC1B,OAAO,EACL,qFAAqF;KACxF,CAAC;SACD,QAAQ,EAAE;IACb,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,CAAC,MAAM,CAAC;SACX,MAAM,CAAC,kBAAkB,EAAE;QAC1B,OAAO,EAAE,yDAAyD;KACnE,CAAC;SACD,QAAQ,EAAE;IACb,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;CACzD,CAAC;KACD,WAAW,EAAyC,CAAC;AAExD,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,EAAmB,EACnB,IAAY;IAEZ,OAAO,QAAQ,EAAE,IAAI,IAAI,EAAE;SACxB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,gFAAgF;AAChF,kFAAkF;AAClF,gFAAgF;AAEhF,MAAM,iBAAiB,GAAoC;IACzD,MAAM,EAAE,aAAa;IACrB,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,cAAc;IACvB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,EAAE,EAAE,IAAI;IACR,SAAS,EAAE,WAAW;IACtB,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAC1C,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CACzC,CAAC;AAErC,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF,SAAS,aAAa,CAAC,IAAmB,EAAE,MAAM,GAAG,EAAE;IACrD,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SAC/B,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,CAAC;SACrD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;SACvC,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,OAAO,GAAG,MAAM,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC;IAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;SAC3B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC;SACnD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,GAAG,MAAM,IAAI,IAAI,GAAG,KAAK,MAAM,QAAQ,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,IAAmB;IAC1C,MAAM,KAAK,GAAG;QACZ,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC;QACrB,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC;KAChC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;SACxC,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,IAAI,CAAC,QAAQ;QAAE,OAAO,UAAU,KAAK,KAAK,CAAC;IAC3C,OAAO,UAAU,KAAK,MAAM,QAAQ,aAAa,CAAC;AACpD,CAAC;AAsBD,SAAS,WAAW,CAAC,IAAkC;IACrD,OAAO,IAAI,EAAE,IAAI,KAAK,mBAAmB;QACvC,IAAI,EAAE,IAAI,KAAK,mBAAmB;QAClC,CAAC,CAAC,IAAI,CAAC,IAAI;QACX,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,IAAsB,EAAE,IAAY;IACzD,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,CAC1B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,iBAAiB,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAChE,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAsB,EAAE,IAAY;IACtD,MAAM,KAAK,GAAG,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACxD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CACzB,IAAsB,EACtB,IAAY;IAEZ,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,iCAAiC,IAAI,mCAAmC,OAAO,KAAK,qDAAqD,CAC1I,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,IAAsB,EAAE,IAAY;IACpD,MAAM,KAAK,GAAG,cAAc,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACxD,OAAO,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAsB,EACtB,IAAI,GAAG,MAAM;IAEb,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,EAAE,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACpC,MAAM,MAAM,GAAkB,EAAE,EAAE,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;YAAE,SAAS;QAC9C,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK,KAAK,SAAS;YACpB,MAAkC,CAAC,IAAI,CAAC,IAAc,CAAC,GAAG,KAAK,CAAC;IACrE,CAAC;IACD,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,2BAA2B,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;SACnC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;SACpE,MAAM,CAAC,OAAO,CAAoB,CAAC;IACtC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACpD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,IAAsB,EAAE,SAAiB;IAC5D,OAAO;QACL,OAAO,EACJ,UAAU,CAAC,IAAI,EAAE,SAAS,CAA8B,IAAI,SAAS;QACxE,UAAU,EAAE,UAAU,CAAC,IAAI,EAAE,YAAY,CAAgC;QACzE,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC;QACpC,IAAI,EAAE,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC;QACtC,GAAG,EAAE,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC;QACpC,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;QACpC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;aAC1B,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACpB,kBAAkB,CAAC,KAAK,EAAE,GAAG,SAAS,WAAW,KAAK,EAAE,CAAC,CAC1D;aACA,MAAM,CAAC,OAAO,CAAoB;KACtC,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAkC;IACzD,GAAG,EAAE,gBAAgB;IACrB,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IACnB,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrD,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC;IAClD,aAAa,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,UAAgC,CAAC;QAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC;QACtE,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACvD,OAAO,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,CAAC;CACF,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { prop, attributeValue } from \"../mdx.js\";\nimport type { BlockMdxConfig } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the shared `wireframe` block: its data shape, zod\n * schema, the stable node-id helper, and the nested-MDX round-trip config. Lives\n * in core so BOTH apps' server/shared registries and the client spec\n * (`wireframe.tsx`) consume one definition; importing it into a server module\n * never pulls React into the Nitro/SSR bundle.\n *\n * The wireframe block originated in the plan template. The vocabulary\n * (`PlanWireframe*` names, the `el` set, the `--wf-*` token contract) and the\n * MDX encoding (`<WireframeBlock>…<Screen>…</Screen></WireframeBlock>` with kit\n * component names `FrameScreen`/`Row`/`Col`/…) are preserved EXACTLY so stored\n * plans round-trip byte-compatibly and existing node ids never change.\n *\n * The wireframe is NESTED MDX, not a flat-attribute or prose block: its body is\n * a `<Screen surface caption>…kit-tree…</Screen>` subtree. So the config uses\n * `serializeChildren`/`parseChildren` (the registry's nested-MDX path) rather\n * than `toAttrs`/`childrenField`.\n */\n\n/* -------------------------------------------------------------------------- */\n/* Vocabulary (decoupled copy of the plan-content wireframe types) */\n/* -------------------------------------------------------------------------- */\n\nexport type WireframeSurface =\n | \"desktop\"\n | \"mobile\"\n | \"popover\"\n | \"panel\"\n | \"browser\";\n\nexport type WireframeRenderMode = \"wireframe\" | \"design\";\n\n/** Tone keyword reused across screen primitives. The renderer maps to color. */\nexport type WireframeTone = \"default\" | \"accent\" | \"warn\" | \"ok\" | \"muted\";\n\n/**\n * Names of the kit primitives. Component-like (MDX-friendly). The renderer maps\n * each to a flex kit component. Layout is ALWAYS flex; row/col/sidebar/main set\n * the flex direction.\n */\nexport type WireframeElName =\n | \"screen\"\n | \"browserBar\"\n | \"statusBar\"\n | \"toolbar\"\n | \"row\"\n | \"col\"\n | \"sidebar\"\n | \"navItem\"\n | \"main\"\n | \"title\"\n | \"text\"\n | \"lines\"\n | \"section\"\n | \"taskRow\"\n | \"chips\"\n | \"chip\"\n | \"pill\"\n | \"check\"\n | \"field\"\n | \"btn\"\n | \"fab\"\n | \"card\"\n | \"column\"\n | \"avatar\"\n | \"iconSquare\"\n | \"kv\"\n | \"searchBar\"\n | \"box\"\n | \"divider\";\n\n/**\n * A single node in the wireframe kit tree. `el` is the primitive name; the\n * remaining props are the union of every primitive's props (kept permissive so\n * the model can compose freely). `children` nests other nodes. `id` is a stable\n * node id used by node-addressable patch ops (auto-assigned on create).\n *\n * There is intentionally NO x/y/width/height here — wireframe internals are\n * geometry-free and laid out by the renderer with flex.\n */\nexport type WireframeNode = {\n /** Stable id for node-addressable patches; auto-assigned when absent. */\n id?: string;\n el: WireframeElName;\n children?: WireframeNode[];\n\n // Generic content props\n text?: string;\n value?: string;\n label?: string;\n placeholder?: string;\n title?: string;\n\n // Styling-by-intent (semantic only; renderer owns actual color/size)\n tone?: WireframeTone;\n color?: WireframeTone;\n weight?: \"normal\" | \"medium\" | \"bold\";\n active?: boolean;\n done?: boolean;\n emphasis?: boolean;\n full?: boolean;\n solid?: boolean;\n dashed?: boolean;\n dot?: boolean;\n script?: boolean;\n area?: boolean;\n shape?: \"square\" | \"circle\";\n\n // Numeric / structured props\n count?: number;\n prio?: number;\n n?: number;\n widths?: number[];\n icon?: string;\n\n // taskRow specifics\n note?: string;\n due?: string;\n dueTone?: WireframeTone;\n\n // Collection props (chips, kv)\n items?: Array<{\n label: string;\n active?: boolean;\n count?: number;\n dot?: boolean;\n }>;\n rows?: Array<{ k: string; v: string }>;\n};\n\nexport interface WireframeData {\n surface: WireframeSurface;\n /** `design` renders full-fidelity branded HTML/CSS instead of a sketch. */\n renderMode?: WireframeRenderMode;\n caption?: string;\n /**\n * Neutral, textless loading register. The renderer drops borders, the sketch\n * outline, and color, rendering soft placeholder geometry only.\n */\n skeleton?: boolean;\n /**\n * PRIMARY content: a self-contained HTML mockup of the screen (sanitized\n * fragment — no document/script/style tags). The renderer owns the surface\n * aspect, the dark/light theme, the hand-drawn font, and the rough overlay.\n * When `html` is set, `screen` is ignored.\n */\n html?: string;\n /** Optional scoped CSS for the html mockup (sanitized fragment). */\n css?: string;\n /** Kit-tree screen. Used when `html` is absent. */\n screen?: WireframeNode[];\n}\n\nexport const WIREFRAME_SURFACES: WireframeSurface[] = [\n \"desktop\",\n \"mobile\",\n \"popover\",\n \"panel\",\n \"browser\",\n];\n\nexport const WIREFRAME_EL_NAMES: WireframeElName[] = [\n \"screen\",\n \"browserBar\",\n \"statusBar\",\n \"toolbar\",\n \"row\",\n \"col\",\n \"sidebar\",\n \"navItem\",\n \"main\",\n \"title\",\n \"text\",\n \"lines\",\n \"section\",\n \"taskRow\",\n \"chips\",\n \"chip\",\n \"pill\",\n \"check\",\n \"field\",\n \"btn\",\n \"fab\",\n \"card\",\n \"column\",\n \"avatar\",\n \"iconSquare\",\n \"kv\",\n \"searchBar\",\n \"box\",\n \"divider\",\n];\n\n/* -------------------------------------------------------------------------- */\n/* Schema (mirrors the plan-content wireframeDataSchema) */\n/* -------------------------------------------------------------------------- */\n\nconst toneSchema = z.enum([\"default\", \"accent\", \"warn\", \"ok\", \"muted\"]);\nconst elNameSchema = z.enum(\n WIREFRAME_EL_NAMES as [WireframeElName, ...WireframeElName[]],\n);\nconst idSchema = z.string().trim().min(1).max(120);\n\n/**\n * Reject full-document HTML (html/head/body/script/style tags) in the `html` /\n * `css` fields. Wireframe content must be a bounded fragment; document or script\n * tags are a stored-XSS and layout-escape hazard.\n */\nfunction noFullHtmlDocument(value: string): boolean {\n return !/<\\s*(?:!doctype|html|head|body|script|style)\\b/i.test(value);\n}\n\nconst wireframeNodeSchema: z.ZodType<WireframeNode> = z.lazy(() =>\n z\n .object({\n id: idSchema.optional(),\n el: elNameSchema,\n children: z.array(wireframeNodeSchema).max(60).optional(),\n\n text: z.string().trim().max(400).optional(),\n value: z.string().trim().max(400).optional(),\n label: z.string().trim().max(200).optional(),\n placeholder: z.string().trim().max(200).optional(),\n title: z.string().trim().max(200).optional(),\n\n tone: toneSchema.optional(),\n color: toneSchema.optional(),\n weight: z.enum([\"normal\", \"medium\", \"bold\"]).optional(),\n active: z.boolean().optional(),\n done: z.boolean().optional(),\n emphasis: z.boolean().optional(),\n full: z.boolean().optional(),\n solid: z.boolean().optional(),\n dashed: z.boolean().optional(),\n dot: z.boolean().optional(),\n script: z.boolean().optional(),\n area: z.boolean().optional(),\n shape: z.enum([\"square\", \"circle\"]).optional(),\n\n count: z.number().int().min(0).max(9_999).optional(),\n prio: z.number().int().min(0).max(9).optional(),\n n: z.number().int().min(0).max(20).optional(),\n widths: z.array(z.number().min(0).max(100)).max(20).optional(),\n icon: z.string().trim().max(40).optional(),\n\n note: z.string().trim().max(400).optional(),\n due: z.string().trim().max(120).optional(),\n dueTone: toneSchema.optional(),\n\n items: z\n .array(\n z.object({\n label: z.string().trim().min(1).max(200),\n active: z.boolean().optional(),\n count: z.number().int().min(0).max(9_999).optional(),\n dot: z.boolean().optional(),\n }),\n )\n .max(40)\n .optional(),\n rows: z\n .array(\n z.object({\n k: z.string().trim().min(1).max(200),\n v: z.string().trim().max(400),\n }),\n )\n .max(40)\n .optional(),\n })\n .passthrough(),\n) as z.ZodType<WireframeNode>;\n\nexport const wireframeSchema = z\n .object({\n surface: z.enum([\"desktop\", \"mobile\", \"popover\", \"panel\", \"browser\"]),\n renderMode: z.enum([\"wireframe\", \"design\"]).optional(),\n caption: z.string().trim().max(400).optional(),\n skeleton: z.boolean().optional(),\n html: z\n .string()\n .max(40_000)\n .refine(noFullHtmlDocument, {\n message:\n \"Wireframe html must be a bounded fragment without html/head/body/script/style tags.\",\n })\n .optional(),\n css: z\n .string()\n .max(20_000)\n .refine(noFullHtmlDocument, {\n message: \"Wireframe css must not include document or script tags.\",\n })\n .optional(),\n screen: z.array(wireframeNodeSchema).max(200).optional(),\n })\n .passthrough() as unknown as z.ZodType<WireframeData>;\n\n/* -------------------------------------------------------------------------- */\n/* Stable node-id derivation (verbatim from plan-mdx.ts) */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Derive a stable node id from the element name and tree path. Re-runs identically\n * to the legacy plan derivation so stored plans round-trip without changing ids.\n */\nexport function createStableWireframeNodeId(\n el: WireframeElName,\n path: string,\n): string {\n return `node-${el}-${path}`\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 80);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Kit node <-> MDX component name maps (mirrors plan-mdx.ts NODE_TO_COMPONENT) */\n/* -------------------------------------------------------------------------- */\n\nconst NODE_TO_COMPONENT: Record<WireframeElName, string> = {\n screen: \"FrameScreen\",\n browserBar: \"BrowserBar\",\n statusBar: \"StatusBar\",\n toolbar: \"Toolbar\",\n row: \"Row\",\n col: \"Col\",\n sidebar: \"Sidebar\",\n navItem: \"NavItem\",\n main: \"Main\",\n title: \"Title\",\n text: \"Text\",\n lines: \"Lines\",\n section: \"SectionLabel\",\n taskRow: \"TaskRow\",\n chips: \"Chips\",\n chip: \"Chip\",\n pill: \"Pill\",\n check: \"Check\",\n field: \"Field\",\n btn: \"Btn\",\n fab: \"Fab\",\n card: \"Card\",\n column: \"Column\",\n avatar: \"Avatar\",\n iconSquare: \"IconSquare\",\n kv: \"KV\",\n searchBar: \"SearchBar\",\n box: \"Box\",\n divider: \"Divider\",\n};\n\nconst COMPONENT_TO_NODE = Object.fromEntries(\n Object.entries(NODE_TO_COMPONENT).map(([el, component]) => [component, el]),\n) as Record<string, WireframeElName>;\n\n/* -------------------------------------------------------------------------- */\n/* Serialize (verbatim port of plan-mdx.ts serializeNode/serializeScreen) */\n/* -------------------------------------------------------------------------- */\n\nfunction serializeNode(node: WireframeNode, indent = \"\"): string {\n const name = NODE_TO_COMPONENT[node.el] ?? \"Box\";\n const attrs = Object.entries(node)\n .filter(([key]) => key !== \"children\" && key !== \"el\")\n .map(([key, value]) => prop(key, value))\n .join(\"\");\n if (!node.children?.length) return `${indent}<${name}${attrs} />`;\n const children = node.children\n .map((child) => serializeNode(child, `${indent} `))\n .join(\"\\n\");\n return `${indent}<${name}${attrs}>\\n${children}\\n${indent}</${name}>`;\n}\n\n/**\n * Serialize the wireframe data to its inner `<Screen>` MDX subtree. The registry\n * serializer wraps this between the `<WireframeBlock …>` open/close tags, so the\n * total output equals the legacy `serializeBlock` wireframe branch exactly.\n */\nfunction serializeScreen(data: WireframeData): string {\n const attrs = [\n prop(\"surface\", data.surface),\n prop(\"renderMode\", data.renderMode),\n prop(\"caption\", data.caption),\n prop(\"html\", data.html),\n prop(\"css\", data.css),\n prop(\"skeleton\", data.skeleton),\n ].join(\"\");\n const children = (data.screen ?? [])\n .map((node) => serializeNode(node, \" \"))\n .join(\"\\n\");\n if (!children) return `<Screen${attrs} />`;\n return `<Screen${attrs}>\\n${children}\\n</Screen>`;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Parse (verbatim port of plan-mdx.ts parseScreen/parseWireframeNode) */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Minimal MDX AST node shape used while walking the wireframe subtree. Declared\n * standalone (not an intersection with `MdxJsxNode`, whose `children` is\n * `unknown[]`) so recursive `children` stays narrowed to `WireframeMdxNode`.\n */\ntype WireframeMdxNode = {\n type: string;\n name?: string;\n attributes?: Array<{\n type: string;\n name?: string;\n value?: string | null | { type: string; value: string; data?: unknown };\n }>;\n children?: WireframeMdxNode[];\n};\n\nfunction elementName(node: WireframeMdxNode | undefined): string | undefined {\n return node?.type === \"mdxJsxFlowElement\" ||\n node?.type === \"mdxJsxTextElement\"\n ? node.name\n : undefined;\n}\n\nfunction findAttribute(node: WireframeMdxNode, name: string) {\n return node.attributes?.find(\n (attr) => attr.type === \"mdxJsxAttribute\" && attr.name === name,\n );\n}\n\nfunction stringAttr(node: WireframeMdxNode, name: string): string | undefined {\n const value = attributeValue(findAttribute(node, name));\n return typeof value === \"string\" ? value : undefined;\n}\n\n/**\n * Resolve a required-when-present string attribute on a `<Screen>`. If the\n * attribute is absent we return undefined, but if it is present yet cannot be\n * resolved to a string (e.g. a number, an object, or an unevaluable expression)\n * we THROW so a malformed wireframe fails the import instead of silently\n * dropping the value and rendering an empty wireframe.\n */\nfunction requiredStringAttr(\n node: WireframeMdxNode,\n name: string,\n): string | undefined {\n const attr = findAttribute(node, name);\n if (!attr) return undefined;\n const value = attributeValue(attr);\n if (typeof value !== \"string\") {\n throw new Error(\n `Wireframe <Screen> attribute \"${name}\" must resolve to a string, got ${typeof value}. Use a quoted string or a static template literal.`,\n );\n }\n return value;\n}\n\nfunction boolAttr(node: WireframeMdxNode, name: string): boolean | undefined {\n const value = attributeValue(findAttribute(node, name));\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction parseWireframeNode(\n node: WireframeMdxNode,\n path = \"node\",\n): WireframeNode | null {\n const component = elementName(node);\n if (!component) return null;\n const el = COMPONENT_TO_NODE[component];\n if (!el) return null;\n const attrs = node.attributes ?? [];\n const parsed: WireframeNode = { el };\n for (const attr of attrs) {\n if (attr.type !== \"mdxJsxAttribute\") continue;\n const value = attributeValue(attr);\n if (value !== undefined)\n (parsed as Record<string, unknown>)[attr.name as string] = value;\n }\n parsed.el = el;\n parsed.id ??= createStableWireframeNodeId(el, path);\n const children = (node.children ?? [])\n .map((child, index) => parseWireframeNode(child, `${path}-${index}`))\n .filter(Boolean) as WireframeNode[];\n if (children.length > 0) parsed.children = children;\n return parsed;\n}\n\nfunction parseScreen(node: WireframeMdxNode, idContext: string): WireframeData {\n return {\n surface:\n (stringAttr(node, \"surface\") as WireframeData[\"surface\"]) ?? \"desktop\",\n renderMode: stringAttr(node, \"renderMode\") as WireframeData[\"renderMode\"],\n caption: stringAttr(node, \"caption\"),\n html: requiredStringAttr(node, \"html\"),\n css: requiredStringAttr(node, \"css\"),\n skeleton: boolAttr(node, \"skeleton\"),\n screen: (node.children ?? [])\n .map((child, index) =>\n parseWireframeNode(child, `${idContext}-screen-${index}`),\n )\n .filter(Boolean) as WireframeNode[],\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* MDX config */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Registry MDX config for the wireframe block. `tag` matches the legacy\n * `WireframeBlock`. The block has no flat attributes (`toAttrs` → `{}`); all data\n * lives in the nested `<Screen>` subtree handled by `serializeChildren` /\n * `parseChildren`. The registry serializer wraps `serializeChildren` between the\n * `<WireframeBlock>` open/close, producing the exact legacy bytes. On parse, the\n * registry passes the already-extended `${idContext}-${blockId}` to\n * `parseChildren` — the same id base the legacy `parseScreen` receives — so node\n * ids are reproduced identically.\n */\nexport const wireframeMdx: BlockMdxConfig<WireframeData> = {\n tag: \"WireframeBlock\",\n toAttrs: () => ({}),\n fromAttrs: () => ({ surface: \"desktop\", screen: [] }),\n serializeChildren: (data) => serializeScreen(data),\n parseChildren: (childNodes, idContext) => {\n const nodes = childNodes as WireframeMdxNode[];\n const screen = nodes.find((child) => elementName(child) === \"Screen\");\n if (!screen) return { surface: \"desktop\", screen: [] };\n return parseScreen(screen, idContext);\n },\n};\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BlockReadProps, BlockEditProps } from "../types.js";
|
|
2
|
+
import { type WireframeData } from "./wireframe.config.js";
|
|
3
|
+
/** Read-only renderer for a `wireframe` block. */
|
|
4
|
+
export declare function WireframeBlock({ data, blockId, title, summary, ctx, }: BlockReadProps<WireframeData>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
/**
|
|
6
|
+
* Editor for the `wireframe` block. The wireframe is canvas / agent-patch edited
|
|
7
|
+
* (it never calls `onChange`), so edit mode reuses the read surface — mirroring
|
|
8
|
+
* the plan `WireframeEditor`. The host document editor already wraps the registry
|
|
9
|
+
* edit path in a titled section, so this renders only the surface to avoid
|
|
10
|
+
* double-nesting.
|
|
11
|
+
*/
|
|
12
|
+
export declare function WireframeEditor({ data, ctx }: BlockEditProps<WireframeData>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
/** Full client spec for the shared `wireframe` block (schema + MDX + Read/Edit). */
|
|
14
|
+
export declare const wireframeBlock: import("../types.js").BlockSpec<WireframeData>;
|
|
15
|
+
//# sourceMappingURL=wireframe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireframe.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/wireframe.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,uBAAuB,CAAC;AAsY/B,kDAAkD;AAClD,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,aAAa,CAAC,2CAW/B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,cAAc,CAAC,aAAa,CAAC,2CAE3E;AAED,oFAAoF;AACpF,eAAO,MAAM,cAAc,gDAczB,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useMemo, useRef, useState, } from "react";
|
|
3
|
+
import { defineBlock } from "../types.js";
|
|
4
|
+
import { wireframeSchema, wireframeMdx, } from "./wireframe.config.js";
|
|
5
|
+
import { HTML_ROUGH_SELECTOR, KitConfigContext, RoughOverlay, Screen, renderNodes, useIsDark, useWireframeStyle, } from "./wireframe-kit.js";
|
|
6
|
+
import { sanitizeWireframeCss, sanitizeWireframeHtml, scopeDesignCss, } from "./sanitize-html.js";
|
|
7
|
+
const SURFACE_PRESETS = {
|
|
8
|
+
// mobile keeps a tall floor: a phone frame reads as a phone even when short.
|
|
9
|
+
mobile: { width: 300, minHeight: 360, radius: 30 },
|
|
10
|
+
desktop: { width: 840, minHeight: 200, radius: 14 },
|
|
11
|
+
browser: { width: 900, minHeight: 200, radius: 14 },
|
|
12
|
+
popover: { width: 360, minHeight: 120, radius: 16 },
|
|
13
|
+
panel: { width: 420, minHeight: 200, radius: 16 },
|
|
14
|
+
};
|
|
15
|
+
function isHtmlData(data) {
|
|
16
|
+
return typeof data.html === "string" && data.html.trim().length > 0;
|
|
17
|
+
}
|
|
18
|
+
/* -------------------------------------------------------------------------- */
|
|
19
|
+
/* Shared frame shell: surface-locked WIDTH + auto (content-driven) height + */
|
|
20
|
+
/* theme + rough overlay. The frame keeps each surface's footprint and chrome */
|
|
21
|
+
/* but fits its content height instead of padding to a fixed aspect, so short */
|
|
22
|
+
/* content yields a short frame and tall content grows. Pass `canvasSize` to */
|
|
23
|
+
/* opt a fixed-aspect canvas artboard back into a hard pixel height. */
|
|
24
|
+
/* -------------------------------------------------------------------------- */
|
|
25
|
+
function ArtboardFrame({ surface, compact, canvasSize, canvasWidth, skeleton, renderMode, roughOverlay = true, selector, caption, render, }) {
|
|
26
|
+
const ref = useRef(null);
|
|
27
|
+
const fitRef = useRef(null);
|
|
28
|
+
const isDark = useIsDark();
|
|
29
|
+
const theme = isDark ? "dark" : "light";
|
|
30
|
+
const style = useWireframeStyle();
|
|
31
|
+
const preset = SURFACE_PRESETS[surface] ?? SURFACE_PRESETS.desktop;
|
|
32
|
+
const width = canvasWidth ?? preset.width;
|
|
33
|
+
// AUTO-HEIGHT: with no explicit `canvasSize` the artboard height is driven by
|
|
34
|
+
// its content (`height: auto`), floored at the surface's `minHeight` so a short
|
|
35
|
+
// screen produces a short frame and a tall screen grows — instead of every
|
|
36
|
+
// surface being padded to a fixed preset height that left a big empty band
|
|
37
|
+
// below short content. A `canvasSize` (fixed-aspect canvas artboard) overrides
|
|
38
|
+
// this with a hard pixel height.
|
|
39
|
+
const fixedHeight = canvasSize;
|
|
40
|
+
const minHeight = fixedHeight ?? preset.minHeight;
|
|
41
|
+
const baseScale = compact ? Math.min(1, 320 / preset.width) : 1;
|
|
42
|
+
const maxFrameWidth = compact ? preset.width * baseScale : width;
|
|
43
|
+
const [fitScale, setFitScale] = useState(baseScale);
|
|
44
|
+
// The scaled artboard is `transform: scale()`-ed, which does not change its
|
|
45
|
+
// layout box, so the wrapper that reserves vertical space must track the
|
|
46
|
+
// artboard's ACTUAL rendered height. With a fixed height that's known up front;
|
|
47
|
+
// with auto-height we measure it.
|
|
48
|
+
const [measuredHeight, setMeasuredHeight] = useState(fixedHeight ?? null);
|
|
49
|
+
const designMode = renderMode === "design";
|
|
50
|
+
const sketchy = !designMode && style === "sketchy" && !skeleton;
|
|
51
|
+
const roughEnabled = sketchy && roughOverlay;
|
|
52
|
+
const paper = designMode
|
|
53
|
+
? "hsl(var(--background))"
|
|
54
|
+
: "var(--plan-document, hsl(var(--background)))";
|
|
55
|
+
const frameBorder = skeleton
|
|
56
|
+
? "var(--plan-placeholder-line, var(--plan-line, hsl(var(--border))))"
|
|
57
|
+
: "var(--plan-line, hsl(var(--border)))";
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const element = fitRef.current;
|
|
60
|
+
if (!element)
|
|
61
|
+
return;
|
|
62
|
+
const measure = () => {
|
|
63
|
+
const availableWidth = element.clientWidth;
|
|
64
|
+
const nextScale = availableWidth > 0
|
|
65
|
+
? Math.min(baseScale, availableWidth / width)
|
|
66
|
+
: baseScale;
|
|
67
|
+
setFitScale((current) => Math.abs(current - nextScale) < 0.001 ? current : nextScale);
|
|
68
|
+
};
|
|
69
|
+
measure();
|
|
70
|
+
const observer = new ResizeObserver(measure);
|
|
71
|
+
observer.observe(element);
|
|
72
|
+
return () => observer.disconnect();
|
|
73
|
+
}, [baseScale, width]);
|
|
74
|
+
// Track the auto-height artboard's rendered height so the (un-transformed)
|
|
75
|
+
// wrapper reserves exactly the scaled space the frame occupies. Skipped when a
|
|
76
|
+
// fixed height is supplied — there's nothing to measure.
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (fixedHeight != null)
|
|
79
|
+
return;
|
|
80
|
+
const element = ref.current;
|
|
81
|
+
if (!element)
|
|
82
|
+
return;
|
|
83
|
+
const measure = () => {
|
|
84
|
+
const next = element.offsetHeight;
|
|
85
|
+
setMeasuredHeight((current) => current != null && Math.abs(current - next) < 0.5 ? current : next);
|
|
86
|
+
};
|
|
87
|
+
measure();
|
|
88
|
+
const observer = new ResizeObserver(measure);
|
|
89
|
+
observer.observe(element);
|
|
90
|
+
return () => observer.disconnect();
|
|
91
|
+
}, [fixedHeight]);
|
|
92
|
+
// Height the wrapper reserves: the measured (or fixed) artboard height scaled
|
|
93
|
+
// by the fit factor. Falls back to the surface floor before the first measure
|
|
94
|
+
// so SSR / first paint reserves a sensible box rather than collapsing.
|
|
95
|
+
const reservedHeight = (measuredHeight ?? minHeight) * fitScale;
|
|
96
|
+
return (_jsxs("div", { ref: fitRef, className: "plan-kit-wireframe", style: {
|
|
97
|
+
width: "100%",
|
|
98
|
+
maxWidth: maxFrameWidth,
|
|
99
|
+
}, children: [_jsx("div", { style: {
|
|
100
|
+
width: "100%",
|
|
101
|
+
maxWidth: maxFrameWidth,
|
|
102
|
+
height: reservedHeight,
|
|
103
|
+
marginInline: "auto",
|
|
104
|
+
}, children: _jsxs("div", { ref: ref, className: "plan-kit-artboard relative", style: {
|
|
105
|
+
width,
|
|
106
|
+
// Auto-height by default (content-driven, floored at `minHeight`);
|
|
107
|
+
// a fixed `canvasSize` locks the height for canvas artboards.
|
|
108
|
+
...(fixedHeight != null ? { height: fixedHeight } : { minHeight }),
|
|
109
|
+
borderRadius: preset.radius,
|
|
110
|
+
background: paper,
|
|
111
|
+
boxShadow: "0 10px 34px hsl(var(--foreground) / 0.10)",
|
|
112
|
+
...(fitScale !== 1
|
|
113
|
+
? {
|
|
114
|
+
transform: `scale(${fitScale})`,
|
|
115
|
+
transformOrigin: "top left",
|
|
116
|
+
}
|
|
117
|
+
: {}),
|
|
118
|
+
}, children: [_jsx("div", { className: "overflow-hidden", style: {
|
|
119
|
+
borderRadius: preset.radius,
|
|
120
|
+
...(fixedHeight != null
|
|
121
|
+
? { position: "absolute", inset: 0 }
|
|
122
|
+
: { minHeight }),
|
|
123
|
+
}, children: render({ theme, style }) }), !roughEnabled && (_jsx("div", { className: "pointer-events-none absolute inset-0", style: {
|
|
124
|
+
borderRadius: preset.radius,
|
|
125
|
+
border: `1.5px solid ${frameBorder}`,
|
|
126
|
+
} })), _jsx(RoughOverlay, { scopeRef: ref, enabled: roughEnabled, frameRadius: preset.radius, selector: selector })] }) }), caption && (_jsx("p", { className: "mt-2 text-center text-xs text-plan-muted", children: caption }))] }));
|
|
127
|
+
}
|
|
128
|
+
/* -------------------------------------------------------------------------- */
|
|
129
|
+
/* HTML artboard — author HTML, themed + roughened by the renderer. */
|
|
130
|
+
/* -------------------------------------------------------------------------- */
|
|
131
|
+
function HtmlArtboard({ data, ctx, compact, }) {
|
|
132
|
+
const renderMode = data.renderMode ?? "wireframe";
|
|
133
|
+
// Sanitize author HTML/CSS at the render point (defense-in-depth against stored
|
|
134
|
+
// XSS). Self-contained in core via the shared block sanitizer (DOM-based in the
|
|
135
|
+
// browser, regex fallback on the server) so the HTML mockup path renders in any
|
|
136
|
+
// app without the host wiring a sanitizer hook.
|
|
137
|
+
const safeHtml = useMemo(() => sanitizeWireframeHtml(data.html), [data.html]);
|
|
138
|
+
const scopeId = useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
139
|
+
const scopedCss = useMemo(() => {
|
|
140
|
+
const safeCss = sanitizeWireframeCss(data.css);
|
|
141
|
+
// Scope every author selector under this instance's artboard so global
|
|
142
|
+
// selectors (body, *, .app-shell, :root) can't restyle/hide the host app.
|
|
143
|
+
return safeCss
|
|
144
|
+
? scopeDesignCss(safeCss, `[data-plan-design-scope="${scopeId}"]`)
|
|
145
|
+
: "";
|
|
146
|
+
}, [data.css, scopeId]);
|
|
147
|
+
return (_jsx(ArtboardFrame, { surface: data.surface, compact: compact, skeleton: data.skeleton, renderMode: renderMode, selector: HTML_ROUGH_SELECTOR, caption: data.caption, render: ({ theme, style }) => (_jsxs("div", { className: "plan-html-frame", "data-theme": theme, "data-style": style, "data-render-mode": renderMode, "data-plan-design-scope": scopeId, "data-skeleton": data.skeleton ? "true" : undefined, children: [scopedCss && _jsx("style", { children: scopedCss }), _jsx("div", { className: "plan-html-frame-content", dangerouslySetInnerHTML: { __html: safeHtml } })] })) }));
|
|
148
|
+
}
|
|
149
|
+
/* -------------------------------------------------------------------------- */
|
|
150
|
+
/* Kit artboard — declarative kit tree. */
|
|
151
|
+
/* -------------------------------------------------------------------------- */
|
|
152
|
+
function KitArtboard({ data, compact, }) {
|
|
153
|
+
return (_jsx(ArtboardFrame, { surface: data.surface, compact: compact, skeleton: data.skeleton, selector: "[data-rough]", caption: data.caption, render: ({ theme, style }) => (_jsx(KitConfigContext.Provider, { value: { skeleton: data.skeleton, theme, style }, children: renderKitScreen(data.screen ?? []) })) }));
|
|
154
|
+
}
|
|
155
|
+
function renderKitScreen(nodes) {
|
|
156
|
+
if (nodes.length === 1 && nodes[0]?.el === "screen") {
|
|
157
|
+
return renderNodes(nodes);
|
|
158
|
+
}
|
|
159
|
+
// `minHeight` (not `height`) so the screen fills the auto-height artboard floor
|
|
160
|
+
// but grows past it when content is tall, instead of locking to a fixed box.
|
|
161
|
+
return (_jsx(Screen, { pad: "calc(var(--pad) * 1.35)", style: { minHeight: "100%" }, children: renderNodes(nodes) }));
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The bare wireframe surface (no block section / title). Routes to the HTML
|
|
165
|
+
* mockup when `data.html` is present and a sanitizer is wired; otherwise renders
|
|
166
|
+
* the kit tree.
|
|
167
|
+
*/
|
|
168
|
+
function WireframeSurfaceView({ data, ctx, compact, }) {
|
|
169
|
+
if (isHtmlData(data)) {
|
|
170
|
+
return _jsx(HtmlArtboard, { data: data, ctx: ctx, compact: compact });
|
|
171
|
+
}
|
|
172
|
+
return _jsx(KitArtboard, { data: data, compact: compact });
|
|
173
|
+
}
|
|
174
|
+
/* -------------------------------------------------------------------------- */
|
|
175
|
+
/* Block Read / Edit */
|
|
176
|
+
/* -------------------------------------------------------------------------- */
|
|
177
|
+
/** Read-only renderer for a `wireframe` block. */
|
|
178
|
+
export function WireframeBlock({ data, blockId, title, summary, ctx, }) {
|
|
179
|
+
return (_jsxs("section", { className: "an-block plan-block an-wireframe", "data-block-id": blockId, children: [title && _jsx("div", { className: "an-block-label plan-block-label", children: title }), _jsx(WireframeSurfaceView, { data: data, ctx: ctx }), summary && _jsx("p", { className: "mt-5 text-plan-muted", children: summary })] }));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Editor for the `wireframe` block. The wireframe is canvas / agent-patch edited
|
|
183
|
+
* (it never calls `onChange`), so edit mode reuses the read surface — mirroring
|
|
184
|
+
* the plan `WireframeEditor`. The host document editor already wraps the registry
|
|
185
|
+
* edit path in a titled section, so this renders only the surface to avoid
|
|
186
|
+
* double-nesting.
|
|
187
|
+
*/
|
|
188
|
+
export function WireframeEditor({ data, ctx }) {
|
|
189
|
+
return _jsx(WireframeSurfaceView, { data: data, ctx: ctx });
|
|
190
|
+
}
|
|
191
|
+
/** Full client spec for the shared `wireframe` block (schema + MDX + Read/Edit). */
|
|
192
|
+
export const wireframeBlock = defineBlock({
|
|
193
|
+
type: "wireframe",
|
|
194
|
+
schema: wireframeSchema,
|
|
195
|
+
mdx: wireframeMdx,
|
|
196
|
+
Read: WireframeBlock,
|
|
197
|
+
Edit: WireframeEditor,
|
|
198
|
+
placement: ["block"],
|
|
199
|
+
editSurface: "inline",
|
|
200
|
+
label: "Wireframe",
|
|
201
|
+
description: "A sketch wireframe of one screen built from kit primitives (or an HTML mockup), rendered in a chosen surface frame (desktop/mobile/popover/panel/browser).",
|
|
202
|
+
// `surface` is the only required field; `screen` defaults to []. Start on the
|
|
203
|
+
// desktop surface with an empty screen so the canvas/agent can fill it in.
|
|
204
|
+
empty: () => ({ surface: "desktop", screen: [] }),
|
|
205
|
+
});
|
|
206
|
+
//# sourceMappingURL=wireframe.js.map
|