@angular/forms 21.2.0-next.1 → 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.1
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,29 +85,318 @@ 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
365
  fieldTree = input.required({
105
366
  ...(ngDevMode ? {
106
367
  debugName: "fieldTree"
107
368
  } : {}),
108
369
  alias: 'formField'
109
370
  });
371
+ renderer = inject(Renderer2);
372
+ destroyRef = inject(DestroyRef);
110
373
  state = computed(() => this.fieldTree()(), ...(ngDevMode ? [{
111
374
  debugName: "state"
112
375
  }] : []));
113
- bindingOptions = signal(undefined, ...(ngDevMode ? [{
114
- debugName: "bindingOptions"
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);
383
+ controlValueAccessors = inject(NG_VALUE_ACCESSOR, {
384
+ optional: true,
385
+ self: true
386
+ });
387
+ config = inject(SIGNAL_FORMS_CONFIG, {
388
+ optional: true
389
+ });
390
+ parseErrorsSource = signal(undefined, ...(ngDevMode ? [{
391
+ debugName: "parseErrorsSource"
115
392
  }] : []));
116
- parseErrors = computed(() => this.bindingOptions()?.parseErrors?.().map(err => ({
393
+ _interopNgControl;
394
+ get interopNgControl() {
395
+ return this._interopNgControl ??= new InteropNgControl(this.state);
396
+ }
397
+ parseErrors = computed(() => this.parseErrorsSource()?.().map(err => ({
117
398
  ...err,
118
- fieldTree: this.fieldTree(),
399
+ fieldTree: untracked(this.fieldTree),
119
400
  formField: this
120
401
  })) ?? [], ...(ngDevMode ? [{
121
402
  debugName: "parseErrors"
@@ -123,27 +404,48 @@ class FormField {
123
404
  errors = computed(() => this.state().errors().filter(err => !err.formField || err.formField === this), ...(ngDevMode ? [{
124
405
  debugName: "errors"
125
406
  }] : []));
126
- [_CONTROL] = controlInstructions;
127
- config = inject(SIGNAL_FORMS_CONFIG, {
128
- optional: true
129
- });
130
- classes = Object.entries(this.config?.classes ?? {}).map(([className, computation]) => [className, computed(() => computation(this))]);
131
- controlValueAccessors = inject(NG_VALUE_ACCESSOR, {
132
- optional: true,
133
- self: true
134
- });
135
- interopNgControl;
136
- get ɵinteropControl() {
407
+ isFieldBinding = false;
408
+ get controlValueAccessor() {
137
409
  return this.controlValueAccessors?.[0] ?? this.interopNgControl?.valueAccessor ?? undefined;
138
410
  }
139
- getOrCreateNgControl() {
140
- 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);
141
436
  }
142
437
  registerAsBinding(bindingOptions) {
143
- if (untracked(this.bindingOptions)) {
438
+ if (this.isFieldBinding) {
144
439
  throw new _RuntimeError(1913, ngDevMode && 'FormField already registered as a binding');
145
440
  }
146
- 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
+ }
147
449
  effect(onCleanup => {
148
450
  const fieldNode = this.state();
149
451
  fieldNode.nodeState.formFieldBindings.update(controls => [...controls, this]);
@@ -154,17 +456,45 @@ class FormField {
154
456
  injector: this.injector
155
457
  });
156
458
  }
157
- focus(options) {
158
- const bindingOptions = untracked(this.bindingOptions);
159
- if (bindingOptions?.focus) {
160
- 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);
161
470
  } else {
162
- 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;
163
493
  }
164
494
  }
165
495
  static ɵfac = i0.ɵɵngDeclareFactory({
166
496
  minVersion: "12.0.0",
167
- version: "21.2.0-next.1",
497
+ version: "21.2.0-next.2",
168
498
  ngImport: i0,
169
499
  type: FormField,
170
500
  deps: [],
@@ -172,7 +502,7 @@ class FormField {
172
502
  });
173
503
  static ɵdir = i0.ɵɵngDeclareDirective({
174
504
  minVersion: "17.1.0",
175
- version: "21.2.0-next.1",
505
+ version: "21.2.0-next.2",
176
506
  type: FormField,
177
507
  isStandalone: true,
178
508
  selector: "[formField]",
@@ -190,15 +520,18 @@ class FormField {
190
520
  useExisting: FormField
191
521
  }, {
192
522
  provide: NgControl,
193
- useFactory: () => inject(FormField).getOrCreateNgControl()
523
+ useFactory: () => inject(FormField).interopNgControl
194
524
  }],
195
525
  exportAs: ["formField"],
526
+ controlCreate: {
527
+ passThroughInput: "formField"
528
+ },
196
529
  ngImport: i0
197
530
  });
198
531
  }
199
532
  i0.ɵɵngDeclareClassMetadata({
200
533
  minVersion: "12.0.0",
201
- version: "21.2.0-next.1",
534
+ version: "21.2.0-next.2",
202
535
  ngImport: i0,
203
536
  type: FormField,
204
537
  decorators: [{
@@ -211,7 +544,7 @@ i0.ɵɵngDeclareClassMetadata({
211
544
  useExisting: FormField
212
545
  }, {
213
546
  provide: NgControl,
214
- useFactory: () => inject(FormField).getOrCreateNgControl()
547
+ useFactory: () => inject(FormField).interopNgControl
215
548
  }]
216
549
  }]
217
550
  }],
@@ -304,10 +637,7 @@ function patternError(pattern, options) {
304
637
  function emailError(options) {
305
638
  return new EmailValidationError(options);
306
639
  }
307
- function standardSchemaError(issue, options) {
308
- return new StandardSchemaValidationError(issue, options);
309
- }
310
- class _NgValidationError {
640
+ class BaseNgValidationError {
311
641
  __brand = undefined;
312
642
  kind = '';
313
643
  fieldTree;
@@ -318,10 +648,10 @@ class _NgValidationError {
318
648
  }
319
649
  }
320
650
  }
321
- class RequiredValidationError extends _NgValidationError {
651
+ class RequiredValidationError extends BaseNgValidationError {
322
652
  kind = 'required';
323
653
  }
324
- class MinValidationError extends _NgValidationError {
654
+ class MinValidationError extends BaseNgValidationError {
325
655
  min;
326
656
  kind = 'min';
327
657
  constructor(min, options) {
@@ -329,7 +659,7 @@ class MinValidationError extends _NgValidationError {
329
659
  this.min = min;
330
660
  }
331
661
  }
332
- class MaxValidationError extends _NgValidationError {
662
+ class MaxValidationError extends BaseNgValidationError {
333
663
  max;
334
664
  kind = 'max';
335
665
  constructor(max, options) {
@@ -337,7 +667,7 @@ class MaxValidationError extends _NgValidationError {
337
667
  this.max = max;
338
668
  }
339
669
  }
340
- class MinLengthValidationError extends _NgValidationError {
670
+ class MinLengthValidationError extends BaseNgValidationError {
341
671
  minLength;
342
672
  kind = 'minLength';
343
673
  constructor(minLength, options) {
@@ -345,7 +675,7 @@ class MinLengthValidationError extends _NgValidationError {
345
675
  this.minLength = minLength;
346
676
  }
347
677
  }
348
- class MaxLengthValidationError extends _NgValidationError {
678
+ class MaxLengthValidationError extends BaseNgValidationError {
349
679
  maxLength;
350
680
  kind = 'maxLength';
351
681
  constructor(maxLength, options) {
@@ -353,7 +683,7 @@ class MaxLengthValidationError extends _NgValidationError {
353
683
  this.maxLength = maxLength;
354
684
  }
355
685
  }
356
- class PatternValidationError extends _NgValidationError {
686
+ class PatternValidationError extends BaseNgValidationError {
357
687
  pattern;
358
688
  kind = 'pattern';
359
689
  constructor(pattern, options) {
@@ -361,18 +691,10 @@ class PatternValidationError extends _NgValidationError {
361
691
  this.pattern = pattern;
362
692
  }
363
693
  }
364
- class EmailValidationError extends _NgValidationError {
694
+ class EmailValidationError extends BaseNgValidationError {
365
695
  kind = 'email';
366
696
  }
367
- class StandardSchemaValidationError extends _NgValidationError {
368
- issue;
369
- kind = 'standardSchema';
370
- constructor(issue, options) {
371
- super(options);
372
- this.issue = issue;
373
- }
374
- }
375
- const NgValidationError = _NgValidationError;
697
+ const NgValidationError = BaseNgValidationError;
376
698
 
377
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])?)*$/;
378
700
  function email(path, config) {
@@ -626,6 +948,9 @@ function validateStandardSchema(path, schema) {
626
948
  onError: () => {}
627
949
  });
628
950
  }
951
+ function standardSchemaError(issue, options) {
952
+ return new StandardSchemaValidationError(issue, options);
953
+ }
629
954
  function standardIssueToFormTreeError(fieldTree, issue) {
630
955
  let target = fieldTree;
631
956
  for (const pathPart of issue.path ?? []) {
@@ -636,6 +961,14 @@ function standardIssueToFormTreeError(fieldTree, issue) {
636
961
  message: issue.message
637
962
  }), target);
638
963
  }
964
+ class StandardSchemaValidationError extends BaseNgValidationError {
965
+ issue;
966
+ kind = 'standardSchema';
967
+ constructor(issue, options) {
968
+ super(options);
969
+ this.issue = issue;
970
+ }
971
+ }
639
972
 
640
973
  function validateHttp(path, opts) {
641
974
  validateAsync(path, {
@@ -658,6 +991,7 @@ function debounceForDuration(durationInMilliseconds) {
658
991
  let timeoutId;
659
992
  const onAbort = () => {
660
993
  clearTimeout(timeoutId);
994
+ resolve();
661
995
  };
662
996
  timeoutId = setTimeout(() => {
663
997
  abortSignal.removeEventListener('abort', onAbort);
@@ -671,5 +1005,5 @@ function debounceForDuration(durationInMilliseconds) {
671
1005
  }
672
1006
  function immediate() {}
673
1007
 
674
- 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 };
675
1009
  //# sourceMappingURL=signals.mjs.map