@pipelex/mthds-form 0.31.0 → 0.33.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 +5 -2
- package/dist/brand/index.d.ts +4 -2
- package/dist/brand/index.js +4 -2
- package/dist/brand/index.js.map +1 -1
- package/dist/{chunk-UZNRJWN5.js → chunk-3GO65HWP.js} +3 -31
- package/dist/chunk-3GO65HWP.js.map +1 -0
- package/dist/chunk-4SRSGZWM.js +2447 -0
- package/dist/chunk-4SRSGZWM.js.map +1 -0
- package/dist/{chunk-XVGAQ4RK.js → chunk-IBBAJXIO.js} +4 -4
- package/dist/{chunk-XVGAQ4RK.js.map → chunk-IBBAJXIO.js.map} +1 -1
- package/dist/chunk-QGFR57OH.js +35 -0
- package/dist/chunk-QGFR57OH.js.map +1 -0
- package/dist/{chunk-ENK5QTUK.js → chunk-UKTYADY3.js} +6 -6
- package/dist/{chunk-ENK5QTUK.js.map → chunk-UKTYADY3.js.map} +1 -1
- package/dist/{chunk-HVWE3TTC.js → chunk-ZB4RYUKV.js} +3 -3
- package/dist/{chunk-HVWE3TTC.js.map → chunk-ZB4RYUKV.js.map} +1 -1
- package/dist/{chunk-2UCH4AAO.js → chunk-ZX52CQJ4.js} +3 -3
- package/dist/{chunk-2UCH4AAO.js.map → chunk-ZX52CQJ4.js.map} +1 -1
- package/dist/core/derive.js +2 -2
- package/dist/core/gate.js +3 -3
- package/dist/core/index.js +12 -12
- package/dist/core/values.js +3 -3
- package/dist/{field-renderer-Dz03dpig.d.ts → field-renderer-BYN6YrU-.d.ts} +6 -6
- package/dist/generative/headless/index.d.ts +1733 -0
- package/dist/generative/headless/index.js +6 -0
- package/dist/generative/headless/index.js.map +1 -0
- package/dist/generative/index.d.ts +112 -1710
- package/dist/generative/index.js +628 -2301
- package/dist/generative/index.js.map +1 -1
- package/dist/manifest-D3DLyNEv.d.ts +17 -0
- package/dist/react/index.d.ts +27 -27
- package/dist/react/index.js +7 -7
- package/dist/{styles-BoXPBjF4.d.ts → styles-Bn8byNdo.d.ts} +1 -17
- package/package.json +5 -1
- package/dist/chunk-UZNRJWN5.js.map +0 -1
package/dist/generative/index.js
CHANGED
|
@@ -1,2083 +1,34 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn, headingClass, checkedAccentClass, focusOutlineClass,
|
|
3
|
-
import '../chunk-
|
|
2
|
+
import { cn, headingClass, checkedAccentClass, focusOutlineClass, useResolveUrl, panelSurfaceClass, panelFlatShadowClass, linkTextClass, actionShadowClass, panelRaisedShadowClass, fieldControlClass, ResultRoot, ResultField, FieldRenderer, enumLabeler, useFieldPresentation, ToggleGroup, ToggleGroupItem, selectedFillStrongClass, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, selectedBorderClass, selectedFillClass, isThenable } from '../chunk-UKTYADY3.js';
|
|
3
|
+
import { baseCatalog, catalog, frameComponents, shareAmount, resultFieldAtPath, segmentsUnder, RESULT_ROOT, inputFieldAtPath, definitionChain, unwrapped } from '../chunk-4SRSGZWM.js';
|
|
4
|
+
export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheck, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog } from '../chunk-4SRSGZWM.js';
|
|
4
5
|
import '../chunk-4VAO6BDE.js';
|
|
5
6
|
export { seedInputs } from '../chunk-VH5CDQDR.js';
|
|
6
7
|
import '../chunk-L23R3JNQ.js';
|
|
7
8
|
import '../chunk-56WECFBD.js';
|
|
9
|
+
import '../chunk-ZX52CQJ4.js';
|
|
10
|
+
import '../chunk-GHVVULHY.js';
|
|
11
|
+
import { readImageContent, viewableUrl, readDateContent } from '../chunk-QQK6Y55E.js';
|
|
12
|
+
export { brandManifestSchema } from '../chunk-QGFR57OH.js';
|
|
13
|
+
import '../chunk-3GO65HWP.js';
|
|
14
|
+
import '../chunk-ZB4RYUKV.js';
|
|
15
|
+
import '../chunk-FABY3DEY.js';
|
|
16
|
+
import '../chunk-XCO6GTEC.js';
|
|
8
17
|
import '../chunk-E6BIXJ6C.js';
|
|
9
18
|
import '../chunk-XO5OENNF.js';
|
|
10
|
-
import '../chunk-GHVVULHY.js';
|
|
11
|
-
import { readImageContent, viewableUrl, readDateContent, isNativeValueNode, formatDateContent, isNativeHtmlNode, isNativeDateNode, isNativeCompositeNode } from '../chunk-QQK6Y55E.js';
|
|
12
|
-
import { APP_STYLES } from '../chunk-UZNRJWN5.js';
|
|
13
|
-
export { brandManifestSchema } from '../chunk-UZNRJWN5.js';
|
|
14
|
-
import '../chunk-HVWE3TTC.js';
|
|
15
19
|
import '../chunk-OD3VYXUY.js';
|
|
16
20
|
import '../chunk-WYH56SOZ.js';
|
|
17
21
|
import { hasOwnProp } from '../chunk-V3OV2XQT.js';
|
|
18
|
-
import '../chunk-FABY3DEY.js';
|
|
19
|
-
import '../chunk-XCO6GTEC.js';
|
|
20
22
|
import '../chunk-GKV77RAS.js';
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
import { z } from 'zod';
|
|
24
|
-
import * as React4 from 'react';
|
|
25
|
-
import { defineRegistry, useStateValue, useStateStore, useBoundProp, useFieldValidation, useRepeatScope, JSONUIProvider, Renderer } from '@json-render/react';
|
|
23
|
+
import * as React6 from 'react';
|
|
24
|
+
import { defineRegistry, useStateValue, useRepeatScope, useStateStore, useBoundProp, useFieldValidation, useOptionalValidation, JSONUIProvider, Renderer, useVisibility } from '@json-render/react';
|
|
26
25
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
(s) => ({
|
|
32
|
-
spec: s.object({
|
|
33
|
-
root: s.string(),
|
|
34
|
-
elements: s.record(
|
|
35
|
-
s.object({
|
|
36
|
-
type: s.ref("catalog.components"),
|
|
37
|
-
props: s.propsOf("catalog.components"),
|
|
38
|
-
children: s.array(s.string()),
|
|
39
|
-
slots: { ...s.record(s.array(s.string())), ...s.optional() },
|
|
40
|
-
visible: { ...s.any(), ...s.optional() },
|
|
41
|
-
repeat: { ...s.any(), ...s.optional() }
|
|
42
|
-
})
|
|
43
|
-
)
|
|
44
|
-
}),
|
|
45
|
-
catalog: s.object({
|
|
46
|
-
components: s.map({
|
|
47
|
-
props: s.zod(),
|
|
48
|
-
slots: s.array(s.string()),
|
|
49
|
-
description: s.string(),
|
|
50
|
-
example: s.any()
|
|
51
|
-
}),
|
|
52
|
-
actions: s.map({
|
|
53
|
-
params: s.zod(),
|
|
54
|
-
description: s.string()
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
}),
|
|
58
|
-
{
|
|
59
|
-
// The runtime handles these four without a registry handler; the names and
|
|
60
|
-
// the wording are the React schema's, so a model that has seen json-render
|
|
61
|
-
// before recognises them. The validator reads them to know which actions
|
|
62
|
-
// need no handler, and `designerCatalog()` lists them first, marked
|
|
63
|
-
// built-in, so the method's prompt names them beside the catalog's own.
|
|
64
|
-
builtInActions: [
|
|
65
|
-
{
|
|
66
|
-
name: "setState",
|
|
67
|
-
description: "Update a value in the state model at the given statePath. Params: { statePath: string, value: any }"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: "pushState",
|
|
71
|
-
description: "Append an item to an array in state. Params: { statePath: string, value: any, clearStatePath?: string }."
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: "removeState",
|
|
75
|
-
description: "Remove an item from an array in state by index. Params: { statePath: string, index: number }"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: "validateForm",
|
|
79
|
-
description: "Validate all registered form fields and write the result to state. Params: { statePath?: string }. Defaults to /formValidation."
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
}
|
|
83
|
-
);
|
|
84
|
-
var validationCheckSchema = z.array(
|
|
85
|
-
z.object({
|
|
86
|
-
type: z.string(),
|
|
87
|
-
message: z.string(),
|
|
88
|
-
args: z.record(z.string(), z.unknown()).optional()
|
|
89
|
-
})
|
|
90
|
-
).nullable();
|
|
91
|
-
var validateOnSchema = z.enum(["change", "blur", "submit"]).nullable();
|
|
92
|
-
var shadcnComponentDefinitions = {
|
|
93
|
-
// ── Layout ────────────────────────────────────────────────────────────────
|
|
94
|
-
Card: {
|
|
95
|
-
props: z.object({
|
|
96
|
-
title: z.string().nullable(),
|
|
97
|
-
description: z.string().nullable(),
|
|
98
|
-
maxWidth: z.enum(["sm", "md", "lg", "full"]).nullable(),
|
|
99
|
-
centered: z.boolean().nullable(),
|
|
100
|
-
className: z.string().nullable().describe("Additional CSS classes")
|
|
101
|
-
}),
|
|
102
|
-
slots: ["default"],
|
|
103
|
-
description: "Container card for content sections. Use for forms/content boxes, NOT for page headers.",
|
|
104
|
-
example: { title: "Overview", description: "Your account summary" }
|
|
105
|
-
},
|
|
106
|
-
Stack: {
|
|
107
|
-
props: z.object({
|
|
108
|
-
direction: z.enum(["horizontal", "vertical"]).nullable(),
|
|
109
|
-
gap: z.enum(["none", "sm", "md", "lg", "xl"]).nullable(),
|
|
110
|
-
align: z.enum(["start", "center", "end", "stretch"]).nullable(),
|
|
111
|
-
justify: z.enum(["start", "center", "end", "between", "around"]).nullable(),
|
|
112
|
-
className: z.string().nullable().describe("Additional CSS classes")
|
|
113
|
-
}),
|
|
114
|
-
slots: ["default"],
|
|
115
|
-
description: "Flex container for layouts",
|
|
116
|
-
example: { direction: "vertical", gap: "md" }
|
|
117
|
-
},
|
|
118
|
-
Grid: {
|
|
119
|
-
props: z.object({
|
|
120
|
-
columns: z.number().nullable(),
|
|
121
|
-
gap: z.enum(["sm", "md", "lg", "xl"]).nullable(),
|
|
122
|
-
className: z.string().nullable().describe("Additional CSS classes")
|
|
123
|
-
}),
|
|
124
|
-
slots: ["default"],
|
|
125
|
-
description: "Grid layout (1-6 columns)",
|
|
126
|
-
example: { columns: 3, gap: "md" }
|
|
127
|
-
},
|
|
128
|
-
Separator: {
|
|
129
|
-
props: z.object({
|
|
130
|
-
orientation: z.enum(["horizontal", "vertical"]).nullable()
|
|
131
|
-
}),
|
|
132
|
-
description: "Visual separator line"
|
|
133
|
-
},
|
|
134
|
-
Collapsible: {
|
|
135
|
-
props: z.object({
|
|
136
|
-
title: z.string(),
|
|
137
|
-
defaultOpen: z.boolean().nullable()
|
|
138
|
-
}),
|
|
139
|
-
slots: ["default"],
|
|
140
|
-
description: "Collapsible section with trigger. Children render inside."
|
|
141
|
-
},
|
|
142
|
-
// ── Content ───────────────────────────────────────────────────────────────
|
|
143
|
-
Heading: {
|
|
144
|
-
props: z.object({
|
|
145
|
-
text: z.string(),
|
|
146
|
-
level: z.enum(["h1", "h2", "h3", "h4"]).nullable()
|
|
147
|
-
}),
|
|
148
|
-
description: "Heading text (h1-h4)",
|
|
149
|
-
example: { text: "Welcome", level: "h1" }
|
|
150
|
-
},
|
|
151
|
-
Text: {
|
|
152
|
-
props: z.object({
|
|
153
|
-
text: z.string(),
|
|
154
|
-
variant: z.enum(["body", "caption", "muted", "lead", "code"]).nullable()
|
|
155
|
-
}),
|
|
156
|
-
description: "Paragraph text",
|
|
157
|
-
example: { text: "Hello, world!" }
|
|
158
|
-
},
|
|
159
|
-
Avatar: {
|
|
160
|
-
props: z.object({
|
|
161
|
-
src: z.string().nullable(),
|
|
162
|
-
name: z.string(),
|
|
163
|
-
size: z.enum(["sm", "md", "lg"]).nullable()
|
|
164
|
-
}),
|
|
165
|
-
description: "User avatar with fallback initials",
|
|
166
|
-
example: { name: "Jane Doe", size: "md" }
|
|
167
|
-
},
|
|
168
|
-
Badge: {
|
|
169
|
-
props: z.object({
|
|
170
|
-
text: z.string(),
|
|
171
|
-
variant: z.enum(["default", "secondary", "destructive", "outline"]).nullable()
|
|
172
|
-
}),
|
|
173
|
-
description: "Status badge",
|
|
174
|
-
example: { text: "Active", variant: "default" }
|
|
175
|
-
},
|
|
176
|
-
Alert: {
|
|
177
|
-
props: z.object({
|
|
178
|
-
title: z.string(),
|
|
179
|
-
message: z.string().nullable(),
|
|
180
|
-
type: z.enum(["info", "success", "warning", "error"]).nullable()
|
|
181
|
-
}),
|
|
182
|
-
description: "Alert banner",
|
|
183
|
-
example: {
|
|
184
|
-
title: "Note",
|
|
185
|
-
message: "Your changes have been saved.",
|
|
186
|
-
type: "success"
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
Progress: {
|
|
190
|
-
props: z.object({
|
|
191
|
-
value: z.number(),
|
|
192
|
-
max: z.number().nullable(),
|
|
193
|
-
label: z.string().nullable()
|
|
194
|
-
}),
|
|
195
|
-
description: "Progress bar (value 0-100)",
|
|
196
|
-
example: { value: 65, max: 100, label: "Upload progress" }
|
|
197
|
-
},
|
|
198
|
-
// ── Inputs ────────────────────────────────────────────────────────────────
|
|
199
|
-
Input: {
|
|
200
|
-
props: z.object({
|
|
201
|
-
label: z.string(),
|
|
202
|
-
name: z.string(),
|
|
203
|
-
type: z.enum(["text", "email", "password", "number"]).nullable(),
|
|
204
|
-
placeholder: z.string().nullable(),
|
|
205
|
-
value: z.string().nullable(),
|
|
206
|
-
checks: validationCheckSchema,
|
|
207
|
-
validateOn: validateOnSchema
|
|
208
|
-
}),
|
|
209
|
-
events: ["submit", "focus", "blur"],
|
|
210
|
-
description: "Text input field. Use { $bindState } on value for two-way binding. Use checks for validation (e.g. required, email, minLength). validateOn controls timing (default: blur).",
|
|
211
|
-
example: {
|
|
212
|
-
label: "Email",
|
|
213
|
-
name: "email",
|
|
214
|
-
type: "email",
|
|
215
|
-
placeholder: "you@example.com"
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
Textarea: {
|
|
219
|
-
props: z.object({
|
|
220
|
-
label: z.string(),
|
|
221
|
-
name: z.string(),
|
|
222
|
-
placeholder: z.string().nullable(),
|
|
223
|
-
rows: z.number().nullable(),
|
|
224
|
-
value: z.string().nullable(),
|
|
225
|
-
checks: validationCheckSchema,
|
|
226
|
-
validateOn: validateOnSchema
|
|
227
|
-
}),
|
|
228
|
-
description: "Multi-line text input. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: blur)."
|
|
229
|
-
},
|
|
230
|
-
Select: {
|
|
231
|
-
props: z.object({
|
|
232
|
-
label: z.string(),
|
|
233
|
-
name: z.string(),
|
|
234
|
-
options: z.array(z.string().min(1)),
|
|
235
|
-
placeholder: z.string().nullable(),
|
|
236
|
-
value: z.string().nullable(),
|
|
237
|
-
checks: validationCheckSchema,
|
|
238
|
-
validateOn: validateOnSchema
|
|
239
|
-
}),
|
|
240
|
-
events: ["change"],
|
|
241
|
-
description: "Dropdown select input. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
242
|
-
},
|
|
243
|
-
Radio: {
|
|
244
|
-
props: z.object({
|
|
245
|
-
label: z.string(),
|
|
246
|
-
name: z.string(),
|
|
247
|
-
options: z.array(z.string().min(1)),
|
|
248
|
-
value: z.string().nullable(),
|
|
249
|
-
checks: validationCheckSchema,
|
|
250
|
-
validateOn: validateOnSchema
|
|
251
|
-
}),
|
|
252
|
-
events: ["change"],
|
|
253
|
-
description: "Radio button group. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
254
|
-
},
|
|
255
|
-
Checkbox: {
|
|
256
|
-
props: z.object({
|
|
257
|
-
label: z.string(),
|
|
258
|
-
name: z.string(),
|
|
259
|
-
checked: z.boolean().nullable(),
|
|
260
|
-
checks: validationCheckSchema,
|
|
261
|
-
validateOn: validateOnSchema
|
|
262
|
-
}),
|
|
263
|
-
events: ["change"],
|
|
264
|
-
description: "Checkbox input. Use { $bindState } on checked for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
265
|
-
},
|
|
266
|
-
Switch: {
|
|
267
|
-
props: z.object({
|
|
268
|
-
label: z.string(),
|
|
269
|
-
name: z.string(),
|
|
270
|
-
checked: z.boolean().nullable(),
|
|
271
|
-
checks: validationCheckSchema,
|
|
272
|
-
validateOn: validateOnSchema
|
|
273
|
-
}),
|
|
274
|
-
events: ["change"],
|
|
275
|
-
description: "Toggle switch. Use { $bindState } on checked for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
276
|
-
},
|
|
277
|
-
// ── Actions ───────────────────────────────────────────────────────────────
|
|
278
|
-
Button: {
|
|
279
|
-
props: z.object({
|
|
280
|
-
label: z.string(),
|
|
281
|
-
variant: z.enum(["primary", "secondary", "danger"]).nullable(),
|
|
282
|
-
disabled: z.boolean().nullable()
|
|
283
|
-
}),
|
|
284
|
-
events: ["press"],
|
|
285
|
-
description: "Clickable button. Bind on.press for handler.",
|
|
286
|
-
example: { label: "Submit", variant: "primary" }
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
// src/generative/components.ts
|
|
291
|
-
var shadcn = shadcnComponentDefinitions;
|
|
292
|
-
var PICKED_SHADCN = [
|
|
293
|
-
"Card",
|
|
294
|
-
"Stack",
|
|
295
|
-
"Grid",
|
|
296
|
-
"Separator",
|
|
297
|
-
"Heading",
|
|
298
|
-
"Text",
|
|
299
|
-
"Badge",
|
|
300
|
-
"Alert",
|
|
301
|
-
"Collapsible",
|
|
302
|
-
"Progress",
|
|
303
|
-
"Avatar",
|
|
304
|
-
"Input",
|
|
305
|
-
"Textarea",
|
|
306
|
-
"Select",
|
|
307
|
-
"Radio",
|
|
308
|
-
"Checkbox",
|
|
309
|
-
"Switch",
|
|
310
|
-
"Button"
|
|
311
|
-
];
|
|
312
|
-
var CUSTOM_COMPONENTS = [
|
|
313
|
-
"Split",
|
|
314
|
-
"Tabs",
|
|
315
|
-
"Steps",
|
|
316
|
-
"Icon",
|
|
317
|
-
"Segmented",
|
|
318
|
-
"NumberInput",
|
|
319
|
-
"MthdsField",
|
|
320
|
-
"MthdsResult",
|
|
321
|
-
"DataTable",
|
|
322
|
-
"Metric"
|
|
323
|
-
];
|
|
324
|
-
var METRIC_FORMATS = ["plain", "integer", "decimal", "compact"];
|
|
325
|
-
var ICON_NAMES = [
|
|
326
|
-
"Sparkles",
|
|
327
|
-
"Rocket",
|
|
328
|
-
"Compass",
|
|
329
|
-
"Map",
|
|
330
|
-
"MapPin",
|
|
331
|
-
"Route",
|
|
332
|
-
"Plane",
|
|
333
|
-
"Train",
|
|
334
|
-
"Car",
|
|
335
|
-
"Ship",
|
|
336
|
-
"Hotel",
|
|
337
|
-
"Home",
|
|
338
|
-
"Building2",
|
|
339
|
-
"Landmark",
|
|
340
|
-
"Globe",
|
|
341
|
-
"Mountain",
|
|
342
|
-
"Leaf",
|
|
343
|
-
"Sun",
|
|
344
|
-
"Moon",
|
|
345
|
-
"Calendar",
|
|
346
|
-
"Clock",
|
|
347
|
-
"Hourglass",
|
|
348
|
-
"Users",
|
|
349
|
-
"User",
|
|
350
|
-
"Baby",
|
|
351
|
-
"Accessibility",
|
|
352
|
-
"Heart",
|
|
353
|
-
"Star",
|
|
354
|
-
"Utensils",
|
|
355
|
-
"Coffee",
|
|
356
|
-
"Music",
|
|
357
|
-
"Camera",
|
|
358
|
-
"Image",
|
|
359
|
-
"Ticket",
|
|
360
|
-
"Gift",
|
|
361
|
-
"Wallet",
|
|
362
|
-
"Banknote",
|
|
363
|
-
"Coins",
|
|
364
|
-
"Receipt",
|
|
365
|
-
"Percent",
|
|
366
|
-
"Hash",
|
|
367
|
-
"TrendingUp",
|
|
368
|
-
"BarChart3",
|
|
369
|
-
"FileText",
|
|
370
|
-
"Upload",
|
|
371
|
-
"Paperclip",
|
|
372
|
-
"Mail",
|
|
373
|
-
"Phone",
|
|
374
|
-
"Tag",
|
|
375
|
-
"Layers",
|
|
376
|
-
"ListChecks",
|
|
377
|
-
"CheckCircle2",
|
|
378
|
-
"AlertCircle",
|
|
379
|
-
"Info",
|
|
380
|
-
"Shield",
|
|
381
|
-
"Flag",
|
|
382
|
-
"Bookmark",
|
|
383
|
-
"Briefcase",
|
|
384
|
-
"Package",
|
|
385
|
-
"Truck",
|
|
386
|
-
"Lightbulb",
|
|
387
|
-
"Zap",
|
|
388
|
-
"Pencil",
|
|
389
|
-
"Send"
|
|
390
|
-
];
|
|
391
|
-
var components = {
|
|
392
|
-
// ── Layout (shadcn) ────────────────────────────────────────────────────
|
|
393
|
-
Card: {
|
|
394
|
-
...shadcn.Card,
|
|
395
|
-
props: shadcn.Card.props.omit({ className: true, maxWidth: true, centered: true }),
|
|
396
|
-
description: 'Container card for content sections. Use for forms/content boxes, NOT for page headers. Its optional "title" renders as an h3, so a titled Card sits under an h2.'
|
|
397
|
-
},
|
|
398
|
-
Stack: { ...shadcn.Stack, props: shadcn.Stack.props.omit({ className: true }) },
|
|
399
|
-
Grid: { ...shadcn.Grid, props: shadcn.Grid.props.omit({ className: true }) },
|
|
400
|
-
Separator: shadcn.Separator,
|
|
401
|
-
Collapsible: shadcn.Collapsible,
|
|
402
|
-
// ── Content (shadcn) ───────────────────────────────────────────────────
|
|
403
|
-
Heading: shadcn.Heading,
|
|
404
|
-
Text: shadcn.Text,
|
|
405
|
-
Badge: shadcn.Badge,
|
|
406
|
-
Alert: shadcn.Alert,
|
|
407
|
-
Progress: shadcn.Progress,
|
|
408
|
-
Avatar: {
|
|
409
|
-
...shadcn.Avatar,
|
|
410
|
-
description: `A round avatar showing the initials of "name" - bind it to a person's name in the state ({ "$state" } or { "$item" }); never set "src".`
|
|
411
|
-
},
|
|
412
|
-
// ── Inputs (shadcn) ────────────────────────────────────────────────────
|
|
413
|
-
Input: shadcn.Input,
|
|
414
|
-
Textarea: shadcn.Textarea,
|
|
415
|
-
Select: shadcn.Select,
|
|
416
|
-
Radio: shadcn.Radio,
|
|
417
|
-
Checkbox: shadcn.Checkbox,
|
|
418
|
-
Switch: shadcn.Switch,
|
|
419
|
-
Button: shadcn.Button,
|
|
420
|
-
// ── Layout (ours) ──────────────────────────────────────────────────────
|
|
421
|
-
Split: {
|
|
422
|
-
props: z.object({
|
|
423
|
-
ratio: z.enum(["1:1", "1:2", "2:1"]).nullable(),
|
|
424
|
-
gap: z.enum(["md", "lg", "xl"]).nullable()
|
|
425
|
-
}),
|
|
426
|
-
slots: ["default"],
|
|
427
|
-
description: 'Two columns side by side, from exactly two children: the first is the left column. "1:2" puts a narrow rail (a summary, the essentials, the run) beside the work; "2:1" the reverse; "1:1" two halves. Columns stack on a narrow screen.',
|
|
428
|
-
example: { ratio: "1:2", gap: "lg" }
|
|
429
|
-
},
|
|
430
|
-
Tabs: {
|
|
431
|
-
props: z.object({
|
|
432
|
-
tabs: z.array(z.object({ label: z.string(), value: z.string() })).min(2)
|
|
433
|
-
}),
|
|
434
|
-
slots: ["default"],
|
|
435
|
-
description: "Concerns of equal weight, one visible at a time. Exactly one child per tab, in the same order - each child is that tab's panel (usually a Stack). The first tab opens. The active tab is the component's own state, never /state.",
|
|
436
|
-
example: {
|
|
437
|
-
tabs: [
|
|
438
|
-
{ label: "The trip", value: "trip" },
|
|
439
|
-
{ label: "Who is going", value: "people" }
|
|
440
|
-
]
|
|
441
|
-
}
|
|
442
|
-
},
|
|
443
|
-
Steps: {
|
|
444
|
-
props: z.object({
|
|
445
|
-
steps: z.array(z.string()).min(2),
|
|
446
|
-
nextLabel: z.string().nullable(),
|
|
447
|
-
backLabel: z.string().nullable()
|
|
448
|
-
}),
|
|
449
|
-
slots: ["default"],
|
|
450
|
-
description: "A journey with a natural order: a numbered indicator, one panel at a time, and its own Back and Next. Exactly one child per step, in order - each child is that step's panel. Put the Button that runs inside the LAST panel; Next disappears there. The current step is the component's own state, never /state.",
|
|
451
|
-
example: { steps: ["Where", "Who", "How"], nextLabel: "Continue" }
|
|
452
|
-
},
|
|
453
|
-
Icon: {
|
|
454
|
-
props: z.object({
|
|
455
|
-
name: z.enum(ICON_NAMES),
|
|
456
|
-
size: z.enum(["sm", "md", "lg"]).nullable()
|
|
457
|
-
}),
|
|
458
|
-
slots: [],
|
|
459
|
-
description: "A decorative icon, one of the listed lucide names, to give a section or a figure a face: put it in a horizontal Stack beside a Heading or a Metric. It carries no meaning on its own and no text.",
|
|
460
|
-
example: { name: "Plane", size: "md" }
|
|
461
|
-
},
|
|
462
|
-
// ── Inputs (ours) ──────────────────────────────────────────────────────
|
|
463
|
-
Segmented: {
|
|
464
|
-
props: z.object({
|
|
465
|
-
label: z.string(),
|
|
466
|
-
name: z.string(),
|
|
467
|
-
options: z.array(z.string().min(1)).min(2).max(6),
|
|
468
|
-
value: z.string().nullable()
|
|
469
|
-
}),
|
|
470
|
-
slots: [],
|
|
471
|
-
description: `A choice of two to six options as a row of pills, one selected - the app's answer to a short Select. "options" are EXACTLY the brief's choices, spelled exactly; bind "value" with { "$bindState": "/inputs/..." }.`,
|
|
472
|
-
example: {
|
|
473
|
-
label: "Pace",
|
|
474
|
-
name: "pace",
|
|
475
|
-
options: ["slow", "balanced", "packed"],
|
|
476
|
-
value: { $bindState: "/inputs/request/pace" }
|
|
477
|
-
}
|
|
478
|
-
},
|
|
479
|
-
NumberInput: {
|
|
480
|
-
props: z.object({
|
|
481
|
-
label: z.string(),
|
|
482
|
-
name: z.string(),
|
|
483
|
-
value: z.number().nullable(),
|
|
484
|
-
placeholder: z.string().nullable(),
|
|
485
|
-
unit: z.string().nullable(),
|
|
486
|
-
min: z.number().nullable(),
|
|
487
|
-
max: z.number().nullable(),
|
|
488
|
-
step: z.number().nullable()
|
|
489
|
-
}),
|
|
490
|
-
slots: [],
|
|
491
|
-
description: 'A figure the person types: writes a NUMBER to the bound path, which Input type "number" does not (it writes text). Bind "value" with { "$bindState": "/inputs/..." }. "unit" is a short suffix ONLY when the brief states one; "min", "max" and "step" only when the brief states them.',
|
|
492
|
-
example: {
|
|
493
|
-
label: "Budget",
|
|
494
|
-
name: "budget",
|
|
495
|
-
value: { $bindState: "/inputs/request/budget" },
|
|
496
|
-
placeholder: "2500"
|
|
497
|
-
}
|
|
498
|
-
},
|
|
499
|
-
// ── The escape hatches and the bound equivalents (ours) ────────────────
|
|
500
|
-
MthdsField: {
|
|
501
|
-
props: z.object({
|
|
502
|
-
path: z.string(),
|
|
503
|
-
// The page words the label and the line under it, as it words every other control.
|
|
504
|
-
label: z.string().nullable(),
|
|
505
|
-
hint: z.string().nullable()
|
|
506
|
-
}),
|
|
507
|
-
slots: [],
|
|
508
|
-
description: `The kernel's own control for ONE input, bound two-way at "path" (a /inputs path from the brief). Use it for every path the brief marks as delegated - a file, a date, a list, a structure you would rather not lay out - and for any scalar you would rather not style. It renders the descriptor's label and description unless the page words them: "label" replaces the label, "hint" the line under it. Inside a repeat, "path" is the item's field name relative to the item ("lines"), never an $item expression.`,
|
|
509
|
-
example: { path: "/inputs/source" }
|
|
510
|
-
},
|
|
511
|
-
MthdsResult: {
|
|
512
|
-
props: z.object({
|
|
513
|
-
path: z.string(),
|
|
514
|
-
hideLabel: z.boolean().nullable()
|
|
515
|
-
}),
|
|
516
|
-
slots: [],
|
|
517
|
-
description: `The kernel's own read-only rendering of ONE result subtree at "path" (a /result path from the brief). Use it for every path the brief marks as delegated - a file, a date, a document, prose, markup - and for any structure you choose not to lay out. It renders its own label unless hideLabel is true. Inside a repeat, "path" is the item's field name relative to the item ("teams"), never an $item expression - the way to delegate one subtree of every item.`,
|
|
518
|
-
example: { path: "/result/issued_on" }
|
|
519
|
-
},
|
|
520
|
-
DataTable: {
|
|
521
|
-
props: z.object({
|
|
522
|
-
rows: z.any(),
|
|
523
|
-
// A column says how its cells read, from the kind the brief states.
|
|
524
|
-
columns: z.array(
|
|
525
|
-
z.object({
|
|
526
|
-
path: z.string(),
|
|
527
|
-
label: z.string(),
|
|
528
|
-
format: z.enum(["text", "date", "number"]).nullable().optional()
|
|
529
|
-
})
|
|
530
|
-
),
|
|
531
|
-
caption: z.string().nullable()
|
|
532
|
-
}),
|
|
533
|
-
slots: [],
|
|
534
|
-
description: 'A table over a list of structures. "rows" MUST be { "$state": "/path/to/the/list" } (never inline rows); each column names a field of one item by its relative path ("label", "unit_price"), the header to show for it, and how its cells read: "date" for a date path (written "9 Mar 2025"), "number" for a number path (digits grouped), "text" otherwise.',
|
|
535
|
-
example: {
|
|
536
|
-
rows: { $state: "/result/lines" },
|
|
537
|
-
columns: [
|
|
538
|
-
{ path: "label", label: "Item" },
|
|
539
|
-
{ path: "quantity", label: "Qty" }
|
|
540
|
-
]
|
|
541
|
-
}
|
|
542
|
-
},
|
|
543
|
-
Metric: {
|
|
544
|
-
props: z.object({
|
|
545
|
-
label: z.string(),
|
|
546
|
-
value: z.any(),
|
|
547
|
-
unit: z.string().nullable(),
|
|
548
|
-
format: z.enum(METRIC_FORMATS).nullable()
|
|
549
|
-
}),
|
|
550
|
-
slots: [],
|
|
551
|
-
description: 'A labelled figure - the one number a reader looks for first. "value" is bound with { "$state": "/path" } (never inline); "unit" is a short suffix and ONLY one the brief states (a currency the structure carries, "%" for a rate, "M" when the brief says "in millions") - never invent a currency the state does not carry; "format" is plain, integer, decimal (two places) or compact.',
|
|
552
|
-
example: { label: "Total", value: { $state: "/result/total" }, unit: "EUR", format: "decimal" }
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
var actions = {
|
|
556
|
-
run: {
|
|
557
|
-
params: z.object({}),
|
|
558
|
-
description: "Start the run with the current /inputs. The host handles it; an input page binds it to its one Button after validateForm."
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
defineCatalog(generativeSchema, { components, actions });
|
|
562
|
-
var generativeComponents = components;
|
|
563
|
-
var generativeActions = actions;
|
|
564
|
-
var FRAMES = ["page", "composer", "result"];
|
|
565
|
-
var COMPOSER_COMPONENTS = ["Composer", "FieldGroup"];
|
|
566
|
-
var RESULT_COMPONENTS = [
|
|
567
|
-
"ResultHeader",
|
|
568
|
-
"ProportionBar",
|
|
569
|
-
"Swatches",
|
|
570
|
-
"Picture",
|
|
571
|
-
"Fact",
|
|
572
|
-
"Detail",
|
|
573
|
-
"DateText",
|
|
574
|
-
"TextList"
|
|
575
|
-
];
|
|
576
|
-
var FRAME_COMPONENTS = [...COMPOSER_COMPONENTS, ...RESULT_COMPONENTS];
|
|
577
|
-
var frameComponents = {
|
|
578
|
-
Composer: {
|
|
579
|
-
props: z.object({
|
|
580
|
-
headline: z.string(),
|
|
581
|
-
lede: z.string().nullable(),
|
|
582
|
-
runLabel: z.string(),
|
|
583
|
-
columns: z.enum(["1", "2"]).nullable(),
|
|
584
|
-
notes: z.array(z.string()).nullable()
|
|
585
|
-
}),
|
|
586
|
-
slots: ["default"],
|
|
587
|
-
events: ["press"],
|
|
588
|
-
description: `The composer: the page's headline (rendered as the h1) and one muted line under it, then a single raised panel holding its children - the inputs - in one column, or two columns side by side when "columns" is "2", and at the panel's foot the host's action row: how long a run takes, as the host knows it, and the one button that runs the method, worded by "runLabel". The action row stays on screen while a long panel scrolls. It is the control that runs the method: bind on.press to validateForm then run. "notes" are a few short lines set under the panel, each after a check mark, in two columns: what one run gives back, in a person's words.`,
|
|
589
|
-
example: {
|
|
590
|
-
headline: "A day-by-day plan for your trip",
|
|
591
|
-
lede: "Tell us who is going, where and when.",
|
|
592
|
-
runLabel: "Plan my trip",
|
|
593
|
-
columns: "2"
|
|
594
|
-
}
|
|
595
|
-
},
|
|
596
|
-
FieldGroup: {
|
|
597
|
-
props: z.object({ title: z.string().nullable() }),
|
|
598
|
-
slots: ["default"],
|
|
599
|
-
description: "A quiet group of inputs inside a panel: an optional small h2 title, then its children stacked with even spacing. No box, no rule: the panel around it is the surface.",
|
|
600
|
-
example: { title: "Where and when" }
|
|
601
|
-
},
|
|
602
|
-
ResultHeader: {
|
|
603
|
-
props: z.object({
|
|
604
|
-
eyebrow: z.string().nullable(),
|
|
605
|
-
title: z.string(),
|
|
606
|
-
subtitle: z.string().nullable()
|
|
607
|
-
}),
|
|
608
|
-
slots: [],
|
|
609
|
-
description: `The result's heading: a small eyebrow in the accent colour, the title (rendered as the h1) and one muted line under it, with the host's actions on the result (download, share) at the right. Text props may be read from the state with { "$state" } or { "$template" }.`,
|
|
610
|
-
example: {
|
|
611
|
-
eyebrow: "Your plan",
|
|
612
|
-
title: { $state: "/result/title" },
|
|
613
|
-
subtitle: { $template: "${/result/currency} ${/result/estimated_total} estimated" }
|
|
614
|
-
}
|
|
615
|
-
},
|
|
616
|
-
ProportionBar: {
|
|
617
|
-
props: z.object({
|
|
618
|
-
label: z.string(),
|
|
619
|
-
total: z.number().nullable(),
|
|
620
|
-
of: z.number().nullable(),
|
|
621
|
-
unit: z.string().nullable(),
|
|
622
|
-
items: z.array(z.any()).nullable(),
|
|
623
|
-
labelKey: z.string(),
|
|
624
|
-
valueKey: z.string()
|
|
625
|
-
}),
|
|
626
|
-
slots: [],
|
|
627
|
-
description: 'A labelled total over its parts, in a raised panel: the label and the total in large figures ("of" a ceiling when there is one), then one bar split in proportion to each part, and a legend naming each part with its amount. "items" is { "$state": ... } on a list of structures; "labelKey" and "valueKey" name the member of one item that labels it and the number that sizes it. "unit" is a currency or unit the state carries, read with { "$state" }.',
|
|
628
|
-
example: {
|
|
629
|
-
label: "Estimated cost",
|
|
630
|
-
total: { $state: "/result/estimated_total" },
|
|
631
|
-
unit: { $state: "/result/currency" },
|
|
632
|
-
items: { $state: "/result/costs" },
|
|
633
|
-
labelKey: "category",
|
|
634
|
-
valueKey: "amount"
|
|
635
|
-
}
|
|
636
|
-
},
|
|
637
|
-
Swatches: {
|
|
638
|
-
props: z.object({ colors: z.array(z.string()) }),
|
|
639
|
-
slots: [],
|
|
640
|
-
description: 'A row of colour swatches, each a small tile filled with the colour and its value written under it in mono. "colors" is a list of colour values, each read from a text path ({ "$state" }, or { "$item" } inside a repeat).',
|
|
641
|
-
example: { colors: [{ $item: "colors/primary" }, { $item: "colors/accent" }] }
|
|
642
|
-
},
|
|
643
|
-
Picture: {
|
|
644
|
-
props: z.object({
|
|
645
|
-
path: z.string(),
|
|
646
|
-
alt: z.string().nullable(),
|
|
647
|
-
aspect: z.enum(["16:9", "4:3", "1:1", "auto"]).nullable()
|
|
648
|
-
}),
|
|
649
|
-
slots: [],
|
|
650
|
-
description: 'A picture the run produced, shown whole and edge to edge in its column with a hairline border, cropped to "aspect" when one is set. "path" is an image path of the brief, literally ("/result/cover"), or relative to the item inside a repeat ("" for the item itself, when the repeat is over a list of images).',
|
|
651
|
-
example: { path: "/result/cover", alt: "The cover", aspect: "16:9" }
|
|
652
|
-
},
|
|
653
|
-
Fact: {
|
|
654
|
-
props: z.object({
|
|
655
|
-
label: z.string(),
|
|
656
|
-
value: z.any(),
|
|
657
|
-
detail: z.string().nullable()
|
|
658
|
-
}),
|
|
659
|
-
slots: [],
|
|
660
|
-
description: 'One fact as a small boxed tile: a muted label, the value under it, and an optional muted detail. Several in a Grid make a band of facts. "value" is a scalar read with { "$state" } or { "$template" }.',
|
|
661
|
-
example: { label: "Order number", value: { $state: "/result/number" } }
|
|
662
|
-
},
|
|
663
|
-
DateText: {
|
|
664
|
-
props: z.object({
|
|
665
|
-
value: z.string().nullable(),
|
|
666
|
-
style: z.enum(["long", "short", "weekday"]).nullable(),
|
|
667
|
-
tone: z.enum(["default", "muted", "accent"]).nullable()
|
|
668
|
-
}),
|
|
669
|
-
slots: [],
|
|
670
|
-
description: 'A date written in words: "long" is "Wednesday 14 April 2027", "short" is "14 Apr 2027", "weekday" is "Wed 14 April". "value" is a date path read with { "$state" } or { "$item" }; "tone" colours it muted or in the accent colour, as an eyebrow over a title.',
|
|
671
|
-
example: { value: { $item: "day" }, style: "weekday", tone: "accent" }
|
|
672
|
-
},
|
|
673
|
-
TextList: {
|
|
674
|
-
props: z.object({
|
|
675
|
-
items: z.array(z.string()).nullable(),
|
|
676
|
-
marker: z.enum(["bullet", "number", "check"]).nullable()
|
|
677
|
-
}),
|
|
678
|
-
slots: [],
|
|
679
|
-
description: 'A list of short texts as one list, each entry a line with a small marker before it: a dot, its number or a check. "items" reads a list of text path with { "$state" }, or { "$item" } inside a repeat - the whole list at once, so it needs no repeat of its own.',
|
|
680
|
-
example: { items: { $state: "/result/notes" }, marker: "bullet" }
|
|
681
|
-
},
|
|
682
|
-
Detail: {
|
|
683
|
-
props: z.object({
|
|
684
|
-
label: z.string(),
|
|
685
|
-
value: z.any()
|
|
686
|
-
}),
|
|
687
|
-
slots: [],
|
|
688
|
-
description: 'A labelled line of text: the label muted in a narrow column at the left, the value wrapping beside it, a hairline under the line. Several in a column read as a list of details. "value" is a scalar read with { "$state" }, { "$item" } or { "$template" }; the line hides itself while the value is empty.',
|
|
689
|
-
example: { label: "Morning", value: { $item: "morning" } }
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
|
|
693
|
-
// src/generative/catalog.ts
|
|
694
|
-
var PRODUCT_COMPONENTS = [
|
|
695
|
-
"AppBar",
|
|
696
|
-
"Hero",
|
|
697
|
-
"Workspace",
|
|
698
|
-
"Section",
|
|
699
|
-
"Rail",
|
|
700
|
-
"SummaryRow",
|
|
701
|
-
"Cta",
|
|
702
|
-
"Footer"
|
|
703
|
-
];
|
|
704
|
-
var product = {
|
|
705
|
-
AppBar: {
|
|
706
|
-
props: z.object({
|
|
707
|
-
app: z.string(),
|
|
708
|
-
links: z.array(z.string()).nullable(),
|
|
709
|
-
tag: z.string().nullable()
|
|
710
|
-
}),
|
|
711
|
-
slots: [],
|
|
712
|
-
description: "A bar across the top of the page: the brand's logo, the name of this app beside it, a few muted links, and a small mono tag at the right (the method behind the page). It renders as the page's banner, so at most one.",
|
|
713
|
-
example: { app: "Trip planner", links: ["Methods", "Runs"], tag: "plan_trip" }
|
|
714
|
-
},
|
|
715
|
-
Hero: {
|
|
716
|
-
props: z.object({
|
|
717
|
-
headline: z.string(),
|
|
718
|
-
lede: z.string().nullable(),
|
|
719
|
-
eyebrow: z.string().nullable()
|
|
720
|
-
}),
|
|
721
|
-
slots: [],
|
|
722
|
-
description: "An opening: one bold headline that says what happens here, one muted line under it at most, and an optional small eyebrow in the accent colour above. The headline renders as an h1, so at most one on a page.",
|
|
723
|
-
example: { headline: "Plan a trip worth taking.", lede: "Tell us where and who is coming." }
|
|
724
|
-
},
|
|
725
|
-
Workspace: {
|
|
726
|
-
props: z.object({ rail: z.enum(["right", "left"]).nullable() }),
|
|
727
|
-
slots: ["default"],
|
|
728
|
-
description: 'Two children side by side on a wide screen and stacked on a narrow one: the work, and beside it a narrower panel that stays sticky while the work scrolls. Exactly two children; "rail" says which side the panel takes, right by default.',
|
|
729
|
-
example: { rail: "right" }
|
|
730
|
-
},
|
|
731
|
-
Section: {
|
|
732
|
-
props: z.object({
|
|
733
|
-
number: z.string().nullable(),
|
|
734
|
-
title: z.string(),
|
|
735
|
-
lede: z.string().nullable()
|
|
736
|
-
}),
|
|
737
|
-
slots: ["default"],
|
|
738
|
-
description: "A titled stage of the work: an optional small mono number in the accent colour, an h2 title, an optional muted line, then its children - flat, spaced, separated from the next Section by a hairline, never boxed.",
|
|
739
|
-
example: { number: "01", title: "Where and when" }
|
|
740
|
-
},
|
|
741
|
-
Rail: {
|
|
742
|
-
props: z.object({ title: z.string() }),
|
|
743
|
-
slots: ["default"],
|
|
744
|
-
description: "A raised, boxed panel: a small uppercase h2 title, then its children in a column. Made to stand beside the work as the panel of a Workspace, and the one boxed surface in this vocabulary.",
|
|
745
|
-
example: { title: "Your trip" }
|
|
746
|
-
},
|
|
747
|
-
SummaryRow: {
|
|
748
|
-
props: z.object({
|
|
749
|
-
label: z.string(),
|
|
750
|
-
value: z.any().nullable(),
|
|
751
|
-
detail: z.any().nullable(),
|
|
752
|
-
separator: z.string().nullable(),
|
|
753
|
-
placeholder: z.string().nullable()
|
|
754
|
-
}),
|
|
755
|
-
slots: [],
|
|
756
|
-
description: 'A line that restates a value: a muted label at the left, a bound value at the right. "value" and the optional "detail" are read with { "$state": "/inputs/..." } and joined by "separator" (a space by default); each is a scalar path - text, number, boolean, date or choice - never a structure, a list or a file. While both are empty the row shows "placeholder", or a dash.',
|
|
757
|
-
example: {
|
|
758
|
-
label: "Budget",
|
|
759
|
-
value: { $state: "/inputs/request/budget" },
|
|
760
|
-
detail: { $state: "/inputs/request/currency" }
|
|
761
|
-
}
|
|
762
|
-
},
|
|
763
|
-
Cta: {
|
|
764
|
-
props: z.object({ label: z.string(), hint: z.string().nullable() }),
|
|
765
|
-
slots: [],
|
|
766
|
-
events: ["press"],
|
|
767
|
-
description: "A call to action: a full-width button in the accent colour that runs the method, with an optional one-line hint under it. Bind on.press to validateForm then run.",
|
|
768
|
-
example: { label: "Plan my trip", hint: "Nothing runs until the request is complete." }
|
|
769
|
-
},
|
|
770
|
-
Footer: {
|
|
771
|
-
props: z.object({ text: z.string(), tag: z.string().nullable() }),
|
|
772
|
-
slots: [],
|
|
773
|
-
description: "A closing line, muted, with an optional mono tag at the right. It renders as the page's contentinfo, so at most one.",
|
|
774
|
-
example: { text: "Runs on Pipelex.", tag: "MTHDS" }
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
var COMPONENT_RENDERINGS = {
|
|
778
|
-
Hero: { heading: { level: 1 } },
|
|
779
|
-
Section: { heading: { level: 2 } },
|
|
780
|
-
Rail: { heading: { level: 2 } },
|
|
781
|
-
Card: { heading: { level: 3, when: "title" } },
|
|
782
|
-
AppBar: { once: "the page's banner" },
|
|
783
|
-
Footer: { once: "the page's contentinfo" },
|
|
784
|
-
Split: { children: { count: 2, roles: "left, right" } },
|
|
785
|
-
Workspace: { children: { count: 2, roles: "work, rail" } },
|
|
786
|
-
Tabs: { panels: { prop: "tabs", noun: "tab" } },
|
|
787
|
-
Steps: { panels: { prop: "steps", noun: "step" } },
|
|
788
|
-
Composer: { heading: { level: 1 }, once: "the composer" },
|
|
789
|
-
ResultHeader: { heading: { level: 1 }, once: "the result's header" },
|
|
790
|
-
FieldGroup: { heading: { level: 2, when: "title" } }
|
|
791
|
-
};
|
|
792
|
-
var catalog = Object.assign(
|
|
793
|
-
defineCatalog(generativeSchema, {
|
|
794
|
-
components: { ...generativeComponents, ...product, ...frameComponents },
|
|
795
|
-
actions: generativeActions
|
|
796
|
-
}),
|
|
797
|
-
{ renders: COMPONENT_RENDERINGS }
|
|
798
|
-
);
|
|
799
|
-
var COMPONENT_NAMES = [
|
|
800
|
-
...PICKED_SHADCN,
|
|
801
|
-
...CUSTOM_COMPONENTS,
|
|
802
|
-
...PRODUCT_COMPONENTS
|
|
803
|
-
];
|
|
804
|
-
var FRAME_EXCLUDED = {
|
|
805
|
-
page: [...FRAME_COMPONENTS],
|
|
806
|
-
composer: [
|
|
807
|
-
"AppBar",
|
|
808
|
-
"Footer",
|
|
809
|
-
"Workspace",
|
|
810
|
-
"Rail",
|
|
811
|
-
"Cta",
|
|
812
|
-
"Button",
|
|
813
|
-
"Hero",
|
|
814
|
-
"SummaryRow",
|
|
815
|
-
"MthdsResult",
|
|
816
|
-
"DataTable",
|
|
817
|
-
"Metric",
|
|
818
|
-
"Progress",
|
|
819
|
-
// `TextList` stays: a composer may list short texts too, such as what a
|
|
820
|
-
// run gives back.
|
|
821
|
-
...RESULT_COMPONENTS.filter((name) => name !== "TextList")
|
|
822
|
-
],
|
|
823
|
-
result: [
|
|
824
|
-
"AppBar",
|
|
825
|
-
"Footer",
|
|
826
|
-
"Workspace",
|
|
827
|
-
"Rail",
|
|
828
|
-
"Cta",
|
|
829
|
-
"Button",
|
|
830
|
-
"Hero",
|
|
831
|
-
"MthdsField",
|
|
832
|
-
"Input",
|
|
833
|
-
"Textarea",
|
|
834
|
-
"Select",
|
|
835
|
-
"Radio",
|
|
836
|
-
"Checkbox",
|
|
837
|
-
"Switch",
|
|
838
|
-
"Segmented",
|
|
839
|
-
"NumberInput",
|
|
840
|
-
"Steps",
|
|
841
|
-
...COMPOSER_COMPONENTS
|
|
842
|
-
]
|
|
843
|
-
};
|
|
844
|
-
function componentNamesFor(frame) {
|
|
845
|
-
const excluded = new Set(FRAME_EXCLUDED[frame]);
|
|
846
|
-
const own = frame === "page" ? [] : [...FRAME_COMPONENTS];
|
|
847
|
-
return [...COMPONENT_NAMES, ...own].filter((name) => !excluded.has(name));
|
|
848
|
-
}
|
|
849
|
-
function frameCatalog(frame) {
|
|
850
|
-
return {
|
|
851
|
-
componentNames: componentNamesFor(frame),
|
|
852
|
-
actionNames: catalog.actionNames,
|
|
853
|
-
data: catalog.data,
|
|
854
|
-
schema: catalog.schema,
|
|
855
|
-
renders: COMPONENT_RENDERINGS
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// src/generative/props-signature.ts
|
|
860
|
-
function definitionOf(schema) {
|
|
861
|
-
return schema._zod.def;
|
|
862
|
-
}
|
|
863
|
-
function propsSignature(schema) {
|
|
864
|
-
const def = definitionOf(schema);
|
|
865
|
-
switch (def.type) {
|
|
866
|
-
case "string":
|
|
867
|
-
return "string";
|
|
868
|
-
case "number":
|
|
869
|
-
return "number";
|
|
870
|
-
case "boolean":
|
|
871
|
-
return "boolean";
|
|
872
|
-
case "literal":
|
|
873
|
-
return JSON.stringify(def.values?.[0]);
|
|
874
|
-
case "enum":
|
|
875
|
-
return Object.values(def.entries ?? {}).map((value) => `"${String(value)}"`).join(" | ");
|
|
876
|
-
case "array":
|
|
877
|
-
return `Array<${def.element ? propsSignature(def.element) : "unknown"}>`;
|
|
878
|
-
case "object": {
|
|
879
|
-
const props = Object.entries(def.shape ?? {}).map(([key, value]) => {
|
|
880
|
-
const inner = definitionOf(value).type;
|
|
881
|
-
const optional = inner === "optional" || inner === "nullable";
|
|
882
|
-
return `${key}${optional ? "?" : ""}: ${propsSignature(value)}`;
|
|
883
|
-
});
|
|
884
|
-
return `{ ${props.join(", ")} }`;
|
|
885
|
-
}
|
|
886
|
-
case "optional":
|
|
887
|
-
case "nullable":
|
|
888
|
-
case "default":
|
|
889
|
-
return def.innerType ? propsSignature(def.innerType) : "unknown";
|
|
890
|
-
case "union":
|
|
891
|
-
return def.options ? def.options.map((option) => propsSignature(option)).join(" | ") : "unknown";
|
|
892
|
-
case "record": {
|
|
893
|
-
const key = def.keyType ? propsSignature(def.keyType) : "string";
|
|
894
|
-
const value = def.valueType ? propsSignature(def.valueType) : "unknown";
|
|
895
|
-
return `Record<${key}, ${value}>`;
|
|
896
|
-
}
|
|
897
|
-
default:
|
|
898
|
-
return "unknown";
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
// src/generative/designer-catalog.ts
|
|
903
|
-
var DESIGNER_CATALOG_CONCEPT = "generative.Catalog";
|
|
904
|
-
function designerCatalog({ frame = "page" } = {}) {
|
|
905
|
-
const definitions = catalog.data.components;
|
|
906
|
-
const components3 = componentNamesFor(frame).map((name) => {
|
|
907
|
-
const definition = definitions[name];
|
|
908
|
-
if (!definition) throw new Error(`the catalog defines no component named '${name}'`);
|
|
909
|
-
const slots = definition.slots ?? [];
|
|
910
|
-
return {
|
|
911
|
-
name,
|
|
912
|
-
props: propsSignature(definition.props),
|
|
913
|
-
description: definition.description,
|
|
914
|
-
accepts_children: slots.includes("default"),
|
|
915
|
-
slots: slots.filter((slot) => slot !== "default"),
|
|
916
|
-
events: [...definition.events ?? []]
|
|
917
|
-
};
|
|
918
|
-
});
|
|
919
|
-
const builtIn = (generativeSchema.builtInActions ?? []).map((action) => ({
|
|
920
|
-
name: action.name,
|
|
921
|
-
description: action.description,
|
|
922
|
-
built_in: true
|
|
923
|
-
}));
|
|
924
|
-
const own = Object.entries(catalog.data.actions).map(
|
|
925
|
-
([name, action]) => ({
|
|
926
|
-
name,
|
|
927
|
-
description: action.description,
|
|
928
|
-
built_in: false
|
|
929
|
-
})
|
|
930
|
-
);
|
|
931
|
-
return { components: components3, actions: [...builtIn, ...own] };
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// src/generative/prompt-hash.ts
|
|
935
|
-
var PROMPT_HASH = "30cf9bc059f6";
|
|
936
|
-
function promptHashSubject(method) {
|
|
937
|
-
const catalogs = FRAMES.map((frame) => designerCatalog({ frame }));
|
|
938
|
-
return `${method}
|
|
939
|
-
${JSON.stringify(catalogs)}`;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
// src/generative/paths.ts
|
|
943
|
-
var INPUTS_ROOT = "/inputs";
|
|
944
|
-
var RESULT_ROOT = "/result";
|
|
945
|
-
function joinPath(root, ...segments) {
|
|
946
|
-
return segments.reduce((path, segment) => `${path}/${escapeSegment(segment)}`, root);
|
|
947
|
-
}
|
|
948
|
-
function escapeSegment(segment) {
|
|
949
|
-
return segment.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
950
|
-
}
|
|
951
|
-
function unescapeSegment(segment) {
|
|
952
|
-
return segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
953
|
-
}
|
|
954
|
-
function segmentsUnder(root, path) {
|
|
955
|
-
if (path === root) return [];
|
|
956
|
-
if (!path.startsWith(`${root}/`)) return void 0;
|
|
957
|
-
return path.slice(root.length + 1).split("/").map(unescapeSegment);
|
|
958
|
-
}
|
|
959
|
-
function fieldAtSegments(fields, segments) {
|
|
960
|
-
const [head, ...rest] = segments;
|
|
961
|
-
if (head === void 0) return void 0;
|
|
962
|
-
const field = fields.find((candidate) => candidate.name === head);
|
|
963
|
-
if (!field) return void 0;
|
|
964
|
-
return rest.length === 0 ? field : descend(field, rest);
|
|
965
|
-
}
|
|
966
|
-
function descend(field, segments) {
|
|
967
|
-
const [head, ...rest] = segments;
|
|
968
|
-
if (head === void 0) return field;
|
|
969
|
-
if (field.kind === "object") return fieldAtSegments(field.fields, segments);
|
|
970
|
-
if (field.kind === "list" && /^\d+$/.test(head)) return descend(field.item, rest);
|
|
971
|
-
return void 0;
|
|
972
|
-
}
|
|
973
|
-
function inputFieldAtPath(fields, path) {
|
|
974
|
-
const segments = segmentsUnder(INPUTS_ROOT, path);
|
|
975
|
-
return segments && segments.length > 0 ? fieldAtSegments(fields, segments) : void 0;
|
|
976
|
-
}
|
|
977
|
-
function resultFieldAtPath(field, path) {
|
|
978
|
-
const segments = segmentsUnder(RESULT_ROOT, path);
|
|
979
|
-
if (!segments) return void 0;
|
|
980
|
-
return segments.length === 0 ? field : descend(field, segments);
|
|
981
|
-
}
|
|
982
|
-
function parentMapOf(spec) {
|
|
983
|
-
const parents = /* @__PURE__ */ new Map();
|
|
984
|
-
for (const [parentKey, element] of Object.entries(spec.elements)) {
|
|
985
|
-
for (const child of element.children ?? []) parents.set(child, parentKey);
|
|
986
|
-
}
|
|
987
|
-
return parents;
|
|
988
|
-
}
|
|
989
|
-
function repeatBasePathOf(spec, key, parents = parentMapOf(spec)) {
|
|
990
|
-
const chain = [];
|
|
991
|
-
const seen = /* @__PURE__ */ new Set();
|
|
992
|
-
let current = key;
|
|
993
|
-
while (current !== void 0 && !seen.has(current)) {
|
|
994
|
-
seen.add(current);
|
|
995
|
-
chain.unshift(current);
|
|
996
|
-
current = parents.get(current);
|
|
997
|
-
}
|
|
998
|
-
let base;
|
|
999
|
-
for (const elementKey of chain) {
|
|
1000
|
-
const repeat = spec.elements[elementKey]?.repeat;
|
|
1001
|
-
if (!repeat) continue;
|
|
1002
|
-
const statePath = repeat.statePath;
|
|
1003
|
-
if (typeof statePath === "string") {
|
|
1004
|
-
base = `${statePath}/0`;
|
|
1005
|
-
continue;
|
|
1006
|
-
}
|
|
1007
|
-
const item = statePath?.$item;
|
|
1008
|
-
if (base === void 0 || typeof item !== "string") return void 0;
|
|
1009
|
-
base = `${joinPath(base, item)}/0`;
|
|
1010
|
-
}
|
|
1011
|
-
return base;
|
|
1012
|
-
}
|
|
1013
|
-
function absoluteHatchPath(spec, key, path, parents) {
|
|
1014
|
-
if (path.startsWith("/")) return path;
|
|
1015
|
-
const base = repeatBasePathOf(spec, key, parents);
|
|
1016
|
-
return base ? `${base}/${path}` : void 0;
|
|
1017
|
-
}
|
|
1018
|
-
function repeatListPathOf(spec, key, parents = parentMapOf(spec)) {
|
|
1019
|
-
const statePath = spec.elements[key]?.repeat?.statePath;
|
|
1020
|
-
if (typeof statePath === "string") return statePath;
|
|
1021
|
-
const item = statePath?.$item;
|
|
1022
|
-
const parent = parents.get(key);
|
|
1023
|
-
const outer = parent === void 0 ? void 0 : repeatBasePathOf(spec, parent, parents);
|
|
1024
|
-
return outer !== void 0 && typeof item === "string" ? joinPath(outer, item) : void 0;
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// src/generative/layout-fits.ts
|
|
1028
|
-
function isUnder(root, path) {
|
|
1029
|
-
return path === root || path.startsWith(`${root}/`);
|
|
1030
|
-
}
|
|
1031
|
-
function itemPathResolver(spec, key, parents) {
|
|
1032
|
-
let base;
|
|
1033
|
-
let resolvedBase = false;
|
|
1034
|
-
return (field) => {
|
|
1035
|
-
if (!resolvedBase) {
|
|
1036
|
-
base = repeatBasePathOf(spec, key, parents);
|
|
1037
|
-
resolvedBase = true;
|
|
1038
|
-
}
|
|
1039
|
-
if (base === void 0) return void 0;
|
|
1040
|
-
const under = field.startsWith("/") ? field.slice(1) : field;
|
|
1041
|
-
return under === "" ? base : `${base}/${under}`;
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
function interpolatedPaths(template, itemPath) {
|
|
1045
|
-
return [...template.matchAll(/\$\{([^}]+)\}/g)].flatMap((match) => {
|
|
1046
|
-
const raw = match[1];
|
|
1047
|
-
if (raw === void 0) return [];
|
|
1048
|
-
if (raw.startsWith("/")) return [raw];
|
|
1049
|
-
return [itemPath(raw) ?? `/${raw}`];
|
|
1050
|
-
});
|
|
1051
|
-
}
|
|
1052
|
-
function mentionedPaths(spec, parents) {
|
|
1053
|
-
const found = { bound: [], read: [], adrift: [] };
|
|
1054
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1055
|
-
const itemPath = itemPathResolver(spec, key, parents);
|
|
1056
|
-
const walk = (value) => {
|
|
1057
|
-
if (Array.isArray(value)) {
|
|
1058
|
-
value.forEach(walk);
|
|
1059
|
-
return;
|
|
1060
|
-
}
|
|
1061
|
-
if (typeof value !== "object" || value === null) return;
|
|
1062
|
-
const record = value;
|
|
1063
|
-
if (typeof record.$bindState === "string") found.bound.push(record.$bindState);
|
|
1064
|
-
if (typeof record.$state === "string") found.read.push(record.$state);
|
|
1065
|
-
if (typeof record.$template === "string") {
|
|
1066
|
-
found.read.push(...interpolatedPaths(record.$template, itemPath));
|
|
1067
|
-
}
|
|
1068
|
-
if (typeof record.$bindItem === "string") {
|
|
1069
|
-
const path = itemPath(record.$bindItem);
|
|
1070
|
-
if (path === void 0) found.adrift.push(key);
|
|
1071
|
-
else found.bound.push(path);
|
|
1072
|
-
}
|
|
1073
|
-
if (typeof record.$item === "string") {
|
|
1074
|
-
const path = itemPath(record.$item);
|
|
1075
|
-
if (path === void 0) found.adrift.push(key);
|
|
1076
|
-
else found.read.push(path);
|
|
1077
|
-
}
|
|
1078
|
-
Object.values(record).forEach(walk);
|
|
1079
|
-
};
|
|
1080
|
-
walk(element.props);
|
|
1081
|
-
walk(element.visible);
|
|
1082
|
-
}
|
|
1083
|
-
return found;
|
|
1084
|
-
}
|
|
1085
|
-
function staleReads(read, root, resolves) {
|
|
1086
|
-
const under = read.filter((path) => isUnder(root, path));
|
|
1087
|
-
return [...new Set(under)].filter((path) => !resolves(path));
|
|
1088
|
-
}
|
|
1089
|
-
function staleRepeats(spec, parents, root, resolves, side) {
|
|
1090
|
-
const problems = [];
|
|
1091
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1092
|
-
if (!element.repeat) continue;
|
|
1093
|
-
const listPath = repeatListPathOf(spec, key, parents);
|
|
1094
|
-
if (listPath === void 0 || !isUnder(root, listPath)) continue;
|
|
1095
|
-
if (!resolves(listPath)) {
|
|
1096
|
-
problems.push(`${key}: repeats over ${listPath}, which no ${side} has`);
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
return problems;
|
|
1100
|
-
}
|
|
1101
|
-
var NOT_A_VALUE = {
|
|
1102
|
-
object: { what: "a structure", instead: "a structure is shown through its members" },
|
|
1103
|
-
list: { what: "a list", instead: "a list is laid out as a repeat or a DataTable" },
|
|
1104
|
-
document: { what: "a file", instead: "a file is delegated to the kernel's own control" },
|
|
1105
|
-
image: { what: "a file", instead: "a file is delegated to the kernel's own control" }
|
|
1106
|
-
};
|
|
1107
|
-
var NOT_VALUES = {
|
|
1108
|
-
object: "structures",
|
|
1109
|
-
list: "lists",
|
|
1110
|
-
document: "files",
|
|
1111
|
-
image: "files"
|
|
1112
|
-
};
|
|
1113
|
-
var listPropsCache;
|
|
1114
|
-
function listProps() {
|
|
1115
|
-
if (listPropsCache) return listPropsCache;
|
|
1116
|
-
const found = /* @__PURE__ */ new Map([
|
|
1117
|
-
["DataTable", /* @__PURE__ */ new Map([["rows", "anything"]])]
|
|
1118
|
-
]);
|
|
1119
|
-
const components3 = catalog.data.components;
|
|
1120
|
-
for (const [type, definition] of Object.entries(components3)) {
|
|
1121
|
-
const shape = definition.props?.shape;
|
|
1122
|
-
for (const [prop, schema] of Object.entries(shape ?? {})) {
|
|
1123
|
-
const items = listItemsOf(schema);
|
|
1124
|
-
if (items === void 0) continue;
|
|
1125
|
-
if (!found.has(type)) found.set(type, /* @__PURE__ */ new Map());
|
|
1126
|
-
found.get(type).set(prop, items);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
listPropsCache = found;
|
|
1130
|
-
return found;
|
|
1131
|
-
}
|
|
1132
|
-
var VALUE_SCHEMAS = /* @__PURE__ */ new Set(["string", "number", "boolean", "enum", "literal"]);
|
|
1133
|
-
function unwrapped(schema) {
|
|
1134
|
-
let current = schema;
|
|
1135
|
-
for (let depth = 0; depth < 8; depth += 1) {
|
|
1136
|
-
const def = current.def;
|
|
1137
|
-
if (!def) return void 0;
|
|
1138
|
-
if (def.innerType === void 0) return def;
|
|
1139
|
-
current = def.innerType;
|
|
1140
|
-
}
|
|
1141
|
-
return void 0;
|
|
1142
|
-
}
|
|
1143
|
-
function listItemsOf(schema) {
|
|
1144
|
-
const def = unwrapped(schema);
|
|
1145
|
-
if (def?.type !== "array") return void 0;
|
|
1146
|
-
const element = unwrapped(def.element);
|
|
1147
|
-
return element?.type !== void 0 && VALUE_SCHEMAS.has(element.type) ? "values" : "anything";
|
|
1148
|
-
}
|
|
1149
|
-
function nonScalarReads(spec, parents, root, fieldAt) {
|
|
1150
|
-
const problems = [];
|
|
1151
|
-
const lists = listProps();
|
|
1152
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1153
|
-
const itemPath = itemPathResolver(spec, key, parents);
|
|
1154
|
-
const listy = lists.get(element.type);
|
|
1155
|
-
const check = (prop, path) => {
|
|
1156
|
-
if (!isUnder(root, path)) return;
|
|
1157
|
-
const field = fieldAt(path);
|
|
1158
|
-
if (!field) return;
|
|
1159
|
-
const wrong = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind] : void 0;
|
|
1160
|
-
if (!wrong) return;
|
|
1161
|
-
problems.push(
|
|
1162
|
-
`${key}: ${prop} shows ${path}, which is ${wrong.what} and not a value; a prop that shows a value takes a scalar path, and ${wrong.instead}`
|
|
1163
|
-
);
|
|
1164
|
-
};
|
|
1165
|
-
const checkList = (prop, path, items) => {
|
|
1166
|
-
if (!isUnder(root, path)) return;
|
|
1167
|
-
const field = fieldAt(path);
|
|
1168
|
-
if (!field || field.kind === "unknown") return;
|
|
1169
|
-
if (field.kind !== "list") {
|
|
1170
|
-
const what = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind].what : "a value";
|
|
1171
|
-
problems.push(
|
|
1172
|
-
`${key}: ${prop} takes a list, and ${path} is ${what}; a prop that takes a list reads a list path`
|
|
1173
|
-
);
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
if (items !== "values") return;
|
|
1177
|
-
const of = hasOwnProp(NOT_VALUES, field.item.kind) ? NOT_VALUES[field.item.kind] : void 0;
|
|
1178
|
-
if (!of) return;
|
|
1179
|
-
problems.push(
|
|
1180
|
-
`${key}: ${prop} takes a list of values, and ${path} is a list of ${of}; a list of ${of} is laid out as a repeat or a DataTable`
|
|
1181
|
-
);
|
|
1182
|
-
};
|
|
1183
|
-
const checkShares = (path) => {
|
|
1184
|
-
if (element.type !== "ProportionBar" || !isUnder(root, path)) return;
|
|
1185
|
-
const field = fieldAt(path);
|
|
1186
|
-
if (field?.kind !== "list") return;
|
|
1187
|
-
if (field.item.kind !== "object") {
|
|
1188
|
-
problems.push(
|
|
1189
|
-
`${key}: ProportionBar reads ${path}, a list of ${field.item.kind} values; its parts are structures, each with a label member and a number member`
|
|
1190
|
-
);
|
|
1191
|
-
return;
|
|
1192
|
-
}
|
|
1193
|
-
const members = field.item.fields;
|
|
1194
|
-
const { labelKey, valueKey } = element.props ?? {};
|
|
1195
|
-
const member = (name) => typeof name === "string" ? members.find((m) => m.name === name) : void 0;
|
|
1196
|
-
if (!member(labelKey)) {
|
|
1197
|
-
problems.push(
|
|
1198
|
-
`${key}: ProportionBar's labelKey ${JSON.stringify(labelKey)} is no member of ${path}'s items`
|
|
1199
|
-
);
|
|
1200
|
-
}
|
|
1201
|
-
const value = member(valueKey);
|
|
1202
|
-
if (!value) {
|
|
1203
|
-
problems.push(
|
|
1204
|
-
`${key}: ProportionBar's valueKey ${JSON.stringify(valueKey)} is no member of ${path}'s items`
|
|
1205
|
-
);
|
|
1206
|
-
} else if (value.kind !== "number") {
|
|
1207
|
-
problems.push(
|
|
1208
|
-
`${key}: ProportionBar's valueKey ${JSON.stringify(valueKey)} holds a ${value.kind}, not a number`
|
|
1209
|
-
);
|
|
1210
|
-
}
|
|
1211
|
-
};
|
|
1212
|
-
const walk = (prop, value) => {
|
|
1213
|
-
if (Array.isArray(value)) {
|
|
1214
|
-
value.forEach((entry) => walk(prop, entry));
|
|
1215
|
-
return;
|
|
1216
|
-
}
|
|
1217
|
-
if (typeof value !== "object" || value === null) return;
|
|
1218
|
-
const record = value;
|
|
1219
|
-
if (typeof record.$state === "string") check(prop, record.$state);
|
|
1220
|
-
if (typeof record.$item === "string") {
|
|
1221
|
-
const path = itemPath(record.$item);
|
|
1222
|
-
if (path !== void 0) check(prop, path);
|
|
1223
|
-
}
|
|
1224
|
-
if (typeof record.$template === "string") {
|
|
1225
|
-
for (const path of interpolatedPaths(record.$template, itemPath)) check(prop, path);
|
|
1226
|
-
}
|
|
1227
|
-
for (const [name, entry] of Object.entries(record)) {
|
|
1228
|
-
if (name !== "$cond") walk(prop, entry);
|
|
1229
|
-
}
|
|
1230
|
-
};
|
|
1231
|
-
for (const [prop, value] of Object.entries(element.props ?? {})) {
|
|
1232
|
-
const items = listy?.get(prop);
|
|
1233
|
-
if (items === void 0 || Array.isArray(value)) {
|
|
1234
|
-
walk(prop, value);
|
|
1235
|
-
continue;
|
|
1236
|
-
}
|
|
1237
|
-
if (typeof value !== "object" || value === null) continue;
|
|
1238
|
-
const record = value;
|
|
1239
|
-
const listPath = typeof record.$state === "string" ? record.$state : typeof record.$item === "string" ? itemPath(record.$item) : void 0;
|
|
1240
|
-
if (listPath !== void 0) {
|
|
1241
|
-
checkList(prop, listPath, items);
|
|
1242
|
-
if (prop === "items") checkShares(listPath);
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
return problems;
|
|
1247
|
-
}
|
|
1248
|
-
function boundProblems(bound, inputs) {
|
|
1249
|
-
const problems = [];
|
|
1250
|
-
const underInputs = bound.filter((path) => isUnder(INPUTS_ROOT, path));
|
|
1251
|
-
if (!inputs) {
|
|
1252
|
-
if (underInputs.length > 0) {
|
|
1253
|
-
problems.push(`a result page binds ${underInputs.join(", ")}; a result page writes nothing`);
|
|
1254
|
-
}
|
|
1255
|
-
} else {
|
|
1256
|
-
for (const path of underInputs) {
|
|
1257
|
-
if (!inputFieldAtPath(inputs, path)) {
|
|
1258
|
-
problems.push(`${path} is bound, and no input has it`);
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
for (const path of bound) {
|
|
1263
|
-
if (isUnder(RESULT_ROOT, path)) {
|
|
1264
|
-
problems.push(
|
|
1265
|
-
`${path} is bound; a layout may not write into ${RESULT_ROOT}, which the run fills`
|
|
1266
|
-
);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
return problems;
|
|
1270
|
-
}
|
|
1271
|
-
function repeatPaths(spec) {
|
|
1272
|
-
const found = [];
|
|
1273
|
-
for (const element of Object.values(spec.elements)) {
|
|
1274
|
-
const statePath = element.repeat?.statePath;
|
|
1275
|
-
if (typeof statePath === "string") found.push(statePath);
|
|
1276
|
-
}
|
|
1277
|
-
return found;
|
|
1278
|
-
}
|
|
1279
|
-
function isOffered(path, offered) {
|
|
1280
|
-
if (offered.bound.has(path) || offered.repeated.has(path)) return true;
|
|
1281
|
-
return offered.delegated.some((at) => path === at || path.startsWith(`${at}/`));
|
|
1282
|
-
}
|
|
1283
|
-
function uncoveredUnder(field, path, offered) {
|
|
1284
|
-
if (isOffered(path, offered)) return [];
|
|
1285
|
-
if (field.kind === "object") {
|
|
1286
|
-
return field.fields.filter((child) => child.required).flatMap((child) => uncoveredUnder(child, joinPath(path, child.name), offered));
|
|
1287
|
-
}
|
|
1288
|
-
return [path];
|
|
1289
|
-
}
|
|
1290
|
-
function layoutProblems(descriptor, spec) {
|
|
1291
|
-
try {
|
|
1292
|
-
return collectLayoutProblems(descriptor, spec);
|
|
1293
|
-
} catch (error) {
|
|
1294
|
-
return [`the layout is not a well-formed spec: ${String(error)}`];
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
function collectLayoutProblems(descriptor, spec) {
|
|
1298
|
-
const problems = [];
|
|
1299
|
-
const delegated = [];
|
|
1300
|
-
const parents = parentMapOf(spec);
|
|
1301
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1302
|
-
const written = element.props?.path;
|
|
1303
|
-
const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
|
|
1304
|
-
if (element.type === "MthdsField") {
|
|
1305
|
-
if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
|
|
1306
|
-
problems.push(`${key}: MthdsField delegates ${String(written)}, which no input has`);
|
|
1307
|
-
} else {
|
|
1308
|
-
delegated.push(path);
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
if (element.type === "MthdsResult") {
|
|
1312
|
-
if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
|
|
1313
|
-
problems.push(`${key}: MthdsResult delegates ${String(written)}, which no result has`);
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
const [onlyKey] = element.children?.length === 1 ? element.children : [];
|
|
1317
|
-
const only = onlyKey === void 0 ? void 0 : spec.elements[onlyKey];
|
|
1318
|
-
if (element.type === "Grid" && element.repeat === void 0 && only?.repeat !== void 0) {
|
|
1319
|
-
problems.push(
|
|
1320
|
-
`${key}: Grid's only child ${onlyKey} carries the repeat, so every item lands in one cell; put the repeat on ${key} itself, with the item's element as its child`
|
|
1321
|
-
);
|
|
1322
|
-
}
|
|
1323
|
-
if (element.type === "Picture") {
|
|
1324
|
-
const shown = written === "" ? repeatBasePathOf(spec, key, parents) : path ?? void 0;
|
|
1325
|
-
const field = shown && descriptor.result ? resultFieldAtPath(descriptor.result, shown) : void 0;
|
|
1326
|
-
if (!field) {
|
|
1327
|
-
problems.push(`${key}: Picture shows ${JSON.stringify(written)}, which no result has`);
|
|
1328
|
-
} else if (field.kind !== "image") {
|
|
1329
|
-
problems.push(`${key}: Picture shows ${shown}, which holds a ${field.kind}, not an image`);
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
const { bound, read, adrift } = mentionedPaths(spec, parents);
|
|
1334
|
-
for (const key of new Set(adrift)) {
|
|
1335
|
-
problems.push(`${key}: reads the current item, and no repeat above it has one`);
|
|
1336
|
-
}
|
|
1337
|
-
problems.push(...boundProblems(bound, descriptor.inputs));
|
|
1338
|
-
if (!descriptor.inputs) {
|
|
1339
|
-
const result = descriptor.result;
|
|
1340
|
-
const fieldAt2 = (path) => result ? resultFieldAtPath(result, path) : void 0;
|
|
1341
|
-
const resolves2 = (path) => fieldAt2(path) !== void 0;
|
|
1342
|
-
problems.push(...staleRepeats(spec, parents, RESULT_ROOT, resolves2, "result"));
|
|
1343
|
-
for (const path of staleReads(read, RESULT_ROOT, resolves2)) {
|
|
1344
|
-
problems.push(`${path} is read, and no result has it`);
|
|
1345
|
-
}
|
|
1346
|
-
problems.push(...nonScalarReads(spec, parents, RESULT_ROOT, fieldAt2));
|
|
1347
|
-
return problems;
|
|
1348
|
-
}
|
|
1349
|
-
const inputs = descriptor.inputs;
|
|
1350
|
-
const fieldAt = (path) => inputFieldAtPath(inputs, path);
|
|
1351
|
-
const resolves = (path) => fieldAt(path) !== void 0;
|
|
1352
|
-
problems.push(...staleRepeats(spec, parents, INPUTS_ROOT, resolves, "input"));
|
|
1353
|
-
for (const path of staleReads(read, INPUTS_ROOT, resolves)) {
|
|
1354
|
-
problems.push(`${path} is read, and no input has it`);
|
|
1355
|
-
}
|
|
1356
|
-
problems.push(...nonScalarReads(spec, parents, INPUTS_ROOT, fieldAt));
|
|
1357
|
-
const offered = {
|
|
1358
|
-
bound: new Set(bound),
|
|
1359
|
-
repeated: new Set(repeatPaths(spec)),
|
|
1360
|
-
delegated
|
|
1361
|
-
};
|
|
1362
|
-
for (const field of inputs) {
|
|
1363
|
-
if (!field.required) continue;
|
|
1364
|
-
for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered)) {
|
|
1365
|
-
problems.push(`${path} is required, and the layout offers nowhere to enter it`);
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
return problems;
|
|
1369
|
-
}
|
|
1370
|
-
function layoutFits(descriptor, spec) {
|
|
1371
|
-
return layoutProblems(descriptor, spec).length === 0;
|
|
1372
|
-
}
|
|
1373
|
-
var EXPRESSION_KEYS = [
|
|
1374
|
-
"$state",
|
|
1375
|
-
"$item",
|
|
1376
|
-
"$index",
|
|
1377
|
-
"$bindState",
|
|
1378
|
-
"$bindItem",
|
|
1379
|
-
"$cond",
|
|
1380
|
-
"$computed",
|
|
1381
|
-
"$template"
|
|
1382
|
-
];
|
|
1383
|
-
var HATCHES = /* @__PURE__ */ new Set(["MthdsField", "MthdsResult"]);
|
|
1384
|
-
function isExpression(value) {
|
|
1385
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).some((key) => EXPRESSION_KEYS.includes(key));
|
|
1386
|
-
}
|
|
1387
|
-
function valueAt(value, path) {
|
|
1388
|
-
let at = value;
|
|
1389
|
-
for (const step of path) {
|
|
1390
|
-
if (typeof at !== "object" || at === null) return void 0;
|
|
1391
|
-
at = at[step];
|
|
1392
|
-
}
|
|
1393
|
-
return at;
|
|
1394
|
-
}
|
|
1395
|
-
function isClosedVocabulary(schema) {
|
|
1396
|
-
let current = schema;
|
|
1397
|
-
for (let depth = 0; depth < 8; depth += 1) {
|
|
1398
|
-
const def = current.def;
|
|
1399
|
-
if (!def) return false;
|
|
1400
|
-
if (def.type === "enum" || def.type === "literal") return true;
|
|
1401
|
-
if (def.innerType === void 0) return false;
|
|
1402
|
-
current = def.innerType;
|
|
1403
|
-
}
|
|
1404
|
-
return false;
|
|
1405
|
-
}
|
|
1406
|
-
function definitionOf2(catalog2, type) {
|
|
1407
|
-
const components3 = catalog2.data.components;
|
|
1408
|
-
return hasOwnProp(components3, type) ? components3[type] : void 0;
|
|
1409
|
-
}
|
|
1410
|
-
function propsSchemaOf(catalog2, type) {
|
|
1411
|
-
const props = definitionOf2(catalog2, type)?.props;
|
|
1412
|
-
return props && typeof props === "object" && "shape" in props ? props : void 0;
|
|
1413
|
-
}
|
|
1414
|
-
function eventsOf(catalog2, type) {
|
|
1415
|
-
const definition = definitionOf2(catalog2, type);
|
|
1416
|
-
if (!definition) return void 0;
|
|
1417
|
-
return Array.isArray(definition.events) ? definition.events.filter((event) => typeof event === "string") : [];
|
|
1418
|
-
}
|
|
1419
|
-
var MAX_ELEMENT_DEPTH = 512;
|
|
1420
|
-
function childKeysOf(spec, key) {
|
|
1421
|
-
const element = spec.elements[key];
|
|
1422
|
-
if (!element) return [];
|
|
1423
|
-
const children = Array.isArray(element.children) ? element.children : [];
|
|
1424
|
-
const slots = typeof element.slots === "object" && element.slots !== null ? Object.values(element.slots).flatMap(
|
|
1425
|
-
(slot) => Array.isArray(slot) ? slot : []
|
|
1426
|
-
) : [];
|
|
1427
|
-
return [...children, ...slots].filter((child) => typeof child === "string");
|
|
1428
|
-
}
|
|
1429
|
-
function deepestChain(spec) {
|
|
1430
|
-
const below = /* @__PURE__ */ new Map();
|
|
1431
|
-
const onPath = /* @__PURE__ */ new Set();
|
|
1432
|
-
let deepest = 0;
|
|
1433
|
-
for (const start of Object.keys(spec.elements)) {
|
|
1434
|
-
if (below.has(start)) continue;
|
|
1435
|
-
const stack = [start];
|
|
1436
|
-
while (stack.length > 0) {
|
|
1437
|
-
const key = stack[stack.length - 1];
|
|
1438
|
-
if (below.has(key)) {
|
|
1439
|
-
onPath.delete(key);
|
|
1440
|
-
stack.pop();
|
|
1441
|
-
continue;
|
|
1442
|
-
}
|
|
1443
|
-
const children = childKeysOf(spec, key).filter((child) => !onPath.has(child));
|
|
1444
|
-
const pending = children.filter((child) => !below.has(child));
|
|
1445
|
-
if (pending.length > 0) {
|
|
1446
|
-
onPath.add(key);
|
|
1447
|
-
stack.push(...pending);
|
|
1448
|
-
continue;
|
|
1449
|
-
}
|
|
1450
|
-
below.set(
|
|
1451
|
-
key,
|
|
1452
|
-
children.reduce((tallest, child) => Math.max(tallest, below.get(child) ?? 0), 0) + 1
|
|
1453
|
-
);
|
|
1454
|
-
onPath.delete(key);
|
|
1455
|
-
stack.pop();
|
|
1456
|
-
}
|
|
1457
|
-
deepest = Math.max(deepest, below.get(start) ?? 0);
|
|
1458
|
-
}
|
|
1459
|
-
return deepest;
|
|
1460
|
-
}
|
|
1461
|
-
function validateAgainstCatalog(spec, catalog2 = frameCatalog("page")) {
|
|
1462
|
-
try {
|
|
1463
|
-
return checkAgainstCatalog(spec, catalog2);
|
|
1464
|
-
} catch (error) {
|
|
1465
|
-
return {
|
|
1466
|
-
ok: false,
|
|
1467
|
-
problems: [{ message: `the layout is not a well-formed spec: ${String(error)}` }]
|
|
1468
|
-
};
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
function checkAgainstCatalog(spec, catalog2) {
|
|
1472
|
-
const problems = [];
|
|
1473
|
-
const depth = deepestChain(spec);
|
|
1474
|
-
if (depth > MAX_ELEMENT_DEPTH) {
|
|
1475
|
-
return {
|
|
1476
|
-
ok: false,
|
|
1477
|
-
problems: [
|
|
1478
|
-
{
|
|
1479
|
-
message: `the element tree is ${depth} deep; this entry renders at most ${MAX_ELEMENT_DEPTH}.`
|
|
1480
|
-
}
|
|
1481
|
-
]
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
|
-
const structure = validateSpec(spec, { checkOrphans: true });
|
|
1485
|
-
for (const issue of structure.issues) {
|
|
1486
|
-
if (issue.severity === "error" || issue.code === "orphaned_element") {
|
|
1487
|
-
problems.push({ elementKey: issue.elementKey, message: issue.message });
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
const cyclic = /* @__PURE__ */ new Set();
|
|
1491
|
-
const state = /* @__PURE__ */ new Map();
|
|
1492
|
-
const descend2 = (key) => {
|
|
1493
|
-
const mark = state.get(key);
|
|
1494
|
-
if (mark === "done") return;
|
|
1495
|
-
if (mark === "open") {
|
|
1496
|
-
cyclic.add(key);
|
|
1497
|
-
return;
|
|
1498
|
-
}
|
|
1499
|
-
state.set(key, "open");
|
|
1500
|
-
const element = spec.elements[key];
|
|
1501
|
-
for (const child of element?.children ?? []) descend2(child);
|
|
1502
|
-
for (const slot of Object.values(element?.slots ?? {}))
|
|
1503
|
-
for (const child of slot) descend2(child);
|
|
1504
|
-
state.set(key, "done");
|
|
1505
|
-
};
|
|
1506
|
-
for (const key of Object.keys(spec.elements)) descend2(key);
|
|
1507
|
-
for (const key of cyclic) {
|
|
1508
|
-
problems.push({
|
|
1509
|
-
elementKey: key,
|
|
1510
|
-
message: `"${key}" is its own descendant: an element tree may not contain a cycle.`
|
|
1511
|
-
});
|
|
1512
|
-
}
|
|
1513
|
-
const known = new Set(catalog2.componentNames);
|
|
1514
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1515
|
-
if (!known.has(element.type)) {
|
|
1516
|
-
problems.push({ elementKey: key, message: `unknown component type "${element.type}"` });
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1520
|
-
const schema = propsSchemaOf(catalog2, element.type);
|
|
1521
|
-
if (!schema) continue;
|
|
1522
|
-
const shape = schema.shape;
|
|
1523
|
-
const props = element.props ?? {};
|
|
1524
|
-
for (const [name, value] of Object.entries(props)) {
|
|
1525
|
-
const propSchema = shape[name];
|
|
1526
|
-
if (!propSchema) {
|
|
1527
|
-
problems.push({
|
|
1528
|
-
elementKey: key,
|
|
1529
|
-
message: `${element.type} has no prop "${name}" (known: ${Object.keys(shape).join(", ")})`
|
|
1530
|
-
});
|
|
1531
|
-
continue;
|
|
1532
|
-
}
|
|
1533
|
-
if (isExpression(value)) {
|
|
1534
|
-
if (HATCHES.has(element.type) && name === "path") {
|
|
1535
|
-
problems.push({
|
|
1536
|
-
elementKey: key,
|
|
1537
|
-
message: `${element.type}.path must be a literal string - absolute, or the item's field name inside a repeat - never an expression.`
|
|
1538
|
-
});
|
|
1539
|
-
} else if (isClosedVocabulary(propSchema)) {
|
|
1540
|
-
problems.push({
|
|
1541
|
-
elementKey: key,
|
|
1542
|
-
message: `${element.type}.${name} is one of a fixed set of names, so it must be written as a literal, never as an expression.`
|
|
1543
|
-
});
|
|
1544
|
-
}
|
|
1545
|
-
continue;
|
|
1546
|
-
}
|
|
1547
|
-
const parsed = propSchema.safeParse(value);
|
|
1548
|
-
const issues = parsed.success ? [] : parsed.error.issues.filter(
|
|
1549
|
-
(issue) => !issue.path.some((_, n) => isExpression(valueAt(value, issue.path.slice(0, n + 1))))
|
|
1550
|
-
);
|
|
1551
|
-
if (issues.length > 0) {
|
|
1552
|
-
problems.push({
|
|
1553
|
-
elementKey: key,
|
|
1554
|
-
message: `${element.type}.${name}: ${issues.map((issue) => issue.message).join("; ")}`
|
|
1555
|
-
});
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
for (const [name, propSchema] of Object.entries(shape)) {
|
|
1559
|
-
if (name in props) continue;
|
|
1560
|
-
if (propSchema.safeParse(void 0).success || propSchema.safeParse(null).success) continue;
|
|
1561
|
-
problems.push({
|
|
1562
|
-
elementKey: key,
|
|
1563
|
-
message: `${element.type} is missing required prop "${name}"`
|
|
1564
|
-
});
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
const renders = catalog2.renders ?? {};
|
|
1568
|
-
const renderingOf = (type) => hasOwnProp(renders, type) ? renders[type] : void 0;
|
|
1569
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1570
|
-
const panelled = renderingOf(element.type)?.panels;
|
|
1571
|
-
if (!panelled) continue;
|
|
1572
|
-
const props = element.props ?? {};
|
|
1573
|
-
const listed = props[panelled.prop];
|
|
1574
|
-
if (!Array.isArray(listed)) continue;
|
|
1575
|
-
const panels = listed.length;
|
|
1576
|
-
const children = element.children?.length ?? 0;
|
|
1577
|
-
if (children !== panels) {
|
|
1578
|
-
problems.push({
|
|
1579
|
-
elementKey: key,
|
|
1580
|
-
message: `${element.type} declares ${panels} panel${panels === 1 ? "" : "s"} but has ${children} child${children === 1 ? "" : "ren"}: exactly one child per ${panelled.noun}, in order.`
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1583
|
-
const runs = (element.children ?? []).filter(
|
|
1584
|
-
(child) => spec.elements[child]?.type === "Button"
|
|
1585
|
-
);
|
|
1586
|
-
if (runs.length > 0) {
|
|
1587
|
-
problems.push({
|
|
1588
|
-
elementKey: key,
|
|
1589
|
-
message: `${element.type} has a Button as a direct child; a panel is a container (a Stack), and the Button belongs inside the last one.`
|
|
1590
|
-
});
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
const present3 = (value) => value !== void 0 && value !== null && value !== "";
|
|
1594
|
-
const levels = [];
|
|
1595
|
-
const onlyOnce = /* @__PURE__ */ new Map();
|
|
1596
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1597
|
-
const walk = (key) => {
|
|
1598
|
-
if (seen.has(key)) return;
|
|
1599
|
-
seen.add(key);
|
|
1600
|
-
const element = spec.elements[key];
|
|
1601
|
-
if (!element) return;
|
|
1602
|
-
const props = element.props ?? {};
|
|
1603
|
-
const rendering = renderingOf(element.type);
|
|
1604
|
-
if (element.type === "Heading") {
|
|
1605
|
-
const level = String(props.level ?? "h2");
|
|
1606
|
-
const match = /^h([1-4])$/.exec(level);
|
|
1607
|
-
if (match) levels.push({ key, type: "Heading", level: Number(match[1]) });
|
|
1608
|
-
} else if (rendering?.heading) {
|
|
1609
|
-
const rendered = rendering.heading;
|
|
1610
|
-
const has = rendered.when === void 0 || present3(props[rendered.when]);
|
|
1611
|
-
if (has) levels.push({ key, type: element.type, level: rendered.level });
|
|
1612
|
-
}
|
|
1613
|
-
if (rendering?.once !== void 0) {
|
|
1614
|
-
const entry = onlyOnce.get(element.type) ?? { reason: rendering.once, keys: [] };
|
|
1615
|
-
entry.keys.push(key);
|
|
1616
|
-
onlyOnce.set(element.type, entry);
|
|
1617
|
-
}
|
|
1618
|
-
for (const child of element.children ?? []) walk(child);
|
|
1619
|
-
for (const slot of Object.values(element.slots ?? {})) for (const child of slot) walk(child);
|
|
1620
|
-
};
|
|
1621
|
-
if (spec.root) walk(spec.root);
|
|
1622
|
-
const describe2 = (heading) => heading.type === "Heading" ? `h${heading.level}` : `${heading.type}'s h${heading.level}`;
|
|
1623
|
-
let previous;
|
|
1624
|
-
for (const heading of levels) {
|
|
1625
|
-
if (previous !== void 0 && heading.level > previous.level + 1) {
|
|
1626
|
-
problems.push({
|
|
1627
|
-
elementKey: heading.key,
|
|
1628
|
-
message: `${describe2(heading)} jumps after ${describe2(previous)}: heading levels increase by one, never by more.`
|
|
1629
|
-
});
|
|
1630
|
-
}
|
|
1631
|
-
previous = heading;
|
|
1632
|
-
}
|
|
1633
|
-
const firsts = levels.filter((heading) => heading.level === 1);
|
|
1634
|
-
const h1Ways = [
|
|
1635
|
-
...known.has("Heading") ? ["as a Heading at level h1"] : [],
|
|
1636
|
-
...Object.entries(renders).filter(([, rendering]) => rendering.heading?.level === 1).map(([type]) => `as the heading a ${type} renders`)
|
|
1637
|
-
];
|
|
1638
|
-
if (firsts.length === 0 && spec.root && h1Ways.length > 0) {
|
|
1639
|
-
problems.push({
|
|
1640
|
-
elementKey: spec.root,
|
|
1641
|
-
message: `the page has no h1: exactly one, ${h1Ways.join(" or ")}.`
|
|
1642
|
-
});
|
|
1643
|
-
}
|
|
1644
|
-
for (const extra of firsts.slice(1)) {
|
|
1645
|
-
problems.push({
|
|
1646
|
-
elementKey: extra.key,
|
|
1647
|
-
message: `a second h1 (${describe2(extra)}, after ${describe2(firsts[0])} at [${firsts[0].key}]): exactly one on a page.`
|
|
1648
|
-
});
|
|
1649
|
-
}
|
|
1650
|
-
for (const [type, { reason, keys }] of onlyOnce) {
|
|
1651
|
-
for (const extra of keys.slice(1)) {
|
|
1652
|
-
problems.push({
|
|
1653
|
-
elementKey: extra,
|
|
1654
|
-
message: `a second ${type} (after [${keys[0]}]): at most one on a page, since it renders as ${reason}.`
|
|
1655
|
-
});
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1659
|
-
const rule = renderingOf(element.type)?.children;
|
|
1660
|
-
if (!rule) continue;
|
|
1661
|
-
const children = element.children?.length ?? 0;
|
|
1662
|
-
if (children !== rule.count) {
|
|
1663
|
-
problems.push({
|
|
1664
|
-
elementKey: key,
|
|
1665
|
-
message: `${element.type} takes exactly ${rule.count} children (${rule.roles}); this one has ${children}.`
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
const declared = [
|
|
1670
|
-
...catalog2.actionNames ?? [],
|
|
1671
|
-
...(catalog2.schema?.builtInActions ?? []).map((action) => action.name)
|
|
1672
|
-
];
|
|
1673
|
-
const knownActions = declared.length > 0 ? new Set(declared) : void 0;
|
|
1674
|
-
const STATE_WRITES = {
|
|
1675
|
-
setState: [{ param: "statePath" }],
|
|
1676
|
-
pushState: [{ param: "statePath" }, { param: "clearStatePath", optional: true }],
|
|
1677
|
-
removeState: [{ param: "statePath" }],
|
|
1678
|
-
validateForm: [{ param: "statePath", optional: true }]
|
|
1679
|
-
};
|
|
1680
|
-
const OWNED_ROOTS = [INPUTS_ROOT, RESULT_ROOT];
|
|
1681
|
-
const ownedRootOf = (written) => {
|
|
1682
|
-
const statePath = written.startsWith("/") ? written : `/${written}`;
|
|
1683
|
-
return OWNED_ROOTS.find((root) => statePath === root || statePath.startsWith(`${root}/`));
|
|
1684
|
-
};
|
|
1685
|
-
const bindingsOf = (binding) => Array.isArray(binding) ? binding : [binding];
|
|
1686
|
-
const refusal = (owned, statePath) => `a layout may not write into ${owned}, which the host fills. Bind the value with { "$bindState": "${statePath}" } or delegate it with MthdsField instead.`;
|
|
1687
|
-
const checkBinding = (key, site, entry) => {
|
|
1688
|
-
const action = entry?.action;
|
|
1689
|
-
if (typeof action !== "string") {
|
|
1690
|
-
problems.push({ elementKey: key, message: `${site} has an entry with no "action" name.` });
|
|
1691
|
-
return;
|
|
1692
|
-
}
|
|
1693
|
-
if (knownActions && !knownActions.has(action)) {
|
|
1694
|
-
problems.push({
|
|
1695
|
-
elementKey: key,
|
|
1696
|
-
message: `${site} names the unknown action "${action}" (known: ${[...knownActions].join(", ")}); nothing would handle it.`
|
|
1697
|
-
});
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
const writes = hasOwnProp(STATE_WRITES, action) ? STATE_WRITES[action] : void 0;
|
|
1701
|
-
if (writes) {
|
|
1702
|
-
const params = entry.params;
|
|
1703
|
-
for (const { param, optional } of writes) {
|
|
1704
|
-
const written = typeof params === "object" && params !== null ? params[param] : void 0;
|
|
1705
|
-
if (written === void 0 || written === null) {
|
|
1706
|
-
if (!optional) {
|
|
1707
|
-
problems.push({
|
|
1708
|
-
elementKey: key,
|
|
1709
|
-
message: `${site} calls ${action} without a literal "${param}".`
|
|
1710
|
-
});
|
|
1711
|
-
}
|
|
1712
|
-
continue;
|
|
1713
|
-
}
|
|
1714
|
-
if (typeof written !== "string") {
|
|
1715
|
-
problems.push({
|
|
1716
|
-
elementKey: key,
|
|
1717
|
-
message: `${site} calls ${action} with a "${param}" that is not a literal string; where an action writes must be named, never computed.`
|
|
1718
|
-
});
|
|
1719
|
-
continue;
|
|
1720
|
-
}
|
|
1721
|
-
const owned = ownedRootOf(written);
|
|
1722
|
-
if (owned) {
|
|
1723
|
-
const where = param === "statePath" ? `on "${written}"` : `with ${param} "${written}"`;
|
|
1724
|
-
problems.push({
|
|
1725
|
-
elementKey: key,
|
|
1726
|
-
message: `${site} calls ${action} ${where}: ${refusal(owned, written.startsWith("/") ? written : `/${written}`)}`
|
|
1727
|
-
});
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
for (const hook of ["onSuccess", "onError"]) {
|
|
1732
|
-
const follow = entry[hook];
|
|
1733
|
-
if (follow === void 0 || follow === null) continue;
|
|
1734
|
-
const hookSite = `${site}.${hook}`;
|
|
1735
|
-
if (typeof follow !== "object" || Array.isArray(follow)) {
|
|
1736
|
-
problems.push({
|
|
1737
|
-
elementKey: key,
|
|
1738
|
-
message: `${hookSite} must be an object: a { "set" } of state paths to values, or an { "action" } binding.`
|
|
1739
|
-
});
|
|
1740
|
-
continue;
|
|
1741
|
-
}
|
|
1742
|
-
const record = follow;
|
|
1743
|
-
if (record.set !== void 0 && record.set !== null) {
|
|
1744
|
-
if (typeof record.set !== "object" || Array.isArray(record.set)) {
|
|
1745
|
-
problems.push({
|
|
1746
|
-
elementKey: key,
|
|
1747
|
-
message: `${hookSite}.set must be an object mapping a state path to its value.`
|
|
1748
|
-
});
|
|
1749
|
-
} else {
|
|
1750
|
-
for (const written of Object.keys(record.set)) {
|
|
1751
|
-
const owned = ownedRootOf(written);
|
|
1752
|
-
if (owned) {
|
|
1753
|
-
problems.push({
|
|
1754
|
-
elementKey: key,
|
|
1755
|
-
message: `${hookSite} sets "${written}": ${refusal(owned, written.startsWith("/") ? written : `/${written}`)}`
|
|
1756
|
-
});
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
if (record.action !== void 0) checkBinding(key, hookSite, record);
|
|
1762
|
-
}
|
|
1763
|
-
};
|
|
1764
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1765
|
-
const on = element.on;
|
|
1766
|
-
if (on !== void 0 && on !== null) {
|
|
1767
|
-
if (typeof on !== "object" || Array.isArray(on)) {
|
|
1768
|
-
problems.push({
|
|
1769
|
-
elementKey: key,
|
|
1770
|
-
message: '"on" must be an object mapping an event name to its actions.'
|
|
1771
|
-
});
|
|
1772
|
-
} else {
|
|
1773
|
-
const emitted = eventsOf(catalog2, element.type);
|
|
1774
|
-
for (const [event, binding] of Object.entries(on)) {
|
|
1775
|
-
if (emitted && !emitted.includes(event)) {
|
|
1776
|
-
problems.push({
|
|
1777
|
-
elementKey: key,
|
|
1778
|
-
message: emitted.length > 0 ? `on.${event}: ${element.type} never emits "${event}" (it emits: ${emitted.join(", ")}), so nothing bound there would ever fire.` : `on.${event}: ${element.type} emits no events, so nothing bound there would ever fire.`
|
|
1779
|
-
});
|
|
1780
|
-
}
|
|
1781
|
-
for (const entry of bindingsOf(binding)) checkBinding(key, `on.${event}`, entry);
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
const watch = element.watch;
|
|
1786
|
-
if (watch !== void 0 && watch !== null) {
|
|
1787
|
-
if (typeof watch !== "object" || Array.isArray(watch)) {
|
|
1788
|
-
problems.push({
|
|
1789
|
-
elementKey: key,
|
|
1790
|
-
message: '"watch" must be an object mapping a state path to the actions its change fires.'
|
|
1791
|
-
});
|
|
1792
|
-
} else {
|
|
1793
|
-
for (const [path, binding] of Object.entries(watch)) {
|
|
1794
|
-
for (const entry of bindingsOf(binding)) checkBinding(key, `watch.${path}`, entry);
|
|
1795
|
-
}
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
return { ok: problems.length === 0, problems };
|
|
1800
|
-
}
|
|
1801
|
-
function formatProblems(problems) {
|
|
1802
|
-
return problems.map(
|
|
1803
|
-
(problem) => problem.elementKey ? `[${problem.elementKey}] ${problem.message}` : problem.message
|
|
1804
|
-
).join("\n");
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
// src/generative/designer-run.ts
|
|
1808
|
-
function seedLine(seed) {
|
|
1809
|
-
return `CREATIVE SEED (derive your direction from it; never reveal it): ${seed}`;
|
|
1810
|
-
}
|
|
1811
|
-
var REPAIR_ATTEMPTS = 2;
|
|
1812
|
-
function layoutCheckProblems(spec, { frame, descriptor }) {
|
|
1813
|
-
const verdict = validateAgainstCatalog(spec, frameCatalog(frame));
|
|
1814
|
-
const invalid = verdict.ok ? [] : formatProblems(verdict.problems).split("\n");
|
|
1815
|
-
const runless = frame !== "result" && descriptor.inputs && !bindsRun(spec) ? ["the layout has no control that runs the method: bind `run` under a control's `on`"] : [];
|
|
1816
|
-
return [...invalid, ...runless, ...layoutProblems(descriptor, spec)];
|
|
1817
|
-
}
|
|
1818
|
-
function bindsRun(spec) {
|
|
1819
|
-
const isRun = (binding) => typeof binding === "object" && binding !== null && binding.action === "run";
|
|
1820
|
-
const elements = spec.elements;
|
|
1821
|
-
if (typeof elements !== "object" || elements === null) return false;
|
|
1822
|
-
return Object.values(elements).some((element) => {
|
|
1823
|
-
if (typeof element !== "object" || element === null) return false;
|
|
1824
|
-
const on = element.on;
|
|
1825
|
-
if (typeof on !== "object" || on === null) return false;
|
|
1826
|
-
return Object.values(on).some(
|
|
1827
|
-
(binding) => Array.isArray(binding) ? binding.some(isRun) : isRun(binding)
|
|
1828
|
-
);
|
|
1829
|
-
});
|
|
1830
|
-
}
|
|
26
|
+
import { resolveRepeatStatePath, getByPath, evaluateVisibility, resolveElementProps } from '@json-render/core';
|
|
27
|
+
export { createStateStore } from '@json-render/core';
|
|
28
|
+
import { Clock, ArrowRight, Send, Pencil, Zap, Lightbulb, Truck, Package, Briefcase, Bookmark, Flag, Shield, Info, AlertCircle, CheckCircle2, ListChecks, Layers, Tag, Phone, Mail, Paperclip, Upload, FileText, BarChart3, TrendingUp, Hash, Percent, Receipt, Coins, Banknote, Wallet, Gift, Ticket, Image, Camera, Music, Coffee, Utensils, Star, Heart, Accessibility, Baby, User, Users, Hourglass, Calendar, Moon, Sun, Leaf, Mountain, Globe, Landmark, Building2, Home, Hotel, Ship, Car, Train, Plane, Route, MapPin, Map as Map$1, Compass, Rocket, Sparkles, ChevronDown } from 'lucide-react';
|
|
29
|
+
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
1831
30
|
|
|
1832
|
-
|
|
1833
|
-
var DESIGNER_BRIEF_CONCEPT = "generative.Brief";
|
|
1834
|
-
var RUN_COMPONENT = "Cta";
|
|
1835
|
-
var COMPOSER_RUN_COMPONENT = "Composer";
|
|
1836
|
-
function isDelegatedInput(field) {
|
|
1837
|
-
return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "list" || field.kind === "unknown" || field.kind === "enum" && field.options.includes("");
|
|
1838
|
-
}
|
|
1839
|
-
function isDelegatedResult(field, frame = "page") {
|
|
1840
|
-
if (isNativeValueNode(field)) return true;
|
|
1841
|
-
if (frame === "result" && (field.kind === "image" || field.kind === "date" && !field.datetime))
|
|
1842
|
-
return false;
|
|
1843
|
-
if (field.kind === "list" && isNativeValueNode(field.item)) return true;
|
|
1844
|
-
return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "prose" || field.kind === "unknown";
|
|
1845
|
-
}
|
|
1846
|
-
function kindLabel(field) {
|
|
1847
|
-
if (isNativeHtmlNode(field)) return "markup (native.Html)";
|
|
1848
|
-
if (isNativeDateNode(field)) return "date (native.Date)";
|
|
1849
|
-
if (isNativeCompositeNode(field)) return "composite (native.Composite)";
|
|
1850
|
-
switch (field.kind) {
|
|
1851
|
-
case "text":
|
|
1852
|
-
return "text";
|
|
1853
|
-
case "prose":
|
|
1854
|
-
return "prose (markdown)";
|
|
1855
|
-
case "number":
|
|
1856
|
-
return field.integer ? "integer" : "number";
|
|
1857
|
-
case "boolean":
|
|
1858
|
-
return "boolean";
|
|
1859
|
-
case "enum":
|
|
1860
|
-
return `choice of ${field.options.map((option) => JSON.stringify(option)).join(" | ")}`;
|
|
1861
|
-
case "date":
|
|
1862
|
-
return field.datetime ? "date with time" : "date";
|
|
1863
|
-
case "document":
|
|
1864
|
-
return "document (a file)";
|
|
1865
|
-
case "image":
|
|
1866
|
-
return "image (a file)";
|
|
1867
|
-
case "object":
|
|
1868
|
-
return `structure${field.conceptRef ? ` ${field.conceptRef}` : ""}`;
|
|
1869
|
-
case "list":
|
|
1870
|
-
return `list of ${kindLabel(field.item)}`;
|
|
1871
|
-
case "unknown":
|
|
1872
|
-
return "unknown";
|
|
1873
|
-
default:
|
|
1874
|
-
return field;
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
function constraints(field) {
|
|
1878
|
-
const notes = [];
|
|
1879
|
-
if (field.kind === "number") {
|
|
1880
|
-
if (field.min !== void 0) notes.push(`min ${field.min}`);
|
|
1881
|
-
if (field.max !== void 0) notes.push(`max ${field.max}`);
|
|
1882
|
-
}
|
|
1883
|
-
if (field.kind === "text" || field.kind === "prose") {
|
|
1884
|
-
if (field.minLength !== void 0) notes.push(`at least ${field.minLength} characters`);
|
|
1885
|
-
if (field.maxLength !== void 0) notes.push(`at most ${field.maxLength} characters`);
|
|
1886
|
-
if (field.format) notes.push(`format ${field.format}`);
|
|
1887
|
-
}
|
|
1888
|
-
if (field.kind === "list") {
|
|
1889
|
-
if (field.itemCount !== void 0) notes.push(`at least ${field.itemCount} items`);
|
|
1890
|
-
if (field.maxItemCount !== void 0) notes.push(`at most ${field.maxItemCount} items`);
|
|
1891
|
-
}
|
|
1892
|
-
if (field.defaultValue !== void 0) notes.push(`default ${JSON.stringify(field.defaultValue)}`);
|
|
1893
|
-
if (field.examples && field.examples.length > 0) {
|
|
1894
|
-
notes.push(`examples ${field.examples.map((example) => JSON.stringify(example)).join(", ")}`);
|
|
1895
|
-
}
|
|
1896
|
-
if (field.hints && Object.keys(field.hints).length > 0) {
|
|
1897
|
-
notes.push(
|
|
1898
|
-
`hints ${Object.entries(field.hints).map(([key, value]) => `${key}=${value}`).join(", ")}`
|
|
1899
|
-
);
|
|
1900
|
-
}
|
|
1901
|
-
return notes;
|
|
1902
|
-
}
|
|
1903
|
-
function entryOf(field, path, depth, side, relative, seeded, frame = "page") {
|
|
1904
|
-
const notes = constraints(field);
|
|
1905
|
-
return {
|
|
1906
|
-
depth,
|
|
1907
|
-
path,
|
|
1908
|
-
kind: kindLabel(field),
|
|
1909
|
-
name: field.name,
|
|
1910
|
-
title: field.title && field.title !== field.name ? field.title : void 0,
|
|
1911
|
-
description: field.description,
|
|
1912
|
-
required: side === "input" ? field.required : void 0,
|
|
1913
|
-
gating: side === "input" && field.gating ? true : void 0,
|
|
1914
|
-
notes: notes.length > 0 ? notes : void 0,
|
|
1915
|
-
default: seeded || field.defaultValue === void 0 ? void 0 : JSON.stringify(field.defaultValue),
|
|
1916
|
-
delegated: side === "input" ? isDelegatedInput(field) : isDelegatedResult(field, frame),
|
|
1917
|
-
relative: relative ? true : void 0
|
|
1918
|
-
};
|
|
1919
|
-
}
|
|
1920
|
-
function describe(field, path, depth, side, entries, seeded = false, frame = "page") {
|
|
1921
|
-
const entry = entryOf(field, path, depth, side, false, seeded, frame);
|
|
1922
|
-
entries.push(entry);
|
|
1923
|
-
if (entry.delegated) return;
|
|
1924
|
-
if (field.kind === "object") {
|
|
1925
|
-
const seededBelow = seeded || field.defaultValue !== void 0 || side === "input" && !field.required;
|
|
1926
|
-
for (const child of field.fields) {
|
|
1927
|
-
describe(child, joinPath(path, child.name), depth + 1, side, entries, seededBelow, frame);
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
if (field.kind === "list" && side === "result") {
|
|
1931
|
-
const item = field.item;
|
|
1932
|
-
entry.item_kind = kindLabel(item);
|
|
1933
|
-
entry.item_description = item.description;
|
|
1934
|
-
if (item.kind === "object" && !isDelegatedResult(item, frame)) {
|
|
1935
|
-
entry.item_laid_out = true;
|
|
1936
|
-
for (const child of item.fields) {
|
|
1937
|
-
describeRelative(child, child.name, depth + 2, entries, side, frame);
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
function describeRelative(field, relativePath, depth, entries, side = "result", frame = "page") {
|
|
1943
|
-
const entry = entryOf(field, relativePath, depth, side, true, false, frame);
|
|
1944
|
-
entries.push(entry);
|
|
1945
|
-
if (entry.delegated) return;
|
|
1946
|
-
if (field.kind === "object") {
|
|
1947
|
-
for (const child of field.fields) {
|
|
1948
|
-
describeRelative(child, joinPath(relativePath, child.name), depth + 1, entries, side, frame);
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
if (field.kind === "list" && side === "result") {
|
|
1952
|
-
const item = field.item;
|
|
1953
|
-
entry.item_kind = kindLabel(item);
|
|
1954
|
-
entry.item_description = item.description;
|
|
1955
|
-
if (item.kind === "object" && !isDelegatedResult(item, frame)) {
|
|
1956
|
-
entry.item_laid_out = true;
|
|
1957
|
-
for (const child of item.fields) {
|
|
1958
|
-
describeRelative(
|
|
1959
|
-
child,
|
|
1960
|
-
joinPath(relativePath, "<i>", child.name),
|
|
1961
|
-
depth + 2,
|
|
1962
|
-
entries,
|
|
1963
|
-
side,
|
|
1964
|
-
frame
|
|
1965
|
-
);
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
function returnsOf(result) {
|
|
1971
|
-
const shape = result.kind === "list" ? result.item : result;
|
|
1972
|
-
const members = shape.kind === "object" ? shape.fields : [shape];
|
|
1973
|
-
return members.map((member) => {
|
|
1974
|
-
const title = member.title ?? member.name.replace(/_/g, " ");
|
|
1975
|
-
return member.description && member.description !== title ? `${title}: ${member.description}` : title;
|
|
1976
|
-
});
|
|
1977
|
-
}
|
|
1978
|
-
function styleOf(style) {
|
|
1979
|
-
if (!style) return void 0;
|
|
1980
|
-
const { name, direction } = APP_STYLES[style];
|
|
1981
|
-
return { name, direction };
|
|
1982
|
-
}
|
|
1983
|
-
function inputBrief(subject, fields, { frame = "page", style, result } = {}) {
|
|
1984
|
-
const paths = [];
|
|
1985
|
-
for (const field of fields) {
|
|
1986
|
-
describe(field, joinPath(INPUTS_ROOT, field.name), 0, "input", paths, false, frame);
|
|
1987
|
-
}
|
|
1988
|
-
return {
|
|
1989
|
-
side: "input",
|
|
1990
|
-
frame,
|
|
1991
|
-
pipe_ref: subject.pipeRef,
|
|
1992
|
-
description: subject.description,
|
|
1993
|
-
name: subject.name,
|
|
1994
|
-
paths,
|
|
1995
|
-
run_control: frame === "composer" ? COMPOSER_RUN_COMPONENT : RUN_COMPONENT,
|
|
1996
|
-
...frame === "composer" && result ? { returns: returnsOf(result) } : {},
|
|
1997
|
-
...style ? { style: styleOf(style) } : {}
|
|
1998
|
-
};
|
|
1999
|
-
}
|
|
2000
|
-
function resultBrief(subject, field, state, { frame = "page", style } = {}) {
|
|
2001
|
-
const paths = [];
|
|
2002
|
-
if (field.kind === "object" && !isDelegatedResult(field, frame)) {
|
|
2003
|
-
paths.push({
|
|
2004
|
-
depth: 0,
|
|
2005
|
-
path: RESULT_ROOT,
|
|
2006
|
-
kind: kindLabel(field),
|
|
2007
|
-
description: field.description,
|
|
2008
|
-
delegated: false
|
|
2009
|
-
});
|
|
2010
|
-
for (const child of field.fields) {
|
|
2011
|
-
describe(child, joinPath(RESULT_ROOT, child.name), 1, "result", paths, false, frame);
|
|
2012
|
-
}
|
|
2013
|
-
} else {
|
|
2014
|
-
describe(field, RESULT_ROOT, 0, "result", paths, false, frame);
|
|
2015
|
-
}
|
|
2016
|
-
return {
|
|
2017
|
-
side: "result",
|
|
2018
|
-
frame,
|
|
2019
|
-
pipe_ref: subject.pipeRef,
|
|
2020
|
-
description: subject.description,
|
|
2021
|
-
paths,
|
|
2022
|
-
...style ? { style: styleOf(style) } : {},
|
|
2023
|
-
sample_state: JSON.stringify(state, null, 2)
|
|
2024
|
-
};
|
|
2025
|
-
}
|
|
2026
|
-
function specToJsonl(spec) {
|
|
2027
|
-
const lines = [];
|
|
2028
|
-
const push = (op, path, value) => lines.push(JSON.stringify({ op, path, value }));
|
|
2029
|
-
push("add", "/root", spec.root);
|
|
2030
|
-
const emitted = /* @__PURE__ */ new Set();
|
|
2031
|
-
const queue = [spec.root];
|
|
2032
|
-
while (queue.length > 0) {
|
|
2033
|
-
const key = queue.shift();
|
|
2034
|
-
if (emitted.has(key)) continue;
|
|
2035
|
-
const element = spec.elements[key];
|
|
2036
|
-
if (!element) continue;
|
|
2037
|
-
emitted.add(key);
|
|
2038
|
-
push("add", `/elements/${escapeSegment(key)}`, element);
|
|
2039
|
-
for (const child of element.children ?? []) queue.push(child);
|
|
2040
|
-
for (const slotChildren of Object.values(element.slots ?? {})) queue.push(...slotChildren);
|
|
2041
|
-
}
|
|
2042
|
-
for (const key of Object.keys(spec.elements)) {
|
|
2043
|
-
if (!emitted.has(key)) push("add", `/elements/${escapeSegment(key)}`, spec.elements[key]);
|
|
2044
|
-
}
|
|
2045
|
-
for (const [key, value] of Object.entries(spec.state ?? {})) {
|
|
2046
|
-
push("add", `/state/${escapeSegment(key)}`, value);
|
|
2047
|
-
}
|
|
2048
|
-
return `${lines.join("\n")}
|
|
2049
|
-
`;
|
|
2050
|
-
}
|
|
2051
|
-
var FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2052
|
-
function pointerReachesPrototype(pointer) {
|
|
2053
|
-
return typeof pointer === "string" && pointer.split("/").some((segment) => FORBIDDEN_SEGMENTS.has(unescapeSegment(segment)));
|
|
2054
|
-
}
|
|
2055
|
-
function reachesPrototype(line) {
|
|
2056
|
-
let parsed;
|
|
2057
|
-
try {
|
|
2058
|
-
parsed = JSON.parse(line);
|
|
2059
|
-
} catch {
|
|
2060
|
-
return false;
|
|
2061
|
-
}
|
|
2062
|
-
const patch = parsed;
|
|
2063
|
-
return pointerReachesPrototype(patch?.path) || pointerReachesPrototype(patch?.from);
|
|
2064
|
-
}
|
|
2065
|
-
function specFromJsonl(jsonl) {
|
|
2066
|
-
let spec = { root: "", elements: {} };
|
|
2067
|
-
for (const line of jsonl.split("\n")) {
|
|
2068
|
-
if (reachesPrototype(line)) continue;
|
|
2069
|
-
try {
|
|
2070
|
-
spec = compileSpecStream(line, spec);
|
|
2071
|
-
} catch {
|
|
2072
|
-
continue;
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
return spec;
|
|
2076
|
-
}
|
|
2077
|
-
function jsonlLines(jsonl) {
|
|
2078
|
-
return jsonl.split("\n").filter((line) => line.trim().length > 0);
|
|
2079
|
-
}
|
|
2080
|
-
var BrandContext = React4.createContext(null);
|
|
31
|
+
var BrandContext = React6.createContext(null);
|
|
2081
32
|
function BrandProvider({
|
|
2082
33
|
manifest,
|
|
2083
34
|
children
|
|
@@ -2086,7 +37,7 @@ function BrandProvider({
|
|
|
2086
37
|
return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
|
|
2087
38
|
}
|
|
2088
39
|
function useBrand() {
|
|
2089
|
-
const manifest =
|
|
40
|
+
const manifest = React6.useContext(BrandContext);
|
|
2090
41
|
if (!manifest)
|
|
2091
42
|
throw new Error(
|
|
2092
43
|
"useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
|
|
@@ -2097,7 +48,7 @@ var WEIGHTS = "400;500;600;700";
|
|
|
2097
48
|
function useWebfont(webfont) {
|
|
2098
49
|
const provider = webfont?.provider;
|
|
2099
50
|
const family = webfont?.family;
|
|
2100
|
-
|
|
51
|
+
React6.useEffect(() => {
|
|
2101
52
|
if (!provider || !family) return;
|
|
2102
53
|
const key = `${provider}:${family}`;
|
|
2103
54
|
if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
|
|
@@ -2117,7 +68,422 @@ function useWebfont(webfont) {
|
|
|
2117
68
|
document.head.appendChild(link);
|
|
2118
69
|
}, [provider, family]);
|
|
2119
70
|
}
|
|
2120
|
-
var
|
|
71
|
+
var CheckedFields = class {
|
|
72
|
+
constructor() {
|
|
73
|
+
// One entry per mounted field, so two fields handed one config object are
|
|
74
|
+
// two entries, and one leaving does not take the other's checks with it.
|
|
75
|
+
this.byPath = /* @__PURE__ */ new Map();
|
|
76
|
+
this.validation = null;
|
|
77
|
+
}
|
|
78
|
+
/** Hands the record json-render's validation, and tells it what is already mounted. */
|
|
79
|
+
attach(validation) {
|
|
80
|
+
if (validation === this.validation) return;
|
|
81
|
+
const first = this.validation === null;
|
|
82
|
+
this.validation = validation;
|
|
83
|
+
if (first) for (const path of this.byPath.keys()) this.publish(path);
|
|
84
|
+
}
|
|
85
|
+
/** Enters one mounted field's checks; what it returns leaves them again. */
|
|
86
|
+
enter(path, config) {
|
|
87
|
+
const configs = this.byPath.get(path) ?? /* @__PURE__ */ new Set();
|
|
88
|
+
this.byPath.set(path, configs);
|
|
89
|
+
const entry = { config };
|
|
90
|
+
configs.add(entry);
|
|
91
|
+
this.publish(path);
|
|
92
|
+
return () => {
|
|
93
|
+
configs.delete(entry);
|
|
94
|
+
if (configs.size === 0) this.byPath.delete(path);
|
|
95
|
+
this.publish(path);
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** The checks of every field mounted at `path`, combined, or none when no field is. */
|
|
99
|
+
configFor(path) {
|
|
100
|
+
const configs = this.byPath.get(path);
|
|
101
|
+
if (!configs || configs.size === 0) return void 0;
|
|
102
|
+
const [first] = configs;
|
|
103
|
+
return {
|
|
104
|
+
checks: [...configs].flatMap(({ config }) => config.checks ?? []),
|
|
105
|
+
...first?.config.validateOn ? { validateOn: first.config.validateOn } : {}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Runs the checks of every path a mounted field carries, as the record
|
|
110
|
+
* holds them now, and answers whether they all pass; every path is checked,
|
|
111
|
+
* so each failing field shows its message. json-render's own `validateAll`
|
|
112
|
+
* reads what it was told as of its provider's last render, which a press
|
|
113
|
+
* can beat by one task when a field has just mounted.
|
|
114
|
+
*/
|
|
115
|
+
check(validation) {
|
|
116
|
+
let pass = true;
|
|
117
|
+
for (const path of this.byPath.keys()) {
|
|
118
|
+
const combined = this.configFor(path);
|
|
119
|
+
if (combined && !validation.validate(path, combined).valid) pass = false;
|
|
120
|
+
}
|
|
121
|
+
return pass;
|
|
122
|
+
}
|
|
123
|
+
publish(path) {
|
|
124
|
+
this.validation?.registerField(path, this.configFor(path) ?? { checks: [] });
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var CheckedFieldsContext = React6.createContext(null);
|
|
128
|
+
function useCheckedField(path, config) {
|
|
129
|
+
const fields = React6.useContext(CheckedFieldsContext);
|
|
130
|
+
const field = useFieldValidation(path, fields ? void 0 : config);
|
|
131
|
+
const validation = useOptionalValidation();
|
|
132
|
+
const signature = config ? JSON.stringify(config) : "";
|
|
133
|
+
const latest = React6.useRef(config);
|
|
134
|
+
React6.useInsertionEffect(() => {
|
|
135
|
+
latest.current = config;
|
|
136
|
+
});
|
|
137
|
+
React6.useEffect(() => {
|
|
138
|
+
const entered = latest.current;
|
|
139
|
+
if (!fields || !path || !entered) return void 0;
|
|
140
|
+
return fields.enter(path, entered);
|
|
141
|
+
}, [fields, path, signature]);
|
|
142
|
+
const fallback = field.validate;
|
|
143
|
+
const validate = React6.useCallback(() => {
|
|
144
|
+
const combined = fields?.configFor(path);
|
|
145
|
+
return validation && combined ? validation.validate(path, combined) : fallback();
|
|
146
|
+
}, [fields, path, validation, fallback]);
|
|
147
|
+
return { ...field, validate };
|
|
148
|
+
}
|
|
149
|
+
var ReportingContext = React6.createContext(false);
|
|
150
|
+
function said(error) {
|
|
151
|
+
try {
|
|
152
|
+
return String(error);
|
|
153
|
+
} catch {
|
|
154
|
+
return "an error that cannot be written out";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function contentOf(value) {
|
|
158
|
+
const open = /* @__PURE__ */ new WeakSet();
|
|
159
|
+
try {
|
|
160
|
+
return JSON.stringify(value, function(_key, entry) {
|
|
161
|
+
if (typeof entry === "bigint") return `${entry}n`;
|
|
162
|
+
if (typeof entry === "object" && entry !== null) {
|
|
163
|
+
if (open.has(entry)) return "[cycle]";
|
|
164
|
+
open.add(entry);
|
|
165
|
+
}
|
|
166
|
+
return entry;
|
|
167
|
+
}) ?? "undefined";
|
|
168
|
+
} catch {
|
|
169
|
+
return "an input that cannot be written out";
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function sameCue(a, b) {
|
|
173
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
174
|
+
return a.length === b.length && a.every((entry, index) => Object.is(entry, b[index]));
|
|
175
|
+
}
|
|
176
|
+
return Object.is(a, b);
|
|
177
|
+
}
|
|
178
|
+
var ElementBoundary = class extends React6.Component {
|
|
179
|
+
constructor(props) {
|
|
180
|
+
super(props);
|
|
181
|
+
this.state = { failed: false, error: void 0 };
|
|
182
|
+
}
|
|
183
|
+
static getDerivedStateFromError(error) {
|
|
184
|
+
return { failed: true, error };
|
|
185
|
+
}
|
|
186
|
+
/** What the element renders from, as text; total, since it reads a model's layout and the store. */
|
|
187
|
+
input() {
|
|
188
|
+
try {
|
|
189
|
+
return contentOf(this.props.inputOf ? this.props.inputOf() : this.props.resetOn);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
return `the input could not be read: ${said(error)}`;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
componentDidCatch(error, info) {
|
|
195
|
+
if (this.props.loading) {
|
|
196
|
+
this.failedOn = void 0;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
this.failedOn = this.input();
|
|
200
|
+
const componentStack = info.componentStack ?? void 0;
|
|
201
|
+
if (this.props.reporting) {
|
|
202
|
+
this.props.report.current?.(error, {
|
|
203
|
+
type: this.props.type,
|
|
204
|
+
...componentStack ? { componentStack } : {}
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (!this.props.root) {
|
|
209
|
+
console.error(
|
|
210
|
+
`[json-render] Rendering error in <${this.props.type}>:`,
|
|
211
|
+
error,
|
|
212
|
+
componentStack
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
componentDidUpdate(previous, previousState) {
|
|
217
|
+
if (!this.state.failed || !previousState.failed) return;
|
|
218
|
+
const streamEnded = previous.loading === true && !this.props.loading;
|
|
219
|
+
if (streamEnded || this.inputChanged(previous)) {
|
|
220
|
+
this.failedOn = void 0;
|
|
221
|
+
this.setState({ failed: false, error: void 0 });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** Whether what the element renders from is no longer what it failed on. */
|
|
225
|
+
inputChanged(previous) {
|
|
226
|
+
if (sameCue(this.props.resetOn, previous.resetOn)) return false;
|
|
227
|
+
if (this.props.loading || this.failedOn === void 0) return true;
|
|
228
|
+
return !Object.is(this.input(), this.failedOn);
|
|
229
|
+
}
|
|
230
|
+
// Whether the root throws the error on is decided as it renders its
|
|
231
|
+
// failure, from whether the host passes a handler in this very render:
|
|
232
|
+
// decided later, it cost a blank commit and a second record of the same
|
|
233
|
+
// error, and decided from the ref, it read the previous render's callback.
|
|
234
|
+
// No host to tell: the root's error goes on, in the same render, to the
|
|
235
|
+
// host's boundary around the page, which records it once.
|
|
236
|
+
render() {
|
|
237
|
+
if (!this.state.failed) return this.props.children;
|
|
238
|
+
if (this.props.root && !this.props.reporting && !this.props.loading) throw this.state.error;
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
function resolvedOf(element, ctx) {
|
|
243
|
+
if (!element) return void 0;
|
|
244
|
+
try {
|
|
245
|
+
return {
|
|
246
|
+
props: resolveElementProps(element.props ?? {}, ctx),
|
|
247
|
+
visible: element.visible === void 0 ? true : evaluateVisibility(element.visible, ctx)
|
|
248
|
+
};
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return `throws: ${said(error)}`;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function childElementOf(node) {
|
|
254
|
+
if (!React6.isValidElement(node)) return void 0;
|
|
255
|
+
const { element, elementKey } = node.props;
|
|
256
|
+
if (typeof elementKey !== "string") return void 0;
|
|
257
|
+
return typeof element === "object" && element !== null ? element : void 0;
|
|
258
|
+
}
|
|
259
|
+
function inputOfElement(props, visibility, scope) {
|
|
260
|
+
const element = props.element;
|
|
261
|
+
const state = visibility.stateModel;
|
|
262
|
+
const ctx = {
|
|
263
|
+
...visibility,
|
|
264
|
+
...scope ? { repeatItem: scope.item, repeatIndex: scope.index, repeatBasePath: scope.basePath } : {}
|
|
265
|
+
};
|
|
266
|
+
const statePath = element?.repeat?.statePath;
|
|
267
|
+
let list;
|
|
268
|
+
if (statePath !== void 0) {
|
|
269
|
+
try {
|
|
270
|
+
const path = resolveRepeatStatePath(statePath, scope?.basePath);
|
|
271
|
+
list = path === void 0 ? void 0 : getByPath(state, path);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
list = `throws: ${said(error)}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const under = (nodes) => React6.Children.toArray(nodes).map((node) => {
|
|
277
|
+
const child = childElementOf(node);
|
|
278
|
+
return child ? { element: child, resolved: resolvedOf(child, ctx) } : null;
|
|
279
|
+
});
|
|
280
|
+
const slots = typeof props.slots === "object" && props.slots !== null ? Object.fromEntries(Object.entries(props.slots).map(([name, nodes]) => [name, under(nodes)])) : void 0;
|
|
281
|
+
return { props: element?.props, list, children: under(props.children), slots };
|
|
282
|
+
}
|
|
283
|
+
function inputOfRoot(spec, visibility) {
|
|
284
|
+
const root = spec?.elements?.[spec.root];
|
|
285
|
+
return { spec, root: resolvedOf(root, visibility) };
|
|
286
|
+
}
|
|
287
|
+
function RootBoundary(props) {
|
|
288
|
+
const { ctx } = useVisibility();
|
|
289
|
+
return /* @__PURE__ */ jsx(
|
|
290
|
+
ElementBoundary,
|
|
291
|
+
{
|
|
292
|
+
type: props.type,
|
|
293
|
+
report: props.report,
|
|
294
|
+
reporting: props.reporting,
|
|
295
|
+
loading: props.loading,
|
|
296
|
+
resetOn: [props.spec, ctx],
|
|
297
|
+
inputOf: () => inputOfRoot(props.spec, ctx),
|
|
298
|
+
root: true,
|
|
299
|
+
children: props.children
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
function reportingRegistry(registry, report, made) {
|
|
304
|
+
const wrapped = {};
|
|
305
|
+
for (const [type, Renderer2] of Object.entries(registry)) {
|
|
306
|
+
const kept = made.get(type);
|
|
307
|
+
if (kept && kept.renderer === Renderer2) {
|
|
308
|
+
wrapped[type] = kept.wrapper;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const Component2 = Renderer2;
|
|
312
|
+
const Reported = (props) => {
|
|
313
|
+
const reporting = React6.useContext(ReportingContext);
|
|
314
|
+
const { ctx } = useVisibility();
|
|
315
|
+
const scope = useRepeatScope();
|
|
316
|
+
return /* @__PURE__ */ jsx(
|
|
317
|
+
ElementBoundary,
|
|
318
|
+
{
|
|
319
|
+
type,
|
|
320
|
+
report,
|
|
321
|
+
reporting,
|
|
322
|
+
loading: props.loading === true,
|
|
323
|
+
resetOn: [props.element, props.children, props.slots, ctx, scope],
|
|
324
|
+
inputOf: () => inputOfElement(props, ctx, scope),
|
|
325
|
+
children: /* @__PURE__ */ jsx(Component2, { ...props })
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
};
|
|
329
|
+
Reported.displayName = `Reported(${type})`;
|
|
330
|
+
made.set(type, { renderer: Renderer2, wrapper: Reported });
|
|
331
|
+
wrapped[type] = Reported;
|
|
332
|
+
}
|
|
333
|
+
return wrapped;
|
|
334
|
+
}
|
|
335
|
+
var CONTAINER = "mx-auto w-full max-w-6xl px-6 sm:px-8";
|
|
336
|
+
function BrandBar({ app, links, tag }) {
|
|
337
|
+
const brand = useBrand();
|
|
338
|
+
return /* @__PURE__ */ jsx("header", { className: "border-b border-border", children: /* @__PURE__ */ jsxs("div", { className: cn(CONTAINER, "flex h-16 items-center gap-5"), children: [
|
|
339
|
+
/* @__PURE__ */ jsx(
|
|
340
|
+
"img",
|
|
341
|
+
{
|
|
342
|
+
src: brand.logo.onLight,
|
|
343
|
+
alt: brand.name,
|
|
344
|
+
referrerPolicy: "no-referrer",
|
|
345
|
+
className: "h-7 w-auto dark:hidden"
|
|
346
|
+
}
|
|
347
|
+
),
|
|
348
|
+
/* @__PURE__ */ jsx(
|
|
349
|
+
"img",
|
|
350
|
+
{
|
|
351
|
+
src: brand.logo.onDark,
|
|
352
|
+
alt: brand.name,
|
|
353
|
+
referrerPolicy: "no-referrer",
|
|
354
|
+
className: "hidden h-7 w-auto dark:block"
|
|
355
|
+
}
|
|
356
|
+
),
|
|
357
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "h-5 w-px bg-border" }),
|
|
358
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground/80", children: app }),
|
|
359
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex min-w-0 items-center gap-6", children: [
|
|
360
|
+
links && links.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Site", className: "hidden items-center gap-6 sm:flex", children: links.map((link, index) => /* @__PURE__ */ jsx(
|
|
361
|
+
"a",
|
|
362
|
+
{
|
|
363
|
+
href: "#",
|
|
364
|
+
onClick: (event) => event.preventDefault(),
|
|
365
|
+
className: "rounded-sm text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-hidden",
|
|
366
|
+
children: link
|
|
367
|
+
},
|
|
368
|
+
`${index}-${link}`
|
|
369
|
+
)) }) : null,
|
|
370
|
+
tag ? /* @__PURE__ */ jsx(
|
|
371
|
+
"span",
|
|
372
|
+
{
|
|
373
|
+
className: cn(
|
|
374
|
+
"min-w-0 truncate rounded-lg border px-2.5 py-1 font-mono text-[11px]",
|
|
375
|
+
selectedBorderClass,
|
|
376
|
+
selectedFillClass,
|
|
377
|
+
linkTextClass
|
|
378
|
+
),
|
|
379
|
+
children: tag
|
|
380
|
+
}
|
|
381
|
+
) : null
|
|
382
|
+
] })
|
|
383
|
+
] }) });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/generative/declared-props.ts
|
|
387
|
+
var factsBySchema = /* @__PURE__ */ new WeakMap();
|
|
388
|
+
function factsOf(schema) {
|
|
389
|
+
const known = factsBySchema.get(schema);
|
|
390
|
+
if (known) return known;
|
|
391
|
+
const chain = definitionChain(schema);
|
|
392
|
+
const def = chain[chain.length - 1];
|
|
393
|
+
const acceptsNull = schema.safeParse(null).success;
|
|
394
|
+
const acceptsUndefined = schema.safeParse(void 0).success;
|
|
395
|
+
const absent = acceptsNull ? null : acceptsUndefined ? void 0 : def?.type === "string" ? "" : def?.type === "array" ? [] : void 0;
|
|
396
|
+
const facts = { def, plain: plainType(chain), acceptsNull, acceptsUndefined, absent };
|
|
397
|
+
factsBySchema.set(schema, facts);
|
|
398
|
+
return facts;
|
|
399
|
+
}
|
|
400
|
+
var PASSING_WRAPPERS = /* @__PURE__ */ new Set([
|
|
401
|
+
"optional",
|
|
402
|
+
"nullable",
|
|
403
|
+
"default",
|
|
404
|
+
"prefault",
|
|
405
|
+
"readonly",
|
|
406
|
+
"catch",
|
|
407
|
+
"nonoptional"
|
|
408
|
+
]);
|
|
409
|
+
function plainType(chain) {
|
|
410
|
+
const def = chain[chain.length - 1];
|
|
411
|
+
if (!def || def.format !== void 0) return void 0;
|
|
412
|
+
if (chain.some((link) => link.checks !== void 0 && link.checks.length > 0)) return void 0;
|
|
413
|
+
if (!chain.slice(0, -1).every((link) => PASSING_WRAPPERS.has(link.type))) return void 0;
|
|
414
|
+
return def.type === "string" || def.type === "boolean" || def.type === "number" ? def.type : void 0;
|
|
415
|
+
}
|
|
416
|
+
function plainlyConforms(plain, value) {
|
|
417
|
+
if (plain === "number") return typeof value === "number" && Number.isFinite(value);
|
|
418
|
+
return plain !== void 0 && typeof value === plain;
|
|
419
|
+
}
|
|
420
|
+
function writtenOut(schema, value) {
|
|
421
|
+
if (typeof value !== "number" && typeof value !== "boolean") return void 0;
|
|
422
|
+
const text = String(value);
|
|
423
|
+
return schema.safeParse(text).success ? text : void 0;
|
|
424
|
+
}
|
|
425
|
+
function keptEntries(schema, element, entries, absent) {
|
|
426
|
+
const textItems = unwrapped(element)?.type === "string";
|
|
427
|
+
const kept = entries.flatMap((entry) => {
|
|
428
|
+
if (element.safeParse(entry).success) return [entry];
|
|
429
|
+
const text = textItems ? writtenOut(element, entry) : void 0;
|
|
430
|
+
return text === void 0 ? [] : [text];
|
|
431
|
+
});
|
|
432
|
+
return schema.safeParse(kept).success ? kept : absent;
|
|
433
|
+
}
|
|
434
|
+
var conformedBySchema = /* @__PURE__ */ new WeakMap();
|
|
435
|
+
function conformValue(schema, value) {
|
|
436
|
+
const facts = factsOf(schema);
|
|
437
|
+
if (value === void 0) return facts.acceptsUndefined ? value : facts.absent;
|
|
438
|
+
if (value === null) return facts.acceptsNull ? value : facts.absent;
|
|
439
|
+
if (typeof value !== "object") {
|
|
440
|
+
if (plainlyConforms(facts.plain, value) || schema.safeParse(value).success) return value;
|
|
441
|
+
if (facts.def?.type === "string") return writtenOut(schema, value) ?? facts.absent;
|
|
442
|
+
return facts.absent;
|
|
443
|
+
}
|
|
444
|
+
let byValue = conformedBySchema.get(schema);
|
|
445
|
+
if (!byValue) {
|
|
446
|
+
byValue = /* @__PURE__ */ new WeakMap();
|
|
447
|
+
conformedBySchema.set(schema, byValue);
|
|
448
|
+
}
|
|
449
|
+
if (byValue.has(value)) return byValue.get(value);
|
|
450
|
+
const held = schema.safeParse(value).success ? value : facts.def?.type === "array" && facts.def.element && Array.isArray(value) ? keptEntries(schema, facts.def.element, value, facts.absent) : facts.absent;
|
|
451
|
+
byValue.set(value, held);
|
|
452
|
+
return held;
|
|
453
|
+
}
|
|
454
|
+
function conformProps(shape, props, asWritten = []) {
|
|
455
|
+
let conformed;
|
|
456
|
+
for (const [name, schema] of Object.entries(shape)) {
|
|
457
|
+
if (asWritten.includes(name)) continue;
|
|
458
|
+
const value = props[name];
|
|
459
|
+
const held = conformValue(schema, value);
|
|
460
|
+
if (held === value) continue;
|
|
461
|
+
conformed ?? (conformed = { ...props });
|
|
462
|
+
conformed[name] = held;
|
|
463
|
+
}
|
|
464
|
+
return conformed ?? props;
|
|
465
|
+
}
|
|
466
|
+
function withDeclaredProps(definitions, renderers, asWritten = {}) {
|
|
467
|
+
const wrapped = {};
|
|
468
|
+
for (const [name, render] of Object.entries(renderers)) {
|
|
469
|
+
const schema = definitions[name]?.props;
|
|
470
|
+
const shape = schema?.shape;
|
|
471
|
+
wrapped[name] = shape ? (ctx) => render({
|
|
472
|
+
...ctx,
|
|
473
|
+
props: conformProps(shape, ctx.props, asWritten[name])
|
|
474
|
+
}) : render;
|
|
475
|
+
}
|
|
476
|
+
return wrapped;
|
|
477
|
+
}
|
|
478
|
+
function textOf(value) {
|
|
479
|
+
if (value === void 0 || value === null) return "";
|
|
480
|
+
if (Array.isArray(value)) {
|
|
481
|
+
return value.map(textOf).filter((text) => text !== "").join(", ");
|
|
482
|
+
}
|
|
483
|
+
if (typeof value === "object") return "";
|
|
484
|
+
return String(value);
|
|
485
|
+
}
|
|
486
|
+
var FrameHostContext = React6.createContext({});
|
|
2121
487
|
function FrameHostProvider({
|
|
2122
488
|
host,
|
|
2123
489
|
children
|
|
@@ -2125,15 +491,15 @@ function FrameHostProvider({
|
|
|
2125
491
|
return /* @__PURE__ */ jsx(FrameHostContext.Provider, { value: host, children });
|
|
2126
492
|
}
|
|
2127
493
|
function useFrameHost() {
|
|
2128
|
-
return
|
|
494
|
+
return React6.useContext(FrameHostContext);
|
|
2129
495
|
}
|
|
2130
496
|
function useBoundField(literal, binding, empty, { checks, validateOn }) {
|
|
2131
497
|
const [boundValue, setBoundValue] = useBoundProp(literal ?? void 0, binding);
|
|
2132
|
-
const [localValue, setLocalValue] =
|
|
498
|
+
const [localValue, setLocalValue] = React6.useState(literal ?? empty);
|
|
2133
499
|
const isBound = Boolean(binding);
|
|
2134
500
|
const hasValidation = Boolean(binding && checks?.length);
|
|
2135
501
|
const when = validateOn ?? "change";
|
|
2136
|
-
const { errors, validate } =
|
|
502
|
+
const { errors, validate } = useCheckedField(
|
|
2137
503
|
binding ?? "",
|
|
2138
504
|
hasValidation ? { checks: checks ?? [], validateOn: when } : void 0
|
|
2139
505
|
);
|
|
@@ -2401,7 +767,7 @@ function Progress({
|
|
|
2401
767
|
] });
|
|
2402
768
|
}
|
|
2403
769
|
function useControlId(name) {
|
|
2404
|
-
return `jr-${name}-${
|
|
770
|
+
return `jr-${name}-${React6.useId()}`;
|
|
2405
771
|
}
|
|
2406
772
|
function Input({
|
|
2407
773
|
props,
|
|
@@ -2580,9 +946,9 @@ function Button({
|
|
|
2580
946
|
}
|
|
2581
947
|
);
|
|
2582
948
|
}
|
|
2583
|
-
var DescriptorContext =
|
|
949
|
+
var DescriptorContext = React6.createContext({});
|
|
2584
950
|
function useDescriptorScope() {
|
|
2585
|
-
return
|
|
951
|
+
return React6.useContext(DescriptorContext);
|
|
2586
952
|
}
|
|
2587
953
|
function DescriptorProvider({
|
|
2588
954
|
scope,
|
|
@@ -2598,8 +964,9 @@ function Unresolved({ path, side }) {
|
|
|
2598
964
|
className: "rounded-md border border-destructive/50 px-2.5 py-1.5 text-[12px] text-destructive",
|
|
2599
965
|
children: [
|
|
2600
966
|
side === "input" ? "No input" : "No result",
|
|
2601
|
-
" at
|
|
2602
|
-
|
|
967
|
+
" at",
|
|
968
|
+
" ",
|
|
969
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: typeof path === "string" ? path : JSON.stringify(path) ?? String(path) })
|
|
2603
970
|
]
|
|
2604
971
|
}
|
|
2605
972
|
);
|
|
@@ -2626,6 +993,7 @@ function pathFromDomId(prefix, id) {
|
|
|
2626
993
|
}
|
|
2627
994
|
function useAbsolutePath(path) {
|
|
2628
995
|
const repeat = useRepeatScope();
|
|
996
|
+
if (typeof path !== "string") return void 0;
|
|
2629
997
|
if (path.startsWith("/")) return path;
|
|
2630
998
|
return repeat ? `${repeat.basePath}/${path}` : void 0;
|
|
2631
999
|
}
|
|
@@ -2635,10 +1003,10 @@ function withoutOptionalMark(label) {
|
|
|
2635
1003
|
function MthdsField({
|
|
2636
1004
|
props
|
|
2637
1005
|
}) {
|
|
2638
|
-
const scope =
|
|
1006
|
+
const scope = React6.useContext(DescriptorContext);
|
|
2639
1007
|
const path = useAbsolutePath(props.path) ?? "";
|
|
2640
1008
|
const found = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
|
|
2641
|
-
const field =
|
|
1009
|
+
const field = React6.useMemo(
|
|
2642
1010
|
() => found && (props.label || props.hint) ? {
|
|
2643
1011
|
...found,
|
|
2644
1012
|
// The control marks an optional field itself, so a label that
|
|
@@ -2650,7 +1018,7 @@ function MthdsField({
|
|
|
2650
1018
|
);
|
|
2651
1019
|
const value = useStateValue(path);
|
|
2652
1020
|
const { set } = useStateStore();
|
|
2653
|
-
const onChange =
|
|
1021
|
+
const onChange = React6.useCallback((next) => set(path, next), [set, path]);
|
|
2654
1022
|
if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "input" });
|
|
2655
1023
|
return /* @__PURE__ */ jsx(
|
|
2656
1024
|
FieldRenderer,
|
|
@@ -2664,7 +1032,7 @@ function MthdsField({
|
|
|
2664
1032
|
);
|
|
2665
1033
|
}
|
|
2666
1034
|
function MthdsResult({ props }) {
|
|
2667
|
-
const scope =
|
|
1035
|
+
const scope = React6.useContext(DescriptorContext);
|
|
2668
1036
|
const path = useAbsolutePath(props.path) ?? "";
|
|
2669
1037
|
const field = scope.result && path ? resultFieldAtPath(scope.result, path) : void 0;
|
|
2670
1038
|
const value = useStateValue(path);
|
|
@@ -2677,13 +1045,13 @@ function AccessibleSelect({ props, bindings, emit }) {
|
|
|
2677
1045
|
props.value ?? void 0,
|
|
2678
1046
|
bindings?.value
|
|
2679
1047
|
);
|
|
2680
|
-
const [localValue, setLocalValue] =
|
|
1048
|
+
const [localValue, setLocalValue] = React6.useState("");
|
|
2681
1049
|
const isBound = Boolean(bindings?.value);
|
|
2682
1050
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
2683
1051
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
2684
1052
|
const validateOn = props.validateOn ?? "change";
|
|
2685
1053
|
const hasValidation = Boolean(bindings?.value && props.checks?.length);
|
|
2686
|
-
const { errors, validate } =
|
|
1054
|
+
const { errors, validate } = useCheckedField(
|
|
2687
1055
|
bindings?.value ?? "",
|
|
2688
1056
|
hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
|
|
2689
1057
|
);
|
|
@@ -2709,7 +1077,7 @@ function AccessibleSelect({ props, bindings, emit }) {
|
|
|
2709
1077
|
errors.length > 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors[0] }) : null
|
|
2710
1078
|
] });
|
|
2711
1079
|
}
|
|
2712
|
-
function
|
|
1080
|
+
function valueAt(row, relativePath) {
|
|
2713
1081
|
let current = row;
|
|
2714
1082
|
for (const segment of relativePath.split("/").filter((part) => part.length > 0)) {
|
|
2715
1083
|
if (typeof current !== "object" || current === null) return void 0;
|
|
@@ -2755,7 +1123,7 @@ function DataTable({ props }) {
|
|
|
2755
1123
|
},
|
|
2756
1124
|
column.path
|
|
2757
1125
|
)) }) }),
|
|
2758
|
-
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border/60 last:border-b-0", children: columns.map((column) => /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top text-foreground", children: formatColumnCell(
|
|
1126
|
+
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border/60 last:border-b-0", children: columns.map((column) => /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top text-foreground", children: formatColumnCell(valueAt(row, column.path), column.format) }, column.path)) }, index)) })
|
|
2759
1127
|
] }) });
|
|
2760
1128
|
}
|
|
2761
1129
|
function numberFormat(format) {
|
|
@@ -2774,7 +1142,7 @@ function numberFormat(format) {
|
|
|
2774
1142
|
}
|
|
2775
1143
|
function Metric({ props }) {
|
|
2776
1144
|
const value = props.value;
|
|
2777
|
-
const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : value
|
|
1145
|
+
const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : textOf(value) || "\u2014";
|
|
2778
1146
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
2779
1147
|
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: props.label }),
|
|
2780
1148
|
/* @__PURE__ */ jsxs("span", { className: "text-2xl font-semibold tabular-nums text-foreground", children: [
|
|
@@ -2807,29 +1175,49 @@ function Split({
|
|
|
2807
1175
|
}
|
|
2808
1176
|
function Tabs({ props, children }) {
|
|
2809
1177
|
const tabs = props.tabs ?? [];
|
|
2810
|
-
const panels =
|
|
2811
|
-
const [
|
|
2812
|
-
|
|
2813
|
-
|
|
1178
|
+
const panels = React6.Children.toArray(children);
|
|
1179
|
+
const [chosen, setChosen] = React6.useState(null);
|
|
1180
|
+
const open = chosen ? openIndex(tabs, chosen) : 0;
|
|
1181
|
+
const value = String(open);
|
|
1182
|
+
const choose = (next) => {
|
|
1183
|
+
const index = Number(next);
|
|
1184
|
+
const tab = tabs[index];
|
|
1185
|
+
if (!tab) return;
|
|
1186
|
+
const occurrence = tabs.slice(0, index).filter((t) => t.value === tab.value).length;
|
|
1187
|
+
setChosen({ value: tab.value, occurrence });
|
|
1188
|
+
};
|
|
1189
|
+
return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: choose, className: "w-full", children: [
|
|
1190
|
+
/* @__PURE__ */ jsx(TabsPrimitive.List, { className: "inline-flex h-10 items-center justify-start rounded-md bg-muted p-1 text-muted-foreground max-sm:h-auto max-sm:flex-wrap", children: tabs.map((tab, index) => /* @__PURE__ */ jsx(
|
|
2814
1191
|
TabsPrimitive.Trigger,
|
|
2815
1192
|
{
|
|
2816
|
-
value:
|
|
1193
|
+
value: String(index),
|
|
2817
1194
|
className: "inline-flex items-center justify-center rounded-sm px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-hidden data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm max-sm:min-h-11 max-sm:min-w-11",
|
|
2818
1195
|
children: tab.label
|
|
2819
1196
|
},
|
|
2820
|
-
|
|
1197
|
+
index
|
|
2821
1198
|
)) }),
|
|
2822
|
-
tabs.map((
|
|
1199
|
+
tabs.map((_tab, index) => /* @__PURE__ */ jsx(
|
|
2823
1200
|
TabsPrimitive.Content,
|
|
2824
1201
|
{
|
|
2825
|
-
value:
|
|
1202
|
+
value: String(index),
|
|
1203
|
+
forceMount: true,
|
|
1204
|
+
hidden: index !== open,
|
|
2826
1205
|
className: "mt-4 focus-visible:outline-hidden",
|
|
2827
1206
|
children: panels[index] ?? null
|
|
2828
1207
|
},
|
|
2829
|
-
|
|
1208
|
+
index
|
|
2830
1209
|
))
|
|
2831
1210
|
] });
|
|
2832
1211
|
}
|
|
1212
|
+
function openIndex(tabs, { value, occurrence }) {
|
|
1213
|
+
let seen = 0;
|
|
1214
|
+
for (const [index, tab] of tabs.entries()) {
|
|
1215
|
+
if (tab.value !== value) continue;
|
|
1216
|
+
if (seen === occurrence) return index;
|
|
1217
|
+
seen += 1;
|
|
1218
|
+
}
|
|
1219
|
+
return 0;
|
|
1220
|
+
}
|
|
2833
1221
|
var BUTTON_BASE = "inline-flex min-h-11 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50";
|
|
2834
1222
|
var PRIMARY_BUTTON = cn(BUTTON_BASE, "bg-primary text-primary-foreground hover:bg-primary/90");
|
|
2835
1223
|
var SECONDARY_BUTTON = cn(
|
|
@@ -2838,9 +1226,10 @@ var SECONDARY_BUTTON = cn(
|
|
|
2838
1226
|
);
|
|
2839
1227
|
function Steps({ props, children }) {
|
|
2840
1228
|
const steps = props.steps ?? [];
|
|
2841
|
-
const panels =
|
|
2842
|
-
const [
|
|
1229
|
+
const panels = React6.Children.toArray(children);
|
|
1230
|
+
const [chosen, setIndex] = React6.useState(0);
|
|
2843
1231
|
const last = steps.length - 1;
|
|
1232
|
+
const index = Math.max(0, Math.min(chosen, last));
|
|
2844
1233
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
2845
1234
|
/* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-x-5 gap-y-2", children: steps.map((label, position) => /* @__PURE__ */ jsxs(
|
|
2846
1235
|
"li",
|
|
@@ -2866,7 +1255,7 @@ function Steps({ props, children }) {
|
|
|
2866
1255
|
},
|
|
2867
1256
|
`${position}-${label}`
|
|
2868
1257
|
)) }),
|
|
2869
|
-
/* @__PURE__ */ jsx("div", { children: panels[
|
|
1258
|
+
steps.map((_step, position) => /* @__PURE__ */ jsx("div", { hidden: position !== index, children: panels[position] ?? null }, position)),
|
|
2870
1259
|
index > 0 || index < last ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
2871
1260
|
index > 0 ? /* @__PURE__ */ jsx(
|
|
2872
1261
|
"button",
|
|
@@ -2968,7 +1357,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
2968
1357
|
props.value ?? void 0,
|
|
2969
1358
|
bindings?.value
|
|
2970
1359
|
);
|
|
2971
|
-
const [localValue, setLocalValue] =
|
|
1360
|
+
const [localValue, setLocalValue] = React6.useState("");
|
|
2972
1361
|
const isBound = Boolean(bindings?.value);
|
|
2973
1362
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
2974
1363
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -2988,7 +1377,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
2988
1377
|
emit("change");
|
|
2989
1378
|
},
|
|
2990
1379
|
className: "flex-wrap justify-start gap-1.5",
|
|
2991
|
-
children: (props.options ?? []).map((option) => /* @__PURE__ */ jsx(
|
|
1380
|
+
children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsx(
|
|
2992
1381
|
ToggleGroupItem,
|
|
2993
1382
|
{
|
|
2994
1383
|
value: option,
|
|
@@ -2997,7 +1386,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
2997
1386
|
className: "rounded-full px-3.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground max-sm:h-11 max-sm:min-w-11",
|
|
2998
1387
|
children: labelOf(option)
|
|
2999
1388
|
},
|
|
3000
|
-
option
|
|
1389
|
+
`${index}-${option}`
|
|
3001
1390
|
))
|
|
3002
1391
|
}
|
|
3003
1392
|
)
|
|
@@ -3008,7 +1397,7 @@ function NumberInput({ props, bindings, emit }) {
|
|
|
3008
1397
|
props.value ?? void 0,
|
|
3009
1398
|
bindings?.value
|
|
3010
1399
|
);
|
|
3011
|
-
const [localValue, setLocalValue] =
|
|
1400
|
+
const [localValue, setLocalValue] = React6.useState(void 0);
|
|
3012
1401
|
const isBound = Boolean(bindings?.value);
|
|
3013
1402
|
const value = isBound ? boundValue : localValue;
|
|
3014
1403
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -3042,7 +1431,7 @@ function NumberInput({ props, bindings, emit }) {
|
|
|
3042
1431
|
] })
|
|
3043
1432
|
] });
|
|
3044
1433
|
}
|
|
3045
|
-
var
|
|
1434
|
+
var components = {
|
|
3046
1435
|
Card: (ctx) => /* @__PURE__ */ jsx(Card, { ...ctx }),
|
|
3047
1436
|
// A vertical Stack stretches its children unless the spec says otherwise:
|
|
3048
1437
|
// hugging the content is the one layout a result page never wants, since a
|
|
@@ -3081,7 +1470,13 @@ var components2 = {
|
|
|
3081
1470
|
DataTable: (ctx) => /* @__PURE__ */ jsx(DataTable, { ...ctx }),
|
|
3082
1471
|
Metric: (ctx) => /* @__PURE__ */ jsx(Metric, { ...ctx })
|
|
3083
1472
|
};
|
|
3084
|
-
var generativeRenderers =
|
|
1473
|
+
var generativeRenderers = withDeclaredProps(
|
|
1474
|
+
baseCatalog.data.components,
|
|
1475
|
+
components,
|
|
1476
|
+
// A hatch resolves its `path` as written, relative inside a repeat, so a
|
|
1477
|
+
// refused one reaches it as refused rather than written out as text.
|
|
1478
|
+
{ MthdsField: ["path"], MthdsResult: ["path"] }
|
|
1479
|
+
);
|
|
3085
1480
|
var RADIUS = "rounded-[calc(var(--radius,0.5rem)*1.5)]";
|
|
3086
1481
|
function useAbsolute(path) {
|
|
3087
1482
|
const repeat = useRepeatScope();
|
|
@@ -3229,10 +1624,12 @@ function amount(value, unit) {
|
|
|
3229
1624
|
return unit ? `${n} ${unit}` : n;
|
|
3230
1625
|
}
|
|
3231
1626
|
function ProportionBar({ props }) {
|
|
3232
|
-
const rows = Array.isArray(props.items) ? props.items : []
|
|
1627
|
+
const rows = (Array.isArray(props.items) ? props.items : []).filter(
|
|
1628
|
+
(row) => typeof row === "object" && row !== null && !Array.isArray(row)
|
|
1629
|
+
);
|
|
3233
1630
|
const parts = rows.map((row) => ({
|
|
3234
|
-
label:
|
|
3235
|
-
value:
|
|
1631
|
+
label: textOf(row[props.labelKey]),
|
|
1632
|
+
value: shareAmount(row[props.valueKey])
|
|
3236
1633
|
})).filter((p) => Number.isFinite(p.value) && p.value > 0);
|
|
3237
1634
|
const sum = parts.reduce((s, p) => s + p.value, 0);
|
|
3238
1635
|
const total = typeof props.total === "number" ? props.total : sum;
|
|
@@ -3317,10 +1714,11 @@ var ASPECT = {
|
|
|
3317
1714
|
function Picture({
|
|
3318
1715
|
props
|
|
3319
1716
|
}) {
|
|
3320
|
-
const
|
|
1717
|
+
const written = typeof props.path === "string" ? props.path : void 0;
|
|
1718
|
+
const path = useAbsolute(written ?? "");
|
|
3321
1719
|
const value = useStateValue(path);
|
|
3322
1720
|
const resolve = useResolveUrl();
|
|
3323
|
-
const content = readImageContent(value);
|
|
1721
|
+
const content = written === void 0 ? void 0 : readImageContent(value);
|
|
3324
1722
|
const src = content ? viewableUrl(resolve?.(content.url)) ?? viewableUrl(content.publicUrl) ?? viewableUrl(content.url) : void 0;
|
|
3325
1723
|
const aspect = props.aspect && props.aspect !== "auto" ? ASPECT[props.aspect] : void 0;
|
|
3326
1724
|
if (!src) return null;
|
|
@@ -3337,26 +1735,25 @@ function Picture({
|
|
|
3337
1735
|
}
|
|
3338
1736
|
);
|
|
3339
1737
|
}
|
|
3340
|
-
function present(value) {
|
|
3341
|
-
return value !== void 0 && value !== null && value !== "";
|
|
3342
|
-
}
|
|
3343
1738
|
function Fact({
|
|
3344
1739
|
props
|
|
3345
1740
|
}) {
|
|
1741
|
+
const text = textOf(props.value);
|
|
3346
1742
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 rounded-[var(--radius,0.5rem)] border border-border bg-background px-4 py-3", children: [
|
|
3347
1743
|
/* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.label }),
|
|
3348
|
-
/* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children:
|
|
1744
|
+
/* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children: text !== "" ? text : "\u2014" }),
|
|
3349
1745
|
props.detail ? /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.detail }) : null
|
|
3350
1746
|
] });
|
|
3351
1747
|
}
|
|
3352
1748
|
function Detail({ props }) {
|
|
3353
|
-
|
|
1749
|
+
const text = textOf(props.value);
|
|
1750
|
+
if (text === "") return null;
|
|
3354
1751
|
return (
|
|
3355
1752
|
// A rule between the rows of a list of details, never under one set in a
|
|
3356
1753
|
// row: there it read as an underline on every detail but the last.
|
|
3357
1754
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,8.5rem)_minmax(0,1fr)] gap-3 border-b border-border py-2.5 text-[14px] last:border-b-0 [.flex-row>&]:border-b-0 [.flex-row>&]:grid-cols-[auto_minmax(0,1fr)]", children: [
|
|
3358
1755
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: props.label }),
|
|
3359
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground", children:
|
|
1756
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground", children: text })
|
|
3360
1757
|
] })
|
|
3361
1758
|
);
|
|
3362
1759
|
}
|
|
@@ -3393,19 +1790,25 @@ function TextList({ props }) {
|
|
|
3393
1790
|
/* @__PURE__ */ jsx("span", { className: "min-w-0", children: String(text) })
|
|
3394
1791
|
] }, index)) });
|
|
3395
1792
|
}
|
|
3396
|
-
var frameRenderers =
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
}
|
|
3408
|
-
|
|
1793
|
+
var frameRenderers = withDeclaredProps(
|
|
1794
|
+
frameComponents,
|
|
1795
|
+
{
|
|
1796
|
+
TextList: (ctx) => /* @__PURE__ */ jsx(TextList, { ...ctx }),
|
|
1797
|
+
DateText: (ctx) => /* @__PURE__ */ jsx(DateText, { ...ctx }),
|
|
1798
|
+
Composer: (ctx) => /* @__PURE__ */ jsx(Composer, { ...ctx }),
|
|
1799
|
+
FieldGroup: (ctx) => /* @__PURE__ */ jsx(FieldGroup, { ...ctx }),
|
|
1800
|
+
ResultHeader: (ctx) => /* @__PURE__ */ jsx(ResultHeader, { ...ctx }),
|
|
1801
|
+
ProportionBar: (ctx) => /* @__PURE__ */ jsx(ProportionBar, { ...ctx }),
|
|
1802
|
+
Swatches: (ctx) => /* @__PURE__ */ jsx(Swatches, { ...ctx }),
|
|
1803
|
+
Picture: (ctx) => /* @__PURE__ */ jsx(Picture, { ...ctx }),
|
|
1804
|
+
Fact: (ctx) => /* @__PURE__ */ jsx(Fact, { ...ctx }),
|
|
1805
|
+
Detail: (ctx) => /* @__PURE__ */ jsx(Detail, { ...ctx })
|
|
1806
|
+
},
|
|
1807
|
+
// A refused `path` reaches the renderer as refused: its nearest value, the
|
|
1808
|
+
// empty text, is the item itself inside a repeat.
|
|
1809
|
+
{ Picture: ["path"] }
|
|
1810
|
+
);
|
|
1811
|
+
var ResultSlotContext = React6.createContext(null);
|
|
3409
1812
|
function ResultSlotProvider({
|
|
3410
1813
|
slot,
|
|
3411
1814
|
children
|
|
@@ -3413,58 +1816,11 @@ function ResultSlotProvider({
|
|
|
3413
1816
|
return /* @__PURE__ */ jsx(ResultSlotContext.Provider, { value: slot, children });
|
|
3414
1817
|
}
|
|
3415
1818
|
function useResultSlot() {
|
|
3416
|
-
return
|
|
1819
|
+
return React6.useContext(ResultSlotContext);
|
|
3417
1820
|
}
|
|
3418
|
-
var CONTAINER = "mx-auto w-full max-w-6xl px-6 sm:px-8";
|
|
3419
1821
|
var LABEL2 = "block text-[13.5px] leading-none font-medium text-foreground";
|
|
3420
1822
|
function AppBar({ props }) {
|
|
3421
|
-
|
|
3422
|
-
return /* @__PURE__ */ jsx("header", { className: "border-b border-border", children: /* @__PURE__ */ jsxs("div", { className: cn(CONTAINER, "flex h-16 items-center gap-5"), children: [
|
|
3423
|
-
/* @__PURE__ */ jsx(
|
|
3424
|
-
"img",
|
|
3425
|
-
{
|
|
3426
|
-
src: brand.logo.onLight,
|
|
3427
|
-
alt: brand.name,
|
|
3428
|
-
referrerPolicy: "no-referrer",
|
|
3429
|
-
className: "h-7 w-auto dark:hidden"
|
|
3430
|
-
}
|
|
3431
|
-
),
|
|
3432
|
-
/* @__PURE__ */ jsx(
|
|
3433
|
-
"img",
|
|
3434
|
-
{
|
|
3435
|
-
src: brand.logo.onDark,
|
|
3436
|
-
alt: brand.name,
|
|
3437
|
-
referrerPolicy: "no-referrer",
|
|
3438
|
-
className: "hidden h-7 w-auto dark:block"
|
|
3439
|
-
}
|
|
3440
|
-
),
|
|
3441
|
-
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "h-5 w-px bg-border" }),
|
|
3442
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground/80", children: props.app }),
|
|
3443
|
-
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex min-w-0 items-center gap-6", children: [
|
|
3444
|
-
props.links && props.links.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Site", className: "hidden items-center gap-6 sm:flex", children: props.links.map((link) => /* @__PURE__ */ jsx(
|
|
3445
|
-
"a",
|
|
3446
|
-
{
|
|
3447
|
-
href: "#",
|
|
3448
|
-
onClick: (event) => event.preventDefault(),
|
|
3449
|
-
className: "rounded-sm text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-hidden",
|
|
3450
|
-
children: link
|
|
3451
|
-
},
|
|
3452
|
-
link
|
|
3453
|
-
)) }) : null,
|
|
3454
|
-
props.tag ? /* @__PURE__ */ jsx(
|
|
3455
|
-
"span",
|
|
3456
|
-
{
|
|
3457
|
-
className: cn(
|
|
3458
|
-
"min-w-0 truncate rounded-lg border px-2.5 py-1 font-mono text-[11px]",
|
|
3459
|
-
selectedBorderClass,
|
|
3460
|
-
selectedFillClass,
|
|
3461
|
-
linkTextClass
|
|
3462
|
-
),
|
|
3463
|
-
children: props.tag
|
|
3464
|
-
}
|
|
3465
|
-
) : null
|
|
3466
|
-
] })
|
|
3467
|
-
] }) });
|
|
1823
|
+
return /* @__PURE__ */ jsx(BrandBar, { app: props.app, links: props.links, tag: props.tag });
|
|
3468
1824
|
}
|
|
3469
1825
|
function Hero({ props }) {
|
|
3470
1826
|
return /* @__PURE__ */ jsxs("section", { className: "pt-12 pb-10 sm:pt-14 sm:pb-12", children: [
|
|
@@ -3489,7 +1845,7 @@ function Hero({ props }) {
|
|
|
3489
1845
|
] });
|
|
3490
1846
|
}
|
|
3491
1847
|
function Workspace({ props, children }) {
|
|
3492
|
-
const [work, rail] =
|
|
1848
|
+
const [work, rail] = React6.Children.toArray(children);
|
|
3493
1849
|
const railLeft = props.rail === "left";
|
|
3494
1850
|
return /* @__PURE__ */ jsxs(
|
|
3495
1851
|
"div",
|
|
@@ -3561,11 +1917,8 @@ function Rail({ props, children }) {
|
|
|
3561
1917
|
)
|
|
3562
1918
|
);
|
|
3563
1919
|
}
|
|
3564
|
-
function present2(value) {
|
|
3565
|
-
return value !== void 0 && value !== null && value !== "";
|
|
3566
|
-
}
|
|
3567
1920
|
function SummaryRow({ props }) {
|
|
3568
|
-
const text = [props.value, props.detail].
|
|
1921
|
+
const text = [props.value, props.detail].map(textOf).filter((half) => half !== "").join(props.separator ?? " ");
|
|
3569
1922
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-4 border-b border-border/60 py-3 first:pt-0 last:border-b-0", children: [
|
|
3570
1923
|
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] text-muted-foreground", children: props.label }),
|
|
3571
1924
|
text ? /* @__PURE__ */ jsx("span", { className: "text-right text-[13px] font-medium text-foreground", children: text }) : /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground/50", children: props.placeholder ?? "\u2014" })
|
|
@@ -3618,13 +1971,13 @@ function useTextField(props, bindings) {
|
|
|
3618
1971
|
props.value ?? void 0,
|
|
3619
1972
|
bindings?.value
|
|
3620
1973
|
);
|
|
3621
|
-
const [localValue, setLocalValue] =
|
|
1974
|
+
const [localValue, setLocalValue] = React6.useState("");
|
|
3622
1975
|
const isBound = Boolean(bindings?.value);
|
|
3623
1976
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
3624
1977
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
3625
1978
|
const validateOn = props.validateOn ?? "blur";
|
|
3626
1979
|
const hasValidation = Boolean(bindings?.value && props.checks?.length);
|
|
3627
|
-
const { errors, validate } =
|
|
1980
|
+
const { errors, validate } = useCheckedField(
|
|
3628
1981
|
bindings?.value ?? "",
|
|
3629
1982
|
hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
|
|
3630
1983
|
);
|
|
@@ -3698,16 +2051,20 @@ function BrandTextarea({
|
|
|
3698
2051
|
var { registry: generativeRegistry } = defineRegistry(catalog, {
|
|
3699
2052
|
components: {
|
|
3700
2053
|
...generativeRenderers,
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
2054
|
+
// Held to their definitions as the base and frame renderers are
|
|
2055
|
+
// (`declared-props.ts`).
|
|
2056
|
+
...withDeclaredProps(catalog.data.components, {
|
|
2057
|
+
Input: (ctx) => /* @__PURE__ */ jsx(BrandInput, { ...ctx }),
|
|
2058
|
+
Textarea: (ctx) => /* @__PURE__ */ jsx(BrandTextarea, { ...ctx }),
|
|
2059
|
+
AppBar: (ctx) => /* @__PURE__ */ jsx(AppBar, { ...ctx }),
|
|
2060
|
+
Hero: (ctx) => /* @__PURE__ */ jsx(Hero, { ...ctx }),
|
|
2061
|
+
Workspace: (ctx) => /* @__PURE__ */ jsx(Workspace, { ...ctx }),
|
|
2062
|
+
Section: (ctx) => /* @__PURE__ */ jsx(Section, { ...ctx }),
|
|
2063
|
+
Rail: (ctx) => /* @__PURE__ */ jsx(Rail, { ...ctx }),
|
|
2064
|
+
SummaryRow: (ctx) => /* @__PURE__ */ jsx(SummaryRow, { ...ctx }),
|
|
2065
|
+
Cta: (ctx) => /* @__PURE__ */ jsx(Cta, { ...ctx }),
|
|
2066
|
+
Footer: (ctx) => /* @__PURE__ */ jsx(Footer, { ...ctx })
|
|
2067
|
+
}),
|
|
3711
2068
|
...frameRenderers
|
|
3712
2069
|
}
|
|
3713
2070
|
});
|
|
@@ -3718,130 +2075,100 @@ function GenerativePage({
|
|
|
3718
2075
|
onRun,
|
|
3719
2076
|
loading,
|
|
3720
2077
|
registry = generativeRegistry,
|
|
3721
|
-
brand
|
|
2078
|
+
brand,
|
|
2079
|
+
onElementError
|
|
3722
2080
|
}) {
|
|
3723
2081
|
const { inputs, result, env, idPrefix } = scope;
|
|
3724
|
-
const stableScope =
|
|
2082
|
+
const stableScope = React6.useMemo(
|
|
3725
2083
|
() => ({ inputs, result, env, idPrefix }),
|
|
3726
2084
|
[inputs, result, env, idPrefix]
|
|
3727
2085
|
);
|
|
3728
|
-
const latest =
|
|
3729
|
-
|
|
2086
|
+
const latest = React6.useRef({ onRun, store });
|
|
2087
|
+
React6.useEffect(() => {
|
|
3730
2088
|
latest.current = { onRun, store };
|
|
3731
2089
|
});
|
|
3732
|
-
const
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
2090
|
+
const report = React6.useRef(onElementError);
|
|
2091
|
+
React6.useInsertionEffect(() => {
|
|
2092
|
+
report.current = onElementError;
|
|
2093
|
+
});
|
|
2094
|
+
const [made] = React6.useState(() => /* @__PURE__ */ new Map());
|
|
2095
|
+
const pageRegistry = React6.useMemo(
|
|
2096
|
+
() => reportingRegistry(registry, report, made),
|
|
2097
|
+
[registry, made]
|
|
2098
|
+
);
|
|
2099
|
+
const rootType = spec?.elements?.[spec.root]?.type ?? "root";
|
|
2100
|
+
const reporting = onElementError !== void 0;
|
|
2101
|
+
const validation = React6.useRef(null);
|
|
2102
|
+
const [checkedFields] = React6.useState(() => new CheckedFields());
|
|
2103
|
+
const running = React6.useRef(false);
|
|
2104
|
+
const [handlers] = React6.useState(() => {
|
|
2105
|
+
const release = () => {
|
|
2106
|
+
setTimeout(() => {
|
|
3741
2107
|
running.current = false;
|
|
3742
|
-
|
|
2108
|
+
}, 0);
|
|
2109
|
+
};
|
|
2110
|
+
return {
|
|
2111
|
+
run: () => {
|
|
2112
|
+
if (running.current) return void 0;
|
|
2113
|
+
const checks = validation.current;
|
|
2114
|
+
if (checks) {
|
|
2115
|
+
const registered = checks.validateAll();
|
|
2116
|
+
const mounted = checkedFields.check(checks);
|
|
2117
|
+
if (!registered || !mounted) return void 0;
|
|
2118
|
+
}
|
|
2119
|
+
running.current = true;
|
|
2120
|
+
let pending;
|
|
2121
|
+
try {
|
|
2122
|
+
pending = latest.current.onRun?.(latest.current.store.getSnapshot());
|
|
2123
|
+
} catch (error) {
|
|
2124
|
+
release();
|
|
2125
|
+
throw error;
|
|
2126
|
+
}
|
|
2127
|
+
if (isThenable(pending)) {
|
|
2128
|
+
const settled = Promise.resolve(pending);
|
|
2129
|
+
settled.then(release, release);
|
|
2130
|
+
return settled;
|
|
2131
|
+
}
|
|
2132
|
+
release();
|
|
2133
|
+
return void 0;
|
|
3743
2134
|
}
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
2135
|
+
};
|
|
2136
|
+
});
|
|
2137
|
+
const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry: pageRegistry, store, handlers, children: /* @__PURE__ */ jsx(ReportingContext.Provider, { value: reporting, children: /* @__PURE__ */ jsxs(CheckedFieldsContext.Provider, { value: checkedFields, children: [
|
|
2138
|
+
/* @__PURE__ */ jsx(ValidationBridge, { into: validation, fields: checkedFields }),
|
|
2139
|
+
/* @__PURE__ */ jsx(
|
|
2140
|
+
RootBoundary,
|
|
2141
|
+
{
|
|
2142
|
+
type: rootType,
|
|
2143
|
+
report,
|
|
2144
|
+
reporting,
|
|
2145
|
+
loading: loading === true,
|
|
2146
|
+
spec,
|
|
2147
|
+
children: /* @__PURE__ */ jsx(Renderer, { spec, registry: pageRegistry, loading })
|
|
3748
2148
|
}
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
}
|
|
3752
|
-
}));
|
|
3753
|
-
const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry, store, handlers, children: /* @__PURE__ */ jsx(Renderer, { spec, registry, loading }) }) });
|
|
2149
|
+
)
|
|
2150
|
+
] }) }) }) });
|
|
3754
2151
|
return brand ? /* @__PURE__ */ jsx(BrandProvider, { manifest: brand, children: page }) : page;
|
|
3755
2152
|
}
|
|
2153
|
+
function ValidationBridge({
|
|
2154
|
+
into,
|
|
2155
|
+
fields
|
|
2156
|
+
}) {
|
|
2157
|
+
const validation = useOptionalValidation();
|
|
2158
|
+
React6.useInsertionEffect(() => {
|
|
2159
|
+
into.current = validation;
|
|
2160
|
+
fields.attach(validation);
|
|
2161
|
+
});
|
|
2162
|
+
return null;
|
|
2163
|
+
}
|
|
3756
2164
|
function useStoreSnapshot(store) {
|
|
3757
|
-
return
|
|
2165
|
+
return React6.useSyncExternalStore(
|
|
3758
2166
|
store.subscribe,
|
|
3759
2167
|
store.getSnapshot,
|
|
3760
2168
|
store.getServerSnapshot ?? store.getSnapshot
|
|
3761
2169
|
);
|
|
3762
2170
|
}
|
|
3763
2171
|
|
|
3764
|
-
|
|
3765
|
-
function isRecord(value) {
|
|
3766
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3767
|
-
}
|
|
3768
|
-
function payloadToState(field, payload) {
|
|
3769
|
-
if (payload === void 0 || payload === null) return payload;
|
|
3770
|
-
if (isNativeValueNode(field)) return payload;
|
|
3771
|
-
switch (field.kind) {
|
|
3772
|
-
case "date": {
|
|
3773
|
-
const content = readDateContent(payload);
|
|
3774
|
-
return content ? formatDateContent(content) : payload;
|
|
3775
|
-
}
|
|
3776
|
-
case "list": {
|
|
3777
|
-
const items = Array.isArray(payload) ? payload : isRecord(payload) && Array.isArray(payload.items) ? payload.items : void 0;
|
|
3778
|
-
if (!items) return payload;
|
|
3779
|
-
return items.map((item) => payloadToState(field.item, item));
|
|
3780
|
-
}
|
|
3781
|
-
case "object": {
|
|
3782
|
-
if (!isRecord(payload)) return payload;
|
|
3783
|
-
const out = { ...payload };
|
|
3784
|
-
for (const child of field.fields) {
|
|
3785
|
-
if (hasOwnProp(payload, child.name)) {
|
|
3786
|
-
out[child.name] = payloadToState(child, payload[child.name]);
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
return out;
|
|
3790
|
-
}
|
|
3791
|
-
case "document":
|
|
3792
|
-
case "image":
|
|
3793
|
-
case "text":
|
|
3794
|
-
case "prose":
|
|
3795
|
-
case "number":
|
|
3796
|
-
case "boolean":
|
|
3797
|
-
case "enum":
|
|
3798
|
-
case "unknown":
|
|
3799
|
-
return payload;
|
|
3800
|
-
default:
|
|
3801
|
-
return field;
|
|
3802
|
-
}
|
|
3803
|
-
}
|
|
3804
|
-
|
|
3805
|
-
// src/generative/fixture.ts
|
|
3806
|
-
function fixtureId(fixture) {
|
|
3807
|
-
return [
|
|
3808
|
-
fixture.producer,
|
|
3809
|
-
fixture.model,
|
|
3810
|
-
fixture.frame ?? null,
|
|
3811
|
-
fixture.style ?? null,
|
|
3812
|
-
fixture.seed ? "seeded" : null,
|
|
3813
|
-
fixture.critic ? "critic" : null
|
|
3814
|
-
].filter((part) => part !== null).join("--");
|
|
3815
|
-
}
|
|
3816
|
-
var PRODUCER_LABEL = {
|
|
3817
|
-
"pipelex-method": "Pipelex method",
|
|
3818
|
-
"claude-code-subagent": "Claude Code subagent",
|
|
3819
|
-
"claude-code-session": "Claude Code session, by hand"
|
|
3820
|
-
};
|
|
3821
|
-
function fixtureLabel(fixture) {
|
|
3822
|
-
const parts = [PRODUCER_LABEL[fixture.producer], fixture.model];
|
|
3823
|
-
if (fixture.frame) parts.push(`${fixture.frame} frame`);
|
|
3824
|
-
if (fixture.style) parts.push(`${fixture.style} style`);
|
|
3825
|
-
if (fixture.seed) parts.push("with a seed");
|
|
3826
|
-
if (fixture.repairs) parts.push(`repaired \xD7 ${fixture.repairs}`);
|
|
3827
|
-
if (fixture.critic) {
|
|
3828
|
-
parts.push(
|
|
3829
|
-
`${fixture.critic.model} critic \xD7 ${fixture.critic.rounds} round${fixture.critic.rounds === 1 ? "" : "s"}`
|
|
3830
|
-
);
|
|
3831
|
-
}
|
|
3832
|
-
return parts.join(" \xB7 ");
|
|
3833
|
-
}
|
|
3834
|
-
function findFixture(fixtures, pipeRef, id) {
|
|
3835
|
-
const found = fixtures.find(
|
|
3836
|
-
(fixture) => fixture.pipeRef === pipeRef && fixtureId(fixture) === id
|
|
3837
|
-
);
|
|
3838
|
-
if (!found) {
|
|
3839
|
-
const known = fixtures.filter((fixture) => fixture.pipeRef === pipeRef).map(fixtureId).join(", ");
|
|
3840
|
-
throw new Error(`No spec fixture ${id} for ${pipeRef}. Known: ${known || "none"}.`);
|
|
3841
|
-
}
|
|
3842
|
-
return found;
|
|
3843
|
-
}
|
|
3844
|
-
|
|
3845
|
-
export { BrandProvider, COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, DescriptorProvider, FRAMES, FRAME_COMPONENTS, FrameHostProvider, GenerativePage, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, ResultSlotProvider, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, domIdFor, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, generativeRegistry, generativeRenderers, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheckProblems, layoutFits, layoutProblems, pathFromDomId, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, useBrand, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot, validateAgainstCatalog };
|
|
2172
|
+
export { BrandBar, BrandProvider, DescriptorProvider, FrameHostProvider, GenerativePage, ResultSlotProvider, domIdFor, generativeRegistry, generativeRenderers, pathFromDomId, useBrand, useCheckedField, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot };
|
|
3846
2173
|
//# sourceMappingURL=index.js.map
|
|
3847
2174
|
//# sourceMappingURL=index.js.map
|