@pipelex/mthds-form 0.29.0 → 0.31.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.
@@ -1,28 +1,30 @@
1
1
  "use client";
2
- import { cn, checkedAccentClass, focusOutlineClass, linkTextClass, selectedBorderClass, selectedFillClass, fieldControlClass, ResultRoot, ResultField, FieldRenderer, enumLabeler, useFieldPresentation, ToggleGroup, ToggleGroupItem, selectedFillStrongClass, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../chunk-RHX7LQRL.js';
2
+ import { cn, headingClass, checkedAccentClass, focusOutlineClass, actionShadowClass, panelSurfaceClass, panelRaisedShadowClass, linkTextClass, selectedBorderClass, selectedFillClass, fieldControlClass, useResolveUrl, panelFlatShadowClass, ResultRoot, ResultField, FieldRenderer, enumLabeler, useFieldPresentation, ToggleGroup, ToggleGroupItem, selectedFillStrongClass, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, isThenable } from '../chunk-ENK5QTUK.js';
3
+ import '../chunk-2UCH4AAO.js';
3
4
  import '../chunk-4VAO6BDE.js';
4
5
  export { seedInputs } from '../chunk-VH5CDQDR.js';
5
6
  import '../chunk-L23R3JNQ.js';
6
7
  import '../chunk-56WECFBD.js';
7
- import '../chunk-ZX52CQJ4.js';
8
- import '../chunk-GHVVULHY.js';
9
- import { isNativeValueNode, readDateContent, formatDateContent, isNativeHtmlNode, isNativeDateNode, isNativeCompositeNode } from '../chunk-QQK6Y55E.js';
10
- export { brandManifestSchema } from '../chunk-QFX332LE.js';
11
- import '../chunk-ZB4RYUKV.js';
12
- import '../chunk-FABY3DEY.js';
13
- import '../chunk-XCO6GTEC.js';
14
8
  import '../chunk-E6BIXJ6C.js';
15
9
  import '../chunk-XO5OENNF.js';
10
+ import '../chunk-GHVVULHY.js';
11
+ import { readImageContent, viewableUrl, readDateContent, isNativeValueNode, formatDateContent, isNativeHtmlNode, isNativeDateNode, isNativeCompositeNode } from '../chunk-QQK6Y55E.js';
12
+ import { APP_STYLES } from '../chunk-UZNRJWN5.js';
13
+ export { brandManifestSchema } from '../chunk-UZNRJWN5.js';
14
+ import '../chunk-HVWE3TTC.js';
16
15
  import '../chunk-OD3VYXUY.js';
17
16
  import '../chunk-WYH56SOZ.js';
18
17
  import { hasOwnProp } from '../chunk-V3OV2XQT.js';
18
+ import '../chunk-FABY3DEY.js';
19
+ import '../chunk-XCO6GTEC.js';
19
20
  import '../chunk-GKV77RAS.js';
20
21
  import { defineSchema, defineCatalog, validateSpec, compileSpecStream } from '@json-render/core';
22
+ export { createStateStore } from '@json-render/core';
21
23
  import { z } from 'zod';
22
- import * as React3 from 'react';
24
+ import * as React4 from 'react';
23
25
  import { defineRegistry, useStateValue, useStateStore, useBoundProp, useFieldValidation, useRepeatScope, JSONUIProvider, Renderer } from '@json-render/react';
24
26
  import { jsx, jsxs } from 'react/jsx-runtime';
25
- import { Send, Pencil, Zap, Lightbulb, Truck, Package, Briefcase, Bookmark, Flag, Shield, Info, AlertCircle, CheckCircle2, ListChecks, Layers, Tag, Phone, Mail, Paperclip, Upload, FileText, BarChart3, TrendingUp, Hash, Percent, Receipt, Coins, Banknote, Wallet, Gift, Ticket, Image, Camera, Music, Coffee, Utensils, Star, Heart, Accessibility, Baby, User, Users, Hourglass, 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';
27
+ import { Clock, ArrowRight, Send, Pencil, Zap, Lightbulb, Truck, Package, Briefcase, Bookmark, Flag, Shield, Info, AlertCircle, CheckCircle2, ListChecks, Layers, Tag, Phone, Mail, Paperclip, Upload, FileText, BarChart3, TrendingUp, Hash, Percent, Receipt, Coins, Banknote, Wallet, Gift, Ticket, Image, Camera, Music, Coffee, Utensils, Star, Heart, Accessibility, Baby, User, Users, Hourglass, Calendar, Moon, Sun, Leaf, Mountain, Globe, Landmark, Building2, Home, Hotel, Ship, Car, Train, Plane, Route, MapPin, Map as Map$1, Compass, Rocket, Sparkles, ChevronDown } from 'lucide-react';
26
28
  import * as TabsPrimitive from '@radix-ui/react-tabs';
27
29
 
28
30
  var generativeSchema = defineSchema(
@@ -497,10 +499,13 @@ var components = {
497
499
  // ── The escape hatches and the bound equivalents (ours) ────────────────
498
500
  MthdsField: {
499
501
  props: z.object({
500
- path: z.string()
502
+ path: z.string(),
503
+ // The page words the label and the line under it, as it words every other control.
504
+ label: z.string().nullable(),
505
+ hint: z.string().nullable()
501
506
  }),
502
507
  slots: [],
503
- description: `The kernel's own control for ONE input, bound two-way at "path" (a /inputs path from the brief). Use it for every path the brief marks as delegated - a file, a date, a list, a structure you would rather not lay out - and for any scalar you would rather not style. It renders its own label and description. Inside a repeat, "path" is the item's field name relative to the item ("lines"), never an $item expression.`,
508
+ description: `The kernel's own control for ONE input, bound two-way at "path" (a /inputs path from the brief). Use it for every path the brief marks as delegated - a file, a date, a list, a structure you would rather not lay out - and for any scalar you would rather not style. It renders the descriptor's label and description unless the page words them: "label" replaces the label, "hint" the line under it. Inside a repeat, "path" is the item's field name relative to the item ("lines"), never an $item expression.`,
504
509
  example: { path: "/inputs/source" }
505
510
  },
506
511
  MthdsResult: {
@@ -515,11 +520,18 @@ var components = {
515
520
  DataTable: {
516
521
  props: z.object({
517
522
  rows: z.any(),
518
- columns: z.array(z.object({ path: z.string(), label: z.string() })),
523
+ // A column says how its cells read, from the kind the brief states.
524
+ columns: z.array(
525
+ z.object({
526
+ path: z.string(),
527
+ label: z.string(),
528
+ format: z.enum(["text", "date", "number"]).nullable().optional()
529
+ })
530
+ ),
519
531
  caption: z.string().nullable()
520
532
  }),
521
533
  slots: [],
522
- description: 'A table over a list of structures. "rows" MUST be { "$state": "/path/to/the/list" } (never inline rows); each column names a field of one item by its relative path ("label", "unit_price") and the header to show for it.',
534
+ description: 'A table over a list of structures. "rows" MUST be { "$state": "/path/to/the/list" } (never inline rows); each column names a field of one item by its relative path ("label", "unit_price"), the header to show for it, and how its cells read: "date" for a date path (written "9 Mar 2025"), "number" for a number path (digits grouped), "text" otherwise.',
523
535
  example: {
524
536
  rows: { $state: "/result/lines" },
525
537
  columns: [
@@ -549,6 +561,134 @@ var actions = {
549
561
  defineCatalog(generativeSchema, { components, actions });
550
562
  var generativeComponents = components;
551
563
  var generativeActions = actions;
564
+ var FRAMES = ["page", "composer", "result"];
565
+ var COMPOSER_COMPONENTS = ["Composer", "FieldGroup"];
566
+ var RESULT_COMPONENTS = [
567
+ "ResultHeader",
568
+ "ProportionBar",
569
+ "Swatches",
570
+ "Picture",
571
+ "Fact",
572
+ "Detail",
573
+ "DateText",
574
+ "TextList"
575
+ ];
576
+ var FRAME_COMPONENTS = [...COMPOSER_COMPONENTS, ...RESULT_COMPONENTS];
577
+ var frameComponents = {
578
+ Composer: {
579
+ props: z.object({
580
+ headline: z.string(),
581
+ lede: z.string().nullable(),
582
+ runLabel: z.string(),
583
+ columns: z.enum(["1", "2"]).nullable(),
584
+ notes: z.array(z.string()).nullable()
585
+ }),
586
+ slots: ["default"],
587
+ events: ["press"],
588
+ description: `The composer: the page's headline (rendered as the h1) and one muted line under it, then a single raised panel holding its children - the inputs - in one column, or two columns side by side when "columns" is "2", and at the panel's foot the host's action row: how long a run takes, as the host knows it, and the one button that runs the method, worded by "runLabel". The action row stays on screen while a long panel scrolls. It is the control that runs the method: bind on.press to validateForm then run. "notes" are a few short lines set under the panel, each after a check mark, in two columns: what one run gives back, in a person's words.`,
589
+ example: {
590
+ headline: "A day-by-day plan for your trip",
591
+ lede: "Tell us who is going, where and when.",
592
+ runLabel: "Plan my trip",
593
+ columns: "2"
594
+ }
595
+ },
596
+ FieldGroup: {
597
+ props: z.object({ title: z.string().nullable() }),
598
+ slots: ["default"],
599
+ description: "A quiet group of inputs inside a panel: an optional small h2 title, then its children stacked with even spacing. No box, no rule: the panel around it is the surface.",
600
+ example: { title: "Where and when" }
601
+ },
602
+ ResultHeader: {
603
+ props: z.object({
604
+ eyebrow: z.string().nullable(),
605
+ title: z.string(),
606
+ subtitle: z.string().nullable()
607
+ }),
608
+ slots: [],
609
+ description: `The result's heading: a small eyebrow in the accent colour, the title (rendered as the h1) and one muted line under it, with the host's actions on the result (download, share) at the right. Text props may be read from the state with { "$state" } or { "$template" }.`,
610
+ example: {
611
+ eyebrow: "Your plan",
612
+ title: { $state: "/result/title" },
613
+ subtitle: { $template: "${/result/currency} ${/result/estimated_total} estimated" }
614
+ }
615
+ },
616
+ ProportionBar: {
617
+ props: z.object({
618
+ label: z.string(),
619
+ total: z.number().nullable(),
620
+ of: z.number().nullable(),
621
+ unit: z.string().nullable(),
622
+ items: z.array(z.any()).nullable(),
623
+ labelKey: z.string(),
624
+ valueKey: z.string()
625
+ }),
626
+ slots: [],
627
+ description: 'A labelled total over its parts, in a raised panel: the label and the total in large figures ("of" a ceiling when there is one), then one bar split in proportion to each part, and a legend naming each part with its amount. "items" is { "$state": ... } on a list of structures; "labelKey" and "valueKey" name the member of one item that labels it and the number that sizes it. "unit" is a currency or unit the state carries, read with { "$state" }.',
628
+ example: {
629
+ label: "Estimated cost",
630
+ total: { $state: "/result/estimated_total" },
631
+ unit: { $state: "/result/currency" },
632
+ items: { $state: "/result/costs" },
633
+ labelKey: "category",
634
+ valueKey: "amount"
635
+ }
636
+ },
637
+ Swatches: {
638
+ props: z.object({ colors: z.array(z.string()) }),
639
+ slots: [],
640
+ description: 'A row of colour swatches, each a small tile filled with the colour and its value written under it in mono. "colors" is a list of colour values, each read from a text path ({ "$state" }, or { "$item" } inside a repeat).',
641
+ example: { colors: [{ $item: "colors/primary" }, { $item: "colors/accent" }] }
642
+ },
643
+ Picture: {
644
+ props: z.object({
645
+ path: z.string(),
646
+ alt: z.string().nullable(),
647
+ aspect: z.enum(["16:9", "4:3", "1:1", "auto"]).nullable()
648
+ }),
649
+ slots: [],
650
+ description: 'A picture the run produced, shown whole and edge to edge in its column with a hairline border, cropped to "aspect" when one is set. "path" is an image path of the brief, literally ("/result/cover"), or relative to the item inside a repeat ("" for the item itself, when the repeat is over a list of images).',
651
+ example: { path: "/result/cover", alt: "The cover", aspect: "16:9" }
652
+ },
653
+ Fact: {
654
+ props: z.object({
655
+ label: z.string(),
656
+ value: z.any(),
657
+ detail: z.string().nullable()
658
+ }),
659
+ slots: [],
660
+ description: 'One fact as a small boxed tile: a muted label, the value under it, and an optional muted detail. Several in a Grid make a band of facts. "value" is a scalar read with { "$state" } or { "$template" }.',
661
+ example: { label: "Order number", value: { $state: "/result/number" } }
662
+ },
663
+ DateText: {
664
+ props: z.object({
665
+ value: z.string().nullable(),
666
+ style: z.enum(["long", "short", "weekday"]).nullable(),
667
+ tone: z.enum(["default", "muted", "accent"]).nullable()
668
+ }),
669
+ slots: [],
670
+ description: 'A date written in words: "long" is "Wednesday 14 April 2027", "short" is "14 Apr 2027", "weekday" is "Wed 14 April". "value" is a date path read with { "$state" } or { "$item" }; "tone" colours it muted or in the accent colour, as an eyebrow over a title.',
671
+ example: { value: { $item: "day" }, style: "weekday", tone: "accent" }
672
+ },
673
+ TextList: {
674
+ props: z.object({
675
+ items: z.array(z.string()).nullable(),
676
+ marker: z.enum(["bullet", "number", "check"]).nullable()
677
+ }),
678
+ slots: [],
679
+ description: 'A list of short texts as one list, each entry a line with a small marker before it: a dot, its number or a check. "items" reads a list of text path with { "$state" }, or { "$item" } inside a repeat - the whole list at once, so it needs no repeat of its own.',
680
+ example: { items: { $state: "/result/notes" }, marker: "bullet" }
681
+ },
682
+ Detail: {
683
+ props: z.object({
684
+ label: z.string(),
685
+ value: z.any()
686
+ }),
687
+ slots: [],
688
+ description: 'A labelled line of text: the label muted in a narrow column at the left, the value wrapping beside it, a hairline under the line. Several in a column read as a list of details. "value" is a scalar read with { "$state" }, { "$item" } or { "$template" }; the line hides itself while the value is empty.',
689
+ example: { label: "Morning", value: { $item: "morning" } }
690
+ }
691
+ };
552
692
 
553
693
  // src/generative/catalog.ts
554
694
  var PRODUCT_COMPONENTS = [
@@ -644,11 +784,14 @@ var COMPONENT_RENDERINGS = {
644
784
  Split: { children: { count: 2, roles: "left, right" } },
645
785
  Workspace: { children: { count: 2, roles: "work, rail" } },
646
786
  Tabs: { panels: { prop: "tabs", noun: "tab" } },
647
- Steps: { panels: { prop: "steps", noun: "step" } }
787
+ Steps: { panels: { prop: "steps", noun: "step" } },
788
+ Composer: { heading: { level: 1 }, once: "the composer" },
789
+ ResultHeader: { heading: { level: 1 }, once: "the result's header" },
790
+ FieldGroup: { heading: { level: 2, when: "title" } }
648
791
  };
649
792
  var catalog = Object.assign(
650
793
  defineCatalog(generativeSchema, {
651
- components: { ...generativeComponents, ...product },
794
+ components: { ...generativeComponents, ...product, ...frameComponents },
652
795
  actions: generativeActions
653
796
  }),
654
797
  { renders: COMPONENT_RENDERINGS }
@@ -658,6 +801,60 @@ var COMPONENT_NAMES = [
658
801
  ...CUSTOM_COMPONENTS,
659
802
  ...PRODUCT_COMPONENTS
660
803
  ];
804
+ var FRAME_EXCLUDED = {
805
+ page: [...FRAME_COMPONENTS],
806
+ composer: [
807
+ "AppBar",
808
+ "Footer",
809
+ "Workspace",
810
+ "Rail",
811
+ "Cta",
812
+ "Button",
813
+ "Hero",
814
+ "SummaryRow",
815
+ "MthdsResult",
816
+ "DataTable",
817
+ "Metric",
818
+ "Progress",
819
+ // `TextList` stays: a composer may list short texts too, such as what a
820
+ // run gives back.
821
+ ...RESULT_COMPONENTS.filter((name) => name !== "TextList")
822
+ ],
823
+ result: [
824
+ "AppBar",
825
+ "Footer",
826
+ "Workspace",
827
+ "Rail",
828
+ "Cta",
829
+ "Button",
830
+ "Hero",
831
+ "MthdsField",
832
+ "Input",
833
+ "Textarea",
834
+ "Select",
835
+ "Radio",
836
+ "Checkbox",
837
+ "Switch",
838
+ "Segmented",
839
+ "NumberInput",
840
+ "Steps",
841
+ ...COMPOSER_COMPONENTS
842
+ ]
843
+ };
844
+ function componentNamesFor(frame) {
845
+ const excluded = new Set(FRAME_EXCLUDED[frame]);
846
+ const own = frame === "page" ? [] : [...FRAME_COMPONENTS];
847
+ return [...COMPONENT_NAMES, ...own].filter((name) => !excluded.has(name));
848
+ }
849
+ function frameCatalog(frame) {
850
+ return {
851
+ componentNames: componentNamesFor(frame),
852
+ actionNames: catalog.actionNames,
853
+ data: catalog.data,
854
+ schema: catalog.schema,
855
+ renders: COMPONENT_RENDERINGS
856
+ };
857
+ }
661
858
 
662
859
  // src/generative/props-signature.ts
663
860
  function definitionOf(schema) {
@@ -704,9 +901,9 @@ function propsSignature(schema) {
704
901
 
705
902
  // src/generative/designer-catalog.ts
706
903
  var DESIGNER_CATALOG_CONCEPT = "generative.Catalog";
707
- function designerCatalog() {
904
+ function designerCatalog({ frame = "page" } = {}) {
708
905
  const definitions = catalog.data.components;
709
- const components3 = COMPONENT_NAMES.map((name) => {
906
+ const components3 = componentNamesFor(frame).map((name) => {
710
907
  const definition = definitions[name];
711
908
  if (!definition) throw new Error(`the catalog defines no component named '${name}'`);
712
909
  const slots = definition.slots ?? [];
@@ -735,7 +932,12 @@ function designerCatalog() {
735
932
  }
736
933
 
737
934
  // src/generative/prompt-hash.ts
738
- var PROMPT_HASH = "2b2325fd1231";
935
+ var PROMPT_HASH = "30cf9bc059f6";
936
+ function promptHashSubject(method) {
937
+ const catalogs = FRAMES.map((frame) => designerCatalog({ frame }));
938
+ return `${method}
939
+ ${JSON.stringify(catalogs)}`;
940
+ }
739
941
 
740
942
  // src/generative/paths.ts
741
943
  var INPUTS_ROOT = "/inputs";
@@ -822,169 +1024,351 @@ function repeatListPathOf(spec, key, parents = parentMapOf(spec)) {
822
1024
  return outer !== void 0 && typeof item === "string" ? joinPath(outer, item) : void 0;
823
1025
  }
824
1026
 
825
- // src/generative/brief.ts
826
- var DESIGNER_BRIEF_CONCEPT = "generative.Brief";
827
- var RUN_COMPONENT = "Cta";
828
- function isDelegatedInput(field) {
829
- return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "list" || field.kind === "unknown" || field.kind === "enum" && field.options.includes("");
1027
+ // src/generative/layout-fits.ts
1028
+ function isUnder(root, path) {
1029
+ return path === root || path.startsWith(`${root}/`);
830
1030
  }
831
- function isDelegatedResult(field) {
832
- if (isNativeValueNode(field)) return true;
833
- if (field.kind === "list" && isNativeValueNode(field.item)) return true;
834
- return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "prose" || field.kind === "unknown";
1031
+ function itemPathResolver(spec, key, parents) {
1032
+ let base;
1033
+ let resolvedBase = false;
1034
+ return (field) => {
1035
+ if (!resolvedBase) {
1036
+ base = repeatBasePathOf(spec, key, parents);
1037
+ resolvedBase = true;
1038
+ }
1039
+ if (base === void 0) return void 0;
1040
+ const under = field.startsWith("/") ? field.slice(1) : field;
1041
+ return under === "" ? base : `${base}/${under}`;
1042
+ };
835
1043
  }
836
- function kindLabel(field) {
837
- if (isNativeHtmlNode(field)) return "markup (native.Html)";
838
- if (isNativeDateNode(field)) return "date (native.Date)";
839
- if (isNativeCompositeNode(field)) return "composite (native.Composite)";
840
- switch (field.kind) {
841
- case "text":
842
- return "text";
843
- case "prose":
844
- return "prose (markdown)";
845
- case "number":
846
- return field.integer ? "integer" : "number";
847
- case "boolean":
848
- return "boolean";
849
- case "enum":
850
- return `choice of ${field.options.map((option) => JSON.stringify(option)).join(" | ")}`;
851
- case "date":
852
- return field.datetime ? "date with time" : "date";
853
- case "document":
854
- return "document (a file)";
855
- case "image":
856
- return "image (a file)";
857
- case "object":
858
- return `structure${field.conceptRef ? ` ${field.conceptRef}` : ""}`;
859
- case "list":
860
- return `list of ${kindLabel(field.item)}`;
861
- case "unknown":
862
- return "unknown";
863
- default:
864
- return field;
865
- }
1044
+ function interpolatedPaths(template, itemPath) {
1045
+ return [...template.matchAll(/\$\{([^}]+)\}/g)].flatMap((match) => {
1046
+ const raw = match[1];
1047
+ if (raw === void 0) return [];
1048
+ if (raw.startsWith("/")) return [raw];
1049
+ return [itemPath(raw) ?? `/${raw}`];
1050
+ });
866
1051
  }
867
- function constraints(field) {
868
- const notes = [];
869
- if (field.kind === "number") {
870
- if (field.min !== void 0) notes.push(`min ${field.min}`);
871
- if (field.max !== void 0) notes.push(`max ${field.max}`);
872
- }
873
- if (field.kind === "text" || field.kind === "prose") {
874
- if (field.minLength !== void 0) notes.push(`at least ${field.minLength} characters`);
875
- if (field.maxLength !== void 0) notes.push(`at most ${field.maxLength} characters`);
876
- if (field.format) notes.push(`format ${field.format}`);
877
- }
878
- if (field.kind === "list") {
879
- if (field.itemCount !== void 0) notes.push(`at least ${field.itemCount} items`);
880
- if (field.maxItemCount !== void 0) notes.push(`at most ${field.maxItemCount} items`);
881
- }
882
- if (field.defaultValue !== void 0) notes.push(`default ${JSON.stringify(field.defaultValue)}`);
883
- if (field.examples && field.examples.length > 0) {
884
- notes.push(`examples ${field.examples.map((example) => JSON.stringify(example)).join(", ")}`);
885
- }
886
- if (field.hints && Object.keys(field.hints).length > 0) {
887
- notes.push(
888
- `hints ${Object.entries(field.hints).map(([key, value]) => `${key}=${value}`).join(", ")}`
889
- );
1052
+ function mentionedPaths(spec, parents) {
1053
+ const found = { bound: [], read: [], adrift: [] };
1054
+ for (const [key, element] of Object.entries(spec.elements)) {
1055
+ const itemPath = itemPathResolver(spec, key, parents);
1056
+ const walk = (value) => {
1057
+ if (Array.isArray(value)) {
1058
+ value.forEach(walk);
1059
+ return;
1060
+ }
1061
+ if (typeof value !== "object" || value === null) return;
1062
+ const record = value;
1063
+ if (typeof record.$bindState === "string") found.bound.push(record.$bindState);
1064
+ if (typeof record.$state === "string") found.read.push(record.$state);
1065
+ if (typeof record.$template === "string") {
1066
+ found.read.push(...interpolatedPaths(record.$template, itemPath));
1067
+ }
1068
+ if (typeof record.$bindItem === "string") {
1069
+ const path = itemPath(record.$bindItem);
1070
+ if (path === void 0) found.adrift.push(key);
1071
+ else found.bound.push(path);
1072
+ }
1073
+ if (typeof record.$item === "string") {
1074
+ const path = itemPath(record.$item);
1075
+ if (path === void 0) found.adrift.push(key);
1076
+ else found.read.push(path);
1077
+ }
1078
+ Object.values(record).forEach(walk);
1079
+ };
1080
+ walk(element.props);
1081
+ walk(element.visible);
890
1082
  }
891
- return notes;
1083
+ return found;
892
1084
  }
893
- function entryOf(field, path, depth, side, relative, seeded) {
894
- const notes = constraints(field);
895
- return {
896
- depth,
897
- path,
898
- kind: kindLabel(field),
899
- name: field.name,
900
- title: field.title && field.title !== field.name ? field.title : void 0,
901
- description: field.description,
902
- required: side === "input" ? field.required : void 0,
903
- gating: side === "input" && field.gating ? true : void 0,
904
- notes: notes.length > 0 ? notes : void 0,
905
- default: seeded || field.defaultValue === void 0 ? void 0 : JSON.stringify(field.defaultValue),
906
- delegated: side === "input" ? isDelegatedInput(field) : isDelegatedResult(field),
907
- relative: relative ? true : void 0
908
- };
1085
+ function staleReads(read, root, resolves) {
1086
+ const under = read.filter((path) => isUnder(root, path));
1087
+ return [...new Set(under)].filter((path) => !resolves(path));
909
1088
  }
910
- function describe(field, path, depth, side, entries, seeded = false) {
911
- const entry = entryOf(field, path, depth, side, false, seeded);
912
- entries.push(entry);
913
- if (entry.delegated) return;
914
- if (field.kind === "object") {
915
- const seededBelow = seeded || field.defaultValue !== void 0 || side === "input" && !field.required;
916
- for (const child of field.fields) {
917
- describe(child, joinPath(path, child.name), depth + 1, side, entries, seededBelow);
918
- }
919
- }
920
- if (field.kind === "list" && side === "result") {
921
- const item = field.item;
922
- entry.item_kind = kindLabel(item);
923
- entry.item_description = item.description;
924
- if (item.kind === "object" && !isDelegatedResult(item)) {
925
- entry.item_laid_out = true;
926
- for (const child of item.fields) {
927
- describeRelative(child, child.name, depth + 2, entries);
928
- }
1089
+ function staleRepeats(spec, parents, root, resolves, side) {
1090
+ const problems = [];
1091
+ for (const [key, element] of Object.entries(spec.elements)) {
1092
+ if (!element.repeat) continue;
1093
+ const listPath = repeatListPathOf(spec, key, parents);
1094
+ if (listPath === void 0 || !isUnder(root, listPath)) continue;
1095
+ if (!resolves(listPath)) {
1096
+ problems.push(`${key}: repeats over ${listPath}, which no ${side} has`);
929
1097
  }
930
1098
  }
1099
+ return problems;
931
1100
  }
932
- function describeRelative(field, relativePath, depth, entries) {
933
- const entry = entryOf(field, relativePath, depth, "result", true, false);
934
- entries.push(entry);
935
- if (entry.delegated) return;
936
- if (field.kind === "object") {
937
- for (const child of field.fields) {
938
- describeRelative(child, joinPath(relativePath, child.name), depth + 1, entries);
1101
+ var NOT_A_VALUE = {
1102
+ object: { what: "a structure", instead: "a structure is shown through its members" },
1103
+ list: { what: "a list", instead: "a list is laid out as a repeat or a DataTable" },
1104
+ document: { what: "a file", instead: "a file is delegated to the kernel's own control" },
1105
+ image: { what: "a file", instead: "a file is delegated to the kernel's own control" }
1106
+ };
1107
+ var NOT_VALUES = {
1108
+ object: "structures",
1109
+ list: "lists",
1110
+ document: "files",
1111
+ image: "files"
1112
+ };
1113
+ var listPropsCache;
1114
+ function listProps() {
1115
+ if (listPropsCache) return listPropsCache;
1116
+ const found = /* @__PURE__ */ new Map([
1117
+ ["DataTable", /* @__PURE__ */ new Map([["rows", "anything"]])]
1118
+ ]);
1119
+ const components3 = catalog.data.components;
1120
+ for (const [type, definition] of Object.entries(components3)) {
1121
+ const shape = definition.props?.shape;
1122
+ for (const [prop, schema] of Object.entries(shape ?? {})) {
1123
+ const items = listItemsOf(schema);
1124
+ if (items === void 0) continue;
1125
+ if (!found.has(type)) found.set(type, /* @__PURE__ */ new Map());
1126
+ found.get(type).set(prop, items);
939
1127
  }
940
1128
  }
941
- if (field.kind === "list") {
942
- const item = field.item;
943
- entry.item_kind = kindLabel(item);
944
- entry.item_description = item.description;
945
- if (item.kind === "object" && !isDelegatedResult(item)) {
946
- entry.item_laid_out = true;
947
- for (const child of item.fields) {
948
- describeRelative(child, joinPath(relativePath, "<i>", child.name), depth + 2, entries);
1129
+ listPropsCache = found;
1130
+ return found;
1131
+ }
1132
+ var VALUE_SCHEMAS = /* @__PURE__ */ new Set(["string", "number", "boolean", "enum", "literal"]);
1133
+ function unwrapped(schema) {
1134
+ let current = schema;
1135
+ for (let depth = 0; depth < 8; depth += 1) {
1136
+ const def = current.def;
1137
+ if (!def) return void 0;
1138
+ if (def.innerType === void 0) return def;
1139
+ current = def.innerType;
1140
+ }
1141
+ return void 0;
1142
+ }
1143
+ function listItemsOf(schema) {
1144
+ const def = unwrapped(schema);
1145
+ if (def?.type !== "array") return void 0;
1146
+ const element = unwrapped(def.element);
1147
+ return element?.type !== void 0 && VALUE_SCHEMAS.has(element.type) ? "values" : "anything";
1148
+ }
1149
+ function nonScalarReads(spec, parents, root, fieldAt) {
1150
+ const problems = [];
1151
+ const lists = listProps();
1152
+ for (const [key, element] of Object.entries(spec.elements)) {
1153
+ const itemPath = itemPathResolver(spec, key, parents);
1154
+ const listy = lists.get(element.type);
1155
+ const check = (prop, path) => {
1156
+ if (!isUnder(root, path)) return;
1157
+ const field = fieldAt(path);
1158
+ if (!field) return;
1159
+ const wrong = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind] : void 0;
1160
+ if (!wrong) return;
1161
+ problems.push(
1162
+ `${key}: ${prop} shows ${path}, which is ${wrong.what} and not a value; a prop that shows a value takes a scalar path, and ${wrong.instead}`
1163
+ );
1164
+ };
1165
+ const checkList = (prop, path, items) => {
1166
+ if (!isUnder(root, path)) return;
1167
+ const field = fieldAt(path);
1168
+ if (!field || field.kind === "unknown") return;
1169
+ if (field.kind !== "list") {
1170
+ const what = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind].what : "a value";
1171
+ problems.push(
1172
+ `${key}: ${prop} takes a list, and ${path} is ${what}; a prop that takes a list reads a list path`
1173
+ );
1174
+ return;
1175
+ }
1176
+ if (items !== "values") return;
1177
+ const of = hasOwnProp(NOT_VALUES, field.item.kind) ? NOT_VALUES[field.item.kind] : void 0;
1178
+ if (!of) return;
1179
+ problems.push(
1180
+ `${key}: ${prop} takes a list of values, and ${path} is a list of ${of}; a list of ${of} is laid out as a repeat or a DataTable`
1181
+ );
1182
+ };
1183
+ const checkShares = (path) => {
1184
+ if (element.type !== "ProportionBar" || !isUnder(root, path)) return;
1185
+ const field = fieldAt(path);
1186
+ if (field?.kind !== "list") return;
1187
+ if (field.item.kind !== "object") {
1188
+ problems.push(
1189
+ `${key}: ProportionBar reads ${path}, a list of ${field.item.kind} values; its parts are structures, each with a label member and a number member`
1190
+ );
1191
+ return;
1192
+ }
1193
+ const members = field.item.fields;
1194
+ const { labelKey, valueKey } = element.props ?? {};
1195
+ const member = (name) => typeof name === "string" ? members.find((m) => m.name === name) : void 0;
1196
+ if (!member(labelKey)) {
1197
+ problems.push(
1198
+ `${key}: ProportionBar's labelKey ${JSON.stringify(labelKey)} is no member of ${path}'s items`
1199
+ );
1200
+ }
1201
+ const value = member(valueKey);
1202
+ if (!value) {
1203
+ problems.push(
1204
+ `${key}: ProportionBar's valueKey ${JSON.stringify(valueKey)} is no member of ${path}'s items`
1205
+ );
1206
+ } else if (value.kind !== "number") {
1207
+ problems.push(
1208
+ `${key}: ProportionBar's valueKey ${JSON.stringify(valueKey)} holds a ${value.kind}, not a number`
1209
+ );
1210
+ }
1211
+ };
1212
+ const walk = (prop, value) => {
1213
+ if (Array.isArray(value)) {
1214
+ value.forEach((entry) => walk(prop, entry));
1215
+ return;
1216
+ }
1217
+ if (typeof value !== "object" || value === null) return;
1218
+ const record = value;
1219
+ if (typeof record.$state === "string") check(prop, record.$state);
1220
+ if (typeof record.$item === "string") {
1221
+ const path = itemPath(record.$item);
1222
+ if (path !== void 0) check(prop, path);
1223
+ }
1224
+ if (typeof record.$template === "string") {
1225
+ for (const path of interpolatedPaths(record.$template, itemPath)) check(prop, path);
1226
+ }
1227
+ for (const [name, entry] of Object.entries(record)) {
1228
+ if (name !== "$cond") walk(prop, entry);
1229
+ }
1230
+ };
1231
+ for (const [prop, value] of Object.entries(element.props ?? {})) {
1232
+ const items = listy?.get(prop);
1233
+ if (items === void 0 || Array.isArray(value)) {
1234
+ walk(prop, value);
1235
+ continue;
1236
+ }
1237
+ if (typeof value !== "object" || value === null) continue;
1238
+ const record = value;
1239
+ const listPath = typeof record.$state === "string" ? record.$state : typeof record.$item === "string" ? itemPath(record.$item) : void 0;
1240
+ if (listPath !== void 0) {
1241
+ checkList(prop, listPath, items);
1242
+ if (prop === "items") checkShares(listPath);
949
1243
  }
950
1244
  }
951
1245
  }
1246
+ return problems;
952
1247
  }
953
- function inputBrief(subject, fields) {
954
- const paths = [];
955
- for (const field of fields) describe(field, joinPath(INPUTS_ROOT, field.name), 0, "input", paths);
956
- return {
957
- side: "input",
958
- pipe_ref: subject.pipeRef,
959
- description: subject.description,
960
- name: subject.name,
961
- paths,
962
- run_control: RUN_COMPONENT
963
- };
964
- }
965
- function resultBrief(subject, field, state) {
966
- const paths = [];
967
- if (field.kind === "object" && !isDelegatedResult(field)) {
968
- paths.push({
969
- depth: 0,
970
- path: RESULT_ROOT,
971
- kind: kindLabel(field),
972
- description: field.description,
973
- delegated: false
974
- });
975
- for (const child of field.fields) {
976
- describe(child, joinPath(RESULT_ROOT, child.name), 1, "result", paths);
1248
+ function boundProblems(bound, inputs) {
1249
+ const problems = [];
1250
+ const underInputs = bound.filter((path) => isUnder(INPUTS_ROOT, path));
1251
+ if (!inputs) {
1252
+ if (underInputs.length > 0) {
1253
+ problems.push(`a result page binds ${underInputs.join(", ")}; a result page writes nothing`);
977
1254
  }
978
1255
  } else {
979
- describe(field, RESULT_ROOT, 0, "result", paths);
1256
+ for (const path of underInputs) {
1257
+ if (!inputFieldAtPath(inputs, path)) {
1258
+ problems.push(`${path} is bound, and no input has it`);
1259
+ }
1260
+ }
980
1261
  }
981
- return {
982
- side: "result",
983
- pipe_ref: subject.pipeRef,
984
- description: subject.description,
985
- paths,
986
- sample_state: JSON.stringify(state, null, 2)
1262
+ for (const path of bound) {
1263
+ if (isUnder(RESULT_ROOT, path)) {
1264
+ problems.push(
1265
+ `${path} is bound; a layout may not write into ${RESULT_ROOT}, which the run fills`
1266
+ );
1267
+ }
1268
+ }
1269
+ return problems;
1270
+ }
1271
+ function repeatPaths(spec) {
1272
+ const found = [];
1273
+ for (const element of Object.values(spec.elements)) {
1274
+ const statePath = element.repeat?.statePath;
1275
+ if (typeof statePath === "string") found.push(statePath);
1276
+ }
1277
+ return found;
1278
+ }
1279
+ function isOffered(path, offered) {
1280
+ if (offered.bound.has(path) || offered.repeated.has(path)) return true;
1281
+ return offered.delegated.some((at) => path === at || path.startsWith(`${at}/`));
1282
+ }
1283
+ function uncoveredUnder(field, path, offered) {
1284
+ if (isOffered(path, offered)) return [];
1285
+ if (field.kind === "object") {
1286
+ return field.fields.filter((child) => child.required).flatMap((child) => uncoveredUnder(child, joinPath(path, child.name), offered));
1287
+ }
1288
+ return [path];
1289
+ }
1290
+ function layoutProblems(descriptor, spec) {
1291
+ try {
1292
+ return collectLayoutProblems(descriptor, spec);
1293
+ } catch (error) {
1294
+ return [`the layout is not a well-formed spec: ${String(error)}`];
1295
+ }
1296
+ }
1297
+ function collectLayoutProblems(descriptor, spec) {
1298
+ const problems = [];
1299
+ const delegated = [];
1300
+ const parents = parentMapOf(spec);
1301
+ for (const [key, element] of Object.entries(spec.elements)) {
1302
+ const written = element.props?.path;
1303
+ const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
1304
+ if (element.type === "MthdsField") {
1305
+ if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
1306
+ problems.push(`${key}: MthdsField delegates ${String(written)}, which no input has`);
1307
+ } else {
1308
+ delegated.push(path);
1309
+ }
1310
+ }
1311
+ if (element.type === "MthdsResult") {
1312
+ if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
1313
+ problems.push(`${key}: MthdsResult delegates ${String(written)}, which no result has`);
1314
+ }
1315
+ }
1316
+ const [onlyKey] = element.children?.length === 1 ? element.children : [];
1317
+ const only = onlyKey === void 0 ? void 0 : spec.elements[onlyKey];
1318
+ if (element.type === "Grid" && element.repeat === void 0 && only?.repeat !== void 0) {
1319
+ problems.push(
1320
+ `${key}: Grid's only child ${onlyKey} carries the repeat, so every item lands in one cell; put the repeat on ${key} itself, with the item's element as its child`
1321
+ );
1322
+ }
1323
+ if (element.type === "Picture") {
1324
+ const shown = written === "" ? repeatBasePathOf(spec, key, parents) : path ?? void 0;
1325
+ const field = shown && descriptor.result ? resultFieldAtPath(descriptor.result, shown) : void 0;
1326
+ if (!field) {
1327
+ problems.push(`${key}: Picture shows ${JSON.stringify(written)}, which no result has`);
1328
+ } else if (field.kind !== "image") {
1329
+ problems.push(`${key}: Picture shows ${shown}, which holds a ${field.kind}, not an image`);
1330
+ }
1331
+ }
1332
+ }
1333
+ const { bound, read, adrift } = mentionedPaths(spec, parents);
1334
+ for (const key of new Set(adrift)) {
1335
+ problems.push(`${key}: reads the current item, and no repeat above it has one`);
1336
+ }
1337
+ problems.push(...boundProblems(bound, descriptor.inputs));
1338
+ if (!descriptor.inputs) {
1339
+ const result = descriptor.result;
1340
+ const fieldAt2 = (path) => result ? resultFieldAtPath(result, path) : void 0;
1341
+ const resolves2 = (path) => fieldAt2(path) !== void 0;
1342
+ problems.push(...staleRepeats(spec, parents, RESULT_ROOT, resolves2, "result"));
1343
+ for (const path of staleReads(read, RESULT_ROOT, resolves2)) {
1344
+ problems.push(`${path} is read, and no result has it`);
1345
+ }
1346
+ problems.push(...nonScalarReads(spec, parents, RESULT_ROOT, fieldAt2));
1347
+ return problems;
1348
+ }
1349
+ const inputs = descriptor.inputs;
1350
+ const fieldAt = (path) => inputFieldAtPath(inputs, path);
1351
+ const resolves = (path) => fieldAt(path) !== void 0;
1352
+ problems.push(...staleRepeats(spec, parents, INPUTS_ROOT, resolves, "input"));
1353
+ for (const path of staleReads(read, INPUTS_ROOT, resolves)) {
1354
+ problems.push(`${path} is read, and no input has it`);
1355
+ }
1356
+ problems.push(...nonScalarReads(spec, parents, INPUTS_ROOT, fieldAt));
1357
+ const offered = {
1358
+ bound: new Set(bound),
1359
+ repeated: new Set(repeatPaths(spec)),
1360
+ delegated
987
1361
  };
1362
+ for (const field of inputs) {
1363
+ if (!field.required) continue;
1364
+ for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered)) {
1365
+ problems.push(`${path} is required, and the layout offers nowhere to enter it`);
1366
+ }
1367
+ }
1368
+ return problems;
1369
+ }
1370
+ function layoutFits(descriptor, spec) {
1371
+ return layoutProblems(descriptor, spec).length === 0;
988
1372
  }
989
1373
  var EXPRESSION_KEYS = [
990
1374
  "$state",
@@ -1000,6 +1384,14 @@ var HATCHES = /* @__PURE__ */ new Set(["MthdsField", "MthdsResult"]);
1000
1384
  function isExpression(value) {
1001
1385
  return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).some((key) => EXPRESSION_KEYS.includes(key));
1002
1386
  }
1387
+ function valueAt(value, path) {
1388
+ let at = value;
1389
+ for (const step of path) {
1390
+ if (typeof at !== "object" || at === null) return void 0;
1391
+ at = at[step];
1392
+ }
1393
+ return at;
1394
+ }
1003
1395
  function isClosedVocabulary(schema) {
1004
1396
  let current = schema;
1005
1397
  for (let depth = 0; depth < 8; depth += 1) {
@@ -1066,7 +1458,7 @@ function deepestChain(spec) {
1066
1458
  }
1067
1459
  return deepest;
1068
1460
  }
1069
- function validateAgainstCatalog(spec, catalog2 = catalog) {
1461
+ function validateAgainstCatalog(spec, catalog2 = frameCatalog("page")) {
1070
1462
  try {
1071
1463
  return checkAgainstCatalog(spec, catalog2);
1072
1464
  } catch (error) {
@@ -1153,10 +1545,13 @@ function checkAgainstCatalog(spec, catalog2) {
1153
1545
  continue;
1154
1546
  }
1155
1547
  const parsed = propSchema.safeParse(value);
1156
- if (!parsed.success) {
1548
+ const issues = parsed.success ? [] : parsed.error.issues.filter(
1549
+ (issue) => !issue.path.some((_, n) => isExpression(valueAt(value, issue.path.slice(0, n + 1))))
1550
+ );
1551
+ if (issues.length > 0) {
1157
1552
  problems.push({
1158
1553
  elementKey: key,
1159
- message: `${element.type}.${name}: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`
1554
+ message: `${element.type}.${name}: ${issues.map((issue) => issue.message).join("; ")}`
1160
1555
  });
1161
1556
  }
1162
1557
  }
@@ -1195,7 +1590,7 @@ function checkAgainstCatalog(spec, catalog2) {
1195
1590
  });
1196
1591
  }
1197
1592
  }
1198
- const present2 = (value) => value !== void 0 && value !== null && value !== "";
1593
+ const present3 = (value) => value !== void 0 && value !== null && value !== "";
1199
1594
  const levels = [];
1200
1595
  const onlyOnce = /* @__PURE__ */ new Map();
1201
1596
  const seen = /* @__PURE__ */ new Set();
@@ -1212,7 +1607,7 @@ function checkAgainstCatalog(spec, catalog2) {
1212
1607
  if (match) levels.push({ key, type: "Heading", level: Number(match[1]) });
1213
1608
  } else if (rendering?.heading) {
1214
1609
  const rendered = rendering.heading;
1215
- const has = rendered.when === void 0 || present2(props[rendered.when]);
1610
+ const has = rendered.when === void 0 || present3(props[rendered.when]);
1216
1611
  if (has) levels.push({ key, type: element.type, level: rendered.level });
1217
1612
  }
1218
1613
  if (rendering?.once !== void 0) {
@@ -1409,306 +1804,224 @@ function formatProblems(problems) {
1409
1804
  ).join("\n");
1410
1805
  }
1411
1806
 
1412
- // src/generative/layout-fits.ts
1413
- function isUnder(root, path) {
1414
- return path === root || path.startsWith(`${root}/`);
1415
- }
1416
- function itemPathResolver(spec, key, parents) {
1417
- let base;
1418
- let resolvedBase = false;
1419
- return (field) => {
1420
- if (!resolvedBase) {
1421
- base = repeatBasePathOf(spec, key, parents);
1422
- resolvedBase = true;
1423
- }
1424
- if (base === void 0) return void 0;
1425
- const under = field.startsWith("/") ? field.slice(1) : field;
1426
- return under === "" ? base : `${base}/${under}`;
1427
- };
1807
+ // src/generative/designer-run.ts
1808
+ function seedLine(seed) {
1809
+ return `CREATIVE SEED (derive your direction from it; never reveal it): ${seed}`;
1810
+ }
1811
+ var REPAIR_ATTEMPTS = 2;
1812
+ function layoutCheckProblems(spec, { frame, descriptor }) {
1813
+ const verdict = validateAgainstCatalog(spec, frameCatalog(frame));
1814
+ const invalid = verdict.ok ? [] : formatProblems(verdict.problems).split("\n");
1815
+ const runless = frame !== "result" && descriptor.inputs && !bindsRun(spec) ? ["the layout has no control that runs the method: bind `run` under a control's `on`"] : [];
1816
+ return [...invalid, ...runless, ...layoutProblems(descriptor, spec)];
1817
+ }
1818
+ function bindsRun(spec) {
1819
+ const isRun = (binding) => typeof binding === "object" && binding !== null && binding.action === "run";
1820
+ const elements = spec.elements;
1821
+ if (typeof elements !== "object" || elements === null) return false;
1822
+ return Object.values(elements).some((element) => {
1823
+ if (typeof element !== "object" || element === null) return false;
1824
+ const on = element.on;
1825
+ if (typeof on !== "object" || on === null) return false;
1826
+ return Object.values(on).some(
1827
+ (binding) => Array.isArray(binding) ? binding.some(isRun) : isRun(binding)
1828
+ );
1829
+ });
1428
1830
  }
1429
- function interpolatedPaths(template, itemPath) {
1430
- return [...template.matchAll(/\$\{([^}]+)\}/g)].flatMap((match) => {
1431
- const raw = match[1];
1432
- if (raw === void 0) return [];
1433
- if (raw.startsWith("/")) return [raw];
1434
- return [itemPath(raw) ?? `/${raw}`];
1435
- });
1436
- }
1437
- function mentionedPaths(spec, parents) {
1438
- const found = { bound: [], read: [], adrift: [] };
1439
- for (const [key, element] of Object.entries(spec.elements)) {
1440
- const itemPath = itemPathResolver(spec, key, parents);
1441
- const walk = (value) => {
1442
- if (Array.isArray(value)) {
1443
- value.forEach(walk);
1444
- return;
1445
- }
1446
- if (typeof value !== "object" || value === null) return;
1447
- const record = value;
1448
- if (typeof record.$bindState === "string") found.bound.push(record.$bindState);
1449
- if (typeof record.$state === "string") found.read.push(record.$state);
1450
- if (typeof record.$template === "string") {
1451
- found.read.push(...interpolatedPaths(record.$template, itemPath));
1452
- }
1453
- if (typeof record.$bindItem === "string") {
1454
- const path = itemPath(record.$bindItem);
1455
- if (path === void 0) found.adrift.push(key);
1456
- else found.bound.push(path);
1457
- }
1458
- if (typeof record.$item === "string") {
1459
- const path = itemPath(record.$item);
1460
- if (path === void 0) found.adrift.push(key);
1461
- else found.read.push(path);
1462
- }
1463
- Object.values(record).forEach(walk);
1464
- };
1465
- walk(element.props);
1466
- walk(element.visible);
1467
- }
1468
- return found;
1469
- }
1470
- function staleReads(read, root, resolves) {
1471
- const under = read.filter((path) => isUnder(root, path));
1472
- return [...new Set(under)].filter((path) => !resolves(path));
1473
- }
1474
- function staleRepeats(spec, parents, root, resolves, side) {
1475
- const problems = [];
1476
- for (const [key, element] of Object.entries(spec.elements)) {
1477
- if (!element.repeat) continue;
1478
- const listPath = repeatListPathOf(spec, key, parents);
1479
- if (listPath === void 0 || !isUnder(root, listPath)) continue;
1480
- if (!resolves(listPath)) {
1481
- problems.push(`${key}: repeats over ${listPath}, which no ${side} has`);
1482
- }
1483
- }
1484
- return problems;
1831
+
1832
+ // src/generative/brief.ts
1833
+ var DESIGNER_BRIEF_CONCEPT = "generative.Brief";
1834
+ var RUN_COMPONENT = "Cta";
1835
+ var COMPOSER_RUN_COMPONENT = "Composer";
1836
+ function isDelegatedInput(field) {
1837
+ return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "list" || field.kind === "unknown" || field.kind === "enum" && field.options.includes("");
1485
1838
  }
1486
- var NOT_A_VALUE = {
1487
- object: { what: "a structure", instead: "a structure is shown through its members" },
1488
- list: { what: "a list", instead: "a list is laid out as a repeat or a DataTable" },
1489
- document: { what: "a file", instead: "a file is delegated to the kernel's own control" },
1490
- image: { what: "a file", instead: "a file is delegated to the kernel's own control" }
1491
- };
1492
- var NOT_VALUES = {
1493
- object: "structures",
1494
- list: "lists",
1495
- document: "files",
1496
- image: "files"
1497
- };
1498
- var listPropsCache;
1499
- function listProps() {
1500
- if (listPropsCache) return listPropsCache;
1501
- const found = /* @__PURE__ */ new Map([
1502
- ["DataTable", /* @__PURE__ */ new Map([["rows", "anything"]])]
1503
- ]);
1504
- const components3 = catalog.data.components;
1505
- for (const [type, definition] of Object.entries(components3)) {
1506
- const shape = definition.props?.shape;
1507
- for (const [prop, schema] of Object.entries(shape ?? {})) {
1508
- const items = listItemsOf(schema);
1509
- if (items === void 0) continue;
1510
- if (!found.has(type)) found.set(type, /* @__PURE__ */ new Map());
1511
- found.get(type).set(prop, items);
1512
- }
1513
- }
1514
- listPropsCache = found;
1515
- return found;
1839
+ function isDelegatedResult(field, frame = "page") {
1840
+ if (isNativeValueNode(field)) return true;
1841
+ if (frame === "result" && (field.kind === "image" || field.kind === "date" && !field.datetime))
1842
+ return false;
1843
+ if (field.kind === "list" && isNativeValueNode(field.item)) return true;
1844
+ return field.kind === "document" || field.kind === "image" || field.kind === "date" || field.kind === "prose" || field.kind === "unknown";
1516
1845
  }
1517
- var VALUE_SCHEMAS = /* @__PURE__ */ new Set(["string", "number", "boolean", "enum", "literal"]);
1518
- function unwrapped(schema) {
1519
- let current = schema;
1520
- for (let depth = 0; depth < 8; depth += 1) {
1521
- const def = current.def;
1522
- if (!def) return void 0;
1523
- if (def.innerType === void 0) return def;
1524
- current = def.innerType;
1846
+ function kindLabel(field) {
1847
+ if (isNativeHtmlNode(field)) return "markup (native.Html)";
1848
+ if (isNativeDateNode(field)) return "date (native.Date)";
1849
+ if (isNativeCompositeNode(field)) return "composite (native.Composite)";
1850
+ switch (field.kind) {
1851
+ case "text":
1852
+ return "text";
1853
+ case "prose":
1854
+ return "prose (markdown)";
1855
+ case "number":
1856
+ return field.integer ? "integer" : "number";
1857
+ case "boolean":
1858
+ return "boolean";
1859
+ case "enum":
1860
+ return `choice of ${field.options.map((option) => JSON.stringify(option)).join(" | ")}`;
1861
+ case "date":
1862
+ return field.datetime ? "date with time" : "date";
1863
+ case "document":
1864
+ return "document (a file)";
1865
+ case "image":
1866
+ return "image (a file)";
1867
+ case "object":
1868
+ return `structure${field.conceptRef ? ` ${field.conceptRef}` : ""}`;
1869
+ case "list":
1870
+ return `list of ${kindLabel(field.item)}`;
1871
+ case "unknown":
1872
+ return "unknown";
1873
+ default:
1874
+ return field;
1525
1875
  }
1526
- return void 0;
1527
- }
1528
- function listItemsOf(schema) {
1529
- const def = unwrapped(schema);
1530
- if (def?.type !== "array") return void 0;
1531
- const element = unwrapped(def.element);
1532
- return element?.type !== void 0 && VALUE_SCHEMAS.has(element.type) ? "values" : "anything";
1533
1876
  }
1534
- function nonScalarReads(spec, parents, root, fieldAt) {
1535
- const problems = [];
1536
- const lists = listProps();
1537
- for (const [key, element] of Object.entries(spec.elements)) {
1538
- const itemPath = itemPathResolver(spec, key, parents);
1539
- const listy = lists.get(element.type);
1540
- const check = (prop, path) => {
1541
- if (!isUnder(root, path)) return;
1542
- const field = fieldAt(path);
1543
- if (!field) return;
1544
- const wrong = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind] : void 0;
1545
- if (!wrong) return;
1546
- problems.push(
1547
- `${key}: ${prop} shows ${path}, which is ${wrong.what} and not a value; a prop that shows a value takes a scalar path, and ${wrong.instead}`
1548
- );
1549
- };
1550
- const checkList = (prop, path, items) => {
1551
- if (!isUnder(root, path)) return;
1552
- const field = fieldAt(path);
1553
- if (!field || field.kind === "unknown") return;
1554
- if (field.kind !== "list") {
1555
- const what = hasOwnProp(NOT_A_VALUE, field.kind) ? NOT_A_VALUE[field.kind].what : "a value";
1556
- problems.push(
1557
- `${key}: ${prop} takes a list, and ${path} is ${what}; a prop that takes a list reads a list path`
1558
- );
1559
- return;
1560
- }
1561
- if (items !== "values") return;
1562
- const of = hasOwnProp(NOT_VALUES, field.item.kind) ? NOT_VALUES[field.item.kind] : void 0;
1563
- if (!of) return;
1564
- problems.push(
1565
- `${key}: ${prop} takes a list of values, and ${path} is a list of ${of}; a list of ${of} is laid out as a repeat or a DataTable`
1566
- );
1567
- };
1568
- const walk = (prop, value) => {
1569
- if (Array.isArray(value)) {
1570
- value.forEach((entry) => walk(prop, entry));
1571
- return;
1572
- }
1573
- if (typeof value !== "object" || value === null) return;
1574
- const record = value;
1575
- if (typeof record.$state === "string") check(prop, record.$state);
1576
- if (typeof record.$item === "string") {
1577
- const path = itemPath(record.$item);
1578
- if (path !== void 0) check(prop, path);
1579
- }
1580
- if (typeof record.$template === "string") {
1581
- for (const path of interpolatedPaths(record.$template, itemPath)) check(prop, path);
1582
- }
1583
- for (const [name, entry] of Object.entries(record)) {
1584
- if (name !== "$cond") walk(prop, entry);
1585
- }
1586
- };
1587
- for (const [prop, value] of Object.entries(element.props ?? {})) {
1588
- const items = listy?.get(prop);
1589
- if (items === void 0 || Array.isArray(value)) {
1590
- walk(prop, value);
1591
- continue;
1592
- }
1593
- if (typeof value !== "object" || value === null) continue;
1594
- const record = value;
1595
- if (typeof record.$state === "string") checkList(prop, record.$state, items);
1596
- if (typeof record.$item === "string") {
1597
- const path = itemPath(record.$item);
1598
- if (path !== void 0) checkList(prop, path, items);
1599
- }
1600
- }
1877
+ function constraints(field) {
1878
+ const notes = [];
1879
+ if (field.kind === "number") {
1880
+ if (field.min !== void 0) notes.push(`min ${field.min}`);
1881
+ if (field.max !== void 0) notes.push(`max ${field.max}`);
1601
1882
  }
1602
- return problems;
1603
- }
1604
- function boundProblems(bound, inputs) {
1605
- const problems = [];
1606
- const underInputs = bound.filter((path) => isUnder(INPUTS_ROOT, path));
1607
- if (!inputs) {
1608
- if (underInputs.length > 0) {
1609
- problems.push(`a result page binds ${underInputs.join(", ")}; a result page writes nothing`);
1610
- }
1611
- } else {
1612
- for (const path of underInputs) {
1613
- if (!inputFieldAtPath(inputs, path)) {
1614
- problems.push(`${path} is bound, and no input has it`);
1615
- }
1616
- }
1883
+ if (field.kind === "text" || field.kind === "prose") {
1884
+ if (field.minLength !== void 0) notes.push(`at least ${field.minLength} characters`);
1885
+ if (field.maxLength !== void 0) notes.push(`at most ${field.maxLength} characters`);
1886
+ if (field.format) notes.push(`format ${field.format}`);
1617
1887
  }
1618
- for (const path of bound) {
1619
- if (isUnder(RESULT_ROOT, path)) {
1620
- problems.push(
1621
- `${path} is bound; a layout may not write into ${RESULT_ROOT}, which the run fills`
1622
- );
1623
- }
1888
+ if (field.kind === "list") {
1889
+ if (field.itemCount !== void 0) notes.push(`at least ${field.itemCount} items`);
1890
+ if (field.maxItemCount !== void 0) notes.push(`at most ${field.maxItemCount} items`);
1624
1891
  }
1625
- return problems;
1626
- }
1627
- function repeatPaths(spec) {
1628
- const found = [];
1629
- for (const element of Object.values(spec.elements)) {
1630
- const statePath = element.repeat?.statePath;
1631
- if (typeof statePath === "string") found.push(statePath);
1892
+ if (field.defaultValue !== void 0) notes.push(`default ${JSON.stringify(field.defaultValue)}`);
1893
+ if (field.examples && field.examples.length > 0) {
1894
+ notes.push(`examples ${field.examples.map((example) => JSON.stringify(example)).join(", ")}`);
1632
1895
  }
1633
- return found;
1634
- }
1635
- function isOffered(path, offered) {
1636
- if (offered.bound.has(path) || offered.repeated.has(path)) return true;
1637
- return offered.delegated.some((at) => path === at || path.startsWith(`${at}/`));
1638
- }
1639
- function uncoveredUnder(field, path, offered) {
1640
- if (isOffered(path, offered)) return [];
1641
- if (field.kind === "object") {
1642
- return field.fields.filter((child) => child.required).flatMap((child) => uncoveredUnder(child, joinPath(path, child.name), offered));
1896
+ if (field.hints && Object.keys(field.hints).length > 0) {
1897
+ notes.push(
1898
+ `hints ${Object.entries(field.hints).map(([key, value]) => `${key}=${value}`).join(", ")}`
1899
+ );
1643
1900
  }
1644
- return [path];
1901
+ return notes;
1645
1902
  }
1646
- function layoutProblems(descriptor, spec) {
1647
- try {
1648
- return collectLayoutProblems(descriptor, spec);
1649
- } catch (error) {
1650
- return [`the layout is not a well-formed spec: ${String(error)}`];
1651
- }
1903
+ function entryOf(field, path, depth, side, relative, seeded, frame = "page") {
1904
+ const notes = constraints(field);
1905
+ return {
1906
+ depth,
1907
+ path,
1908
+ kind: kindLabel(field),
1909
+ name: field.name,
1910
+ title: field.title && field.title !== field.name ? field.title : void 0,
1911
+ description: field.description,
1912
+ required: side === "input" ? field.required : void 0,
1913
+ gating: side === "input" && field.gating ? true : void 0,
1914
+ notes: notes.length > 0 ? notes : void 0,
1915
+ default: seeded || field.defaultValue === void 0 ? void 0 : JSON.stringify(field.defaultValue),
1916
+ delegated: side === "input" ? isDelegatedInput(field) : isDelegatedResult(field, frame),
1917
+ relative: relative ? true : void 0
1918
+ };
1652
1919
  }
1653
- function collectLayoutProblems(descriptor, spec) {
1654
- const problems = [];
1655
- const delegated = [];
1656
- const parents = parentMapOf(spec);
1657
- for (const [key, element] of Object.entries(spec.elements)) {
1658
- const written = element.props?.path;
1659
- const path = typeof written === "string" ? absoluteHatchPath(spec, key, written, parents) : void 0;
1660
- if (element.type === "MthdsField") {
1661
- if (!path || !inputFieldAtPath(descriptor.inputs ?? [], path)) {
1662
- problems.push(`${key}: MthdsField delegates ${String(written)}, which no input has`);
1663
- } else {
1664
- delegated.push(path);
1665
- }
1920
+ function describe(field, path, depth, side, entries, seeded = false, frame = "page") {
1921
+ const entry = entryOf(field, path, depth, side, false, seeded, frame);
1922
+ entries.push(entry);
1923
+ if (entry.delegated) return;
1924
+ if (field.kind === "object") {
1925
+ const seededBelow = seeded || field.defaultValue !== void 0 || side === "input" && !field.required;
1926
+ for (const child of field.fields) {
1927
+ describe(child, joinPath(path, child.name), depth + 1, side, entries, seededBelow, frame);
1666
1928
  }
1667
- if (element.type === "MthdsResult") {
1668
- if (!path || !descriptor.result || !resultFieldAtPath(descriptor.result, path)) {
1669
- problems.push(`${key}: MthdsResult delegates ${String(written)}, which no result has`);
1929
+ }
1930
+ if (field.kind === "list" && side === "result") {
1931
+ const item = field.item;
1932
+ entry.item_kind = kindLabel(item);
1933
+ entry.item_description = item.description;
1934
+ if (item.kind === "object" && !isDelegatedResult(item, frame)) {
1935
+ entry.item_laid_out = true;
1936
+ for (const child of item.fields) {
1937
+ describeRelative(child, child.name, depth + 2, entries, side, frame);
1670
1938
  }
1671
1939
  }
1672
1940
  }
1673
- const { bound, read, adrift } = mentionedPaths(spec, parents);
1674
- for (const key of new Set(adrift)) {
1675
- problems.push(`${key}: reads the current item, and no repeat above it has one`);
1941
+ }
1942
+ function describeRelative(field, relativePath, depth, entries, side = "result", frame = "page") {
1943
+ const entry = entryOf(field, relativePath, depth, side, true, false, frame);
1944
+ entries.push(entry);
1945
+ if (entry.delegated) return;
1946
+ if (field.kind === "object") {
1947
+ for (const child of field.fields) {
1948
+ describeRelative(child, joinPath(relativePath, child.name), depth + 1, entries, side, frame);
1949
+ }
1676
1950
  }
1677
- problems.push(...boundProblems(bound, descriptor.inputs));
1678
- if (!descriptor.inputs) {
1679
- const result = descriptor.result;
1680
- const fieldAt2 = (path) => result ? resultFieldAtPath(result, path) : void 0;
1681
- const resolves2 = (path) => fieldAt2(path) !== void 0;
1682
- problems.push(...staleRepeats(spec, parents, RESULT_ROOT, resolves2, "result"));
1683
- for (const path of staleReads(read, RESULT_ROOT, resolves2)) {
1684
- problems.push(`${path} is read, and no result has it`);
1951
+ if (field.kind === "list" && side === "result") {
1952
+ const item = field.item;
1953
+ entry.item_kind = kindLabel(item);
1954
+ entry.item_description = item.description;
1955
+ if (item.kind === "object" && !isDelegatedResult(item, frame)) {
1956
+ entry.item_laid_out = true;
1957
+ for (const child of item.fields) {
1958
+ describeRelative(
1959
+ child,
1960
+ joinPath(relativePath, "<i>", child.name),
1961
+ depth + 2,
1962
+ entries,
1963
+ side,
1964
+ frame
1965
+ );
1966
+ }
1685
1967
  }
1686
- problems.push(...nonScalarReads(spec, parents, RESULT_ROOT, fieldAt2));
1687
- return problems;
1688
1968
  }
1689
- const inputs = descriptor.inputs;
1690
- const fieldAt = (path) => inputFieldAtPath(inputs, path);
1691
- const resolves = (path) => fieldAt(path) !== void 0;
1692
- problems.push(...staleRepeats(spec, parents, INPUTS_ROOT, resolves, "input"));
1693
- for (const path of staleReads(read, INPUTS_ROOT, resolves)) {
1694
- problems.push(`${path} is read, and no input has it`);
1969
+ }
1970
+ function returnsOf(result) {
1971
+ const shape = result.kind === "list" ? result.item : result;
1972
+ const members = shape.kind === "object" ? shape.fields : [shape];
1973
+ return members.map((member) => {
1974
+ const title = member.title ?? member.name.replace(/_/g, " ");
1975
+ return member.description && member.description !== title ? `${title}: ${member.description}` : title;
1976
+ });
1977
+ }
1978
+ function styleOf(style) {
1979
+ if (!style) return void 0;
1980
+ const { name, direction } = APP_STYLES[style];
1981
+ return { name, direction };
1982
+ }
1983
+ function inputBrief(subject, fields, { frame = "page", style, result } = {}) {
1984
+ const paths = [];
1985
+ for (const field of fields) {
1986
+ describe(field, joinPath(INPUTS_ROOT, field.name), 0, "input", paths, false, frame);
1695
1987
  }
1696
- problems.push(...nonScalarReads(spec, parents, INPUTS_ROOT, fieldAt));
1697
- const offered = {
1698
- bound: new Set(bound),
1699
- repeated: new Set(repeatPaths(spec)),
1700
- delegated
1988
+ return {
1989
+ side: "input",
1990
+ frame,
1991
+ pipe_ref: subject.pipeRef,
1992
+ description: subject.description,
1993
+ name: subject.name,
1994
+ paths,
1995
+ run_control: frame === "composer" ? COMPOSER_RUN_COMPONENT : RUN_COMPONENT,
1996
+ ...frame === "composer" && result ? { returns: returnsOf(result) } : {},
1997
+ ...style ? { style: styleOf(style) } : {}
1701
1998
  };
1702
- for (const field of inputs) {
1703
- if (!field.required) continue;
1704
- for (const path of uncoveredUnder(field, joinPath(INPUTS_ROOT, field.name), offered)) {
1705
- problems.push(`${path} is required, and the layout offers nowhere to enter it`);
1999
+ }
2000
+ function resultBrief(subject, field, state, { frame = "page", style } = {}) {
2001
+ const paths = [];
2002
+ if (field.kind === "object" && !isDelegatedResult(field, frame)) {
2003
+ paths.push({
2004
+ depth: 0,
2005
+ path: RESULT_ROOT,
2006
+ kind: kindLabel(field),
2007
+ description: field.description,
2008
+ delegated: false
2009
+ });
2010
+ for (const child of field.fields) {
2011
+ describe(child, joinPath(RESULT_ROOT, child.name), 1, "result", paths, false, frame);
1706
2012
  }
2013
+ } else {
2014
+ describe(field, RESULT_ROOT, 0, "result", paths, false, frame);
1707
2015
  }
1708
- return problems;
1709
- }
1710
- function layoutFits(descriptor, spec) {
1711
- return layoutProblems(descriptor, spec).length === 0;
2016
+ return {
2017
+ side: "result",
2018
+ frame,
2019
+ pipe_ref: subject.pipeRef,
2020
+ description: subject.description,
2021
+ paths,
2022
+ ...style ? { style: styleOf(style) } : {},
2023
+ sample_state: JSON.stringify(state, null, 2)
2024
+ };
1712
2025
  }
1713
2026
  function specToJsonl(spec) {
1714
2027
  const lines = [];
@@ -1764,7 +2077,7 @@ function specFromJsonl(jsonl) {
1764
2077
  function jsonlLines(jsonl) {
1765
2078
  return jsonl.split("\n").filter((line) => line.trim().length > 0);
1766
2079
  }
1767
- var BrandContext = React3.createContext(null);
2080
+ var BrandContext = React4.createContext(null);
1768
2081
  function BrandProvider({
1769
2082
  manifest,
1770
2083
  children
@@ -1773,7 +2086,7 @@ function BrandProvider({
1773
2086
  return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
1774
2087
  }
1775
2088
  function useBrand() {
1776
- const manifest = React3.useContext(BrandContext);
2089
+ const manifest = React4.useContext(BrandContext);
1777
2090
  if (!manifest)
1778
2091
  throw new Error(
1779
2092
  "useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
@@ -1784,7 +2097,7 @@ var WEIGHTS = "400;500;600;700";
1784
2097
  function useWebfont(webfont) {
1785
2098
  const provider = webfont?.provider;
1786
2099
  const family = webfont?.family;
1787
- React3.useEffect(() => {
2100
+ React4.useEffect(() => {
1788
2101
  if (!provider || !family) return;
1789
2102
  const key = `${provider}:${family}`;
1790
2103
  if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
@@ -1804,9 +2117,19 @@ function useWebfont(webfont) {
1804
2117
  document.head.appendChild(link);
1805
2118
  }, [provider, family]);
1806
2119
  }
2120
+ var FrameHostContext = React4.createContext({});
2121
+ function FrameHostProvider({
2122
+ host,
2123
+ children
2124
+ }) {
2125
+ return /* @__PURE__ */ jsx(FrameHostContext.Provider, { value: host, children });
2126
+ }
2127
+ function useFrameHost() {
2128
+ return React4.useContext(FrameHostContext);
2129
+ }
1807
2130
  function useBoundField(literal, binding, empty, { checks, validateOn }) {
1808
2131
  const [boundValue, setBoundValue] = useBoundProp(literal ?? void 0, binding);
1809
- const [localValue, setLocalValue] = React3.useState(literal ?? empty);
2132
+ const [localValue, setLocalValue] = React4.useState(literal ?? empty);
1810
2133
  const isBound = Boolean(binding);
1811
2134
  const hasValidation = Boolean(binding && checks?.length);
1812
2135
  const when = validateOn ?? "change";
@@ -1843,13 +2166,29 @@ function Card({
1843
2166
  props,
1844
2167
  children
1845
2168
  }) {
1846
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border bg-card p-6 text-card-foreground", children: [
1847
- props.title || props.description ? /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-1.5", children: [
1848
- props.title ? /* @__PURE__ */ jsx("h3", { className: "text-lg leading-none font-semibold", children: props.title }) : null,
1849
- props.description ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: props.description }) : null
1850
- ] }) : null,
1851
- children
1852
- ] });
2169
+ return (
2170
+ // A style's panel: a host writes the style's field fill onto `--input`
2171
+ // here, as on its own panel, so the fields inside do not sink into it.
2172
+ // A panel's corner is one and a half times a control's, as the rail's is.
2173
+ /* @__PURE__ */ jsxs(
2174
+ "div",
2175
+ {
2176
+ "data-style-panel": "",
2177
+ className: cn(
2178
+ "rounded-[calc(var(--radius,0.5rem)*1.5)] p-6 text-card-foreground",
2179
+ panelSurfaceClass,
2180
+ panelFlatShadowClass
2181
+ ),
2182
+ children: [
2183
+ props.title || props.description ? /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-1.5", children: [
2184
+ props.title ? /* @__PURE__ */ jsx("h3", { className: cn("text-lg leading-none", headingClass(600)), children: props.title }) : null,
2185
+ props.description ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: props.description }) : null
2186
+ ] }) : null,
2187
+ children
2188
+ ]
2189
+ }
2190
+ )
2191
+ );
1853
2192
  }
1854
2193
  var GAP = {
1855
2194
  none: "gap-0",
@@ -1929,17 +2268,26 @@ function Collapsible({
1929
2268
  open: props.defaultOpen ?? false,
1930
2269
  "data-slot": "collapsible",
1931
2270
  children: [
1932
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer list-none rounded-md px-4 py-3 text-sm font-medium select-none focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", children: props.title }),
2271
+ /* @__PURE__ */ jsxs("summary", { className: "flex min-h-11 cursor-pointer list-none items-center justify-between gap-3 rounded-md px-4 py-3 text-sm font-medium select-none focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset [&::-webkit-details-marker]:hidden", children: [
2272
+ /* @__PURE__ */ jsx("span", { children: props.title }),
2273
+ /* @__PURE__ */ jsx(
2274
+ ChevronDown,
2275
+ {
2276
+ "aria-hidden": "true",
2277
+ className: "size-4 shrink-0 text-muted-foreground transition-transform [details[open]>summary_&]:rotate-180"
2278
+ }
2279
+ )
2280
+ ] }),
1933
2281
  /* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 py-3", children })
1934
2282
  ]
1935
2283
  }
1936
2284
  );
1937
2285
  }
1938
2286
  var HEADING = {
1939
- h1: "text-3xl font-bold tracking-tight",
1940
- h2: "text-2xl font-semibold tracking-tight",
1941
- h3: "text-lg font-semibold",
1942
- h4: "text-base font-semibold"
2287
+ h1: cn("text-3xl", headingClass(700, true)),
2288
+ h2: cn("text-2xl", headingClass(600, true)),
2289
+ h3: cn("text-lg", headingClass(600)),
2290
+ h4: cn("text-base", headingClass(600))
1943
2291
  };
1944
2292
  function Heading({
1945
2293
  props
@@ -2053,7 +2401,7 @@ function Progress({
2053
2401
  ] });
2054
2402
  }
2055
2403
  function useControlId(name) {
2056
- return `jr-${name}-${React3.useId()}`;
2404
+ return `jr-${name}-${React4.useId()}`;
2057
2405
  }
2058
2406
  function Input({
2059
2407
  props,
@@ -2116,7 +2464,8 @@ function Textarea({
2116
2464
  /* @__PURE__ */ jsx(FieldError, { message: field.error })
2117
2465
  ] });
2118
2466
  }
2119
- var NATIVE_CHECK = cn("size-4", checkedAccentClass, focusOutlineClass);
2467
+ var NATIVE_CHECK = cn("size-4 shrink-0", checkedAccentClass, focusOutlineClass);
2468
+ var NATIVE_CHECK_ROW = "flex items-center gap-2 text-sm max-sm:min-h-11";
2120
2469
  function Radio({
2121
2470
  props,
2122
2471
  bindings,
@@ -2127,7 +2476,7 @@ function Radio({
2127
2476
  const labelOf = enumLabeler(props.options ?? [], useFieldPresentation());
2128
2477
  return /* @__PURE__ */ jsxs("fieldset", { className: "space-y-2", "aria-invalid": field.error ? true : void 0, children: [
2129
2478
  /* @__PURE__ */ jsx("legend", { className: LABEL, children: props.label }),
2130
- /* @__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: [
2479
+ /* @__PURE__ */ jsx("div", { className: "space-y-2 max-sm:space-y-0", children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsxs("label", { className: NATIVE_CHECK_ROW, children: [
2131
2480
  /* @__PURE__ */ jsx(
2132
2481
  "input",
2133
2482
  {
@@ -2156,7 +2505,7 @@ function Checkbox({
2156
2505
  const id = useControlId(props.name);
2157
2506
  const field = useBoundField(props.checked, bindings?.checked, false, props);
2158
2507
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2159
- /* @__PURE__ */ jsxs("label", { htmlFor: id, className: "flex items-center gap-2 text-sm", children: [
2508
+ /* @__PURE__ */ jsxs("label", { htmlFor: id, className: NATIVE_CHECK_ROW, children: [
2160
2509
  /* @__PURE__ */ jsx(
2161
2510
  "input",
2162
2511
  {
@@ -2231,9 +2580,9 @@ function Button({
2231
2580
  }
2232
2581
  );
2233
2582
  }
2234
- var DescriptorContext = React3.createContext({});
2583
+ var DescriptorContext = React4.createContext({});
2235
2584
  function useDescriptorScope() {
2236
- return React3.useContext(DescriptorContext);
2585
+ return React4.useContext(DescriptorContext);
2237
2586
  }
2238
2587
  function DescriptorProvider({
2239
2588
  scope,
@@ -2280,13 +2629,28 @@ function useAbsolutePath(path) {
2280
2629
  if (path.startsWith("/")) return path;
2281
2630
  return repeat ? `${repeat.basePath}/${path}` : void 0;
2282
2631
  }
2283
- function MthdsField({ props }) {
2284
- const scope = React3.useContext(DescriptorContext);
2632
+ function withoutOptionalMark(label) {
2633
+ return label.replace(/\s*\(optional\)\s*$/i, "") || label;
2634
+ }
2635
+ function MthdsField({
2636
+ props
2637
+ }) {
2638
+ const scope = React4.useContext(DescriptorContext);
2285
2639
  const path = useAbsolutePath(props.path) ?? "";
2286
- const field = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
2640
+ const found = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
2641
+ const field = React4.useMemo(
2642
+ () => found && (props.label || props.hint) ? {
2643
+ ...found,
2644
+ // The control marks an optional field itself, so a label that
2645
+ // says "(optional)" too would say it twice.
2646
+ title: props.label ? withoutOptionalMark(props.label) : found.title,
2647
+ description: props.hint || found.description
2648
+ } : found,
2649
+ [found, props.label, props.hint]
2650
+ );
2287
2651
  const value = useStateValue(path);
2288
2652
  const { set } = useStateStore();
2289
- const onChange = React3.useCallback((next) => set(path, next), [set, path]);
2653
+ const onChange = React4.useCallback((next) => set(path, next), [set, path]);
2290
2654
  if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "input" });
2291
2655
  return /* @__PURE__ */ jsx(
2292
2656
  FieldRenderer,
@@ -2300,7 +2664,7 @@ function MthdsField({ props }) {
2300
2664
  );
2301
2665
  }
2302
2666
  function MthdsResult({ props }) {
2303
- const scope = React3.useContext(DescriptorContext);
2667
+ const scope = React4.useContext(DescriptorContext);
2304
2668
  const path = useAbsolutePath(props.path) ?? "";
2305
2669
  const field = scope.result && path ? resultFieldAtPath(scope.result, path) : void 0;
2306
2670
  const value = useStateValue(path);
@@ -2313,7 +2677,7 @@ function AccessibleSelect({ props, bindings, emit }) {
2313
2677
  props.value ?? void 0,
2314
2678
  bindings?.value
2315
2679
  );
2316
- const [localValue, setLocalValue] = React3.useState("");
2680
+ const [localValue, setLocalValue] = React4.useState("");
2317
2681
  const isBound = Boolean(bindings?.value);
2318
2682
  const value = isBound ? boundValue ?? "" : localValue;
2319
2683
  const setValue = isBound ? setBoundValue : setLocalValue;
@@ -2337,7 +2701,7 @@ function AccessibleSelect({ props, bindings, emit }) {
2337
2701
  emit("change");
2338
2702
  },
2339
2703
  children: [
2340
- /* @__PURE__ */ jsx(SelectTrigger, { id, className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: props.placeholder ?? "Select..." }) }),
2704
+ /* @__PURE__ */ jsx(SelectTrigger, { id, className: "h-11 w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: props.placeholder ?? "Select..." }) }),
2341
2705
  /* @__PURE__ */ jsx(SelectContent, { children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsx(SelectItem, { value: option, children: labelOf(option) }, `${index}-${option}`)) })
2342
2706
  ]
2343
2707
  }
@@ -2345,7 +2709,7 @@ function AccessibleSelect({ props, bindings, emit }) {
2345
2709
  errors.length > 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors[0] }) : null
2346
2710
  ] });
2347
2711
  }
2348
- function valueAt(row, relativePath) {
2712
+ function valueAt2(row, relativePath) {
2349
2713
  let current = row;
2350
2714
  for (const segment of relativePath.split("/").filter((part) => part.length > 0)) {
2351
2715
  if (typeof current !== "object" || current === null) return void 0;
@@ -2362,6 +2726,21 @@ function formatCell(value) {
2362
2726
  if (Array.isArray(value)) return value.map(formatCell).join(", ");
2363
2727
  return JSON.stringify(value);
2364
2728
  }
2729
+ function formatColumnCell(value, format) {
2730
+ const written = format === "date" ? readDateContent(value)?.date : void 0;
2731
+ const day = written === void 0 ? null : /^\d{4}-\d{2}-\d{2}/.exec(written);
2732
+ if (day) {
2733
+ const date = /* @__PURE__ */ new Date(`${day[0]}T12:00:00Z`);
2734
+ if (!Number.isNaN(date.getTime()))
2735
+ return date.toLocaleDateString("en-GB", {
2736
+ day: "numeric",
2737
+ month: "short",
2738
+ year: "numeric",
2739
+ timeZone: "UTC"
2740
+ });
2741
+ }
2742
+ return formatCell(value);
2743
+ }
2365
2744
  function DataTable({ props }) {
2366
2745
  const rows = Array.isArray(props.rows) ? props.rows : [];
2367
2746
  const columns = props.columns ?? [];
@@ -2376,7 +2755,7 @@ function DataTable({ props }) {
2376
2755
  },
2377
2756
  column.path
2378
2757
  )) }) }),
2379
- /* @__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)) })
2758
+ /* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border/60 last:border-b-0", children: columns.map((column) => /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top text-foreground", children: formatColumnCell(valueAt2(row, column.path), column.format) }, column.path)) }, index)) })
2380
2759
  ] }) });
2381
2760
  }
2382
2761
  function numberFormat(format) {
@@ -2428,14 +2807,14 @@ function Split({
2428
2807
  }
2429
2808
  function Tabs({ props, children }) {
2430
2809
  const tabs = props.tabs ?? [];
2431
- const panels = React3.Children.toArray(children);
2432
- const [value, setValue] = React3.useState(tabs[0]?.value ?? "");
2810
+ const panels = React4.Children.toArray(children);
2811
+ const [value, setValue] = React4.useState(tabs[0]?.value ?? "");
2433
2812
  return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: setValue, className: "w-full", children: [
2434
- /* @__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(
2813
+ /* @__PURE__ */ jsx(TabsPrimitive.List, { className: "inline-flex h-10 items-center justify-start rounded-md bg-muted p-1 text-muted-foreground max-sm:h-auto max-sm:flex-wrap", children: tabs.map((tab) => /* @__PURE__ */ jsx(
2435
2814
  TabsPrimitive.Trigger,
2436
2815
  {
2437
2816
  value: tab.value,
2438
- 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",
2817
+ className: "inline-flex items-center justify-center rounded-sm px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-hidden data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm max-sm:min-h-11 max-sm:min-w-11",
2439
2818
  children: tab.label
2440
2819
  },
2441
2820
  tab.value
@@ -2451,7 +2830,7 @@ function Tabs({ props, children }) {
2451
2830
  ))
2452
2831
  ] });
2453
2832
  }
2454
- 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";
2833
+ var BUTTON_BASE = "inline-flex min-h-11 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50";
2455
2834
  var PRIMARY_BUTTON = cn(BUTTON_BASE, "bg-primary text-primary-foreground hover:bg-primary/90");
2456
2835
  var SECONDARY_BUTTON = cn(
2457
2836
  BUTTON_BASE,
@@ -2459,8 +2838,8 @@ var SECONDARY_BUTTON = cn(
2459
2838
  );
2460
2839
  function Steps({ props, children }) {
2461
2840
  const steps = props.steps ?? [];
2462
- const panels = React3.Children.toArray(children);
2463
- const [index, setIndex] = React3.useState(0);
2841
+ const panels = React4.Children.toArray(children);
2842
+ const [index, setIndex] = React4.useState(0);
2464
2843
  const last = steps.length - 1;
2465
2844
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
2466
2845
  /* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-x-5 gap-y-2", children: steps.map((label, position) => /* @__PURE__ */ jsxs(
@@ -2589,7 +2968,7 @@ function Segmented({ props, bindings, emit }) {
2589
2968
  props.value ?? void 0,
2590
2969
  bindings?.value
2591
2970
  );
2592
- const [localValue, setLocalValue] = React3.useState("");
2971
+ const [localValue, setLocalValue] = React4.useState("");
2593
2972
  const isBound = Boolean(bindings?.value);
2594
2973
  const value = isBound ? boundValue ?? "" : localValue;
2595
2974
  const setValue = isBound ? setBoundValue : setLocalValue;
@@ -2615,7 +2994,7 @@ function Segmented({ props, bindings, emit }) {
2615
2994
  value: option,
2616
2995
  variant: "outline",
2617
2996
  size: "sm",
2618
- className: "rounded-full px-3.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground",
2997
+ className: "rounded-full px-3.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground max-sm:h-11 max-sm:min-w-11",
2619
2998
  children: labelOf(option)
2620
2999
  },
2621
3000
  option
@@ -2629,7 +3008,7 @@ function NumberInput({ props, bindings, emit }) {
2629
3008
  props.value ?? void 0,
2630
3009
  bindings?.value
2631
3010
  );
2632
- const [localValue, setLocalValue] = React3.useState(void 0);
3011
+ const [localValue, setLocalValue] = React4.useState(void 0);
2633
3012
  const isBound = Boolean(bindings?.value);
2634
3013
  const value = isBound ? boundValue : localValue;
2635
3014
  const setValue = isBound ? setBoundValue : setLocalValue;
@@ -2655,7 +3034,7 @@ function NumberInput({ props, bindings, emit }) {
2655
3034
  },
2656
3035
  className: cn(
2657
3036
  fieldControlClass,
2658
- "h-10 px-3 tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none"
3037
+ "h-11 px-3 tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none"
2659
3038
  )
2660
3039
  }
2661
3040
  ),
@@ -2703,7 +3082,330 @@ var components2 = {
2703
3082
  Metric: (ctx) => /* @__PURE__ */ jsx(Metric, { ...ctx })
2704
3083
  };
2705
3084
  var generativeRenderers = components2;
2706
- var ResultSlotContext = React3.createContext(null);
3085
+ var RADIUS = "rounded-[calc(var(--radius,0.5rem)*1.5)]";
3086
+ function useAbsolute(path) {
3087
+ const repeat = useRepeatScope();
3088
+ if (path.startsWith("/")) return path;
3089
+ if (!repeat) return path;
3090
+ return path === "" ? repeat.basePath : `${repeat.basePath}/${path}`;
3091
+ }
3092
+ function asDate(value) {
3093
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}/.test(value)) return void 0;
3094
+ const date = /* @__PURE__ */ new Date(`${value.slice(0, 10)}T12:00:00Z`);
3095
+ return Number.isNaN(date.getTime()) ? void 0 : date;
3096
+ }
3097
+ function Composer({ props, children, emit }) {
3098
+ const host = useFrameHost();
3099
+ const busy = useDescriptorScope().env?.disabled ?? false;
3100
+ const two = props.columns === "2";
3101
+ return /* @__PURE__ */ jsxs(
3102
+ "div",
3103
+ {
3104
+ className: cn("mx-auto flex w-full flex-col gap-7", two ? "max-w-[980px]" : "max-w-[740px]"),
3105
+ children: [
3106
+ /* @__PURE__ */ jsxs("div", { children: [
3107
+ /* @__PURE__ */ jsx(
3108
+ "h1",
3109
+ {
3110
+ className: cn(
3111
+ "text-[32px] leading-[1.1] text-balance text-foreground sm:text-[38px] sm:leading-[1.08]",
3112
+ headingClass(700, true)
3113
+ ),
3114
+ children: props.headline
3115
+ }
3116
+ ),
3117
+ props.lede ? /* @__PURE__ */ jsx("p", { className: "mt-3.5 max-w-[62ch] text-[17px] leading-relaxed text-muted-foreground", children: props.lede }) : null
3118
+ ] }),
3119
+ /* @__PURE__ */ jsxs(
3120
+ "div",
3121
+ {
3122
+ "data-style-panel": "",
3123
+ className: cn(RADIUS, panelSurfaceClass, panelFlatShadowClass, "p-7 max-sm:p-5"),
3124
+ children: [
3125
+ /* @__PURE__ */ jsx(
3126
+ "div",
3127
+ {
3128
+ className: cn(
3129
+ "grid gap-8",
3130
+ two && "md:block md:columns-2 md:gap-x-10 md:[&>*+*]:mt-8 md:[&>*>h2]:break-after-avoid md:[&>*>*:not(h2)]:break-inside-avoid"
3131
+ ),
3132
+ children
3133
+ }
3134
+ ),
3135
+ /* @__PURE__ */ jsxs("div", { className: "sticky bottom-0 z-[2] -mx-7 -mb-7 mt-7 flex items-center justify-between gap-4 rounded-b-[calc(var(--radius,0.5rem)*1.5)] border-t border-border [background-color:var(--panel-fill,var(--card,hsl(0_0%_100%)))] px-7 pt-[18px] pb-7 max-sm:-mx-5 max-sm:-mb-5 max-sm:flex-col-reverse max-sm:items-stretch max-sm:px-5 max-sm:pb-5", children: [
3136
+ host.eta ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2 text-sm text-muted-foreground max-sm:justify-center", children: [
3137
+ /* @__PURE__ */ jsx(Clock, { className: "size-4", "aria-hidden": "true" }),
3138
+ " ",
3139
+ host.eta
3140
+ ] }) : /* @__PURE__ */ jsx("span", {}),
3141
+ /* @__PURE__ */ jsxs(
3142
+ "button",
3143
+ {
3144
+ type: "button",
3145
+ disabled: busy,
3146
+ onClick: () => emit("press"),
3147
+ className: cn(
3148
+ "inline-flex min-h-11 items-center justify-center gap-2 rounded-[var(--radius,0.5rem)] bg-primary px-[22px] text-[15px] font-semibold text-primary-foreground transition-all hover:bg-primary/90",
3149
+ actionShadowClass,
3150
+ focusOutlineClass,
3151
+ "disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:bg-primary"
3152
+ ),
3153
+ children: [
3154
+ props.runLabel,
3155
+ " ",
3156
+ /* @__PURE__ */ jsx(ArrowRight, { className: "size-4", "aria-hidden": "true" })
3157
+ ]
3158
+ }
3159
+ )
3160
+ ] })
3161
+ ]
3162
+ }
3163
+ ),
3164
+ props.notes && props.notes.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "grid gap-x-8 gap-y-2.5 px-1 sm:grid-cols-2", children: props.notes.map((note, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5 text-sm text-muted-foreground", children: [
3165
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: linkTextClass, children: "\u2713" }),
3166
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children: note })
3167
+ ] }, index)) }) : null
3168
+ ]
3169
+ }
3170
+ );
3171
+ }
3172
+ function FieldGroup({ props, children }) {
3173
+ return /* @__PURE__ */ jsxs("section", { className: "flex min-w-0 flex-col gap-5", children: [
3174
+ props.title ? /* @__PURE__ */ jsx("h2", { className: cn("text-[17px] leading-snug text-foreground", headingClass(600)), children: props.title }) : null,
3175
+ children
3176
+ ] });
3177
+ }
3178
+ function ResultHeader({ props }) {
3179
+ const host = useFrameHost();
3180
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-6 max-sm:flex-col", children: [
3181
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
3182
+ props.eyebrow ? /* @__PURE__ */ jsx("p", { className: cn("mb-1.5 text-[13px] font-semibold", linkTextClass), children: props.eyebrow }) : null,
3183
+ /* @__PURE__ */ jsx(
3184
+ "h1",
3185
+ {
3186
+ className: cn(
3187
+ "text-[28px] leading-[1.12] text-balance text-foreground sm:text-[32px]",
3188
+ headingClass(700, true)
3189
+ ),
3190
+ children: props.title
3191
+ }
3192
+ ),
3193
+ props.subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-[15px] text-muted-foreground", children: props.subtitle }) : null
3194
+ ] }),
3195
+ host.actions && host.actions.length > 0 && host.onAction ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 gap-2", children: host.actions.map((label, i) => /* @__PURE__ */ jsx(
3196
+ "button",
3197
+ {
3198
+ type: "button",
3199
+ onClick: () => host.onAction?.(label),
3200
+ className: cn(
3201
+ "inline-flex min-h-11 items-center rounded-[var(--radius,0.5rem)] px-4 text-sm font-semibold sm:min-h-9",
3202
+ focusOutlineClass,
3203
+ i === 0 ? "bg-primary text-primary-foreground" : "border border-border bg-background text-foreground"
3204
+ ),
3205
+ children: label
3206
+ },
3207
+ `${i}-${label}`
3208
+ )) }) : null
3209
+ ] });
3210
+ }
3211
+ function segmentMix(index, count) {
3212
+ return count <= 1 ? 100 : Math.round(100 - index * 75 / (count - 1));
3213
+ }
3214
+ function segmentColor(index, count) {
3215
+ return `color-mix(in oklab, var(--link, var(--primary, hsl(240 5.9% 10%))) ${segmentMix(index, count)}%, var(--muted, hsl(240 4.8% 95.9%)))`;
3216
+ }
3217
+ function amount(value, unit) {
3218
+ if (unit && /^[A-Z]{3}$/.test(unit)) {
3219
+ try {
3220
+ return new Intl.NumberFormat("en-GB", {
3221
+ style: "currency",
3222
+ currency: unit,
3223
+ maximumFractionDigits: 0
3224
+ }).format(value);
3225
+ } catch {
3226
+ }
3227
+ }
3228
+ const n = new Intl.NumberFormat("en-GB", { maximumFractionDigits: 2 }).format(value);
3229
+ return unit ? `${n} ${unit}` : n;
3230
+ }
3231
+ function ProportionBar({ props }) {
3232
+ const rows = Array.isArray(props.items) ? props.items : [];
3233
+ const parts = rows.map((row) => ({
3234
+ label: String(row[props.labelKey] ?? ""),
3235
+ value: Number(row[props.valueKey] ?? 0)
3236
+ })).filter((p) => Number.isFinite(p.value) && p.value > 0);
3237
+ const sum = parts.reduce((s, p) => s + p.value, 0);
3238
+ const total = typeof props.total === "number" ? props.total : sum;
3239
+ const scale = Math.max(sum, total, typeof props.of === "number" ? props.of : 0) || 1;
3240
+ const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
3241
+ return /* @__PURE__ */ jsxs(
3242
+ "div",
3243
+ {
3244
+ "data-style-panel": "",
3245
+ className: cn(
3246
+ RADIUS,
3247
+ panelSurfaceClass,
3248
+ panelFlatShadowClass,
3249
+ "flex flex-col gap-3.5 px-6 py-5"
3250
+ ),
3251
+ children: [
3252
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2.5", children: [
3253
+ /* @__PURE__ */ jsx("span", { className: "text-[15px] text-muted-foreground", children: props.label }),
3254
+ /* @__PURE__ */ jsx("strong", { className: "text-2xl font-semibold tabular-nums text-foreground", children: amount(total, props.unit) }),
3255
+ typeof props.of === "number" ? /* @__PURE__ */ jsxs("span", { className: "text-[15px] text-muted-foreground", children: [
3256
+ "of ",
3257
+ amount(props.of, props.unit)
3258
+ ] }) : null
3259
+ ] }),
3260
+ /* @__PURE__ */ jsx("div", { className: "flex h-2 gap-0.5 overflow-hidden rounded-full bg-muted", "aria-hidden": "true", children: parts.map((p, i) => /* @__PURE__ */ jsx(
3261
+ "span",
3262
+ {
3263
+ style: {
3264
+ width: `${p.value / scale * 100}%`,
3265
+ background: segmentColor(i, parts.length)
3266
+ }
3267
+ },
3268
+ `${i}-${p.label}`
3269
+ )) }),
3270
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-5 gap-y-1", children: parts.map((p, i) => /* @__PURE__ */ jsxs(
3271
+ "li",
3272
+ {
3273
+ className: "inline-flex items-center gap-2 text-sm text-muted-foreground",
3274
+ children: [
3275
+ /* @__PURE__ */ jsx(
3276
+ "span",
3277
+ {
3278
+ className: "size-2 rounded-[2px]",
3279
+ style: {
3280
+ background: segmentColor(i, parts.length)
3281
+ },
3282
+ "aria-hidden": "true"
3283
+ }
3284
+ ),
3285
+ cap(p.label),
3286
+ " ",
3287
+ amount(p.value, props.unit)
3288
+ ]
3289
+ },
3290
+ `${i}-${p.label}`
3291
+ )) })
3292
+ ]
3293
+ }
3294
+ );
3295
+ }
3296
+ var COLOR_VALUE = /^(?:#[0-9a-f]{3,8}|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch)\([\w\s.,%/+-]*\)|[a-z]+)$/i;
3297
+ function Swatches({ props }) {
3298
+ const colors = (props.colors ?? []).filter(
3299
+ (c) => typeof c === "string" && COLOR_VALUE.test(c.trim())
3300
+ );
3301
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: colors.map((color, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3302
+ /* @__PURE__ */ jsx(
3303
+ "span",
3304
+ {
3305
+ className: "h-7 w-11 rounded-[3px] border border-border",
3306
+ style: { backgroundColor: color.trim() }
3307
+ }
3308
+ ),
3309
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px] text-muted-foreground", children: color })
3310
+ ] }, `${color}-${i}`)) });
3311
+ }
3312
+ var ASPECT = {
3313
+ "16:9": "aspect-video",
3314
+ "4:3": "aspect-[4/3]",
3315
+ "1:1": "aspect-square"
3316
+ };
3317
+ function Picture({
3318
+ props
3319
+ }) {
3320
+ const path = useAbsolute(props.path);
3321
+ const value = useStateValue(path);
3322
+ const resolve = useResolveUrl();
3323
+ const content = readImageContent(value);
3324
+ const src = content ? viewableUrl(resolve?.(content.url)) ?? viewableUrl(content.publicUrl) ?? viewableUrl(content.url) : void 0;
3325
+ const aspect = props.aspect && props.aspect !== "auto" ? ASPECT[props.aspect] : void 0;
3326
+ if (!src) return null;
3327
+ return /* @__PURE__ */ jsx(
3328
+ "img",
3329
+ {
3330
+ src,
3331
+ alt: props.alt ?? content?.caption ?? "",
3332
+ referrerPolicy: "no-referrer",
3333
+ className: cn(
3334
+ "block w-full rounded-[var(--radius,0.5rem)] border border-border bg-muted object-cover",
3335
+ aspect
3336
+ )
3337
+ }
3338
+ );
3339
+ }
3340
+ function present(value) {
3341
+ return value !== void 0 && value !== null && value !== "";
3342
+ }
3343
+ function Fact({
3344
+ props
3345
+ }) {
3346
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 rounded-[var(--radius,0.5rem)] border border-border bg-background px-4 py-3", children: [
3347
+ /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.label }),
3348
+ /* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children: present(props.value) ? String(props.value) : "\u2014" }),
3349
+ props.detail ? /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.detail }) : null
3350
+ ] });
3351
+ }
3352
+ function Detail({ props }) {
3353
+ if (!present(props.value)) return null;
3354
+ return (
3355
+ // A rule between the rows of a list of details, never under one set in a
3356
+ // row: there it read as an underline on every detail but the last.
3357
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,8.5rem)_minmax(0,1fr)] gap-3 border-b border-border py-2.5 text-[14px] last:border-b-0 [.flex-row>&]:border-b-0 [.flex-row>&]:grid-cols-[auto_minmax(0,1fr)]", children: [
3358
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: props.label }),
3359
+ /* @__PURE__ */ jsx("span", { className: "text-foreground", children: String(props.value) })
3360
+ ] })
3361
+ );
3362
+ }
3363
+ var DATE_STYLES = {
3364
+ long: { weekday: "long", day: "numeric", month: "long", year: "numeric", timeZone: "UTC" },
3365
+ short: { day: "numeric", month: "short", year: "numeric", timeZone: "UTC" },
3366
+ weekday: { weekday: "short", day: "numeric", month: "long", timeZone: "UTC" }
3367
+ };
3368
+ function DateText({ props }) {
3369
+ const date = asDate(props.value);
3370
+ if (!date) return null;
3371
+ const tone = props.tone === "accent" ? cn("text-[13px] font-semibold", linkTextClass) : props.tone === "muted" ? "text-sm text-muted-foreground" : "text-[15px] text-foreground";
3372
+ return /* @__PURE__ */ jsx("span", { className: cn("block", tone), children: date.toLocaleDateString("en-GB", DATE_STYLES[props.style ?? "long"]) });
3373
+ }
3374
+ function TextList({ props }) {
3375
+ const items = Array.isArray(props.items) ? props.items.filter((x) => typeof x === "string" && x.trim()) : [];
3376
+ if (items.length === 0) return null;
3377
+ const marker = props.marker ?? "bullet";
3378
+ const List2 = marker === "number" ? "ol" : "ul";
3379
+ return /* @__PURE__ */ jsx(List2, { className: "flex flex-col gap-2.5", children: items.map((text, index) => /* @__PURE__ */ jsxs("li", { className: "flex gap-3 text-[15px] leading-relaxed text-foreground", children: [
3380
+ /* @__PURE__ */ jsx(
3381
+ "span",
3382
+ {
3383
+ "aria-hidden": "true",
3384
+ className: cn(
3385
+ "mt-[0.55em] shrink-0",
3386
+ marker === "bullet" && "size-1.5 rounded-full bg-[color:var(--link,var(--primary,hsl(240_5.9%_10%)))]",
3387
+ marker === "number" && cn("mt-0 min-w-5 text-sm font-semibold tabular-nums", linkTextClass),
3388
+ marker === "check" && cn("mt-0", linkTextClass)
3389
+ ),
3390
+ children: marker === "number" ? `${index + 1}.` : marker === "check" ? "\u2713" : null
3391
+ }
3392
+ ),
3393
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children: String(text) })
3394
+ ] }, index)) });
3395
+ }
3396
+ var frameRenderers = {
3397
+ TextList: (ctx) => /* @__PURE__ */ jsx(TextList, { ...ctx }),
3398
+ DateText: (ctx) => /* @__PURE__ */ jsx(DateText, { ...ctx }),
3399
+ Composer: (ctx) => /* @__PURE__ */ jsx(Composer, { ...ctx }),
3400
+ FieldGroup: (ctx) => /* @__PURE__ */ jsx(FieldGroup, { ...ctx }),
3401
+ ResultHeader: (ctx) => /* @__PURE__ */ jsx(ResultHeader, { ...ctx }),
3402
+ ProportionBar: (ctx) => /* @__PURE__ */ jsx(ProportionBar, { ...ctx }),
3403
+ Swatches: (ctx) => /* @__PURE__ */ jsx(Swatches, { ...ctx }),
3404
+ Picture: (ctx) => /* @__PURE__ */ jsx(Picture, { ...ctx }),
3405
+ Fact: (ctx) => /* @__PURE__ */ jsx(Fact, { ...ctx }),
3406
+ Detail: (ctx) => /* @__PURE__ */ jsx(Detail, { ...ctx })
3407
+ };
3408
+ var ResultSlotContext = React4.createContext(null);
2707
3409
  function ResultSlotProvider({
2708
3410
  slot,
2709
3411
  children
@@ -2711,7 +3413,7 @@ function ResultSlotProvider({
2711
3413
  return /* @__PURE__ */ jsx(ResultSlotContext.Provider, { value: slot, children });
2712
3414
  }
2713
3415
  function useResultSlot() {
2714
- return React3.useContext(ResultSlotContext);
3416
+ return React4.useContext(ResultSlotContext);
2715
3417
  }
2716
3418
  var CONTAINER = "mx-auto w-full max-w-6xl px-6 sm:px-8";
2717
3419
  var LABEL2 = "block text-[13.5px] leading-none font-medium text-foreground";
@@ -2773,12 +3475,21 @@ function Hero({ props }) {
2773
3475
  children: props.eyebrow
2774
3476
  }
2775
3477
  ) : null,
2776
- /* @__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 }),
3478
+ /* @__PURE__ */ jsx(
3479
+ "h1",
3480
+ {
3481
+ className: cn(
3482
+ "max-w-2xl text-4xl text-foreground sm:text-[44px] sm:leading-[1.15]",
3483
+ headingClass(700, true)
3484
+ ),
3485
+ children: props.headline
3486
+ }
3487
+ ),
2777
3488
  props.lede ? /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-2xl text-[17px] leading-relaxed text-muted-foreground", children: props.lede }) : null
2778
3489
  ] });
2779
3490
  }
2780
3491
  function Workspace({ props, children }) {
2781
- const [work, rail] = React3.Children.toArray(children);
3492
+ const [work, rail] = React4.Children.toArray(children);
2782
3493
  const railLeft = props.rail === "left";
2783
3494
  return /* @__PURE__ */ jsxs(
2784
3495
  "div",
@@ -2811,7 +3522,7 @@ function ResultPanel() {
2811
3522
  const slot = useResultSlot();
2812
3523
  if (!slot?.content) return null;
2813
3524
  return /* @__PURE__ */ jsxs("section", { className: "border-t border-border py-9", "data-testid": "result-panel", "aria-live": "polite", children: [
2814
- /* @__PURE__ */ jsx("h2", { className: "mb-6 text-xl font-semibold tracking-tight text-foreground", children: slot.title ?? "Result" }),
3525
+ /* @__PURE__ */ jsx("h2", { className: cn("mb-6 text-xl text-foreground", headingClass(600, true)), children: slot.title ?? "Result" }),
2815
3526
  slot.content
2816
3527
  ] });
2817
3528
  }
@@ -2820,7 +3531,7 @@ function Section({ props, children }) {
2820
3531
  /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
2821
3532
  /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-3", children: [
2822
3533
  props.number ? /* @__PURE__ */ jsx("span", { className: cn("font-mono text-[12px]", linkTextClass), children: props.number }) : null,
2823
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight text-foreground", children: props.title })
3534
+ /* @__PURE__ */ jsx("h2", { className: cn("text-xl text-foreground", headingClass(600, true)), children: props.title })
2824
3535
  ] }),
2825
3536
  props.lede ? /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground", children: props.lede }) : null
2826
3537
  ] }),
@@ -2833,34 +3544,50 @@ function Rail({ props, children }) {
2833
3544
  // the `@theme inline` mapping and does not inherit its fallback - it has to
2834
3545
  // carry its own, or a host that defines no tokens loses the declaration
2835
3546
  // outright. See src/styles/tailwind-entry.css.
2836
- /* @__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: [
2837
- /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold tracking-[0.15em] text-muted-foreground uppercase", children: props.title }),
2838
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-col", children })
2839
- ] })
3547
+ /* @__PURE__ */ jsxs(
3548
+ "div",
3549
+ {
3550
+ "data-style-panel": "",
3551
+ className: cn(
3552
+ "rounded-[calc(var(--radius,0.5rem)*1.5)] p-7 text-card-foreground",
3553
+ panelSurfaceClass,
3554
+ panelRaisedShadowClass
3555
+ ),
3556
+ children: [
3557
+ /* @__PURE__ */ jsx("h2", { className: "text-[11px] font-semibold tracking-[0.15em] text-muted-foreground uppercase", children: props.title }),
3558
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-col", children })
3559
+ ]
3560
+ }
3561
+ )
2840
3562
  );
2841
3563
  }
2842
- function present(value) {
3564
+ function present2(value) {
2843
3565
  return value !== void 0 && value !== null && value !== "";
2844
3566
  }
2845
3567
  function SummaryRow({ props }) {
2846
- const text = [props.value, props.detail].filter(present).map(String).join(props.separator ?? " ");
3568
+ const text = [props.value, props.detail].filter(present2).map(String).join(props.separator ?? " ");
2847
3569
  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: [
2848
3570
  /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] text-muted-foreground", children: props.label }),
2849
3571
  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" })
2850
3572
  ] });
2851
3573
  }
2852
3574
  function Cta({ props, emit }) {
3575
+ const busy = useDescriptorScope().env?.disabled ?? false;
2853
3576
  return /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
2854
3577
  /* @__PURE__ */ jsx(
2855
3578
  "button",
2856
3579
  {
2857
3580
  type: "button",
3581
+ disabled: busy,
2858
3582
  onClick: () => emit("press"),
2859
3583
  className: cn(
2860
- "inline-flex h-12 w-full items-center justify-center rounded-lg bg-primary px-6 text-sm font-semibold text-primary-foreground",
2861
- // The fallback is not decoration here either - see Rail above.
2862
- "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)]",
2863
- "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-hidden"
3584
+ "inline-flex h-12 w-full items-center justify-center rounded-lg bg-primary px-6 text-sm font-semibold text-primary-foreground transition-all hover:bg-primary/90",
3585
+ // The page's call-to-action shadow, or the glow in the button colour
3586
+ // it had. Focus is an outline, which no shadow a style sets can
3587
+ // replace or hide.
3588
+ actionShadowClass,
3589
+ focusOutlineClass,
3590
+ "disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:bg-primary"
2864
3591
  ),
2865
3592
  children: props.label
2866
3593
  }
@@ -2891,7 +3618,7 @@ function useTextField(props, bindings) {
2891
3618
  props.value ?? void 0,
2892
3619
  bindings?.value
2893
3620
  );
2894
- const [localValue, setLocalValue] = React3.useState("");
3621
+ const [localValue, setLocalValue] = React4.useState("");
2895
3622
  const isBound = Boolean(bindings?.value);
2896
3623
  const value = isBound ? boundValue ?? "" : localValue;
2897
3624
  const setValue = isBound ? setBoundValue : setLocalValue;
@@ -2980,7 +3707,8 @@ var { registry: generativeRegistry } = defineRegistry(catalog, {
2980
3707
  Rail: (ctx) => /* @__PURE__ */ jsx(Rail, { ...ctx }),
2981
3708
  SummaryRow: (ctx) => /* @__PURE__ */ jsx(SummaryRow, { ...ctx }),
2982
3709
  Cta: (ctx) => /* @__PURE__ */ jsx(Cta, { ...ctx }),
2983
- Footer: (ctx) => /* @__PURE__ */ jsx(Footer, { ...ctx })
3710
+ Footer: (ctx) => /* @__PURE__ */ jsx(Footer, { ...ctx }),
3711
+ ...frameRenderers
2984
3712
  }
2985
3713
  });
2986
3714
  function GenerativePage({
@@ -2993,24 +3721,40 @@ function GenerativePage({
2993
3721
  brand
2994
3722
  }) {
2995
3723
  const { inputs, result, env, idPrefix } = scope;
2996
- const stableScope = React3.useMemo(
3724
+ const stableScope = React4.useMemo(
2997
3725
  () => ({ inputs, result, env, idPrefix }),
2998
3726
  [inputs, result, env, idPrefix]
2999
3727
  );
3000
- const latest = React3.useRef({ onRun, store });
3001
- React3.useEffect(() => {
3728
+ const latest = React4.useRef({ onRun, store });
3729
+ React4.useEffect(() => {
3002
3730
  latest.current = { onRun, store };
3003
3731
  });
3004
- const [handlers] = React3.useState(() => ({
3732
+ const running = React4.useRef(false);
3733
+ const [handlers] = React4.useState(() => ({
3005
3734
  run: () => {
3006
- latest.current.onRun?.(latest.current.store.getSnapshot());
3735
+ if (running.current) return void 0;
3736
+ running.current = true;
3737
+ let pending;
3738
+ try {
3739
+ pending = latest.current.onRun?.(latest.current.store.getSnapshot());
3740
+ } catch (error) {
3741
+ running.current = false;
3742
+ throw error;
3743
+ }
3744
+ if (isThenable(pending)) {
3745
+ return Promise.resolve(pending).finally(() => {
3746
+ running.current = false;
3747
+ });
3748
+ }
3749
+ running.current = false;
3750
+ return void 0;
3007
3751
  }
3008
3752
  }));
3009
3753
  const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry, store, handlers, children: /* @__PURE__ */ jsx(Renderer, { spec, registry, loading }) }) });
3010
3754
  return brand ? /* @__PURE__ */ jsx(BrandProvider, { manifest: brand, children: page }) : page;
3011
3755
  }
3012
3756
  function useStoreSnapshot(store) {
3013
- return React3.useSyncExternalStore(
3757
+ return React4.useSyncExternalStore(
3014
3758
  store.subscribe,
3015
3759
  store.getSnapshot,
3016
3760
  store.getServerSnapshot ?? store.getSnapshot
@@ -3063,6 +3807,8 @@ function fixtureId(fixture) {
3063
3807
  return [
3064
3808
  fixture.producer,
3065
3809
  fixture.model,
3810
+ fixture.frame ?? null,
3811
+ fixture.style ?? null,
3066
3812
  fixture.seed ? "seeded" : null,
3067
3813
  fixture.critic ? "critic" : null
3068
3814
  ].filter((part) => part !== null).join("--");
@@ -3074,7 +3820,10 @@ var PRODUCER_LABEL = {
3074
3820
  };
3075
3821
  function fixtureLabel(fixture) {
3076
3822
  const parts = [PRODUCER_LABEL[fixture.producer], fixture.model];
3823
+ if (fixture.frame) parts.push(`${fixture.frame} frame`);
3824
+ if (fixture.style) parts.push(`${fixture.style} style`);
3077
3825
  if (fixture.seed) parts.push("with a seed");
3826
+ if (fixture.repairs) parts.push(`repaired \xD7 ${fixture.repairs}`);
3078
3827
  if (fixture.critic) {
3079
3828
  parts.push(
3080
3829
  `${fixture.critic.model} critic \xD7 ${fixture.critic.rounds} round${fixture.critic.rounds === 1 ? "" : "s"}`
@@ -3093,6 +3842,6 @@ function findFixture(fixtures, pipeRef, id) {
3093
3842
  return found;
3094
3843
  }
3095
3844
 
3096
- 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, catalog, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, generativeRegistry, generativeRenderers, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutFits, layoutProblems, pathFromDomId, payloadToState, repeatBasePathOf, resultBrief, resultFieldAtPath, segmentsUnder, specFromJsonl, specToJsonl, useBrand, useDescriptorScope, useResultSlot, useStoreSnapshot, validateAgainstCatalog };
3845
+ export { BrandProvider, COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, DescriptorProvider, FRAMES, FRAME_COMPONENTS, FrameHostProvider, GenerativePage, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, ResultSlotProvider, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, domIdFor, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, generativeRegistry, generativeRenderers, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheckProblems, layoutFits, layoutProblems, pathFromDomId, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, useBrand, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot, validateAgainstCatalog };
3097
3846
  //# sourceMappingURL=index.js.map
3098
3847
  //# sourceMappingURL=index.js.map