@pipelex/mthds-form 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { cn, headingClass, checkedAccentClass, focusOutlineClass, useResolveUrl, panelSurfaceClass, panelFlatShadowClass, linkTextClass, actionShadowClass, panelRaisedShadowClass, fieldControlClass, ResultRoot, ResultField, FieldRenderer, enumLabeler, useFieldPresentation, ToggleGroup, ToggleGroupItem, selectedFillStrongClass, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, selectedBorderClass, selectedFillClass, isThenable } from '../chunk-PCNFELNT.js';
3
- import { baseCatalog, catalog, frameComponents, resultFieldAtPath, segmentsUnder, RESULT_ROOT, inputFieldAtPath } from '../chunk-VBXFGUCG.js';
4
- export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog } from '../chunk-VBXFGUCG.js';
2
+ import { cn, headingClass, checkedAccentClass, focusOutlineClass, useResolveUrl, panelSurfaceClass, panelFlatShadowClass, linkTextClass, actionShadowClass, panelRaisedShadowClass, fieldControlClass, ResultRoot, ResultField, FieldRenderer, enumLabeler, useFieldPresentation, ToggleGroup, ToggleGroupItem, selectedFillStrongClass, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, selectedBorderClass, selectedFillClass, isThenable } from '../chunk-UKTYADY3.js';
3
+ import { baseCatalog, catalog, frameComponents, shareAmount, resultFieldAtPath, segmentsUnder, RESULT_ROOT, inputFieldAtPath, definitionChain, unwrapped } from '../chunk-4SRSGZWM.js';
4
+ export { COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, FRAMES, FRAME_COMPONENTS, ICON_NAMES, INPUTS_ROOT, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheck, layoutCheckProblems, layoutFits, layoutProblems, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, validateAgainstCatalog } from '../chunk-4SRSGZWM.js';
5
5
  import '../chunk-4VAO6BDE.js';
6
6
  export { seedInputs } from '../chunk-VH5CDQDR.js';
7
7
  import '../chunk-L23R3JNQ.js';
@@ -20,14 +20,15 @@ import '../chunk-OD3VYXUY.js';
20
20
  import '../chunk-WYH56SOZ.js';
21
21
  import { hasOwnProp } from '../chunk-V3OV2XQT.js';
22
22
  import '../chunk-GKV77RAS.js';
23
- import * as React5 from 'react';
24
- import { defineRegistry, useStateValue, useRepeatScope, useStateStore, useBoundProp, useFieldValidation, JSONUIProvider, Renderer } from '@json-render/react';
23
+ import * as React6 from 'react';
24
+ import { defineRegistry, useStateValue, useRepeatScope, useStateStore, useBoundProp, useFieldValidation, useOptionalValidation, JSONUIProvider, Renderer, useVisibility } from '@json-render/react';
25
25
  import { jsx, jsxs } from 'react/jsx-runtime';
26
+ import { resolveRepeatStatePath, getByPath, evaluateVisibility, resolveElementProps } from '@json-render/core';
27
+ export { createStateStore } from '@json-render/core';
26
28
  import { Clock, ArrowRight, Send, Pencil, Zap, Lightbulb, Truck, Package, Briefcase, Bookmark, Flag, Shield, Info, AlertCircle, CheckCircle2, ListChecks, Layers, Tag, Phone, Mail, Paperclip, Upload, FileText, BarChart3, TrendingUp, Hash, Percent, Receipt, Coins, Banknote, Wallet, Gift, Ticket, Image, Camera, Music, Coffee, Utensils, Star, Heart, Accessibility, Baby, User, Users, Hourglass, Calendar, Moon, Sun, Leaf, Mountain, Globe, Landmark, Building2, Home, Hotel, Ship, Car, Train, Plane, Route, MapPin, Map as Map$1, Compass, Rocket, Sparkles, ChevronDown } from 'lucide-react';
27
29
  import * as TabsPrimitive from '@radix-ui/react-tabs';
28
- export { createStateStore } from '@json-render/core';
29
30
 
