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

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