@angular/forms 21.2.0-next.0 → 21.2.0-next.2

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,13 +1,13 @@
1
1
  /**
2
- * @license Angular v21.2.0-next.0
2
+ * @license Angular v21.2.0-next.2
3
3
  * (c) 2010-2026 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
7
7
  import * as i0 from '@angular/core';
8
- import { InjectionToken, ɵRuntimeError as _RuntimeError, inject, ElementRef, Injector, input, computed, signal, ɵCONTROL as _CONTROL, untracked, effect, Directive, ɵɵcontrolCreate as __controlCreate, ɵcontrolUpdate as _controlUpdate, ɵisPromise as _isPromise, resource } from '@angular/core';
8
+ import { InjectionToken, ɵRuntimeError as _RuntimeError, untracked, input, inject, Renderer2, DestroyRef, computed, Injector, ElementRef, signal, afterRenderEffect, effect, Directive, ɵisPromise as _isPromise, resource } from '@angular/core';
9
9
  import { Validators, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';
10
- import { assertPathIsCurrent, FieldPathNode, addDefaultField, metadata, createMetadataKey, MAX, MAX_LENGTH, MIN, MIN_LENGTH, PATTERN, REQUIRED, createManagedMetadataKey, DEBOUNCER } from './_structure-chunk.mjs';
10
+ import { signalErrorsToValidationErrors, assertPathIsCurrent, FieldPathNode, addDefaultField, metadata, createMetadataKey, MAX, MAX_LENGTH, MIN, MIN_LENGTH, PATTERN, REQUIRED, createManagedMetadataKey, DEBOUNCER } from './_structure-chunk.mjs';
11
11
  export { MetadataKey, MetadataReducer, apply, applyEach, applyWhen, applyWhenValue, form, schema, submit } from './_structure-chunk.mjs';
12
12
  import { httpResource } from '@angular/common/http';
13
13
  import '@angular/core/primitives/signals';
@@ -46,15 +46,7 @@ class InteropNgControl {
46
46
  return !this.field().disabled();
47
47
  }
48
48
  get errors() {
49
- const errors = this.field().errors();
50
- if (errors.length === 0) {
51
- return null;
52
- }
53
- const errObj = {};
54
- for (const error of errors) {
55
- errObj[error.kind] = error;
56
- }
57
- return errObj;
49
+ return signalErrorsToValidationErrors(this.field().errors());
58
50
  }
59
51
  get pristine() {
60
52
  return !this.field().dirty();
@@ -93,44 +85,367 @@ class InteropNgControl {
93
85
  updateValueAndValidity() {}
94
86
  }
95
87
 
96
- const FORM_FIELD = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'FORM_FIELD' : '');
97
- const controlInstructions = {
98
- create: __controlCreate,
99
- update: _controlUpdate
88
+ function isNativeFormElement(element) {
89
+ return element.tagName === 'INPUT' || element.tagName === 'SELECT' || element.tagName === 'TEXTAREA';
90
+ }
91
+ function isNumericFormElement(element) {
92
+ if (element.tagName !== 'INPUT') {
93
+ return false;
94
+ }
95
+ const type = element.type;
96
+ return type === 'date' || type === 'datetime-local' || type === 'month' || type === 'number' || type === 'range' || type === 'time' || type === 'week';
97
+ }
98
+ function isTextualFormElement(element) {
99
+ return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA';
100
+ }
101
+ function getNativeControlValue(element, currentValue) {
102
+ switch (element.type) {
103
+ case 'checkbox':
104
+ return element.checked;
105
+ case 'number':
106
+ case 'range':
107
+ case 'datetime-local':
108
+ if (typeof untracked(currentValue) === 'number') {
109
+ return element.valueAsNumber;
110
+ }
111
+ break;
112
+ case 'date':
113
+ case 'month':
114
+ case 'time':
115
+ case 'week':
116
+ const value = untracked(currentValue);
117
+ if (value === null || value instanceof Date) {
118
+ return element.valueAsDate;
119
+ } else if (typeof value === 'number') {
120
+ return element.valueAsNumber;
121
+ }
122
+ break;
123
+ }
124
+ return element.value;
125
+ }
126
+ function setNativeControlValue(element, value) {
127
+ switch (element.type) {
128
+ case 'checkbox':
129
+ element.checked = value;
130
+ return;
131
+ case 'radio':
132
+ element.checked = value === element.value;
133
+ return;
134
+ case 'number':
135
+ case 'range':
136
+ case 'datetime-local':
137
+ if (typeof value === 'number') {
138
+ setNativeNumberControlValue(element, value);
139
+ return;
140
+ }
141
+ break;
142
+ case 'date':
143
+ case 'month':
144
+ case 'time':
145
+ case 'week':
146
+ if (value === null || value instanceof Date) {
147
+ element.valueAsDate = value;
148
+ return;
149
+ } else if (typeof value === 'number') {
150
+ setNativeNumberControlValue(element, value);
151
+ return;
152
+ }
153
+ }
154
+ element.value = value;
155
+ }
156
+ function setNativeNumberControlValue(element, value) {
157
+ if (isNaN(value)) {
158
+ element.value = '';
159
+ } else {
160
+ element.valueAsNumber = value;
161
+ }
162
+ }
163
+ function setNativeDomProperty(renderer, element, name, value) {
164
+ switch (name) {
165
+ case 'name':
166
+ renderer.setAttribute(element, name, value);
167
+ break;
168
+ case 'disabled':
169
+ case 'readonly':
170
+ case 'required':
171
+ if (value) {
172
+ renderer.setAttribute(element, name, '');
173
+ } else {
174
+ renderer.removeAttribute(element, name);
175
+ }
176
+ break;
177
+ case 'max':
178
+ case 'min':
179
+ case 'minLength':
180
+ case 'maxLength':
181
+ if (value !== undefined) {
182
+ renderer.setAttribute(element, name, value.toString());
183
+ } else {
184
+ renderer.removeAttribute(element, name);
185
+ }
186
+ break;
187
+ }
188
+ }
189
+
190
+ const FIELD_STATE_KEY_TO_CONTROL_BINDING = {
191
+ disabled: 'disabled',
192
+ disabledReasons: 'disabledReasons',
193
+ dirty: 'dirty',
194
+ errors: 'errors',
195
+ hidden: 'hidden',
196
+ invalid: 'invalid',
197
+ max: 'max',
198
+ maxLength: 'maxLength',
199
+ min: 'min',
200
+ minLength: 'minLength',
201
+ name: 'name',
202
+ pattern: 'pattern',
203
+ pending: 'pending',
204
+ readonly: 'readonly',
205
+ required: 'required',
206
+ touched: 'touched'
100
207
  };
208
+ const CONTROL_BINDING_TO_FIELD_STATE_KEY = /* @__PURE__ */(() => {
209
+ const map = {};
210
+ for (const key of Object.keys(FIELD_STATE_KEY_TO_CONTROL_BINDING)) {
211
+ map[FIELD_STATE_KEY_TO_CONTROL_BINDING[key]] = key;
212
+ }
213
+ return map;
214
+ })();
215
+ function readFieldStateBindingValue(fieldState, key) {
216
+ const property = CONTROL_BINDING_TO_FIELD_STATE_KEY[key];
217
+ return fieldState[property]?.();
218
+ }
219
+ const CONTROL_BINDING_NAMES = /* @__PURE__ */(() => Object.values(FIELD_STATE_KEY_TO_CONTROL_BINDING))();
220
+ function createBindings() {
221
+ return {};
222
+ }
223
+ function bindingUpdated(bindings, key, value) {
224
+ if (bindings[key] !== value) {
225
+ bindings[key] = value;
226
+ return true;
227
+ }
228
+ return false;
229
+ }
230
+
231
+ function cvaControlCreate(host, parent) {
232
+ parent.controlValueAccessor.registerOnChange(value => parent.state().controlValue.set(value));
233
+ parent.controlValueAccessor.registerOnTouched(() => parent.state().markAsTouched());
234
+ parent.registerAsBinding();
235
+ const bindings = createBindings();
236
+ return () => {
237
+ const fieldState = parent.state();
238
+ const value = fieldState.value();
239
+ if (bindingUpdated(bindings, 'controlValue', value)) {
240
+ untracked(() => parent.controlValueAccessor.writeValue(value));
241
+ }
242
+ for (const name of CONTROL_BINDING_NAMES) {
243
+ const value = readFieldStateBindingValue(fieldState, name);
244
+ if (bindingUpdated(bindings, name, value)) {
245
+ const propertyWasSet = host.setInputOnDirectives(name, value);
246
+ if (name === 'disabled' && parent.controlValueAccessor.setDisabledState) {
247
+ untracked(() => parent.controlValueAccessor.setDisabledState(value));
248
+ } else if (!propertyWasSet && parent.elementAcceptsNativeProperty(name)) {
249
+ setNativeDomProperty(parent.renderer, parent.nativeFormElement, name, value);
250
+ }
251
+ }
252
+ }
253
+ };
254
+ }
255
+
256
+ function customControlCreate(host, parent) {
257
+ host.listenToCustomControlModel(value => parent.state().controlValue.set(value));
258
+ host.listenToCustomControlOutput('touchedChange', () => parent.state().markAsTouched());
259
+ parent.registerAsBinding(host.customControl);
260
+ const bindings = createBindings();
261
+ return () => {
262
+ const state = parent.state();
263
+ const controlValue = state.controlValue();
264
+ if (bindingUpdated(bindings, 'controlValue', controlValue)) {
265
+ host.setCustomControlModelInput(controlValue);
266
+ }
267
+ for (const name of CONTROL_BINDING_NAMES) {
268
+ let value;
269
+ if (name === 'errors') {
270
+ value = parent.errors();
271
+ } else {
272
+ value = readFieldStateBindingValue(state, name);
273
+ }
274
+ if (bindingUpdated(bindings, name, value)) {
275
+ host.setInputOnDirectives(name, value);
276
+ if (parent.elementAcceptsNativeProperty(name) && !host.customControlHasInput(name)) {
277
+ setNativeDomProperty(parent.renderer, parent.nativeFormElement, name, value);
278
+ }
279
+ }
280
+ }
281
+ };
282
+ }
283
+
284
+ function observeSelectMutations(select, onMutation, destroyRef) {
285
+ if (typeof MutationObserver !== 'function') {
286
+ return;
287
+ }
288
+ const observer = new MutationObserver(mutations => {
289
+ if (mutations.some(m => isRelevantSelectMutation(m))) {
290
+ onMutation();
291
+ }
292
+ });
293
+ observer.observe(select, {
294
+ attributes: true,
295
+ attributeFilter: ['value'],
296
+ characterData: true,
297
+ childList: true,
298
+ subtree: true
299
+ });
300
+ destroyRef.onDestroy(() => observer.disconnect());
301
+ }
302
+ function isRelevantSelectMutation(mutation) {
303
+ if (mutation.type === 'childList' || mutation.type === 'characterData') {
304
+ if (mutation.target instanceof Comment) {
305
+ return false;
306
+ }
307
+ for (const node of mutation.addedNodes) {
308
+ if (!(node instanceof Comment)) {
309
+ return true;
310
+ }
311
+ }
312
+ for (const node of mutation.removedNodes) {
313
+ if (!(node instanceof Comment)) {
314
+ return true;
315
+ }
316
+ }
317
+ return false;
318
+ }
319
+ if (mutation.type === 'attributes' && mutation.target instanceof HTMLOptionElement) {
320
+ return true;
321
+ }
322
+ return false;
323
+ }
324
+
325
+ function nativeControlCreate(host, parent) {
326
+ let updateMode = false;
327
+ const input = parent.nativeFormElement;
328
+ host.listenToDom('input', () => {
329
+ const state = parent.state();
330
+ state.controlValue.set(getNativeControlValue(input, state.value));
331
+ });
332
+ host.listenToDom('blur', () => parent.state().markAsTouched());
333
+ parent.registerAsBinding();
334
+ if (input.tagName === 'SELECT') {
335
+ observeSelectMutations(input, () => {
336
+ if (!updateMode) {
337
+ return;
338
+ }
339
+ input.value = parent.state().controlValue();
340
+ }, parent.destroyRef);
341
+ }
342
+ const bindings = createBindings();
343
+ return () => {
344
+ const state = parent.state();
345
+ const controlValue = state.controlValue();
346
+ if (bindingUpdated(bindings, 'controlValue', controlValue)) {
347
+ setNativeControlValue(input, controlValue);
348
+ }
349
+ for (const name of CONTROL_BINDING_NAMES) {
350
+ const value = readFieldStateBindingValue(state, name);
351
+ if (bindingUpdated(bindings, name, value)) {
352
+ host.setInputOnDirectives(name, value);
353
+ if (parent.elementAcceptsNativeProperty(name)) {
354
+ setNativeDomProperty(parent.renderer, input, name, value);
355
+ }
356
+ }
357
+ }
358
+ updateMode = true;
359
+ };
360
+ }
361
+
362
+ const ɵNgFieldDirective = Symbol();
363
+ const FORM_FIELD = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'FORM_FIELD' : '');
101
364
  class FormField {
102
- element = inject(ElementRef).nativeElement;
103
- injector = inject(Injector);
104
- formField = input.required(...(ngDevMode ? [{
105
- debugName: "formField"
106
- }] : []));
107
- state = computed(() => this.formField()(), ...(ngDevMode ? [{
365
+ fieldTree = input.required({
366
+ ...(ngDevMode ? {
367
+ debugName: "fieldTree"
368
+ } : {}),
369
+ alias: 'formField'
370
+ });
371
+ renderer = inject(Renderer2);
372
+ destroyRef = inject(DestroyRef);
373
+ state = computed(() => this.fieldTree()(), ...(ngDevMode ? [{
108
374
  debugName: "state"
109
375
  }] : []));
110
- bindingOptions = signal(undefined, ...(ngDevMode ? [{
111
- debugName: "bindingOptions"
112
- }] : []));
113
- [_CONTROL] = controlInstructions;
114
- config = inject(SIGNAL_FORMS_CONFIG, {
115
- optional: true
116
- });
117
- classes = Object.entries(this.config?.classes ?? {}).map(([className, computation]) => [className, computed(() => computation(this))]);
376
+ injector = inject(Injector);
377
+ element = inject(ElementRef).nativeElement;
378
+ elementIsNativeFormElement = isNativeFormElement(this.element);
379
+ elementAcceptsNumericValues = isNumericFormElement(this.element);
380
+ elementAcceptsTextualValues = isTextualFormElement(this.element);
381
+ nativeFormElement = this.elementIsNativeFormElement ? this.element : undefined;
382
+ focuser = options => this.element.focus(options);
118
383
  controlValueAccessors = inject(NG_VALUE_ACCESSOR, {
119
384
  optional: true,
120
385
  self: true
121
386
  });
122
- interopNgControl;
123
- get ɵinteropControl() {
387
+ config = inject(SIGNAL_FORMS_CONFIG, {
388
+ optional: true
389
+ });
390
+ parseErrorsSource = signal(undefined, ...(ngDevMode ? [{
391
+ debugName: "parseErrorsSource"
392
+ }] : []));
393
+ _interopNgControl;
394
+ get interopNgControl() {
395
+ return this._interopNgControl ??= new InteropNgControl(this.state);
396
+ }
397
+ parseErrors = computed(() => this.parseErrorsSource()?.().map(err => ({
398
+ ...err,
399
+ fieldTree: untracked(this.fieldTree),
400
+ formField: this
401
+ })) ?? [], ...(ngDevMode ? [{
402
+ debugName: "parseErrors"
403
+ }] : []));
404
+ errors = computed(() => this.state().errors().filter(err => !err.formField || err.formField === this), ...(ngDevMode ? [{
405
+ debugName: "errors"
406
+ }] : []));
407
+ isFieldBinding = false;
408
+ get controlValueAccessor() {
124
409
  return this.controlValueAccessors?.[0] ?? this.interopNgControl?.valueAccessor ?? undefined;
125
410
  }
126
- getOrCreateNgControl() {
127
- return this.interopNgControl ??= new InteropNgControl(this.state);
411
+ installClassBindingEffect() {
412
+ const classes = Object.entries(this.config?.classes ?? {}).map(([className, computation]) => [className, computed(() => computation(this))]);
413
+ if (classes.length === 0) {
414
+ return;
415
+ }
416
+ const bindings = createBindings();
417
+ afterRenderEffect({
418
+ write: () => {
419
+ for (const [className, computation] of classes) {
420
+ const active = computation();
421
+ if (bindingUpdated(bindings, className, active)) {
422
+ if (active) {
423
+ this.renderer.addClass(this.element, className);
424
+ } else {
425
+ this.renderer.removeClass(this.element, className);
426
+ }
427
+ }
428
+ }
429
+ }
430
+ }, {
431
+ injector: this.injector
432
+ });
433
+ }
434
+ focus(options) {
435
+ this.focuser(options);
128
436
  }
129
437
  registerAsBinding(bindingOptions) {
130
- if (untracked(this.bindingOptions)) {
438
+ if (this.isFieldBinding) {
131
439
  throw new _RuntimeError(1913, ngDevMode && 'FormField already registered as a binding');
132
440
  }
133
- this.bindingOptions.set(bindingOptions);
441
+ this.isFieldBinding = true;
442
+ this.installClassBindingEffect();
443
+ if (bindingOptions?.focus) {
444
+ this.focuser = bindingOptions.focus;
445
+ }
446
+ if (bindingOptions?.parseErrors) {
447
+ this.parseErrorsSource.set(bindingOptions.parseErrors);
448
+ }
134
449
  effect(onCleanup => {
135
450
  const fieldNode = this.state();
136
451
  fieldNode.nodeState.formFieldBindings.update(controls => [...controls, this]);
@@ -141,17 +456,45 @@ class FormField {
141
456
  injector: this.injector
142
457
  });
143
458
  }
144
- focus(options) {
145
- const bindingOptions = untracked(this.bindingOptions);
146
- if (bindingOptions?.focus) {
147
- bindingOptions.focus(options);
459
+ [ɵNgFieldDirective];
460
+ ɵngControlCreate(host) {
461
+ if (host.hasPassThrough) {
462
+ return;
463
+ }
464
+ if (this.controlValueAccessor) {
465
+ this.ɵngControlUpdate = cvaControlCreate(host, this);
466
+ } else if (host.customControl) {
467
+ this.ɵngControlUpdate = customControlCreate(host, this);
468
+ } else if (this.elementIsNativeFormElement) {
469
+ this.ɵngControlUpdate = nativeControlCreate(host, this);
148
470
  } else {
149
- this.element.focus(options);
471
+ throw new _RuntimeError(1914, ngDevMode && `${host.descriptor} is an invalid [formField] directive host. The host must be a native form control ` + `(such as <input>', '<select>', or '<textarea>') or a custom form control with a 'value' or ` + `'checked' model.`);
472
+ }
473
+ }
474
+ ɵngControlUpdate;
475
+ elementAcceptsNativeProperty(key) {
476
+ if (!this.elementIsNativeFormElement) {
477
+ return false;
478
+ }
479
+ switch (key) {
480
+ case 'min':
481
+ case 'max':
482
+ return this.elementAcceptsNumericValues;
483
+ case 'minLength':
484
+ case 'maxLength':
485
+ return this.elementAcceptsTextualValues;
486
+ case 'disabled':
487
+ case 'required':
488
+ case 'readonly':
489
+ case 'name':
490
+ return true;
491
+ default:
492
+ return false;
150
493
  }
151
494
  }
152
495
  static ɵfac = i0.ɵɵngDeclareFactory({
153
496
  minVersion: "12.0.0",
154
- version: "21.2.0-next.0",
497
+ version: "21.2.0-next.2",
155
498
  ngImport: i0,
156
499
  type: FormField,
157
500
  deps: [],
@@ -159,13 +502,13 @@ class FormField {
159
502
  });
160
503
  static ɵdir = i0.ɵɵngDeclareDirective({
161
504
  minVersion: "17.1.0",
162
- version: "21.2.0-next.0",
505
+ version: "21.2.0-next.2",
163
506
  type: FormField,
164
507
  isStandalone: true,
165
508
  selector: "[formField]",
166
509
  inputs: {
167
- formField: {
168
- classPropertyName: "formField",
510
+ fieldTree: {
511
+ classPropertyName: "fieldTree",
169
512
  publicName: "formField",
170
513
  isSignal: true,
171
514
  isRequired: true,
@@ -177,31 +520,36 @@ class FormField {
177
520
  useExisting: FormField
178
521
  }, {
179
522
  provide: NgControl,
180
- useFactory: () => inject(FormField).getOrCreateNgControl()
523
+ useFactory: () => inject(FormField).interopNgControl
181
524
  }],
525
+ exportAs: ["formField"],
526
+ controlCreate: {
527
+ passThroughInput: "formField"
528
+ },
182
529
  ngImport: i0
183
530
  });
184
531
  }
185
532
  i0.ɵɵngDeclareClassMetadata({
186
533
  minVersion: "12.0.0",
187
- version: "21.2.0-next.0",
534
+ version: "21.2.0-next.2",
188
535
  ngImport: i0,
189
536
  type: FormField,
190
537
  decorators: [{
191
538
  type: Directive,
192
539
  args: [{
193
540
  selector: '[formField]',
541
+ exportAs: 'formField',
194
542
  providers: [{
195
543
  provide: FORM_FIELD,
196
544
  useExisting: FormField
197
545
  }, {
198
546
  provide: NgControl,
199
- useFactory: () => inject(FormField).getOrCreateNgControl()
547
+ useFactory: () => inject(FormField).interopNgControl
200
548
  }]
201
549
  }]
202
550
  }],
203
551
  propDecorators: {
204
- formField: [{
552
+ fieldTree: [{
205
553
  type: i0.Input,
206
554
  args: [{
207
555
  isSignal: true,
@@ -289,10 +637,7 @@ function patternError(pattern, options) {
289
637
  function emailError(options) {
290
638
  return new EmailValidationError(options);
291
639
  }
292
- function standardSchemaError(issue, options) {
293
- return new StandardSchemaValidationError(issue, options);
294
- }
295
- class _NgValidationError {
640
+ class BaseNgValidationError {
296
641
  __brand = undefined;
297
642
  kind = '';
298
643
  fieldTree;
@@ -303,10 +648,10 @@ class _NgValidationError {
303
648
  }
304
649
  }
305
650
  }
306
- class RequiredValidationError extends _NgValidationError {
651
+ class RequiredValidationError extends BaseNgValidationError {
307
652
  kind = 'required';
308
653
  }
309
- class MinValidationError extends _NgValidationError {
654
+ class MinValidationError extends BaseNgValidationError {
310
655
  min;
311
656
  kind = 'min';
312
657
  constructor(min, options) {
@@ -314,7 +659,7 @@ class MinValidationError extends _NgValidationError {
314
659
  this.min = min;
315
660
  }
316
661
  }
317
- class MaxValidationError extends _NgValidationError {
662
+ class MaxValidationError extends BaseNgValidationError {
318
663
  max;
319
664
  kind = 'max';
320
665
  constructor(max, options) {
@@ -322,7 +667,7 @@ class MaxValidationError extends _NgValidationError {
322
667
  this.max = max;
323
668
  }
324
669
  }
325
- class MinLengthValidationError extends _NgValidationError {
670
+ class MinLengthValidationError extends BaseNgValidationError {
326
671
  minLength;
327
672
  kind = 'minLength';
328
673
  constructor(minLength, options) {
@@ -330,7 +675,7 @@ class MinLengthValidationError extends _NgValidationError {
330
675
  this.minLength = minLength;
331
676
  }
332
677
  }
333
- class MaxLengthValidationError extends _NgValidationError {
678
+ class MaxLengthValidationError extends BaseNgValidationError {
334
679
  maxLength;
335
680
  kind = 'maxLength';
336
681
  constructor(maxLength, options) {
@@ -338,7 +683,7 @@ class MaxLengthValidationError extends _NgValidationError {
338
683
  this.maxLength = maxLength;
339
684
  }
340
685
  }
341
- class PatternValidationError extends _NgValidationError {
686
+ class PatternValidationError extends BaseNgValidationError {
342
687
  pattern;
343
688
  kind = 'pattern';
344
689
  constructor(pattern, options) {
@@ -346,18 +691,10 @@ class PatternValidationError extends _NgValidationError {
346
691
  this.pattern = pattern;
347
692
  }
348
693
  }
349
- class EmailValidationError extends _NgValidationError {
694
+ class EmailValidationError extends BaseNgValidationError {
350
695
  kind = 'email';
351
696
  }
352
- class StandardSchemaValidationError extends _NgValidationError {
353
- issue;
354
- kind = 'standardSchema';
355
- constructor(issue, options) {
356
- super(options);
357
- this.issue = issue;
358
- }
359
- }
360
- const NgValidationError = _NgValidationError;
697
+ const NgValidationError = BaseNgValidationError;
361
698
 
362
699
  const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
363
700
  function email(path, config) {
@@ -611,6 +948,9 @@ function validateStandardSchema(path, schema) {
611
948
  onError: () => {}
612
949
  });
613
950
  }
951
+ function standardSchemaError(issue, options) {
952
+ return new StandardSchemaValidationError(issue, options);
953
+ }
614
954
  function standardIssueToFormTreeError(fieldTree, issue) {
615
955
  let target = fieldTree;
616
956
  for (const pathPart of issue.path ?? []) {
@@ -621,6 +961,14 @@ function standardIssueToFormTreeError(fieldTree, issue) {
621
961
  message: issue.message
622
962
  }), target);
623
963
  }
964
+ class StandardSchemaValidationError extends BaseNgValidationError {
965
+ issue;
966
+ kind = 'standardSchema';
967
+ constructor(issue, options) {
968
+ super(options);
969
+ this.issue = issue;
970
+ }
971
+ }
624
972
 
625
973
  function validateHttp(path, opts) {
626
974
  validateAsync(path, {
@@ -643,6 +991,7 @@ function debounceForDuration(durationInMilliseconds) {
643
991
  let timeoutId;
644
992
  const onAbort = () => {
645
993
  clearTimeout(timeoutId);
994
+ resolve();
646
995
  };
647
996
  timeoutId = setTimeout(() => {
648
997
  abortSignal.removeEventListener('abort', onAbort);
@@ -656,5 +1005,5 @@ function debounceForDuration(durationInMilliseconds) {
656
1005
  }
657
1006
  function immediate() {}
658
1007
 
659
- export { EmailValidationError, FORM_FIELD, FormField, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PatternValidationError, REQUIRED, RequiredValidationError, StandardSchemaValidationError, createManagedMetadataKey, createMetadataKey, debounce, disabled, email, emailError, hidden, max, maxError, maxLength, maxLengthError, metadata, min, minError, minLength, minLengthError, pattern, patternError, provideSignalFormsConfig, readonly, required, requiredError, standardSchemaError, validate, validateAsync, validateHttp, validateStandardSchema, validateTree };
1008
+ export { BaseNgValidationError, EmailValidationError, FORM_FIELD, FormField, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PatternValidationError, REQUIRED, RequiredValidationError, StandardSchemaValidationError, createManagedMetadataKey, createMetadataKey, debounce, disabled, email, emailError, hidden, max, maxError, maxLength, maxLengthError, metadata, min, minError, minLength, minLengthError, pattern, patternError, provideSignalFormsConfig, readonly, required, requiredError, standardSchemaError, validate, validateAsync, validateHttp, validateStandardSchema, validateTree, ɵNgFieldDirective };
660
1009
  //# sourceMappingURL=signals.mjs.map