@pipelex/mthds-form 0.30.0 → 0.32.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 +11 -257
- package/dist/brand/index.js +11 -645
- package/dist/brand/index.js.map +1 -1
- package/dist/chunk-3GO65HWP.js +693 -0
- package/dist/chunk-3GO65HWP.js.map +1 -0
- package/dist/{chunk-JCFALTTY.js → chunk-PCNFELNT.js} +112 -24
- package/dist/chunk-PCNFELNT.js.map +1 -0
- package/dist/chunk-QGFR57OH.js +35 -0
- package/dist/chunk-QGFR57OH.js.map +1 -0
- package/dist/chunk-VBXFGUCG.js +2221 -0
- package/dist/chunk-VBXFGUCG.js.map +1 -0
- package/dist/generative/headless/index.d.ts +1702 -0
- package/dist/generative/headless/index.js +6 -0
- package/dist/generative/headless/index.js.map +1 -0
- package/dist/generative/index.d.ts +108 -1342
- package/dist/generative/index.js +686 -1923
- package/dist/generative/index.js.map +1 -1
- package/dist/layout-design.mthds +133 -6
- package/dist/{manifest-DUeAWeqa.d.ts → manifest-D3DLyNEv.d.ts} +2 -2
- package/dist/react/index.d.ts +18 -3
- package/dist/react/index.js +1 -1
- package/dist/styles-Bn8byNdo.d.ts +242 -0
- package/dist/styles.css +1 -1
- package/package.json +5 -1
- package/dist/chunk-JCFALTTY.js.map +0 -1
- package/dist/chunk-QFX332LE.js +0 -22
- package/dist/chunk-QFX332LE.js.map +0 -1
package/dist/generative/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn, headingClass, checkedAccentClass, focusOutlineClass,
|
|
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-PCNFELNT.js';
|
|
3
|
+
import { baseCatalog, catalog, frameComponents, resultFieldAtPath, segmentsUnder, RESULT_ROOT, inputFieldAtPath } from '../chunk-VBXFGUCG.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, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog } from '../chunk-VBXFGUCG.js';
|
|
3
5
|
import '../chunk-4VAO6BDE.js';
|
|
4
6
|
export { seedInputs } from '../chunk-VH5CDQDR.js';
|
|
5
7
|
import '../chunk-L23R3JNQ.js';
|
|
6
8
|
import '../chunk-56WECFBD.js';
|
|
7
9
|
import '../chunk-ZX52CQJ4.js';
|
|
8
10
|
import '../chunk-GHVVULHY.js';
|
|
9
|
-
import {
|
|
10
|
-
export { brandManifestSchema } from '../chunk-
|
|
11
|
+
import { readImageContent, viewableUrl, readDateContent } from '../chunk-QQK6Y55E.js';
|
|
12
|
+
export { brandManifestSchema } from '../chunk-QGFR57OH.js';
|
|
13
|
+
import '../chunk-3GO65HWP.js';
|
|
11
14
|
import '../chunk-ZB4RYUKV.js';
|
|
12
15
|
import '../chunk-FABY3DEY.js';
|
|
13
16
|
import '../chunk-XCO6GTEC.js';
|
|
@@ -17,1796 +20,239 @@ import '../chunk-OD3VYXUY.js';
|
|
|
17
20
|
import '../chunk-WYH56SOZ.js';
|
|
18
21
|
import { hasOwnProp } from '../chunk-V3OV2XQT.js';
|
|
19
22
|
import '../chunk-GKV77RAS.js';
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
22
|
-
import * as React3 from 'react';
|
|
23
|
-
import { defineRegistry, useStateValue, useStateStore, useBoundProp, useFieldValidation, useRepeatScope, JSONUIProvider, Renderer } from '@json-render/react';
|
|
23
|
+
import * as React5 from 'react';
|
|
24
|
+
import { defineRegistry, useStateValue, useRepeatScope, useStateStore, useBoundProp, useFieldValidation, JSONUIProvider, Renderer } from '@json-render/react';
|
|
24
25
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
25
|
-
import { 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,
|
|
26
|
+
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';
|
|
26
27
|
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
28
|
+
export { createStateStore } from '@json-render/core';
|
|
27
29
|
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
props: s.propsOf("catalog.components"),
|
|
36
|
-
children: s.array(s.string()),
|
|
37
|
-
slots: { ...s.record(s.array(s.string())), ...s.optional() },
|
|
38
|
-
visible: { ...s.any(), ...s.optional() },
|
|
39
|
-
repeat: { ...s.any(), ...s.optional() }
|
|
40
|
-
})
|
|
41
|
-
)
|
|
42
|
-
}),
|
|
43
|
-
catalog: s.object({
|
|
44
|
-
components: s.map({
|
|
45
|
-
props: s.zod(),
|
|
46
|
-
slots: s.array(s.string()),
|
|
47
|
-
description: s.string(),
|
|
48
|
-
example: s.any()
|
|
49
|
-
}),
|
|
50
|
-
actions: s.map({
|
|
51
|
-
params: s.zod(),
|
|
52
|
-
description: s.string()
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
}),
|
|
56
|
-
{
|
|
57
|
-
// The runtime handles these four without a registry handler; the names and
|
|
58
|
-
// the wording are the React schema's, so a model that has seen json-render
|
|
59
|
-
// before recognises them. The validator reads them to know which actions
|
|
60
|
-
// need no handler, and `designerCatalog()` lists them first, marked
|
|
61
|
-
// built-in, so the method's prompt names them beside the catalog's own.
|
|
62
|
-
builtInActions: [
|
|
63
|
-
{
|
|
64
|
-
name: "setState",
|
|
65
|
-
description: "Update a value in the state model at the given statePath. Params: { statePath: string, value: any }"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: "pushState",
|
|
69
|
-
description: "Append an item to an array in state. Params: { statePath: string, value: any, clearStatePath?: string }."
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: "removeState",
|
|
73
|
-
description: "Remove an item from an array in state by index. Params: { statePath: string, index: number }"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: "validateForm",
|
|
77
|
-
description: "Validate all registered form fields and write the result to state. Params: { statePath?: string }. Defaults to /formValidation."
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
var validationCheckSchema = z.array(
|
|
83
|
-
z.object({
|
|
84
|
-
type: z.string(),
|
|
85
|
-
message: z.string(),
|
|
86
|
-
args: z.record(z.string(), z.unknown()).optional()
|
|
87
|
-
})
|
|
88
|
-
).nullable();
|
|
89
|
-
var validateOnSchema = z.enum(["change", "blur", "submit"]).nullable();
|
|
90
|
-
var shadcnComponentDefinitions = {
|
|
91
|
-
// ── Layout ────────────────────────────────────────────────────────────────
|
|
92
|
-
Card: {
|
|
93
|
-
props: z.object({
|
|
94
|
-
title: z.string().nullable(),
|
|
95
|
-
description: z.string().nullable(),
|
|
96
|
-
maxWidth: z.enum(["sm", "md", "lg", "full"]).nullable(),
|
|
97
|
-
centered: z.boolean().nullable(),
|
|
98
|
-
className: z.string().nullable().describe("Additional CSS classes")
|
|
99
|
-
}),
|
|
100
|
-
slots: ["default"],
|
|
101
|
-
description: "Container card for content sections. Use for forms/content boxes, NOT for page headers.",
|
|
102
|
-
example: { title: "Overview", description: "Your account summary" }
|
|
103
|
-
},
|
|
104
|
-
Stack: {
|
|
105
|
-
props: z.object({
|
|
106
|
-
direction: z.enum(["horizontal", "vertical"]).nullable(),
|
|
107
|
-
gap: z.enum(["none", "sm", "md", "lg", "xl"]).nullable(),
|
|
108
|
-
align: z.enum(["start", "center", "end", "stretch"]).nullable(),
|
|
109
|
-
justify: z.enum(["start", "center", "end", "between", "around"]).nullable(),
|
|
110
|
-
className: z.string().nullable().describe("Additional CSS classes")
|
|
111
|
-
}),
|
|
112
|
-
slots: ["default"],
|
|
113
|
-
description: "Flex container for layouts",
|
|
114
|
-
example: { direction: "vertical", gap: "md" }
|
|
115
|
-
},
|
|
116
|
-
Grid: {
|
|
117
|
-
props: z.object({
|
|
118
|
-
columns: z.number().nullable(),
|
|
119
|
-
gap: z.enum(["sm", "md", "lg", "xl"]).nullable(),
|
|
120
|
-
className: z.string().nullable().describe("Additional CSS classes")
|
|
121
|
-
}),
|
|
122
|
-
slots: ["default"],
|
|
123
|
-
description: "Grid layout (1-6 columns)",
|
|
124
|
-
example: { columns: 3, gap: "md" }
|
|
125
|
-
},
|
|
126
|
-
Separator: {
|
|
127
|
-
props: z.object({
|
|
128
|
-
orientation: z.enum(["horizontal", "vertical"]).nullable()
|
|
129
|
-
}),
|
|
130
|
-
description: "Visual separator line"
|
|
131
|
-
},
|
|
132
|
-
Collapsible: {
|
|
133
|
-
props: z.object({
|
|
134
|
-
title: z.string(),
|
|
135
|
-
defaultOpen: z.boolean().nullable()
|
|
136
|
-
}),
|
|
137
|
-
slots: ["default"],
|
|
138
|
-
description: "Collapsible section with trigger. Children render inside."
|
|
139
|
-
},
|
|
140
|
-
// ── Content ───────────────────────────────────────────────────────────────
|
|
141
|
-
Heading: {
|
|
142
|
-
props: z.object({
|
|
143
|
-
text: z.string(),
|
|
144
|
-
level: z.enum(["h1", "h2", "h3", "h4"]).nullable()
|
|
145
|
-
}),
|
|
146
|
-
description: "Heading text (h1-h4)",
|
|
147
|
-
example: { text: "Welcome", level: "h1" }
|
|
148
|
-
},
|
|
149
|
-
Text: {
|
|
150
|
-
props: z.object({
|
|
151
|
-
text: z.string(),
|
|
152
|
-
variant: z.enum(["body", "caption", "muted", "lead", "code"]).nullable()
|
|
153
|
-
}),
|
|
154
|
-
description: "Paragraph text",
|
|
155
|
-
example: { text: "Hello, world!" }
|
|
156
|
-
},
|
|
157
|
-
Avatar: {
|
|
158
|
-
props: z.object({
|
|
159
|
-
src: z.string().nullable(),
|
|
160
|
-
name: z.string(),
|
|
161
|
-
size: z.enum(["sm", "md", "lg"]).nullable()
|
|
162
|
-
}),
|
|
163
|
-
description: "User avatar with fallback initials",
|
|
164
|
-
example: { name: "Jane Doe", size: "md" }
|
|
165
|
-
},
|
|
166
|
-
Badge: {
|
|
167
|
-
props: z.object({
|
|
168
|
-
text: z.string(),
|
|
169
|
-
variant: z.enum(["default", "secondary", "destructive", "outline"]).nullable()
|
|
170
|
-
}),
|
|
171
|
-
description: "Status badge",
|
|
172
|
-
example: { text: "Active", variant: "default" }
|
|
173
|
-
},
|
|
174
|
-
Alert: {
|
|
175
|
-
props: z.object({
|
|
176
|
-
title: z.string(),
|
|
177
|
-
message: z.string().nullable(),
|
|
178
|
-
type: z.enum(["info", "success", "warning", "error"]).nullable()
|
|
179
|
-
}),
|
|
180
|
-
description: "Alert banner",
|
|
181
|
-
example: {
|
|
182
|
-
title: "Note",
|
|
183
|
-
message: "Your changes have been saved.",
|
|
184
|
-
type: "success"
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
Progress: {
|
|
188
|
-
props: z.object({
|
|
189
|
-
value: z.number(),
|
|
190
|
-
max: z.number().nullable(),
|
|
191
|
-
label: z.string().nullable()
|
|
192
|
-
}),
|
|
193
|
-
description: "Progress bar (value 0-100)",
|
|
194
|
-
example: { value: 65, max: 100, label: "Upload progress" }
|
|
195
|
-
},
|
|
196
|
-
// ── Inputs ────────────────────────────────────────────────────────────────
|
|
197
|
-
Input: {
|
|
198
|
-
props: z.object({
|
|
199
|
-
label: z.string(),
|
|
200
|
-
name: z.string(),
|
|
201
|
-
type: z.enum(["text", "email", "password", "number"]).nullable(),
|
|
202
|
-
placeholder: z.string().nullable(),
|
|
203
|
-
value: z.string().nullable(),
|
|
204
|
-
checks: validationCheckSchema,
|
|
205
|
-
validateOn: validateOnSchema
|
|
206
|
-
}),
|
|
207
|
-
events: ["submit", "focus", "blur"],
|
|
208
|
-
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).",
|
|
209
|
-
example: {
|
|
210
|
-
label: "Email",
|
|
211
|
-
name: "email",
|
|
212
|
-
type: "email",
|
|
213
|
-
placeholder: "you@example.com"
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
Textarea: {
|
|
217
|
-
props: z.object({
|
|
218
|
-
label: z.string(),
|
|
219
|
-
name: z.string(),
|
|
220
|
-
placeholder: z.string().nullable(),
|
|
221
|
-
rows: z.number().nullable(),
|
|
222
|
-
value: z.string().nullable(),
|
|
223
|
-
checks: validationCheckSchema,
|
|
224
|
-
validateOn: validateOnSchema
|
|
225
|
-
}),
|
|
226
|
-
description: "Multi-line text input. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: blur)."
|
|
227
|
-
},
|
|
228
|
-
Select: {
|
|
229
|
-
props: z.object({
|
|
230
|
-
label: z.string(),
|
|
231
|
-
name: z.string(),
|
|
232
|
-
options: z.array(z.string().min(1)),
|
|
233
|
-
placeholder: z.string().nullable(),
|
|
234
|
-
value: z.string().nullable(),
|
|
235
|
-
checks: validationCheckSchema,
|
|
236
|
-
validateOn: validateOnSchema
|
|
237
|
-
}),
|
|
238
|
-
events: ["change"],
|
|
239
|
-
description: "Dropdown select input. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
240
|
-
},
|
|
241
|
-
Radio: {
|
|
242
|
-
props: z.object({
|
|
243
|
-
label: z.string(),
|
|
244
|
-
name: z.string(),
|
|
245
|
-
options: z.array(z.string().min(1)),
|
|
246
|
-
value: z.string().nullable(),
|
|
247
|
-
checks: validationCheckSchema,
|
|
248
|
-
validateOn: validateOnSchema
|
|
249
|
-
}),
|
|
250
|
-
events: ["change"],
|
|
251
|
-
description: "Radio button group. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
252
|
-
},
|
|
253
|
-
Checkbox: {
|
|
254
|
-
props: z.object({
|
|
255
|
-
label: z.string(),
|
|
256
|
-
name: z.string(),
|
|
257
|
-
checked: z.boolean().nullable(),
|
|
258
|
-
checks: validationCheckSchema,
|
|
259
|
-
validateOn: validateOnSchema
|
|
260
|
-
}),
|
|
261
|
-
events: ["change"],
|
|
262
|
-
description: "Checkbox input. Use { $bindState } on checked for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
263
|
-
},
|
|
264
|
-
Switch: {
|
|
265
|
-
props: z.object({
|
|
266
|
-
label: z.string(),
|
|
267
|
-
name: z.string(),
|
|
268
|
-
checked: z.boolean().nullable(),
|
|
269
|
-
checks: validationCheckSchema,
|
|
270
|
-
validateOn: validateOnSchema
|
|
271
|
-
}),
|
|
272
|
-
events: ["change"],
|
|
273
|
-
description: "Toggle switch. Use { $bindState } on checked for binding. Use checks for validation. validateOn controls timing (default: change)."
|
|
274
|
-
},
|
|
275
|
-
// ── Actions ───────────────────────────────────────────────────────────────
|
|
276
|
-
Button: {
|
|
277
|
-
props: z.object({
|
|
278
|
-
label: z.string(),
|
|
279
|
-
variant: z.enum(["primary", "secondary", "danger"]).nullable(),
|
|
280
|
-
disabled: z.boolean().nullable()
|
|
281
|
-
}),
|
|
282
|
-
events: ["press"],
|
|
283
|
-
description: "Clickable button. Bind on.press for handler.",
|
|
284
|
-
example: { label: "Submit", variant: "primary" }
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
// src/generative/components.ts
|
|
289
|
-
var shadcn = shadcnComponentDefinitions;
|
|
290
|
-
var PICKED_SHADCN = [
|
|
291
|
-
"Card",
|
|
292
|
-
"Stack",
|
|
293
|
-
"Grid",
|
|
294
|
-
"Separator",
|
|
295
|
-
"Heading",
|
|
296
|
-
"Text",
|
|
297
|
-
"Badge",
|
|
298
|
-
"Alert",
|
|
299
|
-
"Collapsible",
|
|
300
|
-
"Progress",
|
|
301
|
-
"Avatar",
|
|
302
|
-
"Input",
|
|
303
|
-
"Textarea",
|
|
304
|
-
"Select",
|
|
305
|
-
"Radio",
|
|
306
|
-
"Checkbox",
|
|
307
|
-
"Switch",
|
|
308
|
-
"Button"
|
|
309
|
-
];
|
|
310
|
-
var CUSTOM_COMPONENTS = [
|
|
311
|
-
"Split",
|
|
312
|
-
"Tabs",
|
|
313
|
-
"Steps",
|
|
314
|
-
"Icon",
|
|
315
|
-
"Segmented",
|
|
316
|
-
"NumberInput",
|
|
317
|
-
"MthdsField",
|
|
318
|
-
"MthdsResult",
|
|
319
|
-
"DataTable",
|
|
320
|
-
"Metric"
|
|
321
|
-
];
|
|
322
|
-
var METRIC_FORMATS = ["plain", "integer", "decimal", "compact"];
|
|
323
|
-
var ICON_NAMES = [
|
|
324
|
-
"Sparkles",
|
|
325
|
-
"Rocket",
|
|
326
|
-
"Compass",
|
|
327
|
-
"Map",
|
|
328
|
-
"MapPin",
|
|
329
|
-
"Route",
|
|
330
|
-
"Plane",
|
|
331
|
-
"Train",
|
|
332
|
-
"Car",
|
|
333
|
-
"Ship",
|
|
334
|
-
"Hotel",
|
|
335
|
-
"Home",
|
|
336
|
-
"Building2",
|
|
337
|
-
"Landmark",
|
|
338
|
-
"Globe",
|
|
339
|
-
"Mountain",
|
|
340
|
-
"Leaf",
|
|
341
|
-
"Sun",
|
|
342
|
-
"Moon",
|
|
343
|
-
"Calendar",
|
|
344
|
-
"Clock",
|
|
345
|
-
"Hourglass",
|
|
346
|
-
"Users",
|
|
347
|
-
"User",
|
|
348
|
-
"Baby",
|
|
349
|
-
"Accessibility",
|
|
350
|
-
"Heart",
|
|
351
|
-
"Star",
|
|
352
|
-
"Utensils",
|
|
353
|
-
"Coffee",
|
|
354
|
-
"Music",
|
|
355
|
-
"Camera",
|
|
356
|
-
"Image",
|
|
357
|
-
"Ticket",
|
|
358
|
-
"Gift",
|
|
359
|
-
"Wallet",
|
|
360
|
-
"Banknote",
|
|
361
|
-
"Coins",
|
|
362
|
-
"Receipt",
|
|
363
|
-
"Percent",
|
|
364
|
-
"Hash",
|
|
365
|
-
"TrendingUp",
|
|
366
|
-
"BarChart3",
|
|
367
|
-
"FileText",
|
|
368
|
-
"Upload",
|
|
369
|
-
"Paperclip",
|
|
370
|
-
"Mail",
|
|
371
|
-
"Phone",
|
|
372
|
-
"Tag",
|
|
373
|
-
"Layers",
|
|
374
|
-
"ListChecks",
|
|
375
|
-
"CheckCircle2",
|
|
376
|
-
"AlertCircle",
|
|
377
|
-
"Info",
|
|
378
|
-
"Shield",
|
|
379
|
-
"Flag",
|
|
380
|
-
"Bookmark",
|
|
381
|
-
"Briefcase",
|
|
382
|
-
"Package",
|
|
383
|
-
"Truck",
|
|
384
|
-
"Lightbulb",
|
|
385
|
-
"Zap",
|
|
386
|
-
"Pencil",
|
|
387
|
-
"Send"
|
|
388
|
-
];
|
|
389
|
-
var components = {
|
|
390
|
-
// ── Layout (shadcn) ────────────────────────────────────────────────────
|
|
391
|
-
Card: {
|
|
392
|
-
...shadcn.Card,
|
|
393
|
-
props: shadcn.Card.props.omit({ className: true, maxWidth: true, centered: true }),
|
|
394
|
-
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.'
|
|
395
|
-
},
|
|
396
|
-
Stack: { ...shadcn.Stack, props: shadcn.Stack.props.omit({ className: true }) },
|
|
397
|
-
Grid: { ...shadcn.Grid, props: shadcn.Grid.props.omit({ className: true }) },
|
|
398
|
-
Separator: shadcn.Separator,
|
|
399
|
-
Collapsible: shadcn.Collapsible,
|
|
400
|
-
// ── Content (shadcn) ───────────────────────────────────────────────────
|
|
401
|
-
Heading: shadcn.Heading,
|
|
402
|
-
Text: shadcn.Text,
|
|
403
|
-
Badge: shadcn.Badge,
|
|
404
|
-
Alert: shadcn.Alert,
|
|
405
|
-
Progress: shadcn.Progress,
|
|
406
|
-
Avatar: {
|
|
407
|
-
...shadcn.Avatar,
|
|
408
|
-
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".`
|
|
409
|
-
},
|
|
410
|
-
// ── Inputs (shadcn) ────────────────────────────────────────────────────
|
|
411
|
-
Input: shadcn.Input,
|
|
412
|
-
Textarea: shadcn.Textarea,
|
|
413
|
-
Select: shadcn.Select,
|
|
414
|
-
Radio: shadcn.Radio,
|
|
415
|
-
Checkbox: shadcn.Checkbox,
|
|
416
|
-
Switch: shadcn.Switch,
|
|
417
|
-
Button: shadcn.Button,
|
|
418
|
-
// ── Layout (ours) ──────────────────────────────────────────────────────
|
|
419
|
-
Split: {
|
|
420
|
-
props: z.object({
|
|
421
|
-
ratio: z.enum(["1:1", "1:2", "2:1"]).nullable(),
|
|
422
|
-
gap: z.enum(["md", "lg", "xl"]).nullable()
|
|
423
|
-
}),
|
|
424
|
-
slots: ["default"],
|
|
425
|
-
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.',
|
|
426
|
-
example: { ratio: "1:2", gap: "lg" }
|
|
427
|
-
},
|
|
428
|
-
Tabs: {
|
|
429
|
-
props: z.object({
|
|
430
|
-
tabs: z.array(z.object({ label: z.string(), value: z.string() })).min(2)
|
|
431
|
-
}),
|
|
432
|
-
slots: ["default"],
|
|
433
|
-
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.",
|
|
434
|
-
example: {
|
|
435
|
-
tabs: [
|
|
436
|
-
{ label: "The trip", value: "trip" },
|
|
437
|
-
{ label: "Who is going", value: "people" }
|
|
438
|
-
]
|
|
439
|
-
}
|
|
440
|
-
},
|
|
441
|
-
Steps: {
|
|
442
|
-
props: z.object({
|
|
443
|
-
steps: z.array(z.string()).min(2),
|
|
444
|
-
nextLabel: z.string().nullable(),
|
|
445
|
-
backLabel: z.string().nullable()
|
|
446
|
-
}),
|
|
447
|
-
slots: ["default"],
|
|
448
|
-
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.",
|
|
449
|
-
example: { steps: ["Where", "Who", "How"], nextLabel: "Continue" }
|
|
450
|
-
},
|
|
451
|
-
Icon: {
|
|
452
|
-
props: z.object({
|
|
453
|
-
name: z.enum(ICON_NAMES),
|
|
454
|
-
size: z.enum(["sm", "md", "lg"]).nullable()
|
|
455
|
-
}),
|
|
456
|
-
slots: [],
|
|
457
|
-
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.",
|
|
458
|
-
example: { name: "Plane", size: "md" }
|
|
459
|
-
},
|
|
460
|
-
// ── Inputs (ours) ──────────────────────────────────────────────────────
|
|
461
|
-
Segmented: {
|
|
462
|
-
props: z.object({
|
|
463
|
-
label: z.string(),
|
|
464
|
-
name: z.string(),
|
|
465
|
-
options: z.array(z.string().min(1)).min(2).max(6),
|
|
466
|
-
value: z.string().nullable()
|
|
467
|
-
}),
|
|
468
|
-
slots: [],
|
|
469
|
-
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/..." }.`,
|
|
470
|
-
example: {
|
|
471
|
-
label: "Pace",
|
|
472
|
-
name: "pace",
|
|
473
|
-
options: ["slow", "balanced", "packed"],
|
|
474
|
-
value: { $bindState: "/inputs/request/pace" }
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
NumberInput: {
|
|
478
|
-
props: z.object({
|
|
479
|
-
label: z.string(),
|
|
480
|
-
name: z.string(),
|
|
481
|
-
value: z.number().nullable(),
|
|
482
|
-
placeholder: z.string().nullable(),
|
|
483
|
-
unit: z.string().nullable(),
|
|
484
|
-
min: z.number().nullable(),
|
|
485
|
-
max: z.number().nullable(),
|
|
486
|
-
step: z.number().nullable()
|
|
487
|
-
}),
|
|
488
|
-
slots: [],
|
|
489
|
-
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.',
|
|
490
|
-
example: {
|
|
491
|
-
label: "Budget",
|
|
492
|
-
name: "budget",
|
|
493
|
-
value: { $bindState: "/inputs/request/budget" },
|
|
494
|
-
placeholder: "2500"
|
|
495
|
-
}
|
|
496
|
-
},
|
|
497
|
-
// ── The escape hatches and the bound equivalents (ours) ────────────────
|
|
498
|
-
MthdsField: {
|
|
499
|
-
props: z.object({
|
|
500
|
-
path: z.string()
|
|
501
|
-
}),
|
|
502
|
-
slots: [],
|
|
503
|
-
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 its own label and description. Inside a repeat, "path" is the item's field name relative to the item ("lines"), never an $item expression.`,
|
|
504
|
-
example: { path: "/inputs/source" }
|
|
505
|
-
},
|
|
506
|
-
MthdsResult: {
|
|
507
|
-
props: z.object({
|
|
508
|
-
path: z.string(),
|
|
509
|
-
hideLabel: z.boolean().nullable()
|
|
510
|
-
}),
|
|
511
|
-
slots: [],
|
|
512
|
-
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.`,
|
|
513
|
-
example: { path: "/result/issued_on" }
|
|
514
|
-
},
|
|
515
|
-
DataTable: {
|
|
516
|
-
props: z.object({
|
|
517
|
-
rows: z.any(),
|
|
518
|
-
columns: z.array(z.object({ path: z.string(), label: z.string() })),
|
|
519
|
-
caption: z.string().nullable()
|
|
520
|
-
}),
|
|
521
|
-
slots: [],
|
|
522
|
-
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") and the header to show for it.',
|
|
523
|
-
example: {
|
|
524
|
-
rows: { $state: "/result/lines" },
|
|
525
|
-
columns: [
|
|
526
|
-
{ path: "label", label: "Item" },
|
|
527
|
-
{ path: "quantity", label: "Qty" }
|
|
528
|
-
]
|
|
529
|
-
}
|
|
530
|
-
},
|
|
531
|
-
Metric: {
|
|
532
|
-
props: z.object({
|
|
533
|
-
label: z.string(),
|
|
534
|
-
value: z.any(),
|
|
535
|
-
unit: z.string().nullable(),
|
|
536
|
-
format: z.enum(METRIC_FORMATS).nullable()
|
|
537
|
-
}),
|
|
538
|
-
slots: [],
|
|
539
|
-
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.',
|
|
540
|
-
example: { label: "Total", value: { $state: "/result/total" }, unit: "EUR", format: "decimal" }
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
var actions = {
|
|
544
|
-
run: {
|
|
545
|
-
params: z.object({}),
|
|
546
|
-
description: "Start the run with the current /inputs. The host handles it; an input page binds it to its one Button after validateForm."
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
|
-
defineCatalog(generativeSchema, { components, actions });
|
|
550
|
-
var generativeComponents = components;
|
|
551
|
-
var generativeActions = actions;
|
|
552
|
-
|
|
553
|
-
// src/generative/catalog.ts
|
|
554
|
-
var PRODUCT_COMPONENTS = [
|
|
555
|
-
"AppBar",
|
|
556
|
-
"Hero",
|
|
557
|
-
"Workspace",
|
|
558
|
-
"Section",
|
|
559
|
-
"Rail",
|
|
560
|
-
"SummaryRow",
|
|
561
|
-
"Cta",
|
|
562
|
-
"Footer"
|
|
563
|
-
];
|
|
564
|
-
var product = {
|
|
565
|
-
AppBar: {
|
|
566
|
-
props: z.object({
|
|
567
|
-
app: z.string(),
|
|
568
|
-
links: z.array(z.string()).nullable(),
|
|
569
|
-
tag: z.string().nullable()
|
|
570
|
-
}),
|
|
571
|
-
slots: [],
|
|
572
|
-
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.",
|
|
573
|
-
example: { app: "Trip planner", links: ["Methods", "Runs"], tag: "plan_trip" }
|
|
574
|
-
},
|
|
575
|
-
Hero: {
|
|
576
|
-
props: z.object({
|
|
577
|
-
headline: z.string(),
|
|
578
|
-
lede: z.string().nullable(),
|
|
579
|
-
eyebrow: z.string().nullable()
|
|
580
|
-
}),
|
|
581
|
-
slots: [],
|
|
582
|
-
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.",
|
|
583
|
-
example: { headline: "Plan a trip worth taking.", lede: "Tell us where and who is coming." }
|
|
584
|
-
},
|
|
585
|
-
Workspace: {
|
|
586
|
-
props: z.object({ rail: z.enum(["right", "left"]).nullable() }),
|
|
587
|
-
slots: ["default"],
|
|
588
|
-
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.',
|
|
589
|
-
example: { rail: "right" }
|
|
590
|
-
},
|
|
591
|
-
Section: {
|
|
592
|
-
props: z.object({
|
|
593
|
-
number: z.string().nullable(),
|
|
594
|
-
title: z.string(),
|
|
595
|
-
lede: z.string().nullable()
|
|
596
|
-
}),
|
|
597
|
-
slots: ["default"],
|
|
598
|
-
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.",
|
|
599
|
-
example: { number: "01", title: "Where and when" }
|
|
600
|
-
},
|
|
601
|
-
Rail: {
|
|
602
|
-
props: z.object({ title: z.string() }),
|
|
603
|
-
slots: ["default"],
|
|
604
|
-
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.",
|
|
605
|
-
example: { title: "Your trip" }
|
|
606
|
-
},
|
|
607
|
-
SummaryRow: {
|
|
608
|
-
props: z.object({
|
|
609
|
-
label: z.string(),
|
|
610
|
-
value: z.any().nullable(),
|
|
611
|
-
detail: z.any().nullable(),
|
|
612
|
-
separator: z.string().nullable(),
|
|
613
|
-
placeholder: z.string().nullable()
|
|
614
|
-
}),
|
|
615
|
-
slots: [],
|
|
616
|
-
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.',
|
|
617
|
-
example: {
|
|
618
|
-
label: "Budget",
|
|
619
|
-
value: { $state: "/inputs/request/budget" },
|
|
620
|
-
detail: { $state: "/inputs/request/currency" }
|
|
621
|
-
}
|
|
622
|
-
},
|
|
623
|
-
Cta: {
|
|
624
|
-
props: z.object({ label: z.string(), hint: z.string().nullable() }),
|
|
625
|
-
slots: [],
|
|
626
|
-
events: ["press"],
|
|
627
|
-
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.",
|
|
628
|
-
example: { label: "Plan my trip", hint: "Nothing runs until the request is complete." }
|
|
629
|
-
},
|
|
630
|
-
Footer: {
|
|
631
|
-
props: z.object({ text: z.string(), tag: z.string().nullable() }),
|
|
632
|
-
slots: [],
|
|
633
|
-
description: "A closing line, muted, with an optional mono tag at the right. It renders as the page's contentinfo, so at most one.",
|
|
634
|
-
example: { text: "Runs on Pipelex.", tag: "MTHDS" }
|
|
635
|
-
}
|
|
636
|
-
};
|
|
637
|
-
var COMPONENT_RENDERINGS = {
|
|
638
|
-
Hero: { heading: { level: 1 } },
|
|
639
|
-
Section: { heading: { level: 2 } },
|
|
640
|
-
Rail: { heading: { level: 2 } },
|
|
641
|
-
Card: { heading: { level: 3, when: "title" } },
|
|
642
|
-
AppBar: { once: "the page's banner" },
|
|
643
|
-
Footer: { once: "the page's contentinfo" },
|
|
644
|
-
Split: { children: { count: 2, roles: "left, right" } },
|
|
645
|
-
Workspace: { children: { count: 2, roles: "work, rail" } },
|
|
646
|
-
Tabs: { panels: { prop: "tabs", noun: "tab" } },
|
|
647
|
-
Steps: { panels: { prop: "steps", noun: "step" } }
|
|
648
|
-
};
|
|
649
|
-
var catalog = Object.assign(
|
|
650
|
-
defineCatalog(generativeSchema, {
|
|
651
|
-
components: { ...generativeComponents, ...product },
|
|
652
|
-
actions: generativeActions
|
|
653
|
-
}),
|
|
654
|
-
{ renders: COMPONENT_RENDERINGS }
|
|
655
|
-
);
|
|
656
|
-
var COMPONENT_NAMES = [
|
|
657
|
-
...PICKED_SHADCN,
|
|
658
|
-
...CUSTOM_COMPONENTS,
|
|
659
|
-
...PRODUCT_COMPONENTS
|
|
660
|
-
];
|
|
661
|
-
|
|
662
|
-
// src/generative/props-signature.ts
|
|
663
|
-
function definitionOf(schema) {
|
|
664
|
-
return schema._zod.def;
|
|
665
|
-
}
|
|
666
|
-
function propsSignature(schema) {
|
|
667
|
-
const def = definitionOf(schema);
|
|
668
|
-
switch (def.type) {
|
|
669
|
-
case "string":
|
|
670
|
-
return "string";
|
|
671
|
-
case "number":
|
|
672
|
-
return "number";
|
|
673
|
-
case "boolean":
|
|
674
|
-
return "boolean";
|
|
675
|
-
case "literal":
|
|
676
|
-
return JSON.stringify(def.values?.[0]);
|
|
677
|
-
case "enum":
|
|
678
|
-
return Object.values(def.entries ?? {}).map((value) => `"${String(value)}"`).join(" | ");
|
|
679
|
-
case "array":
|
|
680
|
-
return `Array<${def.element ? propsSignature(def.element) : "unknown"}>`;
|
|
681
|
-
case "object": {
|
|
682
|
-
const props = Object.entries(def.shape ?? {}).map(([key, value]) => {
|
|
683
|
-
const inner = definitionOf(value).type;
|
|
684
|
-
const optional = inner === "optional" || inner === "nullable";
|
|
685
|
-
return `${key}${optional ? "?" : ""}: ${propsSignature(value)}`;
|
|
686
|
-
});
|
|
687
|
-
return `{ ${props.join(", ")} }`;
|
|
688
|
-
}
|
|
689
|
-
case "optional":
|
|
690
|
-
case "nullable":
|
|
691
|
-
case "default":
|
|
692
|
-
return def.innerType ? propsSignature(def.innerType) : "unknown";
|
|
693
|
-
case "union":
|
|
694
|
-
return def.options ? def.options.map((option) => propsSignature(option)).join(" | ") : "unknown";
|
|
695
|
-
case "record": {
|
|
696
|
-
const key = def.keyType ? propsSignature(def.keyType) : "string";
|
|
697
|
-
const value = def.valueType ? propsSignature(def.valueType) : "unknown";
|
|
698
|
-
return `Record<${key}, ${value}>`;
|
|
699
|
-
}
|
|
700
|
-
default:
|
|
701
|
-
return "unknown";
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// src/generative/designer-catalog.ts
|
|
706
|
-
var DESIGNER_CATALOG_CONCEPT = "generative.Catalog";
|
|
707
|
-
function designerCatalog() {
|
|
708
|
-
const definitions = catalog.data.components;
|
|
709
|
-
const components3 = COMPONENT_NAMES.map((name) => {
|
|
710
|
-
const definition = definitions[name];
|
|
711
|
-
if (!definition) throw new Error(`the catalog defines no component named '${name}'`);
|
|
712
|
-
const slots = definition.slots ?? [];
|
|
713
|
-
return {
|
|
714
|
-
name,
|
|
715
|
-
props: propsSignature(definition.props),
|
|
716
|
-
description: definition.description,
|
|
717
|
-
accepts_children: slots.includes("default"),
|
|
718
|
-
slots: slots.filter((slot) => slot !== "default"),
|
|
719
|
-
events: [...definition.events ?? []]
|
|
720
|
-
};
|
|
721
|
-
});
|
|
722
|
-
const builtIn = (generativeSchema.builtInActions ?? []).map((action) => ({
|
|
723
|
-
name: action.name,
|
|
724
|
-
description: action.description,
|
|
725
|
-
built_in: true
|
|
726
|
-
}));
|
|
727
|
-
const own = Object.entries(catalog.data.actions).map(
|
|
728
|
-
([name, action]) => ({
|
|
729
|
-
name,
|
|
730
|
-
description: action.description,
|
|
731
|
-
built_in: false
|
|
732
|
-
})
|
|
733
|
-
);
|
|
734
|
-
return { components: components3, actions: [...builtIn, ...own] };
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// src/generative/prompt-hash.ts
|
|
738
|
-
var PROMPT_HASH = "2b2325fd1231";
|
|
739
|
-
|
|
740
|
-
// src/generative/paths.ts
|
|
741
|
-
var INPUTS_ROOT = "/inputs";
|
|
742
|
-
var RESULT_ROOT = "/result";
|
|
743
|
-
function joinPath(root, ...segments) {
|
|
744
|
-
return segments.reduce((path, segment) => `${path}/${escapeSegment(segment)}`, root);
|
|
745
|
-
}
|
|
746
|
-
function escapeSegment(segment) {
|
|
747
|
-
return segment.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
748
|
-
}
|
|
749
|
-
function unescapeSegment(segment) {
|
|
750
|
-
return segment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
751
|
-
}
|
|
752
|
-
function segmentsUnder(root, path) {
|
|
753
|
-
if (path === root) return [];
|
|
754
|
-
if (!path.startsWith(`${root}/`)) return void 0;
|
|
755
|
-
return path.slice(root.length + 1).split("/").map(unescapeSegment);
|
|
756
|
-
}
|
|
757
|
-
function fieldAtSegments(fields, segments) {
|
|
758
|
-
const [head, ...rest] = segments;
|
|
759
|
-
if (head === void 0) return void 0;
|
|
760
|
-
const field = fields.find((candidate) => candidate.name === head);
|
|
761
|
-
if (!field) return void 0;
|
|
762
|
-
return rest.length === 0 ? field : descend(field, rest);
|
|
763
|
-
}
|
|
764
|
-
function descend(field, segments) {
|
|
765
|
-
const [head, ...rest] = segments;
|
|
766
|
-
if (head === void 0) return field;
|
|
767
|
-
if (field.kind === "object") return fieldAtSegments(field.fields, segments);
|
|
768
|
-
if (field.kind === "list" && /^\d+$/.test(head)) return descend(field.item, rest);
|
|
769
|
-
return void 0;
|
|
770
|
-
}
|
|
771
|
-
function inputFieldAtPath(fields, path) {
|
|
772
|
-
const segments = segmentsUnder(INPUTS_ROOT, path);
|
|
773
|
-
return segments && segments.length > 0 ? fieldAtSegments(fields, segments) : void 0;
|
|
774
|
-
}
|
|
775
|
-
function resultFieldAtPath(field, path) {
|
|
776
|
-
const segments = segmentsUnder(RESULT_ROOT, path);
|
|
777
|
-
if (!segments) return void 0;
|
|
778
|
-
return segments.length === 0 ? field : descend(field, segments);
|
|
779
|
-
}
|
|
780
|
-
function parentMapOf(spec) {
|
|
781
|
-
const parents = /* @__PURE__ */ new Map();
|
|
782
|
-
for (const [parentKey, element] of Object.entries(spec.elements)) {
|
|
783
|
-
for (const child of element.children ?? []) parents.set(child, parentKey);
|
|
784
|
-
}
|
|
785
|
-
return parents;
|
|
786
|
-
}
|
|
787
|
-
function repeatBasePathOf(spec, key, parents = parentMapOf(spec)) {
|
|
788
|
-
const chain = [];
|
|
789
|
-
const seen = /* @__PURE__ */ new Set();
|
|
790
|
-
let current = key;
|
|
791
|
-
while (current !== void 0 && !seen.has(current)) {
|
|
792
|
-
seen.add(current);
|
|
793
|
-
chain.unshift(current);
|
|
794
|
-
current = parents.get(current);
|
|
795
|
-
}
|
|
796
|
-
let base;
|
|
797
|
-
for (const elementKey of chain) {
|
|
798
|
-
const repeat = spec.elements[elementKey]?.repeat;
|
|
799
|
-
if (!repeat) continue;
|
|
800
|
-
const statePath = repeat.statePath;
|
|
801
|
-
if (typeof statePath === "string") {
|
|
802
|
-
base = `${statePath}/0`;
|
|
803
|
-
continue;
|
|
804
|
-
}
|
|
805
|
-
const item = statePath?.$item;
|
|
806
|
-
if (base === void 0 || typeof item !== "string") return void 0;
|
|
807
|
-
base = `${joinPath(base, item)}/0`;
|
|
808
|
-
}
|
|
809
|
-
return base;
|
|
810
|
-
}
|
|
811
|
-
function absoluteHatchPath(spec, key, path, parents) {
|
|
812
|
-
if (path.startsWith("/")) return path;
|
|
813
|
-
const base = repeatBasePathOf(spec, key, parents);
|
|
814
|
-
return base ? `${base}/${path}` : void 0;
|
|
815
|
-
}
|
|
816
|
-
function repeatListPathOf(spec, key, parents = parentMapOf(spec)) {
|
|
817
|
-
const statePath = spec.elements[key]?.repeat?.statePath;
|
|
818
|
-
if (typeof statePath === "string") return statePath;
|
|
819
|
-
const item = statePath?.$item;
|
|
820
|
-
const parent = parents.get(key);
|
|
821
|
-
const outer = parent === void 0 ? void 0 : repeatBasePathOf(spec, parent, parents);
|
|
822
|
-
return outer !== void 0 && typeof item === "string" ? joinPath(outer, item) : void 0;
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// src/generative/brief.ts
|
|
826
|
-
var DESIGNER_BRIEF_CONCEPT = "generative.Brief";
|
|
827
|
-
var RUN_COMPONENT = "Cta";
|
|
828
|
-
function isDelegatedInput(field) {
|
|
829
|
-
return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "list" || field.kind === "unknown" || field.kind === "enum" && field.options.includes("");
|
|
830
|
-
}
|
|
831
|
-
function isDelegatedResult(field) {
|
|
832
|
-
if (isNativeValueNode(field)) return true;
|
|
833
|
-
if (field.kind === "list" && isNativeValueNode(field.item)) return true;
|
|
834
|
-
return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "prose" || field.kind === "unknown";
|
|
835
|
-
}
|
|
836
|
-
function kindLabel(field) {
|
|
837
|
-
if (isNativeHtmlNode(field)) return "markup (native.Html)";
|
|
838
|
-
if (isNativeDateNode(field)) return "date (native.Date)";
|
|
839
|
-
if (isNativeCompositeNode(field)) return "composite (native.Composite)";
|
|
840
|
-
switch (field.kind) {
|
|
841
|
-
case "text":
|
|
842
|
-
return "text";
|
|
843
|
-
case "prose":
|
|
844
|
-
return "prose (markdown)";
|
|
845
|
-
case "number":
|
|
846
|
-
return field.integer ? "integer" : "number";
|
|
847
|
-
case "boolean":
|
|
848
|
-
return "boolean";
|
|
849
|
-
case "enum":
|
|
850
|
-
return `choice of ${field.options.map((option) => JSON.stringify(option)).join(" | ")}`;
|
|
851
|
-
case "date":
|
|
852
|
-
return field.datetime ? "date with time" : "date";
|
|
853
|
-
case "document":
|
|
854
|
-
return "document (a file)";
|
|
855
|
-
case "image":
|
|
856
|
-
return "image (a file)";
|
|
857
|
-
case "object":
|
|
858
|
-
return `structure${field.conceptRef ? ` ${field.conceptRef}` : ""}`;
|
|
859
|
-
case "list":
|
|
860
|
-
return `list of ${kindLabel(field.item)}`;
|
|
861
|
-
case "unknown":
|
|
862
|
-
return "unknown";
|
|
863
|
-
default:
|
|
864
|
-
return field;
|
|
865
|
-
}
|
|
30
|
+
var BrandContext = React5.createContext(null);
|
|
31
|
+
function BrandProvider({
|
|
32
|
+
manifest,
|
|
33
|
+
children
|
|
34
|
+
}) {
|
|
35
|
+
useWebfont(manifest.webfont);
|
|
36
|
+
return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
|
|
866
37
|
}
|
|
867
|
-
function
|
|
868
|
-
const
|
|
869
|
-
if (
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
}
|
|
873
|
-
if (field.kind === "text" || field.kind === "prose") {
|
|
874
|
-
if (field.minLength !== void 0) notes.push(`at least ${field.minLength} characters`);
|
|
875
|
-
if (field.maxLength !== void 0) notes.push(`at most ${field.maxLength} characters`);
|
|
876
|
-
if (field.format) notes.push(`format ${field.format}`);
|
|
877
|
-
}
|
|
878
|
-
if (field.kind === "list") {
|
|
879
|
-
if (field.itemCount !== void 0) notes.push(`at least ${field.itemCount} items`);
|
|
880
|
-
if (field.maxItemCount !== void 0) notes.push(`at most ${field.maxItemCount} items`);
|
|
881
|
-
}
|
|
882
|
-
if (field.defaultValue !== void 0) notes.push(`default ${JSON.stringify(field.defaultValue)}`);
|
|
883
|
-
if (field.examples && field.examples.length > 0) {
|
|
884
|
-
notes.push(`examples ${field.examples.map((example) => JSON.stringify(example)).join(", ")}`);
|
|
885
|
-
}
|
|
886
|
-
if (field.hints && Object.keys(field.hints).length > 0) {
|
|
887
|
-
notes.push(
|
|
888
|
-
`hints ${Object.entries(field.hints).map(([key, value]) => `${key}=${value}`).join(", ")}`
|
|
38
|
+
function useBrand() {
|
|
39
|
+
const manifest = React5.useContext(BrandContext);
|
|
40
|
+
if (!manifest)
|
|
41
|
+
throw new Error(
|
|
42
|
+
"useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
|
|
889
43
|
);
|
|
890
|
-
|
|
891
|
-
return notes;
|
|
892
|
-
}
|
|
893
|
-
function entryOf(field, path, depth, side, relative, seeded) {
|
|
894
|
-
const notes = constraints(field);
|
|
895
|
-
return {
|
|
896
|
-
depth,
|
|
897
|
-
path,
|
|
898
|
-
kind: kindLabel(field),
|
|
899
|
-
name: field.name,
|
|
900
|
-
title: field.title && field.title !== field.name ? field.title : void 0,
|
|
901
|
-
description: field.description,
|
|
902
|
-
required: side === "input" ? field.required : void 0,
|
|
903
|
-
gating: side === "input" && field.gating ? true : void 0,
|
|
904
|
-
notes: notes.length > 0 ? notes : void 0,
|
|
905
|
-
default: seeded || field.defaultValue === void 0 ? void 0 : JSON.stringify(field.defaultValue),
|
|
906
|
-
delegated: side === "input" ? isDelegatedInput(field) : isDelegatedResult(field),
|
|
907
|
-
relative: relative ? true : void 0
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
function describe(field, path, depth, side, entries, seeded = false) {
|
|
911
|
-
const entry = entryOf(field, path, depth, side, false, seeded);
|
|
912
|
-
entries.push(entry);
|
|
913
|
-
if (entry.delegated) return;
|
|
914
|
-
if (field.kind === "object") {
|
|
915
|
-
const seededBelow = seeded || field.defaultValue !== void 0 || side === "input" && !field.required;
|
|
916
|
-
for (const child of field.fields) {
|
|
917
|
-
describe(child, joinPath(path, child.name), depth + 1, side, entries, seededBelow);
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
if (field.kind === "list" && side === "result") {
|
|
921
|
-
const item = field.item;
|
|
922
|
-
entry.item_kind = kindLabel(item);
|
|
923
|
-
entry.item_description = item.description;
|
|
924
|
-
if (item.kind === "object" && !isDelegatedResult(item)) {
|
|
925
|
-
entry.item_laid_out = true;
|
|
926
|
-
for (const child of item.fields) {
|
|
927
|
-
describeRelative(child, child.name, depth + 2, entries);
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
function describeRelative(field, relativePath, depth, entries) {
|
|
933
|
-
const entry = entryOf(field, relativePath, depth, "result", true, false);
|
|
934
|
-
entries.push(entry);
|
|
935
|
-
if (entry.delegated) return;
|
|
936
|
-
if (field.kind === "object") {
|
|
937
|
-
for (const child of field.fields) {
|
|
938
|
-
describeRelative(child, joinPath(relativePath, child.name), depth + 1, entries);
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
if (field.kind === "list") {
|
|
942
|
-
const item = field.item;
|
|
943
|
-
entry.item_kind = kindLabel(item);
|
|
944
|
-
entry.item_description = item.description;
|
|
945
|
-
if (item.kind === "object" && !isDelegatedResult(item)) {
|
|
946
|
-
entry.item_laid_out = true;
|
|
947
|
-
for (const child of item.fields) {
|
|
948
|
-
describeRelative(child, joinPath(relativePath, "<i>", child.name), depth + 2, entries);
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
function inputBrief(subject, fields) {
|
|
954
|
-
const paths = [];
|
|
955
|
-
for (const field of fields) describe(field, joinPath(INPUTS_ROOT, field.name), 0, "input", paths);
|
|
956
|
-
return {
|
|
957
|
-
side: "input",
|
|
958
|
-
pipe_ref: subject.pipeRef,
|
|
959
|
-
description: subject.description,
|
|
960
|
-
name: subject.name,
|
|
961
|
-
paths,
|
|
962
|
-
run_control: RUN_COMPONENT
|
|
963
|
-
};
|
|
964
|
-
}
|
|
965
|
-
function resultBrief(subject, field, state) {
|
|
966
|
-
const paths = [];
|
|
967
|
-
if (field.kind === "object" && !isDelegatedResult(field)) {
|
|
968
|
-
paths.push({
|
|
969
|
-
depth: 0,
|
|
970
|
-
path: RESULT_ROOT,
|
|
971
|
-
kind: kindLabel(field),
|
|
972
|
-
description: field.description,
|
|
973
|
-
delegated: false
|
|
974
|
-
});
|
|
975
|
-
for (const child of field.fields) {
|
|
976
|
-
describe(child, joinPath(RESULT_ROOT, child.name), 1, "result", paths);
|
|
977
|
-
}
|
|
978
|
-
} else {
|
|
979
|
-
describe(field, RESULT_ROOT, 0, "result", paths);
|
|
980
|
-
}
|
|
981
|
-
return {
|
|
982
|
-
side: "result",
|
|
983
|
-
pipe_ref: subject.pipeRef,
|
|
984
|
-
description: subject.description,
|
|
985
|
-
paths,
|
|
986
|
-
sample_state: JSON.stringify(state, null, 2)
|
|
987
|
-
};
|
|
44
|
+
return manifest;
|
|
988
45
|
}
|
|
989
|
-
var
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
];
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
let current = schema;
|
|
1005
|
-
for (let depth = 0; depth < 8; depth += 1) {
|
|
1006
|
-
const def = current.def;
|
|
1007
|
-
if (!def) return false;
|
|
1008
|
-
if (def.type === "enum" || def.type === "literal") return true;
|
|
1009
|
-
if (def.innerType === void 0) return false;
|
|
1010
|
-
current = def.innerType;
|
|
1011
|
-
}
|
|
1012
|
-
return false;
|
|
1013
|
-
}
|
|
1014
|
-
function definitionOf2(catalog2, type) {
|
|
1015
|
-
const components3 = catalog2.data.components;
|
|
1016
|
-
return hasOwnProp(components3, type) ? components3[type] : void 0;
|
|
1017
|
-
}
|
|
1018
|
-
function propsSchemaOf(catalog2, type) {
|
|
1019
|
-
const props = definitionOf2(catalog2, type)?.props;
|
|
1020
|
-
return props && typeof props === "object" && "shape" in props ? props : void 0;
|
|
1021
|
-
}
|
|
1022
|
-
function eventsOf(catalog2, type) {
|
|
1023
|
-
const definition = definitionOf2(catalog2, type);
|
|
1024
|
-
if (!definition) return void 0;
|
|
1025
|
-
return Array.isArray(definition.events) ? definition.events.filter((event) => typeof event === "string") : [];
|
|
1026
|
-
}
|
|
1027
|
-
var MAX_ELEMENT_DEPTH = 512;
|
|
1028
|
-
function childKeysOf(spec, key) {
|
|
1029
|
-
const element = spec.elements[key];
|
|
1030
|
-
if (!element) return [];
|
|
1031
|
-
const children = Array.isArray(element.children) ? element.children : [];
|
|
1032
|
-
const slots = typeof element.slots === "object" && element.slots !== null ? Object.values(element.slots).flatMap(
|
|
1033
|
-
(slot) => Array.isArray(slot) ? slot : []
|
|
1034
|
-
) : [];
|
|
1035
|
-
return [...children, ...slots].filter((child) => typeof child === "string");
|
|
1036
|
-
}
|
|
1037
|
-
function deepestChain(spec) {
|
|
1038
|
-
const below = /* @__PURE__ */ new Map();
|
|
1039
|
-
const onPath = /* @__PURE__ */ new Set();
|
|
1040
|
-
let deepest = 0;
|
|
1041
|
-
for (const start of Object.keys(spec.elements)) {
|
|
1042
|
-
if (below.has(start)) continue;
|
|
1043
|
-
const stack = [start];
|
|
1044
|
-
while (stack.length > 0) {
|
|
1045
|
-
const key = stack[stack.length - 1];
|
|
1046
|
-
if (below.has(key)) {
|
|
1047
|
-
onPath.delete(key);
|
|
1048
|
-
stack.pop();
|
|
1049
|
-
continue;
|
|
1050
|
-
}
|
|
1051
|
-
const children = childKeysOf(spec, key).filter((child) => !onPath.has(child));
|
|
1052
|
-
const pending = children.filter((child) => !below.has(child));
|
|
1053
|
-
if (pending.length > 0) {
|
|
1054
|
-
onPath.add(key);
|
|
1055
|
-
stack.push(...pending);
|
|
1056
|
-
continue;
|
|
1057
|
-
}
|
|
1058
|
-
below.set(
|
|
1059
|
-
key,
|
|
1060
|
-
children.reduce((tallest, child) => Math.max(tallest, below.get(child) ?? 0), 0) + 1
|
|
1061
|
-
);
|
|
1062
|
-
onPath.delete(key);
|
|
1063
|
-
stack.pop();
|
|
46
|
+
var WEIGHTS = "400;500;600;700";
|
|
47
|
+
function useWebfont(webfont) {
|
|
48
|
+
const provider = webfont?.provider;
|
|
49
|
+
const family = webfont?.family;
|
|
50
|
+
React5.useEffect(() => {
|
|
51
|
+
if (!provider || !family) return;
|
|
52
|
+
const key = `${provider}:${family}`;
|
|
53
|
+
if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
|
|
54
|
+
for (const origin of ["https://fonts.googleapis.com", "https://fonts.gstatic.com"]) {
|
|
55
|
+
if (document.head.querySelector(`link[rel="preconnect"][href="${origin}"]`)) continue;
|
|
56
|
+
const preconnect = document.createElement("link");
|
|
57
|
+
preconnect.rel = "preconnect";
|
|
58
|
+
preconnect.href = origin;
|
|
59
|
+
if (origin.endsWith("gstatic.com")) preconnect.crossOrigin = "anonymous";
|
|
60
|
+
document.head.appendChild(preconnect);
|
|
1064
61
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
62
|
+
const link = document.createElement("link");
|
|
63
|
+
link.rel = "stylesheet";
|
|
64
|
+
const encoded = encodeURIComponent(family).replace(/%20/g, "+");
|
|
65
|
+
link.href = `https://fonts.googleapis.com/css2?family=${encoded}:wght@${WEIGHTS}&display=swap`;
|
|
66
|
+
link.dataset.brandWebfont = key;
|
|
67
|
+
document.head.appendChild(link);
|
|
68
|
+
}, [provider, family]);
|
|
1068
69
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
ok: false,
|
|
1075
|
-
problems: [{ message: `the layout is not a well-formed spec: ${String(error)}` }]
|
|
1076
|
-
};
|
|
70
|
+
var ReportingContext = React5.createContext(false);
|
|
71
|
+
var ElementBoundary = class extends React5.Component {
|
|
72
|
+
constructor(props) {
|
|
73
|
+
super(props);
|
|
74
|
+
this.state = { failed: false, error: void 0, resetOn: props.resetOn };
|
|
1077
75
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
const problems = [];
|
|
1081
|
-
const depth = deepestChain(spec);
|
|
1082
|
-
if (depth > MAX_ELEMENT_DEPTH) {
|
|
1083
|
-
return {
|
|
1084
|
-
ok: false,
|
|
1085
|
-
problems: [
|
|
1086
|
-
{
|
|
1087
|
-
message: `the element tree is ${depth} deep; this entry renders at most ${MAX_ELEMENT_DEPTH}.`
|
|
1088
|
-
}
|
|
1089
|
-
]
|
|
1090
|
-
};
|
|
76
|
+
static getDerivedStateFromError(error) {
|
|
77
|
+
return { failed: true, error };
|
|
1091
78
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
problems.push({ elementKey: issue.elementKey, message: issue.message });
|
|
1096
|
-
}
|
|
79
|
+
static getDerivedStateFromProps(props, state) {
|
|
80
|
+
if (Object.is(props.resetOn, state.resetOn)) return null;
|
|
81
|
+
return { failed: false, error: void 0, resetOn: props.resetOn };
|
|
1097
82
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
cyclic.add(key);
|
|
1105
|
-
return;
|
|
1106
|
-
}
|
|
1107
|
-
state.set(key, "open");
|
|
1108
|
-
const element = spec.elements[key];
|
|
1109
|
-
for (const child of element?.children ?? []) descend2(child);
|
|
1110
|
-
for (const slot of Object.values(element?.slots ?? {}))
|
|
1111
|
-
for (const child of slot) descend2(child);
|
|
1112
|
-
state.set(key, "done");
|
|
1113
|
-
};
|
|
1114
|
-
for (const key of Object.keys(spec.elements)) descend2(key);
|
|
1115
|
-
for (const key of cyclic) {
|
|
1116
|
-
problems.push({
|
|
1117
|
-
elementKey: key,
|
|
1118
|
-
message: `"${key}" is its own descendant: an element tree may not contain a cycle.`
|
|
83
|
+
componentDidCatch(error, info) {
|
|
84
|
+
if (!this.props.reporting) return;
|
|
85
|
+
const componentStack = info.componentStack ?? void 0;
|
|
86
|
+
this.props.report.current?.(error, {
|
|
87
|
+
type: this.props.type,
|
|
88
|
+
...componentStack ? { componentStack } : {}
|
|
1119
89
|
});
|
|
1120
90
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
91
|
+
// Whether to report or to throw the error on is decided as the boundary
|
|
92
|
+
// renders its failure, from whether the host passes a handler in this very
|
|
93
|
+
// render: decided later, it cost a blank commit and a second record of the
|
|
94
|
+
// same error, and decided from the ref, it read the previous render's
|
|
95
|
+
// callback. No host to tell: the error goes on, in the same render, to
|
|
96
|
+
// json-render's boundary or the host's around the page, which record it
|
|
97
|
+
// once, as if this one were not here.
|
|
98
|
+
render() {
|
|
99
|
+
if (!this.state.failed) return this.props.children;
|
|
100
|
+
if (!this.props.reporting) throw this.state.error;
|
|
101
|
+
return null;
|
|
1126
102
|
}
|
|
1127
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1128
|
-
const schema = propsSchemaOf(catalog2, element.type);
|
|
1129
|
-
if (!schema) continue;
|
|
1130
|
-
const shape = schema.shape;
|
|
1131
|
-
const props = element.props ?? {};
|
|
1132
|
-
for (const [name, value] of Object.entries(props)) {
|
|
1133
|
-
const propSchema = shape[name];
|
|
1134
|
-
if (!propSchema) {
|
|
1135
|
-
problems.push({
|
|
1136
|
-
elementKey: key,
|
|
1137
|
-
message: `${element.type} has no prop "${name}" (known: ${Object.keys(shape).join(", ")})`
|
|
1138
|
-
});
|
|
1139
|
-
continue;
|
|
1140
|
-
}
|
|
1141
|
-
if (isExpression(value)) {
|
|
1142
|
-
if (HATCHES.has(element.type) && name === "path") {
|
|
1143
|
-
problems.push({
|
|
1144
|
-
elementKey: key,
|
|
1145
|
-
message: `${element.type}.path must be a literal string - absolute, or the item's field name inside a repeat - never an expression.`
|
|
1146
|
-
});
|
|
1147
|
-
} else if (isClosedVocabulary(propSchema)) {
|
|
1148
|
-
problems.push({
|
|
1149
|
-
elementKey: key,
|
|
1150
|
-
message: `${element.type}.${name} is one of a fixed set of names, so it must be written as a literal, never as an expression.`
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
continue;
|
|
1154
|
-
}
|
|
1155
|
-
const parsed = propSchema.safeParse(value);
|
|
1156
|
-
if (!parsed.success) {
|
|
1157
|
-
problems.push({
|
|
1158
|
-
elementKey: key,
|
|
1159
|
-
message: `${element.type}.${name}: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
for (const [name, propSchema] of Object.entries(shape)) {
|
|
1164
|
-
if (name in props) continue;
|
|
1165
|
-
if (propSchema.safeParse(void 0).success || propSchema.safeParse(null).success) continue;
|
|
1166
|
-
problems.push({
|
|
1167
|
-
elementKey: key,
|
|
1168
|
-
message: `${element.type} is missing required prop "${name}"`
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
const renders = catalog2.renders ?? {};
|
|
1173
|
-
const renderingOf = (type) => hasOwnProp(renders, type) ? renders[type] : void 0;
|
|
1174
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1175
|
-
const panelled = renderingOf(element.type)?.panels;
|
|
1176
|
-
if (!panelled) continue;
|
|
1177
|
-
const props = element.props ?? {};
|
|
1178
|
-
const listed = props[panelled.prop];
|
|
1179
|
-
if (!Array.isArray(listed)) continue;
|
|
1180
|
-
const panels = listed.length;
|
|
1181
|
-
const children = element.children?.length ?? 0;
|
|
1182
|
-
if (children !== panels) {
|
|
1183
|
-
problems.push({
|
|
1184
|
-
elementKey: key,
|
|
1185
|
-
message: `${element.type} declares ${panels} panel${panels === 1 ? "" : "s"} but has ${children} child${children === 1 ? "" : "ren"}: exactly one child per ${panelled.noun}, in order.`
|
|
1186
|
-
});
|
|
1187
|
-
}
|
|
1188
|
-
const runs = (element.children ?? []).filter(
|
|
1189
|
-
(child) => spec.elements[child]?.type === "Button"
|
|
1190
|
-
);
|
|
1191
|
-
if (runs.length > 0) {
|
|
1192
|
-
problems.push({
|
|
1193
|
-
elementKey: key,
|
|
1194
|
-
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.`
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
const present2 = (value) => value !== void 0 && value !== null && value !== "";
|
|
1199
|
-
const levels = [];
|
|
1200
|
-
const onlyOnce = /* @__PURE__ */ new Map();
|
|
1201
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1202
|
-
const walk = (key) => {
|
|
1203
|
-
if (seen.has(key)) return;
|
|
1204
|
-
seen.add(key);
|
|
1205
|
-
const element = spec.elements[key];
|
|
1206
|
-
if (!element) return;
|
|
1207
|
-
const props = element.props ?? {};
|
|
1208
|
-
const rendering = renderingOf(element.type);
|
|
1209
|
-
if (element.type === "Heading") {
|
|
1210
|
-
const level = String(props.level ?? "h2");
|
|
1211
|
-
const match = /^h([1-4])$/.exec(level);
|
|
1212
|
-
if (match) levels.push({ key, type: "Heading", level: Number(match[1]) });
|
|
1213
|
-
} else if (rendering?.heading) {
|
|
1214
|
-
const rendered = rendering.heading;
|
|
1215
|
-
const has = rendered.when === void 0 || present2(props[rendered.when]);
|
|
1216
|
-
if (has) levels.push({ key, type: element.type, level: rendered.level });
|
|
1217
|
-
}
|
|
1218
|
-
if (rendering?.once !== void 0) {
|
|
1219
|
-
const entry = onlyOnce.get(element.type) ?? { reason: rendering.once, keys: [] };
|
|
1220
|
-
entry.keys.push(key);
|
|
1221
|
-
onlyOnce.set(element.type, entry);
|
|
1222
|
-
}
|
|
1223
|
-
for (const child of element.children ?? []) walk(child);
|
|
1224
|
-
for (const slot of Object.values(element.slots ?? {})) for (const child of slot) walk(child);
|
|
1225
|
-
};
|
|
1226
|
-
if (spec.root) walk(spec.root);
|
|
1227
|
-
const describe2 = (heading) => heading.type === "Heading" ? `h${heading.level}` : `${heading.type}'s h${heading.level}`;
|
|
1228
|
-
let previous;
|
|
1229
|
-
for (const heading of levels) {
|
|
1230
|
-
if (previous !== void 0 && heading.level > previous.level + 1) {
|
|
1231
|
-
problems.push({
|
|
1232
|
-
elementKey: heading.key,
|
|
1233
|
-
message: `${describe2(heading)} jumps after ${describe2(previous)}: heading levels increase by one, never by more.`
|
|
1234
|
-
});
|
|
1235
|
-
}
|
|
1236
|
-
previous = heading;
|
|
1237
|
-
}
|
|
1238
|
-
const firsts = levels.filter((heading) => heading.level === 1);
|
|
1239
|
-
const h1Ways = [
|
|
1240
|
-
...known.has("Heading") ? ["as a Heading at level h1"] : [],
|
|
1241
|
-
...Object.entries(renders).filter(([, rendering]) => rendering.heading?.level === 1).map(([type]) => `as the heading a ${type} renders`)
|
|
1242
|
-
];
|
|
1243
|
-
if (firsts.length === 0 && spec.root && h1Ways.length > 0) {
|
|
1244
|
-
problems.push({
|
|
1245
|
-
elementKey: spec.root,
|
|
1246
|
-
message: `the page has no h1: exactly one, ${h1Ways.join(" or ")}.`
|
|
1247
|
-
});
|
|
1248
|
-
}
|
|
1249
|
-
for (const extra of firsts.slice(1)) {
|
|
1250
|
-
problems.push({
|
|
1251
|
-
elementKey: extra.key,
|
|
1252
|
-
message: `a second h1 (${describe2(extra)}, after ${describe2(firsts[0])} at [${firsts[0].key}]): exactly one on a page.`
|
|
1253
|
-
});
|
|
1254
|
-
}
|
|
1255
|
-
for (const [type, { reason, keys }] of onlyOnce) {
|
|
1256
|
-
for (const extra of keys.slice(1)) {
|
|
1257
|
-
problems.push({
|
|
1258
|
-
elementKey: extra,
|
|
1259
|
-
message: `a second ${type} (after [${keys[0]}]): at most one on a page, since it renders as ${reason}.`
|
|
1260
|
-
});
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1264
|
-
const rule = renderingOf(element.type)?.children;
|
|
1265
|
-
if (!rule) continue;
|
|
1266
|
-
const children = element.children?.length ?? 0;
|
|
1267
|
-
if (children !== rule.count) {
|
|
1268
|
-
problems.push({
|
|
1269
|
-
elementKey: key,
|
|
1270
|
-
message: `${element.type} takes exactly ${rule.count} children (${rule.roles}); this one has ${children}.`
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
const declared = [
|
|
1275
|
-
...catalog2.actionNames ?? [],
|
|
1276
|
-
...(catalog2.schema?.builtInActions ?? []).map((action) => action.name)
|
|
1277
|
-
];
|
|
1278
|
-
const knownActions = declared.length > 0 ? new Set(declared) : void 0;
|
|
1279
|
-
const STATE_WRITES = {
|
|
1280
|
-
setState: [{ param: "statePath" }],
|
|
1281
|
-
pushState: [{ param: "statePath" }, { param: "clearStatePath", optional: true }],
|
|
1282
|
-
removeState: [{ param: "statePath" }],
|
|
1283
|
-
validateForm: [{ param: "statePath", optional: true }]
|
|
1284
|
-
};
|
|
1285
|
-
const OWNED_ROOTS = [INPUTS_ROOT, RESULT_ROOT];
|
|
1286
|
-
const ownedRootOf = (written) => {
|
|
1287
|
-
const statePath = written.startsWith("/") ? written : `/${written}`;
|
|
1288
|
-
return OWNED_ROOTS.find((root) => statePath === root || statePath.startsWith(`${root}/`));
|
|
1289
|
-
};
|
|
1290
|
-
const bindingsOf = (binding) => Array.isArray(binding) ? binding : [binding];
|
|
1291
|
-
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.`;
|
|
1292
|
-
const checkBinding = (key, site, entry) => {
|
|
1293
|
-
const action = entry?.action;
|
|
1294
|
-
if (typeof action !== "string") {
|
|
1295
|
-
problems.push({ elementKey: key, message: `${site} has an entry with no "action" name.` });
|
|
1296
|
-
return;
|
|
1297
|
-
}
|
|
1298
|
-
if (knownActions && !knownActions.has(action)) {
|
|
1299
|
-
problems.push({
|
|
1300
|
-
elementKey: key,
|
|
1301
|
-
message: `${site} names the unknown action "${action}" (known: ${[...knownActions].join(", ")}); nothing would handle it.`
|
|
1302
|
-
});
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
const writes = hasOwnProp(STATE_WRITES, action) ? STATE_WRITES[action] : void 0;
|
|
1306
|
-
if (writes) {
|
|
1307
|
-
const params = entry.params;
|
|
1308
|
-
for (const { param, optional } of writes) {
|
|
1309
|
-
const written = typeof params === "object" && params !== null ? params[param] : void 0;
|
|
1310
|
-
if (written === void 0 || written === null) {
|
|
1311
|
-
if (!optional) {
|
|
1312
|
-
problems.push({
|
|
1313
|
-
elementKey: key,
|
|
1314
|
-
message: `${site} calls ${action} without a literal "${param}".`
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
continue;
|
|
1318
|
-
}
|
|
1319
|
-
if (typeof written !== "string") {
|
|
1320
|
-
problems.push({
|
|
1321
|
-
elementKey: key,
|
|
1322
|
-
message: `${site} calls ${action} with a "${param}" that is not a literal string; where an action writes must be named, never computed.`
|
|
1323
|
-
});
|
|
1324
|
-
continue;
|
|
1325
|
-
}
|
|
1326
|
-
const owned = ownedRootOf(written);
|
|
1327
|
-
if (owned) {
|
|
1328
|
-
const where = param === "statePath" ? `on "${written}"` : `with ${param} "${written}"`;
|
|
1329
|
-
problems.push({
|
|
1330
|
-
elementKey: key,
|
|
1331
|
-
message: `${site} calls ${action} ${where}: ${refusal(owned, written.startsWith("/") ? written : `/${written}`)}`
|
|
1332
|
-
});
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
}
|
|
1336
|
-
for (const hook of ["onSuccess", "onError"]) {
|
|
1337
|
-
const follow = entry[hook];
|
|
1338
|
-
if (follow === void 0 || follow === null) continue;
|
|
1339
|
-
const hookSite = `${site}.${hook}`;
|
|
1340
|
-
if (typeof follow !== "object" || Array.isArray(follow)) {
|
|
1341
|
-
problems.push({
|
|
1342
|
-
elementKey: key,
|
|
1343
|
-
message: `${hookSite} must be an object: a { "set" } of state paths to values, or an { "action" } binding.`
|
|
1344
|
-
});
|
|
1345
|
-
continue;
|
|
1346
|
-
}
|
|
1347
|
-
const record = follow;
|
|
1348
|
-
if (record.set !== void 0 && record.set !== null) {
|
|
1349
|
-
if (typeof record.set !== "object" || Array.isArray(record.set)) {
|
|
1350
|
-
problems.push({
|
|
1351
|
-
elementKey: key,
|
|
1352
|
-
message: `${hookSite}.set must be an object mapping a state path to its value.`
|
|
1353
|
-
});
|
|
1354
|
-
} else {
|
|
1355
|
-
for (const written of Object.keys(record.set)) {
|
|
1356
|
-
const owned = ownedRootOf(written);
|
|
1357
|
-
if (owned) {
|
|
1358
|
-
problems.push({
|
|
1359
|
-
elementKey: key,
|
|
1360
|
-
message: `${hookSite} sets "${written}": ${refusal(owned, written.startsWith("/") ? written : `/${written}`)}`
|
|
1361
|
-
});
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
if (record.action !== void 0) checkBinding(key, hookSite, record);
|
|
1367
|
-
}
|
|
1368
|
-
};
|
|
1369
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1370
|
-
const on = element.on;
|
|
1371
|
-
if (on !== void 0 && on !== null) {
|
|
1372
|
-
if (typeof on !== "object" || Array.isArray(on)) {
|
|
1373
|
-
problems.push({
|
|
1374
|
-
elementKey: key,
|
|
1375
|
-
message: '"on" must be an object mapping an event name to its actions.'
|
|
1376
|
-
});
|
|
1377
|
-
} else {
|
|
1378
|
-
const emitted = eventsOf(catalog2, element.type);
|
|
1379
|
-
for (const [event, binding] of Object.entries(on)) {
|
|
1380
|
-
if (emitted && !emitted.includes(event)) {
|
|
1381
|
-
problems.push({
|
|
1382
|
-
elementKey: key,
|
|
1383
|
-
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.`
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
for (const entry of bindingsOf(binding)) checkBinding(key, `on.${event}`, entry);
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
const watch = element.watch;
|
|
1391
|
-
if (watch !== void 0 && watch !== null) {
|
|
1392
|
-
if (typeof watch !== "object" || Array.isArray(watch)) {
|
|
1393
|
-
problems.push({
|
|
1394
|
-
elementKey: key,
|
|
1395
|
-
message: '"watch" must be an object mapping a state path to the actions its change fires.'
|
|
1396
|
-
});
|
|
1397
|
-
} else {
|
|
1398
|
-
for (const [path, binding] of Object.entries(watch)) {
|
|
1399
|
-
for (const entry of bindingsOf(binding)) checkBinding(key, `watch.${path}`, entry);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
return { ok: problems.length === 0, problems };
|
|
1405
|
-
}
|
|
1406
|
-
function formatProblems(problems) {
|
|
1407
|
-
return problems.map(
|
|
1408
|
-
(problem) => problem.elementKey ? `[${problem.elementKey}] ${problem.message}` : problem.message
|
|
1409
|
-
).join("\n");
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// src/generative/layout-fits.ts
|
|
1413
|
-
function isUnder(root, path) {
|
|
1414
|
-
return path === root || path.startsWith(`${root}/`);
|
|
1415
|
-
}
|
|
1416
|
-
function itemPathResolver(spec, key, parents) {
|
|
1417
|
-
let base;
|
|
1418
|
-
let resolvedBase = false;
|
|
1419
|
-
return (field) => {
|
|
1420
|
-
if (!resolvedBase) {
|
|
1421
|
-
base = repeatBasePathOf(spec, key, parents);
|
|
1422
|
-
resolvedBase = true;
|
|
1423
|
-
}
|
|
1424
|
-
if (base === void 0) return void 0;
|
|
1425
|
-
const under = field.startsWith("/") ? field.slice(1) : field;
|
|
1426
|
-
return under === "" ? base : `${base}/${under}`;
|
|
1427
|
-
};
|
|
1428
|
-
}
|
|
1429
|
-
function interpolatedPaths(template, itemPath) {
|
|
1430
|
-
return [...template.matchAll(/\$\{([^}]+)\}/g)].flatMap((match) => {
|
|
1431
|
-
const raw = match[1];
|
|
1432
|
-
if (raw === void 0) return [];
|
|
1433
|
-
if (raw.startsWith("/")) return [raw];
|
|
1434
|
-
return [itemPath(raw) ?? `/${raw}`];
|
|
1435
|
-
});
|
|
1436
|
-
}
|
|
1437
|
-
function mentionedPaths(spec, parents) {
|
|
1438
|
-
const found = { bound: [], read: [], adrift: [] };
|
|
1439
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1440
|
-
const itemPath = itemPathResolver(spec, key, parents);
|
|
1441
|
-
const walk = (value) => {
|
|
1442
|
-
if (Array.isArray(value)) {
|
|
1443
|
-
value.forEach(walk);
|
|
1444
|
-
return;
|
|
1445
|
-
}
|
|
1446
|
-
if (typeof value !== "object" || value === null) return;
|
|
1447
|
-
const record = value;
|
|
1448
|
-
if (typeof record.$bindState === "string") found.bound.push(record.$bindState);
|
|
1449
|
-
if (typeof record.$state === "string") found.read.push(record.$state);
|
|
1450
|
-
if (typeof record.$template === "string") {
|
|
1451
|
-
found.read.push(...interpolatedPaths(record.$template, itemPath));
|
|
1452
|
-
}
|
|
1453
|
-
if (typeof record.$bindItem === "string") {
|
|
1454
|
-
const path = itemPath(record.$bindItem);
|
|
1455
|
-
if (path === void 0) found.adrift.push(key);
|
|
1456
|
-
else found.bound.push(path);
|
|
1457
|
-
}
|
|
1458
|
-
if (typeof record.$item === "string") {
|
|
1459
|
-
const path = itemPath(record.$item);
|
|
1460
|
-
if (path === void 0) found.adrift.push(key);
|
|
1461
|
-
else found.read.push(path);
|
|
1462
|
-
}
|
|
1463
|
-
Object.values(record).forEach(walk);
|
|
1464
|
-
};
|
|
1465
|
-
walk(element.props);
|
|
1466
|
-
walk(element.visible);
|
|
1467
|
-
}
|
|
1468
|
-
return found;
|
|
1469
|
-
}
|
|
1470
|
-
function staleReads(read, root, resolves) {
|
|
1471
|
-
const under = read.filter((path) => isUnder(root, path));
|
|
1472
|
-
return [...new Set(under)].filter((path) => !resolves(path));
|
|
1473
|
-
}
|
|
1474
|
-
function staleRepeats(spec, parents, root, resolves, side) {
|
|
1475
|
-
const problems = [];
|
|
1476
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1477
|
-
if (!element.repeat) continue;
|
|
1478
|
-
const listPath = repeatListPathOf(spec, key, parents);
|
|
1479
|
-
if (listPath === void 0 || !isUnder(root, listPath)) continue;
|
|
1480
|
-
if (!resolves(listPath)) {
|
|
1481
|
-
problems.push(`${key}: repeats over ${listPath}, which no ${side} has`);
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
return problems;
|
|
1485
|
-
}
|
|
1486
|
-
var NOT_A_VALUE = {
|
|
1487
|
-
object: { what: "a structure", instead: "a structure is shown through its members" },
|
|
1488
|
-
list: { what: "a list", instead: "a list is laid out as a repeat or a DataTable" },
|
|
1489
|
-
document: { what: "a file", instead: "a file is delegated to the kernel's own control" },
|
|
1490
|
-
image: { what: "a file", instead: "a file is delegated to the kernel's own control" }
|
|
1491
103
|
};
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
function listProps() {
|
|
1500
|
-
if (listPropsCache) return listPropsCache;
|
|
1501
|
-
const found = /* @__PURE__ */ new Map([
|
|
1502
|
-
["DataTable", /* @__PURE__ */ new Map([["rows", "anything"]])]
|
|
1503
|
-
]);
|
|
1504
|
-
const components3 = catalog.data.components;
|
|
1505
|
-
for (const [type, definition] of Object.entries(components3)) {
|
|
1506
|
-
const shape = definition.props?.shape;
|
|
1507
|
-
for (const [prop, schema] of Object.entries(shape ?? {})) {
|
|
1508
|
-
const items = listItemsOf(schema);
|
|
1509
|
-
if (items === void 0) continue;
|
|
1510
|
-
if (!found.has(type)) found.set(type, /* @__PURE__ */ new Map());
|
|
1511
|
-
found.get(type).set(prop, items);
|
|
104
|
+
function reportingRegistry(registry, report, made) {
|
|
105
|
+
const wrapped = {};
|
|
106
|
+
for (const [type, Renderer2] of Object.entries(registry)) {
|
|
107
|
+
const kept = made.get(type);
|
|
108
|
+
if (kept && kept.renderer === Renderer2) {
|
|
109
|
+
wrapped[type] = kept.wrapper;
|
|
110
|
+
continue;
|
|
1512
111
|
}
|
|
112
|
+
const Component2 = Renderer2;
|
|
113
|
+
const Reported = (props) => /* @__PURE__ */ jsx(ElementBoundary, { type, report, reporting: React5.useContext(ReportingContext), children: /* @__PURE__ */ jsx(Component2, { ...props }) });
|
|
114
|
+
Reported.displayName = `Reported(${type})`;
|
|
115
|
+
made.set(type, { renderer: Renderer2, wrapper: Reported });
|
|
116
|
+
wrapped[type] = Reported;
|
|
1513
117
|
}
|
|
1514
|
-
|
|
1515
|
-
return found;
|
|
118
|
+
return wrapped;
|
|
1516
119
|
}
|
|
1517
|
-
var
|
|
1518
|
-
function
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
function listItemsOf(schema) {
|
|
1529
|
-
const def = unwrapped(schema);
|
|
1530
|
-
if (def?.type !== "array") return void 0;
|
|
1531
|
-
const element = unwrapped(def.element);
|
|
1532
|
-
return element?.type !== void 0 && VALUE_SCHEMAS.has(element.type) ? "values" : "anything";
|
|
1533
|
-
}
|
|
1534
|
-
function nonScalarReads(spec, parents, root, fieldAt) {
|
|
1535
|
-
const problems = [];
|
|
1536
|
-
const lists = listProps();
|
|
1537
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1538
|
-
const itemPath = itemPathResolver(spec, key, parents);
|
|
1539
|
-
const listy = lists.get(element.type);
|
|
1540
|
-
const check = (prop, path) => {
|
|
1541
|
-
if (!isUnder(root, path)) return;
|
|
1542
|
-
const field = fieldAt(path);
|
|
1543
|
-
if (!field) return;
|
|
1544
|
-
const wrong = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind] : void 0;
|
|
1545
|
-
if (!wrong) return;
|
|
1546
|
-
problems.push(
|
|
1547
|
-
`${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}`
|
|
1548
|
-
);
|
|
1549
|
-
};
|
|
1550
|
-
const checkList = (prop, path, items) => {
|
|
1551
|
-
if (!isUnder(root, path)) return;
|
|
1552
|
-
const field = fieldAt(path);
|
|
1553
|
-
if (!field || field.kind === "unknown") return;
|
|
1554
|
-
if (field.kind !== "list") {
|
|
1555
|
-
const what = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind].what : "a value";
|
|
1556
|
-
problems.push(
|
|
1557
|
-
`${key}: ${prop} takes a list, and ${path} is ${what}; a prop that takes a list reads a list path`
|
|
1558
|
-
);
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
|
-
if (items !== "values") return;
|
|
1562
|
-
const of = hasOwnProp(NOT_VALUES, field.item.kind) ? NOT_VALUES[field.item.kind] : void 0;
|
|
1563
|
-
if (!of) return;
|
|
1564
|
-
problems.push(
|
|
1565
|
-
`${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`
|
|
1566
|
-
);
|
|
1567
|
-
};
|
|
1568
|
-
const walk = (prop, value) => {
|
|
1569
|
-
if (Array.isArray(value)) {
|
|
1570
|
-
value.forEach((entry) => walk(prop, entry));
|
|
1571
|
-
return;
|
|
1572
|
-
}
|
|
1573
|
-
if (typeof value !== "object" || value === null) return;
|
|
1574
|
-
const record = value;
|
|
1575
|
-
if (typeof record.$state === "string") check(prop, record.$state);
|
|
1576
|
-
if (typeof record.$item === "string") {
|
|
1577
|
-
const path = itemPath(record.$item);
|
|
1578
|
-
if (path !== void 0) check(prop, path);
|
|
1579
|
-
}
|
|
1580
|
-
if (typeof record.$template === "string") {
|
|
1581
|
-
for (const path of interpolatedPaths(record.$template, itemPath)) check(prop, path);
|
|
1582
|
-
}
|
|
1583
|
-
for (const [name, entry] of Object.entries(record)) {
|
|
1584
|
-
if (name !== "$cond") walk(prop, entry);
|
|
1585
|
-
}
|
|
1586
|
-
};
|
|
1587
|
-
for (const [prop, value] of Object.entries(element.props ?? {})) {
|
|
1588
|
-
const items = listy?.get(prop);
|
|
1589
|
-
if (items === void 0 || Array.isArray(value)) {
|
|
1590
|
-
walk(prop, value);
|
|
1591
|
-
continue;
|
|
1592
|
-
}
|
|
1593
|
-
if (typeof value !== "object" || value === null) continue;
|
|
1594
|
-
const record = value;
|
|
1595
|
-
if (typeof record.$state === "string") checkList(prop, record.$state, items);
|
|
1596
|
-
if (typeof record.$item === "string") {
|
|
1597
|
-
const path = itemPath(record.$item);
|
|
1598
|
-
if (path !== void 0) checkList(prop, path, items);
|
|
120
|
+
var CONTAINER = "mx-auto w-full max-w-6xl px-6 sm:px-8";
|
|
121
|
+
function BrandBar({ app, links, tag }) {
|
|
122
|
+
const brand = useBrand();
|
|
123
|
+
return /* @__PURE__ */ jsx("header", { className: "border-b border-border", children: /* @__PURE__ */ jsxs("div", { className: cn(CONTAINER, "flex h-16 items-center gap-5"), children: [
|
|
124
|
+
/* @__PURE__ */ jsx(
|
|
125
|
+
"img",
|
|
126
|
+
{
|
|
127
|
+
src: brand.logo.onLight,
|
|
128
|
+
alt: brand.name,
|
|
129
|
+
referrerPolicy: "no-referrer",
|
|
130
|
+
className: "h-7 w-auto dark:hidden"
|
|
1599
131
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
if (underInputs.length > 0) {
|
|
1609
|
-
problems.push(`a result page binds ${underInputs.join(", ")}; a result page writes nothing`);
|
|
1610
|
-
}
|
|
1611
|
-
} else {
|
|
1612
|
-
for (const path of underInputs) {
|
|
1613
|
-
if (!inputFieldAtPath(inputs, path)) {
|
|
1614
|
-
problems.push(`${path} is bound, and no input has it`);
|
|
132
|
+
),
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
"img",
|
|
135
|
+
{
|
|
136
|
+
src: brand.logo.onDark,
|
|
137
|
+
alt: brand.name,
|
|
138
|
+
referrerPolicy: "no-referrer",
|
|
139
|
+
className: "hidden h-7 w-auto dark:block"
|
|
1615
140
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
141
|
+
),
|
|
142
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "h-5 w-px bg-border" }),
|
|
143
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground/80", children: app }),
|
|
144
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex min-w-0 items-center gap-6", children: [
|
|
145
|
+
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(
|
|
146
|
+
"a",
|
|
147
|
+
{
|
|
148
|
+
href: "#",
|
|
149
|
+
onClick: (event) => event.preventDefault(),
|
|
150
|
+
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",
|
|
151
|
+
children: link
|
|
152
|
+
},
|
|
153
|
+
`${index}-${link}`
|
|
154
|
+
)) }) : null,
|
|
155
|
+
tag ? /* @__PURE__ */ jsx(
|
|
156
|
+
"span",
|
|
157
|
+
{
|
|
158
|
+
className: cn(
|
|
159
|
+
"min-w-0 truncate rounded-lg border px-2.5 py-1 font-mono text-[11px]",
|
|
160
|
+
selectedBorderClass,
|
|
161
|
+
selectedFillClass,
|
|
162
|
+
linkTextClass
|
|
163
|
+
),
|
|
164
|
+
children: tag
|
|
165
|
+
}
|
|
166
|
+
) : null
|
|
167
|
+
] })
|
|
168
|
+
] }) });
|
|
1638
169
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
}
|
|
1644
|
-
return [path];
|
|
170
|
+
|
|
171
|
+
// src/generative/declared-props.ts
|
|
172
|
+
function definitionOf(schema) {
|
|
173
|
+
return schema._zod?.def;
|
|
1645
174
|
}
|
|
1646
|
-
function
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
175
|
+
function unwrapped(schema) {
|
|
176
|
+
let def = definitionOf(schema);
|
|
177
|
+
for (let depth = 0; depth < 8 && def; depth += 1) {
|
|
178
|
+
if (def.type !== "nullable" && def.type !== "optional" && def.type !== "default") return def;
|
|
179
|
+
def = def.innerType ? definitionOf(def.innerType) : void 0;
|
|
1651
180
|
}
|
|
181
|
+
return def;
|
|
182
|
+
}
|
|
183
|
+
function absentValueOf(schema) {
|
|
184
|
+
if (schema.safeParse(null).success) return null;
|
|
185
|
+
if (schema.safeParse(void 0).success) return void 0;
|
|
186
|
+
const type = unwrapped(schema)?.type;
|
|
187
|
+
if (type === "string") return "";
|
|
188
|
+
if (type === "array") return [];
|
|
189
|
+
return void 0;
|
|
1652
190
|
}
|
|
1653
|
-
function
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
const parents = parentMapOf(spec);
|
|
1657
|
-
for (const [key, element] of Object.entries(spec.elements)) {
|
|
1658
|
-
const written = element.props?.path;
|
|
1659
|
-
const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
|
|
1660
|
-
if (element.type === "MthdsField") {
|
|
1661
|
-
if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
|
|
1662
|
-
problems.push(`${key}: MthdsField delegates ${String(written)}, which no input has`);
|
|
1663
|
-
} else {
|
|
1664
|
-
delegated.push(path);
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
if (element.type === "MthdsResult") {
|
|
1668
|
-
if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
|
|
1669
|
-
problems.push(`${key}: MthdsResult delegates ${String(written)}, which no result has`);
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
191
|
+
function conformValue(schema, value) {
|
|
192
|
+
if (value === void 0 || value === null) {
|
|
193
|
+
return schema.safeParse(value).success ? value : absentValueOf(schema);
|
|
1672
194
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
problems.push(...boundProblems(bound, descriptor.inputs));
|
|
1678
|
-
if (!descriptor.inputs) {
|
|
1679
|
-
const result = descriptor.result;
|
|
1680
|
-
const fieldAt2 = (path) => result ? resultFieldAtPath(result, path) : void 0;
|
|
1681
|
-
const resolves2 = (path) => fieldAt2(path) !== void 0;
|
|
1682
|
-
problems.push(...staleRepeats(spec, parents, RESULT_ROOT, resolves2, "result"));
|
|
1683
|
-
for (const path of staleReads(read, RESULT_ROOT, resolves2)) {
|
|
1684
|
-
problems.push(`${path} is read, and no result has it`);
|
|
1685
|
-
}
|
|
1686
|
-
problems.push(...nonScalarReads(spec, parents, RESULT_ROOT, fieldAt2));
|
|
1687
|
-
return problems;
|
|
1688
|
-
}
|
|
1689
|
-
const inputs = descriptor.inputs;
|
|
1690
|
-
const fieldAt = (path) => inputFieldAtPath(inputs, path);
|
|
1691
|
-
const resolves = (path) => fieldAt(path) !== void 0;
|
|
1692
|
-
problems.push(...staleRepeats(spec, parents, INPUTS_ROOT, resolves, "input"));
|
|
1693
|
-
for (const path of staleReads(read, INPUTS_ROOT, resolves)) {
|
|
1694
|
-
problems.push(`${path} is read, and no input has it`);
|
|
1695
|
-
}
|
|
1696
|
-
problems.push(...nonScalarReads(spec, parents, INPUTS_ROOT, fieldAt));
|
|
1697
|
-
const offered = {
|
|
1698
|
-
bound: new Set(bound),
|
|
1699
|
-
repeated: new Set(repeatPaths(spec)),
|
|
1700
|
-
delegated
|
|
1701
|
-
};
|
|
1702
|
-
for (const field of inputs) {
|
|
1703
|
-
if (!field.required) continue;
|
|
1704
|
-
for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered)) {
|
|
1705
|
-
problems.push(`${path} is required, and the layout offers nowhere to enter it`);
|
|
1706
|
-
}
|
|
195
|
+
if (schema.safeParse(value).success) return value;
|
|
196
|
+
const def = unwrapped(schema);
|
|
197
|
+
if (def?.type === "string" && (typeof value === "number" || typeof value === "boolean")) {
|
|
198
|
+
return String(value);
|
|
1707
199
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
return layoutProblems(descriptor, spec).length === 0;
|
|
1712
|
-
}
|
|
1713
|
-
function specToJsonl(spec) {
|
|
1714
|
-
const lines = [];
|
|
1715
|
-
const push = (op, path, value) => lines.push(JSON.stringify({ op, path, value }));
|
|
1716
|
-
push("add", "/root", spec.root);
|
|
1717
|
-
const emitted = /* @__PURE__ */ new Set();
|
|
1718
|
-
const queue = [spec.root];
|
|
1719
|
-
while (queue.length > 0) {
|
|
1720
|
-
const key = queue.shift();
|
|
1721
|
-
if (emitted.has(key)) continue;
|
|
1722
|
-
const element = spec.elements[key];
|
|
1723
|
-
if (!element) continue;
|
|
1724
|
-
emitted.add(key);
|
|
1725
|
-
push("add", `/elements/${escapeSegment(key)}`, element);
|
|
1726
|
-
for (const child of element.children ?? []) queue.push(child);
|
|
1727
|
-
for (const slotChildren of Object.values(element.slots ?? {})) queue.push(...slotChildren);
|
|
200
|
+
if (def?.type === "array" && def.element && Array.isArray(value)) {
|
|
201
|
+
const element = def.element;
|
|
202
|
+
return value.filter((entry) => element.safeParse(entry).success);
|
|
1728
203
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
204
|
+
return absentValueOf(schema);
|
|
205
|
+
}
|
|
206
|
+
function conformProps(shape, props, asWritten = []) {
|
|
207
|
+
let conformed;
|
|
208
|
+
for (const [name, schema] of Object.entries(shape)) {
|
|
209
|
+
if (asWritten.includes(name)) continue;
|
|
210
|
+
const value = props[name];
|
|
211
|
+
const held = conformValue(schema, value);
|
|
212
|
+
if (held === value) continue;
|
|
213
|
+
conformed ?? (conformed = { ...props });
|
|
214
|
+
conformed[name] = held;
|
|
1731
215
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
216
|
+
return conformed ?? props;
|
|
217
|
+
}
|
|
218
|
+
function withDeclaredProps(definitions, renderers, asWritten = {}) {
|
|
219
|
+
const wrapped = {};
|
|
220
|
+
for (const [name, render] of Object.entries(renderers)) {
|
|
221
|
+
const schema = definitions[name]?.props;
|
|
222
|
+
const shape = schema?.shape;
|
|
223
|
+
wrapped[name] = shape ? (ctx) => render({
|
|
224
|
+
...ctx,
|
|
225
|
+
props: conformProps(shape, ctx.props, asWritten[name])
|
|
226
|
+
}) : render;
|
|
1734
227
|
}
|
|
1735
|
-
return
|
|
1736
|
-
`;
|
|
1737
|
-
}
|
|
1738
|
-
var FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1739
|
-
function pointerReachesPrototype(pointer) {
|
|
1740
|
-
return typeof pointer === "string" && pointer.split("/").some((segment) => FORBIDDEN_SEGMENTS.has(unescapeSegment(segment)));
|
|
228
|
+
return wrapped;
|
|
1741
229
|
}
|
|
1742
|
-
function
|
|
1743
|
-
|
|
230
|
+
function textOf(value) {
|
|
231
|
+
if (value === void 0 || value === null) return "";
|
|
232
|
+
if (typeof value !== "object") return String(value);
|
|
1744
233
|
try {
|
|
1745
|
-
|
|
234
|
+
return String(value);
|
|
1746
235
|
} catch {
|
|
1747
|
-
return false;
|
|
1748
|
-
}
|
|
1749
|
-
const patch = parsed;
|
|
1750
|
-
return pointerReachesPrototype(patch?.path) || pointerReachesPrototype(patch?.from);
|
|
1751
|
-
}
|
|
1752
|
-
function specFromJsonl(jsonl) {
|
|
1753
|
-
let spec = { root: "", elements: {} };
|
|
1754
|
-
for (const line of jsonl.split("\n")) {
|
|
1755
|
-
if (reachesPrototype(line)) continue;
|
|
1756
236
|
try {
|
|
1757
|
-
|
|
237
|
+
return JSON.stringify(value) ?? "";
|
|
1758
238
|
} catch {
|
|
1759
|
-
|
|
239
|
+
return "";
|
|
1760
240
|
}
|
|
1761
241
|
}
|
|
1762
|
-
return spec;
|
|
1763
|
-
}
|
|
1764
|
-
function jsonlLines(jsonl) {
|
|
1765
|
-
return jsonl.split("\n").filter((line) => line.trim().length > 0);
|
|
1766
242
|
}
|
|
1767
|
-
var
|
|
1768
|
-
function
|
|
1769
|
-
|
|
243
|
+
var FrameHostContext = React5.createContext({});
|
|
244
|
+
function FrameHostProvider({
|
|
245
|
+
host,
|
|
1770
246
|
children
|
|
1771
247
|
}) {
|
|
1772
|
-
|
|
1773
|
-
return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
|
|
248
|
+
return /* @__PURE__ */ jsx(FrameHostContext.Provider, { value: host, children });
|
|
1774
249
|
}
|
|
1775
|
-
function
|
|
1776
|
-
|
|
1777
|
-
if (!manifest)
|
|
1778
|
-
throw new Error(
|
|
1779
|
-
"useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
|
|
1780
|
-
);
|
|
1781
|
-
return manifest;
|
|
1782
|
-
}
|
|
1783
|
-
var WEIGHTS = "400;500;600;700";
|
|
1784
|
-
function useWebfont(webfont) {
|
|
1785
|
-
const provider = webfont?.provider;
|
|
1786
|
-
const family = webfont?.family;
|
|
1787
|
-
React3.useEffect(() => {
|
|
1788
|
-
if (!provider || !family) return;
|
|
1789
|
-
const key = `${provider}:${family}`;
|
|
1790
|
-
if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
|
|
1791
|
-
for (const origin of ["https://fonts.googleapis.com", "https://fonts.gstatic.com"]) {
|
|
1792
|
-
if (document.head.querySelector(`link[rel="preconnect"][href="${origin}"]`)) continue;
|
|
1793
|
-
const preconnect = document.createElement("link");
|
|
1794
|
-
preconnect.rel = "preconnect";
|
|
1795
|
-
preconnect.href = origin;
|
|
1796
|
-
if (origin.endsWith("gstatic.com")) preconnect.crossOrigin = "anonymous";
|
|
1797
|
-
document.head.appendChild(preconnect);
|
|
1798
|
-
}
|
|
1799
|
-
const link = document.createElement("link");
|
|
1800
|
-
link.rel = "stylesheet";
|
|
1801
|
-
const encoded = encodeURIComponent(family).replace(/%20/g, "+");
|
|
1802
|
-
link.href = `https://fonts.googleapis.com/css2?family=${encoded}:wght@${WEIGHTS}&display=swap`;
|
|
1803
|
-
link.dataset.brandWebfont = key;
|
|
1804
|
-
document.head.appendChild(link);
|
|
1805
|
-
}, [provider, family]);
|
|
250
|
+
function useFrameHost() {
|
|
251
|
+
return React5.useContext(FrameHostContext);
|
|
1806
252
|
}
|
|
1807
253
|
function useBoundField(literal, binding, empty, { checks, validateOn }) {
|
|
1808
254
|
const [boundValue, setBoundValue] = useBoundProp(literal ?? void 0, binding);
|
|
1809
|
-
const [localValue, setLocalValue] =
|
|
255
|
+
const [localValue, setLocalValue] = React5.useState(literal ?? empty);
|
|
1810
256
|
const isBound = Boolean(binding);
|
|
1811
257
|
const hasValidation = Boolean(binding && checks?.length);
|
|
1812
258
|
const when = validateOn ?? "change";
|
|
@@ -1846,11 +292,16 @@ function Card({
|
|
|
1846
292
|
return (
|
|
1847
293
|
// A style's panel: a host writes the style's field fill onto `--input`
|
|
1848
294
|
// here, as on its own panel, so the fields inside do not sink into it.
|
|
295
|
+
// A panel's corner is one and a half times a control's, as the rail's is.
|
|
1849
296
|
/* @__PURE__ */ jsxs(
|
|
1850
297
|
"div",
|
|
1851
298
|
{
|
|
1852
299
|
"data-style-panel": "",
|
|
1853
|
-
className: cn(
|
|
300
|
+
className: cn(
|
|
301
|
+
"rounded-[calc(var(--radius,0.5rem)*1.5)] p-6 text-card-foreground",
|
|
302
|
+
panelSurfaceClass,
|
|
303
|
+
panelFlatShadowClass
|
|
304
|
+
),
|
|
1854
305
|
children: [
|
|
1855
306
|
props.title || props.description ? /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-1.5", children: [
|
|
1856
307
|
props.title ? /* @__PURE__ */ jsx("h3", { className: cn("text-lg leading-none", headingClass(600)), children: props.title }) : null,
|
|
@@ -1940,7 +391,16 @@ function Collapsible({
|
|
|
1940
391
|
open: props.defaultOpen ?? false,
|
|
1941
392
|
"data-slot": "collapsible",
|
|
1942
393
|
children: [
|
|
1943
|
-
/* @__PURE__ */
|
|
394
|
+
/* @__PURE__ */ jsxs("summary", { className: "flex min-h-11 cursor-pointer list-none items-center justify-between gap-3 rounded-md px-4 py-3 text-sm font-medium select-none focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset [&::-webkit-details-marker]:hidden", children: [
|
|
395
|
+
/* @__PURE__ */ jsx("span", { children: props.title }),
|
|
396
|
+
/* @__PURE__ */ jsx(
|
|
397
|
+
ChevronDown,
|
|
398
|
+
{
|
|
399
|
+
"aria-hidden": "true",
|
|
400
|
+
className: "size-4 shrink-0 text-muted-foreground transition-transform [details[open]>summary_&]:rotate-180"
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
] }),
|
|
1944
404
|
/* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 py-3", children })
|
|
1945
405
|
]
|
|
1946
406
|
}
|
|
@@ -2064,7 +524,7 @@ function Progress({
|
|
|
2064
524
|
] });
|
|
2065
525
|
}
|
|
2066
526
|
function useControlId(name) {
|
|
2067
|
-
return `jr-${name}-${
|
|
527
|
+
return `jr-${name}-${React5.useId()}`;
|
|
2068
528
|
}
|
|
2069
529
|
function Input({
|
|
2070
530
|
props,
|
|
@@ -2243,9 +703,9 @@ function Button({
|
|
|
2243
703
|
}
|
|
2244
704
|
);
|
|
2245
705
|
}
|
|
2246
|
-
var DescriptorContext =
|
|
706
|
+
var DescriptorContext = React5.createContext({});
|
|
2247
707
|
function useDescriptorScope() {
|
|
2248
|
-
return
|
|
708
|
+
return React5.useContext(DescriptorContext);
|
|
2249
709
|
}
|
|
2250
710
|
function DescriptorProvider({
|
|
2251
711
|
scope,
|
|
@@ -2292,13 +752,28 @@ function useAbsolutePath(path) {
|
|
|
2292
752
|
if (path.startsWith("/")) return path;
|
|
2293
753
|
return repeat ? `${repeat.basePath}/${path}` : void 0;
|
|
2294
754
|
}
|
|
2295
|
-
function
|
|
2296
|
-
|
|
755
|
+
function withoutOptionalMark(label) {
|
|
756
|
+
return label.replace(/\s*\(optional\)\s*$/i, "") || label;
|
|
757
|
+
}
|
|
758
|
+
function MthdsField({
|
|
759
|
+
props
|
|
760
|
+
}) {
|
|
761
|
+
const scope = React5.useContext(DescriptorContext);
|
|
2297
762
|
const path = useAbsolutePath(props.path) ?? "";
|
|
2298
|
-
const
|
|
763
|
+
const found = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
|
|
764
|
+
const field = React5.useMemo(
|
|
765
|
+
() => found && (props.label || props.hint) ? {
|
|
766
|
+
...found,
|
|
767
|
+
// The control marks an optional field itself, so a label that
|
|
768
|
+
// says "(optional)" too would say it twice.
|
|
769
|
+
title: props.label ? withoutOptionalMark(props.label) : found.title,
|
|
770
|
+
description: props.hint || found.description
|
|
771
|
+
} : found,
|
|
772
|
+
[found, props.label, props.hint]
|
|
773
|
+
);
|
|
2299
774
|
const value = useStateValue(path);
|
|
2300
775
|
const { set } = useStateStore();
|
|
2301
|
-
const onChange =
|
|
776
|
+
const onChange = React5.useCallback((next) => set(path, next), [set, path]);
|
|
2302
777
|
if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "input" });
|
|
2303
778
|
return /* @__PURE__ */ jsx(
|
|
2304
779
|
FieldRenderer,
|
|
@@ -2312,7 +787,7 @@ function MthdsField({ props }) {
|
|
|
2312
787
|
);
|
|
2313
788
|
}
|
|
2314
789
|
function MthdsResult({ props }) {
|
|
2315
|
-
const scope =
|
|
790
|
+
const scope = React5.useContext(DescriptorContext);
|
|
2316
791
|
const path = useAbsolutePath(props.path) ?? "";
|
|
2317
792
|
const field = scope.result && path ? resultFieldAtPath(scope.result, path) : void 0;
|
|
2318
793
|
const value = useStateValue(path);
|
|
@@ -2325,7 +800,7 @@ function AccessibleSelect({ props, bindings, emit }) {
|
|
|
2325
800
|
props.value ?? void 0,
|
|
2326
801
|
bindings?.value
|
|
2327
802
|
);
|
|
2328
|
-
const [localValue, setLocalValue] =
|
|
803
|
+
const [localValue, setLocalValue] = React5.useState("");
|
|
2329
804
|
const isBound = Boolean(bindings?.value);
|
|
2330
805
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
2331
806
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -2374,6 +849,21 @@ function formatCell(value) {
|
|
|
2374
849
|
if (Array.isArray(value)) return value.map(formatCell).join(", ");
|
|
2375
850
|
return JSON.stringify(value);
|
|
2376
851
|
}
|
|
852
|
+
function formatColumnCell(value, format) {
|
|
853
|
+
const written = format === "date" ? readDateContent(value)?.date : void 0;
|
|
854
|
+
const day = written === void 0 ? null : /^\d{4}-\d{2}-\d{2}/.exec(written);
|
|
855
|
+
if (day) {
|
|
856
|
+
const date = /* @__PURE__ */ new Date(`${day[0]}T12:00:00Z`);
|
|
857
|
+
if (!Number.isNaN(date.getTime()))
|
|
858
|
+
return date.toLocaleDateString("en-GB", {
|
|
859
|
+
day: "numeric",
|
|
860
|
+
month: "short",
|
|
861
|
+
year: "numeric",
|
|
862
|
+
timeZone: "UTC"
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
return formatCell(value);
|
|
866
|
+
}
|
|
2377
867
|
function DataTable({ props }) {
|
|
2378
868
|
const rows = Array.isArray(props.rows) ? props.rows : [];
|
|
2379
869
|
const columns = props.columns ?? [];
|
|
@@ -2388,7 +878,7 @@ function DataTable({ props }) {
|
|
|
2388
878
|
},
|
|
2389
879
|
column.path
|
|
2390
880
|
)) }) }),
|
|
2391
|
-
/* @__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:
|
|
881
|
+
/* @__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)) })
|
|
2392
882
|
] }) });
|
|
2393
883
|
}
|
|
2394
884
|
function numberFormat(format) {
|
|
@@ -2407,7 +897,7 @@ function numberFormat(format) {
|
|
|
2407
897
|
}
|
|
2408
898
|
function Metric({ props }) {
|
|
2409
899
|
const value = props.value;
|
|
2410
|
-
const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : value === null || value === void 0 || value === "" ? "\u2014" :
|
|
900
|
+
const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : value === null || value === void 0 || value === "" ? "\u2014" : textOf(value);
|
|
2411
901
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
2412
902
|
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: props.label }),
|
|
2413
903
|
/* @__PURE__ */ jsxs("span", { className: "text-2xl font-semibold tabular-nums text-foreground", children: [
|
|
@@ -2440,8 +930,8 @@ function Split({
|
|
|
2440
930
|
}
|
|
2441
931
|
function Tabs({ props, children }) {
|
|
2442
932
|
const tabs = props.tabs ?? [];
|
|
2443
|
-
const panels =
|
|
2444
|
-
const [value, setValue] =
|
|
933
|
+
const panels = React5.Children.toArray(children);
|
|
934
|
+
const [value, setValue] = React5.useState(tabs[0]?.value ?? "");
|
|
2445
935
|
return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: setValue, className: "w-full", children: [
|
|
2446
936
|
/* @__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) => /* @__PURE__ */ jsx(
|
|
2447
937
|
TabsPrimitive.Trigger,
|
|
@@ -2471,8 +961,8 @@ var SECONDARY_BUTTON = cn(
|
|
|
2471
961
|
);
|
|
2472
962
|
function Steps({ props, children }) {
|
|
2473
963
|
const steps = props.steps ?? [];
|
|
2474
|
-
const panels =
|
|
2475
|
-
const [index, setIndex] =
|
|
964
|
+
const panels = React5.Children.toArray(children);
|
|
965
|
+
const [index, setIndex] = React5.useState(0);
|
|
2476
966
|
const last = steps.length - 1;
|
|
2477
967
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
2478
968
|
/* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-x-5 gap-y-2", children: steps.map((label, position) => /* @__PURE__ */ jsxs(
|
|
@@ -2601,7 +1091,7 @@ function Segmented({ props, bindings, emit }) {
|
|
|
2601
1091
|
props.value ?? void 0,
|
|
2602
1092
|
bindings?.value
|
|
2603
1093
|
);
|
|
2604
|
-
const [localValue, setLocalValue] =
|
|
1094
|
+
const [localValue, setLocalValue] = React5.useState("");
|
|
2605
1095
|
const isBound = Boolean(bindings?.value);
|
|
2606
1096
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
2607
1097
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -2641,7 +1131,7 @@ function NumberInput({ props, bindings, emit }) {
|
|
|
2641
1131
|
props.value ?? void 0,
|
|
2642
1132
|
bindings?.value
|
|
2643
1133
|
);
|
|
2644
|
-
const [localValue, setLocalValue] =
|
|
1134
|
+
const [localValue, setLocalValue] = React5.useState(void 0);
|
|
2645
1135
|
const isBound = Boolean(bindings?.value);
|
|
2646
1136
|
const value = isBound ? boundValue : localValue;
|
|
2647
1137
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -2675,7 +1165,7 @@ function NumberInput({ props, bindings, emit }) {
|
|
|
2675
1165
|
] })
|
|
2676
1166
|
] });
|
|
2677
1167
|
}
|
|
2678
|
-
var
|
|
1168
|
+
var components = {
|
|
2679
1169
|
Card: (ctx) => /* @__PURE__ */ jsx(Card, { ...ctx }),
|
|
2680
1170
|
// A vertical Stack stretches its children unless the spec says otherwise:
|
|
2681
1171
|
// hugging the content is the one layout a result page never wants, since a
|
|
@@ -2714,67 +1204,356 @@ var components2 = {
|
|
|
2714
1204
|
DataTable: (ctx) => /* @__PURE__ */ jsx(DataTable, { ...ctx }),
|
|
2715
1205
|
Metric: (ctx) => /* @__PURE__ */ jsx(Metric, { ...ctx })
|
|
2716
1206
|
};
|
|
2717
|
-
var generativeRenderers =
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
1207
|
+
var generativeRenderers = withDeclaredProps(
|
|
1208
|
+
baseCatalog.data.components,
|
|
1209
|
+
components
|
|
1210
|
+
);
|
|
1211
|
+
var RADIUS = "rounded-[calc(var(--radius,0.5rem)*1.5)]";
|
|
1212
|
+
function useAbsolute(path) {
|
|
1213
|
+
const repeat = useRepeatScope();
|
|
1214
|
+
if (path.startsWith("/")) return path;
|
|
1215
|
+
if (!repeat) return path;
|
|
1216
|
+
return path === "" ? repeat.basePath : `${repeat.basePath}/${path}`;
|
|
1217
|
+
}
|
|
1218
|
+
function asDate(value) {
|
|
1219
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}/.test(value)) return void 0;
|
|
1220
|
+
const date = /* @__PURE__ */ new Date(`${value.slice(0, 10)}T12:00:00Z`);
|
|
1221
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
1222
|
+
}
|
|
1223
|
+
function Composer({ props, children, emit }) {
|
|
1224
|
+
const host = useFrameHost();
|
|
1225
|
+
const busy = useDescriptorScope().env?.disabled ?? false;
|
|
1226
|
+
const two = props.columns === "2";
|
|
1227
|
+
return /* @__PURE__ */ jsxs(
|
|
1228
|
+
"div",
|
|
1229
|
+
{
|
|
1230
|
+
className: cn("mx-auto flex w-full flex-col gap-7", two ? "max-w-[980px]" : "max-w-[740px]"),
|
|
1231
|
+
children: [
|
|
1232
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1233
|
+
/* @__PURE__ */ jsx(
|
|
1234
|
+
"h1",
|
|
1235
|
+
{
|
|
1236
|
+
className: cn(
|
|
1237
|
+
"text-[32px] leading-[1.1] text-balance text-foreground sm:text-[38px] sm:leading-[1.08]",
|
|
1238
|
+
headingClass(700, true)
|
|
1239
|
+
),
|
|
1240
|
+
children: props.headline
|
|
1241
|
+
}
|
|
1242
|
+
),
|
|
1243
|
+
props.lede ? /* @__PURE__ */ jsx("p", { className: "mt-3.5 max-w-[62ch] text-[17px] leading-relaxed text-muted-foreground", children: props.lede }) : null
|
|
1244
|
+
] }),
|
|
1245
|
+
/* @__PURE__ */ jsxs(
|
|
1246
|
+
"div",
|
|
1247
|
+
{
|
|
1248
|
+
"data-style-panel": "",
|
|
1249
|
+
className: cn(RADIUS, panelSurfaceClass, panelFlatShadowClass, "p-7 max-sm:p-5"),
|
|
1250
|
+
children: [
|
|
1251
|
+
/* @__PURE__ */ jsx(
|
|
1252
|
+
"div",
|
|
1253
|
+
{
|
|
1254
|
+
className: cn(
|
|
1255
|
+
"grid gap-8",
|
|
1256
|
+
two && "md:block md:columns-2 md:gap-x-10 md:[&>*+*]:mt-8 md:[&>*>h2]:break-after-avoid md:[&>*>*:not(h2)]:break-inside-avoid"
|
|
1257
|
+
),
|
|
1258
|
+
children
|
|
1259
|
+
}
|
|
1260
|
+
),
|
|
1261
|
+
/* @__PURE__ */ jsxs("div", { className: "sticky bottom-0 z-[2] -mx-7 -mb-7 mt-7 flex items-center justify-between gap-4 rounded-b-[calc(var(--radius,0.5rem)*1.5)] border-t border-border [background-color:var(--panel-fill,var(--card,hsl(0_0%_100%)))] px-7 pt-[18px] pb-7 max-sm:-mx-5 max-sm:-mb-5 max-sm:flex-col-reverse max-sm:items-stretch max-sm:px-5 max-sm:pb-5", children: [
|
|
1262
|
+
host.eta ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2 text-sm text-muted-foreground max-sm:justify-center", children: [
|
|
1263
|
+
/* @__PURE__ */ jsx(Clock, { className: "size-4", "aria-hidden": "true" }),
|
|
1264
|
+
" ",
|
|
1265
|
+
host.eta
|
|
1266
|
+
] }) : /* @__PURE__ */ jsx("span", {}),
|
|
1267
|
+
/* @__PURE__ */ jsxs(
|
|
1268
|
+
"button",
|
|
1269
|
+
{
|
|
1270
|
+
type: "button",
|
|
1271
|
+
disabled: busy,
|
|
1272
|
+
onClick: () => emit("press"),
|
|
1273
|
+
className: cn(
|
|
1274
|
+
"inline-flex min-h-11 items-center justify-center gap-2 rounded-[var(--radius,0.5rem)] bg-primary px-[22px] text-[15px] font-semibold text-primary-foreground transition-all hover:bg-primary/90",
|
|
1275
|
+
actionShadowClass,
|
|
1276
|
+
focusOutlineClass,
|
|
1277
|
+
"disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:bg-primary"
|
|
1278
|
+
),
|
|
1279
|
+
children: [
|
|
1280
|
+
props.runLabel,
|
|
1281
|
+
" ",
|
|
1282
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "size-4", "aria-hidden": "true" })
|
|
1283
|
+
]
|
|
1284
|
+
}
|
|
1285
|
+
)
|
|
1286
|
+
] })
|
|
1287
|
+
]
|
|
1288
|
+
}
|
|
1289
|
+
),
|
|
1290
|
+
props.notes && props.notes.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "grid gap-x-8 gap-y-2.5 px-1 sm:grid-cols-2", children: props.notes.map((note, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5 text-sm text-muted-foreground", children: [
|
|
1291
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: linkTextClass, children: "\u2713" }),
|
|
1292
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0", children: note })
|
|
1293
|
+
] }, index)) }) : null
|
|
1294
|
+
]
|
|
1295
|
+
}
|
|
1296
|
+
);
|
|
2724
1297
|
}
|
|
2725
|
-
function
|
|
2726
|
-
return
|
|
1298
|
+
function FieldGroup({ props, children }) {
|
|
1299
|
+
return /* @__PURE__ */ jsxs("section", { className: "flex min-w-0 flex-col gap-5", children: [
|
|
1300
|
+
props.title ? /* @__PURE__ */ jsx("h2", { className: cn("text-[17px] leading-snug text-foreground", headingClass(600)), children: props.title }) : null,
|
|
1301
|
+
children
|
|
1302
|
+
] });
|
|
2727
1303
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
1304
|
+
function ResultHeader({ props }) {
|
|
1305
|
+
const host = useFrameHost();
|
|
1306
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-6 max-sm:flex-col", children: [
|
|
1307
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
1308
|
+
props.eyebrow ? /* @__PURE__ */ jsx("p", { className: cn("mb-1.5 text-[13px] font-semibold", linkTextClass), children: props.eyebrow }) : null,
|
|
1309
|
+
/* @__PURE__ */ jsx(
|
|
1310
|
+
"h1",
|
|
1311
|
+
{
|
|
1312
|
+
className: cn(
|
|
1313
|
+
"text-[28px] leading-[1.12] text-balance text-foreground sm:text-[32px]",
|
|
1314
|
+
headingClass(700, true)
|
|
1315
|
+
),
|
|
1316
|
+
children: props.title
|
|
1317
|
+
}
|
|
1318
|
+
),
|
|
1319
|
+
props.subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-[15px] text-muted-foreground", children: props.subtitle }) : null
|
|
1320
|
+
] }),
|
|
1321
|
+
host.actions && host.actions.length > 0 && host.onAction ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 gap-2", children: host.actions.map((label, i) => /* @__PURE__ */ jsx(
|
|
1322
|
+
"button",
|
|
1323
|
+
{
|
|
1324
|
+
type: "button",
|
|
1325
|
+
onClick: () => host.onAction?.(label),
|
|
1326
|
+
className: cn(
|
|
1327
|
+
"inline-flex min-h-11 items-center rounded-[var(--radius,0.5rem)] px-4 text-sm font-semibold sm:min-h-9",
|
|
1328
|
+
focusOutlineClass,
|
|
1329
|
+
i === 0 ? "bg-primary text-primary-foreground" : "border border-border bg-background text-foreground"
|
|
1330
|
+
),
|
|
1331
|
+
children: label
|
|
1332
|
+
},
|
|
1333
|
+
`${i}-${label}`
|
|
1334
|
+
)) }) : null
|
|
1335
|
+
] });
|
|
1336
|
+
}
|
|
1337
|
+
function segmentMix(index, count) {
|
|
1338
|
+
return count <= 1 ? 100 : Math.round(100 - index * 75 / (count - 1));
|
|
1339
|
+
}
|
|
1340
|
+
function segmentColor(index, count) {
|
|
1341
|
+
return `color-mix(in oklab, var(--link, var(--primary, hsl(240 5.9% 10%))) ${segmentMix(index, count)}%, var(--muted, hsl(240 4.8% 95.9%)))`;
|
|
1342
|
+
}
|
|
1343
|
+
function amount(value, unit) {
|
|
1344
|
+
if (unit && /^[A-Z]{3}$/.test(unit)) {
|
|
1345
|
+
try {
|
|
1346
|
+
return new Intl.NumberFormat("en-GB", {
|
|
1347
|
+
style: "currency",
|
|
1348
|
+
currency: unit,
|
|
1349
|
+
maximumFractionDigits: 0
|
|
1350
|
+
}).format(value);
|
|
1351
|
+
} catch {
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
const n = new Intl.NumberFormat("en-GB", { maximumFractionDigits: 2 }).format(value);
|
|
1355
|
+
return unit ? `${n} ${unit}` : n;
|
|
1356
|
+
}
|
|
1357
|
+
function ProportionBar({ props }) {
|
|
1358
|
+
const rows = (Array.isArray(props.items) ? props.items : []).filter(
|
|
1359
|
+
(row) => typeof row === "object" && row !== null && !Array.isArray(row)
|
|
1360
|
+
);
|
|
1361
|
+
const amountOf = (raw) => typeof raw === "object" && raw !== null ? Number.NaN : Number(raw ?? 0);
|
|
1362
|
+
const parts = rows.map((row) => ({
|
|
1363
|
+
label: textOf(row[props.labelKey]),
|
|
1364
|
+
value: amountOf(row[props.valueKey])
|
|
1365
|
+
})).filter((p) => Number.isFinite(p.value) && p.value > 0);
|
|
1366
|
+
const sum = parts.reduce((s, p) => s + p.value, 0);
|
|
1367
|
+
const total = typeof props.total === "number" ? props.total : sum;
|
|
1368
|
+
const scale = Math.max(sum, total, typeof props.of === "number" ? props.of : 0) || 1;
|
|
1369
|
+
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
1370
|
+
return /* @__PURE__ */ jsxs(
|
|
1371
|
+
"div",
|
|
1372
|
+
{
|
|
1373
|
+
"data-style-panel": "",
|
|
1374
|
+
className: cn(
|
|
1375
|
+
RADIUS,
|
|
1376
|
+
panelSurfaceClass,
|
|
1377
|
+
panelFlatShadowClass,
|
|
1378
|
+
"flex flex-col gap-3.5 px-6 py-5"
|
|
1379
|
+
),
|
|
1380
|
+
children: [
|
|
1381
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2.5", children: [
|
|
1382
|
+
/* @__PURE__ */ jsx("span", { className: "text-[15px] text-muted-foreground", children: props.label }),
|
|
1383
|
+
/* @__PURE__ */ jsx("strong", { className: "text-2xl font-semibold tabular-nums text-foreground", children: amount(total, props.unit) }),
|
|
1384
|
+
typeof props.of === "number" ? /* @__PURE__ */ jsxs("span", { className: "text-[15px] text-muted-foreground", children: [
|
|
1385
|
+
"of ",
|
|
1386
|
+
amount(props.of, props.unit)
|
|
1387
|
+
] }) : null
|
|
1388
|
+
] }),
|
|
1389
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-2 gap-0.5 overflow-hidden rounded-full bg-muted", "aria-hidden": "true", children: parts.map((p, i) => /* @__PURE__ */ jsx(
|
|
1390
|
+
"span",
|
|
1391
|
+
{
|
|
1392
|
+
style: {
|
|
1393
|
+
width: `${p.value / scale * 100}%`,
|
|
1394
|
+
background: segmentColor(i, parts.length)
|
|
1395
|
+
}
|
|
1396
|
+
},
|
|
1397
|
+
`${i}-${p.label}`
|
|
1398
|
+
)) }),
|
|
1399
|
+
/* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-5 gap-y-1", children: parts.map((p, i) => /* @__PURE__ */ jsxs(
|
|
1400
|
+
"li",
|
|
1401
|
+
{
|
|
1402
|
+
className: "inline-flex items-center gap-2 text-sm text-muted-foreground",
|
|
1403
|
+
children: [
|
|
1404
|
+
/* @__PURE__ */ jsx(
|
|
1405
|
+
"span",
|
|
1406
|
+
{
|
|
1407
|
+
className: "size-2 rounded-[2px]",
|
|
1408
|
+
style: {
|
|
1409
|
+
background: segmentColor(i, parts.length)
|
|
1410
|
+
},
|
|
1411
|
+
"aria-hidden": "true"
|
|
1412
|
+
}
|
|
1413
|
+
),
|
|
1414
|
+
cap(p.label),
|
|
1415
|
+
" ",
|
|
1416
|
+
amount(p.value, props.unit)
|
|
1417
|
+
]
|
|
1418
|
+
},
|
|
1419
|
+
`${i}-${p.label}`
|
|
1420
|
+
)) })
|
|
1421
|
+
]
|
|
1422
|
+
}
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
var COLOR_VALUE = /^(?:#[0-9a-f]{3,8}|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch)\([\w\s.,%/+-]*\)|[a-z]+)$/i;
|
|
1426
|
+
function Swatches({ props }) {
|
|
1427
|
+
const colors = (props.colors ?? []).filter(
|
|
1428
|
+
(c) => typeof c === "string" && COLOR_VALUE.test(c.trim())
|
|
1429
|
+
);
|
|
1430
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: colors.map((color, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2733
1431
|
/* @__PURE__ */ jsx(
|
|
2734
|
-
"
|
|
1432
|
+
"span",
|
|
2735
1433
|
{
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
referrerPolicy: "no-referrer",
|
|
2739
|
-
className: "h-7 w-auto dark:hidden"
|
|
1434
|
+
className: "h-7 w-11 rounded-[3px] border border-border",
|
|
1435
|
+
style: { backgroundColor: color.trim() }
|
|
2740
1436
|
}
|
|
2741
1437
|
),
|
|
1438
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-[11px] text-muted-foreground", children: color })
|
|
1439
|
+
] }, `${color}-${i}`)) });
|
|
1440
|
+
}
|
|
1441
|
+
var ASPECT = {
|
|
1442
|
+
"16:9": "aspect-video",
|
|
1443
|
+
"4:3": "aspect-[4/3]",
|
|
1444
|
+
"1:1": "aspect-square"
|
|
1445
|
+
};
|
|
1446
|
+
function Picture({
|
|
1447
|
+
props
|
|
1448
|
+
}) {
|
|
1449
|
+
const written = typeof props.path === "string" ? props.path : void 0;
|
|
1450
|
+
const path = useAbsolute(written ?? "");
|
|
1451
|
+
const value = useStateValue(path);
|
|
1452
|
+
const resolve = useResolveUrl();
|
|
1453
|
+
const content = written === void 0 ? void 0 : readImageContent(value);
|
|
1454
|
+
const src = content ? viewableUrl(resolve?.(content.url)) ?? viewableUrl(content.publicUrl) ?? viewableUrl(content.url) : void 0;
|
|
1455
|
+
const aspect = props.aspect && props.aspect !== "auto" ? ASPECT[props.aspect] : void 0;
|
|
1456
|
+
if (!src) return null;
|
|
1457
|
+
return /* @__PURE__ */ jsx(
|
|
1458
|
+
"img",
|
|
1459
|
+
{
|
|
1460
|
+
src,
|
|
1461
|
+
alt: props.alt ?? content?.caption ?? "",
|
|
1462
|
+
referrerPolicy: "no-referrer",
|
|
1463
|
+
className: cn(
|
|
1464
|
+
"block w-full rounded-[var(--radius,0.5rem)] border border-border bg-muted object-cover",
|
|
1465
|
+
aspect
|
|
1466
|
+
)
|
|
1467
|
+
}
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
function present(value) {
|
|
1471
|
+
return value !== void 0 && value !== null && value !== "";
|
|
1472
|
+
}
|
|
1473
|
+
function Fact({
|
|
1474
|
+
props
|
|
1475
|
+
}) {
|
|
1476
|
+
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: [
|
|
1477
|
+
/* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.label }),
|
|
1478
|
+
/* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children: present(props.value) ? textOf(props.value) : "\u2014" }),
|
|
1479
|
+
props.detail ? /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.detail }) : null
|
|
1480
|
+
] });
|
|
1481
|
+
}
|
|
1482
|
+
function Detail({ props }) {
|
|
1483
|
+
if (!present(props.value)) return null;
|
|
1484
|
+
return (
|
|
1485
|
+
// A rule between the rows of a list of details, never under one set in a
|
|
1486
|
+
// row: there it read as an underline on every detail but the last.
|
|
1487
|
+
/* @__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: [
|
|
1488
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: props.label }),
|
|
1489
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground", children: textOf(props.value) })
|
|
1490
|
+
] })
|
|
1491
|
+
);
|
|
1492
|
+
}
|
|
1493
|
+
var DATE_STYLES = {
|
|
1494
|
+
long: { weekday: "long", day: "numeric", month: "long", year: "numeric", timeZone: "UTC" },
|
|
1495
|
+
short: { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" },
|
|
1496
|
+
weekday: { weekday: "short", day: "numeric", month: "long", timeZone: "UTC" }
|
|
1497
|
+
};
|
|
1498
|
+
function DateText({ props }) {
|
|
1499
|
+
const date = asDate(props.value);
|
|
1500
|
+
if (!date) return null;
|
|
1501
|
+
const tone = props.tone === "accent" ? cn("text-[13px] font-semibold", linkTextClass) : props.tone === "muted" ? "text-sm text-muted-foreground" : "text-[15px] text-foreground";
|
|
1502
|
+
return /* @__PURE__ */ jsx("span", { className: cn("block", tone), children: date.toLocaleDateString("en-GB", DATE_STYLES[props.style ?? "long"]) });
|
|
1503
|
+
}
|
|
1504
|
+
function TextList({ props }) {
|
|
1505
|
+
const items = Array.isArray(props.items) ? props.items.filter((x) => typeof x === "string" && x.trim()) : [];
|
|
1506
|
+
if (items.length === 0) return null;
|
|
1507
|
+
const marker = props.marker ?? "bullet";
|
|
1508
|
+
const List2 = marker === "number" ? "ol" : "ul";
|
|
1509
|
+
return /* @__PURE__ */ jsx(List2, { className: "flex flex-col gap-2.5", children: items.map((text, index) => /* @__PURE__ */ jsxs("li", { className: "flex gap-3 text-[15px] leading-relaxed text-foreground", children: [
|
|
2742
1510
|
/* @__PURE__ */ jsx(
|
|
2743
|
-
"
|
|
1511
|
+
"span",
|
|
2744
1512
|
{
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
1513
|
+
"aria-hidden": "true",
|
|
1514
|
+
className: cn(
|
|
1515
|
+
"mt-[0.55em] shrink-0",
|
|
1516
|
+
marker === "bullet" && "size-1.5 rounded-full bg-[color:var(--link,var(--primary,hsl(240_5.9%_10%)))]",
|
|
1517
|
+
marker === "number" && cn("mt-0 min-w-5 text-sm font-semibold tabular-nums", linkTextClass),
|
|
1518
|
+
marker === "check" && cn("mt-0", linkTextClass)
|
|
1519
|
+
),
|
|
1520
|
+
children: marker === "number" ? `${index + 1}.` : marker === "check" ? "\u2713" : null
|
|
2749
1521
|
}
|
|
2750
1522
|
),
|
|
2751
|
-
/* @__PURE__ */ jsx("span", {
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
1523
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0", children: String(text) })
|
|
1524
|
+
] }, index)) });
|
|
1525
|
+
}
|
|
1526
|
+
var frameRenderers = withDeclaredProps(
|
|
1527
|
+
frameComponents,
|
|
1528
|
+
{
|
|
1529
|
+
TextList: (ctx) => /* @__PURE__ */ jsx(TextList, { ...ctx }),
|
|
1530
|
+
DateText: (ctx) => /* @__PURE__ */ jsx(DateText, { ...ctx }),
|
|
1531
|
+
Composer: (ctx) => /* @__PURE__ */ jsx(Composer, { ...ctx }),
|
|
1532
|
+
FieldGroup: (ctx) => /* @__PURE__ */ jsx(FieldGroup, { ...ctx }),
|
|
1533
|
+
ResultHeader: (ctx) => /* @__PURE__ */ jsx(ResultHeader, { ...ctx }),
|
|
1534
|
+
ProportionBar: (ctx) => /* @__PURE__ */ jsx(ProportionBar, { ...ctx }),
|
|
1535
|
+
Swatches: (ctx) => /* @__PURE__ */ jsx(Swatches, { ...ctx }),
|
|
1536
|
+
Picture: (ctx) => /* @__PURE__ */ jsx(Picture, { ...ctx }),
|
|
1537
|
+
Fact: (ctx) => /* @__PURE__ */ jsx(Fact, { ...ctx }),
|
|
1538
|
+
Detail: (ctx) => /* @__PURE__ */ jsx(Detail, { ...ctx })
|
|
1539
|
+
},
|
|
1540
|
+
// A refused `path` reaches the renderer as refused: its nearest value, the
|
|
1541
|
+
// empty text, is the item itself inside a repeat.
|
|
1542
|
+
{ Picture: ["path"] }
|
|
1543
|
+
);
|
|
1544
|
+
var ResultSlotContext = React5.createContext(null);
|
|
1545
|
+
function ResultSlotProvider({
|
|
1546
|
+
slot,
|
|
1547
|
+
children
|
|
1548
|
+
}) {
|
|
1549
|
+
return /* @__PURE__ */ jsx(ResultSlotContext.Provider, { value: slot, children });
|
|
1550
|
+
}
|
|
1551
|
+
function useResultSlot() {
|
|
1552
|
+
return React5.useContext(ResultSlotContext);
|
|
1553
|
+
}
|
|
1554
|
+
var LABEL2 = "block text-[13.5px] leading-none font-medium text-foreground";
|
|
1555
|
+
function AppBar({ props }) {
|
|
1556
|
+
return /* @__PURE__ */ jsx(BrandBar, { app: props.app, links: props.links, tag: props.tag });
|
|
2778
1557
|
}
|
|
2779
1558
|
function Hero({ props }) {
|
|
2780
1559
|
return /* @__PURE__ */ jsxs("section", { className: "pt-12 pb-10 sm:pt-14 sm:pb-12", children: [
|
|
@@ -2799,7 +1578,7 @@ function Hero({ props }) {
|
|
|
2799
1578
|
] });
|
|
2800
1579
|
}
|
|
2801
1580
|
function Workspace({ props, children }) {
|
|
2802
|
-
const [work, rail] =
|
|
1581
|
+
const [work, rail] = React5.Children.toArray(children);
|
|
2803
1582
|
const railLeft = props.rail === "left";
|
|
2804
1583
|
return /* @__PURE__ */ jsxs(
|
|
2805
1584
|
"div",
|
|
@@ -2871,22 +1650,24 @@ function Rail({ props, children }) {
|
|
|
2871
1650
|
)
|
|
2872
1651
|
);
|
|
2873
1652
|
}
|
|
2874
|
-
function
|
|
1653
|
+
function present2(value) {
|
|
2875
1654
|
return value !== void 0 && value !== null && value !== "";
|
|
2876
1655
|
}
|
|
2877
1656
|
function SummaryRow({ props }) {
|
|
2878
|
-
const text = [props.value, props.detail].filter(
|
|
1657
|
+
const text = [props.value, props.detail].filter(present2).map(textOf).join(props.separator ?? " ");
|
|
2879
1658
|
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: [
|
|
2880
1659
|
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] text-muted-foreground", children: props.label }),
|
|
2881
1660
|
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" })
|
|
2882
1661
|
] });
|
|
2883
1662
|
}
|
|
2884
1663
|
function Cta({ props, emit }) {
|
|
1664
|
+
const busy = useDescriptorScope().env?.disabled ?? false;
|
|
2885
1665
|
return /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
2886
1666
|
/* @__PURE__ */ jsx(
|
|
2887
1667
|
"button",
|
|
2888
1668
|
{
|
|
2889
1669
|
type: "button",
|
|
1670
|
+
disabled: busy,
|
|
2890
1671
|
onClick: () => emit("press"),
|
|
2891
1672
|
className: cn(
|
|
2892
1673
|
"inline-flex h-12 w-full items-center justify-center rounded-lg bg-primary px-6 text-sm font-semibold text-primary-foreground transition-all hover:bg-primary/90",
|
|
@@ -2894,7 +1675,8 @@ function Cta({ props, emit }) {
|
|
|
2894
1675
|
// it had. Focus is an outline, which no shadow a style sets can
|
|
2895
1676
|
// replace or hide.
|
|
2896
1677
|
actionShadowClass,
|
|
2897
|
-
focusOutlineClass
|
|
1678
|
+
focusOutlineClass,
|
|
1679
|
+
"disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:bg-primary"
|
|
2898
1680
|
),
|
|
2899
1681
|
children: props.label
|
|
2900
1682
|
}
|
|
@@ -2925,7 +1707,7 @@ function useTextField(props, bindings) {
|
|
|
2925
1707
|
props.value ?? void 0,
|
|
2926
1708
|
bindings?.value
|
|
2927
1709
|
);
|
|
2928
|
-
const [localValue, setLocalValue] =
|
|
1710
|
+
const [localValue, setLocalValue] = React5.useState("");
|
|
2929
1711
|
const isBound = Boolean(bindings?.value);
|
|
2930
1712
|
const value = isBound ? boundValue ?? "" : localValue;
|
|
2931
1713
|
const setValue = isBound ? setBoundValue : setLocalValue;
|
|
@@ -3005,16 +1787,21 @@ function BrandTextarea({
|
|
|
3005
1787
|
var { registry: generativeRegistry } = defineRegistry(catalog, {
|
|
3006
1788
|
components: {
|
|
3007
1789
|
...generativeRenderers,
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
1790
|
+
// Held to their definitions as the base and frame renderers are
|
|
1791
|
+
// (`declared-props.ts`).
|
|
1792
|
+
...withDeclaredProps(catalog.data.components, {
|
|
1793
|
+
Input: (ctx) => /* @__PURE__ */ jsx(BrandInput, { ...ctx }),
|
|
1794
|
+
Textarea: (ctx) => /* @__PURE__ */ jsx(BrandTextarea, { ...ctx }),
|
|
1795
|
+
AppBar: (ctx) => /* @__PURE__ */ jsx(AppBar, { ...ctx }),
|
|
1796
|
+
Hero: (ctx) => /* @__PURE__ */ jsx(Hero, { ...ctx }),
|
|
1797
|
+
Workspace: (ctx) => /* @__PURE__ */ jsx(Workspace, { ...ctx }),
|
|
1798
|
+
Section: (ctx) => /* @__PURE__ */ jsx(Section, { ...ctx }),
|
|
1799
|
+
Rail: (ctx) => /* @__PURE__ */ jsx(Rail, { ...ctx }),
|
|
1800
|
+
SummaryRow: (ctx) => /* @__PURE__ */ jsx(SummaryRow, { ...ctx }),
|
|
1801
|
+
Cta: (ctx) => /* @__PURE__ */ jsx(Cta, { ...ctx }),
|
|
1802
|
+
Footer: (ctx) => /* @__PURE__ */ jsx(Footer, { ...ctx })
|
|
1803
|
+
}),
|
|
1804
|
+
...frameRenderers
|
|
3018
1805
|
}
|
|
3019
1806
|
});
|
|
3020
1807
|
function GenerativePage({
|
|
@@ -3024,109 +1811,85 @@ function GenerativePage({
|
|
|
3024
1811
|
onRun,
|
|
3025
1812
|
loading,
|
|
3026
1813
|
registry = generativeRegistry,
|
|
3027
|
-
brand
|
|
1814
|
+
brand,
|
|
1815
|
+
onElementError
|
|
3028
1816
|
}) {
|
|
3029
1817
|
const { inputs, result, env, idPrefix } = scope;
|
|
3030
|
-
const stableScope =
|
|
1818
|
+
const stableScope = React5.useMemo(
|
|
3031
1819
|
() => ({ inputs, result, env, idPrefix }),
|
|
3032
1820
|
[inputs, result, env, idPrefix]
|
|
3033
1821
|
);
|
|
3034
|
-
const latest =
|
|
3035
|
-
|
|
1822
|
+
const latest = React5.useRef({ onRun, store });
|
|
1823
|
+
React5.useEffect(() => {
|
|
3036
1824
|
latest.current = { onRun, store };
|
|
3037
1825
|
});
|
|
3038
|
-
const
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
const
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
function useStoreSnapshot(store) {
|
|
3047
|
-
return React3.useSyncExternalStore(
|
|
3048
|
-
store.subscribe,
|
|
3049
|
-
store.getSnapshot,
|
|
3050
|
-
store.getServerSnapshot ?? store.getSnapshot
|
|
1826
|
+
const report = React5.useRef(onElementError);
|
|
1827
|
+
React5.useInsertionEffect(() => {
|
|
1828
|
+
report.current = onElementError;
|
|
1829
|
+
});
|
|
1830
|
+
const [made] = React5.useState(() => /* @__PURE__ */ new Map());
|
|
1831
|
+
const pageRegistry = React5.useMemo(
|
|
1832
|
+
() => reportingRegistry(registry, report, made),
|
|
1833
|
+
[registry, made]
|
|
3051
1834
|
);
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
1835
|
+
const rootType = spec?.elements?.[spec.root]?.type ?? "root";
|
|
1836
|
+
const specContent = React5.useMemo(() => contentOf(spec), [spec]);
|
|
1837
|
+
const reporting = onElementError !== void 0;
|
|
1838
|
+
const running = React5.useRef(false);
|
|
1839
|
+
const [handlers] = React5.useState(() => {
|
|
1840
|
+
const release = () => {
|
|
1841
|
+
setTimeout(() => {
|
|
1842
|
+
running.current = false;
|
|
1843
|
+
}, 0);
|
|
1844
|
+
};
|
|
1845
|
+
return {
|
|
1846
|
+
run: () => {
|
|
1847
|
+
if (running.current) return void 0;
|
|
1848
|
+
running.current = true;
|
|
1849
|
+
let pending;
|
|
1850
|
+
try {
|
|
1851
|
+
pending = latest.current.onRun?.(latest.current.store.getSnapshot());
|
|
1852
|
+
} catch (error) {
|
|
1853
|
+
release();
|
|
1854
|
+
throw error;
|
|
1855
|
+
}
|
|
1856
|
+
if (isThenable(pending)) {
|
|
1857
|
+
const settled = Promise.resolve(pending);
|
|
1858
|
+
settled.then(release, release);
|
|
1859
|
+
return settled;
|
|
3077
1860
|
}
|
|
1861
|
+
release();
|
|
1862
|
+
return void 0;
|
|
3078
1863
|
}
|
|
3079
|
-
|
|
1864
|
+
};
|
|
1865
|
+
});
|
|
1866
|
+
const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry: pageRegistry, store, handlers, children: /* @__PURE__ */ jsx(ReportingContext.Provider, { value: reporting, children: /* @__PURE__ */ jsx(
|
|
1867
|
+
ElementBoundary,
|
|
1868
|
+
{
|
|
1869
|
+
type: rootType,
|
|
1870
|
+
report,
|
|
1871
|
+
reporting,
|
|
1872
|
+
resetOn: specContent,
|
|
1873
|
+
children: /* @__PURE__ */ jsx(Renderer, { spec, registry: pageRegistry, loading })
|
|
3080
1874
|
}
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
case "text":
|
|
3084
|
-
case "prose":
|
|
3085
|
-
case "number":
|
|
3086
|
-
case "boolean":
|
|
3087
|
-
case "enum":
|
|
3088
|
-
case "unknown":
|
|
3089
|
-
return payload;
|
|
3090
|
-
default:
|
|
3091
|
-
return field;
|
|
3092
|
-
}
|
|
1875
|
+
) }) }) });
|
|
1876
|
+
return brand ? /* @__PURE__ */ jsx(BrandProvider, { manifest: brand, children: page }) : page;
|
|
3093
1877
|
}
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
fixture.model,
|
|
3100
|
-
fixture.seed ? "seeded" : null,
|
|
3101
|
-
fixture.critic ? "critic" : null
|
|
3102
|
-
].filter((part) => part !== null).join("--");
|
|
3103
|
-
}
|
|
3104
|
-
var PRODUCER_LABEL = {
|
|
3105
|
-
"pipelex-method": "Pipelex method",
|
|
3106
|
-
"claude-code-subagent": "Claude Code subagent",
|
|
3107
|
-
"claude-code-session": "Claude Code session, by hand"
|
|
3108
|
-
};
|
|
3109
|
-
function fixtureLabel(fixture) {
|
|
3110
|
-
const parts = [PRODUCER_LABEL[fixture.producer], fixture.model];
|
|
3111
|
-
if (fixture.seed) parts.push("with a seed");
|
|
3112
|
-
if (fixture.critic) {
|
|
3113
|
-
parts.push(
|
|
3114
|
-
`${fixture.critic.model} critic \xD7 ${fixture.critic.rounds} round${fixture.critic.rounds === 1 ? "" : "s"}`
|
|
3115
|
-
);
|
|
1878
|
+
function contentOf(spec) {
|
|
1879
|
+
try {
|
|
1880
|
+
return JSON.stringify(spec);
|
|
1881
|
+
} catch {
|
|
1882
|
+
return spec;
|
|
3116
1883
|
}
|
|
3117
|
-
return parts.join(" \xB7 ");
|
|
3118
1884
|
}
|
|
3119
|
-
function
|
|
3120
|
-
|
|
3121
|
-
|
|
1885
|
+
function useStoreSnapshot(store) {
|
|
1886
|
+
return React5.useSyncExternalStore(
|
|
1887
|
+
store.subscribe,
|
|
1888
|
+
store.getSnapshot,
|
|
1889
|
+
store.getServerSnapshot ?? store.getSnapshot
|
|
3122
1890
|
);
|
|
3123
|
-
if (!found) {
|
|
3124
|
-
const known = fixtures.filter((fixture) => fixture.pipeRef === pipeRef).map(fixtureId).join(", ");
|
|
3125
|
-
throw new Error(`No spec fixture ${id} for ${pipeRef}. Known: ${known || "none"}.`);
|
|
3126
|
-
}
|
|
3127
|
-
return found;
|
|
3128
1891
|
}
|
|
3129
1892
|
|
|
3130
|
-
export {
|
|
1893
|
+
export { BrandBar, BrandProvider, DescriptorProvider, FrameHostProvider, GenerativePage, ResultSlotProvider, domIdFor, generativeRegistry, generativeRenderers, pathFromDomId, useBrand, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot };
|
|
3131
1894
|
//# sourceMappingURL=index.js.map
|
|
3132
1895
|
//# sourceMappingURL=index.js.map
|