@burojs/react 0.2.0 → 0.5.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.
@@ -0,0 +1,488 @@
1
+
2
+ import { AnyBlockHandle, ApplicationSnapshot, BlockLookup, Check, CheckOutcome, CheckSurface, CompiledScreen, DraftOption, EntityRef, ErasedResourceHandle, FieldIssue, FilterExpression, FixedFilterInput, FlowRun, FormBody, MessageReference, NodeState, ResourceFieldDefinition, ResourceFieldMap, ResourceHandle, ScreenEntry, ScreenFailure, ScreenPlan, ScreenSources, SourceState, StandardSchemaV1, TypeOfferState, ValidationContext, ValidationIssue, ValidationIssueSeverity, ValidationIssues } from "@burojs/core";
3
+ //#region src/flows/inline-holder.d.ts
4
+ /**
5
+ * What an inline flow placement keeps beyond the lifetime of its node (P6 3.12): the run, so that
6
+ * switching a tab away and back, or a re-render of the tree, neither loses what was typed nor
7
+ * starts a second attempt. `useFlowRun` fills `run` and `deps` through its `lease` option.
8
+ * @internal
9
+ */
10
+ interface InlineLease {
11
+ /** The placement's key on its screen. */
12
+ readonly key: string;
13
+ readonly flowId: string;
14
+ readonly record: string;
15
+ /** The run the lease holds; created by the first `useFlowRun` that takes the lease. */
16
+ run: FlowRun | null;
17
+ /** What the run was built for; a change builds a new run in the lease. */
18
+ deps: string | null;
19
+ /** Whether the run was opened (its gate asked) already. */
20
+ opened: boolean;
21
+ /** The run's values when it opened, as JSON: what "dirty" is measured against. */
22
+ initial?: string;
23
+ /** The flow's label, for the guard's text when the node is not on screen. */
24
+ label: string;
25
+ /** Unsaved input, or an unresolved attempt: set by the host from the run's snapshots. */
26
+ dirty: boolean;
27
+ /** A write is in flight. */
28
+ locked: boolean;
29
+ /** How many nodes currently show this lease. */
30
+ mounted: number;
31
+ }
32
+ /**
33
+ * The screen-held state of inline flows (P6 3.12): one lease per placement key, and the registry of
34
+ * which flow-and-record slot a mounted screen holds, so a second screen showing the same record
35
+ * (a quick sheet over the page) draws the flow's button instead of a second form. A slot is the
36
+ * attempt slot of P4: `(user, flow, record)`.
37
+ * @internal
38
+ */
39
+ interface InlineFlowHolder {
40
+ /**
41
+ * The placement's lease, created on the first call and kept; or `'held-elsewhere'` when another
42
+ * mounted holder already holds the slot. `user` is the signed-in user's id (`''` without one).
43
+ */
44
+ acquire(key: string, flowId: string, record: string, user?: string): InlineLease | 'held-elsewhere';
45
+ /** Whether the screen places `flowId` inline: the flow's own button is not drawn on it. */
46
+ suppressed(flowId: string): boolean;
47
+ /** The lease of `key` if the screen holds one (no acquisition). */
48
+ get(key: string): InlineLease | undefined;
49
+ /** Replaces the set of flows the screen places inline (by flow name). */
50
+ declare(flowNames: Iterable<string>): void;
51
+ /** Frees the lease of `key`; a run with a write in flight is disposed once that write settles (the attempt store adopts it). */
52
+ release(key: string): void;
53
+ /**
54
+ * Marks the holder mounted. The returned function marks it unmounted: the leases are released
55
+ * after the commit, unless the holder was attached again (StrictMode's simulated unmount).
56
+ */
57
+ attach(): () => void;
58
+ /** Tells the screen's blockers that a lease changed (dirty, locked, mounted). */
59
+ touch(): void;
60
+ subscribe(listener: () => void): () => void;
61
+ /** Counts every change `touch` announced: the external store's version. */
62
+ version(): number;
63
+ /**
64
+ * What the screen must guard for the leases whose node is not on screen: the labels of those
65
+ * holding unsaved input, and whether any write is in flight.
66
+ */
67
+ guarded(): {
68
+ readonly labels: readonly string[];
69
+ readonly locked: boolean;
70
+ };
71
+ }
72
+ //#endregion
73
+ //#region src/forms/controller/placements.d.ts
74
+ /** What the resolver knows of one placement at mount (spec 8.1, decision 35). */
75
+ interface PlacementRuntime {
76
+ readonly key: string;
77
+ readonly block: EntityRef;
78
+ /** Over props, validation and `data` entries: absent > pending > failed > ready. */
79
+ readonly state: NodeState;
80
+ /**
81
+ * `'access'`: absent because a required prop reads a field its user may not view (P5 spec
82
+ * 3.6.3) — no view mounts, no block `data` is read, and the plan's reason is `access`.
83
+ */
84
+ readonly reason?: 'access';
85
+ readonly error?: unknown;
86
+ /** Whether Retry can help: a failed read, never a refused prop or a missing definition. */
87
+ readonly retryable: boolean;
88
+ /** The validated props (each schema's output), once ready. */
89
+ readonly props?: Readonly<Record<string, unknown>>;
90
+ /** The ready `data` entry values. */
91
+ readonly data: Readonly<Record<string, unknown>>;
92
+ /** A development error to report once (`block.prop-invalid`, `block.data-order`). */
93
+ readonly problem?: {
94
+ readonly code: string;
95
+ readonly message: string;
96
+ };
97
+ /** The block handle (the view's `t` and a test read its definition). */
98
+ readonly definition?: AnyBlockHandle;
99
+ }
100
+ //#endregion
101
+ //#region src/checks/use-check-gate.d.ts
102
+ interface CheckGateRequest {
103
+ readonly surface: CheckSurface;
104
+ readonly values?: Record<string, unknown>;
105
+ readonly saved?: Record<string, unknown>;
106
+ readonly record?: Record<string, unknown>;
107
+ readonly actionName?: string;
108
+ /** The screen's `with` sources the checks read, by name (P2 4.10). */
109
+ readonly sources?: Readonly<Record<string, SourceState>>;
110
+ /** An existing `action.confirm` message; becomes the dialog header. */
111
+ readonly header?: string | null;
112
+ }
113
+ interface CheckGateState {
114
+ /**
115
+ * The resource whose checks this gate evaluates. Carried in the state so the
116
+ * dialog rendering it can bind its translations to the same resource the
117
+ * rules came from: a check message's i18n key is `checks.<id>`, which only
118
+ * reaches the per-resource entry `resources.<name>.checks.<id>` when a
119
+ * resource is bound.
120
+ *
121
+ * It must travel WITH the state rather than being passed to the dialog
122
+ * separately — the ambient `ResourceContext` is not a substitute. Only
123
+ * `<RecordScreen>` and `<DeclarativeForm>` mount one, so an action gated from a
124
+ * LIST ROW has no ambient resource at all, and the same check would render
125
+ * translated on a show page and untranslated in the list. (Exactly the bug
126
+ * `useResolvedLabel` in `action-button.tsx` carries a comment about.)
127
+ *
128
+ * Optional because a resource-less host — `<DeclarativeForm>` builds this
129
+ * shape by hand — genuinely has no resource to name.
130
+ */
131
+ readonly resource?: string;
132
+ readonly open: boolean;
133
+ readonly busy: boolean;
134
+ readonly header: string | null;
135
+ readonly blockers: ValidationIssues;
136
+ readonly confirmable: ValidationIssues;
137
+ readonly proceed: () => void;
138
+ readonly cancel: () => void;
139
+ }
140
+ interface UseCheckGateResult {
141
+ readonly run: (request: CheckGateRequest) => Promise<'proceed' | 'cancel'>;
142
+ readonly state: CheckGateState;
143
+ }
144
+ /**
145
+ * Imperative pre-flight gate. `run()` evaluates the resource's checks for the
146
+ * surface, and resolves immediately with 'proceed' when there is nothing to say.
147
+ * Otherwise it opens (the host renders the dialog off `state`) and resolves once
148
+ * the user decides. One dialog: an existing `action.confirm` becomes its header
149
+ * rather than a second prompt.
150
+ */
151
+ declare function useCheckGate(resource: string): UseCheckGateResult;
152
+ //#endregion
153
+ //#region src/forms/types.d.ts
154
+ /** The live values map a declarative form reads from and writes to. */
155
+ type FormValues = Record<string, unknown>;
156
+ /**
157
+ * A friendly validator return, resolved through `normalizeFieldIssues` at
158
+ * the boundary. Reused for both per-field validators (`ResourceFieldDefinition.
159
+ * validators`, from `@burojs/core`) and the form-level `validate` below.
160
+ */
161
+ type FormLevelValidationResult = FieldIssue | readonly FieldIssue[] | null | undefined;
162
+ /**
163
+ * Cross-field / whole-form validator. Receives the full values map plus the
164
+ * same `{ values, field? }` context shape core's per-field `FieldValidator`
165
+ * uses — deliberately NOT the richer visibility/permission `FieldCtx` from
166
+ * the design doc's §4, since predicates and conditional visibility are
167
+ * Task 4. Keeping this context-free is what lets `renderHook` run this
168
+ * controller with no provider wrapper.
169
+ */
170
+ type FormValidate = (values: FormValues, ctx: ValidationContext) => FormLevelValidationResult | Promise<FormLevelValidationResult>;
171
+ /** A validation issue projected for display: one field, one message. */
172
+ interface ResolvedIssue {
173
+ readonly field: string;
174
+ /** The issue's code (`required`, `string.minLength`, …): `resolveValidationMessage` keys on it. */
175
+ readonly code?: string;
176
+ readonly severity: ValidationIssueSeverity;
177
+ readonly message: MessageReference;
178
+ /**
179
+ * Interpolation params for a bundle-translated `message.key` (e.g. a
180
+ * check's `{ checkId, show, trigger }` — `evaluateChecks`, `@burojs/core`).
181
+ * Forwarded from the source `ValidationIssue.params` so a renderer's
182
+ * `t(message.key, { params })` call can fill in a `{{placeholder}}` in a
183
+ * registered bundle entry, mirroring `resolveValidationMessage`
184
+ * and `<CheckConfirmDialog>`'s own `issueText`.
185
+ */
186
+ readonly params?: Readonly<Record<string, unknown>>;
187
+ }
188
+ /**
189
+ * Minimal event shape `handleSubmit`'s returned handler needs. Structurally
190
+ * compatible with a real DOM `FormEvent`, but the controller itself never
191
+ * imports React's DOM event types — it stays usable outside a `<form>`.
192
+ */
193
+ interface SubmitEventLike {
194
+ readonly preventDefault?: () => void;
195
+ }
196
+ /**
197
+ * The prop bag `<Field {...form.field(name)} />` spreads, and the raw escape
198
+ * hatch for a hand-rolled input. Carries `resource` (derived from
199
+ * `i18nPrefix` via `i18nPrefixToRef`) but deliberately NOT a UI `fallback`
200
+ * node — `@burojs/react` has no shadcn/DOM dependency; the `<Field>` brick
201
+ * in `@burojs/ui-shadcn` supplies its own default fallback.
202
+ *
203
+ * `required`/`disabled`/`hidden` are RESOLVED (Task 4): `hidden` is
204
+ * `!evaluateVisible(field.visible, ctx, values)` (`@burojs/core`'s existing
205
+ * `visible` convention, reused as-is); `required`/`disabled` are each
206
+ * either a static boolean or a predicate `(ctx, values) => boolean`
207
+ * evaluated the same way — see `packages/react/src/forms/conditional.ts`.
208
+ */
209
+ interface FieldBinding {
210
+ readonly name: string;
211
+ readonly value: unknown;
212
+ readonly onChange: (value: unknown) => void;
213
+ readonly onBlur: () => void;
214
+ readonly error?: ResolvedIssue;
215
+ readonly warnings: readonly ResolvedIssue[];
216
+ readonly required: boolean;
217
+ readonly disabled: boolean;
218
+ readonly hidden: boolean;
219
+ readonly resource: EntityRef;
220
+ readonly field: ResourceFieldDefinition;
221
+ /**
222
+ * A relation field's `filter` function, RESOLVED against the current `values` snapshot (design
223
+ * doc §5). `undefined` when the field declared none (or it threw / returned a non-array — the
224
+ * "broken predicate behaves as if never declared" convention `resolvePredicate` uses for
225
+ * `required`/`disabled`, see `./conditional.js`). `@burojs/ui-shadcn`'s `<Field>` hands it to
226
+ * the select as a prop, applied on top of the field's `candidates` (data in `meta`), so a plain
227
+ * `{...binding}` spread onto `<Field>` (what `<DeclarativeForm>` does) needs no extra wiring.
228
+ *
229
+ * Typed as `FixedFilterInput` (not the bare AST) so it widens together
230
+ * with `RelationPickerProps.fixedFilters` and
231
+ * `RelationPickerDialogProps.fixedFilters` downstream.
232
+ */
233
+ readonly fixedFilters?: readonly FixedFilterInput[];
234
+ /**
235
+ * A relation field's create seeds (P6-31): the top-level `eq` literals of the field's
236
+ * `meta.candidates`, read from the code registry's definition only, and none for a field whose
237
+ * candidates a granted layer chose. Never derived from `fixedFilters` or the compiled
238
+ * declaration, which a component or a granted layer can write.
239
+ */
240
+ readonly relationSeeds?: Readonly<Record<string, unknown>>;
241
+ }
242
+ /**
243
+ * A relation field's `filter` (design doc §5): code that returns extra filters from the form's
244
+ * current values, applied on top of the field's `candidates` (data, in `meta`). A static array is
245
+ * not a `filter` — that is `candidates`. See `readFieldFilterOpt` in `./conditional.js`.
246
+ */
247
+ type RelationFilterOpt = (values: FormValues) => readonly FilterExpression<ErasedResourceHandle>[];
248
+ /** The members every form controller exposes (values, bindings, submit). */
249
+ interface FormControllerMembers {
250
+ /** Spread into `<Field/>`, or read raw for a hand-rolled input. */
251
+ field(name: string): FieldBinding;
252
+ /** The fields the plan does not make inactive, in declaration order. */
253
+ readonly fields: readonly FieldBinding[];
254
+ readonly values: FormValues;
255
+ /** severity 'error' issues, form-level plus per-field, from the last validation pass. */
256
+ readonly errors: readonly ResolvedIssue[];
257
+ /** severity 'warning' | 'info' issues — never block `canSubmit`. */
258
+ readonly warnings: readonly ResolvedIssue[];
259
+ /** `errors.length === 0 && !isSubmitting`. */
260
+ readonly canSubmit: boolean;
261
+ /** Current `values` vs. the baseline captured once at mount. */
262
+ readonly isDirty: boolean;
263
+ readonly isSubmitting: boolean;
264
+ /** The last check pass, for a host that mounts its own confirm gate. */
265
+ readonly checkOutcome: CheckOutcome | null;
266
+ handleSubmit(cb?: (values: FormValues) => unknown | Promise<unknown>): (e?: SubmitEventLike) => Promise<void>;
267
+ setValue(name: string, value: unknown): void;
268
+ reset(next?: FormValues): void;
269
+ /**
270
+ * Re-run every field's + the form's validation against the current
271
+ * `values` and update `errors`/`warnings`. A live seam for a renderer or
272
+ * adopter to call on value change (e.g. debounced) — this controller does
273
+ * NOT call it itself; deciding when to revalidate outside of blur/submit
274
+ * is the caller's job.
275
+ */
276
+ revalidate(): Promise<void>;
277
+ }
278
+ //#endregion
279
+ //#region src/forms/controller/types.d.ts
280
+ type AnyResourceHandle = ResourceHandle<any, any, any, any>;
281
+ /** A record form: its screen comes from `compiledScreenFor`, its record from the `SourceResolver`. */
282
+ interface UseFormControllerRecordOptions {
283
+ /** A canonical name, or a handle reduced to its canonical ref (never read). */
284
+ readonly resource: string | AnyResourceHandle;
285
+ readonly mode: 'create' | 'edit' | 'show';
286
+ /** The record's id (edit, show). */
287
+ readonly recordId?: string;
288
+ /** The accepted type of a typed create (from the route's `?type=` or the type offer). */
289
+ readonly type?: string;
290
+ /** A caller-supplied row: nothing is read. */
291
+ readonly record?: Record<string, unknown>;
292
+ /** The caller's seed tier of a create, above the field defaults and the type's defaults. */
293
+ readonly defaults?: Record<string, unknown>;
294
+ /** Default: the resource's `draft`. */
295
+ readonly draft?: DraftOption;
296
+ /** Replaces the built-in create / update mutation; receives the payload. */
297
+ readonly onSubmit?: (payload: Record<string, unknown>) => Promise<unknown>;
298
+ /**
299
+ * The entry the screen is compiled for (P6 3.8): `'route'` by default; a quick host passes
300
+ * `'quick'` so a declared quick screen plans its own body. Typed in P6-A; read from P6-B.
301
+ */
302
+ readonly entry?: ScreenEntry;
303
+ }
304
+ /**
305
+ * A resource-less form: its screen is compiled from `fields` and `body`
306
+ * (`compileFormScreen`), and only `onSubmit` writes.
307
+ */
308
+ interface UseFormControllerFormOptions<F extends ResourceFieldMap = ResourceFieldMap> {
309
+ readonly fields: F;
310
+ /** The tree; absent, the generic one-column tree in declaration order. */
311
+ readonly body?: FormBody<F>;
312
+ /** The draft identity; `draft` without it is a development error. */
313
+ readonly formId?: string;
314
+ /** Default `'create'`; `'show'` is display only. */
315
+ readonly mode?: 'create' | 'edit' | 'show';
316
+ /** The check surface; default `'edit'` in edit mode, `'create'` otherwise. */
317
+ readonly surface?: CheckSurface;
318
+ /** Text slots key as `resources.<i18nPrefix>.…`; default `'form'`. */
319
+ readonly i18nPrefix?: string;
320
+ readonly defaults?: FormValues;
321
+ /** Controlled values; the form follows them and reports edits through `onChange`. */
322
+ readonly value?: FormValues;
323
+ readonly onChange?: (values: FormValues) => void;
324
+ readonly schema?: StandardSchemaV1;
325
+ readonly validate?: FormValidate;
326
+ readonly checks?: readonly Check[];
327
+ readonly onConfirmChecks?: (outcome: CheckOutcome) => Promise<'proceed' | 'cancel'>;
328
+ readonly draft?: DraftOption;
329
+ /**
330
+ * @internal A flow's form (P4 spec 4.4): the run `useFlowRun` created. With it — a claim the
331
+ * controller verifies, never a bare flag (Known finding 24) — the controller emits no
332
+ * `form.submit` (the run emits `flow.submit`) and keys its draft in mode `flow`.
333
+ */
334
+ readonly flowRun?: FlowRun;
335
+ /**
336
+ * @internal A flow's form: the issues its run decided (honoured only with the run's claim).
337
+ */
338
+ readonly flowIssues?: readonly ValidationIssue[];
339
+ /**
340
+ * @internal The owner's own source states a field's `meta` refs read beside the form's `values`,
341
+ * `scope` and `user` (P7 3.2): a flow's `record` and `args`. Honoured only with the run's claim
342
+ * (`flowRun`), like the flow issues: a bare option cannot put a source in front of a field.
343
+ */
344
+ readonly metaSources?: ScreenSources;
345
+ /** @internal The flow draft key's segments: the record, the args and selection hashes. */
346
+ readonly flowDraft?: {
347
+ readonly recordId?: string;
348
+ readonly argsHash?: string;
349
+ readonly selectionHash?: string;
350
+ /** The run's attempt key: a forced sign-out keeps the draft while it is unresolved. */
351
+ readonly attempt?: string;
352
+ };
353
+ /**
354
+ * @internal The trusted block catalogue the tree may place from (P4-D): a flow's form and
355
+ * review pass the app's (`snapshotBlockLookup` over the committed snapshot), so
356
+ * `l.place(appBlock)` resolves. Without it only the built-in blocks do.
357
+ */
358
+ readonly blocks?: BlockLookup;
359
+ /** Receives the active declared values (the payload). */
360
+ readonly onSubmit?: (values: FormValues) => unknown | Promise<unknown>;
361
+ /**
362
+ * The field access of a resource's fields (P5 decision 41): a form field whose name is a
363
+ * declared field of `resource` takes that field's `requires` and `field/*` rules, planned and
364
+ * projected exactly as on a record form (in edit and show the form's values are the record the
365
+ * rules see); any other field has none.
366
+ */
367
+ readonly access?: {
368
+ readonly resource: string;
369
+ };
370
+ }
371
+ /** Why a controller plans nothing and refuses to submit. */
372
+ type FormControllerFailure = {
373
+ readonly kind: 'screen';
374
+ readonly failure: ScreenFailure;
375
+ } | {
376
+ readonly kind: 'type-required';
377
+ };
378
+ type FormSubmitResult = {
379
+ readonly status: 'submitted';
380
+ readonly result: unknown;
381
+ } |
382
+ /** The write threw: `error` is what it threw; the values and the draft stay. */
383
+ {
384
+ readonly status: 'failed';
385
+ readonly error: unknown;
386
+ } | {
387
+ readonly status: 'invalid' | 'blocked' | 'cancelled' | 'refused';
388
+ };
389
+ /** A stored draft offered for restore. */
390
+ interface FormDraftState {
391
+ readonly pending: {
392
+ readonly savedAt: string;
393
+ } | null;
394
+ /**
395
+ * Edit only: the record changed since the draft was made. The draft is
396
+ * still offered (the host shows `draft.recordChanged`), `restore()` is
397
+ * refused and `discard()` stays.
398
+ */
399
+ readonly recordChanged: boolean;
400
+ restore(): void;
401
+ discard(): void;
402
+ }
403
+ /**
404
+ * A create's `steps` wizard (P1b+P1c decision 11). Step ids are the step
405
+ * panels' keys (else their node ids), in order; the current step is the
406
+ * steps node's open panel.
407
+ */
408
+ interface FormSteps {
409
+ readonly ids: readonly string[];
410
+ readonly current: string | undefined;
411
+ /** The steps left with Next, in the order they were completed. */
412
+ readonly completed: readonly string[];
413
+ /**
414
+ * Validates the current step's active fields and, when they pass, opens the
415
+ * next step that has an active field; whether it advanced.
416
+ */
417
+ next(): Promise<boolean>;
418
+ /** Opens the previous step that has an active field. */
419
+ back(): void;
420
+ /** Opens a completed step (or the current one); any other id is ignored. */
421
+ goTo(id: string): void;
422
+ }
423
+ interface FormController extends FormControllerMembers {
424
+ /**
425
+ * The compiled screen this controller plans (the accessor's object); `null`
426
+ * on a failure or an unknown resource. Hosts render the tree from it.
427
+ */
428
+ readonly screen: CompiledScreen | null;
429
+ /** `null` on a failure. */
430
+ readonly plan: ScreenPlan | null;
431
+ readonly failure: FormControllerFailure | null;
432
+ submit(): Promise<FormSubmitResult>;
433
+ readonly draft: FormDraftState;
434
+ /**
435
+ * The record the form shows or edits once it is ready (a caller's `record`,
436
+ * or the one the `SourceResolver` read); `undefined` in create and while
437
+ * the read is pending.
438
+ */
439
+ readonly record: Readonly<Record<string, unknown>> | undefined;
440
+ /**
441
+ * The sources the plan was made from, as view code reads them (P5 spec 3.6.1): `record` and
442
+ * `values` projected by field view, `scope`, `user`, and the screen's `with` sources. A field's
443
+ * `meta` refs read these, so a field P5 withholds stays pending there too.
444
+ */
445
+ readonly sources: ScreenSources;
446
+ /** Refetches the failed requests under these source names (a failed node's Retry). */
447
+ retry(sources: readonly string[]): void;
448
+ /**
449
+ * A placement at mount, by its key (a nested one by its derived key): its props validated, its
450
+ * `data` entries resolved; `undefined` for a key the screen does not place. `usePlacement`
451
+ * reads it.
452
+ */
453
+ placement(key: string): PlacementRuntime | undefined;
454
+ /**
455
+ * The number of error issues (not fields) on the `active` field leaves under
456
+ * the keyed node `containerKey`: a tab's, a step's or a panel's badge.
457
+ */
458
+ errorsIn(containerKey: string): number;
459
+ /**
460
+ * Registers what brings a node into view: a submit refused by validation
461
+ * calls, outermost first, the reveal of every container holding the first
462
+ * failing field, then that field leaf's own reveal (which focuses its input).
463
+ * `nodeId` is the compiled node's id. Returns the unregister function.
464
+ */
465
+ registerReveal(nodeId: string, reveal: () => void): () => void;
466
+ /**
467
+ * The resource's check gate (a record form): the confirm dialog a host
468
+ * renders while a submit waits for the user's decision; `null` for a
469
+ * resource-less form, whose host passes `onConfirmChecks`.
470
+ */
471
+ readonly checkGate: CheckGateState | null;
472
+ /**
473
+ * A background run of the resource's form-level `validate` is in flight (the
474
+ * debounced run as the user types; a submit's own run is `isSubmitting`).
475
+ */
476
+ readonly isValidating: boolean;
477
+ /** A create whose body holds a `steps` node: the wizard; `null` otherwise. */
478
+ readonly steps: FormSteps | null;
479
+ /**
480
+ * A typed create's type offer (P1b+P1c decision 24): `pending` while the
481
+ * offer's `scope` is, else the types on offer; `null` for any other form.
482
+ * A host shows it while `failure` is `type-required`.
483
+ */
484
+ readonly typeOffer: TypeOfferState | null;
485
+ }
486
+ //#endregion
487
+ export { InlineFlowHolder as _, FormSubmitResult as a, FieldBinding as c, ResolvedIssue as d, CheckGateRequest as f, PlacementRuntime as g, useCheckGate as h, FormSteps as i, FormValues as l, UseCheckGateResult as m, FormControllerFailure as n, UseFormControllerFormOptions as o, CheckGateState as p, FormDraftState as r, UseFormControllerRecordOptions as s, FormController as t, RelationFilterOpt as u, InlineLease as v };
488
+ //# sourceMappingURL=types-DH3beUOO.d.cts.map