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