@angular/forms 21.0.0-rc.2 → 21.0.0-rc.3

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,2240 @@
1
+ /**
2
+ * @license Angular v21.0.0-rc.3
3
+ * (c) 2010-2025 Google LLC. https://angular.dev/
4
+ * License: MIT
5
+ */
6
+
7
+ import * as i0 from '@angular/core';
8
+ import { InjectionToken, ɵControl as _Control, ɵCONTROL as _CONTROL, ɵInteropControl as _InteropControl, ɵFieldState as _FieldState, Signal, WritableSignal, DestroyableInjector, Injector } from '@angular/core';
9
+ import * as _angular_forms from '@angular/forms';
10
+ import { NgControl, AbstractControl, ValidationErrors, FormControlStatus, ControlValueAccessor, ValidatorFn } from '@angular/forms';
11
+ import { StandardSchemaV1 } from '@standard-schema/spec';
12
+
13
+ /**
14
+ * Properties of both NgControl & AbstractControl that are supported by the InteropNgControl.
15
+ */
16
+ type InteropSharedKeys = 'value' | 'valid' | 'invalid' | 'touched' | 'untouched' | 'disabled' | 'enabled' | 'errors' | 'pristine' | 'dirty' | 'status';
17
+ /**
18
+ * A fake version of `NgControl` provided by the `Field` directive. This allows interoperability
19
+ * with a wider range of components designed to work with reactive forms, in particular ones that
20
+ * inject the `NgControl`. The interop control does not implement *all* properties and methods of
21
+ * the real `NgControl`, but does implement some of the most commonly used ones that have a clear
22
+ * equivalent in signal forms.
23
+ */
24
+ declare class InteropNgControl implements Pick<NgControl, InteropSharedKeys | 'control' | 'valueAccessor'>, Pick<AbstractControl<unknown>, InteropSharedKeys | 'hasValidator'> {
25
+ protected field: () => FieldState<unknown>;
26
+ constructor(field: () => FieldState<unknown>);
27
+ readonly control: AbstractControl<any, any>;
28
+ get value(): any;
29
+ get valid(): boolean;
30
+ get invalid(): boolean;
31
+ get pending(): boolean | null;
32
+ get disabled(): boolean;
33
+ get enabled(): boolean;
34
+ get errors(): ValidationErrors | null;
35
+ get pristine(): boolean;
36
+ get dirty(): boolean;
37
+ get touched(): boolean;
38
+ get untouched(): boolean;
39
+ get status(): FormControlStatus;
40
+ valueAccessor: ControlValueAccessor | null;
41
+ hasValidator(validator: ValidatorFn): boolean;
42
+ updateValueAndValidity(): void;
43
+ }
44
+
45
+ /**
46
+ * Lightweight DI token provided by the {@link Field} directive.
47
+ *
48
+ * @category control
49
+ * @experimental 21.0.0
50
+ */
51
+ declare const FIELD: InjectionToken<Field<unknown>>;
52
+ /**
53
+ * Binds a form `FieldTree` to a UI control that edits it. A UI control can be one of several things:
54
+ * 1. A native HTML input or textarea
55
+ * 2. A signal forms custom control that implements `FormValueControl` or `FormCheckboxControl`
56
+ * 3. A component that provides a `ControlValueAccessor`. This should only be used for backwards
57
+ * compatibility with reactive forms. Prefer options (1) and (2).
58
+ *
59
+ * This directive has several responsibilities:
60
+ * 1. Two-way binds the field's value with the UI control's value
61
+ * 2. Binds additional forms related state on the field to the UI control (disabled, required, etc.)
62
+ * 3. Relays relevant events on the control to the field (e.g. marks field touched on blur)
63
+ * 4. Provides a fake `NgControl` that implements a subset of the features available on the
64
+ * reactive forms `NgControl`. This is provided to improve interoperability with controls
65
+ * designed to work with reactive forms. It should not be used by controls written for signal
66
+ * forms.
67
+ *
68
+ * @category control
69
+ * @experimental 21.0.0
70
+ */
71
+ declare class Field<T> implements _Control<T> {
72
+ private readonly injector;
73
+ readonly field: i0.InputSignal<FieldTree<T>>;
74
+ readonly state: i0.Signal<[T] extends [_angular_forms.AbstractControl<any, any, any>] ? CompatFieldState<T, string | number> : FieldState<T, string | number>>;
75
+ readonly [_CONTROL]: undefined;
76
+ /** Any `ControlValueAccessor` instances provided on the host element. */
77
+ private readonly controlValueAccessors;
78
+ /** A lazily instantiated fake `NgControl`. */
79
+ private interopNgControl;
80
+ /** A `ControlValueAccessor`, if configured, for the host component. */
81
+ get ɵinteropControl(): _InteropControl | undefined;
82
+ /** Lazily instantiates a fake `NgControl` for this field. */
83
+ protected getOrCreateNgControl(): InteropNgControl;
84
+ ɵregister(): void;
85
+ static ɵfac: i0.ɵɵFactoryDeclaration<Field<any>, never>;
86
+ static ɵdir: i0.ɵɵDirectiveDeclaration<Field<any>, "[field]", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
87
+ }
88
+
89
+ /**
90
+ * Represents metadata that may be defined on a field when it is created using a `metadata` rule
91
+ * in the schema. A particular `MetadataKey` can only be defined on a particular field **once**.
92
+ *
93
+ * @category logic
94
+ * @experimental 21.0.0
95
+ */
96
+ declare class MetadataKey<TValue> {
97
+ private brand;
98
+ /** Use {@link createMetadataKey}. */
99
+ private constructor();
100
+ }
101
+ /**
102
+ * Creates a {@link MetadataKey}.
103
+ *
104
+ * @experimental 21.0.0
105
+ */
106
+ declare function createMetadataKey<TValue>(): MetadataKey<TValue>;
107
+ /**
108
+ * Represents metadata that is aggregated from multiple parts according to the key's reducer
109
+ * function. A value can be contributed to the aggregated value for a field using an
110
+ * `aggregateMetadata` rule in the schema. There may be multiple rules in a schema that contribute
111
+ * values to the same `AggregateMetadataKey` of the same field.
112
+ *
113
+ * @experimental 21.0.0
114
+ */
115
+ declare class AggregateMetadataKey<TAcc, TItem> {
116
+ readonly reduce: (acc: TAcc, item: TItem) => TAcc;
117
+ readonly getInitial: () => TAcc;
118
+ private brand;
119
+ /** Use {@link reducedMetadataKey}. */
120
+ private constructor();
121
+ }
122
+ /**
123
+ * Creates an {@link AggregateMetadataKey} that reduces its individual values into an accumulated
124
+ * value using the given `reduce` and `getInitial` functions.
125
+ * @param reduce The reducer function.
126
+ * @param getInitial A function that gets the initial value for the reduce operation.
127
+ *
128
+ * @experimental 21.0.0
129
+ */
130
+ declare function reducedMetadataKey<TAcc, TItem>(reduce: (acc: TAcc, item: TItem) => TAcc, getInitial: NoInfer<() => TAcc>): AggregateMetadataKey<TAcc, TItem>;
131
+ /**
132
+ * Creates an {@link AggregateMetadataKey} that reduces its individual values into a list.
133
+ *
134
+ * @experimental 21.0.0
135
+ */
136
+ declare function listMetadataKey<TItem>(): AggregateMetadataKey<TItem[], TItem | undefined>;
137
+ /**
138
+ * Creates {@link AggregateMetadataKey} that reduces its individual values by taking their min.
139
+ *
140
+ * @experimental 21.0.0
141
+ */
142
+ declare function minMetadataKey(): AggregateMetadataKey<number | undefined, number | undefined>;
143
+ /**
144
+ * Creates {@link AggregateMetadataKey} that reduces its individual values by taking their max.
145
+ *
146
+ * @experimental 21.0.0
147
+ */
148
+ declare function maxMetadataKey(): AggregateMetadataKey<number | undefined, number | undefined>;
149
+ /**
150
+ * Creates an {@link AggregateMetadataKey} that reduces its individual values by logically or-ing
151
+ * them.
152
+ *
153
+ * @experimental 21.0.0
154
+ */
155
+ declare function orMetadataKey(): AggregateMetadataKey<boolean, boolean>;
156
+ /**
157
+ * Creates an {@link AggregateMetadataKey} that reduces its individual values by logically and-ing
158
+ * them.
159
+ *
160
+ * @experimental 21.0.0
161
+ */
162
+ declare function andMetadataKey(): AggregateMetadataKey<boolean, boolean>;
163
+ /**
164
+ * An {@link AggregateMetadataKey} representing whether the field is required.
165
+ *
166
+ * @category validation
167
+ * @experimental 21.0.0
168
+ */
169
+ declare const REQUIRED: AggregateMetadataKey<boolean, boolean>;
170
+ /**
171
+ * An {@link AggregateMetadataKey} representing the min value of the field.
172
+ *
173
+ * @category validation
174
+ * @experimental 21.0.0
175
+ */
176
+ declare const MIN: AggregateMetadataKey<number | undefined, number | undefined>;
177
+ /**
178
+ * An {@link AggregateMetadataKey} representing the max value of the field.
179
+ *
180
+ * @category validation
181
+ * @experimental 21.0.0
182
+ */
183
+ declare const MAX: AggregateMetadataKey<number | undefined, number | undefined>;
184
+ /**
185
+ * An {@link AggregateMetadataKey} representing the min length of the field.
186
+ *
187
+ * @category validation
188
+ * @experimental 21.0.0
189
+ */
190
+ declare const MIN_LENGTH: AggregateMetadataKey<number | undefined, number | undefined>;
191
+ /**
192
+ * An {@link AggregateMetadataKey} representing the max length of the field.
193
+ *
194
+ * @category validation
195
+ * @experimental 21.0.0
196
+ */
197
+ declare const MAX_LENGTH: AggregateMetadataKey<number | undefined, number | undefined>;
198
+ /**
199
+ * An {@link AggregateMetadataKey} representing the patterns the field must match.
200
+ *
201
+ * @category validation
202
+ * @experimental 21.0.0
203
+ */
204
+ declare const PATTERN: AggregateMetadataKey<RegExp[], RegExp | undefined>;
205
+
206
+ /**
207
+ * Options used to create a `ValidationError`.
208
+ */
209
+ interface ValidationErrorOptions {
210
+ /** Human readable error message. */
211
+ message?: string;
212
+ }
213
+ /**
214
+ * A type that requires the given type `T` to have a `field` property.
215
+ * @template T The type to add a `field` to.
216
+ *
217
+ * @experimental 21.0.0
218
+ */
219
+ type WithField<T> = T & {
220
+ field: FieldTree<unknown>;
221
+ };
222
+ /**
223
+ * A type that allows the given type `T` to optionally have a `field` property.
224
+ * @template T The type to optionally add a `field` to.
225
+ *
226
+ * @experimental 21.0.0
227
+ */
228
+ type WithOptionalField<T> = Omit<T, 'field'> & {
229
+ field?: FieldTree<unknown>;
230
+ };
231
+ /**
232
+ * A type that ensures the given type `T` does not have a `field` property.
233
+ * @template T The type to remove the `field` from.
234
+ *
235
+ * @experimental 21.0.0
236
+ */
237
+ type WithoutField<T> = T & {
238
+ field: never;
239
+ };
240
+ /**
241
+ * Create a required error associated with the target field
242
+ * @param options The validation error options
243
+ *
244
+ * @experimental 21.0.0
245
+ */
246
+ declare function requiredError(options: WithField<ValidationErrorOptions>): RequiredValidationError;
247
+ /**
248
+ * Create a required error
249
+ * @param options The optional validation error options
250
+ *
251
+ * @category validation
252
+ * @experimental 21.0.0
253
+ */
254
+ declare function requiredError(options?: ValidationErrorOptions): WithoutField<RequiredValidationError>;
255
+ /**
256
+ * Create a min value error associated with the target field
257
+ * @param min The min value constraint
258
+ * @param options The validation error options
259
+ *
260
+ * @category validation
261
+ * @experimental 21.0.0
262
+ */
263
+ declare function minError(min: number, options: WithField<ValidationErrorOptions>): MinValidationError;
264
+ /**
265
+ * Create a min value error
266
+ * @param min The min value constraint
267
+ * @param options The optional validation error options
268
+ *
269
+ * @category validation
270
+ * @experimental 21.0.0
271
+ */
272
+ declare function minError(min: number, options?: ValidationErrorOptions): WithoutField<MinValidationError>;
273
+ /**
274
+ * Create a max value error associated with the target field
275
+ * @param max The max value constraint
276
+ * @param options The validation error options
277
+ *
278
+ * @category validation
279
+ * @experimental 21.0.0
280
+ */
281
+ declare function maxError(max: number, options: WithField<ValidationErrorOptions>): MaxValidationError;
282
+ /**
283
+ * Create a max value error
284
+ * @param max The max value constraint
285
+ * @param options The optional validation error options
286
+ *
287
+ * @category validation
288
+ * @experimental 21.0.0
289
+ */
290
+ declare function maxError(max: number, options?: ValidationErrorOptions): WithoutField<MaxValidationError>;
291
+ /**
292
+ * Create a minLength error associated with the target field
293
+ * @param minLength The minLength constraint
294
+ * @param options The validation error options
295
+ *
296
+ * @category validation
297
+ * @experimental 21.0.0
298
+ */
299
+ declare function minLengthError(minLength: number, options: WithField<ValidationErrorOptions>): MinLengthValidationError;
300
+ /**
301
+ * Create a minLength error
302
+ * @param minLength The minLength constraint
303
+ * @param options The optional validation error options
304
+ *
305
+ * @category validation
306
+ * @experimental 21.0.0
307
+ */
308
+ declare function minLengthError(minLength: number, options?: ValidationErrorOptions): WithoutField<MinLengthValidationError>;
309
+ /**
310
+ * Create a maxLength error associated with the target field
311
+ * @param maxLength The maxLength constraint
312
+ * @param options The validation error options
313
+ *
314
+ * @category validation
315
+ * @experimental 21.0.0
316
+ */
317
+ declare function maxLengthError(maxLength: number, options: WithField<ValidationErrorOptions>): MaxLengthValidationError;
318
+ /**
319
+ * Create a maxLength error
320
+ * @param maxLength The maxLength constraint
321
+ * @param options The optional validation error options
322
+ *
323
+ * @category validation
324
+ * @experimental 21.0.0
325
+ */
326
+ declare function maxLengthError(maxLength: number, options?: ValidationErrorOptions): WithoutField<MaxLengthValidationError>;
327
+ /**
328
+ * Create a pattern matching error associated with the target field
329
+ * @param pattern The violated pattern
330
+ * @param options The validation error options
331
+ *
332
+ * @category validation
333
+ * @experimental 21.0.0
334
+ */
335
+ declare function patternError(pattern: RegExp, options: WithField<ValidationErrorOptions>): PatternValidationError;
336
+ /**
337
+ * Create a pattern matching error
338
+ * @param pattern The violated pattern
339
+ * @param options The optional validation error options
340
+ *
341
+ * @category validation
342
+ * @experimental 21.0.0
343
+ */
344
+ declare function patternError(pattern: RegExp, options?: ValidationErrorOptions): WithoutField<PatternValidationError>;
345
+ /**
346
+ * Create an email format error associated with the target field
347
+ * @param options The validation error options
348
+ *
349
+ * @category validation
350
+ * @experimental 21.0.0
351
+ */
352
+ declare function emailError(options: WithField<ValidationErrorOptions>): EmailValidationError;
353
+ /**
354
+ * Create an email format error
355
+ * @param options The optional validation error options
356
+ *
357
+ * @category validation
358
+ * @experimental 21.0.0
359
+ */
360
+ declare function emailError(options?: ValidationErrorOptions): WithoutField<EmailValidationError>;
361
+ /**
362
+ * Create a standard schema issue error associated with the target field
363
+ * @param issue The standard schema issue
364
+ * @param options The validation error options
365
+ *
366
+ * @category validation
367
+ * @experimental 21.0.0
368
+ */
369
+ declare function standardSchemaError(issue: StandardSchemaV1.Issue, options: WithField<ValidationErrorOptions>): StandardSchemaValidationError;
370
+ /**
371
+ * Create a standard schema issue error
372
+ * @param issue The standard schema issue
373
+ * @param options The optional validation error options
374
+ *
375
+ * @category validation
376
+ * @experimental 21.0.0
377
+ */
378
+ declare function standardSchemaError(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions): WithoutField<StandardSchemaValidationError>;
379
+ /**
380
+ * Create a custom error associated with the target field
381
+ * @param obj The object to create an error from
382
+ *
383
+ * @category validation
384
+ * @experimental 21.0.0
385
+ */
386
+ declare function customError<E extends Partial<ValidationError.WithField>>(obj: WithField<E>): CustomValidationError;
387
+ /**
388
+ * Create a custom error
389
+ * @param obj The object to create an error from
390
+ *
391
+ * @category validation
392
+ * @experimental 21.0.0
393
+ */
394
+ declare function customError<E extends Partial<ValidationError.WithField>>(obj?: E): WithoutField<CustomValidationError>;
395
+ /**
396
+ * Common interface for all validation errors.
397
+ *
398
+ * This can be returned from validators.
399
+ *
400
+ * It's also used by the creation functions to create an instance
401
+ * (e.g. `requiredError`, `minError`, etc.).
402
+ *
403
+ * @category validation
404
+ * @experimental 21.0.0
405
+ */
406
+ interface ValidationError {
407
+ /** Identifies the kind of error. */
408
+ readonly kind: string;
409
+ /** Human readable error message. */
410
+ readonly message?: string;
411
+ }
412
+ declare namespace ValidationError {
413
+ /**
414
+ * Validation error with a field.
415
+ *
416
+ * This is returned from field state, e.g., catField.errors() would be of a list of errors with
417
+ * `field: catField` bound to state.
418
+ */
419
+ interface WithField extends ValidationError {
420
+ /** The field associated with this error. */
421
+ readonly field: FieldTree<unknown>;
422
+ }
423
+ /**
424
+ * Validation error with optional field.
425
+ *
426
+ * This is generally used in places where the result might have a field.
427
+ * e.g., as a result of a `validateTree`, or when handling form submission.
428
+ */
429
+ interface WithOptionalField extends ValidationError {
430
+ /** The field associated with this error. */
431
+ readonly field?: FieldTree<unknown>;
432
+ }
433
+ /**
434
+ * Validation error with no field.
435
+ *
436
+ * This is used to strongly enforce that fields are not allowed in validation result.
437
+ */
438
+ interface WithoutField extends ValidationError {
439
+ /** The field associated with this error. */
440
+ readonly field?: never;
441
+ }
442
+ }
443
+ /**
444
+ * A custom error that may contain additional properties
445
+ *
446
+ * @category validation
447
+ * @experimental 21.0.0
448
+ */
449
+ declare class CustomValidationError implements ValidationError {
450
+ /** Brand the class to avoid Typescript structural matching */
451
+ private __brand;
452
+ /**
453
+ * Allow the user to attach arbitrary other properties.
454
+ */
455
+ [key: PropertyKey]: unknown;
456
+ /** Identifies the kind of error. */
457
+ readonly kind: string;
458
+ /** The field associated with this error. */
459
+ readonly field: FieldTree<unknown>;
460
+ /** Human readable error message. */
461
+ readonly message?: string;
462
+ constructor(options?: ValidationErrorOptions);
463
+ }
464
+ /**
465
+ * Internal version of `NgValidationError`, we create this separately so we can change its type on
466
+ * the exported version to a type union of the possible sub-classes.
467
+ *
468
+ * @experimental 21.0.0
469
+ */
470
+ declare abstract class _NgValidationError implements ValidationError {
471
+ /** Brand the class to avoid Typescript structural matching */
472
+ private __brand;
473
+ /** Identifies the kind of error. */
474
+ readonly kind: string;
475
+ /** The field associated with this error. */
476
+ readonly field: FieldTree<unknown>;
477
+ /** Human readable error message. */
478
+ readonly message?: string;
479
+ constructor(options?: ValidationErrorOptions);
480
+ }
481
+ /**
482
+ * An error used to indicate that a required field is empty.
483
+ *
484
+ * @category validation
485
+ * @experimental 21.0.0
486
+ */
487
+ declare class RequiredValidationError extends _NgValidationError {
488
+ readonly kind = "required";
489
+ }
490
+ /**
491
+ * An error used to indicate that a value is lower than the minimum allowed.
492
+ *
493
+ * @category validation
494
+ * @experimental 21.0.0
495
+ */
496
+ declare class MinValidationError extends _NgValidationError {
497
+ readonly min: number;
498
+ readonly kind = "min";
499
+ constructor(min: number, options?: ValidationErrorOptions);
500
+ }
501
+ /**
502
+ * An error used to indicate that a value is higher than the maximum allowed.
503
+ *
504
+ * @category validation
505
+ * @experimental 21.0.0
506
+ */
507
+ declare class MaxValidationError extends _NgValidationError {
508
+ readonly max: number;
509
+ readonly kind = "max";
510
+ constructor(max: number, options?: ValidationErrorOptions);
511
+ }
512
+ /**
513
+ * An error used to indicate that a value is shorter than the minimum allowed length.
514
+ *
515
+ * @category validation
516
+ * @experimental 21.0.0
517
+ */
518
+ declare class MinLengthValidationError extends _NgValidationError {
519
+ readonly minLength: number;
520
+ readonly kind = "minLength";
521
+ constructor(minLength: number, options?: ValidationErrorOptions);
522
+ }
523
+ /**
524
+ * An error used to indicate that a value is longer than the maximum allowed length.
525
+ *
526
+ * @category validation
527
+ * @experimental 21.0.0
528
+ */
529
+ declare class MaxLengthValidationError extends _NgValidationError {
530
+ readonly maxLength: number;
531
+ readonly kind = "maxLength";
532
+ constructor(maxLength: number, options?: ValidationErrorOptions);
533
+ }
534
+ /**
535
+ * An error used to indicate that a value does not match the required pattern.
536
+ *
537
+ * @category validation
538
+ * @experimental 21.0.0
539
+ */
540
+ declare class PatternValidationError extends _NgValidationError {
541
+ readonly pattern: RegExp;
542
+ readonly kind = "pattern";
543
+ constructor(pattern: RegExp, options?: ValidationErrorOptions);
544
+ }
545
+ /**
546
+ * An error used to indicate that a value is not a valid email.
547
+ *
548
+ * @category validation
549
+ * @experimental 21.0.0
550
+ */
551
+ declare class EmailValidationError extends _NgValidationError {
552
+ readonly kind = "email";
553
+ }
554
+ /**
555
+ * An error used to indicate an issue validating against a standard schema.
556
+ *
557
+ * @category validation
558
+ * @experimental 21.0.0
559
+ */
560
+ declare class StandardSchemaValidationError extends _NgValidationError {
561
+ readonly issue: StandardSchemaV1.Issue;
562
+ readonly kind = "standardSchema";
563
+ constructor(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions);
564
+ }
565
+ /**
566
+ * The base class for all built-in, non-custom errors. This class can be used to check if an error
567
+ * is one of the standard kinds, allowing you to switch on the kind to further narrow the type.
568
+ *
569
+ * @example
570
+ * ```
571
+ * const f = form(...);
572
+ * for (const e of form().errors()) {
573
+ * if (e instanceof NgValidationError) {
574
+ * switch(e.kind) {
575
+ * case 'required':
576
+ * console.log('This is required!');
577
+ * break;
578
+ * case 'min':
579
+ * console.log(`Must be at least ${e.min}`);
580
+ * break;
581
+ * ...
582
+ * }
583
+ * }
584
+ * }
585
+ * ```
586
+ *
587
+ * @category validation
588
+ * @experimental 21.0.0
589
+ */
590
+ declare const NgValidationError: abstract new () => NgValidationError;
591
+ type NgValidationError = RequiredValidationError | MinValidationError | MaxValidationError | MinLengthValidationError | MaxLengthValidationError | PatternValidationError | EmailValidationError | StandardSchemaValidationError;
592
+
593
+ /**
594
+ * Symbol used to retain generic type information when it would otherwise be lost.
595
+ */
596
+ declare const ɵɵTYPE: unique symbol;
597
+ /**
598
+ * A type that represents either a single value of type `T` or a readonly array of `T`.
599
+ * @template T The type of the value(s).
600
+ *
601
+ * @experimental 21.0.0
602
+ */
603
+ type OneOrMany<T> = T | readonly T[];
604
+ /**
605
+ * The kind of `FieldPath` (`Root`, `Child` of another `FieldPath`, or `Item` in a `FieldPath` array)
606
+ *
607
+ * @experimental 21.0.0
608
+ */
609
+ type PathKind = PathKind.Root | PathKind.Child | PathKind.Item;
610
+ declare namespace PathKind {
611
+ /**
612
+ * The `PathKind` for a `FieldPath` that is at the root of its field tree.
613
+ */
614
+ interface Root {
615
+ /**
616
+ * The `ɵɵTYPE` is constructed to allow the `extends` clause on `Child` and `Item` to narrow the
617
+ * type. Another way to think about this is, if we have a function that expects this kind of
618
+ * path, the `ɵɵTYPE` lists the kinds of path we are allowed to pass to it.
619
+ */
620
+ [ɵɵTYPE]: 'root' | 'child' | 'item';
621
+ }
622
+ /**
623
+ * The `PathKind` for a `FieldPath` that is a child of another `FieldPath`.
624
+ */
625
+ interface Child extends PathKind.Root {
626
+ [ɵɵTYPE]: 'child' | 'item';
627
+ }
628
+ /**
629
+ * The `PathKind` for a `FieldPath` that is an item in a `FieldPath` array.
630
+ */
631
+ interface Item extends PathKind.Child {
632
+ [ɵɵTYPE]: 'item';
633
+ }
634
+ }
635
+ /**
636
+ * A status indicating whether a field is unsubmitted, submitted, or currently submitting.
637
+ *
638
+ * @category types
639
+ * @experimental 21.0.0
640
+ */
641
+ type SubmittedStatus = 'unsubmitted' | 'submitted' | 'submitting';
642
+ /**
643
+ * A reason for a field's disablement.
644
+ *
645
+ * @category logic
646
+ * @experimental 21.0.0
647
+ */
648
+ interface DisabledReason {
649
+ /** The field that is disabled. */
650
+ readonly field: FieldTree<unknown>;
651
+ /** A user-facing message describing the reason for the disablement. */
652
+ readonly message?: string;
653
+ }
654
+ /**
655
+ * The absence of an error which indicates a successful validation result.
656
+ *
657
+ * @category types
658
+ * @experimental 21.0.0
659
+ */
660
+ type ValidationSuccess = null | undefined | void;
661
+ /**
662
+ * The result of running a tree validation function.
663
+ *
664
+ * The result may be one of the following:
665
+ * 1. A {@link ValidationSuccess} to indicate no errors.
666
+ * 2. A {@link ValidationError} without a field to indicate an error on the field being validated.
667
+ * 3. A {@link ValidationError} with a field to indicate an error on the target field.
668
+ * 4. A list of {@link ValidationError} with or without fields to indicate multiple errors.
669
+ *
670
+ * @template E the type of error (defaults to {@link ValidationError}).
671
+ *
672
+ * @category types
673
+ * @experimental 21.0.0
674
+ */
675
+ type TreeValidationResult<E extends ValidationError.WithOptionalField = ValidationError.WithOptionalField> = ValidationSuccess | OneOrMany<E>;
676
+ /**
677
+ * A validation result where all errors explicitly define their target field.
678
+ *
679
+ * The result may be one of the following:
680
+ * 1. A {@link ValidationSuccess} to indicate no errors.
681
+ * 2. A {@link ValidationError} with a field to indicate an error on the target field.
682
+ * 3. A list of {@link ValidationError} with fields to indicate multiple errors.
683
+ *
684
+ * @template E the type of error (defaults to {@link ValidationError}).
685
+ *
686
+ * @category types
687
+ * @experimental 21.0.0
688
+ */
689
+ type ValidationResult<E extends ValidationError = ValidationError> = ValidationSuccess | OneOrMany<E>;
690
+ /**
691
+ * An asynchronous validation result where all errors explicitly define their target field.
692
+ *
693
+ * The result may be one of the following:
694
+ * 1. A {@link ValidationResult} to indicate the result if resolved.
695
+ * 5. 'pending' if the validation is not yet resolved.
696
+ *
697
+ * @template E the type of error (defaults to {@link ValidationError}).
698
+ *
699
+ * @category types
700
+ * @experimental 21.0.0
701
+ */
702
+ type AsyncValidationResult<E extends ValidationError = ValidationError> = ValidationResult<E> | 'pending';
703
+ /**
704
+ * An object that represents a tree of fields in a form. This includes both primitive value fields
705
+ * (e.g. fields that contain a `string` or `number`), as well as "grouping fields" that contain
706
+ * sub-fields. `FieldTree` objects are arranged in a tree whose structure mimics the structure of the
707
+ * underlying data. For example a `FieldTree<{x: number}>` has a property `x` which contains a
708
+ * `FieldTree<number>`. To access the state associated with a field, call it as a function.
709
+ *
710
+ * @template TValue The type of the data which the field is wrapped around.
711
+ * @template TKey The type of the property key which this field resides under in its parent.
712
+ *
713
+ * @category types
714
+ * @experimental 21.0.0
715
+ */
716
+ type FieldTree<TModel, TKey extends string | number = string | number> = (() => [TModel] extends [AbstractControl] ? CompatFieldState<TModel, TKey> : FieldState<TModel, TKey>) & ([TModel] extends [AbstractControl] ? object : [TModel] extends [Array<infer U>] ? ReadonlyArrayLike<MaybeFieldTree<U, number>> : TModel extends Record<string, any> ? Subfields<TModel> : object);
717
+ /**
718
+ * The sub-fields that a user can navigate to from a `FieldTree<TModel>`.
719
+ *
720
+ * @template TModel The type of the data which the parent field is wrapped around.
721
+ *
722
+ * @experimental 21.0.0
723
+ */
724
+ type Subfields<TModel> = {
725
+ readonly [K in keyof TModel as TModel[K] extends Function ? never : K]: MaybeFieldTree<TModel[K], string>;
726
+ } & {
727
+ [Symbol.iterator](): Iterator<[string, MaybeFieldTree<TModel[keyof TModel], string>]>;
728
+ };
729
+ /**
730
+ * An iterable object with the same shape as a readonly array.
731
+ *
732
+ * @template T The array item type.
733
+ *
734
+ * @experimental 21.0.0
735
+ */
736
+ type ReadonlyArrayLike<T> = Pick<ReadonlyArray<T>, number | 'length' | typeof Symbol.iterator>;
737
+ /**
738
+ * Helper type for defining `FieldTree`. Given a type `TValue` that may include `undefined`, it extracts
739
+ * the `undefined` outside the `FieldTree` type.
740
+ *
741
+ * For example `MaybeField<{a: number} | undefined, TKey>` would be equivalent to
742
+ * `undefined | FieldTree<{a: number}, TKey>`.
743
+ *
744
+ * @template TModel The type of the data which the field is wrapped around.
745
+ * @template TKey The type of the property key which this field resides under in its parent.
746
+ *
747
+ * @experimental 21.0.0
748
+ */
749
+ type MaybeFieldTree<TModel, TKey extends string | number = string | number> = (TModel & undefined) | FieldTree<Exclude<TModel, undefined>, TKey>;
750
+ /**
751
+ * Contains all of the state (e.g. value, statuses, etc.) associated with a `FieldTree`, exposed as
752
+ * signals.
753
+ *
754
+ * @category structure
755
+ * @experimental 21.0.0
756
+ */
757
+ interface FieldState<TValue, TKey extends string | number = string | number> extends _FieldState<TValue> {
758
+ /**
759
+ * A signal indicating whether field value has been changed by user.
760
+ */
761
+ readonly dirty: Signal<boolean>;
762
+ /**
763
+ * A signal indicating whether a field is hidden.
764
+ *
765
+ * When a field is hidden it is ignored when determining the valid, touched, and dirty states.
766
+ *
767
+ * Note: This doesn't hide the field in the template, that must be done manually.
768
+ * ```
769
+ * @if (!field.hidden()) {
770
+ * ...
771
+ * }
772
+ * ```
773
+ */
774
+ readonly hidden: Signal<boolean>;
775
+ readonly disabledReasons: Signal<readonly DisabledReason[]>;
776
+ readonly errors: Signal<ValidationError.WithField[]>;
777
+ /**
778
+ * A signal containing the {@link errors} of the field and its descendants.
779
+ */
780
+ readonly errorSummary: Signal<ValidationError.WithField[]>;
781
+ /**
782
+ * A signal indicating whether the field's value is currently valid.
783
+ *
784
+ * Note: `valid()` is not the same as `!invalid()`.
785
+ * - `valid()` is `true` when there are no validation errors *and* no pending validators.
786
+ * - `invalid()` is `true` when there are validation errors, regardless of pending validators.
787
+ *
788
+ * Ex: consider the situation where a field has 3 validators, 2 of which have no errors and 1 of
789
+ * which is still pending. In this case `valid()` is `false` because of the pending validator.
790
+ * However `invalid()` is also `false` because there are no errors.
791
+ */
792
+ readonly valid: Signal<boolean>;
793
+ /**
794
+ * A signal indicating whether the field's value is currently invalid.
795
+ *
796
+ * Note: `invalid()` is not the same as `!valid()`.
797
+ * - `invalid()` is `true` when there are validation errors, regardless of pending validators.
798
+ * - `valid()` is `true` when there are no validation errors *and* no pending validators.
799
+ *
800
+ * Ex: consider the situation where a field has 3 validators, 2 of which have no errors and 1 of
801
+ * which is still pending. In this case `invalid()` is `false` because there are no errors.
802
+ * However `valid()` is also `false` because of the pending validator.
803
+ */
804
+ readonly invalid: Signal<boolean>;
805
+ /**
806
+ * Whether there are any validators still pending for this field.
807
+ */
808
+ readonly pending: Signal<boolean>;
809
+ /**
810
+ * A signal indicating whether the field is currently in the process of being submitted.
811
+ */
812
+ readonly submitting: Signal<boolean>;
813
+ /**
814
+ * The property key in the parent field under which this field is stored. If the parent field is
815
+ * array-valued, for example, this is the index of this field in that array.
816
+ */
817
+ readonly keyInParent: Signal<TKey>;
818
+ /**
819
+ * The {@link Field} directives that bind this field to a UI control.
820
+ */
821
+ readonly fieldBindings: Signal<readonly Field<unknown>[]>;
822
+ /**
823
+ * Reads an aggregate metadata value from the field.
824
+ * @param key The metadata key to read.
825
+ */
826
+ metadata<M>(key: AggregateMetadataKey<M, any>): Signal<M>;
827
+ /**
828
+ * Reads a metadata value from the field.
829
+ * @param key The metadata key to read.
830
+ */
831
+ metadata<M>(key: MetadataKey<M>): M | undefined;
832
+ /**
833
+ * Checks whether the given metadata key has been defined for this field.
834
+ */
835
+ hasMetadata(key: MetadataKey<any> | AggregateMetadataKey<any, any>): boolean;
836
+ /**
837
+ * Resets the {@link touched} and {@link dirty} state of the field and its descendants.
838
+ *
839
+ * Note this does not change the data model, which can be reset directly if desired.
840
+ */
841
+ reset(): void;
842
+ }
843
+ /**
844
+ * This is FieldState also providing access to the wrapped FormControl.
845
+ *
846
+ * @category interop
847
+ * @experimental 21.0.0
848
+ */
849
+ type CompatFieldState<TControl extends AbstractControl, TKey extends string | number = string | number> = FieldState<TControl extends AbstractControl<unknown, infer TValue> ? TValue : never, TKey> & {
850
+ control: Signal<TControl>;
851
+ };
852
+ /**
853
+ * Allows declaring whether the Rules are supported for a given path.
854
+ *
855
+ * @experimental 21.0.0
856
+ **/
857
+ type SchemaPathRules = SchemaPathRules.Supported | SchemaPathRules.Unsupported;
858
+ declare namespace SchemaPathRules {
859
+ /**
860
+ * Used for paths that support settings rules.
861
+ */
862
+ type Supported = 1;
863
+ /**
864
+ * Used for paths that do not support settings rules, e.g., compatPath.
865
+ */
866
+ type Unsupported = 2;
867
+ }
868
+ /**
869
+ * An object that represents a location in the `FieldTree` tree structure and is used to bind logic to a
870
+ * particular part of the structure prior to the creation of the form. Because the `FieldPath`
871
+ * exists prior to the form's creation, it cannot be used to access any of the field state.
872
+ *
873
+ * @template TValue The type of the data which the form is wrapped around.
874
+ * @template TPathKind The kind of path (root field, child field, or item of an array)
875
+ *
876
+ * @category types
877
+ * @experimental 21.0.0
878
+ */
879
+ type SchemaPath<TValue, TSupportsRules extends SchemaPathRules = SchemaPathRules.Supported, TPathKind extends PathKind = PathKind.Root> = {
880
+ [ɵɵTYPE]: {
881
+ value: () => TValue;
882
+ supportsRules: TSupportsRules;
883
+ pathKind: TPathKind;
884
+ };
885
+ };
886
+ /**
887
+ * Schema path used if the value is an AbstractControl.
888
+ *
889
+ * @category interop
890
+ * @experimental 21.0.0
891
+ */
892
+ type CompatSchemaPath<TControl extends AbstractControl, TPathKind extends PathKind = PathKind.Root> = SchemaPath<TControl extends AbstractControl<unknown, infer TValue> ? TValue : never, SchemaPathRules.Unsupported, TPathKind> & {
893
+ [ɵɵTYPE]: {
894
+ control: TControl;
895
+ };
896
+ };
897
+ /**
898
+ * Nested schema path.
899
+ *
900
+ * It mirrors the structure of a given data structure, and allows applying rules to the appropriate
901
+ * fields.
902
+ *
903
+ * @experimental 21.0.0
904
+ */
905
+ type SchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = ([TModel] extends [AbstractControl] ? CompatSchemaPath<TModel, TPathKind> : SchemaPath<TModel, SchemaPathRules.Supported, TPathKind>) & (TModel extends AbstractControl ? unknown : TModel extends Array<any> ? unknown : TModel extends Record<string, any> ? {
906
+ [K in keyof TModel]: MaybeSchemaPathTree<TModel[K], PathKind.Child>;
907
+ } : unknown);
908
+ /**
909
+ * Helper type for defining `FieldPath`. Given a type `TValue` that may include `undefined`, it
910
+ * extracts the `undefined` outside the `FieldPath` type.
911
+ *
912
+ * For example `MaybeFieldPath<{a: number} | undefined, PathKind.Child>` would be equivalent to
913
+ * `undefined | FieldTree<{a: number}, PathKind.child>`.
914
+ *
915
+ * @template TValue The type of the data which the field is wrapped around.
916
+ * @template TPathKind The kind of path (root field, child field, or item of an array)
917
+ *
918
+ * @experimental 21.0.0
919
+ */
920
+ type MaybeSchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = (TModel & undefined) | SchemaPathTree<Exclude<TModel, undefined>, TPathKind>;
921
+ /**
922
+ * Defines logic for a form.
923
+ *
924
+ * @template TValue The type of data stored in the form that this schema is attached to.
925
+ *
926
+ * @category types
927
+ * @experimental 21.0.0
928
+ */
929
+ type Schema<in TModel> = {
930
+ [ɵɵTYPE]: SchemaFn<TModel, PathKind.Root>;
931
+ };
932
+ /**
933
+ * Function that defines rules for a schema.
934
+ *
935
+ * @template TModel The type of data stored in the form that this schema function is attached to.
936
+ * @template TPathKind The kind of path this schema function can be bound to.
937
+ *
938
+ * @category types
939
+ * @experimental 21.0.0
940
+ */
941
+ type SchemaFn<TModel, TPathKind extends PathKind = PathKind.Root> = (p: SchemaPathTree<TModel, TPathKind>) => void;
942
+ /**
943
+ * A schema or schema definition function.
944
+ *
945
+ * @template TModel The type of data stored in the form that this schema function is attached to.
946
+ * @template TPathKind The kind of path this schema function can be bound to.
947
+ *
948
+ * @category types
949
+ * @experimental 21.0.0
950
+ */
951
+ type SchemaOrSchemaFn<TModel, TPathKind extends PathKind = PathKind.Root> = Schema<TModel> | SchemaFn<TModel, TPathKind>;
952
+ /**
953
+ * A function that receives the `FieldContext` for the field the logic is bound to and returns
954
+ * a specific result type.
955
+ *
956
+ * @template TValue The data type for the field the logic is bound to.
957
+ * @template TReturn The type of the result returned by the logic function.
958
+ * @template TPathKind The kind of path the logic is applied to (root field, child field, or item of an array)
959
+ *
960
+ * @category types
961
+ * @experimental 21.0.0
962
+ */
963
+ type LogicFn<TValue, TReturn, TPathKind extends PathKind = PathKind.Root> = (ctx: FieldContext<TValue, TPathKind>) => TReturn;
964
+ /**
965
+ * A function that takes the `FieldContext` for the field being validated and returns a
966
+ * `ValidationResult` indicating errors for the field.
967
+ *
968
+ * @template TValue The type of value stored in the field being validated
969
+ * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
970
+ *
971
+ * @category validation
972
+ * @experimental 21.0.0
973
+ */
974
+ type FieldValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, ValidationResult<ValidationError.WithoutField>, TPathKind>;
975
+ /**
976
+ * A function that takes the `FieldContext` for the field being validated and returns a
977
+ * `TreeValidationResult` indicating errors for the field and its sub-fields.
978
+ *
979
+ * @template TValue The type of value stored in the field being validated
980
+ * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
981
+ *
982
+ * @category types
983
+ * @experimental 21.0.0
984
+ */
985
+ type TreeValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, TreeValidationResult, TPathKind>;
986
+ /**
987
+ * A function that takes the `FieldContext` for the field being validated and returns a
988
+ * `ValidationResult` indicating errors for the field and its sub-fields. In a `Validator` all
989
+ * errors must explicitly define their target field.
990
+ *
991
+ * @template TValue The type of value stored in the field being validated
992
+ * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
993
+ *
994
+ * @category types
995
+ * @experimental 21.0.0
996
+ */
997
+ type Validator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn<TValue, ValidationResult, TPathKind>;
998
+ /**
999
+ * Provides access to the state of the current field as well as functions that can be used to look
1000
+ * up state of other fields based on a `FieldPath`.
1001
+ *
1002
+ * @category types
1003
+ * @experimental 21.0.0
1004
+ */
1005
+ type FieldContext<TValue, TPathKind extends PathKind = PathKind.Root> = TPathKind extends PathKind.Item ? ItemFieldContext<TValue> : TPathKind extends PathKind.Child ? ChildFieldContext<TValue> : RootFieldContext<TValue>;
1006
+ /**
1007
+ * The base field context that is available for all fields.
1008
+ *
1009
+ * @experimental 21.0.0
1010
+ */
1011
+ interface RootFieldContext<TValue> {
1012
+ /** A signal containing the value of the current field. */
1013
+ readonly value: Signal<TValue>;
1014
+ /** The state of the current field. */
1015
+ readonly state: FieldState<TValue>;
1016
+ /** The current field. */
1017
+ readonly field: FieldTree<TValue>;
1018
+ /** Gets the value of the field represented by the given path. */
1019
+ valueOf<PValue>(p: SchemaPath<PValue, SchemaPathRules>): PValue;
1020
+ /** Gets the state of the field represented by the given path. */
1021
+ stateOf<PControl extends AbstractControl>(p: CompatSchemaPath<PControl>): CompatFieldState<PControl>;
1022
+ stateOf<PValue>(p: SchemaPath<PValue, SchemaPathRules>): FieldState<PValue>;
1023
+ /** Gets the field represented by the given path. */
1024
+ fieldTreeOf<PModel>(p: SchemaPathTree<PModel>): FieldTree<PModel>;
1025
+ /** The list of keys that lead from the root field to the current field. */
1026
+ readonly pathKeys: Signal<readonly string[]>;
1027
+ }
1028
+ /**
1029
+ * Field context that is available for all fields that are a child of another field.
1030
+ *
1031
+ * @category structure
1032
+ * @experimental 21.0.0
1033
+ */
1034
+ interface ChildFieldContext<TValue> extends RootFieldContext<TValue> {
1035
+ /** The key of the current field in its parent field. */
1036
+ readonly key: Signal<string>;
1037
+ }
1038
+ /**
1039
+ * Field context that is available for all fields that are an item in an array field.
1040
+ *
1041
+ * @experimental 21.0.0
1042
+ */
1043
+ interface ItemFieldContext<TValue> extends ChildFieldContext<TValue> {
1044
+ /** The index of the current field in its parent field. */
1045
+ readonly index: Signal<number>;
1046
+ }
1047
+ /**
1048
+ * Gets the item type of an object that is possibly an array.
1049
+ *
1050
+ * @experimental 21.0.0
1051
+ */
1052
+ type ItemType<T extends Object> = T extends ReadonlyArray<any> ? T[number] : T[keyof T];
1053
+ /**
1054
+ * A function that defines custom debounce logic for a field.
1055
+ *
1056
+ * @param context The field context.
1057
+ * @param abortSignal An `AbortSignal` used to communicate that the debounced operation was aborted.
1058
+ * @returns A `Promise<void>` to debounce an update, or `void` to apply an update immediately.
1059
+ * @template TValue The type of value stored in the field.
1060
+ * @template TPathKind The kind of path the debouncer is applied to (root field, child field, or item of an array).
1061
+ *
1062
+ * @experimental 21.0.0
1063
+ */
1064
+ type Debouncer<TValue, TPathKind extends PathKind = PathKind.Root> = (context: FieldContext<TValue, TPathKind>, abortSignal: AbortSignal) => Promise<void> | void;
1065
+
1066
+ /** Represents a result that should be ignored because its predicate indicates it is not active. */
1067
+ declare const IGNORED: unique symbol;
1068
+ /**
1069
+ * A predicate that indicates whether an `AbstractLogic` instance is currently active, or should be
1070
+ * ignored.
1071
+ */
1072
+ interface Predicate {
1073
+ /** A boolean logic function that returns true if the logic is considered active. */
1074
+ readonly fn: LogicFn<any, boolean>;
1075
+ /**
1076
+ * The path which this predicate was created for. This is used to determine the correct
1077
+ * `FieldContext` to pass to the predicate function.
1078
+ */
1079
+ readonly path: SchemaPath<any>;
1080
+ }
1081
+ /**
1082
+ * Represents a predicate that is bound to a particular depth in the field tree. This is needed for
1083
+ * recursively applied logic to ensure that the predicate is evaluated against the correct
1084
+ * application of that logic.
1085
+ *
1086
+ * Consider the following example:
1087
+ *
1088
+ * ```
1089
+ * const s = schema(p => {
1090
+ * disabled(p.data);
1091
+ * applyWhen(p.next, ({valueOf}) => valueOf(p.data) === 1, s);
1092
+ * });
1093
+ *
1094
+ * const f = form(signal({data: 0, next: {data: 1, next: {data: 2, next: undefined}}}), s);
1095
+ *
1096
+ * const isDisabled = f.next.next.data().disabled();
1097
+ * ```
1098
+ *
1099
+ * In order to determine `isDisabled` we need to evaluate the predicate from `applyWhen` *twice*.
1100
+ * Once to see if the schema should be applied to `f.next` and again to see if it should be applied
1101
+ * to `f.next.next`. The `depth` tells us which field we should be evaluating against each time.
1102
+ */
1103
+ interface BoundPredicate extends Predicate {
1104
+ /** The depth in the field tree at which this predicate is bound. */
1105
+ readonly depth: number;
1106
+ }
1107
+ /**
1108
+ * Base class for all logic. It is responsible for combining the results from multiple individual
1109
+ * logic functions registered in the schema, and using them to derive the value for some associated
1110
+ * piece of field state.
1111
+ */
1112
+ declare abstract class AbstractLogic<TReturn, TValue = TReturn> {
1113
+ /**
1114
+ * A list of predicates that conditionally enable all logic in this logic instance.
1115
+ * The logic is only enabled when *all* of the predicates evaluate to true.
1116
+ */
1117
+ private predicates;
1118
+ /** The set of logic functions that contribute to the value of the associated state. */
1119
+ protected readonly fns: Array<LogicFn<any, TValue | typeof IGNORED>>;
1120
+ constructor(
1121
+ /**
1122
+ * A list of predicates that conditionally enable all logic in this logic instance.
1123
+ * The logic is only enabled when *all* of the predicates evaluate to true.
1124
+ */
1125
+ predicates: ReadonlyArray<BoundPredicate>);
1126
+ /**
1127
+ * Computes the value of the associated field state based on the logic functions and predicates
1128
+ * registered with this logic instance.
1129
+ */
1130
+ abstract compute(arg: FieldContext<any>): TReturn;
1131
+ /**
1132
+ * The default value that the associated field state should assume if there are no logic functions
1133
+ * registered by the schema (or if the logic is disabled by a predicate).
1134
+ */
1135
+ abstract get defaultValue(): TReturn;
1136
+ /** Registers a logic function with this logic instance. */
1137
+ push(logicFn: LogicFn<any, TValue>): void;
1138
+ /**
1139
+ * Merges in the logic from another logic instance, subject to the predicates of both the other
1140
+ * instance and this instance.
1141
+ */
1142
+ mergeIn(other: AbstractLogic<TReturn, TValue>): void;
1143
+ }
1144
+ /** Logic that combines its individual logic function results with logical OR. */
1145
+ declare class BooleanOrLogic extends AbstractLogic<boolean> {
1146
+ get defaultValue(): boolean;
1147
+ compute(arg: FieldContext<any>): boolean;
1148
+ }
1149
+ /**
1150
+ * Logic that combines its individual logic function results by aggregating them in an array.
1151
+ * Depending on its `ignore` function it may ignore certain values, omitting them from the array.
1152
+ */
1153
+ declare class ArrayMergeIgnoreLogic<TElement, TIgnore = never> extends AbstractLogic<readonly TElement[], TElement | readonly (TElement | TIgnore)[] | TIgnore | undefined | void> {
1154
+ private ignore;
1155
+ /** Creates an instance of this class that ignores `null` values. */
1156
+ static ignoreNull<TElement>(predicates: ReadonlyArray<BoundPredicate>): ArrayMergeIgnoreLogic<TElement, null>;
1157
+ constructor(predicates: ReadonlyArray<BoundPredicate>, ignore: undefined | ((e: TElement | undefined | TIgnore) => e is TIgnore));
1158
+ get defaultValue(): never[];
1159
+ compute(arg: FieldContext<any>): readonly TElement[];
1160
+ }
1161
+ /** Logic that combines its individual logic function results by aggregating them in an array. */
1162
+ declare class ArrayMergeLogic<TElement> extends ArrayMergeIgnoreLogic<TElement, never> {
1163
+ constructor(predicates: ReadonlyArray<BoundPredicate>);
1164
+ }
1165
+ /**
1166
+ * Container for all the different types of logic that can be applied to a field
1167
+ * (disabled, hidden, errors, etc.)
1168
+ */
1169
+ declare class LogicContainer {
1170
+ private predicates;
1171
+ /** Logic that determines if the field is hidden. */
1172
+ readonly hidden: BooleanOrLogic;
1173
+ /** Logic that determines reasons for the field being disabled. */
1174
+ readonly disabledReasons: ArrayMergeLogic<DisabledReason>;
1175
+ /** Logic that determines if the field is read-only. */
1176
+ readonly readonly: BooleanOrLogic;
1177
+ /** Logic that produces synchronous validation errors for the field. */
1178
+ readonly syncErrors: ArrayMergeIgnoreLogic<ValidationError.WithField, null>;
1179
+ /** Logic that produces synchronous validation errors for the field's subtree. */
1180
+ readonly syncTreeErrors: ArrayMergeIgnoreLogic<ValidationError.WithField, null>;
1181
+ /** Logic that produces asynchronous validation results (errors or 'pending'). */
1182
+ readonly asyncErrors: ArrayMergeIgnoreLogic<ValidationError.WithField | 'pending', null>;
1183
+ /** A map of aggregate metadata keys to the `AbstractLogic` instances that compute their values. */
1184
+ private readonly aggregateMetadataKeys;
1185
+ /** A map of metadata keys to the factory functions that create their values. */
1186
+ private readonly metadataFactories;
1187
+ /**
1188
+ * Constructs a new `Logic` container.
1189
+ * @param predicates An array of predicates that must all be true for the logic
1190
+ * functions within this container to be active.
1191
+ */
1192
+ constructor(predicates: ReadonlyArray<BoundPredicate>);
1193
+ /** Checks whether there is logic for the given aggregate metadata key. */
1194
+ hasAggregateMetadata(key: AggregateMetadataKey<any, any>): boolean;
1195
+ /**
1196
+ * Gets an iterable of [aggregate metadata, logic function] pairs.
1197
+ * @returns An iterable of aggregate metadata entries.
1198
+ */
1199
+ getAggregateMetadataEntries(): MapIterator<[AggregateMetadataKey<unknown, unknown>, AbstractLogic<unknown, unknown>]>;
1200
+ /**
1201
+ * Gets an iterable of [metadata, value factory function] pairs.
1202
+ * @returns An iterable of metadata factory entries.
1203
+ */
1204
+ getMetadataFactoryEntries(): MapIterator<[MetadataKey<unknown>, (ctx: FieldContext<unknown>) => unknown]>;
1205
+ /**
1206
+ * Retrieves or creates the `AbstractLogic` for a given aggregate metadata key.
1207
+ * @param key The `AggregateMetadataKey` for which to get the logic.
1208
+ * @returns The `AbstractLogic` associated with the key.
1209
+ */
1210
+ getAggregateMetadata<T>(key: AggregateMetadataKey<any, T>): AbstractLogic<T>;
1211
+ /**
1212
+ * Adds a factory function for a given metadata key.
1213
+ * @param key The `MetadataKey` to associate the factory with.
1214
+ * @param factory The factory function.
1215
+ * @throws If a factory is already defined for the given key.
1216
+ */
1217
+ addMetadataFactory(key: MetadataKey<unknown>, factory: (ctx: FieldContext<unknown>) => unknown): void;
1218
+ /**
1219
+ * Merges logic from another `Logic` instance into this one.
1220
+ * @param other The `Logic` instance to merge from.
1221
+ */
1222
+ mergeIn(other: LogicContainer): void;
1223
+ }
1224
+
1225
+ /**
1226
+ * Abstract base class for building a `LogicNode`.
1227
+ * This class defines the interface for adding various logic rules (e.g., hidden, disabled)
1228
+ * and data factories to a node in the logic tree.
1229
+ * LogicNodeBuilders are 1:1 with nodes in the Schema tree.
1230
+ */
1231
+ declare abstract class AbstractLogicNodeBuilder {
1232
+ /** The depth of this node in the schema tree. */
1233
+ protected readonly depth: number;
1234
+ constructor(
1235
+ /** The depth of this node in the schema tree. */
1236
+ depth: number);
1237
+ /** Adds a rule to determine if a field should be hidden. */
1238
+ abstract addHiddenRule(logic: LogicFn<any, boolean>): void;
1239
+ /** Adds a rule to determine if a field should be disabled, and for what reason. */
1240
+ abstract addDisabledReasonRule(logic: LogicFn<any, DisabledReason | undefined>): void;
1241
+ /** Adds a rule to determine if a field should be read-only. */
1242
+ abstract addReadonlyRule(logic: LogicFn<any, boolean>): void;
1243
+ /** Adds a rule for synchronous validation errors for a field. */
1244
+ abstract addSyncErrorRule(logic: LogicFn<any, ValidationResult>): void;
1245
+ /** Adds a rule for synchronous validation errors that apply to a subtree. */
1246
+ abstract addSyncTreeErrorRule(logic: LogicFn<any, ValidationResult>): void;
1247
+ /** Adds a rule for asynchronous validation errors for a field. */
1248
+ abstract addAsyncErrorRule(logic: LogicFn<any, AsyncValidationResult>): void;
1249
+ /** Adds a rule to compute aggregate metadata for a field. */
1250
+ abstract addAggregateMetadataRule<M>(key: AggregateMetadataKey<unknown, M>, logic: LogicFn<any, M>): void;
1251
+ /** Adds a factory function to produce a data value associated with a field. */
1252
+ abstract addMetadataFactory<D>(key: MetadataKey<D>, factory: (ctx: FieldContext<any>) => D): void;
1253
+ /**
1254
+ * Gets a builder for a child node associated with the given property key.
1255
+ * @param key The property key of the child.
1256
+ * @returns A `LogicNodeBuilder` for the child.
1257
+ */
1258
+ abstract getChild(key: PropertyKey): LogicNodeBuilder;
1259
+ /**
1260
+ * Checks whether a particular `AbstractLogicNodeBuilder` has been merged into this one.
1261
+ * @param builder The builder to check for.
1262
+ * @returns True if the builder has been merged, false otherwise.
1263
+ */
1264
+ abstract hasLogic(builder: AbstractLogicNodeBuilder): boolean;
1265
+ /**
1266
+ * Builds the `LogicNode` from the accumulated rules and child builders.
1267
+ * @returns The constructed `LogicNode`.
1268
+ */
1269
+ build(): LogicNode;
1270
+ }
1271
+ /**
1272
+ * A builder for `LogicNode`. Used to add logic to the final `LogicNode` tree.
1273
+ * This builder supports merging multiple sources of logic, potentially with predicates,
1274
+ * preserving the order of rule application.
1275
+ */
1276
+ declare class LogicNodeBuilder extends AbstractLogicNodeBuilder {
1277
+ constructor(depth: number);
1278
+ /**
1279
+ * The current `NonMergeableLogicNodeBuilder` being used to add rules directly to this
1280
+ * `LogicNodeBuilder`. Do not use this directly, call `getCurrent()` which will create a current
1281
+ * builder if there is none.
1282
+ */
1283
+ private current;
1284
+ /**
1285
+ * Stores all builders that contribute to this node, along with any predicates
1286
+ * that gate their application.
1287
+ */
1288
+ readonly all: {
1289
+ builder: AbstractLogicNodeBuilder;
1290
+ predicate?: Predicate;
1291
+ }[];
1292
+ addHiddenRule(logic: LogicFn<any, boolean>): void;
1293
+ addDisabledReasonRule(logic: LogicFn<any, DisabledReason | undefined>): void;
1294
+ addReadonlyRule(logic: LogicFn<any, boolean>): void;
1295
+ addSyncErrorRule(logic: LogicFn<any, ValidationResult<ValidationError.WithField>>): void;
1296
+ addSyncTreeErrorRule(logic: LogicFn<any, ValidationResult<ValidationError.WithField>>): void;
1297
+ addAsyncErrorRule(logic: LogicFn<any, AsyncValidationResult<ValidationError.WithField>>): void;
1298
+ addAggregateMetadataRule<T>(key: AggregateMetadataKey<any, T>, logic: LogicFn<any, T>): void;
1299
+ addMetadataFactory<D>(key: MetadataKey<D>, factory: (ctx: FieldContext<any>) => D): void;
1300
+ getChild(key: PropertyKey): LogicNodeBuilder;
1301
+ hasLogic(builder: AbstractLogicNodeBuilder): boolean;
1302
+ /**
1303
+ * Merges logic from another `LogicNodeBuilder` into this one.
1304
+ * If a `predicate` is provided, all logic from the `other` builder will only apply
1305
+ * when the predicate evaluates to true.
1306
+ * @param other The `LogicNodeBuilder` to merge in.
1307
+ * @param predicate An optional predicate to gate the merged logic.
1308
+ */
1309
+ mergeIn(other: LogicNodeBuilder, predicate?: Predicate): void;
1310
+ /**
1311
+ * Gets the current `NonMergeableLogicNodeBuilder` for adding rules directly to this
1312
+ * `LogicNodeBuilder`. If no current builder exists, a new one is created.
1313
+ * The current builder is cleared whenever `mergeIn` is called to preserve the order
1314
+ * of rules when merging separate builder trees.
1315
+ * @returns The current `NonMergeableLogicNodeBuilder`.
1316
+ */
1317
+ private getCurrent;
1318
+ /**
1319
+ * Creates a new root `LogicNodeBuilder`.
1320
+ * @returns A new instance of `LogicNodeBuilder`.
1321
+ */
1322
+ static newRoot(): LogicNodeBuilder;
1323
+ }
1324
+ /**
1325
+ * Represents a node in the logic tree, containing all logic applicable
1326
+ * to a specific field or path in the form structure.
1327
+ * LogicNodes are 1:1 with nodes in the Field tree.
1328
+ */
1329
+ interface LogicNode {
1330
+ /** The collection of logic rules (hidden, disabled, errors, etc.) for this node. */
1331
+ readonly logic: LogicContainer;
1332
+ /**
1333
+ * Retrieves the `LogicNode` for a child identified by the given property key.
1334
+ * @param key The property key of the child.
1335
+ * @returns The `LogicNode` for the specified child.
1336
+ */
1337
+ getChild(key: PropertyKey): LogicNode;
1338
+ /**
1339
+ * Checks whether the logic from a particular `AbstractLogicNodeBuilder` has been merged into this
1340
+ * node.
1341
+ * @param builder The builder to check for.
1342
+ * @returns True if the builder has been merged, false otherwise.
1343
+ */
1344
+ hasLogic(builder: AbstractLogicNodeBuilder): boolean;
1345
+ }
1346
+
1347
+ /**
1348
+ * Implements the `Schema` concept.
1349
+ */
1350
+ declare class SchemaImpl {
1351
+ private schemaFn;
1352
+ constructor(schemaFn: SchemaFn<unknown>);
1353
+ /**
1354
+ * Compiles this schema within the current root compilation context. If the schema was previously
1355
+ * compiled within this context, we reuse the cached FieldPathNode, otherwise we create a new one
1356
+ * and cache it in the compilation context.
1357
+ */
1358
+ compile(): FieldPathNode;
1359
+ /**
1360
+ * Creates a SchemaImpl from the given SchemaOrSchemaFn.
1361
+ */
1362
+ static create(schema: SchemaImpl | SchemaOrSchemaFn<any>): SchemaImpl;
1363
+ /**
1364
+ * Compiles the given schema in a fresh compilation context. This clears the cached results of any
1365
+ * previous compilations.
1366
+ */
1367
+ static rootCompile(schema: SchemaImpl | SchemaOrSchemaFn<any> | undefined): FieldPathNode;
1368
+ }
1369
+
1370
+ /**
1371
+ * A path in the schema on which logic is stored so that it can be added to the corresponding field
1372
+ * when the field is created.
1373
+ */
1374
+ declare class FieldPathNode {
1375
+ /** The property keys used to navigate from the root path to this path. */
1376
+ readonly keys: PropertyKey[];
1377
+ /** The parent of this path node. */
1378
+ private readonly parent;
1379
+ /** The key of this node in its parent. */
1380
+ private readonly keyInParent;
1381
+ /** The root path node from which this path node is descended. */
1382
+ readonly root: FieldPathNode;
1383
+ /**
1384
+ * A map containing all child path nodes that have been created on this path.
1385
+ * Child path nodes are created automatically on first access if they do not exist already.
1386
+ */
1387
+ private readonly children;
1388
+ /**
1389
+ * A proxy that wraps the path node, allowing navigation to its child paths via property access.
1390
+ */
1391
+ readonly fieldPathProxy: SchemaPath<any>;
1392
+ /**
1393
+ * For a root path node this will contain the root logic builder. For non-root nodes,
1394
+ * they determine their logic builder from their parent so this is undefined.
1395
+ */
1396
+ private readonly logicBuilder;
1397
+ protected constructor(
1398
+ /** The property keys used to navigate from the root path to this path. */
1399
+ keys: PropertyKey[], root: FieldPathNode | undefined,
1400
+ /** The parent of this path node. */
1401
+ parent: FieldPathNode | undefined,
1402
+ /** The key of this node in its parent. */
1403
+ keyInParent: PropertyKey | undefined);
1404
+ /** The logic builder used to accumulate logic on this path node. */
1405
+ get builder(): LogicNodeBuilder;
1406
+ /**
1407
+ * Gets the path node for the given child property key.
1408
+ * Child paths are created automatically on first access if they do not exist already.
1409
+ */
1410
+ getChild(key: PropertyKey): FieldPathNode;
1411
+ /**
1412
+ * Merges in logic from another schema to this one.
1413
+ * @param other The other schema to merge in the logic from
1414
+ * @param predicate A predicate indicating when the merged in logic should be active.
1415
+ */
1416
+ mergeIn(other: SchemaImpl, predicate?: Predicate): void;
1417
+ /** Extracts the underlying path node from the given path proxy. */
1418
+ static unwrapFieldPath(formPath: SchemaPath<unknown, SchemaPathRules>): FieldPathNode;
1419
+ /** Creates a new root path node to be passed in to a schema function. */
1420
+ static newRoot(): FieldPathNode;
1421
+ }
1422
+
1423
+ /**
1424
+ * Tracks custom metadata associated with a `FieldNode`.
1425
+ */
1426
+ declare class FieldMetadataState {
1427
+ private readonly node;
1428
+ /** A map of all `MetadataKey` and `AggregateMetadataKey` that have been defined for this field. */
1429
+ private readonly metadata;
1430
+ constructor(node: FieldNode);
1431
+ /** Gets the value of a `MetadataKey` or `AggregateMetadataKey` for the field. */
1432
+ get<T>(key: MetadataKey<T> | AggregateMetadataKey<T, unknown>): T | undefined | Signal<T>;
1433
+ /** Checks whether the current metadata state has the given metadata key. */
1434
+ has(key: MetadataKey<any> | AggregateMetadataKey<any, any>): boolean;
1435
+ }
1436
+
1437
+ /**
1438
+ * The non-validation and non-submit state associated with a `FieldNode`, such as touched and dirty
1439
+ * status, as well as derived logical state.
1440
+ */
1441
+ declare class FieldNodeState {
1442
+ private readonly node;
1443
+ /**
1444
+ * Indicates whether this field has been touched directly by the user (as opposed to indirectly by
1445
+ * touching a child field).
1446
+ *
1447
+ * A field is considered directly touched when a user stops editing it for the first time (i.e. on blur)
1448
+ */
1449
+ private readonly selfTouched;
1450
+ /**
1451
+ * Indicates whether this field has been dirtied directly by the user (as opposed to indirectly by
1452
+ * dirtying a child field).
1453
+ *
1454
+ * A field is considered directly dirtied if a user changed the value of the field at least once.
1455
+ */
1456
+ private readonly selfDirty;
1457
+ /**
1458
+ * Marks this specific field as touched.
1459
+ */
1460
+ markAsTouched(): void;
1461
+ /**
1462
+ * Marks this specific field as dirty.
1463
+ */
1464
+ markAsDirty(): void;
1465
+ /**
1466
+ * Marks this specific field as not dirty.
1467
+ */
1468
+ markAsPristine(): void;
1469
+ /**
1470
+ * Marks this specific field as not touched.
1471
+ */
1472
+ markAsUntouched(): void;
1473
+ /** The {@link Field} directives that bind this field to a UI control. */
1474
+ readonly fieldBindings: i0.WritableSignal<readonly Field<unknown>[]>;
1475
+ constructor(node: FieldNode);
1476
+ /**
1477
+ * Whether this field is considered dirty.
1478
+ *
1479
+ * A field is considered dirty if one of the following is true:
1480
+ * - It was directly dirtied and is interactive
1481
+ * - One of its children is considered dirty
1482
+ */
1483
+ readonly dirty: Signal<boolean>;
1484
+ /**
1485
+ * Whether this field is considered touched.
1486
+ *
1487
+ * A field is considered touched if one of the following is true:
1488
+ * - It was directly touched and is interactive
1489
+ * - One of its children is considered touched
1490
+ */
1491
+ readonly touched: Signal<boolean>;
1492
+ /**
1493
+ * The reasons for this field's disablement. This includes disabled reasons for any parent field
1494
+ * that may have been disabled, indirectly causing this field to be disabled as well.
1495
+ * The `field` property of the `DisabledReason` can be used to determine which field ultimately
1496
+ * caused the disablement.
1497
+ */
1498
+ readonly disabledReasons: Signal<readonly DisabledReason[]>;
1499
+ /**
1500
+ * Whether this field is considered disabled.
1501
+ *
1502
+ * A field is considered disabled if one of the following is true:
1503
+ * - The schema contains logic that directly disabled it
1504
+ * - Its parent field is considered disabled
1505
+ */
1506
+ readonly disabled: Signal<boolean>;
1507
+ /**
1508
+ * Whether this field is considered readonly.
1509
+ *
1510
+ * A field is considered readonly if one of the following is true:
1511
+ * - The schema contains logic that directly made it readonly
1512
+ * - Its parent field is considered readonly
1513
+ */
1514
+ readonly readonly: Signal<boolean>;
1515
+ /**
1516
+ * Whether this field is considered hidden.
1517
+ *
1518
+ * A field is considered hidden if one of the following is true:
1519
+ * - The schema contains logic that directly hides it
1520
+ * - Its parent field is considered hidden
1521
+ */
1522
+ readonly hidden: Signal<boolean>;
1523
+ readonly name: Signal<string>;
1524
+ /**
1525
+ * An optional {@link Debouncer} factory for this field.
1526
+ */
1527
+ readonly debouncer: Signal<((signal: AbortSignal) => Promise<void> | void) | undefined>;
1528
+ /** Whether this field is considered non-interactive.
1529
+ *
1530
+ * A field is considered non-interactive if one of the following is true:
1531
+ * - It is hidden
1532
+ * - It is disabled
1533
+ * - It is readonly
1534
+ */
1535
+ private readonly isNonInteractive;
1536
+ }
1537
+
1538
+ /**
1539
+ * State of a `FieldNode` that's associated with form submission.
1540
+ */
1541
+ declare class FieldSubmitState {
1542
+ private readonly node;
1543
+ /**
1544
+ * Whether this field was directly submitted (as opposed to indirectly by a parent field being submitted)
1545
+ * and is still in the process of submitting.
1546
+ */
1547
+ readonly selfSubmitting: WritableSignal<boolean>;
1548
+ /** Server errors that are associated with this field. */
1549
+ readonly serverErrors: WritableSignal<readonly ValidationError.WithField[]>;
1550
+ constructor(node: FieldNode);
1551
+ /**
1552
+ * Whether this form is currently in the process of being submitted.
1553
+ * Either because the field was submitted directly, or because a parent field was submitted.
1554
+ */
1555
+ readonly submitting: Signal<boolean>;
1556
+ }
1557
+
1558
+ interface ValidationState {
1559
+ /**
1560
+ * The full set of synchronous tree errors visible to this field. This includes ones that are
1561
+ * targeted at a descendant field rather than at this field.
1562
+ */
1563
+ rawSyncTreeErrors: Signal<ValidationError.WithField[]>;
1564
+ /**
1565
+ * The full set of synchronous errors for this field, including synchronous tree errors and server
1566
+ * errors. Server errors are considered "synchronous" because they are imperatively added. From
1567
+ * the perspective of the field state they are either there or not, they are never in a pending
1568
+ * state.
1569
+ */
1570
+ syncErrors: Signal<ValidationError.WithField[]>;
1571
+ /**
1572
+ * Whether the field is considered valid according solely to its synchronous validators.
1573
+ * Errors resulting from a previous submit attempt are also considered for this state.
1574
+ */
1575
+ syncValid: Signal<boolean>;
1576
+ /**
1577
+ * The full set of asynchronous tree errors visible to this field. This includes ones that are
1578
+ * targeted at a descendant field rather than at this field, as well as sentinel 'pending' values
1579
+ * indicating that the validator is still running and an error could still occur.
1580
+ */
1581
+ rawAsyncErrors: Signal<(ValidationError.WithField | 'pending')[]>;
1582
+ /**
1583
+ * The asynchronous tree errors visible to this field that are specifically targeted at this field
1584
+ * rather than a descendant. This also includes all 'pending' sentinel values, since those could
1585
+ * theoretically result in errors for this field.
1586
+ */
1587
+ asyncErrors: Signal<(ValidationError.WithField | 'pending')[]>;
1588
+ /**
1589
+ * The combined set of all errors that currently apply to this field.
1590
+ */
1591
+ errors: Signal<ValidationError.WithField[]>;
1592
+ /**
1593
+ * The combined set of all errors that currently apply to this field and its descendants.
1594
+ */
1595
+ errorSummary: Signal<ValidationError.WithField[]>;
1596
+ /**
1597
+ * Whether this field has any asynchronous validators still pending.
1598
+ */
1599
+ pending: Signal<boolean>;
1600
+ /**
1601
+ * The validation status of the field.
1602
+ * - The status is 'valid' if neither the field nor any of its children has any errors or pending
1603
+ * validators.
1604
+ * - The status is 'invalid' if the field or any of its children has an error
1605
+ * (regardless of pending validators)
1606
+ * - The status is 'unknown' if neither the field nor any of its children has any errors,
1607
+ * but the field or any of its children does have a pending validator.
1608
+ *
1609
+ * A field is considered valid if *all* of the following are true:
1610
+ * - It has no errors or pending validators
1611
+ * - All of its children are considered valid
1612
+ * A field is considered invalid if *any* of the following are true:
1613
+ * - It has an error
1614
+ * - Any of its children is considered invalid
1615
+ * A field is considered to have unknown validity status if it is not valid or invalid.
1616
+ */
1617
+ status: Signal<'valid' | 'invalid' | 'unknown'>;
1618
+ /**
1619
+ * Whether the field is considered valid.
1620
+ *
1621
+ * A field is considered valid if *all* of the following are true:
1622
+ * - It has no errors or pending validators
1623
+ * - All of its children are considered valid
1624
+ *
1625
+ * Note: `!valid()` is *not* the same as `invalid()`. Both `valid()` and `invalid()` can be false
1626
+ * if there are currently no errors, but validators are still pending.
1627
+ */
1628
+ valid: Signal<boolean>;
1629
+ /**
1630
+ * Whether the field is considered invalid.
1631
+ *
1632
+ * A field is considered invalid if *any* of the following are true:
1633
+ * - It has an error
1634
+ * - Any of its children is considered invalid
1635
+ *
1636
+ * Note: `!invalid()` is *not* the same as `valid()`. Both `valid()` and `invalid()` can be false
1637
+ * if there are currently no errors, but validators are still pending.
1638
+ */
1639
+ invalid: Signal<boolean>;
1640
+ /**
1641
+ * Indicates whether validation should be skipped for this field because it is hidden, disabled,
1642
+ * or readonly.
1643
+ */
1644
+ shouldSkipValidation: Signal<boolean>;
1645
+ }
1646
+
1647
+ /**
1648
+ * Internal node in the form tree for a given field.
1649
+ *
1650
+ * Field nodes have several responsibilities:
1651
+ * - They track instance state for the particular field (touched)
1652
+ * - They compute signals for derived state (valid, disabled, etc) based on their associated
1653
+ * `LogicNode`
1654
+ * - They act as the public API for the field (they implement the `FieldState` interface)
1655
+ * - They implement navigation of the form tree via `.parent` and `.getChild()`.
1656
+ *
1657
+ * This class is largely a wrapper that aggregates several smaller pieces that each manage a subset of
1658
+ * the responsibilities.
1659
+ */
1660
+ declare class FieldNode implements FieldState<unknown> {
1661
+ readonly structure: FieldNodeStructure;
1662
+ readonly validationState: ValidationState;
1663
+ readonly metadataState: FieldMetadataState;
1664
+ readonly nodeState: FieldNodeState;
1665
+ readonly submitState: FieldSubmitState;
1666
+ readonly fieldAdapter: FieldAdapter;
1667
+ private _context;
1668
+ get context(): FieldContext<unknown>;
1669
+ /**
1670
+ * Proxy to this node which allows navigation of the form graph below it.
1671
+ */
1672
+ readonly fieldProxy: FieldTree<any>;
1673
+ constructor(options: FieldNodeOptions);
1674
+ /**
1675
+ * The `AbortController` for the currently debounced sync, or `undefined` if there is none.
1676
+ *
1677
+ * This is used to cancel a pending debounced sync when {@link setControlValue} is called again
1678
+ * before the pending debounced sync resolves. It will also cancel any pending debounced sync
1679
+ * automatically when recomputed due to `value` being set directly from others sources.
1680
+ */
1681
+ private readonly pendingSync;
1682
+ get logicNode(): LogicNode;
1683
+ get value(): WritableSignal<unknown>;
1684
+ private _controlValue;
1685
+ get controlValue(): Signal<unknown>;
1686
+ get keyInParent(): Signal<string | number>;
1687
+ get errors(): Signal<ValidationError.WithField[]>;
1688
+ get errorSummary(): Signal<ValidationError.WithField[]>;
1689
+ get pending(): Signal<boolean>;
1690
+ get valid(): Signal<boolean>;
1691
+ get invalid(): Signal<boolean>;
1692
+ get dirty(): Signal<boolean>;
1693
+ get touched(): Signal<boolean>;
1694
+ get disabled(): Signal<boolean>;
1695
+ get disabledReasons(): Signal<readonly DisabledReason[]>;
1696
+ get hidden(): Signal<boolean>;
1697
+ get readonly(): Signal<boolean>;
1698
+ get fieldBindings(): Signal<readonly Field<unknown>[]>;
1699
+ get submitting(): Signal<boolean>;
1700
+ get name(): Signal<string>;
1701
+ private metadataOrUndefined;
1702
+ get max(): Signal<number | undefined> | undefined;
1703
+ get maxLength(): Signal<number | undefined> | undefined;
1704
+ get min(): Signal<number | undefined> | undefined;
1705
+ get minLength(): Signal<number | undefined> | undefined;
1706
+ get pattern(): Signal<readonly RegExp[]>;
1707
+ get required(): Signal<boolean>;
1708
+ metadata<M>(key: AggregateMetadataKey<M, any>): Signal<M>;
1709
+ metadata<M>(key: MetadataKey<M>): M | undefined;
1710
+ hasMetadata(key: MetadataKey<any> | AggregateMetadataKey<any, any>): boolean;
1711
+ /**
1712
+ * Marks this specific field as touched.
1713
+ */
1714
+ markAsTouched(): void;
1715
+ /**
1716
+ * Marks this specific field as dirty.
1717
+ */
1718
+ markAsDirty(): void;
1719
+ /**
1720
+ * Resets the {@link touched} and {@link dirty} state of the field and its descendants.
1721
+ *
1722
+ * Note this does not change the data model, which can be reset directly if desired.
1723
+ */
1724
+ reset(): void;
1725
+ /**
1726
+ * Sets the control value of the field. This value may be debounced before it is synchronized with
1727
+ * the field's {@link value} signal, depending on the debounce configuration.
1728
+ */
1729
+ setControlValue(newValue: unknown): void;
1730
+ /**
1731
+ * Synchronizes the {@link controlValue} with the {@link value} signal immediately.
1732
+ */
1733
+ private sync;
1734
+ /**
1735
+ * Initiates a debounced {@link sync}.
1736
+ *
1737
+ * If a debouncer is configured, the synchronization will occur after the debouncer resolves. If
1738
+ * no debouncer is configured, the synchronization happens immediately. If {@link setControlValue}
1739
+ * is called again while a debounce is pending, the previous debounce operation is aborted in
1740
+ * favor of the new one.
1741
+ */
1742
+ private debounceSync;
1743
+ /**
1744
+ * Creates a new root field node for a new form.
1745
+ */
1746
+ static newRoot<T>(fieldManager: FormFieldManager, value: WritableSignal<T>, pathNode: FieldPathNode, adapter: FieldAdapter): FieldNode;
1747
+ /**
1748
+ * Creates a child field node based on the given options.
1749
+ */
1750
+ private static newChild;
1751
+ createStructure(options: FieldNodeOptions): RootFieldNodeStructure | ChildFieldNodeStructure;
1752
+ }
1753
+ /**
1754
+ * Field node of a field that has children.
1755
+ * This simplifies and makes certain types cleaner.
1756
+ */
1757
+ interface ParentFieldNode extends FieldNode {
1758
+ readonly value: WritableSignal<Record<string, unknown>>;
1759
+ readonly structure: FieldNodeStructure & {
1760
+ value: WritableSignal<Record<string, unknown>>;
1761
+ };
1762
+ }
1763
+
1764
+ /**
1765
+ * Key by which a parent `FieldNode` tracks its children.
1766
+ *
1767
+ * Often this is the actual property key of the child, but in the case of arrays it could be a
1768
+ * tracking key allocated for the object.
1769
+ */
1770
+ type TrackingKey = PropertyKey & {
1771
+ __brand: 'FieldIdentity';
1772
+ };
1773
+ /** Structural component of a `FieldNode` which tracks its path, parent, and children. */
1774
+ declare abstract class FieldNodeStructure {
1775
+ /** The logic to apply to this field. */
1776
+ readonly logic: LogicNode;
1777
+ /** Computed map of child fields, based on the current value of this field. */
1778
+ abstract readonly childrenMap: Signal<Map<TrackingKey, FieldNode> | undefined>;
1779
+ /** The field's value. */
1780
+ abstract readonly value: WritableSignal<unknown>;
1781
+ /**
1782
+ * The key of this field in its parent field.
1783
+ * Attempting to read this for the root field will result in an error being thrown.
1784
+ */
1785
+ abstract readonly keyInParent: Signal<string>;
1786
+ /** The field manager responsible for managing this field. */
1787
+ abstract readonly fieldManager: FormFieldManager;
1788
+ /** The root field that this field descends from. */
1789
+ abstract readonly root: FieldNode;
1790
+ /** The list of property keys to follow to get from the `root` to this field. */
1791
+ abstract readonly pathKeys: Signal<readonly string[]>;
1792
+ /** The parent field of this field. */
1793
+ abstract readonly parent: FieldNode | undefined;
1794
+ /** Added to array elements for tracking purposes. */
1795
+ readonly identitySymbol: symbol;
1796
+ /** Lazily initialized injector. Do not access directly, access via `injector` getter instead. */
1797
+ private _injector;
1798
+ /** Lazily initialized injector. */
1799
+ get injector(): DestroyableInjector;
1800
+ constructor(
1801
+ /** The logic to apply to this field. */
1802
+ logic: LogicNode);
1803
+ /** Gets the child fields of this field. */
1804
+ children(): Iterable<FieldNode>;
1805
+ /** Retrieve a child `FieldNode` of this node by property key. */
1806
+ getChild(key: PropertyKey): FieldNode | undefined;
1807
+ /** Destroys the field when it is no longer needed. */
1808
+ destroy(): void;
1809
+ }
1810
+ /** The structural component of a `FieldNode` that is the root of its field tree. */
1811
+ declare class RootFieldNodeStructure extends FieldNodeStructure {
1812
+ /** The full field node that corresponds to this structure. */
1813
+ private readonly node;
1814
+ readonly fieldManager: FormFieldManager;
1815
+ readonly value: WritableSignal<unknown>;
1816
+ get parent(): undefined;
1817
+ get root(): FieldNode;
1818
+ get pathKeys(): Signal<readonly string[]>;
1819
+ get keyInParent(): Signal<string>;
1820
+ readonly childrenMap: Signal<Map<TrackingKey, FieldNode> | undefined>;
1821
+ /**
1822
+ * Creates the structure for the root node of a field tree.
1823
+ *
1824
+ * @param node The full field node that this structure belongs to
1825
+ * @param pathNode The path corresponding to this node in the schema
1826
+ * @param logic The logic to apply to this field
1827
+ * @param fieldManager The field manager for this field
1828
+ * @param value The value signal for this field
1829
+ * @param adapter Adapter that knows how to create new fields and appropriate state.
1830
+ * @param createChildNode A factory function to create child nodes for this field.
1831
+ */
1832
+ constructor(
1833
+ /** The full field node that corresponds to this structure. */
1834
+ node: FieldNode, pathNode: FieldPathNode, logic: LogicNode, fieldManager: FormFieldManager, value: WritableSignal<unknown>, adapter: FieldAdapter, createChildNode: (options: ChildFieldNodeOptions) => FieldNode);
1835
+ }
1836
+ /** The structural component of a child `FieldNode` within a field tree. */
1837
+ declare class ChildFieldNodeStructure extends FieldNodeStructure {
1838
+ readonly parent: ParentFieldNode;
1839
+ readonly root: FieldNode;
1840
+ readonly pathKeys: Signal<readonly string[]>;
1841
+ readonly keyInParent: Signal<string>;
1842
+ readonly value: WritableSignal<unknown>;
1843
+ readonly childrenMap: Signal<Map<TrackingKey, FieldNode> | undefined>;
1844
+ get fieldManager(): FormFieldManager;
1845
+ /**
1846
+ * Creates the structure for a child field node in a field tree.
1847
+ *
1848
+ * @param node The full field node that this structure belongs to
1849
+ * @param pathNode The path corresponding to this node in the schema
1850
+ * @param logic The logic to apply to this field
1851
+ * @param parent The parent field node for this node
1852
+ * @param identityInParent The identity used to track this field in its parent
1853
+ * @param initialKeyInParent The key of this field in its parent at the time of creation
1854
+ * @param adapter Adapter that knows how to create new fields and appropriate state.
1855
+ * @param createChildNode A factory function to create child nodes for this field.
1856
+ */
1857
+ constructor(node: FieldNode, pathNode: FieldPathNode, logic: LogicNode, parent: ParentFieldNode, identityInParent: TrackingKey | undefined, initialKeyInParent: string, adapter: FieldAdapter, createChildNode: (options: ChildFieldNodeOptions) => FieldNode);
1858
+ }
1859
+ /** Options passed when constructing a root field node. */
1860
+ interface RootFieldNodeOptions {
1861
+ /** Kind of node, used to differentiate root node options from child node options. */
1862
+ readonly kind: 'root';
1863
+ /** The path node corresponding to this field in the schema. */
1864
+ readonly pathNode: FieldPathNode;
1865
+ /** The logic to apply to this field. */
1866
+ readonly logic: LogicNode;
1867
+ /** The value signal for this field. */
1868
+ readonly value: WritableSignal<unknown>;
1869
+ /** The field manager for this field. */
1870
+ readonly fieldManager: FormFieldManager;
1871
+ /** This allows for more granular field and state management, and is currently used for compat. */
1872
+ readonly fieldAdapter: FieldAdapter;
1873
+ }
1874
+ /** Options passed when constructing a child field node. */
1875
+ interface ChildFieldNodeOptions {
1876
+ /** Kind of node, used to differentiate root node options from child node options. */
1877
+ readonly kind: 'child';
1878
+ /** The parent field node of this field. */
1879
+ readonly parent: ParentFieldNode;
1880
+ /** The path node corresponding to this field in the schema. */
1881
+ readonly pathNode: FieldPathNode;
1882
+ /** The logic to apply to this field. */
1883
+ readonly logic: LogicNode;
1884
+ /** The key of this field in its parent at the time of creation. */
1885
+ readonly initialKeyInParent: string;
1886
+ /** The identity used to track this field in its parent. */
1887
+ readonly identityInParent: TrackingKey | undefined;
1888
+ /** This allows for more granular field and state management, and is currently used for compat. */
1889
+ readonly fieldAdapter: FieldAdapter;
1890
+ }
1891
+ /** Options passed when constructing a field node. */
1892
+ type FieldNodeOptions = RootFieldNodeOptions | ChildFieldNodeOptions;
1893
+
1894
+ /**
1895
+ * Manages the collection of fields associated with a given `form`.
1896
+ *
1897
+ * Fields are created implicitly, through reactivity, and may create "owned" entities like effects
1898
+ * or resources. When a field is no longer connected to the form, these owned entities should be
1899
+ * destroyed, which is the job of the `FormFieldManager`.
1900
+ */
1901
+ declare class FormFieldManager {
1902
+ readonly injector: Injector;
1903
+ readonly rootName: string;
1904
+ constructor(injector: Injector, rootName: string | undefined);
1905
+ /**
1906
+ * Contains all child field structures that have been created as part of the current form.
1907
+ * New child structures are automatically added when they are created.
1908
+ * Structures are destroyed and removed when they are no longer reachable from the root.
1909
+ */
1910
+ readonly structures: Set<FieldNodeStructure>;
1911
+ /**
1912
+ * Creates an effect that runs when the form's structure changes and checks for structures that
1913
+ * have become unreachable to clean up.
1914
+ *
1915
+ * For example, consider a form wrapped around the following model: `signal([0, 1, 2])`.
1916
+ * This form would have 4 nodes as part of its structure tree.
1917
+ * One structure for the root array, and one structure for each element of the array.
1918
+ * Now imagine the data is updated: `model.set([0])`. In this case the structure for the first
1919
+ * element can still be reached from the root, but the structures for the second and third
1920
+ * elements are now orphaned and not connected to the root. Thus they will be destroyed.
1921
+ *
1922
+ * @param root The root field structure.
1923
+ */
1924
+ createFieldManagementEffect(root: FieldNodeStructure): void;
1925
+ /**
1926
+ * Collects all structures reachable from the given structure into the given set.
1927
+ *
1928
+ * @param structure The root structure
1929
+ * @param liveStructures The set of reachable structures to populate
1930
+ */
1931
+ private markStructuresLive;
1932
+ }
1933
+
1934
+ /**
1935
+ * Adapter allowing customization of the creation logic for a field and its associated
1936
+ * structure and state.
1937
+ */
1938
+ interface FieldAdapter {
1939
+ /**
1940
+ * Creates a node structure.
1941
+ * @param node
1942
+ * @param options
1943
+ */
1944
+ createStructure(node: FieldNode, options: FieldNodeOptions): FieldNodeStructure;
1945
+ /**
1946
+ * Creates node validation state
1947
+ * @param param
1948
+ * @param options
1949
+ */
1950
+ createValidationState(param: FieldNode, options: FieldNodeOptions): ValidationState;
1951
+ /**
1952
+ * Creates node state.
1953
+ * @param param
1954
+ * @param options
1955
+ */
1956
+ createNodeState(param: FieldNode, options: FieldNodeOptions): FieldNodeState;
1957
+ /**
1958
+ * Creates a custom child node.
1959
+ * @param options
1960
+ */
1961
+ newChild(options: ChildFieldNodeOptions): FieldNode;
1962
+ /**
1963
+ * Creates a custom root node.
1964
+ * @param fieldManager
1965
+ * @param model
1966
+ * @param pathNode
1967
+ * @param adapter
1968
+ */
1969
+ newRoot<TValue>(fieldManager: FormFieldManager, model: WritableSignal<TValue>, pathNode: FieldPathNode, adapter: FieldAdapter): FieldNode;
1970
+ }
1971
+
1972
+ /**
1973
+ * Options that may be specified when creating a form.
1974
+ *
1975
+ * @category structure
1976
+ * @experimental 21.0.0
1977
+ */
1978
+ interface FormOptions {
1979
+ /**
1980
+ * The injector to use for dependency injection. If this is not provided, the injector for the
1981
+ * current [injection context](guide/di/dependency-injection-context), will be used.
1982
+ */
1983
+ injector?: Injector;
1984
+ name?: string;
1985
+ /**
1986
+ * Adapter allows managing fields in a more flexible way.
1987
+ * Currently this is used to support interop with reactive forms.
1988
+ */
1989
+ adapter?: FieldAdapter;
1990
+ }
1991
+ /**
1992
+ * Creates a form wrapped around the given model data. A form is represented as simply a `FieldTree`
1993
+ * of the model data.
1994
+ *
1995
+ * `form` uses the given model as the source of truth and *does not* maintain its own copy of the
1996
+ * data. This means that updating the value on a `FieldState` updates the originally passed in model
1997
+ * as well.
1998
+ *
1999
+ * @example
2000
+ * ```
2001
+ * const nameModel = signal({first: '', last: ''});
2002
+ * const nameForm = form(nameModel);
2003
+ * nameForm.first().value.set('John');
2004
+ * nameForm().value(); // {first: 'John', last: ''}
2005
+ * nameModel(); // {first: 'John', last: ''}
2006
+ * ```
2007
+ *
2008
+ * @param model A writable signal that contains the model data for the form. The resulting field
2009
+ * structure will match the shape of the model and any changes to the form data will be written to
2010
+ * the model.
2011
+ * @return A `FieldTree` representing a form around the data model.
2012
+ * @template TModel The type of the data model.
2013
+ *
2014
+ * @category structure
2015
+ * @experimental 21.0.0
2016
+ */
2017
+ declare function form<TModel>(model: WritableSignal<TModel>): FieldTree<TModel>;
2018
+ /**
2019
+ * Creates a form wrapped around the given model data. A form is represented as simply a `FieldTree`
2020
+ * of the model data.
2021
+ *
2022
+ * `form` uses the given model as the source of truth and *does not* maintain its own copy of the
2023
+ * data. This means that updating the value on a `FieldState` updates the originally passed in model
2024
+ * as well.
2025
+ *
2026
+ * @example
2027
+ * ```
2028
+ * const nameModel = signal({first: '', last: ''});
2029
+ * const nameForm = form(nameModel);
2030
+ * nameForm.first().value.set('John');
2031
+ * nameForm().value(); // {first: 'John', last: ''}
2032
+ * nameModel(); // {first: 'John', last: ''}
2033
+ * ```
2034
+ *
2035
+ * The form can also be created with a schema, which is a set of rules that define the logic for the
2036
+ * form. The schema can be either a pre-defined schema created with the `schema` function, or a
2037
+ * function that builds the schema by binding logic to a parts of the field structure.
2038
+ *
2039
+ * @example
2040
+ * ```
2041
+ * const nameForm = form(signal({first: '', last: ''}), (name) => {
2042
+ * required(name.first);
2043
+ * pattern(name.last, /^[a-z]+$/i, {message: 'Alphabet characters only'});
2044
+ * });
2045
+ * nameForm().valid(); // false
2046
+ * nameForm().value.set({first: 'John', last: 'Doe'});
2047
+ * nameForm().valid(); // true
2048
+ * ```
2049
+ *
2050
+ * @param model A writable signal that contains the model data for the form. The resulting field
2051
+ * structure will match the shape of the model and any changes to the form data will be written to
2052
+ * the model.
2053
+ * @param schemaOrOptions The second argument can be either
2054
+ * 1. A schema or a function used to specify logic for the form (e.g. validation, disabled fields, etc.).
2055
+ * When passing a schema, the form options can be passed as a third argument if needed.
2056
+ * 2. The form options
2057
+ * @return A `FieldTree` representing a form around the data model
2058
+ * @template TValue The type of the data model.
2059
+ *
2060
+ * @category structure
2061
+ * @experimental 21.0.0
2062
+ */
2063
+ declare function form<TModel>(model: WritableSignal<TModel>, schemaOrOptions: SchemaOrSchemaFn<TModel> | FormOptions): FieldTree<TModel>;
2064
+ /**
2065
+ * Creates a form wrapped around the given model data. A form is represented as simply a `FieldTree`
2066
+ * of the model data.
2067
+ *
2068
+ * `form` uses the given model as the source of truth and *does not* maintain its own copy of the
2069
+ * data. This means that updating the value on a `FieldState` updates the originally passed in model
2070
+ * as well.
2071
+ *
2072
+ * @example
2073
+ * ```
2074
+ * const nameModel = signal({first: '', last: ''});
2075
+ * const nameForm = form(nameModel);
2076
+ * nameForm.first().value.set('John');
2077
+ * nameForm().value(); // {first: 'John', last: ''}
2078
+ * nameModel(); // {first: 'John', last: ''}
2079
+ * ```
2080
+ *
2081
+ * The form can also be created with a schema, which is a set of rules that define the logic for the
2082
+ * form. The schema can be either a pre-defined schema created with the `schema` function, or a
2083
+ * function that builds the schema by binding logic to a parts of the field structure.
2084
+ *
2085
+ * @example
2086
+ * ```
2087
+ * const nameForm = form(signal({first: '', last: ''}), (name) => {
2088
+ * required(name.first);
2089
+ * validate(name.last, ({value}) => !/^[a-z]+$/i.test(value()) ? customError({kind: 'alphabet-only'}) : undefined);
2090
+ * });
2091
+ * nameForm().valid(); // false
2092
+ * nameForm().value.set({first: 'John', last: 'Doe'});
2093
+ * nameForm().valid(); // true
2094
+ * ```
2095
+ *
2096
+ * @param model A writable signal that contains the model data for the form. The resulting field
2097
+ * structure will match the shape of the model and any changes to the form data will be written to
2098
+ * the model.
2099
+ * @param schema A schema or a function used to specify logic for the form (e.g. validation, disabled fields, etc.)
2100
+ * @param options The form options
2101
+ * @return A `FieldTree` representing a form around the data model.
2102
+ * @template TModel The type of the data model.
2103
+ *
2104
+ * @category structure
2105
+ * @experimental 21.0.0
2106
+ */
2107
+ declare function form<TModel>(model: WritableSignal<TModel>, schema: SchemaOrSchemaFn<TModel>, options: FormOptions): FieldTree<TModel>;
2108
+ /**
2109
+ * Applies a schema to each item of an array.
2110
+ *
2111
+ * @example
2112
+ * ```
2113
+ * const nameSchema = schema<{first: string, last: string}>((name) => {
2114
+ * required(name.first);
2115
+ * required(name.last);
2116
+ * });
2117
+ * const namesForm = form(signal([{first: '', last: ''}]), (names) => {
2118
+ * applyEach(names, nameSchema);
2119
+ * });
2120
+ * ```
2121
+ *
2122
+ * @param path The target path for an array field whose items the schema will be applied to.
2123
+ * @param schema A schema for an element of the array, or function that binds logic to an
2124
+ * element of the array.
2125
+ * @template TValue The data type of the item field to apply the schema to.
2126
+ *
2127
+ * @category structure
2128
+ * @experimental 21.0.0
2129
+ */
2130
+ declare function applyEach<TValue extends ReadonlyArray<any>>(path: SchemaPath<TValue>, schema: NoInfer<SchemaOrSchemaFn<TValue[number], PathKind.Item>>): void;
2131
+ declare function applyEach<TValue extends Object>(path: SchemaPath<TValue>, schema: NoInfer<SchemaOrSchemaFn<ItemType<TValue>, PathKind.Child>>): void;
2132
+ /**
2133
+ * Applies a predefined schema to a given `FieldPath`.
2134
+ *
2135
+ * @example
2136
+ * ```
2137
+ * const nameSchema = schema<{first: string, last: string}>((name) => {
2138
+ * required(name.first);
2139
+ * required(name.last);
2140
+ * });
2141
+ * const profileForm = form(signal({name: {first: '', last: ''}, age: 0}), (profile) => {
2142
+ * apply(profile.name, nameSchema);
2143
+ * });
2144
+ * ```
2145
+ *
2146
+ * @param path The target path to apply the schema to.
2147
+ * @param schema The schema to apply to the property
2148
+ * @template TValue The data type of the field to apply the schema to.
2149
+ *
2150
+ * @category structure
2151
+ * @experimental 21.0.0
2152
+ */
2153
+ declare function apply<TValue>(path: SchemaPath<TValue>, schema: NoInfer<SchemaOrSchemaFn<TValue>>): void;
2154
+ /**
2155
+ * Conditionally applies a predefined schema to a given `FieldPath`.
2156
+ *
2157
+ * @param path The target path to apply the schema to.
2158
+ * @param logic A `LogicFn<T, boolean>` that returns `true` when the schema should be applied.
2159
+ * @param schema The schema to apply to the field when the `logic` function returns `true`.
2160
+ * @template TValue The data type of the field to apply the schema to.
2161
+ *
2162
+ * @category structure
2163
+ * @experimental 21.0.0
2164
+ */
2165
+ declare function applyWhen<TValue>(path: SchemaPath<TValue>, logic: LogicFn<TValue, boolean>, schema: NoInfer<SchemaOrSchemaFn<TValue>>): void;
2166
+ /**
2167
+ * Conditionally applies a predefined schema to a given `FieldPath`.
2168
+ *
2169
+ * @param path The target path to apply the schema to.
2170
+ * @param predicate A type guard that accepts a value `T` and returns `true` if `T` is of type
2171
+ * `TNarrowed`.
2172
+ * @param schema The schema to apply to the field when `predicate` returns `true`.
2173
+ * @template TValue The data type of the field to apply the schema to.
2174
+ * @template TNarrowed The data type of the schema (a narrowed type of TValue).
2175
+ *
2176
+ * @category structure
2177
+ * @experimental 21.0.0
2178
+ */
2179
+ declare function applyWhenValue<TValue, TNarrowed extends TValue>(path: SchemaPath<TValue>, predicate: (value: TValue) => value is TNarrowed, schema: SchemaOrSchemaFn<TNarrowed>): void;
2180
+ /**
2181
+ * Conditionally applies a predefined schema to a given `FieldPath`.
2182
+ *
2183
+ * @param path The target path to apply the schema to.
2184
+ * @param predicate A function that accepts a value `T` and returns `true` when the schema
2185
+ * should be applied.
2186
+ * @param schema The schema to apply to the field when `predicate` returns `true`.
2187
+ * @template TValue The data type of the field to apply the schema to.
2188
+ *
2189
+ * @category structure
2190
+ * @experimental 21.0.0
2191
+ */
2192
+ declare function applyWhenValue<TValue>(path: SchemaPath<TValue>, predicate: (value: TValue) => boolean, schema: NoInfer<SchemaOrSchemaFn<TValue>>): void;
2193
+ /**
2194
+ * Submits a given `FieldTree` using the given action function and applies any server errors
2195
+ * resulting from the action to the field. Server errors returned by the `action` will be integrated
2196
+ * into the field as a `ValidationError` on the sub-field indicated by the `field` property of the
2197
+ * server error.
2198
+ *
2199
+ * @example
2200
+ * ```
2201
+ * async function registerNewUser(registrationForm: FieldTree<{username: string, password: string}>) {
2202
+ * const result = await myClient.registerNewUser(registrationForm().value());
2203
+ * if (result.errorCode === myClient.ErrorCode.USERNAME_TAKEN) {
2204
+ * return [{
2205
+ * field: registrationForm.username,
2206
+ * error: {kind: 'server', message: 'Username already taken'}
2207
+ * }];
2208
+ * }
2209
+ * return undefined;
2210
+ * }
2211
+ *
2212
+ * const registrationForm = form(signal({username: 'god', password: ''}));
2213
+ * submit(registrationForm, async (f) => {
2214
+ * return registerNewUser(registrationForm);
2215
+ * });
2216
+ * registrationForm.username().errors(); // [{kind: 'server', message: 'Username already taken'}]
2217
+ * ```
2218
+ *
2219
+ * @param form The field to submit.
2220
+ * @param action An asynchronous action used to submit the field. The action may return server
2221
+ * errors.
2222
+ * @template TModel The data type of the field being submitted.
2223
+ *
2224
+ * @category submission
2225
+ * @experimental 21.0.0
2226
+ */
2227
+ declare function submit<TModel>(form: FieldTree<TModel>, action: (form: FieldTree<TModel>) => Promise<TreeValidationResult>): Promise<void>;
2228
+ /**
2229
+ * Creates a `Schema` that adds logic rules to a form.
2230
+ * @param fn A **non-reactive** function that sets up reactive logic rules for the form.
2231
+ * @returns A schema object that implements the given logic.
2232
+ * @template TValue The value type of a `FieldTree` that this schema binds to.
2233
+ *
2234
+ * @category structure
2235
+ * @experimental 21.0.0
2236
+ */
2237
+ declare function schema<TValue>(fn: SchemaFn<TValue>): Schema<TValue>;
2238
+
2239
+ export { AggregateMetadataKey, CustomValidationError, EmailValidationError, FIELD, Field, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MetadataKey, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PathKind, PatternValidationError, REQUIRED, RequiredValidationError, SchemaPathRules, StandardSchemaValidationError, ValidationError, andMetadataKey, apply, applyEach, applyWhen, applyWhenValue, createMetadataKey, customError, emailError, form, listMetadataKey, maxError, maxLengthError, maxMetadataKey, minError, minLengthError, minMetadataKey, orMetadataKey, patternError, reducedMetadataKey, requiredError, schema, standardSchemaError, submit };
2240
+ export type { AsyncValidationResult, ChildFieldContext, CompatFieldState, CompatSchemaPath, Debouncer, DisabledReason, FieldContext, FieldState, FieldTree, FieldValidator, FormOptions, ItemFieldContext, ItemType, LogicFn, MaybeFieldTree, MaybeSchemaPathTree, OneOrMany, ReadonlyArrayLike, RootFieldContext, Schema, SchemaFn, SchemaOrSchemaFn, SchemaPath, SchemaPathTree, Subfields, SubmittedStatus, TreeValidationResult, TreeValidator, ValidationResult, ValidationSuccess, Validator, WithField, WithOptionalField, WithoutField };