@pipelex/mthds-form 0.8.0 → 0.10.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 (66) hide show
  1. package/README.md +9 -3
  2. package/dist/{chunk-4BSBBG2T.js → chunk-4JQAJT7C.js} +3 -3
  3. package/dist/{chunk-4BSBBG2T.js.map → chunk-4JQAJT7C.js.map} +1 -1
  4. package/dist/{chunk-T4NSAGOS.js → chunk-4KGQ65TQ.js} +4 -4
  5. package/dist/{chunk-T4NSAGOS.js.map → chunk-4KGQ65TQ.js.map} +1 -1
  6. package/dist/chunk-CAKQ5VFT.js +35 -0
  7. package/dist/chunk-CAKQ5VFT.js.map +1 -0
  8. package/dist/{chunk-IIU3YK4O.js → chunk-DARLDVJM.js} +3 -3
  9. package/dist/{chunk-IIU3YK4O.js.map → chunk-DARLDVJM.js.map} +1 -1
  10. package/dist/{chunk-25I6JDIK.js → chunk-FABY3DEY.js} +2 -2
  11. package/dist/chunk-FABY3DEY.js.map +1 -0
  12. package/dist/chunk-G6BWZUGV.js +2840 -0
  13. package/dist/chunk-G6BWZUGV.js.map +1 -0
  14. package/dist/{chunk-R7B7ID25.js → chunk-IUWLOSAM.js} +4 -4
  15. package/dist/{chunk-R7B7ID25.js.map → chunk-IUWLOSAM.js.map} +1 -1
  16. package/dist/chunk-TID7ZN63.js +198 -0
  17. package/dist/chunk-TID7ZN63.js.map +1 -0
  18. package/dist/{chunk-XYQ7NXQZ.js → chunk-WYH56SOZ.js} +2 -2
  19. package/dist/chunk-WYH56SOZ.js.map +1 -0
  20. package/dist/chunk-XCO6GTEC.js +38 -0
  21. package/dist/chunk-XCO6GTEC.js.map +1 -0
  22. package/dist/{chunk-YEVVR6FE.js → chunk-Y2ND6W4W.js} +3 -3
  23. package/dist/{chunk-YEVVR6FE.js.map → chunk-Y2ND6W4W.js.map} +1 -1
  24. package/dist/{chunk-J4L32LD6.js → chunk-ZB4RYUKV.js} +5 -5
  25. package/dist/chunk-ZB4RYUKV.js.map +1 -0
  26. package/dist/core/contracts.d.ts +4 -4
  27. package/dist/core/contracts.js +1 -1
  28. package/dist/core/derive.d.ts +1 -0
  29. package/dist/core/derive.js +3 -3
  30. package/dist/core/descriptor.d.ts +13 -2
  31. package/dist/core/descriptor.js +1 -1
  32. package/dist/core/file-formats.d.ts +34 -7
  33. package/dist/core/file-formats.js +1 -1
  34. package/dist/core/gate.js +3 -3
  35. package/dist/core/gating-fields.d.ts +1 -0
  36. package/dist/core/gating-fields.js +2 -2
  37. package/dist/core/index.d.ts +3 -2
  38. package/dist/core/index.js +11 -10
  39. package/dist/core/narrow-file-formats.d.ts +50 -0
  40. package/dist/core/narrow-file-formats.js +4 -0
  41. package/dist/core/narrow-file-formats.js.map +1 -0
  42. package/dist/core/native-content.d.ts +75 -19
  43. package/dist/core/native-content.js +1 -1
  44. package/dist/core/output-form.js +2 -2
  45. package/dist/core/readiness.d.ts +1 -0
  46. package/dist/core/stuff-files.d.ts +1 -0
  47. package/dist/core/stuff-files.js +2 -2
  48. package/dist/core/values.d.ts +1 -0
  49. package/dist/core/values.js +4 -4
  50. package/dist/field-renderer-BSU2hMf6.d.ts +34 -0
  51. package/dist/generative/index.d.ts +2106 -0
  52. package/dist/generative/index.js +3093 -0
  53. package/dist/generative/index.js.map +1 -0
  54. package/dist/layout-design.mthds +452 -0
  55. package/dist/react/index.d.ts +107 -45
  56. package/dist/react/index.js +8 -2614
  57. package/dist/react/index.js.map +1 -1
  58. package/dist/styles.css +1 -1
  59. package/package.json +19 -7
  60. package/dist/chunk-25I6JDIK.js.map +0 -1
  61. package/dist/chunk-2JWRG53S.js +0 -33
  62. package/dist/chunk-2JWRG53S.js.map +0 -1
  63. package/dist/chunk-45C2MKK6.js +0 -94
  64. package/dist/chunk-45C2MKK6.js.map +0 -1
  65. package/dist/chunk-J4L32LD6.js.map +0 -1
  66. package/dist/chunk-XYQ7NXQZ.js.map +0 -1