30
- var BrandContext = React5.createContext(null);
31
+ var BrandContext = React6.createContext(null);
31
32
  function BrandProvider({
32
33
  manifest,
33
34
  children
@@ -36,7 +37,7 @@ function BrandProvider({
36
37
  return /* @__PURE__ */ jsx(BrandContext.Provider, { value: manifest, children });
37
38
  }
38
39
  function useBrand() {
39
- const manifest = React5.useContext(BrandContext);
40
+ const manifest = React6.useContext(BrandContext);
40
41
  if (!manifest)
41
42
  throw new Error(
42
43
  "useBrand: no brand in scope. Pass `brand` to GenerativePage, or wrap the tree in BrandProvider."
@@ -47,7 +48,7 @@ var WEIGHTS = "400;500;600;700";
47
48
  function useWebfont(webfont) {
48
49
  const provider = webfont?.provider;
49
50
  const family = webfont?.family;
50
- React5.useEffect(() => {
51
+ React6.useEffect(() => {
51
52
  if (!provider || !family) return;
52
53
  const key = `${provider}:${family}`;
53
54
  if (document.head.querySelector(`link[data-brand-webfont="${CSS.escape(key)}"]`)) return;
@@ -67,40 +68,238 @@ function useWebfont(webfont) {
67
68
  document.head.appendChild(link);
68
69
  }, [provider, family]);
69
70
  }
70
- var ReportingContext = React5.createContext(false);
71
- var ElementBoundary = class extends React5.Component {
71
+ var CheckedFields = class {
72
+ constructor() {
73
+ // One entry per mounted field, so two fields handed one config object are
74
+ // two entries, and one leaving does not take the other's checks with it.
75
+ this.byPath = /* @__PURE__ */ new Map();
76
+ this.validation = null;
77
+ }
78
+ /** Hands the record json-render's validation, and tells it what is already mounted. */
79
+ attach(validation) {
80
+ if (validation === this.validation) return;
81
+ const first = this.validation === null;
82
+ this.validation = validation;
83
+ if (first) for (const path of this.byPath.keys()) this.publish(path);
84
+ }
85
+ /** Enters one mounted field's checks; what it returns leaves them again. */
86
+ enter(path, config) {
87
+ const configs = this.byPath.get(path) ?? /* @__PURE__ */ new Set();
88
+ this.byPath.set(path, configs);
89
+ const entry = { config };
90
+ configs.add(entry);
91
+ this.publish(path);
92
+ return () => {
93
+ configs.delete(entry);
94
+ if (configs.size === 0) this.byPath.delete(path);
95
+ this.publish(path);
96
+ };
97
+ }
98
+ /** The checks of every field mounted at `path`, combined, or none when no field is. */
99
+ configFor(path) {
100
+ const configs = this.byPath.get(path);
101
+ if (!configs || configs.size === 0) return void 0;
102
+ const [first] = configs;
103
+ return {
104
+ checks: [...configs].flatMap(({ config }) => config.checks ?? []),
105
+ ...first?.config.validateOn ? { validateOn: first.config.validateOn } : {}
106
+ };
107
+ }
108
+ /**
109
+ * Runs the checks of every path a mounted field carries, as the record
110
+ * holds them now, and answers whether they all pass; every path is checked,
111
+ * so each failing field shows its message. json-render's own `validateAll`
112
+ * reads what it was told as of its provider's last render, which a press
113
+ * can beat by one task when a field has just mounted.
114
+ */
115
+ check(validation) {
116
+ let pass = true;
117
+ for (const path of this.byPath.keys()) {
118
+ const combined = this.configFor(path);
119
+ if (combined && !validation.validate(path, combined).valid) pass = false;
120
+ }
121
+ return pass;
122
+ }
123
+ publish(path) {
124
+ this.validation?.registerField(path, this.configFor(path) ?? { checks: [] });
125
+ }
126
+ };
127
+ var CheckedFieldsContext = React6.createContext(null);
128
+ function useCheckedField(path, config) {
129
+ const fields = React6.useContext(CheckedFieldsContext);
130
+ const field = useFieldValidation(path, fields ? void 0 : config);
131
+ const validation = useOptionalValidation();
132
+ const signature = config ? JSON.stringify(config) : "";
133
+ const latest = React6.useRef(config);
134
+ React6.useInsertionEffect(() => {
135
+ latest.current = config;
136
+ });
137
+ React6.useEffect(() => {
138
+ const entered = latest.current;
139
+ if (!fields || !path || !entered) return void 0;
140
+ return fields.enter(path, entered);
141
+ }, [fields, path, signature]);
142
+ const fallback = field.validate;
143
+ const validate = React6.useCallback(() => {
144
+ const combined = fields?.configFor(path);
145
+ return validation && combined ? validation.validate(path, combined) : fallback();
146
+ }, [fields, path, validation, fallback]);
147
+ return { ...field, validate };
148
+ }
149
+ var ReportingContext = React6.createContext(false);
150
+ function said(error) {
151
+ try {
152
+ return String(error);
153
+ } catch {
154
+ return "an error that cannot be written out";
155
+ }
156
+ }
157
+ function contentOf(value) {
158
+ const open = /* @__PURE__ */ new WeakSet();
159
+ try {
160
+ return JSON.stringify(value, function(_key, entry) {
161
+ if (typeof entry === "bigint") return `${entry}n`;
162
+ if (typeof entry === "object" && entry !== null) {
163
+ if (open.has(entry)) return "[cycle]";
164
+ open.add(entry);
165
+ }
166
+ return entry;
167
+ }) ?? "undefined";
168
+ } catch {
169
+ return "an input that cannot be written out";
170
+ }
171
+ }
172
+ function sameCue(a, b) {
173
+ if (Array.isArray(a) && Array.isArray(b)) {
174
+ return a.length === b.length && a.every((entry, index) => Object.is(entry, b[index]));
175
+ }
176
+ return Object.is(a, b);
177
+ }
178
+ var ElementBoundary = class extends React6.Component {
72
179
  constructor(props) {
73
180
  super(props);
74
- this.state = { failed: false, error: void 0, resetOn: props.resetOn };
181
+ this.state = { failed: false, error: void 0 };
75
182
  }
76
183
  static getDerivedStateFromError(error) {
77
184
  return { failed: true, error };
78
185
  }
79
- static getDerivedStateFromProps(props, state) {
80
- if (Object.is(props.resetOn, state.resetOn)) return null;
81
- return { failed: false, error: void 0, resetOn: props.resetOn };
186
+ /** What the element renders from, as text; total, since it reads a model's layout and the store. */
187
+ input() {
188
+ try {
189
+ return contentOf(this.props.inputOf ? this.props.inputOf() : this.props.resetOn);
190
+ } catch (error) {
191
+ return `the input could not be read: ${said(error)}`;
192
+ }
82
193
  }
83
194
  componentDidCatch(error, info) {
84
- if (!this.props.reporting) return;
195
+ if (this.props.loading) {
196
+ this.failedOn = void 0;
197
+ return;
198
+ }
199
+ this.failedOn = this.input();
85
200
  const componentStack = info.componentStack ?? void 0;
86
- this.props.report.current?.(error, {
87
- type: this.props.type,
88
- ...componentStack ? { componentStack } : {}
89
- });
201
+ if (this.props.reporting) {
202
+ this.props.report.current?.(error, {
203
+ type: this.props.type,
204
+ ...componentStack ? { componentStack } : {}
205
+ });
206
+ return;
207
+ }
208
+ if (!this.props.root) {
209
+ console.error(
210
+ `[json-render] Rendering error in <${this.props.type}>:`,
211
+ error,
212
+ componentStack
213
+ );
214
+ }
90
215
  }
91
- // Whether to report or to throw the error on is decided as the boundary
92
- // renders its failure, from whether the host passes a handler in this very
93
- // render: decided later, it cost a blank commit and a second record of the
94
- // same error, and decided from the ref, it read the previous render's
95
- // callback. No host to tell: the error goes on, in the same render, to
96
- // json-render's boundary or the host's around the page, which record it
97
- // once, as if this one were not here.
216
+ componentDidUpdate(previous, previousState) {
217
+ if (!this.state.failed || !previousState.failed) return;
218
+ const streamEnded = previous.loading === true && !this.props.loading;
219
+ if (streamEnded || this.inputChanged(previous)) {
220
+ this.failedOn = void 0;
221
+ this.setState({ failed: false, error: void 0 });
222
+ }
223
+ }
224
+ /** Whether what the element renders from is no longer what it failed on. */
225
+ inputChanged(previous) {
226
+ if (sameCue(this.props.resetOn, previous.resetOn)) return false;
227
+ if (this.props.loading || this.failedOn === void 0) return true;
228
+ return !Object.is(this.input(), this.failedOn);
229
+ }
230
+ // Whether the root throws the error on is decided as it renders its
231
+ // failure, from whether the host passes a handler in this very render:
232
+ // decided later, it cost a blank commit and a second record of the same
233
+ // error, and decided from the ref, it read the previous render's callback.
234
+ // No host to tell: the root's error goes on, in the same render, to the
235
+ // host's boundary around the page, which records it once.
98
236
  render() {
99
237
  if (!this.state.failed) return this.props.children;
100
- if (!this.props.reporting) throw this.state.error;
238
+ if (this.props.root && !this.props.reporting && !this.props.loading) throw this.state.error;
101
239
  return null;
102
240
  }
103
241
  };
242
+ function resolvedOf(element, ctx) {
243
+ if (!element) return void 0;
244
+ try {
245
+ return {
246
+ props: resolveElementProps(element.props ?? {}, ctx),
247
+ visible: element.visible === void 0 ? true : evaluateVisibility(element.visible, ctx)
248
+ };
249
+ } catch (error) {
250
+ return `throws: ${said(error)}`;
251
+ }
252
+ }
253
+ function childElementOf(node) {
254
+ if (!React6.isValidElement(node)) return void 0;
255
+ const { element, elementKey } = node.props;
256
+ if (typeof elementKey !== "string") return void 0;
257
+ return typeof element === "object" && element !== null ? element : void 0;
258
+ }
259
+ function inputOfElement(props, visibility, scope) {
260
+ const element = props.element;
261
+ const state = visibility.stateModel;
262
+ const ctx = {
263
+ ...visibility,
264
+ ...scope ? { repeatItem: scope.item, repeatIndex: scope.index, repeatBasePath: scope.basePath } : {}
265
+ };
266
+ const statePath = element?.repeat?.statePath;
267
+ let list;
268
+ if (statePath !== void 0) {
269
+ try {
270
+ const path = resolveRepeatStatePath(statePath, scope?.basePath);
271
+ list = path === void 0 ? void 0 : getByPath(state, path);
272
+ } catch (error) {
273
+ list = `throws: ${said(error)}`;
274
+ }
275
+ }
276
+ const under = (nodes) => React6.Children.toArray(nodes).map((node) => {
277
+ const child = childElementOf(node);
278
+ return child ? { element: child, resolved: resolvedOf(child, ctx) } : null;
279
+ });
280
+ const slots = typeof props.slots === "object" && props.slots !== null ? Object.fromEntries(Object.entries(props.slots).map(([name, nodes]) => [name, under(nodes)])) : void 0;
281
+ return { props: element?.props, list, children: under(props.children), slots };
282
+ }
283
+ function inputOfRoot(spec, visibility) {
284
+ const root = spec?.elements?.[spec.root];
285
+ return { spec, root: resolvedOf(root, visibility) };
286
+ }
287
+ function RootBoundary(props) {
288
+ const { ctx } = useVisibility();
289
+ return /* @__PURE__ */ jsx(
290
+ ElementBoundary,
291
+ {
292
+ type: props.type,
293
+ report: props.report,
294
+ reporting: props.reporting,
295
+ loading: props.loading,
296
+ resetOn: [props.spec, ctx],
297
+ inputOf: () => inputOfRoot(props.spec, ctx),
298
+ root: true,
299
+ children: props.children
300
+ }
301
+ );
302
+ }
104
303
  function reportingRegistry(registry, report, made) {
105
304
  const wrapped = {};
106
305
  for (const [type, Renderer2] of Object.entries(registry)) {
@@ -110,7 +309,23 @@ function reportingRegistry(registry, report, made) {
110
309
  continue;
111
310
  }
112
311
  const Component2 = Renderer2;
113
- const Reported = (props) => /* @__PURE__ */ jsx(ElementBoundary, { type, report, reporting: React5.useContext(ReportingContext), children: /* @__PURE__ */ jsx(Component2, { ...props }) });
312
+ const Reported = (props) => {
313
+ const reporting = React6.useContext(ReportingContext);
314
+ const { ctx } = useVisibility();
315
+ const scope = useRepeatScope();
316
+ return /* @__PURE__ */ jsx(
317
+ ElementBoundary,
318
+ {
319
+ type,
320
+ report,
321
+ reporting,
322
+ loading: props.loading === true,
323
+ resetOn: [props.element, props.children, props.slots, ctx, scope],
324
+ inputOf: () => inputOfElement(props, ctx, scope),
325
+ children: /* @__PURE__ */ jsx(Component2, { ...props })
326
+ }
327
+ );
328
+ };
114
329
  Reported.displayName = `Reported(${type})`;
115
330
  made.set(type, { renderer: Renderer2, wrapper: Reported });
116
331
  wrapped[type] = Reported;
@@ -169,39 +384,72 @@ function BrandBar({ app, links, tag }) {
169
384
  }
170
385
 
171
386
  // src/generative/declared-props.ts
172
- function definitionOf(schema) {
173
- return schema._zod?.def;
174
- }
175
- function unwrapped(schema) {
176
- let def = definitionOf(schema);
177
- for (let depth = 0; depth < 8 && def; depth += 1) {
178
- if (def.type !== "nullable" && def.type !== "optional" && def.type !== "default") return def;
179
- def = def.innerType ? definitionOf(def.innerType) : void 0;
180
- }
181
- return def;
182
- }
183
- function absentValueOf(schema) {
184
- if (schema.safeParse(null).success) return null;
185
- if (schema.safeParse(void 0).success) return void 0;
186
- const type = unwrapped(schema)?.type;
187
- if (type === "string") return "";
188
- if (type === "array") return [];
189
- return void 0;
387
+ var factsBySchema = /* @__PURE__ */ new WeakMap();
388
+ function factsOf(schema) {
389
+ const known = factsBySchema.get(schema);
390
+ if (known) return known;
391
+ const chain = definitionChain(schema);
392
+ const def = chain[chain.length - 1];
393
+ const acceptsNull = schema.safeParse(null).success;
394
+ const acceptsUndefined = schema.safeParse(void 0).success;
395
+ const absent = acceptsNull ? null : acceptsUndefined ? void 0 : def?.type === "string" ? "" : def?.type === "array" ? [] : void 0;
396
+ const facts = { def, plain: plainType(chain), acceptsNull, acceptsUndefined, absent };
397
+ factsBySchema.set(schema, facts);
398
+ return facts;
399
+ }
400
+ var PASSING_WRAPPERS = /* @__PURE__ */ new Set([
401
+ "optional",
402
+ "nullable",
403
+ "default",
404
+ "prefault",
405
+ "readonly",
406
+ "catch",
407
+ "nonoptional"
408
+ ]);
409
+ function plainType(chain) {
410
+ const def = chain[chain.length - 1];
411
+ if (!def || def.format !== void 0) return void 0;
412
+ if (chain.some((link) => link.checks !== void 0 && link.checks.length > 0)) return void 0;
413
+ if (!chain.slice(0, -1).every((link) => PASSING_WRAPPERS.has(link.type))) return void 0;
414
+ return def.type === "string" || def.type === "boolean" || def.type === "number" ? def.type : void 0;
415
+ }
416
+ function plainlyConforms(plain, value) {
417
+ if (plain === "number") return typeof value === "number" && Number.isFinite(value);
418
+ return plain !== void 0 && typeof value === plain;
419
+ }
420
+ function writtenOut(schema, value) {
421
+ if (typeof value !== "number" && typeof value !== "boolean") return void 0;
422
+ const text = String(value);
423
+ return schema.safeParse(text).success ? text : void 0;
424
+ }
425
+ function keptEntries(schema, element, entries, absent) {
426
+ const textItems = unwrapped(element)?.type === "string";
427
+ const kept = entries.flatMap((entry) => {
428
+ if (element.safeParse(entry).success) return [entry];
429
+ const text = textItems ? writtenOut(element, entry) : void 0;
430
+ return text === void 0 ? [] : [text];
431
+ });
432
+ return schema.safeParse(kept).success ? kept : absent;
190
433
  }
434
+ var conformedBySchema = /* @__PURE__ */ new WeakMap();
191
435
  function conformValue(schema, value) {
192
- if (value === void 0 || value === null) {
193
- return schema.safeParse(value).success ? value : absentValueOf(schema);
194
- }
195
- if (schema.safeParse(value).success) return value;
196
- const def = unwrapped(schema);
197
- if (def?.type === "string" && (typeof value === "number" || typeof value === "boolean")) {
198
- return String(value);
436
+ const facts = factsOf(schema);
437
+ if (value === void 0) return facts.acceptsUndefined ? value : facts.absent;
438
+ if (value === null) return facts.acceptsNull ? value : facts.absent;
439
+ if (typeof value !== "object") {
440
+ if (plainlyConforms(facts.plain, value) || schema.safeParse(value).success) return value;
441
+ if (facts.def?.type === "string") return writtenOut(schema, value) ?? facts.absent;
442
+ return facts.absent;
199
443
  }
200
- if (def?.type === "array" && def.element && Array.isArray(value)) {
201
- const element = def.element;
202
- return value.filter((entry) => element.safeParse(entry).success);
444
+ let byValue = conformedBySchema.get(schema);
445
+ if (!byValue) {
446
+ byValue = /* @__PURE__ */ new WeakMap();
447
+ conformedBySchema.set(schema, byValue);
203
448
  }
204
- return absentValueOf(schema);
449
+ if (byValue.has(value)) return byValue.get(value);
450
+ const held = schema.safeParse(value).success ? value : facts.def?.type === "array" && facts.def.element && Array.isArray(value) ? keptEntries(schema, facts.def.element, value, facts.absent) : facts.absent;
451
+ byValue.set(value, held);
452
+ return held;
205
453
  }
206
454
  function conformProps(shape, props, asWritten = []) {
207
455
  let conformed;
@@ -229,18 +477,13 @@ function withDeclaredProps(definitions, renderers, asWritten = {}) {
229
477
  }
230
478
  function textOf(value) {
231
479
  if (value === void 0 || value === null) return "";
232
- if (typeof value !== "object") return String(value);
233
- try {
234
- return String(value);
235
- } catch {
236
- try {
237
- return JSON.stringify(value) ?? "";
238
- } catch {
239
- return "";
240
- }
480
+ if (Array.isArray(value)) {
481
+ return value.map(textOf).filter((text) => text !== "").join(", ");
241
482
  }
483
+ if (typeof value === "object") return "";
484
+ return String(value);
242
485
  }
243
- var FrameHostContext = React5.createContext({});
486
+ var FrameHostContext = React6.createContext({});
244
487
  function FrameHostProvider({
245
488
  host,
246
489
  children
@@ -248,15 +491,15 @@ function FrameHostProvider({
248
491
  return /* @__PURE__ */ jsx(FrameHostContext.Provider, { value: host, children });
249
492
  }
250
493
  function useFrameHost() {
251
- return React5.useContext(FrameHostContext);
494
+ return React6.useContext(FrameHostContext);
252
495
  }
253
496
  function useBoundField(literal, binding, empty, { checks, validateOn }) {
254
497
  const [boundValue, setBoundValue] = useBoundProp(literal ?? void 0, binding);
255
- const [localValue, setLocalValue] = React5.useState(literal ?? empty);
498
+ const [localValue, setLocalValue] = React6.useState(literal ?? empty);
256
499
  const isBound = Boolean(binding);
257
500
  const hasValidation = Boolean(binding && checks?.length);
258
501
  const when = validateOn ?? "change";
259
- const { errors, validate } = useFieldValidation(
502
+ const { errors, validate } = useCheckedField(
260
503
  binding ?? "",
261
504
  hasValidation ? { checks: checks ?? [], validateOn: when } : void 0
262
505
  );
@@ -524,7 +767,7 @@ function Progress({
524
767
  ] });
525
768
  }
526
769
  function useControlId(name) {
527
- return `jr-${name}-${React5.useId()}`;
770
+ return `jr-${name}-${React6.useId()}`;
528
771
  }
529
772
  function Input({
530
773
  props,
@@ -703,9 +946,9 @@ function Button({
703
946
  }
704
947
  );
705
948
  }
706
- var DescriptorContext = React5.createContext({});
949
+ var DescriptorContext = React6.createContext({});
707
950
  function useDescriptorScope() {
708
- return React5.useContext(DescriptorContext);
951
+ return React6.useContext(DescriptorContext);
709
952
  }
710
953
  function DescriptorProvider({
711
954
  scope,
@@ -721,8 +964,9 @@ function Unresolved({ path, side }) {
721
964
  className: "rounded-md border border-destructive/50 px-2.5 py-1.5 text-[12px] text-destructive",
722
965
  children: [
723
966
  side === "input" ? "No input" : "No result",
724
- " at ",
725
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: path })
967
+ " at",
968
+ " ",
969
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: typeof path === "string" ? path : JSON.stringify(path) ?? String(path) })
726
970
  ]
727
971
  }
728
972
  );
@@ -749,6 +993,7 @@ function pathFromDomId(prefix, id) {
749
993
  }
750
994
  function useAbsolutePath(path) {
751
995
  const repeat = useRepeatScope();
996
+ if (typeof path !== "string") return void 0;
752
997
  if (path.startsWith("/")) return path;
753
998
  return repeat ? `${repeat.basePath}/${path}` : void 0;
754
999
  }
@@ -758,10 +1003,10 @@ function withoutOptionalMark(label) {
758
1003
  function MthdsField({
759
1004
  props
760
1005
  }) {
761
- const scope = React5.useContext(DescriptorContext);
1006
+ const scope = React6.useContext(DescriptorContext);
762
1007
  const path = useAbsolutePath(props.path) ?? "";
763
1008
  const found = scope.inputs && path ? inputFieldAtPath(scope.inputs, path) : void 0;
764
- const field = React5.useMemo(
1009
+ const field = React6.useMemo(
765
1010
  () => found && (props.label || props.hint) ? {
766
1011
  ...found,
767
1012
  // The control marks an optional field itself, so a label that
@@ -773,7 +1018,7 @@ function MthdsField({
773
1018
  );
774
1019
  const value = useStateValue(path);
775
1020
  const { set } = useStateStore();
776
- const onChange = React5.useCallback((next) => set(path, next), [set, path]);
1021
+ const onChange = React6.useCallback((next) => set(path, next), [set, path]);
777
1022
  if (!field) return /* @__PURE__ */ jsx(Unresolved, { path: props.path, side: "input" });
778
1023
  return /* @__PURE__ */ jsx(
779
1024
  FieldRenderer,
@@ -787,7 +1032,7 @@ function MthdsField({
787
1032
  );
788
1033
  }
789
1034
  function MthdsResult({ props }) {
790
- const scope = React5.useContext(DescriptorContext);
1035
+ const scope = React6.useContext(DescriptorContext);
791
1036
  const path = useAbsolutePath(props.path) ?? "";
792
1037
  const field = scope.result && path ? resultFieldAtPath(scope.result, path) : void 0;
793
1038
  const value = useStateValue(path);
@@ -800,13 +1045,13 @@ function AccessibleSelect({ props, bindings, emit }) {
800
1045
  props.value ?? void 0,
801
1046
  bindings?.value
802
1047
  );
803
- const [localValue, setLocalValue] = React5.useState("");
1048
+ const [localValue, setLocalValue] = React6.useState("");
804
1049
  const isBound = Boolean(bindings?.value);
805
1050
  const value = isBound ? boundValue ?? "" : localValue;
806
1051
  const setValue = isBound ? setBoundValue : setLocalValue;
807
1052
  const validateOn = props.validateOn ?? "change";
808
1053
  const hasValidation = Boolean(bindings?.value && props.checks?.length);
809
- const { errors, validate } = useFieldValidation(
1054
+ const { errors, validate } = useCheckedField(
810
1055
  bindings?.value ?? "",
811
1056
  hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
812
1057
  );
@@ -897,7 +1142,7 @@ function numberFormat(format) {
897
1142
  }
898
1143
  function Metric({ props }) {
899
1144
  const value = props.value;
900
- const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : value === null || value === void 0 || value === "" ? "\u2014" : textOf(value);
1145
+ const text = typeof value === "number" ? numberFormat(props.format ?? "plain").format(value) : textOf(value) || "\u2014";
901
1146
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
902
1147
  /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: props.label }),
903
1148
  /* @__PURE__ */ jsxs("span", { className: "text-2xl font-semibold tabular-nums text-foreground", children: [
@@ -930,29 +1175,49 @@ function Split({
930
1175
  }
931
1176
  function Tabs({ props, children }) {
932
1177
  const tabs = props.tabs ?? [];
933
- const panels = React5.Children.toArray(children);
934
- const [value, setValue] = React5.useState(tabs[0]?.value ?? "");
935
- return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: setValue, className: "w-full", children: [
936
- /* @__PURE__ */ jsx(TabsPrimitive.List, { className: "inline-flex h-10 items-center justify-start rounded-md bg-muted p-1 text-muted-foreground max-sm:h-auto max-sm:flex-wrap", children: tabs.map((tab) => /* @__PURE__ */ jsx(
1178
+ const panels = React6.Children.toArray(children);
1179
+ const [chosen, setChosen] = React6.useState(null);
1180
+ const open = chosen ? openIndex(tabs, chosen) : 0;
1181
+ const value = String(open);
1182
+ const choose = (next) => {
1183
+ const index = Number(next);
1184
+ const tab = tabs[index];
1185
+ if (!tab) return;
1186
+ const occurrence = tabs.slice(0, index).filter((t) => t.value === tab.value).length;
1187
+ setChosen({ value: tab.value, occurrence });
1188
+ };
1189
+ return /* @__PURE__ */ jsxs(TabsPrimitive.Root, { value, onValueChange: choose, className: "w-full", children: [
1190
+ /* @__PURE__ */ jsx(TabsPrimitive.List, { className: "inline-flex h-10 items-center justify-start rounded-md bg-muted p-1 text-muted-foreground max-sm:h-auto max-sm:flex-wrap", children: tabs.map((tab, index) => /* @__PURE__ */ jsx(
937
1191
  TabsPrimitive.Trigger,
938
1192
  {
939
- value: tab.value,
1193
+ value: String(index),
940
1194
  className: "inline-flex items-center justify-center rounded-sm px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-hidden data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm max-sm:min-h-11 max-sm:min-w-11",
941
1195
  children: tab.label
942
1196
  },
943
- tab.value
1197
+ index
944
1198
  )) }),
945
- tabs.map((tab, index) => /* @__PURE__ */ jsx(
1199
+ tabs.map((_tab, index) => /* @__PURE__ */ jsx(
946
1200
  TabsPrimitive.Content,
947
1201
  {
948
- value: tab.value,
1202
+ value: String(index),
1203
+ forceMount: true,
1204
+ hidden: index !== open,
949
1205
  className: "mt-4 focus-visible:outline-hidden",
950
1206
  children: panels[index] ?? null
951
1207
  },
952
- tab.value
1208
+ index
953
1209
  ))
954
1210
  ] });
955
1211
  }
1212
+ function openIndex(tabs, { value, occurrence }) {
1213
+ let seen = 0;
1214
+ for (const [index, tab] of tabs.entries()) {
1215
+ if (tab.value !== value) continue;
1216
+ if (seen === occurrence) return index;
1217
+ seen += 1;
1218
+ }
1219
+ return 0;
1220
+ }
956
1221
  var BUTTON_BASE = "inline-flex min-h-11 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50";
957
1222
  var PRIMARY_BUTTON = cn(BUTTON_BASE, "bg-primary text-primary-foreground hover:bg-primary/90");
958
1223
  var SECONDARY_BUTTON = cn(
@@ -961,9 +1226,10 @@ var SECONDARY_BUTTON = cn(
961
1226
  );
962
1227
  function Steps({ props, children }) {
963
1228
  const steps = props.steps ?? [];
964
- const panels = React5.Children.toArray(children);
965
- const [index, setIndex] = React5.useState(0);
1229
+ const panels = React6.Children.toArray(children);
1230
+ const [chosen, setIndex] = React6.useState(0);
966
1231
  const last = steps.length - 1;
1232
+ const index = Math.max(0, Math.min(chosen, last));
967
1233
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
968
1234
  /* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-x-5 gap-y-2", children: steps.map((label, position) => /* @__PURE__ */ jsxs(
969
1235
  "li",
@@ -989,7 +1255,7 @@ function Steps({ props, children }) {
989
1255
  },
990
1256
  `${position}-${label}`
991
1257
  )) }),
992
- /* @__PURE__ */ jsx("div", { children: panels[index] ?? null }),
1258
+ steps.map((_step, position) => /* @__PURE__ */ jsx("div", { hidden: position !== index, children: panels[position] ?? null }, position)),
993
1259
  index > 0 || index < last ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
994
1260
  index > 0 ? /* @__PURE__ */ jsx(
995
1261
  "button",
@@ -1091,7 +1357,7 @@ function Segmented({ props, bindings, emit }) {
1091
1357
  props.value ?? void 0,
1092
1358
  bindings?.value
1093
1359
  );
1094
- const [localValue, setLocalValue] = React5.useState("");
1360
+ const [localValue, setLocalValue] = React6.useState("");
1095
1361
  const isBound = Boolean(bindings?.value);
1096
1362
  const value = isBound ? boundValue ?? "" : localValue;
1097
1363
  const setValue = isBound ? setBoundValue : setLocalValue;
@@ -1111,7 +1377,7 @@ function Segmented({ props, bindings, emit }) {
1111
1377
  emit("change");
1112
1378
  },
1113
1379
  className: "flex-wrap justify-start gap-1.5",
1114
- children: (props.options ?? []).map((option) => /* @__PURE__ */ jsx(
1380
+ children: (props.options ?? []).map((option, index) => /* @__PURE__ */ jsx(
1115
1381
  ToggleGroupItem,
1116
1382
  {
1117
1383
  value: option,
@@ -1120,7 +1386,7 @@ function Segmented({ props, bindings, emit }) {
1120
1386
  className: "rounded-full px-3.5 data-[state=on]:border-primary data-[state=on]:bg-primary data-[state=on]:text-primary-foreground max-sm:h-11 max-sm:min-w-11",
1121
1387
  children: labelOf(option)
1122
1388
  },
1123
- option
1389
+ `${index}-${option}`
1124
1390
  ))
1125
1391
  }
1126
1392
  )
@@ -1131,7 +1397,7 @@ function NumberInput({ props, bindings, emit }) {
1131
1397
  props.value ?? void 0,
1132
1398
  bindings?.value
1133
1399
  );
1134
- const [localValue, setLocalValue] = React5.useState(void 0);
1400
+ const [localValue, setLocalValue] = React6.useState(void 0);
1135
1401
  const isBound = Boolean(bindings?.value);
1136
1402
  const value = isBound ? boundValue : localValue;
1137
1403
  const setValue = isBound ? setBoundValue : setLocalValue;
@@ -1206,7 +1472,10 @@ var components = {
1206
1472
  };
1207
1473
  var generativeRenderers = withDeclaredProps(
1208
1474
  baseCatalog.data.components,
1209
- components
1475
+ components,
1476
+ // A hatch resolves its `path` as written, relative inside a repeat, so a
1477
+ // refused one reaches it as refused rather than written out as text.
1478
+ { MthdsField: ["path"], MthdsResult: ["path"] }
1210
1479
  );
1211
1480
  var RADIUS = "rounded-[calc(var(--radius,0.5rem)*1.5)]";
1212
1481
  function useAbsolute(path) {
@@ -1358,10 +1627,9 @@ function ProportionBar({ props }) {
1358
1627
  const rows = (Array.isArray(props.items) ? props.items : []).filter(
1359
1628
  (row) => typeof row === "object" && row !== null && !Array.isArray(row)
1360
1629
  );
1361
- const amountOf = (raw) => typeof raw === "object" && raw !== null ? Number.NaN : Number(raw ?? 0);
1362
1630
  const parts = rows.map((row) => ({
1363
1631
  label: textOf(row[props.labelKey]),
1364
- value: amountOf(row[props.valueKey])
1632
+ value: shareAmount(row[props.valueKey])
1365
1633
  })).filter((p) => Number.isFinite(p.value) && p.value > 0);
1366
1634
  const sum = parts.reduce((s, p) => s + p.value, 0);
1367
1635
  const total = typeof props.total === "number" ? props.total : sum;
@@ -1467,26 +1735,25 @@ function Picture({
1467
1735
  }
1468
1736
  );
1469
1737
  }
1470
- function present(value) {
1471
- return value !== void 0 && value !== null && value !== "";
1472
- }
1473
1738
  function Fact({
1474
1739
  props
1475
1740
  }) {
1741
+ const text = textOf(props.value);
1476
1742
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 rounded-[var(--radius,0.5rem)] border border-border bg-background px-4 py-3", children: [
1477
1743
  /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.label }),
1478
- /* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children: present(props.value) ? textOf(props.value) : "\u2014" }),
1744
+ /* @__PURE__ */ jsx("span", { className: "text-[16px] font-medium text-foreground tabular-nums", children: text !== "" ? text : "\u2014" }),
1479
1745
  props.detail ? /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground", children: props.detail }) : null
1480
1746
  ] });
1481
1747
  }
1482
1748
  function Detail({ props }) {
1483
- if (!present(props.value)) return null;
1749
+ const text = textOf(props.value);
1750
+ if (text === "") return null;
1484
1751
  return (
1485
1752
  // A rule between the rows of a list of details, never under one set in a
1486
1753
  // row: there it read as an underline on every detail but the last.
1487
1754
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,8.5rem)_minmax(0,1fr)] gap-3 border-b border-border py-2.5 text-[14px] last:border-b-0 [.flex-row>&]:border-b-0 [.flex-row>&]:grid-cols-[auto_minmax(0,1fr)]", children: [
1488
1755
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: props.label }),
1489
- /* @__PURE__ */ jsx("span", { className: "text-foreground", children: textOf(props.value) })
1756
+ /* @__PURE__ */ jsx("span", { className: "text-foreground", children: text })
1490
1757
  ] })
1491
1758
  );
1492
1759
  }
@@ -1541,7 +1808,7 @@ var frameRenderers = withDeclaredProps(
1541
1808
  // empty text, is the item itself inside a repeat.
1542
1809
  { Picture: ["path"] }
1543
1810
  );
1544
- var ResultSlotContext = React5.createContext(null);
1811
+ var ResultSlotContext = React6.createContext(null);
1545
1812
  function ResultSlotProvider({
1546
1813
  slot,
1547
1814
  children
@@ -1549,7 +1816,7 @@ function ResultSlotProvider({
1549
1816
  return /* @__PURE__ */ jsx(ResultSlotContext.Provider, { value: slot, children });
1550
1817
  }
1551
1818
  function useResultSlot() {
1552
- return React5.useContext(ResultSlotContext);
1819
+ return React6.useContext(ResultSlotContext);
1553
1820
  }
1554
1821
  var LABEL2 = "block text-[13.5px] leading-none font-medium text-foreground";
1555
1822
  function AppBar({ props }) {
@@ -1578,7 +1845,7 @@ function Hero({ props }) {
1578
1845
  ] });
1579
1846
  }
1580
1847
  function Workspace({ props, children }) {
1581
- const [work, rail] = React5.Children.toArray(children);
1848
+ const [work, rail] = React6.Children.toArray(children);
1582
1849
  const railLeft = props.rail === "left";
1583
1850
  return /* @__PURE__ */ jsxs(
1584
1851
  "div",
@@ -1650,11 +1917,8 @@ function Rail({ props, children }) {
1650
1917
  )
1651
1918
  );
1652
1919
  }
1653
- function present2(value) {
1654
- return value !== void 0 && value !== null && value !== "";
1655
- }
1656
1920
  function SummaryRow({ props }) {
1657
- const text = [props.value, props.detail].filter(present2).map(textOf).join(props.separator ?? " ");
1921
+ const text = [props.value, props.detail].map(textOf).filter((half) => half !== "").join(props.separator ?? " ");
1658
1922
  return /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-4 border-b border-border/60 py-3 first:pt-0 last:border-b-0", children: [
1659
1923
  /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[13px] text-muted-foreground", children: props.label }),
1660
1924
  text ? /* @__PURE__ */ jsx("span", { className: "text-right text-[13px] font-medium text-foreground", children: text }) : /* @__PURE__ */ jsx("span", { className: "text-[13px] text-muted-foreground/50", children: props.placeholder ?? "\u2014" })
@@ -1707,13 +1971,13 @@ function useTextField(props, bindings) {
1707
1971
  props.value ?? void 0,
1708
1972
  bindings?.value
1709
1973
  );
1710
- const [localValue, setLocalValue] = React5.useState("");
1974
+ const [localValue, setLocalValue] = React6.useState("");
1711
1975
  const isBound = Boolean(bindings?.value);
1712
1976
  const value = isBound ? boundValue ?? "" : localValue;
1713
1977
  const setValue = isBound ? setBoundValue : setLocalValue;
1714
1978
  const validateOn = props.validateOn ?? "blur";
1715
1979
  const hasValidation = Boolean(bindings?.value && props.checks?.length);
1716
- const { errors, validate } = useFieldValidation(
1980
+ const { errors, validate } = useCheckedField(
1717
1981
  bindings?.value ?? "",
1718
1982
  hasValidation ? { checks: props.checks ?? [], validateOn } : void 0
1719
1983
  );
@@ -1815,28 +2079,29 @@ function GenerativePage({
1815
2079
  onElementError
1816
2080
  }) {
1817
2081
  const { inputs, result, env, idPrefix } = scope;
1818
- const stableScope = React5.useMemo(
2082
+ const stableScope = React6.useMemo(
1819
2083
  () => ({ inputs, result, env, idPrefix }),
1820
2084
  [inputs, result, env, idPrefix]
1821
2085
  );
1822
- const latest = React5.useRef({ onRun, store });
1823
- React5.useEffect(() => {
2086
+ const latest = React6.useRef({ onRun, store });
2087
+ React6.useEffect(() => {
1824
2088
  latest.current = { onRun, store };
1825
2089
  });
1826
- const report = React5.useRef(onElementError);
1827
- React5.useInsertionEffect(() => {
2090
+ const report = React6.useRef(onElementError);
2091
+ React6.useInsertionEffect(() => {
1828
2092
  report.current = onElementError;
1829
2093
  });
1830
- const [made] = React5.useState(() => /* @__PURE__ */ new Map());
1831
- const pageRegistry = React5.useMemo(
2094
+ const [made] = React6.useState(() => /* @__PURE__ */ new Map());
2095
+ const pageRegistry = React6.useMemo(
1832
2096
  () => reportingRegistry(registry, report, made),
1833
2097
  [registry, made]
1834
2098
  );
1835
2099
  const rootType = spec?.elements?.[spec.root]?.type ?? "root";
1836
- const specContent = React5.useMemo(() => contentOf(spec), [spec]);
1837
2100
  const reporting = onElementError !== void 0;
1838
- const running = React5.useRef(false);
1839
- const [handlers] = React5.useState(() => {
2101
+ const validation = React6.useRef(null);
2102
+ const [checkedFields] = React6.useState(() => new CheckedFields());
2103
+ const running = React6.useRef(false);
2104
+ const [handlers] = React6.useState(() => {
1840
2105
  const release = () => {
1841
2106
  setTimeout(() => {
1842
2107
  running.current = false;
@@ -1845,6 +2110,12 @@ function GenerativePage({
1845
2110
  return {
1846
2111
  run: () => {
1847
2112
  if (running.current) return void 0;
2113
+ const checks = validation.current;
2114
+ if (checks) {
2115
+ const registered = checks.validateAll();
2116
+ const mounted = checkedFields.check(checks);
2117
+ if (!registered || !mounted) return void 0;
2118
+ }
1848
2119
  running.current = true;
1849
2120
  let pending;
1850
2121
  try {
@@ -1863,33 +2134,41 @@ function GenerativePage({
1863
2134
  }
1864
2135
  };
1865
2136
  });
1866
- const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry: pageRegistry, store, handlers, children: /* @__PURE__ */ jsx(ReportingContext.Provider, { value: reporting, children: /* @__PURE__ */ jsx(
1867
- ElementBoundary,
1868
- {
1869
- type: rootType,
1870
- report,
1871
- reporting,
1872
- resetOn: specContent,
1873
- children: /* @__PURE__ */ jsx(Renderer, { spec, registry: pageRegistry, loading })
1874
- }
1875
- ) }) }) });
2137
+ const page = /* @__PURE__ */ jsx(DescriptorProvider, { scope: stableScope, children: /* @__PURE__ */ jsx(JSONUIProvider, { registry: pageRegistry, store, handlers, children: /* @__PURE__ */ jsx(ReportingContext.Provider, { value: reporting, children: /* @__PURE__ */ jsxs(CheckedFieldsContext.Provider, { value: checkedFields, children: [
2138
+ /* @__PURE__ */ jsx(ValidationBridge, { into: validation, fields: checkedFields }),
2139
+ /* @__PURE__ */ jsx(
2140
+ RootBoundary,
2141
+ {
2142
+ type: rootType,
2143
+ report,
2144
+ reporting,
2145
+ loading: loading === true,
2146
+ spec,
2147
+ children: /* @__PURE__ */ jsx(Renderer, { spec, registry: pageRegistry, loading })
2148
+ }
2149
+ )
2150
+ ] }) }) }) });
1876
2151
  return brand ? /* @__PURE__ */ jsx(BrandProvider, { manifest: brand, children: page }) : page;
1877
2152
  }
1878
- function contentOf(spec) {
1879
- try {
1880
- return JSON.stringify(spec);
1881
- } catch {
1882
- return spec;
1883
- }
2153
+ function ValidationBridge({
2154
+ into,
2155
+ fields
2156
+ }) {
2157
+ const validation = useOptionalValidation();
2158
+ React6.useInsertionEffect(() => {
2159
+ into.current = validation;
2160
+ fields.attach(validation);
2161
+ });
2162
+ return null;
1884
2163
  }
1885
2164
  function useStoreSnapshot(store) {
1886
- return React5.useSyncExternalStore(
2165
+ return React6.useSyncExternalStore(
1887
2166
  store.subscribe,
1888
2167
  store.getSnapshot,
1889
2168
  store.getServerSnapshot ?? store.getSnapshot
1890
2169
  );
1891
2170
  }
1892
2171
 
1893
- export { BrandBar, BrandProvider, DescriptorProvider, FrameHostProvider, GenerativePage, ResultSlotProvider, domIdFor, generativeRegistry, generativeRenderers, pathFromDomId, useBrand, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot };
2172
+ export { BrandBar, BrandProvider, DescriptorProvider, FrameHostProvider, GenerativePage, ResultSlotProvider, domIdFor, generativeRegistry, generativeRenderers, pathFromDomId, useBrand, useCheckedField, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot };
1894
2173
  //# sourceMappingURL=index.js.map
1895
2174
  //# sourceMappingURL=index.js.map