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