@@ -0,0 +1,3093 @@
1
+ "use client";
2
+ import { cn, fieldControlClass, ResultField, FieldRenderer, ToggleGroup, ToggleGroupItem, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../chunk-G6BWZUGV.js';
3
+ import '../chunk-4JQAJT7C.js';
4
+ import { isNativeValueNode, readDateContent, formatDateContent, isNativeHtmlNode, isNativeDateNode, isNativeCompositeNode } from '../chunk-TID7ZN63.js';
5
+ import '../chunk-FABY3DEY.js';
6
+ import '../chunk-XCO6GTEC.js';
7
+ import '../chunk-PM55AHRO.js';
8
+ import '../chunk-GKV77RAS.js';
9
+ import { hasOwnProp } from '../chunk-V3OV2XQT.js';
10
+ import { defineSchema, defineCatalog, validateSpec, compileSpecStream } from '@json-render/core';
11
+ import { z } from 'zod';
12
+ import * as React3 from 'react';
13
+ import { defineRegistry, useStateValue, useStateStore, useBoundProp, useFieldValidation, useRepeatScope, JSONUIProvider, Renderer } from '@json-render/react';
14
+ import { jsx, jsxs } from 'react/jsx-runtime';
15
+ import { Send, Pencil, Zap, Lightbulb, Truck, Package, Briefcase, Bookmark, Flag, Shield, Info, AlertCircle, CheckCircle2, ListChecks, Layers, Tag, Phone, Mail, Paperclip, Upload, FileText, BarChart3, TrendingUp, Hash, Percent, Receipt, Coins, Banknote, Wallet, Gift, Ticket, Image, Camera, Music, Coffee, Utensils, Star, Heart, Accessibility, Baby, User, Users, Hourglass, Clock, Calendar, Moon, Sun, Leaf, Mountain, Globe, Landmark, Building2, Home, Hotel, Ship, Car, Train, Plane, Route, MapPin, Map as Map$1, Compass, Rocket, Sparkles } from 'lucide-react';
16
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
17
+
18
+ var generativeSchema = defineSchema(
19
+ (s) => ({
20
+ spec: s.object({
21
+ root: s.string(),
22
+ elements: s.record(
23
+ s.object({
24
+ type: s.ref("catalog.components"),
25
+ props: s.propsOf("catalog.components"),
26
+ children: s.array(s.string()),
27
+ slots: { ...s.record(s.array(s.string())), ...s.optional() },
28
+ visible: { ...s.any(), ...s.optional() },
29
+ repeat: { ...s.any(), ...s.optional() }
30
+ })
31
+ )
32
+ }),
33
+ catalog: s.object({
34
+ components: s.map({
35
+ props: s.zod(),
36
+ slots: s.array(s.string()),
37
+ description: s.string(),
38
+ example: s.any()
39
+ }),
40
+ actions: s.map({
41
+ params: s.zod(),
42
+ description: s.string()
43
+ })
44
+ })
45
+ }),
46
+ {
47
+ // The runtime handles these four without a registry handler; the names and
48
+ // the wording are the React schema's, so a model that has seen json-render
49
+ // before recognises them. The validator reads them to know which actions
50
+ // need no handler, and `designerCatalog()` lists them first, marked
51
+ // built-in, so the method's prompt names them beside the catalog's own.
52
+ builtInActions: [
53
+ {
54
+ name: "setState",
55
+ description: "Update a value in the state model at the given statePath. Params: { statePath: string, value: any }"
56
+ },
57
+ {
58
+ name: "pushState",
59
+ description: "Append an item to an array in state. Params: { statePath: string, value: any, clearStatePath?: string }."
60
+ },
61
+ {
62
+ name: "removeState",
63
+ description: "Remove an item from an array in state by index. Params: { statePath: string, index: number }"
64
+ },
65
+ {
66
+ name: "validateForm",
67
+ description: "Validate all registered form fields and write the result to state. Params: { statePath?: string }. Defaults to /formValidation."
68
+ }
69
+ ]
70
+ }
71
+ );
72
+ var validationCheckSchema = z.array(
73
+ z.object({
74
+ type: z.string(),
75
+ message: z.string(),
76
+ args: z.record(z.string(), z.unknown()).optional()
77
+ })
78
+ ).nullable();
79
+ var validateOnSchema = z.enum(["change", "blur", "submit"]).nullable();
80
+ var shadcnComponentDefinitions = {
81
+ // ── Layout ────────────────────────────────────────────────────────────────
82
+ Card: {
83
+ props: z.object({
84
+ title: z.string().nullable(),
85
+ description: z.string().nullable(),
86
+ maxWidth: z.enum(["sm", "md", "lg", "full"]).nullable(),
87
+ centered: z.boolean().nullable(),
88
+ className: z.string().nullable().describe("Additional CSS classes")
89
+ }),
90
+ slots: ["default"],
91
+ description: "Container card for content sections. Use for forms/content boxes, NOT for page headers.",
92
+ example: { title: "Overview", description: "Your account summary" }
93
+ },
94
+ Stack: {
95
+ props: z.object({
96
+ direction: z.enum(["horizontal", "vertical"]).nullable(),
97
+ gap: z.enum(["none", "sm", "md", "lg", "xl"]).nullable(),
98
+ align: z.enum(["start", "center", "end", "stretch"]).nullable(),
99
+ justify: z.enum(["start", "center", "end", "between", "around"]).nullable(),
100
+ className: z.string().nullable().describe("Additional CSS classes")
101
+ }),
102
+ slots: ["default"],
103
+ description: "Flex container for layouts",
104
+ example: { direction: "vertical", gap: "md" }
105
+ },
106
+ Grid: {
107
+ props: z.object({
108
+ columns: z.number().nullable(),
109
+ gap: z.enum(["sm", "md", "lg", "xl"]).nullable(),
110
+ className: z.string().nullable().describe("Additional CSS classes")
111
+ }),
112
+ slots: ["default"],
113
+ description: "Grid layout (1-6 columns)",
114
+ example: { columns: 3, gap: "md" }
115
+ },
116
+ Separator: {
117
+ props: z.object({
118
+ orientation: z.enum(["horizontal", "vertical"]).nullable()
119
+ }),
120
+ description: "Visual separator line"
121
+ },
122
+ Collapsible: {
123
+ props: z.object({
124
+ title: z.string(),
125
+ defaultOpen: z.boolean().nullable()
126
+ }),
127
+ slots: ["default"],
128
+ description: "Collapsible section with trigger. Children render inside."
129
+ },
130
+ // ── Content ───────────────────────────────────────────────────────────────
131
+ Heading: {
132
+ props: z.object({
133
+ text: z.string(),
134
+ level: z.enum(["h1", "h2", "h3", "h4"]).nullable()
135
+ }),
136
+ description: "Heading text (h1-h4)",
137
+ example: { text: "Welcome", level: "h1" }
138
+ },
139
+ Text: {
140
+ props: z.object({
141
+ text: z.string(),
142
+ variant: z.enum(["body", "caption", "muted", "lead", "code"]).nullable()
143
+ }),
144
+ description: "Paragraph text",
145
+ example: { text: "Hello, world!" }
146
+ },
147
+ Avatar: {
148
+ props: z.object({
149
+ src: z.string().nullable(),
150
+ name: z.string(),
151
+ size: z.enum(["sm", "md", "lg"]).nullable()
152
+ }),
153
+ description: "User avatar with fallback initials",
154
+ example: { name: "Jane Doe", size: "md" }
155
+ },
156
+ Badge: {
157
+ props: z.object({
158
+ text: z.string(),
159
+ variant: z.enum(["default", "secondary", "destructive", "outline"]).nullable()
160
+ }),
161
+ description: "Status badge",
162
+ example: { text: "Active", variant: "default" }
163
+ },
164
+ Alert: {
165
+ props: z.object({
166
+ title: z.string(),
167
+ message: z.string().nullable(),
168
+ type: z.enum(["info", "success", "warning", "error"]).nullable()
169
+ }),
170
+ description: "Alert banner",
171
+ example: {
172
+ title: "Note",
173
+ message: "Your changes have been saved.",
174
+ type: "success"
175
+ }
176
+ },
177
+ Progress: {
178
+ props: z.object({
179
+ value: z.number(),
180
+ max: z.number().nullable(),
181
+ label: z.string().nullable()
182
+ }),
183
+ description: "Progress bar (value 0-100)",
184
+ example: { value: 65, max: 100, label: "Upload progress" }
185
+ },
186
+ // ── Inputs ────────────────────────────────────────────────────────────────
187
+ Input: {
188
+ props: z.object({
189
+ label: z.string(),
190
+ name: z.string(),
191
+ type: z.enum(["text", "email", "password", "number"]).nullable(),
192
+ placeholder: z.string().nullable(),
193
+ value: z.string().nullable(),
194
+ checks: validationCheckSchema,
195
+ validateOn: validateOnSchema
196
+ }),
197
+ events: ["submit", "focus", "blur"],
198
+ 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).",
199
+ example: {
200
+ label: "Email",
201
+ name: "email",
202
+ type: "email",
203
+ placeholder: "you@example.com"
204
+ }
205
+ },
206
+ Textarea: {
207
+ props: z.object({
208
+ label: z.string(),
209
+ name: z.string(),
210
+ placeholder: z.string().nullable(),
211
+ rows: z.number().nullable(),
212
+ value: z.string().nullable(),
213
+ checks: validationCheckSchema,
214
+ validateOn: validateOnSchema
215
+ }),
216
+ description: "Multi-line text input. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: blur)."
217
+ },
218
+ Select: {
219
+ props: z.object({
220
+ label: z.string(),
221
+ name: z.string(),
222
+ options: z.array(z.string().min(1)),
223
+ placeholder: z.string().nullable(),
224
+ value: z.string().nullable(),
225
+ checks: validationCheckSchema,
226
+ validateOn: validateOnSchema
227
+ }),
228
+ events: ["change"],
229
+ description: "Dropdown select input. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: change)."
230
+ },
231
+ Radio: {
232
+ props: z.object({
233
+ label: z.string(),
234
+ name: z.string(),
235
+ options: z.array(z.string().min(1)),
236
+ value: z.string().nullable(),
237
+ checks: validationCheckSchema,
238
+ validateOn: validateOnSchema
239
+ }),
240
+ events: ["change"],
241
+ description: "Radio button group. Use { $bindState } on value for binding. Use checks for validation. validateOn controls timing (default: change)."
242
+ },
243
+ Checkbox: {
244
+ props: z.object({
245
+ label: z.string(),
246
+ name: z.string(),
247
+ checked: z.boolean().nullable(),
248
+ checks: validationCheckSchema,
249
+ validateOn: validateOnSchema
250
+ }),
251
+ events: ["change"],
252
+ description: "Checkbox input. Use { $bindState } on checked for binding. Use checks for validation. validateOn controls timing (default: change)."
253
+ },
254
+ Switch: {
255
+ props: z.object({
256
+ label: z.string(),
257
+ name: z.string(),
258
+ checked: z.boolean().nullable(),
259
+ checks: validationCheckSchema,
260
+ validateOn: validateOnSchema
261
+ }),
262
+ events: ["change"],
263
+ description: "Toggle switch. Use { $bindState } on checked for binding. Use checks for validation. validateOn controls timing (default: change)."
264
+ },
265
+ // ── Actions ───────────────────────────────────────────────────────────────
266
+ Button: {
267
+ props: z.object({
268
+ label: z.string(),
269
+ variant: z.enum(["primary", "secondary", "danger"]).nullable(),
270
+ disabled: z.boolean().nullable()
271
+ }),
272
+ events: ["press"],
273
+ description: "Clickable button. Bind on.press for handler.",
274
+ example: { label: "Submit", variant: "primary" }
275
+ }
276
+ };
277
+
278
+ // src/generative/components.ts
279
+ var shadcn = shadcnComponentDefinitions;
280
+ var PICKED_SHADCN = [
281
+ "Card",
282
+ "Stack",
283
+ "Grid",
284
+ "Separator",
285
+ "Heading",
286
+ "Text",
287
+ "Badge",
288
+ "Alert",
289
+ "Collapsible",
290
+ "Progress",
291
+ "Avatar",
292
+ "Input",
293
+ "Textarea",
294
+ "Select",
295
+ "Radio",
296
+ "Checkbox",
297
+ "Switch",
298
+ "Button"
299
+ ];
300
+ var CUSTOM_COMPONENTS = [
301
+ "Split",
302
+ "Tabs",
303
+ "Steps",
304
+ "Icon",
305
+ "Segmented",
306
+ "NumberInput",
307
+ "MthdsField",
308
+ "MthdsResult",
309
+ "DataTable",
310
+ "Metric"
311
+ ];
312
+ var METRIC_FORMATS = ["plain", "integer", "decimal", "compact"];
313
+ var ICON_NAMES = [
314
+ "Sparkles",
315
+ "Rocket",
316
+ "Compass",
317
+ "Map",
318
+ "MapPin",
319
+ "Route",
320
+ "Plane",
321
+ "Train",
322
+ "Car",
323
+ "Ship",
324
+ "Hotel",
325
+ "Home",
326
+ "Building2",
327
+ "Landmark",
328
+ "Globe",
329
+ "Mountain",
330
+ "Leaf",
331
+ "Sun",
332
+ "Moon",
333
+ "Calendar",
334
+ "Clock",
335
+ "Hourglass",
336
+ "Users",
337
+ "User",
338
+ "Baby",
339
+ "Accessibility",
340
+ "Heart",
341
+ "Star",
342
+ "Utensils",
343
+ "Coffee",
344
+ "Music",
345
+ "Camera",
346
+ "Image",
347
+ "Ticket",
348
+ "Gift",
349
+ "Wallet",
350
+ "Banknote",
351
+ "Coins",
352
+ "Receipt",
353
+ "Percent",
354
+ "Hash",
355
+ "TrendingUp",
356
+ "BarChart3",
357
+ "FileText",
358
+ "Upload",
359
+ "Paperclip",
360
+ "Mail",
361
+ "Phone",
362
+ "Tag",
363
+ "Layers",
364
+ "ListChecks",
365
+ "CheckCircle2",
366
+ "AlertCircle",
367
+ "Info",
368
+ "Shield",
369
+ "Flag",
370
+ "Bookmark",
371
+ "Briefcase",
372
+ "Package",
373
+ "Truck",
374
+ "Lightbulb",
375
+ "Zap",
376
+ "Pencil",
377
+ "Send"
378
+ ];
379
+ var components = {
380
+ // ── Layout (shadcn) ────────────────────────────────────────────────────
381
+ Card: {
382
+ ...shadcn.Card,
383
+ props: shadcn.Card.props.omit({ className: true, maxWidth: true, centered: true }),
384
+ 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.'
385
+ },
386
+ Stack: { ...shadcn.Stack, props: shadcn.Stack.props.omit({ className: true }) },
387
+ Grid: { ...shadcn.Grid, props: shadcn.Grid.props.omit({ className: true }) },
388
+ Separator: shadcn.Separator,
389
+ Collapsible: shadcn.Collapsible,
390
+ // ── Content (shadcn) ───────────────────────────────────────────────────
391
+ Heading: shadcn.Heading,
392
+ Text: shadcn.Text,
393
+ Badge: shadcn.Badge,
394
+ Alert: shadcn.Alert,
395
+ Progress: shadcn.Progress,
396
+ Avatar: {
397
+ ...shadcn.Avatar,
398
+ 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".`
399
+ },
400
+ // ── Inputs (shadcn) ────────────────────────────────────────────────────
401
+ Input: shadcn.Input,
402
+ Textarea: shadcn.Textarea,
403
+ Select: shadcn.Select,
404
+ Radio: shadcn.Radio,
405
+ Checkbox: shadcn.Checkbox,
406
+ Switch: shadcn.Switch,
407
+ Button: shadcn.Button,
408
+ // ── Layout (ours) ──────────────────────────────────────────────────────
409
+ Split: {
410
+ props: z.object({
411
+ ratio: z.enum(["1:1", "1:2", "2:1"]).nullable(),
412
+ gap: z.enum(["md", "lg", "xl"]).nullable()
413
+ }),
414
+ slots: ["default"],
415
+ 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.',
416
+ example: { ratio: "1:2", gap: "lg" }
417
+ },
418
+ Tabs: {
419
+ props: z.object({
420
+ tabs: z.array(z.object({ label: z.string(), value: z.string() })).min(2)
421
+ }),
422
+ slots: ["default"],
423
+ 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.",
424
+ example: {
425
+ tabs: [
426
+ { label: "The trip", value: "trip" },
427
+ { label: "Who is going", value: "people" }
428
+ ]
429
+ }
430
+ },
431
+ Steps: {
432
+ props: z.object({
433
+ steps: z.array(z.string()).min(2),
434
+ nextLabel: z.string().nullable(),
435
+ backLabel: z.string().nullable()
436
+ }),
437
+ slots: ["default"],
438
+ 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.",
439
+ example: { steps: ["Where", "Who", "How"], nextLabel: "Continue" }
440
+ },
441
+ Icon: {
442
+ props: z.object({
443
+ name: z.enum(ICON_NAMES),
444
+ size: z.enum(["sm", "md", "lg"]).nullable()
445
+ }),
446
+ slots: [],
447
+ 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.",
448
+ example: { name: "Plane", size: "md" }
449
+ },
450
+ // ── Inputs (ours) ──────────────────────────────────────────────────────
451
+ Segmented: {
452
+ props: z.object({
453
+ label: z.string(),
454
+ name: z.string(),
455
+ options: z.array(z.string().min(1)).min(2).max(6),
456
+ value: z.string().nullable()
457
+ }),
458
+ slots: [],
459
+ 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/..." }.`,
460
+ example: {
461
+ label: "Pace",
462
+ name: "pace",
463
+ options: ["slow", "balanced", "packed"],
464
+ value: { $bindState: "/inputs/request/pace" }
465
+ }
466
+ },
467
+ NumberInput: {
468
+ props: z.object({
469
+ label: z.string(),
470
+ name: z.string(),
471
+ value: z.number().nullable(),
472
+ placeholder: z.string().nullable(),
473
+ unit: z.string().nullable(),
474
+ min: z.number().nullable(),
475
+ max: z.number().nullable(),
476
+ step: z.number().nullable()
477
+ }),
478
+ slots: [],
479
+ 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.',
480
+ example: {
481
+ label: "Budget",
482
+ name: "budget",
483
+ value: { $bindState: "/inputs/request/budget" },
484
+ placeholder: "2500"
485
+ }
486
+ },
487
+ // ── The escape hatches and the bound equivalents (ours) ────────────────
488
+ MthdsField: {
489
+ props: z.object({
490
+ path: z.string()
491
+ }),
492
+ slots: [],
493
+ description: `The kernel's own control for ONE input, bound two-way at "path" (a /inputs path from the brief). Use it for every path the brief marks as delegated - a file, a date, a list, a structure you would rather not lay out - and for any scalar you would rather not style. It renders its own label and description. Inside a repeat, "path" is the item's field name relative to the item ("lines"), never an $item expression.`,
494
+ example: { path: "/inputs/source" }
495
+ },
496
+ MthdsResult: {
497
+ props: z.object({
498
+ path: z.string(),
499
+ hideLabel: z.boolean().nullable()
500
+ }),
501
+ slots: [],
502
+ 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.`,
503
+ example: { path: "/result/issued_on" }
504
+ },
505
+ DataTable: {
506
+ props: z.object({
507
+ rows: z.any(),
508
+ columns: z.array(z.object({ path: z.string(), label: z.string() })),
509
+ caption: z.string().nullable()
510
+ }),
511
+ slots: [],
512
+ description: 'A table over a list of structures. "rows" MUST be { "$state": "/path/to/the/list" } (never inline rows); each column names a field of one item by its relative path ("label", "unit_price") and the header to show for it.',
513
+ example: {
514
+ rows: { $state: "/result/lines" },
515
+ columns: [
516
+ { path: "label", label: "Item" },
517
+ { path: "quantity", label: "Qty" }
518
+ ]
519
+ }
520
+ },
521
+ Metric: {
522
+ props: z.object({
523
+ label: z.string(),
524
+ value: z.any(),
525
+ unit: z.string().nullable(),
526
+ format: z.enum(METRIC_FORMATS).nullable()
527
+ }),
528
+ slots: [],
529
+ 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.',
530
+ example: { label: "Total", value: { $state: "/result/total" }, unit: "EUR", format: "decimal" }
531
+ }
532
+ };
533
+ var actions = {
534
+ run: {
535
+ params: z.object({}),
536
+ description: "Start the run with the current /inputs. The host handles it; an input page binds it to its one Button after validateForm."
537
+ }
538
+ };
539
+ defineCatalog(generativeSchema, { components, actions });
540
+ var generativeComponents = components;
541
+ var generativeActions = actions;
542
+
543
+ // src/generative/catalog.ts
544
+ var PRODUCT_COMPONENTS = [
545
+ "AppBar",
546
+ "Hero",
547
+ "Workspace",
548
+ "Section",
549
+ "Rail",
550
+ "SummaryRow",
551
+ "Cta",
552
+ "Footer"
553
+ ];
554
+ var product = {
555
+ AppBar: {
556
+ props: z.object({
557
+ app: z.string(),
558
+ links: z.array(z.string()).nullable(),
559
+ tag: z.string().nullable()
560
+ }),
561
+ slots: [],
562
+ 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.",
563
+ example: { app: "Trip planner", links: ["Methods", "Runs"], tag: "plan_trip" }
564
+ },
565
+ Hero: {
566
+ props: z.object({
567
+ headline: z.string(),
568
+ lede: z.string().nullable(),
569
+ eyebrow: z.string().nullable()
570
+ }),
571
+ slots: [],
572
+ 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.",
573
+ example: { headline: "Plan a trip worth taking.", lede: "Tell us where and who is coming." }
574
+ },
575
+ Workspace: {
576
+ props: z.object({ rail: z.enum(["right", "left"]).nullable() }),
577
+ slots: ["default"],
578
+ 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.',
579
+ example: { rail: "right" }
580
+ },
581
+ Section: {
582
+ props: z.object({
583
+ number: z.string().nullable(),
584
+ title: z.string(),
585
+ lede: z.string().nullable()
586
+ }),
587
+ slots: ["default"],
588
+ 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.",
589
+ example: { number: "01", title: "Where and when" }
590
+ },
591
+ Rail: {
592
+ props: z.object({ title: z.string() }),
593
+ slots: ["default"],
594
+ 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.",
595
+ example: { title: "Your trip" }
596
+ },
597
+ SummaryRow: {
598
+ props: z.object({
599
+ label: z.string(),
600
+ value: z.any().nullable(),
601
+ detail: z.any().nullable(),
602
+ separator: z.string().nullable(),
603
+ placeholder: z.string().nullable()
604
+ }),
605
+ slots: [],
606
+ 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.',
607
+ example: {
608
+ label: "Budget",
609
+ value: { $state: "/inputs/request/budget" },
610
+ detail: { $state: "/inputs/request/currency" }
611
+ }
612
+ },
613
+ Cta: {
614
+ props: z.object({ label: z.string(), hint: z.string().nullable() }),
615
+ slots: [],
616
+ events: ["press"],
617
+ 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.",
618
+ example: { label: "Plan my trip", hint: "Nothing runs until the request is complete." }
619
+ },
620
+ Footer: {
621
+ props: z.object({ text: z.string(), tag: z.string().nullable() }),
622
+ slots: [],
623
+ description: "A closing line, muted, with an optional mono tag at the right. It renders as the page's contentinfo, so at most one.",
624
+ example: { text: "Runs on Pipelex.", tag: "MTHDS" }
625
+ }
626
+ };
627
+ var COMPONENT_RENDERINGS = {
628
+ Hero: { heading: { level: 1 } },
629
+ Section: { heading: { level: 2 } },
630
+ Rail: { heading: { level: 2 } },
631
+ Card: { heading: { level: 3, when: "title" } },
632
+ AppBar: { once: "the page's banner" },
633
+ Footer: { once: "the page's contentinfo" },
634
+ Split: { children: { count: 2, roles: "left, right" } },
635
+ Workspace: { children: { count: 2, roles: "work, rail" } },
636
+ Tabs: { panels: { prop: "tabs", noun: "tab" } },
637
+ Steps: { panels: { prop: "steps", noun: "step" } }
638
+ };
639
+ var catalog = Object.assign(
640
+ defineCatalog(generativeSchema, {
641
+ components: { ...generativeComponents, ...product },
642
+ actions: generativeActions
643
+ }),
644
+ { renders: COMPONENT_RENDERINGS }
645
+ );
646
+ var COMPONENT_NAMES = [
647
+ ...PICKED_SHADCN,
648
+ ...CUSTOM_COMPONENTS,
649
+ ...PRODUCT_COMPONENTS
650
+ ];
651
+
652
+ // src/generative/props-signature.ts
653
+ function definitionOf(schema) {
654
+ return schema._zod.def;
655
+ }
656
+ function propsSignature(schema) {
657
+ const def = definitionOf(schema);
658
+ switch (def.type) {
659
+ case "string":
660
+ return "string";
661
+ case "number":
662
+ return "number";
663
+ case "boolean":
664
+ return "boolean";
665
+ case "literal":
666
+ return JSON.stringify(def.values?.[0]);
667
+ case "enum":
668
+ return Object.values(def.entries ?? {}).map((value) => `"${String(value)}"`).join(" | ");
669
+ case "array":
670
+ return `Array<${def.element ? propsSignature(def.element) : "unknown"}>`;
671
+ case "object": {
672
+ const props = Object.entries(def.shape ?? {}).map(([key, value]) => {
673
+ const inner = definitionOf(value).type;
674
+ const optional = inner === "optional" || inner === "nullable";
675
+ return `${key}${optional ? "?" : ""}: ${propsSignature(value)}`;
676
+ });
677
+ return `{ ${props.join(", ")} }`;
678
+ }
679
+ case "optional":
680
+ case "nullable":
681
+ case "default":
682
+ return def.innerType ? propsSignature(def.innerType) : "unknown";
683
+ case "union":
684
+ return def.options ? def.options.map((option) => propsSignature(option)).join(" | ") : "unknown";
685
+ case "record": {
686
+ const key = def.keyType ? propsSignature(def.keyType) : "string";
687
+ const value = def.valueType ? propsSignature(def.valueType) : "unknown";
688
+ return `Record<${key}, ${value}>`;
689
+ }
690
+ default:
691
+ return "unknown";
692
+ }
693
+ }
694
+
695
+ // src/generative/designer-catalog.ts
696
+ var DESIGNER_CATALOG_CONCEPT = "generative.Catalog";
697
+ function designerCatalog() {
698
+ const definitions = catalog.data.components;
699
+ const components3 = COMPONENT_NAMES.map((name) => {
700
+ const definition = definitions[name];
701
+ if (!definition) throw new Error(`the catalog defines no component named '${name}'`);
702
+ const slots = definition.slots ?? [];
703
+ return {
704
+ name,
705
+ props: propsSignature(definition.props),
706
+ description: definition.description,
707
+ accepts_children: slots.includes("default"),
708
+ slots: slots.filter((slot) => slot !== "default"),
709
+ events: [...definition.events ?? []]
710
+ };
711
+ });
712
+ const builtIn = (generativeSchema.builtInActions ?? []).map((action) => ({
713
+ name: action.name,
714
+ description: action.description,
715
+ built_in: true
716
+ }));
717
+ const own = Object.entries(catalog.data.actions).map(
718
+ ([name, action]) => ({
719
+ name,
720
+ description: action.description,
721
+ built_in: false
722
+ })
723
+ );
724
+ return { components: components3, actions: [...builtIn, ...own] };
725
+ }
726
+
727
+ // src/generative/prompt-hash.ts
728
+ var PROMPT_HASH = "2b2325fd1231";
729
+
730
+ // src/generative/paths.ts
731
+ var INPUTS_ROOT = "/inputs";
732
+ var RESULT_ROOT = "/result";
733
+ function joinPath(root, ...segments) {
734
+ return segments.reduce((path, segment) => `${path}/${escapeSegment(segment)}`, root);
735
+ }
736
+ function escapeSegment(segment) {
737
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
738
+ }
739
+ function unescapeSegment(segment) {
740
+ return segment.replace(/~1/g, "/").replace(/~0/g, "~");
741
+ }
742
+ function segmentsUnder(root, path) {
743
+ if (path === root) return [];
744
+ if (!path.startsWith(`${root}/`)) return void 0;
745
+ return path.slice(root.length + 1).split("/").map(unescapeSegment);
746
+ }
747
+ function fieldAtSegments(fields, segments) {
748
+ const [head, ...rest] = segments;
749
+ if (head === void 0) return void 0;
750
+ const field = fields.find((candidate) => candidate.name === head);
751
+ if (!field) return void 0;
752
+ return rest.length === 0 ? field : descend(field, rest);
753
+ }
754
+ function descend(field, segments) {
755
+ const [head, ...rest] = segments;
756
+ if (head === void 0) return field;
757
+ if (field.kind === "object") return fieldAtSegments(field.fields, segments);
758
+ if (field.kind === "list" && /^\d+$/.test(head)) return descend(field.item, rest);
759
+ return void 0;
760
+ }
761
+ function inputFieldAtPath(fields, path) {
762
+ const segments = segmentsUnder(INPUTS_ROOT, path);
763
+ return segments && segments.length > 0 ? fieldAtSegments(fields, segments) : void 0;
764
+ }
765
+ function resultFieldAtPath(field, path) {
766
+ const segments = segmentsUnder(RESULT_ROOT, path);
767
+ if (!segments) return void 0;
768
+ return segments.length === 0 ? field : descend(field, segments);
769
+ }
770
+ function parentMapOf(spec) {
771
+ const parents = /* @__PURE__ */ new Map();
772
+ for (const [parentKey, element] of Object.entries(spec.elements)) {
773
+ for (const child of element.children ?? []) parents.set(child, parentKey);
774
+ }
775
+ return parents;
776
+ }
777
+ function repeatBasePathOf(spec, key, parents = parentMapOf(spec)) {
778
+ const chain = [];
779
+ const seen = /* @__PURE__ */ new Set();
780
+ let current = key;
781
+ while (current !== void 0 && !seen.has(current)) {
782
+ seen.add(current);
783
+ chain.unshift(current);
784
+ current = parents.get(current);
785
+ }
786
+ let base;
787
+ for (const elementKey of chain) {
788
+ const repeat = spec.elements[elementKey]?.repeat;
789
+ if (!repeat) continue;
790
+ const statePath = repeat.statePath;
791
+ if (typeof statePath === "string") {
792
+ base = `${statePath}/0`;
793
+ continue;
794
+ }
795
+ const item = statePath?.$item;
796
+ if (base === void 0 || typeof item !== "string") return void 0;
797
+ base = `${joinPath(base, item)}/0`;
798
+ }
799
+ return base;
800
+ }
801
+ function absoluteHatchPath(spec, key, path, parents) {
802
+ if (path.startsWith("/")) return path;
803
+ const base = repeatBasePathOf(spec, key, parents);
804
+ return base ? `${base}/${path}` : void 0;
805
+ }
806
+ function repeatListPathOf(spec, key, parents = parentMapOf(spec)) {
807
+ const statePath = spec.elements[key]?.repeat?.statePath;
808
+ if (typeof statePath === "string") return statePath;
809
+ const item = statePath?.$item;
810
+ const parent = parents.get(key);
811
+ const outer = parent === void 0 ? void 0 : repeatBasePathOf(spec, parent, parents);
812
+ return outer !== void 0 && typeof item === "string" ? joinPath(outer, item) : void 0;
813
+ }
814
+
815
+ // src/generative/brief.ts
816
+ var DESIGNER_BRIEF_CONCEPT = "generative.Brief";
817
+ var RUN_COMPONENT = "Cta";
818
+ function isDelegatedInput(field) {
819
+ return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "list" || field.kind === "unknown" || field.kind === "enum" && field.options.includes("");
820
+ }
821
+ function isDelegatedResult(field) {
822
+ if (isNativeValueNode(field)) return true;
823
+ if (field.kind === "list" && isNativeValueNode(field.item)) return true;
824
+ return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "prose" || field.kind === "unknown";
825
+ }
826
+ function kindLabel(field) {
827
+ if (isNativeHtmlNode(field)) return "markup (native.Html)";
828
+ if (isNativeDateNode(field)) return "date (native.Date)";
829
+ if (isNativeCompositeNode(field)) return "composite (native.Composite)";
830
+ switch (field.kind) {
831
+ case "text":
832
+ return "text";
833
+ case "prose":
834
+ return "prose (markdown)";
835
+ case "number":
836
+ return field.integer ? "integer" : "number";
837
+ case "boolean":
838
+ return "boolean";
839
+ case "enum":
840
+ return `choice of ${field.options.map((option) => JSON.stringify(option)).join(" | ")}`;
841
+ case "date":
842
+ return field.datetime ? "date with time" : "date";
843
+ case "document":
844
+ return "document (a file)";
845
+ case "image":
846
+ return "image (a file)";
847
+ case "object":
848
+ return `structure${field.conceptRef ? ` ${field.conceptRef}` : ""}`;
849
+ case "list":
850
+ return `list of ${kindLabel(field.item)}`;
851
+ case "unknown":
852
+ return "unknown";
853
+ default:
854
+ return field;
855
+ }
856
+ }
857
+ function constraints(field) {
858
+ const notes = [];
859
+ if (field.kind === "number") {
860
+ if (field.min !== void 0) notes.push(`min ${field.min}`);
861
+ if (field.max !== void 0) notes.push(`max ${field.max}`);
862
+ }
863
+ if (field.kind === "text" || field.kind === "prose") {
864
+ if (field.minLength !== void 0) notes.push(`at least ${field.minLength} characters`);
865
+ if (field.maxLength !== void 0) notes.push(`at most ${field.maxLength} characters`);
866
+ if (field.format) notes.push(`format ${field.format}`);
867
+ }
868
+ if (field.kind === "list") {
869
+ if (field.itemCount !== void 0) notes.push(`at least ${field.itemCount} items`);
870
+ if (field.maxItemCount !== void 0) notes.push(`at most ${field.maxItemCount} items`);
871
+ }
872
+ if (field.defaultValue !== void 0) notes.push(`default ${JSON.stringify(field.defaultValue)}`);
873
+ if (field.examples && field.examples.length > 0) {
874
+ notes.push(`examples ${field.examples.map((example) => JSON.stringify(example)).join(", ")}`);
875
+ }
876
+ if (field.hints && Object.keys(field.hints).length > 0) {
877
+ notes.push(
878
+ `hints ${Object.entries(field.hints).map(([key, value]) => `${key}=${value}`).join(", ")}`
879
+ );
880
+ }
881
+ return notes;
882
+ }
883
+ function entryOf(field, path, depth, side, relative, seeded) {
884
+ const notes = constraints(field);
885
+ return {
886
+ depth,
887
+ path,
888
+ kind: kindLabel(field),
889
+ name: field.name,
890
+ title: field.title && field.title !== field.name ? field.title : void 0,
891
+ description: field.description,
892
+ required: side === "input" ? field.required : void 0,
893
+ gating: side === "input" && field.gating ? true : void 0,
894
+ notes: notes.length > 0 ? notes : void 0,
895
+ default: seeded || field.defaultValue === void 0 ? void 0 : JSON.stringify(field.defaultValue),
896
+ delegated: side === "input" ? isDelegatedInput(field) : isDelegatedResult(field),
897
+ relative: relative ? true : void 0
898
+ };
899
+ }
900
+ function describe(field, path, depth, side, entries, seeded = false) {
901
+ const entry = entryOf(field, path, depth, side, false, seeded);
902
+ entries.push(entry);
903
+ if (entry.delegated) return;
904
+ if (field.kind === "object") {
905
+ const seededBelow = seeded || field.defaultValue !== void 0;
906
+ for (const child of field.fields) {
907
+ describe(child, joinPath(path, child.name), depth + 1, side, entries, seededBelow);
908
+ }
909
+ }
910
+ if (field.kind === "list" && side === "result") {
911
+ const item = field.item;
912
+ entry.item_kind = kindLabel(item);
913
+ entry.item_description = item.description;
914
+ if (item.kind === "object" && !isDelegatedResult(item)) {
915
+ entry.item_laid_out = true;
916
+ for (const child of item.fields) {
917
+ describeRelative(child, child.name, depth + 2, entries);
918
+ }
919
+ }
920
+ }
921
+ }
922
+ function describeRelative(field, relativePath, depth, entries) {
923
+ const entry = entryOf(field, relativePath, depth, "result", true, false);
924
+ entries.push(entry);
925
+ if (entry.delegated) return;
926
+ if (field.kind === "object") {
927
+ for (const child of field.fields) {
928
+ describeRelative(child, joinPath(relativePath, child.name), depth + 1, entries);
929
+ }
930
+ }
931
+ if (field.kind === "list") {
932
+ const item = field.item;
933
+ entry.item_kind = kindLabel(item);
934
+ entry.item_description = item.description;
935
+ if (item.kind === "object" && !isDelegatedResult(item)) {
936
+ entry.item_laid_out = true;
937
+ for (const child of item.fields) {
938
+ describeRelative(child, joinPath(relativePath, "<i>", child.name), depth + 2, entries);
939
+ }
940
+ }
941
+ }
942
+ }
943
+ function inputBrief(subject, fields) {
944
+ const paths = [];
945
+ for (const field of fields) describe(field, joinPath(INPUTS_ROOT, field.name), 0, "input", paths);
946
+ return {
947
+ side: "input",
948
+ pipe_ref: subject.pipeRef,
949
+ description: subject.description,
950
+ name: subject.name,
951
+ paths,
952
+ run_control: RUN_COMPONENT
953
+ };
954
+ }
955
+ function resultBrief(subject, field, state) {
956
+ const paths = [];
957
+ if (field.kind === "object" && !isDelegatedResult(field)) {
958
+ paths.push({
959
+ depth: 0,
960
+ path: RESULT_ROOT,
961
+ kind: kindLabel(field),
962
+ description: field.description,
963
+ delegated: false
964
+ });
965
+ for (const child of field.fields) {
966
+ describe(child, joinPath(RESULT_ROOT, child.name), 1, "result", paths);
967
+ }
968
+ } else {
969
+ describe(field, RESULT_ROOT, 0, "result", paths);
970
+ }
971
+ return {
972
+ side: "result",
973
+ pipe_ref: subject.pipeRef,
974
+ description: subject.description,
975
+ paths,
976
+ sample_state: JSON.stringify(state, null, 2)
977
+ };
978
+ }
979
+ var EXPRESSION_KEYS = [
980
+ "$state",
981
+ "$item",
982
+ "$index",
983
+ "$bindState",
984
+ "$bindItem",
985
+ "$cond",
986
+ "$computed",
987
+ "$template"
988
+ ];
989
+ var HATCHES = /* @__PURE__ */ new Set(["MthdsField", "MthdsResult"]);
990
+ function isExpression(value) {
991
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).some((key) => EXPRESSION_KEYS.includes(key));
992
+ }
993
+ function isClosedVocabulary(schema) {
994
+ let current = schema;
995
+ for (let depth = 0; depth < 8; depth += 1) {
996
+ const def = current.def;
997
+ if (!def) return false;
998
+ if (def.type === "enum" || def.type === "literal") return true;
999
+ if (def.innerType === void 0) return false;
1000
+ current = def.innerType;
1001
+ }
1002
+ return false;
1003
+ }
1004
+ function definitionOf2(catalog2, type) {
1005
+ const components3 = catalog2.data.components;
1006
+ return hasOwnProp(components3, type) ? components3[type] : void 0;
1007
+ }
1008
+ function propsSchemaOf(catalog2, type) {
1009
+ const props = definitionOf2(catalog2, type)?.props;
1010
+ return props && typeof props === "object" && "shape" in props ? props : void 0;
1011
+ }
1012
+ function eventsOf(catalog2, type) {
1013
+ const definition = definitionOf2(catalog2, type);
1014
+ if (!definition) return void 0;
1015
+ return Array.isArray(definition.events) ? definition.events.filter((event) => typeof event === "string") : [];
1016
+ }
1017
+ var MAX_ELEMENT_DEPTH = 512;
1018
+ function childKeysOf(spec, key) {
1019
+ const element = spec.elements[key];
1020
+ if (!element) return [];
1021
+ const children = Array.isArray(element.children) ? element.children : [];
1022
+ const slots = typeof element.slots === "object" && element.slots !== null ? Object.values(element.slots).flatMap(
1023
+ (slot) => Array.isArray(slot) ? slot : []
1024
+ ) : [];
1025
+ return [...children, ...slots].filter((child) => typeof child === "string");
1026
+ }
1027
+ function deepestChain(spec) {
1028
+ const below = /* @__PURE__ */ new Map();
1029
+ const onPath = /* @__PURE__ */ new Set();
1030
+ let deepest = 0;
1031
+ for (const start of Object.keys(spec.elements)) {
1032
+ if (below.has(start)) continue;
1033
+ const stack = [start];
1034
+ while (stack.length > 0) {
1035
+ const key = stack[stack.length - 1];
1036
+ if (below.has(key)) {
1037
+ onPath.delete(key);
1038
+ stack.pop();
1039
+ continue;
1040
+ }
1041
+ const children = childKeysOf(spec, key).filter((child) => !onPath.has(child));
1042
+ const pending = children.filter((child) => !below.has(child));
1043
+ if (pending.length > 0) {
1044
+ onPath.add(key);
1045
+ stack.push(...pending);
1046
+ continue;
1047
+ }
1048
+ below.set(
1049
+ key,
1050
+ children.reduce((tallest, child) => Math.max(tallest, below.get(child) ?? 0), 0) + 1
1051
+ );
1052
+ onPath.delete(key);
1053
+ stack.pop();
1054
+ }
1055
+ deepest = Math.max(deepest, below.get(start) ?? 0);
1056
+ }
1057
+ return deepest;
1058
+ }
1059
+ function validateAgainstCatalog(spec, catalog2 = catalog) {
1060
+ try {
1061
+ return checkAgainstCatalog(spec, catalog2);
1062
+ } catch (error) {
1063
+ return {
1064
+ ok: false,
1065
+ problems: [{ message: `the layout is not a well-formed spec: ${String(error)}` }]
1066
+ };
1067
+ }
1068
+ }
1069
+ function checkAgainstCatalog(spec, catalog2) {
1070
+ const problems = [];
1071
+ const depth = deepestChain(spec);
1072
+ if (depth > MAX_ELEMENT_DEPTH) {
1073
+ return {
1074
+ ok: false,
1075
+ problems: [
1076
+ {
1077
+ message: `the element tree is ${depth} deep; this entry renders at most ${MAX_ELEMENT_DEPTH}.`
1078
+ }
1079
+ ]
1080
+ };
1081
+ }
1082
+ const structure = validateSpec(spec, { checkOrphans: true });
1083
+ for (const issue of structure.issues) {
1084
+ if (issue.severity === "error" || issue.code === "orphaned_element") {
1085
+ problems.push({ elementKey: issue.elementKey, message: issue.message });
1086
+ }
1087
+ }
1088
+ const cyclic = /* @__PURE__ */ new Set();
1089
+ const state = /* @__PURE__ */ new Map();
1090
+ const descend2 = (key) => {
1091
+ const mark = state.get(key);
1092
+ if (mark === "done") return;
1093
+ if (mark === "open") {
1094
+ cyclic.add(key);
1095
+ return;
1096
+ }
1097
+ state.set(key, "open");
1098
+ const element = spec.elements[key];
1099
+ for (const child of element?.children ?? []) descend2(child);
1100
+ for (const slot of Object.values(element?.slots ?? {}))
1101
+ for (const child of slot) descend2(child);
1102
+ state.set(key, "done");
1103
+ };
1104
+ for (const key of Object.keys(spec.elements)) descend2(key);
1105
+ for (const key of cyclic) {
1106
+ problems.push({
1107
+ elementKey: key,
1108
+ message: `"${key}" is its own descendant: an element tree may not contain a cycle.`
1109
+ });
1110
+ }
1111
+ const known = new Set(catalog2.componentNames);
1112
+ for (const [key, element] of Object.entries(spec.elements)) {
1113
+ if (!known.has(element.type)) {
1114
+ problems.push({ elementKey: key, message: `unknown component type "${element.type}"` });
1115
+ }
1116
+ }
1117
+ for (const [key, element] of Object.entries(spec.elements)) {
1118
+ const schema = propsSchemaOf(catalog2, element.type);
1119
+ if (!schema) continue;
1120
+ const shape = schema.shape;
1121
+ const props = element.props ?? {};
1122
+ for (const [name, value] of Object.entries(props)) {
1123
+ const propSchema = shape[name];
1124
+ if (!propSchema) {
1125
+ problems.push({
1126
+ elementKey: key,
1127
+ message: `${element.type} has no prop "${name}" (known: ${Object.keys(shape).join(", ")})`
1128
+ });
1129
+ continue;
1130
+ }
1131
+ if (isExpression(value)) {
1132
+ if (HATCHES.has(element.type) && name === "path") {
1133
+ problems.push({
1134
+ elementKey: key,
1135
+ message: `${element.type}.path must be a literal string - absolute, or the item's field name inside a repeat - never an expression.`
1136
+ });
1137
+ } else if (isClosedVocabulary(propSchema)) {
1138
+ problems.push({
1139
+ elementKey: key,
1140
+ message: `${element.type}.${name} is one of a fixed set of names, so it must be written as a literal, never as an expression.`
1141
+ });
1142
+ }
1143
+ continue;
1144
+ }
1145
+ const parsed = propSchema.safeParse(value);
1146
+ if (!parsed.success) {
1147
+ problems.push({
1148
+ elementKey: key,
1149
+ message: `${element.type}.${name}: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`
1150
+ });
1151
+ }
1152
+ }
1153
+ for (const [name, propSchema] of Object.entries(shape)) {
1154
+ if (name in props) continue;
1155
+ if (propSchema.safeParse(void 0).success || propSchema.safeParse(null).success) continue;
1156
+ problems.push({
1157
+ elementKey: key,
1158
+ message: `${element.type} is missing required prop "${name}"`
1159
+ });
1160
+ }
1161
+ }
1162
+ const renders = catalog2.renders ?? {};
1163
+ const renderingOf = (type) => hasOwnProp(renders, type) ? renders[type] : void 0;
1164
+ for (const [key, element] of Object.entries(spec.elements)) {
1165
+ const panelled = renderingOf(element.type)?.panels;
1166
+ if (!panelled) continue;
1167
+ const props = element.props ?? {};
1168
+ const listed = props[panelled.prop];
1169
+ if (!Array.isArray(listed)) continue;
1170
+ const panels = listed.length;
1171
+ const children = element.children?.length ?? 0;
1172
+ if (children !== panels) {
1173
+ problems.push({
1174
+ elementKey: key,
1175
+ message: `${element.type} declares ${panels} panel${panels === 1 ? "" : "s"} but has ${children} child${children === 1 ? "" : "ren"}: exactly one child per ${panelled.noun}, in order.`
1176
+ });
1177
+ }
1178
+ const runs = (element.children ?? []).filter(
1179
+ (child) => spec.elements[child]?.type === "Button"
1180
+ );
1181
+ if (runs.length > 0) {
1182
+ problems.push({
1183
+ elementKey: key,
1184
+ 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.`
1185
+ });
1186
+ }
1187
+ }
1188
+ const present2 = (value) => value !== void 0 && value !== null && value !== "";
1189
+ const levels = [];
1190
+ const onlyOnce = /* @__PURE__ */ new Map();
1191
+ const seen = /* @__PURE__ */ new Set();
1192
+ const walk = (key) => {
1193
+ if (seen.has(key)) return;
1194
+ seen.add(key);
1195
+ const element = spec.elements[key];
1196
+ if (!element) return;
1197
+ const props = element.props ?? {};
1198
+ const rendering = renderingOf(element.type);
1199
+ if (element.type === "Heading") {
1200
+ const level = String(props.level ?? "h2");
1201
+ const match = /^h([1-4])$/.exec(level);
1202
+ if (match) levels.push({ key, type: "Heading", level: Number(match[1]) });
1203
+ } else if (rendering?.heading) {
1204
+ const rendered = rendering.heading;
1205
+ const has = rendered.when === void 0 || present2(props[rendered.when]);
1206
+ if (has) levels.push({ key, type: element.type, level: rendered.level });
1207
+ }
1208
+ if (rendering?.once !== void 0) {
1209
+ const entry = onlyOnce.get(element.type) ?? { reason: rendering.once, keys: [] };
1210
+ entry.keys.push(key);
1211
+ onlyOnce.set(element.type, entry);
1212
+ }
1213
+ for (const child of element.children ?? []) walk(child);
1214
+ for (const slot of Object.values(element.slots ?? {})) for (const child of slot) walk(child);
1215
+ };
1216
+ if (spec.root) walk(spec.root);
1217
+ const describe2 = (heading) => heading.type === "Heading" ? `h${heading.level}` : `${heading.type}'s h${heading.level}`;
1218
+ let previous;
1219
+ for (const heading of levels) {
1220
+ if (previous !== void 0 && heading.level > previous.level + 1) {
1221
+ problems.push({
1222
+ elementKey: heading.key,
1223
+ message: `${describe2(heading)} jumps after ${describe2(previous)}: heading levels increase by one, never by more.`
1224
+ });
1225
+ }
1226
+ previous = heading;
1227
+ }
1228
+ const firsts = levels.filter((heading) => heading.level === 1);
1229
+ const h1Ways = [
1230
+ ...known.has("Heading") ? ["as a Heading at level h1"] : [],
1231
+ ...Object.entries(renders).filter(([, rendering]) => rendering.heading?.level === 1).map(([type]) => `as the heading a ${type} renders`)
1232
+ ];
1233
+ if (firsts.length === 0 && spec.root && h1Ways.length > 0) {
1234
+ problems.push({
1235
+ elementKey: spec.root,
1236
+ message: `the page has no h1: exactly one, ${h1Ways.join(" or ")}.`
1237
+ });
1238
+ }
1239
+ for (const extra of firsts.slice(1)) {
1240
+ problems.push({
1241
+ elementKey: extra.key,
1242
+ message: `a second h1 (${describe2(extra)}, after ${describe2(firsts[0])} at [${firsts[0].key}]): exactly one on a page.`
1243
+ });
1244
+ }
1245
+ for (const [type, { reason, keys }] of onlyOnce) {
1246
+ for (const extra of keys.slice(1)) {
1247
+ problems.push({
1248
+ elementKey: extra,
1249
+ message: `a second ${type} (after [${keys[0]}]): at most one on a page, since it renders as ${reason}.`
1250
+ });
1251
+ }
1252
+ }
1253
+ for (const [key, element] of Object.entries(spec.elements)) {
1254
+ const rule = renderingOf(element.type)?.children;
1255
+ if (!rule) continue;
1256
+ const children = element.children?.length ?? 0;
1257
+ if (children !== rule.count) {
1258
+ problems.push({
1259
+ elementKey: key,
1260
+ message: `${element.type} takes exactly ${rule.count} children (${rule.roles}); this one has ${children}.`
1261
+ });
1262
+ }
1263
+ }
1264
+ const declared = [
1265
+ ...catalog2.actionNames ?? [],
1266
+ ...(catalog2.schema?.builtInActions ?? []).map((action) => action.name)
1267
+ ];
1268
+ const knownActions = declared.length > 0 ? new Set(declared) : void 0;
1269
+ const STATE_WRITES = {
1270
+ setState: [{ param: "statePath" }],
1271
+ pushState: [{ param: "statePath" }, { param: "clearStatePath", optional: true }],
1272
+ removeState: [{ param: "statePath" }],
1273
+ validateForm: [{ param: "statePath", optional: true }]
1274
+ };
1275
+ const OWNED_ROOTS = [INPUTS_ROOT, RESULT_ROOT];
1276
+ const ownedRootOf = (written) => {
1277
+ const statePath = written.startsWith("/") ? written : `/${written}`;
1278
+ return OWNED_ROOTS.find((root) => statePath === root || statePath.startsWith(`${root}/`));
1279
+ };
1280
+ const bindingsOf = (binding) => Array.isArray(binding) ? binding : [binding];
1281
+ 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.`;
1282
+ const checkBinding = (key, site, entry) => {
1283
+ const action = entry?.action;
1284
+ if (typeof action !== "string") {
1285
+ problems.push({ elementKey: key, message: `${site} has an entry with no "action" name.` });
1286
+ return;
1287
+ }
1288
+ if (knownActions && !knownActions.has(action)) {
1289
+ problems.push({
1290
+ elementKey: key,
1291
+ message: `${site} names the unknown action "${action}" (known: ${[...knownActions].join(", ")}); nothing would handle it.`
1292
+ });
1293
+ return;
1294
+ }
1295
+ const writes = hasOwnProp(STATE_WRITES, action) ? STATE_WRITES[action] : void 0;
1296
+ if (writes) {
1297
+ const params = entry.params;
1298
+ for (const { param, optional } of writes) {
1299
+ const written = typeof params === "object" && params !== null ? params[param] : void 0;
1300
+ if (written === void 0 || written === null) {
1301
+ if (!optional) {
1302
+ problems.push({
1303
+ elementKey: key,
1304
+ message: `${site} calls ${action} without a literal "${param}".`
1305
+ });
1306
+ }
1307
+ continue;
1308
+ }
1309
+ if (typeof written !== "string") {
1310
+ problems.push({
1311
+ elementKey: key,
1312
+ message: `${site} calls ${action} with a "${param}" that is not a literal string; where an action writes must be named, never computed.`
1313
+ });
1314
+ continue;
1315
+ }
1316
+ const owned = ownedRootOf(written);
1317
+ if (owned) {
1318
+ const where = param === "statePath" ? `on "${written}"` : `with ${param} "${written}"`;
1319
+ problems.push({
1320
+ elementKey: key,
1321
+ message: `${site} calls ${action} ${where}: ${refusal(owned, written.startsWith("/") ? written : `/${written}`)}`
1322
+ });
1323
+ }
1324
+ }
1325
+ }
1326
+ for (const hook of ["onSuccess", "onError"]) {
1327
+ const follow = entry[hook];
1328
+ if (follow === void 0 || follow === null) continue;
1329
+ const hookSite = `${site}.${hook}`;
1330
+ if (typeof follow !== "object" || Array.isArray(follow)) {
1331
+ problems.push({
1332
+ elementKey: key,
1333
+ message: `${hookSite} must be an object: a { "set" } of state paths to values, or an { "action" } binding.`
1334
+ });
1335
+ continue;
1336
+ }
1337
+ const record = follow;
1338
+ if (record.set !== void 0 && record.set !== null) {
1339
+ if (typeof record.set !== "object" || Array.isArray(record.set)) {
1340
+ problems.push({
1341
+ elementKey: key,
1342
+ message: `${hookSite}.set must be an object mapping a state path to its value.`
1343
+ });
1344
+ } else {
1345
+ for (const written of Object.keys(record.set)) {
1346
+ const owned = ownedRootOf(written);
1347
+ if (owned) {
1348
+ problems.push({
1349
+ elementKey: key,
1350
+ message: `${hookSite} sets "${written}": ${refusal(owned, written.startsWith("/") ? written : `/${written}`)}`
1351
+ });
1352
+ }
1353
+ }
1354
+ }
1355
+ }
1356
+ if (record.action !== void 0) checkBinding(key, hookSite, record);
1357
+ }
1358
+ };
1359
+ for (const [key, element] of Object.entries(spec.elements)) {
1360
+ const on = element.on;
1361
+ if (on !== void 0 && on !== null) {
1362
+ if (typeof on !== "object" || Array.isArray(on)) {
1363
+ problems.push({
1364
+ elementKey: key,
1365
+ message: '"on" must be an object mapping an event name to its actions.'
1366
+ });
1367
+ } else {
1368
+ const emitted = eventsOf(catalog2, element.type);
1369
+ for (const [event, binding] of Object.entries(on)) {
1370
+ if (emitted && !emitted.includes(event)) {
1371
+ problems.push({
1372
+ elementKey: key,
1373
+ 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.`
1374
+ });
1375
+ }
1376
+ for (const entry of bindingsOf(binding)) checkBinding(key, `on.${event}`, entry);
1377
+ }
1378
+ }
1379
+ }
1380
+ const watch = element.watch;
1381
+ if (watch !== void 0 && watch !== null) {
1382
+ if (typeof watch !== "object" || Array.isArray(watch)) {
1383
+ problems.push({
1384
+ elementKey: key,
1385
+ message: '"watch" must be an object mapping a state path to the actions its change fires.'
1386
+ });
1387
+ } else {
1388
+ for (const [path, binding] of Object.entries(watch)) {
1389
+ for (const entry of bindingsOf(binding)) checkBinding(key, `watch.${path}`, entry);
1390
+ }
1391
+ }
1392
+ }
1393
+ }
1394
+ return { ok: problems.length === 0, problems };
1395
+ }
1396
+ function formatProblems(problems) {
1397
+ return problems.map(
1398
+ (problem) => problem.elementKey ? `[${problem.elementKey}] ${problem.message}` : problem.message
1399
+ ).join("\n");
1400
+ }
1401
+
1402
+ // src/generative/layout-fits.ts
1403
+ function isUnder(root, path) {
1404
+ return path === root || path.startsWith(`${root}/`);
1405
+ }
1406
+ function itemPathResolver(spec, key, parents) {
1407
+ let base;
1408
+ let resolvedBase = false;
1409
+ return (field) => {
1410
+ if (!resolvedBase) {
1411
+ base = repeatBasePathOf(spec, key, parents);
1412
+ resolvedBase = true;
1413
+ }
1414
+ if (base === void 0) return void 0;
1415
+ const under = field.startsWith("/") ? field.slice(1) : field;
1416
+ return under === "" ? base : `${base}/${under}`;
1417
+ };
1418
+ }
1419
+ function interpolatedPaths(template, itemPath) {
1420
+ return [...template.matchAll(/\$\{([^}]+)\}/g)].flatMap((match) => {
1421
+ const raw = match[1];
1422
+ if (raw === void 0) return [];
1423
+ if (raw.startsWith("/")) return [raw];
1424
+ return [itemPath(raw) ?? `/${raw}`];
1425
+ });
1426
+ }
1427
+ function mentionedPaths(spec, parents) {
1428
+ const found = { bound: [], read: [], adrift: [] };
1429
+ for (const [key, element] of Object.entries(spec.elements)) {
1430
+ const itemPath = itemPathResolver(spec, key, parents);
1431
+ const walk = (value) => {
1432
+ if (Array.isArray(value)) {
1433
+ value.forEach(walk);
1434
+ return;
1435
+ }
1436
+ if (typeof value !== "object" || value === null) return;
1437
+ const record = value;
1438
+ if (typeof record.$bindState === "string") found.bound.push(record.$bindState);
1439
+ if (typeof record.$state === "string") found.read.push(record.$state);
1440
+ if (typeof record.$template === "string") {
1441
+ found.read.push(...interpolatedPaths(record.$template, itemPath));
1442
+ }
1443
+ if (typeof record.$bindItem === "string") {
1444
+ const path = itemPath(record.$bindItem);
1445
+ if (path === void 0) found.adrift.push(key);
1446
+ else found.bound.push(path);
1447
+ }
1448
+ if (typeof record.$item === "string") {
1449
+ const path = itemPath(record.$item);
1450
+ if (path === void 0) found.adrift.push(key);
1451
+ else found.read.push(path);
1452
+ }
1453
+ Object.values(record).forEach(walk);
1454
+ };
1455
+ walk(element.props);
1456
+ walk(element.visible);
1457
+ }
1458
+ return found;
1459
+ }
1460
+ function staleReads(read, root, resolves) {
1461
+ const under = read.filter((path) => isUnder(root, path));
1462
+ return [...new Set(under)].filter((path) => !resolves(path));
1463
+ }
1464
+ function staleRepeats(spec, parents, root, resolves, side) {
1465
+ const problems = [];
1466
+ for (const [key, element] of Object.entries(spec.elements)) {
1467
+ if (!element.repeat) continue;
1468
+ const listPath = repeatListPathOf(spec, key, parents);
1469
+ if (listPath === void 0 || !isUnder(root, listPath)) continue;
1470
+ if (!resolves(listPath)) {
1471
+ problems.push(`${key}: repeats over ${listPath}, which no ${side} has`);
1472
+ }
1473
+ }
1474
+ return problems;
1475
+ }
1476
+ var NOT_A_VALUE = {
1477
+ object: { what: "a structure", instead: "a structure is shown through its members" },
1478
+ list: { what: "a list", instead: "a list is laid out as a repeat or a DataTable" },
1479
+ document: { what: "a file", instead: "a file is delegated to the kernel's own control" },
1480
+ image: { what: "a file", instead: "a file is delegated to the kernel's own control" }
1481
+ };
1482
+ var NOT_VALUES = {
1483
+ object: "structures",
1484
+ list: "lists",
1485
+ document: "files",
1486
+ image: "files"
1487
+ };
1488
+ var listPropsCache;
1489
+ function listProps() {
1490
+ if (listPropsCache) return listPropsCache;
1491
+ const found = /* @__PURE__ */ new Map([
1492
+ ["DataTable", /* @__PURE__ */ new Map([["rows", "anything"]])]
1493
+ ]);
1494
+ const components3 = catalog.data.components;
1495
+ for (const [type, definition] of Object.entries(components3)) {
1496
+ const shape = definition.props?.shape;
1497
+ for (const [prop, schema] of Object.entries(shape ?? {})) {
1498
+ const items = listItemsOf(schema);
1499
+ if (items === void 0) continue;
1500
+ if (!found.has(type)) found.set(type, /* @__PURE__ */ new Map());
1501
+ found.get(type).set(prop, items);
1502
+ }
1503
+ }
1504
+ listPropsCache = found;
1505
+ return found;
1506
+ }
1507
+ var VALUE_SCHEMAS = /* @__PURE__ */ new Set(["string", "number", "boolean", "enum", "literal"]);
1508
+ function unwrapped(schema) {
1509
+ let current = schema;
1510
+ for (let depth = 0; depth < 8; depth += 1) {
1511
+ const def = current.def;
1512
+ if (!def) return void 0;
1513
+ if (def.innerType === void 0) return def;
1514
+ current = def.innerType;
1515
+ }
1516
+ return void 0;
1517
+ }
1518
+ function listItemsOf(schema) {
1519
+ const def = unwrapped(schema);
1520
+ if (def?.type !== "array") return void 0;
1521
+ const element = unwrapped(def.element);
1522
+ return element?.type !== void 0 && VALUE_SCHEMAS.has(element.type) ? "values" : "anything";
1523
+ }
1524
+ function nonScalarReads(spec, parents, root, fieldAt) {
1525
+ const problems = [];
1526
+ const lists = listProps();
1527
+ for (const [key, element] of Object.entries(spec.elements)) {
1528
+ const itemPath = itemPathResolver(spec, key, parents);
1529
+ const listy = lists.get(element.type);
1530
+ const check = (prop, path) => {
1531
+ if (!isUnder(root, path)) return;
1532
+ const field = fieldAt(path);
1533
+ if (!field) return;
1534
+ const wrong = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind] : void 0;
1535
+ if (!wrong) return;
1536
+ problems.push(
1537
+ `${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}`
1538
+ );
1539
+ };
1540
+ const checkList = (prop, path, items) => {
1541
+ if (!isUnder(root, path)) return;
1542
+ const field = fieldAt(path);
1543
+ if (!field || field.kind === "unknown") return;
1544
+ if (field.kind !== "list") {
1545
+ const what = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind].what : "a value";
1546
+ problems.push(
1547
+ `${key}: ${prop} takes a list, and ${path} is ${what}; a prop that takes a list reads a list path`
1548
+ );
1549
+ return;
1550
+ }
1551
+ if (items !== "values") return;
1552
+ const of = hasOwnProp(NOT_VALUES, field.item.kind) ? NOT_VALUES[field.item.kind] : void 0;
1553
+ if (!of) return;
1554
+ problems.push(
1555
+ `${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`
1556
+ );
1557
+ };
1558
+ const walk = (prop, value) => {
1559
+ if (Array.isArray(value)) {
1560
+ value.forEach((entry) => walk(prop, entry));
1561
+ return;
1562
+ }
1563
+ if (typeof value !== "object" || value === null) return;
1564
+ const record = value;
1565
+ if (typeof record.$state === "string") check(prop, record.$state);
1566
+ if (typeof record.$item === "string") {
1567
+ const path = itemPath(record.$item);
1568
+ if (path !== void 0) check(prop, path);
1569
+ }
1570
+ if (typeof record.$template === "string") {
1571
+ for (const path of interpolatedPaths(record.$template, itemPath)) check(prop, path);
1572
+ }
1573
+ for (const [name, entry] of Object.entries(record)) {
1574
+ if (name !== "$cond") walk(prop, entry);
1575
+ }
1576
+ };
1577
+ for (const [prop, value] of Object.entries(element.props ?? {})) {
1578
+ const items = listy?.get(prop);
1579
+ if (items === void 0 || Array.isArray(value)) {
1580
+ walk(prop, value);
1581
+ continue;
1582
+ }
1583
+ if (typeof value !== "object" || value === null) continue;
1584
+ const record = value;
1585
+ if (typeof record.$state === "string") checkList(prop, record.$state, items);
1586
+ if (typeof record.$item === "string") {
1587
+ const path = itemPath(record.$item);
1588
+ if (path !== void 0) checkList(prop, path, items);
1589
+ }
1590
+ }
1591
+ }
1592
+ return problems;
1593
+ }
1594
+ function boundProblems(bound, inputs) {
1595
+ const problems = [];
1596
+ const underInputs = bound.filter((path) => isUnder(INPUTS_ROOT, path));
1597
+ if (!inputs) {
1598
+ if (underInputs.length > 0) {
1599
+ problems.push(`a result page binds ${underInputs.join(", ")}; a result page writes nothing`);
1600
+ }
1601
+ } else {
1602
+ for (const path of underInputs) {
1603
+ if (!inputFieldAtPath(inputs, path)) {
1604
+ problems.push(`${path} is bound, and no input has it`);
1605
+ }
1606
+ }
1607
+ }
1608
+ for (const path of bound) {
1609
+ if (isUnder(RESULT_ROOT, path)) {
1610
+ problems.push(
1611
+ `${path} is bound; a layout may not write into ${RESULT_ROOT}, which the run fills`
1612
+ );
1613
+ }
1614
+ }
1615
+ return problems;
1616
+ }
1617
+ function repeatPaths(spec) {
1618
+ const found = [];
1619
+ for (const element of Object.values(spec.elements)) {
1620
+ const statePath = element.repeat?.statePath;
1621
+ if (typeof statePath === "string") found.push(statePath);
1622
+ }
1623
+ return found;
1624
+ }
1625
+ function isOffered(path, offered) {
1626
+ if (offered.bound.has(path) || offered.repeated.has(path)) return true;
1627
+ return offered.delegated.some((at) => path === at || path.startsWith(`${at}/`));
1628
+ }
1629
+ function uncoveredUnder(field, path, offered) {
1630
+ if (isOffered(path, offered)) return [];
1631
+ if (field.kind === "object") {
1632
+ return field.fields.filter((child) => child.required).flatMap((child) => uncoveredUnder(child, joinPath(path, child.name), offered));
1633
+ }
1634
+ return [path];
1635
+ }
1636
+ function layoutProblems(descriptor, spec) {
1637
+ try {
1638
+ return collectLayoutProblems(descriptor, spec);
1639
+ } catch (error) {
1640
+ return [`the layout is not a well-formed spec: ${String(error)}`];
1641
+ }
1642
+ }
1643
+ function collectLayoutProblems(descriptor, spec) {
1644
+ const problems = [];
1645
+ const delegated = [];
1646
+ const parents = parentMapOf(spec);
1647
+ for (const [key, element] of Object.entries(spec.elements)) {
1648
+ const written = element.props?.path;
1649
+ const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
1650
+ if (element.type === "MthdsField") {
1651
+ if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
1652
+ problems.push(`${key}: MthdsField delegates ${String(written)}, which no input has`);
1653
+ } else {
1654
+ delegated.push(path);
1655
+ }
1656
+ }
1657
+ if (element.type === "MthdsResult") {
1658
+ if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
1659
+ problems.push(`${key}: MthdsResult delegates ${String(written)}, which no result has`);
1660
+ }
1661
+ }
1662
+ }
1663
+ const { bound, read, adrift } = mentionedPaths(spec, parents);
1664
+ for (const key of new Set(adrift)) {
1665
+ problems.push(`${key}: reads the current item, and no repeat above it has one`);
1666
+ }
1667
+ problems.push(...boundProblems(bound, descriptor.inputs));
1668
+ if (!descriptor.inputs) {
1669
+ const result = descriptor.result;
1670
+ const fieldAt2 = (path) => result ? resultFieldAtPath(result, path) : void 0;
1671
+ const resolves2 = (path) => fieldAt2(path) !== void 0;
1672
+ problems.push(...staleRepeats(spec, parents, RESULT_ROOT, resolves2, "result"));
1673
+ for (const path of staleReads(read, RESULT_ROOT, resolves2)) {
1674
+ problems.push(`${path} is read, and no result has it`);
1675
+ }
1676
+ problems.push(...nonScalarReads(spec, parents, RESULT_ROOT, fieldAt2));
1677
+ return problems;
1678
+ }
1679
+ const inputs = descriptor.inputs;
1680
+ const fieldAt = (path) => inputFieldAtPath(inputs, path);
1681
+ const resolves = (path) => fieldAt(path) !== void 0;
1682
+ problems.push(...staleRepeats(spec, parents, INPUTS_ROOT, resolves, "input"));
1683
+ for (const path of staleReads(read, INPUTS_ROOT, resolves)) {
1684
+ problems.push(`${path} is read, and no input has it`);
1685
+ }
1686
+ problems.push(...nonScalarReads(spec, parents, INPUTS_ROOT, fieldAt));
1687
+ const offered = {
1688
+ bound: new Set(bound),
1689
+ repeated: new Set(repeatPaths(spec)),
1690
+ delegated
1691
+ };
1692
+ for (const field of inputs) {
1693
+ if (!field.required) continue;
1694
+ for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered)) {
1695
+ problems.push(`${path} is required, and the layout offers nowhere to enter it`);
1696
+ }
1697
+ }
1698
+ return problems;
1699
+ }
1700
+ function layoutFits(descriptor, spec) {
1701
+ return layoutProblems(descriptor, spec).length === 0;
1702
+ }
1703
+ function specToJsonl(spec) {
1704
+ const lines = [];
1705
+ const push = (op, path, value) => lines.push(JSON.stringify({ op, path, value }));
1706
+ push("add", "/root", spec.root);
1707
+ const emitted = /* @__PURE__ */ new Set();
1708
+ const queue = [spec.root];
1709
+ while (queue.length > 0) {
1710
+ const key = queue.shift();
1711
+ if (emitted.has(key)) continue;
1712
+ const element = spec.elements[key];
1713
+ if (!element) continue;
1714
+ emitted.add(key);
1715
+ push("add", `/elements/${escapeSegment(key)}`, element);
1716
+ for (const child of element.children ?? []) queue.push(child);
1717
+ for (const slotChildren of Object.values(element.slots ?? {})) queue.push(...slotChildren);
1718
+ }
1719
+ for (const key of Object.keys(spec.elements)) {
1720
+ if (!emitted.has(key)) push("add", `/elements/${escapeSegment(key)}`, spec.elements[key]);
1721
+ }
1722
+ for (const [key, value] of Object.entries(spec.state ?? {})) {
1723
+ push("add", `/state/${escapeSegment(key)}`, value);
1724
+ }
1725
+ return `${lines.join("\n")}
1726
+ `;
1727
+ }
1728
+ var FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1729
+ function pointerReachesPrototype(pointer) {
1730
+ return typeof pointer === "string" && pointer.split("/").some((segment) => FORBIDDEN_SEGMENTS.has(unescapeSegment(segment)));
1731
+ }
1732
+ function reachesPrototype(line) {
1733
+ let parsed;
1734
+ try {
1735
+ parsed = JSON.parse(line);
1736
+ } catch {
1737
+ return false;
1738
+ }
1739
+ const patch = parsed;
1740
+ return pointerReachesPrototype(patch?.path) || pointerReachesPrototype(patch?.from);
1741
+ }
1742
+ function specFromJsonl(jsonl) {
1743
+ let spec = { root: "", elements: {} };
1744
+ for (const line of jsonl.split("\n")) {
1745
+ if (reachesPrototype(line)) continue;
1746
+ try {
1747
+ spec = compileSpecStream(line, spec);
1748
+ } catch {
1749
+ continue;
1750
+ }
1751
+ }
1752
+ return spec;
1753
+ }
1754
+ function jsonlLines(jsonl) {
1755
+ return jsonl.split("\n").filter((line) => line.trim().length > 0);
1756
+ }
1757
+ var BrandContext = React3.createContext(null);
1758
+ function BrandProvider({
1759
+ manifest,
1760
+ children
1761
+ }) {
1762
+ useWebfont(manifest.webfont);
1763
+ return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
1764
+ }
1765
+ function useBrand() {
1766
+ const manifest = React3.useContext(BrandContext);
1767
+ if (!manifest)
1768
+ throw new Error(
1769
+ "useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
1770
+ );
1771
+ return manifest;
1772
+ }
1773
+ var WEIGHTS = "400;500;600;700";
1774
+ function useWebfont(webfont) {
1775
+ const provider = webfont?.provider;
1776
+ const family = webfont?.family;
1777
+ React3.useEffect(() => {
1778
+ if (!provider || !family) return;
1779
+ const key = `${provider}:${family}`;
1780
+ if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
1781
+ for (const origin of ["https://fonts.googleapis.com", "https://fonts.gstatic.com"]) {
1782
+ if (document.head.querySelector(`link[rel="preconnect"][href="${origin}"]`)) continue;
1783
+ const preconnect = document.createElement("link");
1784
+ preconnect.rel = "preconnect";
1785
+ preconnect.href = origin;
1786
+ if (origin.endsWith("gstatic.com")) preconnect.crossOrigin = "anonymous";
1787
+ document.head.appendChild(preconnect);
1788
+ }
1789
+ const link = document.createElement("link");
1790
+ link.rel = "stylesheet";
1791
+ const encoded = encodeURIComponent(family).replace(/%20/g, "+");
1792
+ link.href = `https://fonts.googleapis.com/css2?family=${encoded}:wght@${WEIGHTS}&display=swap`;
1793
+ link.dataset.brandWebfont = key;
1794
+ document.head.appendChild(link);
1795
+ }, [provider, family]);
1796
+ }
1797
+ function useBoundField(literal, binding, empty, { checks, validateOn }) {
1798
+ const [boundValue, setBoundValue] = useBoundProp(literal ?? void 0, binding);
1799
+ const [localValue, setLocalValue] = React3.useState(literal ?? empty);
1800
+ const isBound = Boolean(binding);
1801
+ const hasValidation = Boolean(binding && checks?.length);
1802
+ const when = validateOn ?? "change";
1803
+ const { errors, validate } = useFieldValidation(
1804
+ binding ?? "",
1805
+ hasValidation ? { checks: checks ?? [], validateOn: when } : void 0
1806
+ );
1807
+ return {
1808
+ value: isBound ? boundValue ?? empty : localValue,
1809
+ setValue: (next) => {
1810
+ if (isBound) setBoundValue(next);
1811
+ else setLocalValue(next);
1812
+ },
1813
+ error: errors[0],
1814
+ validateOnChange: () => {
1815
+ if (hasValidation && when === "change") validate();
1816
+ },
1817
+ validateOnBlur: () => {
1818
+ if (hasValidation && when === "blur") validate();
1819
+ }
1820
+ };
1821
+ }
1822
+ var LABEL = "block text-sm leading-none font-medium";
1823
+ function FieldError({ message }) {
1824
+ return message ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: message }) : null;
1825
+ }
1826
+ function pickKey(table, key, fallback) {
1827
+ return key != null && hasOwnProp(table, key) ? key : fallback;
1828
+ }
1829
+ function pick(table, key, fallback) {
1830
+ return table[pickKey(table, key, fallback)];
1831
+ }
1832
+ function Card({
1833
+ props,
1834
+ children
1835
+ }) {
1836
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border bg-card p-6 text-card-foreground", children: [
1837
+ props.title || props.description ? /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-1.5", children: [
1838
+ props.title ? /* @__PURE__ */ jsx("h3", { className: "text-lg leading-none font-semibold", children: props.title }) : null,
1839
+ props.description ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: props.description }) : null
1840
+ ] }) : null,
1841
+ children
1842
+ ] });
1843
+ }
1844
+ var GAP = {
1845
+ none: "gap-0",
1846
+ sm: "gap-2",
1847
+ md: "gap-4",
1848
+ lg: "gap-6",
1849
+ xl: "gap-8"
1850
+ };
1851
+ var ALIGN = {
1852
+ start: "items-start",
1853
+ center: "items-center",
1854
+ end: "items-end",
1855
+ stretch: "items-stretch"
1856
+ };
1857
+ var JUSTIFY = {
1858
+ start: "justify-start",
1859
+ center: "justify-center",
1860
+ end: "justify-end",
1861
+ between: "justify-between",
1862
+ around: "justify-around"
1863
+ };
1864
+ function Stack({
1865
+ props,
1866
+ children
1867
+ }) {
1868
+ const horizontal = props.direction === "horizontal";
1869
+ return /* @__PURE__ */ jsx(
1870
+ "div",
1871
+ {
1872
+ className: cn(
1873
+ "flex",
1874
+ horizontal ? "flex-row" : "flex-col",
1875
+ pick(GAP, props.gap, "md"),
1876
+ pick(ALIGN, props.align, horizontal ? "start" : "stretch"),
1877
+ props.justify ? pick(JUSTIFY, props.justify, "start") : void 0
1878
+ ),
1879
+ children
1880
+ }
1881
+ );
1882
+ }
1883
+ var COLUMNS = {
1884
+ 1: "grid-cols-1",
1885
+ 2: "sm:grid-cols-2",
1886
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
1887
+ 4: "sm:grid-cols-2 lg:grid-cols-4",
1888
+ 5: "sm:grid-cols-2 lg:grid-cols-5",
1889
+ 6: "sm:grid-cols-2 lg:grid-cols-6"
1890
+ };
1891
+ function Grid({
1892
+ props,
1893
+ children
1894
+ }) {
1895
+ const columns = Math.min(Math.max(Math.round(props.columns ?? 2), 1), 6);
1896
+ return /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-1", COLUMNS[columns], pick(GAP, props.gap, "md")), children });
1897
+ }
1898
+ function Separator({
1899
+ props
1900
+ }) {
1901
+ const vertical = props.orientation === "vertical";
1902
+ return /* @__PURE__ */ jsx(
1903
+ "div",
1904
+ {
1905
+ role: "separator",
1906
+ "aria-orientation": vertical ? "vertical" : "horizontal",
1907
+ className: cn("shrink-0 bg-border", vertical ? "h-full w-px" : "h-px w-full")
1908
+ }
1909
+ );
1910
+ }
1911
+ function Collapsible({
1912
+ props,
1913
+ children
1914
+ }) {
1915
+ return /* @__PURE__ */ jsxs(
1916
+ "details",
1917
+ {
1918
+ className: "rounded-md border border-border",
1919
+ open: props.defaultOpen ?? false,
1920
+ "data-slot": "collapsible",
1921
+ children: [
1922
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer list-none px-4 py-3 text-sm font-medium select-none", children: props.title }),
1923
+ /* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 py-3", children })
1924
+ ]
1925
+ }
1926
+ );
1927
+ }
1928
+ var HEADING = {
1929
+ h1: "text-3xl font-bold tracking-tight",
1930
+ h2: "text-2xl font-semibold tracking-tight",
1931
+ h3: "text-lg font-semibold",
1932
+ h4: "text-base font-semibold"
1933
+ };
1934
+ function Heading({
1935
+ props
1936
+ }) {
1937
+ const Tag2 = pickKey(HEADING, props.level, "h2");
1938
+ return /* @__PURE__ */ jsx(Tag2, { className: cn("text-foreground", HEADING[Tag2]), children: props.text });
1939
+ }
1940
+ var TEXT = {
1941
+ body: "text-sm text-foreground",
1942
+ caption: "text-xs text-muted-foreground",
1943
+ muted: "text-sm text-muted-foreground",
1944
+ lead: "text-lg text-muted-foreground",
1945
+ code: "font-mono text-[13px] text-foreground"
1946
+ };
1947
+ function Text({
1948
+ props
1949
+ }) {
1950
+ return /* @__PURE__ */ jsx("p", { className: pick(TEXT, props.variant, "body"), children: props.text });
1951
+ }
1952
+ var AVATAR_SIZE = {
1953
+ sm: "size-8 text-[11px]",
1954
+ md: "size-10 text-xs",
1955
+ lg: "size-12 text-sm"
1956
+ };
1957
+ function initialsOf(name) {
1958
+ const words = name.trim().split(/\s+/).filter(Boolean);
1959
+ if (words.length === 0) return "?";
1960
+ const first = words[0]?.[0] ?? "";
1961
+ const last = words.length > 1 ? words[words.length - 1]?.[0] ?? "" : "";
1962
+ return (first + last).toUpperCase();
1963
+ }
1964
+ function Avatar({
1965
+ props
1966
+ }) {
1967
+ const name = String(props.name ?? "");
1968
+ return /* @__PURE__ */ jsx(
1969
+ "span",
1970
+ {
1971
+ className: cn(
1972
+ "inline-flex shrink-0 items-center justify-center rounded-full bg-muted font-medium text-muted-foreground",
1973
+ pick(AVATAR_SIZE, props.size, "md")
1974
+ ),
1975
+ "aria-label": name || void 0,
1976
+ role: "img",
1977
+ children: initialsOf(name)
1978
+ }
1979
+ );
1980
+ }
1981
+ var BADGE = {
1982
+ default: "bg-primary text-primary-foreground",
1983
+ secondary: "bg-secondary text-secondary-foreground",
1984
+ destructive: "bg-destructive text-white",
1985
+ outline: "border border-border text-foreground"
1986
+ };
1987
+ function Badge({
1988
+ props
1989
+ }) {
1990
+ return /* @__PURE__ */ jsx(
1991
+ "span",
1992
+ {
1993
+ className: cn(
1994
+ "inline-flex w-fit items-center rounded-md px-2 py-0.5 text-xs font-medium",
1995
+ pick(BADGE, props.variant, "default")
1996
+ ),
1997
+ children: props.text
1998
+ }
1999
+ );
2000
+ }
2001
+ var ALERT = {
2002
+ info: "border-border bg-muted text-foreground",
2003
+ success: "border-border bg-muted text-foreground",
2004
+ warning: "border-border bg-muted text-foreground",
2005
+ error: "border-destructive/50 bg-destructive/10 text-foreground"
2006
+ };
2007
+ function Alert({
2008
+ props
2009
+ }) {
2010
+ const type = pickKey(ALERT, props.type, "info");
2011
+ return /* @__PURE__ */ jsxs(
2012
+ "div",
2013
+ {
2014
+ role: type === "error" ? "alert" : "status",
2015
+ className: cn("rounded-md border px-4 py-3 text-sm", ALERT[type]),
2016
+ children: [
2017
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: props.title }),
2018
+ props.message ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-muted-foreground", children: props.message }) : null
2019
+ ]
2020
+ }
2021
+ );
2022
+ }
2023
+ function Progress({
2024
+ props
2025
+ }) {
2026
+ const max = props.max ?? 100;
2027
+ const value = Math.min(Math.max(Number(props.value) || 0, 0), max);
2028
+ const percent = max > 0 ? value / max * 100 : 0;
2029
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2030
+ props.label ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: props.label }) : null,
2031
+ /* @__PURE__ */ jsx(
2032
+ "div",
2033
+ {
2034
+ role: "progressbar",
2035
+ "aria-valuenow": value,
2036
+ "aria-valuemin": 0,
2037
+ "aria-valuemax": max,
2038
+ "aria-label": props.label ?? void 0,
2039
+ className: "h-2 w-full overflow-hidden rounded-full bg-muted",
2040
+ children: /* @__PURE__ */ jsx("div", { className: "h-full bg-primary transition-all", style: { width: `${percent}%` } })
2041
+ }
2042
+ )
2043
+ ] });
2044
+ }
2045
+ function useControlId(name) {
2046
+ return `jr-${name}-${React3.useId()}`;
2047
+ }
2048
+ function Input({
2049
+ props,
2050
+ bindings,
2051
+ emit
2052
+ }) {
2053
+ const id = useControlId(props.name);
2054
+ const field = useBoundField(props.value, bindings?.value, "", props);
2055
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2056
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: LABEL, children: props.label }),
2057
+ /* @__PURE__ */ jsx(
2058
+ "input",
2059
+ {
2060
+ id,
2061
+ name: props.name,
2062
+ type: props.type ?? "text",
2063
+ className: cn(fieldControlClass, "min-h-11 px-3 py-2"),
2064
+ placeholder: props.placeholder ?? void 0,
2065
+ value: field.value,
2066
+ "aria-invalid": field.error ? true : void 0,
2067
+ onChange: (event) => {
2068
+ field.setValue(event.target.value);
2069
+ field.validateOnChange();
2070
+ },
2071
+ onFocus: () => emit("focus"),
2072
+ onBlur: () => {
2073
+ field.validateOnBlur();
2074
+ emit("blur");
2075
+ }
2076
+ }
2077
+ ),
2078
+ /* @__PURE__ */ jsx(FieldError, { message: field.error })
2079
+ ] });
2080
+ }
2081
+ function Textarea({
2082
+ props,
2083
+ bindings
2084
+ }) {
2085
+ const id = useControlId(props.name);
2086
+ const field = useBoundField(props.value, bindings?.value, "", props);
2087
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2088
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: LABEL, children: props.label }),
2089
+ /* @__PURE__ */ jsx(
2090
+ "textarea",
2091
+ {
2092
+ id,
2093
+ name: props.name,
2094
+ rows: props.rows ?? 4,
2095
+ className: cn(fieldControlClass, "px-3 py-2"),
2096
+ placeholder: props.placeholder ?? void 0,
2097
+ value: field.value,
2098
+ "aria-invalid": field.error ? true : void 0,
2099
+ onChange: (event) => {
2100
+ field.setValue(event.target.value);
2101
+ field.validateOnChange();
2102
+ },
2103
+ onBlur: field.validateOnBlur
2104
+ }
2105
+ ),
2106
+ /* @__PURE__ */ jsx(FieldError, { message: field.error })
2107
+ ] });
2108
+ }
2109
+ function Radio({
2110
+ props,
2111
+ bindings,
2112
+ emit
2113
+ }) {
2114
+ const id = useControlId(props.name);
2115
+ const field = useBoundField(props.value, bindings?.value, "", props);
2116
+ return /* @__PURE__ */ jsxs("fieldset", { className: "space-y-2", "aria-invalid": field.error ? true : void 0, children: [
2117
+ /* @__PURE__ */ jsx("legend", { className: LABEL, children: props.label }),
2118
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
2119
+ /* @__PURE__ */ jsx(
2120
+ "input",
2121
+ {
2122
+ type: "radio",
2123
+ name: id,
2124
+ value: option,
2125
+ checked: field.value === option,
2126
+ className: "size-4 accent-primary",
2127
+ onChange: () => {
2128
+ field.setValue(option);
2129
+ field.validateOnChange();
2130
+ emit("change");
2131
+ }
2132
+ }
2133
+ ),
2134
+ /* @__PURE__ */ jsx("span", { children: option })
2135
+ ] }, `${index}-${option}`)) }),
2136
+ /* @__PURE__ */ jsx(FieldError, { message: field.error })
2137
+ ] });
2138
+ }
2139
+ function Checkbox({
2140
+ props,
2141
+ bindings,
2142
+ emit
2143
+ }) {
2144
+ const id = useControlId(props.name);
2145
+ const field = useBoundField(props.checked, bindings?.checked, false, props);
2146
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2147
+ /* @__PURE__ */ jsxs("label", { htmlFor: id, className: "flex items-center gap-2 text-sm", children: [
2148
+ /* @__PURE__ */ jsx(
2149
+ "input",
2150
+ {
2151
+ id,
2152
+ name: props.name,
2153
+ type: "checkbox",
2154
+ className: "size-4 accent-primary",
2155
+ checked: field.value,
2156
+ "aria-invalid": field.error ? true : void 0,
2157
+ onChange: (event) => {
2158
+ field.setValue(event.target.checked);
2159
+ field.validateOnChange();
2160
+ emit("change");
2161
+ }
2162
+ }
2163
+ ),
2164
+ /* @__PURE__ */ jsx("span", { children: props.label })
2165
+ ] }),
2166
+ /* @__PURE__ */ jsx(FieldError, { message: field.error })
2167
+ ] });
2168
+ }
2169
+ function Switch2({
2170
+ props,
2171
+ bindings,
2172
+ emit
2173
+ }) {
2174
+ const id = useControlId(props.name);
2175
+ const field = useBoundField(props.checked, bindings?.checked, false, props);
2176
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2177
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2178
+ /* @__PURE__ */ jsx(
2179
+ Switch,
2180
+ {
2181
+ id,
2182
+ name: props.name,
2183
+ checked: field.value,
2184
+ "aria-invalid": field.error ? true : void 0,
2185
+ onCheckedChange: (next) => {
2186
+ field.setValue(next);
2187
+ field.validateOnChange();
2188
+ emit("change");
2189
+ }
2190
+ }
2191
+ ),
2192
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-sm", children: props.label })
2193
+ ] }),
2194
+ /* @__PURE__ */ jsx(FieldError, { message: field.error })
2195
+ ] });
2196
+ }
2197
+ var BUTTON = {
2198
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
2199
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2200
+ danger: "bg-destructive text-white hover:bg-destructive/90"
2201
+ };
2202
+ function Button({
2203
+ props,
2204
+ emit
2205
+ }) {
2206
+ return /* @__PURE__ */ jsx(
2207
+ "button",
2208
+ {
2209
+ type: "button",
2210
+ disabled: props.disabled ?? false,
2211
+ className: cn(
2212
+ "inline-flex min-h-11 w-fit items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors",
2213
+ "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2214
+ "disabled:pointer-events-none disabled:opacity-50",
2215
+ pick(BUTTON, props.variant, "primary")
2216
+ ),
2217
+ onClick: () => emit("press"),
2218
+ children: props.label
2219
+ }
2220
+ );
2221
+ }
2222
+ var DescriptorContext = React3.createContext({});
2223
+ function useDescriptorScope() {
2224
+ return React3.useContext(DescriptorContext);
2225
+ }
2226
+ function DescriptorProvider({
2227
+ scope,
2228
+ children
2229
+ }) {
2230
+ return /* @__PURE__ */ jsx(DescriptorContext.Provider, { value: scope, children });
2231
+ }
2232
+ function Unresolved({ path, side }) {
2233
+ return /* @__PURE__ */ jsxs(
2234
+ "p",
2235
+ {
2236
+ role: "alert",
2237
+ className: "rounded-md border border-destructive/50 px-2.5 py-1.5 text-[12px] text-destructive",
2238
+ children: [
2239
+ side === "input" ? "No input" : "No result",
2240
+ " at ",
2241
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: path })
2242
+ ]
2243
+ }
2244
+ );
2245
+ }
2246
+ function encodeSegment(segment) {
2247
+ return segment.replace(/_/g, "_u").replace(/-/g, "_d").replace(/~/g, "_t");
2248
+ }
2249
+ function decodeSegment(segment) {
2250
+ return segment.replace(
2251
+ /_([udt])/g,
2252
+ (_match, code) => code === "u" ? "_" : code === "d" ? "-" : "~"
2253
+ );
2254
+ }
2255
+ function domIdFor(prefix, path) {
2256
+ return `${prefix ?? "gen"}${path.split("/").map(encodeSegment).join("-")}`;
2257
+ }
2258
+ function pathFromDomId(prefix, id) {
2259
+ const head = prefix ?? "gen";
2260
+ if (!id.startsWith(head)) return void 0;
2261
+ const [own = "", ...children] = id.slice(head.length).split(".");
2262
+ if (!own.startsWith("-")) return void 0;
2263
+ const path = own.split("-").map(decodeSegment).join("/");
2264
+ return `${path}${children.map((child) => `/${child}`).join("")}`;
2265
+ }
2266
+ function useAbsolutePath(path) {
2267
+ const repeat = useRepeatScope();
2268
+ if (path.startsWith("/")) return path;
2269
+ return repeat ? `${repeat.basePath}/${path}` : void 0;
2270
+ }
2271
+ function MthdsField({ props }) {
2272
+ const scope = React3.useContext(DescriptorContext);
2273
+ const path = useAbsolutePath(props.path) ?? "";
2274
+ const field = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
2275
+ const value = useStateValue(path);
2276
+ const { set } = useStateStore();
2277
+ const onChange = React3.useCallback((next) => set(path, next), [set, path]);
2278
+ if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "input" });
2279
+ return /* @__PURE__ */ jsx(
2280
+ FieldRenderer,
2281
+ {
2282
+ field,
2283
+ value,
2284
+ onChange,
2285
+ id: domIdFor(scope.idPrefix, path),
2286
+ env: scope.env
2287
+ }
2288
+ );
2289
+ }
2290
+ function MthdsResult({ props }) {
2291
+ const scope = React3.useContext(DescriptorContext);
2292
+ const path = useAbsolutePath(props.path) ?? "";
2293
+ const field = scope.result && path ? resultFieldAtPath(scope.result, path) : void 0;
2294
+ const value = useStateValue(path);
2295
+ if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "result" });
2296
+ return /* @__PURE__ */ jsx(ResultField, { field, value, hideLabel: props.hideLabel ?? false });
2297
+ }
2298
+ function AccessibleSelect({ props, bindings, emit }) {
2299
+ const [boundValue, setBoundValue] = useBoundProp(
2300
+ props.value ?? void 0,
2301
+ bindings?.value
2302
+ );
2303
+ const [localValue, setLocalValue] = React3.useState("");
2304
+ const isBound = Boolean(bindings?.value);
2305
+ const value = isBound ? boundValue ?? "" : localValue;
2306
+ const setValue = isBound ? setBoundValue : setLocalValue;
2307
+ const validateOn = props.validateOn ?? "change";
2308
+ const hasValidation = Boolean(bindings?.value && props.checks?.length);
2309
+ const { errors, validate } = useFieldValidation(
2310
+ bindings?.value ?? "",
2311
+ hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
2312
+ );
2313
+ const id = useControlId(props.name);
2314
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2315
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: "block text-sm leading-none font-medium", children: props.label }),
2316
+ /* @__PURE__ */ jsxs(
2317
+ Select,
2318
+ {
2319
+ value,
2320
+ onValueChange: (next) => {
2321
+ setValue(next);
2322
+ if (hasValidation && validateOn === "change") validate();
2323
+ emit("change");
2324
+ },
2325
+ children: [
2326
+ /* @__PURE__ */ jsx(SelectTrigger, { id, className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: props.placeholder ?? "Select..." }) }),
2327
+ /* @__PURE__ */ jsx(SelectContent, { children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsx(SelectItem, { value: option, children: option }, `${index}-${option}`)) })
2328
+ ]
2329
+ }
2330
+ ),
2331
+ errors.length > 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors[0] }) : null
2332
+ ] });
2333
+ }
2334
+ function valueAt(row, relativePath) {
2335
+ let current = row;
2336
+ for (const segment of relativePath.split("/").filter((part) => part.length > 0)) {
2337
+ if (typeof current !== "object" || current === null) return void 0;
2338
+ current = current[segment];
2339
+ }
2340
+ return current;
2341
+ }
2342
+ var CELL_NUMBER = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 });
2343
+ function formatCell(value) {
2344
+ if (value === null || value === void 0 || value === "") return "\u2014";
2345
+ if (typeof value === "boolean") return value ? "yes" : "no";
2346
+ if (typeof value === "number") return CELL_NUMBER.format(value);
2347
+ if (typeof value === "string") return value;
2348
+ if (Array.isArray(value)) return value.map(formatCell).join(", ");
2349
+ return JSON.stringify(value);
2350
+ }
2351
+ function DataTable({ props }) {
2352
+ const rows = Array.isArray(props.rows) ? props.rows : [];
2353
+ const columns = props.columns ?? [];
2354
+ return /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-full border-collapse text-[13px]", children: [
2355
+ props.caption ? /* @__PURE__ */ jsx("caption", { className: "px-2.5 py-1.5 text-start text-[12px] text-muted-foreground", children: props.caption }) : null,
2356
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border bg-muted", children: columns.map((column) => /* @__PURE__ */ jsx(
2357
+ "th",
2358
+ {
2359
+ scope: "col",
2360
+ className: "whitespace-nowrap px-2.5 py-1.5 text-start font-semibold text-foreground",
2361
+ children: column.label
2362
+ },
2363
+ column.path
2364
+ )) }) }),
2365
+ /* @__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: formatCell(valueAt(row, column.path)) }, column.path)) }, index)) })
2366
+ ] }) });
2367
+ }
2368
+ function numberFormat(format) {
2369
+ switch (format) {
2370
+ case "integer":
2371
+ return new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
2372
+ case "decimal":
2373
+ return new Intl.NumberFormat("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
2374
+ case "compact":
2375
+ return new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
2376
+ case "plain":
2377
+ return new Intl.NumberFormat("en-US", { maximumFractionDigits: 20, useGrouping: false });
2378
+ default:
2379
+ return format;
2380
+ }
2381
+ }
2382
+ function Metric({ props }) {
2383
+ const value = props.value;
2384
+ const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : value === null || value === void 0 || value === "" ? "\u2014" : String(value);
2385
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
2386
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: props.label }),
2387
+ /* @__PURE__ */ jsxs("span", { className: "text-2xl font-semibold tabular-nums text-foreground", children: [
2388
+ text,
2389
+ props.unit ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-sm font-normal text-muted-foreground", children: props.unit }) : null
2390
+ ] })
2391
+ ] });
2392
+ }
2393
+ var SPLIT_COLUMNS = {
2394
+ "1:1": "sm:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]",
2395
+ "1:2": "sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]",
2396
+ "2:1": "sm:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]"
2397
+ };
2398
+ var SPLIT_GAP = { md: "gap-4", lg: "gap-6", xl: "gap-8" };
2399
+ function Split({
2400
+ props,
2401
+ children
2402
+ }) {
2403
+ return /* @__PURE__ */ jsx(
2404
+ "div",
2405
+ {
2406
+ className: cn(
2407
+ "grid grid-cols-1 items-start",
2408
+ pick(SPLIT_COLUMNS, props.ratio, "1:2"),
2409
+ pick(SPLIT_GAP, props.gap, "lg")
2410
+ ),
2411
+ children
2412
+ }
2413
+ );
2414
+ }
2415
+ function Tabs({ props, children }) {
2416
+ const tabs = props.tabs ?? [];
2417
+ const panels = React3.Children.toArray(children);
2418
+ const [value, setValue] = React3.useState(tabs[0]?.value ?? "");
2419
+ return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: setValue, className: "w-full", children: [
2420
+ /* @__PURE__ */ jsx(TabsPrimitive.List, { className: "inline-flex h-10 items-center justify-start rounded-md bg-muted p-1 text-muted-foreground", children: tabs.map((tab) => /* @__PURE__ */ jsx(
2421
+ TabsPrimitive.Trigger,
2422
+ {
2423
+ value: tab.value,
2424
+ className: "inline-flex items-center justify-center rounded-sm px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-hidden data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
2425
+ children: tab.label
2426
+ },
2427
+ tab.value
2428
+ )) }),
2429
+ tabs.map((tab, index) => /* @__PURE__ */ jsx(
2430
+ TabsPrimitive.Content,
2431
+ {
2432
+ value: tab.value,
2433
+ className: "mt-4 focus-visible:outline-hidden",
2434
+ children: panels[index] ?? null
2435
+ },
2436
+ tab.value
2437
+ ))
2438
+ ] });
2439
+ }
2440
+ var BUTTON_BASE = "inline-flex h-10 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50";
2441
+ var PRIMARY_BUTTON = cn(BUTTON_BASE, "bg-primary text-primary-foreground hover:bg-primary/90");
2442
+ var SECONDARY_BUTTON = cn(
2443
+ BUTTON_BASE,
2444
+ "border border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground"
2445
+ );
2446
+ function Steps({ props, children }) {
2447
+ const steps = props.steps ?? [];
2448
+ const panels = React3.Children.toArray(children);
2449
+ const [index, setIndex] = React3.useState(0);
2450
+ const last = steps.length - 1;
2451
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
2452
+ /* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-x-5 gap-y-2", children: steps.map((label, position) => /* @__PURE__ */ jsxs(
2453
+ "li",
2454
+ {
2455
+ "aria-current": position === index ? "step" : void 0,
2456
+ className: cn(
2457
+ "flex items-center gap-2 text-sm",
2458
+ position === index ? "font-medium text-foreground" : "text-muted-foreground"
2459
+ ),
2460
+ children: [
2461
+ /* @__PURE__ */ jsx(
2462
+ "span",
2463
+ {
2464
+ className: cn(
2465
+ "flex h-6 w-6 items-center justify-center rounded-full text-[12px] font-semibold tabular-nums",
2466
+ position < index ? "bg-primary/15 text-primary" : position === index ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"
2467
+ ),
2468
+ children: position + 1
2469
+ }
2470
+ ),
2471
+ label
2472
+ ]
2473
+ },
2474
+ `${position}-${label}`
2475
+ )) }),
2476
+ /* @__PURE__ */ jsx("div", { children: panels[index] ?? null }),
2477
+ index > 0 || index < last ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
2478
+ index > 0 ? /* @__PURE__ */ jsx(
2479
+ "button",
2480
+ {
2481
+ type: "button",
2482
+ "data-testid": "steps-back",
2483
+ onClick: () => setIndex((current) => Math.max(0, current - 1)),
2484
+ className: SECONDARY_BUTTON,
2485
+ children: props.backLabel ?? "Back"
2486
+ }
2487
+ ) : /* @__PURE__ */ jsx("span", {}),
2488
+ index < last ? /* @__PURE__ */ jsx(
2489
+ "button",
2490
+ {
2491
+ type: "button",
2492
+ "data-testid": "steps-next",
2493
+ onClick: () => setIndex((current) => Math.min(last, current + 1)),
2494
+ className: PRIMARY_BUTTON,
2495
+ children: props.nextLabel ?? "Next"
2496
+ }
2497
+ ) : null
2498
+ ] }) : null
2499
+ ] });
2500
+ }
2501
+ var ICONS = {
2502
+ Sparkles,
2503
+ Rocket,
2504
+ Compass,
2505
+ Map: Map$1,
2506
+ MapPin,
2507
+ Route,
2508
+ Plane,
2509
+ Train,
2510
+ Car,
2511
+ Ship,
2512
+ Hotel,
2513
+ Home,
2514
+ Building2,
2515
+ Landmark,
2516
+ Globe,
2517
+ Mountain,
2518
+ Leaf,
2519
+ Sun,
2520
+ Moon,
2521
+ Calendar,
2522
+ Clock,
2523
+ Hourglass,
2524
+ Users,
2525
+ User,
2526
+ Baby,
2527
+ Accessibility,
2528
+ Heart,
2529
+ Star,
2530
+ Utensils,
2531
+ Coffee,
2532
+ Music,
2533
+ Camera,
2534
+ Image,
2535
+ Ticket,
2536
+ Gift,
2537
+ Wallet,
2538
+ Banknote,
2539
+ Coins,
2540
+ Receipt,
2541
+ Percent,
2542
+ Hash,
2543
+ TrendingUp,
2544
+ BarChart3,
2545
+ FileText,
2546
+ Upload,
2547
+ Paperclip,
2548
+ Mail,
2549
+ Phone,
2550
+ Tag,
2551
+ Layers,
2552
+ ListChecks,
2553
+ CheckCircle2,
2554
+ AlertCircle,
2555
+ Info,
2556
+ Shield,
2557
+ Flag,
2558
+ Bookmark,
2559
+ Briefcase,
2560
+ Package,
2561
+ Truck,
2562
+ Lightbulb,
2563
+ Zap,
2564
+ Pencil,
2565
+ Send
2566
+ };
2567
+ function Icon({ props }) {
2568
+ const Glyph = ICONS[props.name];
2569
+ if (!Glyph) return null;
2570
+ const size = props.size === "lg" ? "h-7 w-7" : props.size === "sm" ? "h-4 w-4" : "h-5 w-5";
2571
+ return /* @__PURE__ */ jsx(Glyph, { "aria-hidden": "true", className: cn(size, "shrink-0 text-muted-foreground") });
2572
+ }
2573
+ function Segmented({ props, bindings, emit }) {
2574
+ const [boundValue, setBoundValue] = useBoundProp(
2575
+ props.value ?? void 0,
2576
+ bindings?.value
2577
+ );
2578
+ const [localValue, setLocalValue] = React3.useState("");
2579
+ const isBound = Boolean(bindings?.value);
2580
+ const value = isBound ? boundValue ?? "" : localValue;
2581
+ const setValue = isBound ? setBoundValue : setLocalValue;
2582
+ const labelId = useControlId(props.name);
2583
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2584
+ /* @__PURE__ */ jsx("span", { id: labelId, className: "block text-sm leading-none font-medium", children: props.label }),
2585
+ /* @__PURE__ */ jsx(
2586
+ ToggleGroup,
2587
+ {
2588
+ type: "single",
2589
+ "aria-labelledby": labelId,
2590
+ value,
2591
+ onValueChange: (next) => {
2592
+ if (!next) return;
2593
+ setValue(next);
2594
+ emit("change");
2595
+ },
2596
+ className: "flex-wrap justify-start gap-1.5",
2597
+ children: (props.options ?? []).map((option) => /* @__PURE__ */ jsx(
2598
+ ToggleGroupItem,
2599
+ {
2600
+ value: option,
2601
+ variant: "outline",
2602
+ size: "sm",
2603
+ className: "rounded-full px-3.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground",
2604
+ children: option
2605
+ },
2606
+ option
2607
+ ))
2608
+ }
2609
+ )
2610
+ ] });
2611
+ }
2612
+ function NumberInput({ props, bindings, emit }) {
2613
+ const [boundValue, setBoundValue] = useBoundProp(
2614
+ props.value ?? void 0,
2615
+ bindings?.value
2616
+ );
2617
+ const [localValue, setLocalValue] = React3.useState(void 0);
2618
+ const isBound = Boolean(bindings?.value);
2619
+ const value = isBound ? boundValue : localValue;
2620
+ const setValue = isBound ? setBoundValue : setLocalValue;
2621
+ const id = useControlId(props.name);
2622
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2623
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: "block text-sm leading-none font-medium", children: props.label }),
2624
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2625
+ /* @__PURE__ */ jsx(
2626
+ "input",
2627
+ {
2628
+ id,
2629
+ type: "number",
2630
+ inputMode: "decimal",
2631
+ value: typeof value === "number" ? value : "",
2632
+ min: props.min ?? void 0,
2633
+ max: props.max ?? void 0,
2634
+ step: props.step ?? "any",
2635
+ placeholder: props.placeholder ?? void 0,
2636
+ onChange: (event) => {
2637
+ const raw = event.target.value;
2638
+ setValue(raw === "" ? void 0 : Number(raw));
2639
+ emit("change");
2640
+ },
2641
+ className: cn(
2642
+ fieldControlClass,
2643
+ "h-10 px-3 tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none"
2644
+ )
2645
+ }
2646
+ ),
2647
+ props.unit ? /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: props.unit }) : null
2648
+ ] })
2649
+ ] });
2650
+ }
2651
+ var components2 = {
2652
+ Card: (ctx) => /* @__PURE__ */ jsx(Card, { ...ctx }),
2653
+ // A vertical Stack stretches its children unless the spec says otherwise:
2654
+ // hugging the content is the one layout a result page never wants, since a
2655
+ // table or a grid inside it would stop short of the page's width.
2656
+ Stack: (ctx) => /* @__PURE__ */ jsx(Stack, { ...ctx }),
2657
+ Grid: (ctx) => /* @__PURE__ */ jsx(Grid, { ...ctx }),
2658
+ Separator: (ctx) => /* @__PURE__ */ jsx(Separator, { ...ctx }),
2659
+ Collapsible: (ctx) => /* @__PURE__ */ jsx(Collapsible, { ...ctx }),
2660
+ Heading: (ctx) => /* @__PURE__ */ jsx(Heading, { ...ctx }),
2661
+ Text: (ctx) => /* @__PURE__ */ jsx(Text, { ...ctx }),
2662
+ Badge: (ctx) => /* @__PURE__ */ jsx(Badge, { ...ctx }),
2663
+ Alert: (ctx) => /* @__PURE__ */ jsx(Alert, { ...ctx }),
2664
+ Progress: (ctx) => /* @__PURE__ */ jsx(Progress, { ...ctx }),
2665
+ Avatar: (ctx) => /* @__PURE__ */ jsx(Avatar, { ...ctx }),
2666
+ Input: (ctx) => /* @__PURE__ */ jsx(Input, { ...ctx }),
2667
+ Textarea: (ctx) => /* @__PURE__ */ jsx(Textarea, { ...ctx }),
2668
+ // A plain label beside a trigger leaves the trigger with no accessible name,
2669
+ // which axe reports as a button without one (`a11y` runs at error). This one
2670
+ // is the package's own vendored select under a label that names the trigger.
2671
+ Select: (ctx) => /* @__PURE__ */ jsx(AccessibleSelect, { ...ctx }),
2672
+ Radio: (ctx) => /* @__PURE__ */ jsx(Radio, { ...ctx }),
2673
+ Checkbox: (ctx) => /* @__PURE__ */ jsx(Checkbox, { ...ctx }),
2674
+ Switch: (ctx) => /* @__PURE__ */ jsx(Switch2, { ...ctx }),
2675
+ Button: (ctx) => /* @__PURE__ */ jsx(Button, { ...ctx }),
2676
+ Split: (ctx) => /* @__PURE__ */ jsx(Split, { ...ctx }),
2677
+ Tabs: (ctx) => /* @__PURE__ */ jsx(Tabs, { ...ctx }),
2678
+ Steps: (ctx) => /* @__PURE__ */ jsx(Steps, { ...ctx }),
2679
+ Icon: (ctx) => /* @__PURE__ */ jsx(Icon, { ...ctx }),
2680
+ Segmented: (ctx) => /* @__PURE__ */ jsx(Segmented, { ...ctx }),
2681
+ NumberInput: (ctx) => /* @__PURE__ */ jsx(NumberInput, { ...ctx }),
2682
+ // Ours are React components (they use hooks), so each is MOUNTED rather than
2683
+ // called: a render function that called hooks itself would run them inside
2684
+ // the registry's wrapper and break the moment the wrapper re-ordered them.
2685
+ MthdsField: (ctx) => /* @__PURE__ */ jsx(MthdsField, { ...ctx }),
2686
+ MthdsResult: (ctx) => /* @__PURE__ */ jsx(MthdsResult, { ...ctx }),
2687
+ DataTable: (ctx) => /* @__PURE__ */ jsx(DataTable, { ...ctx }),
2688
+ Metric: (ctx) => /* @__PURE__ */ jsx(Metric, { ...ctx })
2689
+ };
2690
+ var generativeRenderers = components2;
2691
+ var ResultSlotContext = React3.createContext(null);
2692
+ function ResultSlotProvider({
2693
+ slot,
2694
+ children
2695
+ }) {
2696
+ return /* @__PURE__ */ jsx(ResultSlotContext.Provider, { value: slot, children });
2697
+ }
2698
+ function useResultSlot() {
2699
+ return React3.useContext(ResultSlotContext);
2700
+ }
2701
+ var CONTAINER = "mx-auto w-full max-w-6xl px-6 sm:px-8";
2702
+ var LABEL2 = "block text-[13.5px] leading-none font-medium text-foreground";
2703
+ function AppBar({ props }) {
2704
+ const brand = useBrand();
2705
+ return /* @__PURE__ */ jsx("header", { className: "border-b border-border", children: /* @__PURE__ */ jsxs("div", { className: cn(CONTAINER, "flex h-16 items-center gap-5"), children: [
2706
+ /* @__PURE__ */ jsx(
2707
+ "img",
2708
+ {
2709
+ src: brand.logo.onLight,
2710
+ alt: brand.name,
2711
+ referrerPolicy: "no-referrer",
2712
+ className: "h-7 w-auto dark:hidden"
2713
+ }
2714
+ ),
2715
+ /* @__PURE__ */ jsx(
2716
+ "img",
2717
+ {
2718
+ src: brand.logo.onDark,
2719
+ alt: brand.name,
2720
+ referrerPolicy: "no-referrer",
2721
+ className: "hidden h-7 w-auto dark:block"
2722
+ }
2723
+ ),
2724
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "h-5 w-px bg-border" }),
2725
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground/80", children: props.app }),
2726
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex min-w-0 items-center gap-6", children: [
2727
+ 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(
2728
+ "a",
2729
+ {
2730
+ href: "#",
2731
+ onClick: (event) => event.preventDefault(),
2732
+ className: "text-sm text-muted-foreground transition-colors hover:text-foreground",
2733
+ children: link
2734
+ },
2735
+ link
2736
+ )) }) : null,
2737
+ props.tag ? /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate rounded-lg border border-primary/40 bg-primary/10 px-2.5 py-1 font-mono text-[11px] text-primary", children: props.tag }) : null
2738
+ ] })
2739
+ ] }) });
2740
+ }
2741
+ function Hero({ props }) {
2742
+ return /* @__PURE__ */ jsxs("section", { className: "pt-12 pb-10 sm:pt-14 sm:pb-12", children: [
2743
+ props.eyebrow ? /* @__PURE__ */ jsx("p", { className: "mb-4 text-[11px] font-medium tracking-[0.15em] text-primary uppercase", children: props.eyebrow }) : null,
2744
+ /* @__PURE__ */ jsx("h1", { className: "max-w-2xl text-4xl font-bold tracking-tight text-foreground sm:text-[44px] sm:leading-[1.15]", children: props.headline }),
2745
+ props.lede ? /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-2xl text-[17px] leading-relaxed text-muted-foreground", children: props.lede }) : null
2746
+ ] });
2747
+ }
2748
+ function Workspace({ props, children }) {
2749
+ const [work, rail] = React3.Children.toArray(children);
2750
+ const railLeft = props.rail === "left";
2751
+ return /* @__PURE__ */ jsxs(
2752
+ "div",
2753
+ {
2754
+ className: cn(
2755
+ CONTAINER,
2756
+ "grid grid-cols-1 gap-10 pb-16 lg:gap-14",
2757
+ railLeft ? "lg:grid-cols-[360px_minmax(0,1fr)]" : "lg:grid-cols-[minmax(0,1fr)_360px]"
2758
+ ),
2759
+ children: [
2760
+ /* @__PURE__ */ jsxs("div", { className: cn("min-w-0", railLeft && "lg:order-2"), children: [
2761
+ work,
2762
+ /* @__PURE__ */ jsx(ResultPanel, {})
2763
+ ] }),
2764
+ /* @__PURE__ */ jsx(
2765
+ "aside",
2766
+ {
2767
+ className: cn(
2768
+ "lg:sticky lg:top-6 lg:self-start lg:pt-12 sm:lg:pt-14",
2769
+ railLeft && "lg:order-1"
2770
+ ),
2771
+ children: rail
2772
+ }
2773
+ )
2774
+ ]
2775
+ }
2776
+ );
2777
+ }
2778
+ function ResultPanel() {
2779
+ const slot = useResultSlot();
2780
+ if (!slot?.content) return null;
2781
+ return /* @__PURE__ */ jsxs("section", { className: "border-t border-border py-9", "data-testid": "result-panel", "aria-live": "polite", children: [
2782
+ /* @__PURE__ */ jsx("h2", { className: "mb-6 text-xl font-semibold tracking-tight text-foreground", children: slot.title ?? "Result" }),
2783
+ slot.content
2784
+ ] });
2785
+ }
2786
+ function Section({ props, children }) {
2787
+ return /* @__PURE__ */ jsxs("section", { className: "border-t border-border py-9 first:border-t-0 first:pt-0", children: [
2788
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
2789
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-3", children: [
2790
+ props.number ? /* @__PURE__ */ jsx("span", { className: "font-mono text-[12px] text-primary", children: props.number }) : null,
2791
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight text-foreground", children: props.title })
2792
+ ] }),
2793
+ props.lede ? /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground", children: props.lede }) : null
2794
+ ] }),
2795
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children })
2796
+ ] });
2797
+ }
2798
+ function Rail({ props, children }) {
2799
+ return (
2800
+ // An arbitrary value reads the token directly, so it does NOT go through
2801
+ // the `@theme inline` mapping and does not inherit its fallback - it has to
2802
+ // carry its own, or a host that defines no tokens loses the declaration
2803
+ // outright. See src/styles/tailwind-entry.css.
2804
+ /* @__PURE__ */ jsxs("div", { className: "rounded-[calc(var(--radius,0.5rem)*1.5)] border border-border bg-card p-7 text-card-foreground shadow-xl", children: [
2805
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold tracking-[0.15em] text-muted-foreground uppercase", children: props.title }),
2806
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-col", children })
2807
+ ] })
2808
+ );
2809
+ }
2810
+ function present(value) {
2811
+ return value !== void 0 && value !== null && value !== "";
2812
+ }
2813
+ function SummaryRow({ props }) {
2814
+ const text = [props.value, props.detail].filter(present).map(String).join(props.separator ?? " ");
2815
+ 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: [
2816
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] text-muted-foreground", children: props.label }),
2817
+ 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" })
2818
+ ] });
2819
+ }
2820
+ function Cta({ props, emit }) {
2821
+ return /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
2822
+ /* @__PURE__ */ jsx(
2823
+ "button",
2824
+ {
2825
+ type: "button",
2826
+ onClick: () => emit("press"),
2827
+ className: cn(
2828
+ "inline-flex h-12 w-full items-center justify-center rounded-lg bg-primary px-6 text-sm font-semibold text-primary-foreground",
2829
+ // The fallback is not decoration here either - see Rail above.
2830
+ "shadow-[0_0_28px_color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_35%,transparent)] transition-all hover:bg-primary/90 hover:shadow-[0_0_44px_color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_50%,transparent)]",
2831
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-hidden"
2832
+ ),
2833
+ children: props.label
2834
+ }
2835
+ ),
2836
+ props.hint ? /* @__PURE__ */ jsx("p", { className: "mt-3 text-center text-[12px] leading-relaxed text-muted-foreground", children: props.hint }) : null
2837
+ ] });
2838
+ }
2839
+ function Footer({ props }) {
2840
+ return /* @__PURE__ */ jsx("footer", { className: "border-t border-border", children: /* @__PURE__ */ jsxs(
2841
+ "div",
2842
+ {
2843
+ className: cn(
2844
+ CONTAINER,
2845
+ // Wraps, and the tag may break anywhere: a pipe's code is one long
2846
+ // word, and at phone width an unbreakable one widened the document
2847
+ // past the viewport.
2848
+ "flex flex-wrap items-center justify-between gap-x-6 gap-y-2 py-6 text-[12px] text-muted-foreground"
2849
+ ),
2850
+ children: [
2851
+ /* @__PURE__ */ jsx("span", { children: props.text }),
2852
+ props.tag ? /* @__PURE__ */ jsx("span", { className: "min-w-0 font-mono text-[11px] tracking-wider break-all text-muted-foreground/70 uppercase", children: props.tag }) : null
2853
+ ]
2854
+ }
2855
+ ) });
2856
+ }
2857
+ function useTextField(props, bindings) {
2858
+ const [boundValue, setBoundValue] = useBoundProp(
2859
+ props.value ?? void 0,
2860
+ bindings?.value
2861
+ );
2862
+ const [localValue, setLocalValue] = React3.useState("");
2863
+ const isBound = Boolean(bindings?.value);
2864
+ const value = isBound ? boundValue ?? "" : localValue;
2865
+ const setValue = isBound ? setBoundValue : setLocalValue;
2866
+ const validateOn = props.validateOn ?? "blur";
2867
+ const hasValidation = Boolean(bindings?.value && props.checks?.length);
2868
+ const { errors, validate } = useFieldValidation(
2869
+ bindings?.value ?? "",
2870
+ hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
2871
+ );
2872
+ const onChange = (next) => {
2873
+ setValue(next);
2874
+ if (hasValidation && validateOn === "change") validate();
2875
+ };
2876
+ const onBlur = () => {
2877
+ if (hasValidation && validateOn === "blur") validate();
2878
+ };
2879
+ return { value, errors, onChange, onBlur };
2880
+ }
2881
+ function BrandInput({
2882
+ props,
2883
+ bindings,
2884
+ emit
2885
+ }) {
2886
+ const field = useTextField(props, bindings);
2887
+ const id = useControlId(props.name);
2888
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2889
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: LABEL2, children: props.label }),
2890
+ /* @__PURE__ */ jsx(
2891
+ "input",
2892
+ {
2893
+ id,
2894
+ name: props.name,
2895
+ type: props.type ?? "text",
2896
+ value: field.value,
2897
+ placeholder: props.placeholder ?? "",
2898
+ "aria-invalid": field.errors.length > 0 || void 0,
2899
+ onChange: (event) => field.onChange(event.target.value),
2900
+ onBlur: () => {
2901
+ field.onBlur();
2902
+ emit("blur");
2903
+ },
2904
+ onFocus: () => emit("focus"),
2905
+ onKeyDown: (event) => {
2906
+ if (event.key === "Enter") emit("submit");
2907
+ },
2908
+ className: cn(fieldControlClass, "h-11 px-3.5")
2909
+ }
2910
+ ),
2911
+ field.errors[0] ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[11px] text-destructive", children: field.errors[0] }) : null
2912
+ ] });
2913
+ }
2914
+ function BrandTextarea({
2915
+ props,
2916
+ bindings
2917
+ }) {
2918
+ const field = useTextField(props, bindings);
2919
+ const id = useControlId(props.name);
2920
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2921
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: LABEL2, children: props.label }),
2922
+ /* @__PURE__ */ jsx(
2923
+ "textarea",
2924
+ {
2925
+ id,
2926
+ name: props.name,
2927
+ rows: props.rows ?? 3,
2928
+ value: field.value,
2929
+ placeholder: props.placeholder ?? "",
2930
+ "aria-invalid": field.errors.length > 0 || void 0,
2931
+ onChange: (event) => field.onChange(event.target.value),
2932
+ onBlur: field.onBlur,
2933
+ className: cn(fieldControlClass, "px-3.5 py-2.5 leading-relaxed")
2934
+ }
2935
+ ),
2936
+ field.errors[0] ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[11px] text-destructive", children: field.errors[0] }) : null
2937
+ ] });
2938
+ }
2939
+ var { registry: generativeRegistry } = defineRegistry(catalog, {
2940
+ components: {
2941
+ ...generativeRenderers,
2942
+ Input: (ctx) => /* @__PURE__ */ jsx(BrandInput, { ...ctx }),
2943
+ Textarea: (ctx) => /* @__PURE__ */ jsx(BrandTextarea, { ...ctx }),
2944
+ AppBar: (ctx) => /* @__PURE__ */ jsx(AppBar, { ...ctx }),
2945
+ Hero: (ctx) => /* @__PURE__ */ jsx(Hero, { ...ctx }),
2946
+ Workspace: (ctx) => /* @__PURE__ */ jsx(Workspace, { ...ctx }),
2947
+ Section: (ctx) => /* @__PURE__ */ jsx(Section, { ...ctx }),
2948
+ Rail: (ctx) => /* @__PURE__ */ jsx(Rail, { ...ctx }),
2949
+ SummaryRow: (ctx) => /* @__PURE__ */ jsx(SummaryRow, { ...ctx }),
2950
+ Cta: (ctx) => /* @__PURE__ */ jsx(Cta, { ...ctx }),
2951
+ Footer: (ctx) => /* @__PURE__ */ jsx(Footer, { ...ctx })
2952
+ }
2953
+ });
2954
+ function GenerativePage({
2955
+ spec,
2956
+ store,
2957
+ scope,
2958
+ onRun,
2959
+ loading,
2960
+ registry = generativeRegistry,
2961
+ brand
2962
+ }) {
2963
+ const { inputs, result, env, idPrefix } = scope;
2964
+ const stableScope = React3.useMemo(
2965
+ () => ({ inputs, result, env, idPrefix }),
2966
+ [inputs, result, env, idPrefix]
2967
+ );
2968
+ const latest = React3.useRef({ onRun, store });
2969
+ React3.useEffect(() => {
2970
+ latest.current = { onRun, store };
2971
+ });
2972
+ const [handlers] = React3.useState(() => ({
2973
+ run: () => {
2974
+ latest.current.onRun?.(latest.current.store.getSnapshot());
2975
+ }
2976
+ }));
2977
+ const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry, store, handlers, children: /* @__PURE__ */ jsx(Renderer, { spec, registry, loading }) }) });
2978
+ return brand ? /* @__PURE__ */ jsx(BrandProvider, { manifest: brand, children: page }) : page;
2979
+ }
2980
+ function useStoreSnapshot(store) {
2981
+ return React3.useSyncExternalStore(
2982
+ store.subscribe,
2983
+ store.getSnapshot,
2984
+ store.getServerSnapshot ?? store.getSnapshot
2985
+ );
2986
+ }
2987
+ var httpUrl = z.url({ protocol: /^https?$/ });
2988
+ var brandManifestSchema = z.strictObject({
2989
+ name: z.string().min(1),
2990
+ website: httpUrl,
2991
+ logo: z.strictObject({
2992
+ /** The mark drawn on the light canvas: usually the dark version of the logo. */
2993
+ onLight: httpUrl,
2994
+ /** The mark drawn on the dark canvas: usually the light version of the logo. */
2995
+ onDark: httpUrl
2996
+ }),
2997
+ webfont: z.strictObject({
2998
+ provider: z.literal("google-fonts"),
2999
+ family: z.string().min(1)
3000
+ }).nullable()
3001
+ });
3002
+
3003
+ // src/generative/state.ts
3004
+ function isRecord(value) {
3005
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3006
+ }
3007
+ function payloadToState(field, payload) {
3008
+ if (payload === void 0 || payload === null) return payload;
3009
+ if (isNativeValueNode(field)) return payload;
3010
+ switch (field.kind) {
3011
+ case "date": {
3012
+ const content = readDateContent(payload);
3013
+ return content ? formatDateContent(content) : payload;
3014
+ }
3015
+ case "list": {
3016
+ const items = Array.isArray(payload) ? payload : isRecord(payload) && Array.isArray(payload.items) ? payload.items : void 0;
3017
+ if (!items) return payload;
3018
+ return items.map((item) => payloadToState(field.item, item));
3019
+ }
3020
+ case "object": {
3021
+ if (!isRecord(payload)) return payload;
3022
+ const out = { ...payload };
3023
+ for (const child of field.fields) {
3024
+ if (hasOwnProp(payload, child.name)) {
3025
+ out[child.name] = payloadToState(child, payload[child.name]);
3026
+ }
3027
+ }
3028
+ return out;
3029
+ }
3030
+ case "document":
3031
+ case "image":
3032
+ case "text":
3033
+ case "prose":
3034
+ case "number":
3035
+ case "boolean":
3036
+ case "enum":
3037
+ case "unknown":
3038
+ return payload;
3039
+ default:
3040
+ return field;
3041
+ }
3042
+ }
3043
+ function seedInputs(fields) {
3044
+ const seed = {};
3045
+ for (const field of fields) {
3046
+ if (field.defaultValue !== void 0) {
3047
+ seed[field.name] = field.defaultValue;
3048
+ } else if (field.kind === "object") {
3049
+ const nested = seedInputs(field.fields);
3050
+ if (Object.keys(nested).length > 0) seed[field.name] = nested;
3051
+ }
3052
+ }
3053
+ return seed;
3054
+ }
3055
+
3056
+ // src/generative/fixture.ts
3057
+ function fixtureId(fixture) {
3058
+ return [
3059
+ fixture.producer,
3060
+ fixture.model,
3061
+ fixture.seed ? "seeded" : null,
3062
+ fixture.critic ? "critic" : null
3063
+ ].filter((part) => part !== null).join("--");
3064
+ }
3065
+ var PRODUCER_LABEL = {
3066
+ "pipelex-method": "Pipelex method",
3067
+ "claude-code-subagent": "Claude Code subagent",
3068
+ "claude-code-session": "Claude Code session, by hand"
3069
+ };
3070
+ function fixtureLabel(fixture) {
3071
+ const parts = [PRODUCER_LABEL[fixture.producer], fixture.model];
3072
+ if (fixture.seed) parts.push("with a seed");
3073
+ if (fixture.critic) {
3074
+ parts.push(
3075
+ `${fixture.critic.model} critic \xD7 ${fixture.critic.rounds} round${fixture.critic.rounds === 1 ? "" : "s"}`
3076
+ );
3077
+ }
3078
+ return parts.join(" \xB7 ");
3079
+ }
3080
+ function findFixture(fixtures, pipeRef, id) {
3081
+ const found = fixtures.find(
3082
+ (fixture) => fixture.pipeRef === pipeRef && fixtureId(fixture) === id
3083
+ );
3084
+ if (!found) {
3085
+ const known = fixtures.filter((fixture) => fixture.pipeRef === pipeRef).map(fixtureId).join(", ");
3086
+ throw new Error(`No spec fixture ${id} for ${pipeRef}. Known: ${known || "none"}.`);
3087
+ }
3088
+ return found;
3089
+ }
3090
+
3091
+ export { BrandProvider, COMPONENT_NAMES, COMPONENT_RENDERINGS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, DescriptorProvider, GenerativePage, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, RESULT_ROOT, ResultSlotProvider, absoluteHatchPath, brandManifestSchema, catalog, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, generativeRegistry, generativeRenderers, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutFits, layoutProblems, pathFromDomId, payloadToState, repeatBasePathOf, resultBrief, resultFieldAtPath, seedInputs, segmentsUnder, specFromJsonl, specToJsonl, useBrand, useDescriptorScope, useResultSlot, useStoreSnapshot, validateAgainstCatalog };
3092
+ //# sourceMappingURL=index.js.map
3093
+ //# sourceMappingURL=index.js.map